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


Выбор устройства захвата

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

Чтобы выбрать устройство аудио- или видеозахвата, используйте перечислитель системных устройств, описанный в разделе Использование перечислителя системных устройств. Перечислитель системных устройств возвращает коллекцию моникеров устройств, выбранных по категории устройства. Моникер — это COM-объект, содержащий сведения о другом объекте. Моникеры позволяют приложению получать сведения об объекте без фактического создания объекта. Позже приложение может использовать моникер для создания объекта . Дополнительные сведения о моникерах см. в документации по IMoniker.

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

  1. Вызовите CoCreateInstance , чтобы создать экземпляр перечислителя системных устройств.

  2. Вызовите метод ICreateDevEnum::CreateClassEnumerator и укажите категорию устройства в качестве GUID. Для устройств записи относятся следующие категории.

    GUID категории Описание
    CLSID_AudioInputDeviceCategory Устройства записи звука
    CLSID_VideoInputDeviceCategory Устройства захвата видео

     

    Если видеокамера имеет встроенный микрофон, она отображается в обеих категориях. Однако камера и микрофон рассматриваются системой как отдельные устройства для целей перечисления, создания устройства и потоковой передачи данных.

  3. Метод CreateClassEnumerator возвращает указатель на интерфейс IEnumMoniker . Чтобы перечислить моникеры, вызовите IEnumMoniker::Next.

Следующий код создает перечислитель для указанной категории устройств.

#include <windows.h>
#include <dshow.h>

#pragma comment(lib, "strmiids")

HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
    // Create the System Device Enumerator.
    ICreateDevEnum *pDevEnum;
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,  
        CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));

    if (SUCCEEDED(hr))
    {
        // Create an enumerator for the category.
        hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
        if (hr == S_FALSE)
        {
            hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.
        }
        pDevEnum->Release();
    }
    return hr;
}

Интерфейс IEnumMoniker перечисляет список интерфейсов IMoniker , каждый из которых представляет моникер устройства. Приложение может считывать свойства из моникера или использовать моникер для создания фильтра захвата DirectShow для устройства. Свойства моникера возвращаются в виде значений VARIANT . Следующие свойства поддерживаются моникерами устройств.

Свойство Описание Тип VARIANT
"FriendlyName" Название устройства. VT_BSTR
"Описание" Описание устройства. VT_BSTR
DevicePath Уникальная строка, идентифицирующая устройство. (Только для устройств захвата видео.) VT_BSTR
"WaveInID" Идентификатор устройства аудиозахвата. (Только для устройств записи звука.) VT_I4

 

Свойства FriendlyName и Description подходят для отображения в пользовательском интерфейсе.

  • Свойство FriendlyName доступно для каждого устройства. Он содержит понятное имя устройства.
  • Свойство Description доступно только для устройств dv и D-VHS/MPEG camcorder. Дополнительные сведения см. в разделах Драйвер MSDV и Драйвер MSTape. Если доступно, оно содержит описание устройства, которое более конкретно, чем свойство FriendlyName. Как правило, он включает имя поставщика.
  • Свойство DevicePath не является удобочитаемой строкой, но гарантированно будет уникальным для каждого устройства захвата видео в системе. Это свойство можно использовать для различения двух или более экземпляров одной модели устройства.
  • Если свойство WaveInID присутствует, это означает, что фильтр захвата DirectShow использует API-интерфейсы Waveform Audio для взаимодействия с устройством. Значение свойства WaveInID соответствует идентификатору, используемому функциями waveIn* , например waveInOpen.

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

  1. Вызовите метод IMoniker::BindToStorage , чтобы получить указатель на интерфейс IPropertyBag .
  2. Вызовите метод IPropertyBag::Read , чтобы прочитать свойство .

В следующем примере кода показано, как перечислить список моникеров устройств и получить свойства.

void DisplayDeviceInformation(IEnumMoniker *pEnum)
{
    IMoniker *pMoniker = NULL;

    while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
    {
        IPropertyBag *pPropBag;
        HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
        if (FAILED(hr))
        {
            pMoniker->Release();
            continue;  
        } 

        VARIANT var;
        VariantInit(&var);

        // Get description or friendly name.
        hr = pPropBag->Read(L"Description", &var, 0);
        if (FAILED(hr))
        {
            hr = pPropBag->Read(L"FriendlyName", &var, 0);
        }
        if (SUCCEEDED(hr))
        {
            printf("%S\n", var.bstrVal);
            VariantClear(&var); 
        }

        hr = pPropBag->Write(L"FriendlyName", &var);

        // WaveInID applies only to audio capture devices.
        hr = pPropBag->Read(L"WaveInID", &var, 0);
        if (SUCCEEDED(hr))
        {
            printf("WaveIn ID: %d\n", var.lVal);
            VariantClear(&var); 
        }

        hr = pPropBag->Read(L"DevicePath", &var, 0);
        if (SUCCEEDED(hr))
        {
            // The device path is not intended for display.
            printf("Device path: %S\n", var.bstrVal);
            VariantClear(&var); 
        }

        pPropBag->Release();
        pMoniker->Release();
    }
}

void main()
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (SUCCEEDED(hr))
    {
        IEnumMoniker *pEnum;

        hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
        if (SUCCEEDED(hr))
        {
            DisplayDeviceInformation(pEnum);
            pEnum->Release();
        }
        hr = EnumerateDevices(CLSID_AudioInputDeviceCategory, &pEnum);
        if (SUCCEEDED(hr))
        {
            DisplayDeviceInformation(pEnum);
            pEnum->Release();
        }
        CoUninitialize();
    }
}

Чтобы создать фильтр захвата DirectShow для устройства, вызовите метод IMoniker::BindToObject , чтобы получить указатель IBaseFilter . Затем вызовите IFilterGraph::AddFilter , чтобы добавить фильтр в граф фильтра:

IBaseFilter *pCap = NULL;
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (SUCCEEDED(hr))
{
    hr = m_pGraph->AddFilter(pCap, L"Capture Filter");
}

Захват звука

Захват видео