Microsoft DirectX 8.0

How to Register DirectShow Filters

This article describes how to make a Microsoft® DirectShow® filter self-registering. It contains the following sections:

This article does not describe how to create a DLL. For information on creating DLLs, see How to Create a DLL.

Layout of the Registry Keys

DirectShow filters are registered in two places:

The registry entry for the DLL is:

HKEY_CLASSES_ROOT
    CLSID
        Filter CLSID
            REG_SZ: (Default) = Friendly name

            InprocServer32
                REG_SZ: (Default) = File name of the DLL
                REG_SZ: ThreadingModel = Both

The registry entry for the filter information is:

HKEY_CLASSES_ROOT
    CLSID
        Category
            Instance
                Filter CLSID
                    REG_SZ: CLSID = Filter CLSID
                    REG_BINARY: Filter Data = Filter information
                    REG_SZ: FriendlyName = Friendly name

Category is the GUID of a filter category. The filter information is packed into a binary format. The IFilterMapper2 interface unpacks this data when it searches the registry for a filter.

Registering a Filter

To register a filter, perform the following steps:

  1. Declare filter information.
  2. In the factory template for the filter, include a pointer to the filter information.
  3. Implement the DllRegisterServer function.

The sections that follow describe these steps in detail.

Declare Filter Information

The first step is to declare the filter information. DirectShow defines a set of structures for describing filters, pins, and media types:

AMOVIESETUP_FILTERDescribes a filter.
AMOVIESETUP_PINDescribes a pin.
AMOVIESETUP_MEDIATYPEDescribes a media type.

These structures are nested. The filter structure has a pointer to an array of pin structures, and each pin structure has a pointer to an array of media-type structures. The structures provide enough information for the IFilterMapper2 interface to locate a filter. They are not a complete description of a filter. For example, if the filter creates multiple instances of the same pin, you should declare only one AMOVIESETUP_PIN structure for that pin. Also, a filter is not required to support every combination of media types that it registers.

Declare the set-up structures as global variables within your DLL. The following example shows a filter with one output pin:

static const WCHAR g_wszName[] = L"Some Filter";

AMOVIESETUP_MEDIATYPE sudMediaTypes[] = {
    { &MEDIATYPE_Video, &MEDIASUBTYPE_RGB24 },
    { &MEDIATYPE_Video, &MEDIASUBTYPE_RGB32 },
};

AMOVIESETUP_PIN sudOutputPin = {
    L"",            // Obsolete, not used.
    FALSE,          // Is this pin rendered?
    TRUE,           // Is it an output pin?
    FALSE,          // Can the filter create zero instances?
    FALSE,          // Does the filter create multiple instances?
    &GUID_NULL,     // Obsolete.
    NULL,           // Obsolete.
    2,              // Number of media types.
    sudMediaTypes   // Pointer to media types.
};

AMOVIESETUP_FILTER sudFilterReg = {
    &CLSID_SomeFilter,      // Filter CLSID.
    g_wszName,              // Filter name.
    MERIT_NORMAL,           // Merit.
    1,                      // Number of pin types.
    &sudPins                // Pointer to pin information.
};

The filter name is declared as a static global variable, because it will be used again elsewhere.

Declare the Factory Template

The next step is to declare the factory template for your filter. A factory template is a C++ class that contains information for the class factory. In your DLL, declare a global array of factory templates, one for each filter or COM component in your DLL. The array must be named g_Templates. For more information about factory templates, see How to Create a DLL.

The m_pAMovieSetup_Filter member of the factory template is a pointer to the AMOVIESETUP_FILTER structure described previously. The following example shows a factory template, using the structure given in the previous example:

CFactoryTemplate g_Templates[] =
{
    {
        g_wszName,                      // Name.
        &CLSID_SomeFilter,              // CLSID.
        CSomeFilter::CreateInstance,    // Creation function.
        NULL,
        &sudFilterReg                   // Pointer to filter information.
    }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

Implement DllRegisterServer

The final step is to implement the DllRegisterServer function. The DLL that contains the component must export this function. The function will be called by a set-up application, or when the user runs the Regsvr32.exe tool.

The following example shows a minimal implementation of DlLRegisterServer:

STDAPI DllRegisterServer(void)
{
    return AMovieDllRegisterServer2(TRUE);
}

The DirectShow function AMovieDllRegisterServer2 creates registry entries for every component in the g_Templates array. However, this function has some limitations. First, it assigns every filter to the CLSID_LegacyAmFilterCategory category. Not all filters belong in this category. Capture filters and compression filters, for example, have their own categories. (For a list of categories, see Filter Categories.) Second, if your filter supports a hardware device, you might need to register two pieces of information that AMovieDLLRegisterServer2 does not handle: the medium and the pin category. A medium defines a method of communication in a hardware device, such as a bus. The pin category defines the function of a pin. For information on mediums, see KSPIN_MEDIUM in the Microsoft® Windows® Driver Development Kit (DDK). For a list of pin categories, see Pin Property Set.

If you want to specify the filter category, the medium, or the pin category, call the IFilterMapper2::RegisterFilter method from within DllRegisterServer. This method takes a pointer to a REGFILTER2 structure, which specifies information about the filter.

To complicate matters somewhat, the REGFILTER2 structure supports two different formats for registering pins. The dwVersion member specifies the format:

The REGFILTERPINS2 structure includes entries for pin mediums and pin categories. Also, it uses bit flags for some items that AMOVIESETUP_PIN declares as Boolean values.

The following example shows how to call IFilterMapper2::RegisterFilter from inside DllRegisterServer:

REGFILTER2 rf2FilterReg = {
    1,              // Version 1 (no pin mediums or pin category).
    MERIT_NORMAL,   // Merit.
    1,              // Number of pins.
    &sudPins        // Pointer to pin information.
};

STDAPI DllRegisterServer(void)
{
    HRESULT hr;
    IFilterMapper2 *pFM2 = NULL;

    hr = AMovieDllRegisterServer2(TRUE);
    if (FAILED(hr))
        return hr;

    hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
            IID_IFilterMapper2, (void **)&pFM2);

    if (FAILED(hr))
        return hr;

    hr = pFM2->RegisterFilter(
        CLSID_SomeFilter,                // Filter CLSID. 
        g_wszName,                       // Filter name.
        NULL,                            // Device moniker. 
        &CLSID_VideoCompressorCategory,  // Video compressor category.
        g_wszName,                       // Instance data.
        &rf2FilterReg                    // Pointer to filter information.
    );
    pFM2->Release();
    return hr;
}

Unregistering a Filter

To unregister a filter, implement the DllUnregisterServer function. Within this function, call the DirectShow AMovieDllRegisterServer2 function with a value of FALSE. If you called IFilterMapper2::RegisterFilter when you registered the filter, call the IFilterMapper2::UnregisterFilter method here.

The following example shows how to unregister a filter:

STDAPI DllUnregisterServer()
{
    HRESULT hr;
    IFilterMapper2 *pFM2 = NULL;

    hr = AMovieDllRegisterServer2(FALSE);
    if (FAILED(hr))
        return hr;
 
    hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
            IID_IFilterMapper2, (void **)&pFM2);

    if (FAILED(hr))
        return hr;

    hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory, 
            g_wszName, CLSID_SomeFilter);

    pFM2->Release();
    return hr;
}