# Any Plugin Experts Out There?



## Jaxel (Oct 16, 2014)

I want to start writing OBS plugins. But I don't know where to get started.

Is anyone out there willing to help me walk through some stuff?


----------



## dodgepong (Oct 16, 2014)

First, a caveat: OBS Multiplatform is still early in development, but eventually it will overtake the current version of OBS in terms of features and functionality, and the original will be deprecated. I'm not sure when that point will be, but keep that in mind when choosing which version to develop plugins for.

A good way to start is to check out the source code and try to get OBS building. Feel free to join #obs-dev on Quakenet if you need help.

The API for original OBS (OBS1) is not documented at all, unfortunately. To learn the API, you'll basically have to read the source code. You may also consider using the CLR Host Plugin to develop plugins in C#/VB.NET instead of C++. Many plugins are open source, so you can check out the source to see how they work.

The API for OBS-Studio is much better documented and easier to use. Most of the core elements to OBS-Studio are actually plugins, as you can see in the plugins folder. It should be a lot easier to get an idea of how the OBS-Studio API works. Again, checking out the code from git and getting it to build is a good first step.


----------



## Jaxel (Oct 18, 2014)

Okay... then any experts on CLR Host willing to help me out?


----------



## dodgepong (Oct 18, 2014)

Here is the documentation from the CLR Host plugin author: http://catchexception.org/docs/creating-a-plugin/

And the CLR Host plugin itself: https://obsproject.com/forum/resources/clr-host-plugin.21/

One thing nice about developing using the CLR Host is that the CLR Host API actually does include some documentation, as opposed to the raw OBS API, which does not.


----------



## Jaxel (Oct 18, 2014)

dodgepong said:


> Here is the documentation from the CLR Host plugin author: http://catchexception.org/docs/creating-a-plugin/
> 
> And the CLR Host plugin itself: https://obsproject.com/forum/resources/clr-host-plugin.21/
> 
> One thing nice about developing using the CLR Host is that the CLR Host API actually does include some documentation, as opposed to the raw OBS API, which does not.


The problem is I don't need help with C#; C# I got... what I need help on is the ABSOLUTE basics of VS.

There is so much that documentation doesn't explain.


----------



## dodgepong (Oct 18, 2014)

I suppose if you're going to make a plugin using the CLR Host, you can skip the step where you build OBS yourself, so you don't need to use Visual Studio for that. What have you done your C# development with in the past? I assumed you were familiar with Visual Studio, since Visual Studio is the tool of choice for virtually all C# development.


----------



## Jaxel (Oct 18, 2014)

I dont really do any C# development... Scoreboard Assistant is it (which I use VS2013e). I come from the areas of procedural programming, and scripting languages. I am a web developer. Things like "MVVC", and "Compiling" are weird to me. My main languages are PHP, Perl, JS and HTML.

Following the CLR documentation, it tells you how to basically hook into CLR Host. But it doesn't tell you much more than that. For instance, how do I tell it WHAT to display on OBS? How do I set up a configuration page? What methodology does it use to save variables? There are a lot of unanswered questions.


----------



## Jaxel (Oct 21, 2014)

Basically all I want to do is write a plugin that does this:
http://8wayrun.tv/scripts/sboard.html

I already have the code written in C#... I just need to know how to make it into a plugin.


----------



## Faruton (Oct 21, 2014)

https://github.com/kc5nra/CLRHostPlugin/tree/cleanup/CLRCSharpSamplePlugin

There is a sample included with the plugin


----------



## Jaxel (Oct 22, 2014)

Okay... I've got it mostly working so far... Have a plugin, have the config screen, have it rendering the proper size... I just don't know how to set it to render my animated UserControl on the display screen. Again, lack of documentation that pretty much explains anything. This is my code:


