What can be done with DirectShow and C# PDF Print E-mail
We would like to start by asking why there is no managed wrapper for DirectShow. The DirectShow SDK documentation contains a FAQ with this answer: "There are no current plans to implement a "Managed DirectShow" platform. You can use COM interop to create DirectShow client applications in managed code, but creating filters that depend on the Common Language Runtime (CLR) is not recommended for performance reasons."

Should we buy this answer like it would be "words from the Gospels"? I like the motto "trust but verify". One thing is sure, when we create a GraphBuilder object and run a stream through it, we end up creating a lot of threads and mixing native COM and managed code might not be an ideal mix for people who don't want to work more than what they have to get the job done.

So, we're not going to write filters in C#. But DirectShow client applications are an interesting possibility. The SDK already contains samples written in VB and there is no reason why we couldn't write similar applications in C#. So how do we go about it. There are a few samples at www.codeproject.com that use C# and DirectShow.

The easiest way to write a DirectShow client application is simply to wrap the library "quartz.dll" (with the tool tlbimp from the .Net SDK or by adding a reference to in a VS project). That's the easiest way but the methods we'd like might not be exposed this way. So we have a couple of alternatives. There a library called "FSFWrap.dll" that adds some of the missing APIs or we can look at DShowNet (available on the CodeProject web site).

Playing a file using DirectShow in C++ is illustrated in the SDK documentation as:

  2. #include <dshow.h>
  3. void main(void)
  4. {
  5. IGraphBuilder *pGraph = NULL;
  6. IMediaControl *pControl = NULL;
  7. IMediaEvent *pEvent = NULL;
  8. // Initialize the COM library.
  9. HRESULT hr = CoInitialize(NULL);
  10. if (FAILED(hr))
  11. {
  12. printf("ERROR - Could not initialize COM library");
  13. return;
  14. }
  15. // Create the filter graph manager and query for interfaces.
  16. hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
  17. IID_IGraphBuilder, (void **)&pGraph);
  18. if (FAILED(hr))
  19. {
  20. printf("ERROR - Could not create the Filter Graph Manager.");
  21. return;
  22. }
  23. hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
  24. hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
  25. // Build the graph. IMPORTANT: Change this string to a file on your system.
  26. hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
  27. if (SUCCEEDED(hr))
  28. {
  29. // Run the graph.
  30. hr = pControl->Run();
  31. if (SUCCEEDED(hr))
  32. {
  33. // Wait for completion.
  34. long evCode;
  35. pEvent->WaitForCompletion(INFINITE, &evCode);
  36. // Note: Do not use INFINITE in a real application, because it
  37. // can block indefinitely.
  38. }
  39. }
  40. pControl->Release();
  41. pEvent->Release();
  42. pGraph->Release();
  43. CoUninitialize();
  44. }

Here's is the equivalent code in C# using interop and quartz.dll:

  2. using System;
  3. using QuartzTypeLib;
  4. class PlayFile {
  5. public static void Main( string [] args ) {
  6. FilgraphManagerClass graphClass = null;
  7. try {
  8. graphClass = new FilgraphManagerClass();
  9. graphClass.RenderFile( args[0] );
  10. graphClass.Run();
  11. int evCode;
  12. graphClass.WaitForCompletion( -1, out evCode );
  13. } catch( Exception ) {}
  14. finally {
  15. graphClass = null;
  16. }
  17. }
  18. }

We declare the namespace QuartzTypeLib and we reference it on the command line (the command line to compile this program is: csc /r:Interop.QuartzTypeLib.dll PlayFile.cs). We passed the file name to play on the command line instead of hardcoding the name in the source as the example from the SDK. Also the first argument to WaitForCompletion is -1 because INFINITE is defined as 0xfffffff.

The interop version uses the FilgraphManagerClass to do all the work.

.Net Master (at CodeProject) decided that the COM interfaces for DirectShow are sufficiantly simple to write wrappers for them using the IDL provided with the SDK. The advantage of this approach is that you have more control on which members of the interfaces that you can access. The disadvantages are the code can be rather ugly and you have to think in term of native COM and managed code at the same time. Here is a C# version using DShowNet from .Net Master at CodeProject:

  2. using System;
  3. using System.Runtime.InteropServices;
  4. using DShowNET;
  5. class PlayFile {
  6. public static void Main( string [] args ) {
  7. IGraphBuilder graphBuilder = null;
  8. IMediaControl mediaCtrl = null;
  9. IMediaEvent mediaEvt = null;
  10. Type comtype = null;
  11. object comobj = null;
  12. try {
  13. comtype = Type.GetTypeFromCLSID( Clsid.FilterGraph );
  14. comobj = Activator.CreateInstance( comtype );
  15. graphBuilder = (IGraphBuilder) comobj; comobj = null;
  16. mediaCtrl = (IMediaControl) graphBuilder;
  17. mediaEvt = (IMediaEvent) graphBuilder;
  18. graphBuilder.RenderFile( args[0], null );
  19. mediaCtrl.Run();
  20. int evCode;
  21. mediaEvt.WaitForCompletion( -1, out evCode );
  22. }
  23. catch(Exception) {}
  24. finally {
  25. if( comobj != null )
  26. Marshal.ReleaseComObject( comobj );
  27. comobj = null;
  28. mediaCtrl = null;
  29. mediaEvt = null;
  30. graphBuilder = null;
  31. }
  32. }
  33. }

The call to GetTypeFromCLSID of the Type class, the call to CreateInstance of the Activator class and ReleaseComOjbect of the Marshall class are examples of what I meant by having to keep track of native COM and managed code. If the DShowNet implementation give you access to what you need but not the plain Quartz interop. Then DShowNet is the way to go.

At the moment, there is a Beta version of an open source extension to the DShowNet library. When the final version will be released, we'll look at the possibility to update our code using this new library.

We'll stop here for our first look at DirectShow and C#.

Bookmark it...
Next >
Joomla Template by Joomlashack
Joomla Templates by JoomlaShack Joomla Templates by Compass Design