Аудио-видеозахват в Media Foundation

Microsoft Media Foundation поддерживает звук и видеозахват. Устройства записи видео поддерживаются с помощью драйвера класса UVC и должны быть совместимы с UVC 1.1. Устройства записи звука поддерживаются через API сеанса звука Windows (WASAPI).

Устройство захвата представлено в Media Foundation объектом источника мультимедиа, который предоставляет интерфейс IMFMediaSource. В большинстве случаев приложение не будет использовать этот интерфейс напрямую, но будет использовать API более высокого уровня, например средство чтения источников для управления устройством записи.

Перечисление устройств записи

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

  1. Вызовите функцию MFCreateAttributes, чтобы создать хранилище атрибутов.

  2. Задайте для атрибута MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE одно из следующих значений:

    значение Описание
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID Перечисление устройств записи звука.
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID Перечисление устройств записи видео.

     

  3. Вызовите функцию MFEnumDeviceSources . Эта функция выделяет массив указателей IMFActivate. Каждый указатель представляет объект активации для одного устройства в системе.

  4. Вызовите метод IMFActivate::ActivateObject, чтобы создать экземпляр источника мультимедиа из одного из объектов активации.

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

HRESULT CreateVideoCaptureDevice(IMFMediaSource **ppSource)
{
    *ppSource = NULL;

    UINT32 count = 0;

    IMFAttributes *pConfig = NULL;
    IMFActivate **ppDevices = NULL;

    // Create an attribute store to hold the search criteria.
    HRESULT hr = MFCreateAttributes(&pConfig, 1);

    // Request video capture devices.
    if (SUCCEEDED(hr))
    {
        hr = pConfig->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, 
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
            );
    }

    // Enumerate the devices,
    if (SUCCEEDED(hr))
    {
        hr = MFEnumDeviceSources(pConfig, &ppDevices, &count);
    }

    // Create a media source for the first device in the list.
    if (SUCCEEDED(hr))
    {
        if (count > 0)
        {
            hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(ppSource));
        }
        else
        {
            hr = MF_E_NOT_FOUND;
        }
    }

    for (DWORD i = 0; i < count; i++)
    {
        ppDevices[i]->Release();
    }
    CoTaskMemFree(ppDevices);
    return hr;
}

Объекты активации можно запрашивать для различных атрибутов, включая следующие:

  • Атрибут MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME содержит отображаемое имя устройства. Отображаемое имя подходит для отображения пользователю, но может быть не уникальным.
  • Для видеоустройств атрибут MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SY МБ OLIC_LINK содержит символьную ссылку на устройство. Символьная ссылка однозначно идентифицирует устройство в системе, но не является читаемой строкой.
  • Для звуковых устройств атрибут MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID содержит идентификатор конечной точки звука устройства. Идентификатор конечной точки звука похож на символьную ссылку. Он однозначно идентифицирует устройство в системе, но не является читаемой строкой.

Следующий пример принимает массив указателей IMFActivate и выводит отображаемое имя каждого устройства в окно отладки:

void DebugShowDeviceNames(IMFActivate **ppDevices, UINT count)
{
    for (DWORD i = 0; i < count; i++)
    {
        HRESULT hr = S_OK;
        WCHAR *szFriendlyName = NULL;
    
        // Try to get the display name.
        UINT32 cchName;
        hr = ppDevices[i]->GetAllocatedString(
            MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
            &szFriendlyName, &cchName);

        if (SUCCEEDED(hr))
        {
            OutputDebugString(szFriendlyName);
            OutputDebugString(L"\n");
        }
        CoTaskMemFree(szFriendlyName);
    }
}

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

  1. Вызовите MFCreateAttributes для создания хранилища атрибутов.
  2. Задайте для атрибута MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE значение MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID.
  3. Задайте для атрибута MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SY МБ OLIC_LINK символьную ссылку.
  4. Вызовите функцию MFCreateDeviceSource или MFCreateDeviceSourceActivate. Бывший возвращает указатель IMFMediaSource. Последний возвращает указатель МВФActivate на объект активации. Объект активации можно использовать для создания источника. (Объект активации можно маршалировать в другой процесс, поэтому полезно создать источник в другом процессе. Дополнительные сведения см. в разделе "Объекты активации".)

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

HRESULT CreateVideoCaptureDevice(PCWSTR *pszSymbolicLink, IMFMediaSource **ppSource)
{
    *ppSource = NULL;
    
    IMFAttributes *pAttributes = NULL;
    IMFMediaSource *pSource = NULL;

    HRESULT hr = MFCreateAttributes(&pAttributes, 2);

    // Set the device type to video.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
            );
    }


    // Set the symbolic link.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetString(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
            (LPCWSTR)pszSymbolicLink
            );            
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateDeviceSource(pAttributes, ppSource);
    }

    SafeRelease(&pAttributes);
    return hr;    
}

Существует эквивалентный способ создания звукового устройства из идентификатора конечной точки аудио:

  1. Вызовите MFCreateAttributes для создания хранилища атрибутов.
  2. Задайте для атрибута MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE значение MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID.
  3. Задайте для атрибута MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID идентификатор конечной точки.
  4. Вызовите функцию MFCreateDeviceSource или MFCreateDeviceSourceActivate.

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

HRESULT CreateAudioCaptureDevice(PCWSTR *pszEndPointID, IMFMediaSource **ppSource)
{
    *ppSource = NULL;
    
    IMFAttributes *pAttributes = NULL;
    IMFMediaSource *pSource = NULL;

    HRESULT hr = MFCreateAttributes(&pAttributes, 2);

    // Set the device type to audio.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID
            );
    }

    // Set the endpoint ID.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetString(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID,
            (LPCWSTR)pszEndPointID
            ); 
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateDeviceSource(pAttributes, ppSource);
    }

    SafeRelease(&pAttributes);
    return hr;    
}

Использование устройства записи

После создания источника мультимедиа для устройства записи используйте средство чтения источника для получения данных с устройства. Средство чтения источника предоставляет примеры мультимедиа, содержащие звуковые данные или видеокадры. Следующий шаг зависит от сценария приложения:

  • Предварительная версия видео: используйте Microsoft Direct3D или Direct2D для отображения видео.
  • Запись файлов: используйте модуль записи приемника для кодирования файла.
  • Предварительный просмотр звука: используйте WASAPI.

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

Завершение работы устройства записи

Если устройство захвата больше не требуется, необходимо завершить работу устройства, вызвав завершение работы объекта IMFMediaSource, полученного путем вызова MFCreateDeviceSource или МВФActivate::ActivateObject. Сбой вызова завершения работы может привести к утечкам памяти, так как система может держать ссылку на ресурсы МВФMediaSource до вызова завершения работы.

if (g_pSource)
{
    g_pSource->Shutdown();
    g_pSource->Release();
    g_pSource = NULL;
}

Если вы выделили строку, содержащую символьную ссылку на устройство захвата, вы также должны освободить этот объект.

    CoTaskMemFree(g_pwszSymbolicLink);
    g_pwszSymbolicLink = NULL;

    g_cchSymbolicLink = 0;

Звук и видеозахват