Well, if you don’t know what VLC player is, then I guess you must have been abducted by aliens for the past few years. In which case, welcome back! VLC is a cross platform media player with a somewhat quirky interface, but whereas say Windoze Media Player relies on codecs – a nightmare of codec incompatibilities exist there (all, for once, not Microsoft’s fault)(OK, mostly). Instead, VLC has all the decoding code built-in, so just works straight out of the box, the only exception being AVISynth scripts – come on VLC developers, get yer fingers out!
But as a developer, you can use the Windows DirectShow API to access all the codecs and rustle up your own player. In theory. Just a quicky RenderStream(), job done. Trouble is, unless you are going to manage which codec combinations get used with which format, physically block certain codecs and add additional code to manage the quirks of specific codecs then be prepared to write a video player that probably won’t work half the time and even blow your app up in ways you can’t trap.
So, as an alternative, wouldn’t it be nice to host a nice DirectShow-less player such as VLC in your own application ? But where to start? “VLC documentation” I hear you shout. Well, there is a basic tutorial , then there is the massive doxygen-generated doc , (though I’m not sure how simply dumping all the available functions with no clue on there usage is really that helpful). So, I thought, instead of just whinging I would instead go through a real coding example (and yes, just have a minor little whinge).
We ‘aint going nowhere without knowing the DLL(s) we will be accessing. Well, the primary one is LibVlc.dll (on my machine located in C:\Program Files\VideoLAN\VLC\plugins) and that’s the one we’ll be talking too. However, this DLL relies on a few others such as libvlccore.dll and a whole shed load plugins located in the sensibly named “plugins” subdirectory.
So, decision time. If we want to use the standard interop methods to access the DLL then all the DLLs must be on the environment PATH. Unlikely this is the case with most people. Secondly, we stick with the interop methods but copy all the dlls into our project. Well, it’d work, but what’s a lot of extra baggage to say nothing of user updates to VLC. So its settled then, we need to use the good old Win32 “LoadLiibrary” … this’ll be fun in C# won’t it
So lets start of by creating a class “LibVlcDll_Prototype” and in its constructor we’ll load the DLL:-
We pass in the directory containing the DLL to the constructor, which then loads the DLL. Note we have to temporarily switch the current directory to the DLL’s directory, Windows just hates looking for associated DLLs in the same directory as the DLL being loaded. Grrrrr.
Oh, the function LastError() ? Don’t worry, just because even .NET 4 still prefers error numbers just like 80′s computers did doesn’t mean we have to use them:-
The more observant of you will notice that my class is derived from IDisposable, that’s because if we loaded a DLL we need to also release it at close of play. In it’s simplest form:
[Note: this isn't the correct Dispose() implementation, just a brief example.]
Well, that’s loading / releasing the DLL. Now for the bit we need to connect up to the functions in the DLL. Its not gonna be pretty. Instead of attempting to link to all the functions from within the constructor, instead I’m going to link to each function as and when needed. Before diving off and attempting to connect up all the functions only to find Microsoft has managed to throw another unexpected spanner in the works, lets pick a function that we can test with the minimal of coding effort, and here it is :-
We create a delegate (‘libvlc_get_version’) for the function we wish to call, then use Marshal.GetDelegateForFunctionPointer to create a delegate instance against from the DLL, specifying the name of the DLL function in quotes. Now, I decided to name the delegate the same as the name of the DLL function, but you do not have to; the DLL function name only appears once, in the call to GetProcAddress(), everywhere else libvlc_get_version is referring to the delegate.
Well, that’s about it really. Each function gets its own delegate but really we just repeat the GetVersion() code and change the names appropriately for each individual function (having said that, some of the delegates get a bit hairy such as array of pointers to strings, but we’ll get to that later).
[Edit : 2015-05-15] If you now make a quick test program that just calls GetVersion() whilst running in the VisualStudio IDE debugger, you may get an error “vshost32-dr2.exe has stopped working”. However, if you run the exe directly it all works. There appears to be a problem with VS2012 on Windows 8 (I don’t recall seeing it on Win7 running VS2010 or XP running 2008) and you can work around it by enabling “Enable native code debugging” in you project’s configuration.
In the next part we’ll do some of the initialisation of VLC that we need to do before we get to the real purpose – playing some files!.