```
using CLROBS;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SbaEvent
{
    class SbaEventSource : AbstractImageSource
    {
        private Object textureLock = new Object();
        private Texture texture = null;
        private XElement config;

        public SbaEventSource(XElement config)
        {
            this.config = config;
            UpdateSettings();
        }

        override public void UpdateSettings()
        {
            uint width = (uint)config.GetInt("width", 640);
            uint height = (uint)config.GetInt("height", 480);

            Size.X = width;
            Size.Y = height;

            config.Parent.SetInt("cx", (int)width);
            config.Parent.SetInt("cy", (int)height);

            lock (textureLock)
            {
                if (texture != null)
                {
                    texture.Dispose();
                    texture = null;
                }

                texture = GS.CreateTexture(width, height, GSColorFormat.GS_BGRA, null, false, false);
            }
        }

        override public void Render(float x, float y, float width, float height)
        {
            lock (textureLock)
            {
                if (texture != null)
                {
                    GS.DrawSprite(texture, 0xFFFFFFFF, x, y, x + width, y + height);
                }
            }
        }

        public void Dispose()
        {
            lock (textureLock)
            {
                if (texture != null)
                {
                    texture.Dispose();
                    texture = null;
                }
            }
        }
    }
}
```


----------



## dodgepong (Oct 22, 2014)

I understand it's frustrating not having sufficient documentation, requiring a lot of learning on your own. Not having documentation makes it harder for developers to get involved, which means less engagement, which is not what we want to happen, and better documentation is a goal of OBS2 for that reason.

You might try coming by #obs-dev to get some more help from people who develop for OBS.


----------



## Faruton (Oct 22, 2014)

https://github.com/kc5nra/starboard-sc2/tree/master/starboard-sc2/OBS

There should be an example of exactly what you are trying to do in that


----------



## Jaxel (Oct 22, 2014)

Faruton said:


> https://github.com/kc5nra/starboard-sc2/tree/master/starboard-sc2/OBS
> 
> There should be an example of exactly what you are trying to do in that


Ehh... not exactly. That writes the starboard as a static single bitmap image. It basically throws out the animations.


----------



## Faruton (Oct 23, 2014)

I'm not sure you are reading the code right

It converts to image every tine obs requests it which is up to 60 times a second making it animated


----------



## Jaxel (Oct 23, 2014)

Faruton said:


> I'm not sure you are reading the code right
> 
> It converts to image every tine obs requests it which is up to 60 times a second making it animated


See I can't get ANY animation to work... at all. This is my code:

```
using CLROBS;
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace SbaEvent
{
    class SbaEventSource : AbstractImageSource, IDisposable
    {
        private Object textureLock = new Object();
        private Texture texture = null;
        private XElement config;

        private SbaEventControl eventControl;

        public SbaEventSource(XElement config)
        {
            this.config = config;
            UpdateSettings();
        }

        override public void UpdateSettings()
        {
            UInt32 width = (UInt32)config.GetInt("width", 1280);
            UInt32 height = (UInt32)config.GetInt("height", 40);

            if (eventControl == null)
            {
                eventControl = new SbaEventControl(this.config);
                eventControl.Arrange(new Rect(new Size(width, height)));
            }

            lock (textureLock)
            {
                if (texture != null)
                {
                    texture.Dispose();
                    texture = null;
                }

                Size.X = width;
                Size.Y = height;

                texture = GS.CreateTexture(width, height, GSColorFormat.GS_BGRA, null, false, false);
            }
        }

        private delegate void TickFunctionDelegate();
        private void renderBitmap()
        {
            lock (textureLock)
            {
                if (texture != null)
                {
                    int width = config.GetInt("width", 1280);
                    int height = config.GetInt("height", 40);

                    RenderTargetBitmap bitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
                    bitmap.Render(eventControl);
                    WriteableBitmap wBitmap = new WriteableBitmap(bitmap);

                    texture.SetImage(wBitmap.BackBuffer, GSImageFormat.GS_IMAGEFORMAT_BGRA, (UInt32)(wBitmap.PixelWidth * 4));
                }
            }
        }
        public override void Tick(float fSeconds)
        {
            Application.Current.Dispatcher.Invoke(new TickFunctionDelegate(renderBitmap));
        }

        override public void Render(float x, float y, float width, float height)
        {
            lock (textureLock)
            {
                if (texture != null)
                {
                    GS.DrawSprite(texture, 0xFFFFFFFF, x, y, x + width, y + height);
                }
            }
        }

        public void Dispose()
        {
            lock (textureLock)
            {
                if (texture != null)
                {
                    texture.Dispose();
                    texture = null;
                }
            }
        }
    }
}
```


