Choosing a Compression Filter

[The feature associated with this page, DirectShow, is a legacy feature. It has been superseded by MediaPlayer, IMFMediaEngine, and Audio/Video Capture in Media Foundation. Those features have been optimized for Windows 10 and Windows 11. Microsoft strongly recommends that new code use MediaPlayer, IMFMediaEngine and Audio/Video Capture in Media Foundation instead of DirectShow, when possible. Microsoft suggests that existing code that uses the legacy APIs be rewritten to use the new APIs if possible.]

Several types of software components can perform video or audio compression, such as:

  • Native DirectShow filters
  • Video Compression Manager (VCM) codecs
  • Audio Compression Manager (ACM) codecs
  • DirectX Media Objects (DMOs)

In DirectShow, VCM codecs are wrapped by the AVI Compressor Filter, and ACM codecs are wrapped by the ACM Wrapper Filter. DMOs are wrapped by the DMO Wrapper Filter. The system device enumerator provides a consistent way to enumerate and create any of these compressor types, without worrying about the underlying model.

For details about the system device enumerator, see Using the System Device Enumerator. Briefly, all DirectShow filters are classified by category, and each category is identified by a GUID. For video compressors, the category GUID is CLSID_VideoCompressorCategory. For audio compressors, it is CLSID_AudioCompressorCategory. To enumerate a particular category, the system device enumerator creates an enumerator object that supports the IEnumMoniker interface. The application uses this interface to retrieve device monikers, where each device moniker represents an instance of a DirectShow filter. You can use the moniker to create the filter, or to get the device's friendly name without creating the filter.

To enumerate the video or audio compressors available on the user's system, do the following:

  1. Call CoCreateInstance to create the system device enumerator, which has a class ID of CLSID_SystemDeviceEnum.
  2. Call ICreateDevEnum::CreateClassEnumerator with the filter category GUID. The method returns an IEnumMoniker interface pointer.
  3. Use the IEnumMoniker::Next method to enumerate the device monikers. This method returns an IMoniker interface, which represents the moniker.

To get the friendly name from a moniker, do the following:

  1. Call the IMoniker::BindToStorage method. This method returns an IPropertyBag interface pointer.
  2. Use the IPropertyBag::Read method to read the FriendlyName property.

Typically, an application would display a list of compressors, so that the user could choose one. For example, the following code populates a list box with the names of the available video compressors.

void OnInitDialog(HWND hDlg)
{
    HRESULT hr;
    ICreateDevEnum *pSysDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    IMoniker *pMoniker = NULL;

    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, 
        CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, 
        (void**)&pSysDevEnum);
    if (FAILED(hr))
    {
        // Handle the error.
    }    

    hr = pSysDevEnum->CreateClassEnumerator(
             CLSID_VideoCompressorCategory, &pEnum, 0);
    if (hr == S_OK)  // S_FALSE means nothing in this category.
    {
        while (S_OK == pEnum->Next(1, &pMoniker, NULL))
        {
            IPropertyBag *pPropBag = NULL;
            pMoniker->BindToStorage(0, 0, IID_IPropertyBag, 
                (void **)&pPropBag);
            VARIANT var;
            VariantInit(&var);
            hr = pPropBag->Read(L"FriendlyName", &var, 0);
            if (SUCCEEDED(hr))
            {
                LRESULT iSel = AddString(GetDlgItem(hDlg, 
                    IDC_CODEC_LIST), var.bstrVal);
            }   
            VariantClear(&var); 
            pPropBag->Release();
            pMoniker->Release();
        }
    }

    SendDlgItemMessage(hDlg, IDC_CODEC_LIST, 
                       LB_SETCURSEL, 0, 0);
    pSysDevEnum->Release();
    pEnum->Release();
}

To create a filter instance from the moniker, call the IMoniker::BindToObject method. The method returns an IBaseFilter pointer.

IBaseFilter *pFilter = NULL;
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, 
                                       (void**)&pFilter);
if (SUCCEEDED(hr))
{
    // Use the filter. 
    // Remember to release the IBaseFilter interface.
}

For VCM codecs, each moniker represents one particular codec, even though all of the codecs are wrapped by the same AVI Compression filter. Calling BindToObject creates an instance of this filter, initialized for that codec. For this reason, you cannot call CoCreateInstance directly on the AVI Compression filter. You must go through the system device enumerator.

Recompressing an AVI File