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:

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;
}
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
Thanks for the code!
Comment by 1 — March 31, 2008 @ 7:26 pm