```
using CLROBS;
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Xml;

namespace SbaEvent
{
    /// <summary>
    /// Interaction logic for SbaEventControl.xaml
    /// </summary>
    public partial class SbaEventControl : UserControl
    {
        private CircleEase easeIn = new CircleEase();
        private CircleEase easeOut = new CircleEase();
        private TimeSpan speedIn = TimeSpan.FromSeconds(1);
        private TimeSpan speedOut = TimeSpan.FromSeconds(1);

        private XElement config;

        public SbaEventControl(XElement config)
        {
            InitializeComponent();
            this.config = config;

            easeIn.EasingMode = EasingMode.EaseOut;
            easeOut.EasingMode = EasingMode.EaseOut;

            imageEE.Source = new ImageSourceConverter().ConvertFromString(config.GetString("imgFile")) as System.Windows.Media.ImageSource;

            ThicknessAnimation animateIn = new ThicknessAnimation(new Thickness(0, 0, 0, -40), speedIn);
            animateIn.EasingFunction = easeIn;
            canvasEE.BeginAnimation(Canvas.MarginProperty, animateIn);
        }
    }
}
```
The user control does render. It shows the image, as well as other stuff within the control. However, it never shows any animation... and when I close OBS, it now crashes.


----------



## Jaxel (Oct 23, 2014)

Okay... I got the animations working. Don't know what I did; but its magically working now.

I have 2 issues.

My config screen has options for width/height of the element. When I add the element however, it doesn't create the element with the width/height I specified. It creates it 100x100 and I have to click "Reset Size (ctrl+r)" to fix it. Its a minor annoyance.
When I close OBS, or click "Stop Preview"; OBS crashes.


----------



## Jaxel (Oct 23, 2014)

New interesting issue...

Sometimes when I first click "Preview Stream", the element doesn't work. However, the moment I double click the element in the sources list and open the config window... it magically starts working.

I then have to click "Cancel" on the config window to continue. As if I click "OK", the issue with #2 posted above occurs and OBS crashes.


----------



## Jaxel (Oct 23, 2014)

When I change scenes... it crashes. Its as if the "Dispose" is failing.


----------



## Faruton (Oct 23, 2014)

Can I see the crash log?  Otherwise I can't really diagnose that problem.

Is there a repository you have all this?  I can probably take a lo


----------



## Jaxel (Oct 23, 2014)

I dont have a repository... but I've attached it in a zip file. The zip file also includes an image and an XML file; which is required to setup the plugin.

Issues:

Plugin doesn't seem to dispose properly. If I change scenes or close OBS, it crashes. If I edit the plugin config and click OK, it crashes as well.
If I load up OBS, with an existing plugin element, it doesn't properly load the plugin. I have to bring up the plugin config window before it starts loading.
When first setting up the plugin, it doesn't size correctly and forces me to hit Ctrl+R to get it to the correct size.

Also, the crash log is completely unhelpful.


```
OBS has encountered an unhandled exception and has terminated. If you are able to
reproduce this crash, please submit this crash report on the forums at
http://www.obsproject.com/ - include the contents of this crash log and the
minidump .dmp file (if available) as well as your regular OBS log files and
a description of what you were doing at the time of the crash.

This crash appears to have occured in the 'c:\windows\syswow64\kernelbase.dll' module.

**** UNHANDLED EXCEPTION: 80000003
Fault address: 77083226 (c:\windows\syswow64\kernelbase.dll)
OBS version: Open Broadcaster Software v0.637b
Windows version: 6.1 (Build 7601) Service Pack 1
CPU: Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz

Crashing thread stack trace:
Stack    EIP      Arg0     Arg1     Arg2     Arg3     Address
0018F048 77083226 0000089C 00007532 763B78E2 002C0800 kernelbase.dll!0x77083226
0018F058 012D84FA 00000001 00000001 763B78E2 002C0800 obs.exe!OBS::Stop+0x19a
0018F0A0 012D199E 682C4C40 0018F9A4 012C9DAC 00000001 obs.exe!OBS::~OBS+0x2e
0018F4D0 012D190B 00000001 00000000 00000001 00000000 obs.exe!OBS::`vector deleting destructor'+0xb
0018F4DC 012C9DAC 01280000 00000000 002E3165 00000001 obs.exe!WinMain+0x9bc
0018F9AC 0131AB2A FFFDE000 0018FA3C 776F9F72 FFFDE000 obs.exe!__tmainCRTStartup+0xfd
0018F9F8 76A3338A FFFDE000 7712CC95 00000000 00000000 kernel32.dll!0x76a3338a
0018FA04 776F9F72 0131AA23 FFFDE000 00000000 00000000 ntdll.dll!0x776f9f72
0018FA44 776F9F45 0131AA23 FFFDE000 00000000 00000000 ntdll.dll!0x776f9f45

