选择压缩筛选器

多种软件组件可以执行视频或音频压缩,例如:

  • 本机DirectShow筛选器
  • 视频压缩管理器 (VCM) 编解码器
  • 音频压缩管理器 (ACM) 编解码器
  • DirectX 媒体对象 (DMO)

在DirectShow中,VCM 编解码器由 AVI 压缩器筛选器包装,ACM 编解码器由 ACM 包装器筛选器包装。 DMO 由DMO包装器筛选器包装。 系统设备枚举器提供一致的方法来枚举和创建其中的任何压缩器类型,而无需担心基础模型。

有关系统设备枚举器的详细信息,请参阅 使用系统设备枚举器。 简言之,所有DirectShow筛选器都按类别进行分类,每个类别由 GUID 标识。 对于视频压缩器,类别 GUID CLSID_VideoCompressorCategory。 对于音频压缩器,它CLSID_AudioCompressorCategory。 若要枚举特定类别,系统设备枚举器会创建一个支持 IEnumMoniker 接口的枚举器对象。 应用程序使用此接口检索设备名字对象,其中每个设备名字对象表示DirectShow筛选器的实例。 可以使用名字对象创建筛选器,或者无需创建筛选器即可获取设备的友好名称。

若要枚举用户系统上可用的视频或音频压缩器,请执行以下操作:

  1. 调用 CoCreateInstance 以创建系统设备枚举器,该枚举器具有类 ID CLSID_SystemDeviceEnum。
  2. 使用筛选器类别 GUID 调用 ICreateDevEnum::CreateClassEnumerator 。 该方法返回 IEnumMoniker 接口指针。
  3. 使用 IEnumMoniker::Next 方法枚举设备名字对象。 此方法返回一个 IMoniker 接口,该接口表示名字对象。

若要从名字对象获取友好名称,请执行以下操作:

  1. 调用 IMoniker::BindToStorage 方法。 此方法返回 IPropertyBag 接口指针。
  2. 使用 IPropertyBag::Read 方法读取 FriendlyName 属性。

通常,应用程序将显示压缩器列表,以便用户可以选择一个。 例如,以下代码使用可用视频压缩器的名称填充列表框。

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();
}

若要从名字对象创建筛选器实例,请调用 IMoniker::BindToObject 方法。 该方法返回 IBaseFilter 指针。

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

对于 VCM 编解码器,每个名字对象都表示一个特定的编解码器,即使所有编解码器都由同一个 AVI 压缩筛选器包装。 调用 BindToObject 会创建为此编解码器初始化的此筛选器的实例。 因此,不能直接在 AVI 压缩筛选器上调用 CoCreateInstance 。 必须通过系统设备枚举器。

重新压缩 AVI 文件