6581 Useful Things

October 12, 2006

Instantiating Directshow filters by name

Filed under: DirectShow — sid6581 @ 9:43 pm

One of the most basic things you need to do in a DirectShow application is add filters to a graph. If it is a basic stock filter you can usually find the CLSID in MSDN, and creating the filter is as easy instantiating it as a regular COM object from that CLSID.

If you fire up GraphEdit on your system you’ll probably find a whole bunch of different filters that aren’t mentioned in MSDN. For instance, in the video compressor category there are several interesting filters:

GraphEdit Video Compressors List

It is important to remember that not all filters are supported by third party applications, and some filters may be unusable without having access to custom interfaces to configure and control them. Some filters (notably MPEG encoders and decoders) may have license restrictions preventing their use from your application without your paying license fees. Nevertheless, there are several cases where you will need to use a filter for which you don’t have a CLSID. Maybe you know the name of a filter that will work, or you’d like to give the user the choice of using third-party filters he has installed on his system.

One easy way to find such filters is to enumerate them and look for the specific filter you need. Below are a couple of helper functions that will assist you with that. They will show you how to enumerate filters by category and match them by name, and instantiate and add the matched filter to a filter graph.

As an example of how to use these functions, this code snippet instantiates the Microsoft MPEG4 V2 compressor and adds it to the filter graph:

   CComPtr compressor; 
   AddFilter(filtergraph, L"Microsoft MPEG-4 Video Codec V2", &compressor, 
      CLSID_VideoCompressorCategory, L"VideoCompressor");

The category list can be found in MSDN under the topic Filter Categories.

And here are the functions:

/// 
/// Create a filter by category and name, and add it to a filter 
/// graph. Will enumerate all filters of the given category and 
/// add the filter whose name matches, if any. If the filter could be 
/// created but not added to the graph, the filter is destroyed. 
/// 
/// @param Graph Filter graph. 
/// @param Name of filter to create. 
/// @param Filter Receives a pointer to the filter. 
/// @param FilterCategory Filter category. 
/// @param NameInGraph Name for the filter in the graph, or 0 for no 
/// name. 
/// 
/// @return true if successful. 
bool AddFilter(IFilterGraph *Graph, const WCHAR *Name, 
   IBaseFilter **Filter, REFCLSID FilterCategory, 
   const WCHAR *NameInGraph) 
{ 
   assert(Graph); 
   assert(Name); 
   assert(Filter); 
   assert(!*Filter);   

   if (!CreateFilter(Name, Filter, FilterCategory)) 
      return false;   

   if (FAILED(Graph->AddFilter(*Filter, NameInGraph))) 
   { 
      (*Filter)->Release(); 
      *Filter = 0; 
      return false; 
   }   

   return true; 
}   

/// 
/// Create a filter by category and name. Will enumerate all filters 
/// of the given category and return the filter whose name matches, 
/// if any. 
/// 
/// @param Name of filter to create. 
/// @param Filter Will receive the pointer to the interface 
/// for the created filter. 
/// @param FilterCategory Filter category. 
/// 
/// @return true if successful. 
bool CreateFilter(const WCHAR *Name, IBaseFilter **Filter, 
   REFCLSID FilterCategory) 
{ 
   assert(Name); 
   assert(Filter); 
   assert(!*Filter);    

   HRESULT hr;    

   // Create the system device enumerator. 
   CComPtr<ICreateDevEnum> devenum; 
   hr = devenum.CoCreateInstance(CLSID_SystemDeviceEnum); 
   if (FAILED(hr)) 
      return false;    

   // Create an enumerator for this category. 
   CComPtr<IEnumMoniker> classenum; 
   hr = devenum->CreateClassEnumerator(FilterCategory, &classenum, 0); 
   if (hr != S_OK) 
      return false;    

   // Find the filter that matches the name given. 
   CComVariant name(Name); 
   CComPtr<IMoniker> moniker; 
   while (classenum->Next(1, &moniker, 0) == S_OK) 
   { 
      CComPtr<IPropertyBag> properties; 
      hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&properties); 
      if (FAILED(hr)) 
         return false;    

      CComVariant friendlyname; 
      hr = properties->Read(L"FriendlyName", &friendlyname, 0); 
      if (FAILED(hr)) 
         return false;    

      if (name == friendlyname) 
      { 
         hr = moniker->BindToObject(0, 0, IID_IBaseFilter, (void **)Filter); 
         return SUCCEEDED(hr); 
      }    

      moniker.Release(); 
   }    

   // Couldn't find a matching filter. 
   return false; 
}
Advertisements

4 Comments »

  1. Very usefull thing indeed 🙂

    I wasted a lot of time until I found this.
    Earlier I thought that the filter GUID is unique but it is not.
    For example many filters use CLSID_AVIco as GUID.

    Even GrapheditPlus generates non working code when it relies on GUIDs.
    This is also a DirectShow filter problem
    – it is not very good practice to use friendly name as a unique identifier of a filter –
    but we seem to have no choice.

    One thing I noticed when playing with filters is that many video and audio compressors
    register themselves into CLSID_LegacyAmFilterCategory instead CLSID_VideoCompressorCategory
    or CLSID_AudioCompressorCategory, so I made it like this:

    HRESULT hr = CreateFilter(Name, Filter, FilterCategory);
    // If not found from specified category use legacy category
    if (!SUCCEEDED(hr))
    {
    hr = CreateFilter(Name, Filter, CLSID_LegacyAmFilterCategory);
    if (!SUCCEEDED(hr))
    {
    return hr;
    }
    }

    Comment by Pekka — March 26, 2008 @ 2:37 am

  2. Thanks for the code!

    Comment by 1 — March 31, 2008 @ 7:26 pm

  3. I can find my filter with your method in this article, but CoCreateInstance is failed. What seems to be wrong here ?

    Comment by Nick — July 9, 2013 @ 8:23 am

  4. u6bcfu6b21u8981u8c03u6765u8c03u53bbu5c31u5f88u4f24u5fc3uff0cu8fdeu7740u4e0au73edu611fu89c9u81eau5df1u50cfu52a8u7269uff0cu957fu5047u90a3u91ccu90fdu662f Click http://pepij.nl/succeaa100645

    Comment by marcelinakerr49075 — April 9, 2016 @ 4:47 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: