Поделиться через


Выбор фильтра сжатия

[Функция, связанная с этой страницей DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngine, и аудио/ видео захвата в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать в новом коде MediaPlayer, IMFMediaEngine и аудио/видеозахват в Media Foundation вместо DirectShow, когда это возможно. Корпорация Майкрософт предлагает переписать существующий код, в котором используются устаревшие API, чтобы по возможности использовать новые API.]

Некоторые типы программных компонентов могут выполнять сжатие видео или звука, например:

  • Собственные фильтры DirectShow
  • Кодеки диспетчера сжатия видео (VCM)
  • Кодеки диспетчера сжатия аудио (ACM)
  • Объекты мультимедиа DirectX (DMOS)

В DirectShow кодеки VCM упаковываются фильтром компрессора AVI, а кодеки ACM — фильтром-оболочкой ACM. Объекты dmos упаковываются фильтром-оболочкой DMO. Перечислитель системных устройств предоставляет согласованный способ перечисления и создания любого из этих типов компрессоров, не беспокоясь о базовой модели.

Дополнительные сведения о перечислителях системных устройств см. в разделе Использование перечислителя системных устройств. Вкратце, все фильтры DirectShow классифицируются по категориям, а каждая категория определяется с помощью GUID. Для видеокомпрессоров GUID категории CLSID_VideoCompressorCategory. Для аудиокомпрессоров это CLSID_AudioCompressorCategory. Чтобы перечислить определенную категорию, перечислитель системного устройства создает объект перечислителя , поддерживающий интерфейс IEnumMoniker . Приложение использует этот интерфейс для получения моникеров устройства, где каждое моникер устройства представляет экземпляр фильтра DirectShow. Вы можете использовать моникер для создания фильтра или для получения понятного имени устройства без создания фильтра.

Чтобы перечислить видео- или аудиокомпрессоры, доступные в системе пользователя, сделайте следующее:

  1. Вызовите CoCreateInstance , чтобы создать перечислитель системного устройства с идентификатором класса CLSID_SystemDeviceEnum.
  2. Вызовите метод ICreateDevEnum::CreateClassEnumerator с guid категории фильтра. Метод возвращает указатель интерфейса 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 создает экземпляр этого фильтра, инициализированный для этого кодека. По этой причине нельзя вызвать CoCreateInstance непосредственно в фильтре сжатия AVI. Необходимо пройти через перечислитель системных устройств.

Повторное сжатие файла AVI