Video thread stack trace:
Stack    EIP      Arg0     Arg1     Arg2     Arg3     Address
1A5EECE4 776E015D 1A5EED34 1A5EEDA8 00000001 FFFFFFFF ntdll.dll!0x776e015d
1A5EED88 76A319F8 00000001 FFFDE000 00000001 FFFFFFFF kernel32.dll!0x76a319f8
1A5EEDD0 67ABCABF 00000001 FFFFFFFF 00000001 0B8902A8 clr.dll!0x67abcabf
1A5EEE20 67ABC81B 00000001 1A5EEFE0 00000001 FFFFFFFF clr.dll!0x67abc81b
1A5EEEAC 67ABC90C 00000001 1A5EEFE0 00000001 FFFFFFFF clr.dll!0x67abc90c
1A5EEF18 67AC0282 00000000 00000000 65B0B67F 04AB83A8 clr.dll!0x67ac0282
1A5EF008 66B36DD2 00000000 FFFFFFFF FFFFFFFF 04D26F38 mscorlib.ni.dll!0x66b36dd2
1A5EF020 66B4E3A0 FFFFD8F0 FFFFFFFF 00000000 00000000 mscorlib.ni.dll!0x66b4e3a0
1A5EF040 65B6294F BFF00000 04D2700C 04A82578 04AB8324 windowsbase.ni.dll!0x65b6294f
1A5EF074 65BD44CF FFFFD8F0 FFFFFFFF 00000000 FFFFD8F0 windowsbase.ni.dll!0x65bd44cf
1A5EF08C 65953AF5 FFFFD8F0 FFFFFFFF 00000000 00000000 windowsbase.ni.dll!0x65953af5
1A5EF0D8 6595AB8D FFFFFFFF 04D26F28 04D26F08 FFFFD8F0 windowsbase.ni.dll!0x6595ab8d
1A5EF124 65B0A14B 3D888888 073AFAD0 1A5EF1D8 67963315 windowsbase.ni.dll!0x65b0a14b
1A5EF17C 67953DE2 1A5EF3E0 1A5EF1C8 67AA2C66 1A5EF49C clr.dll!0x67953de2
1A5EF18C 67963315 0B891E80 00000001 073AFAD0 00000000 clr.dll!0x67963315
1A5EF1E0 679CB84C 0000A2D8 04D26ED4 66BFFE8C 0000001D clr.dll!0x679cb84c
1A5EF220 679CB714 00000000 04BF2050 04B53600 00000001 clr.dll!0x679cb714
1A5EF530 66B29B5D 04D26EF4 04D26ED4 00000000 04D26EF4 mscorlib.ni.dll!0x66b29b5d
1A5EF554 66BCE52D 00000000 04D26ED4 00000000 00000000 mscorlib.ni.dll!0x66bce52d
1A5EF580 66BCE4B4 04D26ED4 66C125EC 00000001 0100000C mscorlib.ni.dll!0x66bce4b4
1A5EF598 671BA40C 00000000 0000000D 00000000 0430FECC mscorlib.ni.dll!0x671ba40c
1A5EF5FC 6795421E 671BA384 66BCE4A0 1A5EF8F4 00000005 clr.dll!0x6795421e
1A5EF630 67ACE670 00F0E520 1A5EF8B0 0B8914E8 00F0E520 clr.dll!0x67ace670
1A5EF6A8 67ACE8B5 00F0E520 1A5EF8B0 FFFFFFFF 1A5EF8E4 clr.dll!0x67ace8b5
1A5EF878 67ACE4C1 002B8400 1BA91210 00000000 1A5EF948 clr.dll!0x67ace4c1
1A5EF8D4 680C653D 00F0E528 0000000D 00000000 0430FECC clrhostplugin.dll!0x680c653d
1A5EF8F4 680C653D 3D888888 01CFEF01 0000000D 00000000 clrhostplugin.dll!0x680c653d
1A5EF928 682C97C9 1A5EF964 682B5870 3D888888 002C0800 obsapi.dll!OSGetTimeMicroseconds+0xe9
1A5EF950 680C1A20 3D888888 002C0800 00000000 1A5EFCBC clrhostplugin.dll!0x680c1a20
1A5EF958 682B5870 3D888888 00000000 00000000 00000001 obsapi.dll!Scene::Tick+0x30
1A5EF96C 012DD512 76A3338A 00000000 1A5EFD0C 776F9F72 obs.exe!OBS::MainCaptureLoop+0xb52
1A5EFCC4 012DB285 00000000 1A5EFD0C 776F9F72 00000000 obs.exe!OBS::MainCaptureThread+0x5
1A5EFCC8 76A3338A 00000000 6D54CBA5 00000000 00000000 kernel32.dll!0x76a3338a
1A5EFCD4 776F9F72 012DB280 00000000 00000000 00000000 ntdll.dll!0x776f9f72
1A5EFD14 776F9F45 012DB280 00000000 00000000 00000000 ntdll.dll!0x776f9f45

A minidump was saved to C:\Users\Jaxel\AppData\Roaming\OBS\crashDumps\OBSCrashDump2014-10-23_17.dmp.
Please include this file when posting a crash report.

List of loaded modules:
Base Address      Module
```


----------



## Jaxel (Oct 24, 2014)

The issue appears to be in the following code:

```
public override void Tick(float fSeconds)
    {
        Application.Current.Dispatcher.Invoke(new TickFunctionDelegate(renderBitmap));
    }
```

If I comment out that code, and instead run renderBitmap() from within the UpdateSettings(), I no longer get any crashes... of course, then my plugin is no longer animated; which defeats the entire purpose of the plugin... but at least it no longer crashes.

Any ideas on how to fix?


----------



## Jaxel (Oct 24, 2014)

Okay, I appear to have fixed the crashing issue by replacing "Invoke" with "BeginInvoke".

Still have 2 remaining issues.

When I add the plugin to a source, it adds it 100x100, instead of the WidthxHeight I define in my plugin config. Must hit Ctrl+R to fix.
When I open up OBS with the plugin already set up in a scene, the plugin won't "start" until after I open the config window at least once.

* EDIT *

New issue... when I edit the plugin config... it doesn't actually apply the config changes until I "hide>show" the plugin.


----------



## Jaxel (Oct 24, 2014)

New question... The plugin takes a TON of memory. Most likely due to the fact that every frame, its building a bitmap image and setting it as a texture. Is there any way to fix this?


----------



## Faruton (Oct 24, 2014)

You answered your own question.

Reuse the bitmap


----------



## Jaxel (Oct 24, 2014)

Faruton said:


> You answered your own question.
> 
> Reuse the bitmap


What about any of the other issues?


----------



## Faruton (Oct 24, 2014)

Don't really have time to look, all I can say is to refer to CLRBrowserSourcePlugin as it exercises the CLRHost plugin the most.


----------



## Jaxel (Oct 24, 2014)

How would I "reuse" the bitmap?


----------



## Faruton (Oct 24, 2014)

Don't create it more than once


----------



## Jaxel (Oct 25, 2014)

Okay, new question...

When I edit the config of my plugin, it doesn't reload the plugin when I click "OK". I have to "hide/show" the plugin using the checkbox next to it in the source list in order for it to reload and use the new config settings. How do I force the plugin to reload itself when the configuration is changed?


----------



## Faruton (Oct 25, 2014)

Looking at your UpdateSettings, you don't change anything if it is already initialized.  Saving configuration doesn't automatically reload the plugin


----------



## Jaxel (Oct 25, 2014)

Faruton said:


> Looking at your UpdateSettings, you don't change anything if it is already initialized.  Saving configuration doesn't automatically reload the plugin


So... how do I reload the plugin?


----------



## Communicationcrafts (Nov 28, 2014)

I am using code in C# and also in VB. And it's really good information that you had share here. Thanks. Keep it Up.


----------

