Captura de áudio/vídeo no Media Foundation

O Microsoft Media Foundation oferece suporte à captura de áudio e vídeo. Os dispositivos de captura de vídeo são suportados através do driver da classe UVC e devem ser compatíveis com o UVC 1.1. Os dispositivos de captura de áudio são suportados através da API de Sessão de Áudio do Windows (WASAPI).

Um dispositivo de captura é representado no Media Foundation por um objeto de origem de mídia, que expõe a interface IMFMediaSource. Na maioria dos casos, o aplicativo não usará essa interface diretamente, mas usará uma API de nível superior, como o Leitor de código-fonte , para controlar o dispositivo de captura.

Enumerar dispositivos de captura

Para enumerar os dispositivos de captura no sistema, execute as seguintes etapas:

  1. Chame a função MFCreateAttributes para criar um repositório de atributos.

  2. Defina o atributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE para um dos seguintes valores:

    Valor Descrição
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID Enumerar dispositivos de captura de áudio.
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID Enumerar dispositivos de captura de vídeo.

     

  3. Chame a função MFEnumDeviceSources. Essa função aloca uma matriz de ponteiros IMFActivate. Cada ponteiro representa um objeto de ativação para um dispositivo no sistema.

  4. Chame o método IMFActivate::ActivateObject para criar uma instância da fonte de mídia de um dos objetos de ativação.

O exemplo a seguir cria uma fonte de mídia para o primeiro dispositivo de captura de vídeo na lista de enumeração:

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

Você pode consultar os objetos de ativação para vários atributos, incluindo o seguinte:

O exemplo a seguir usa uma matriz de ponteiros IMFActivate e imprime o nome de exibição de cada dispositivo na janela de depuração:

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

Se você já conhece o link simbólico para um dispositivo de vídeo, há outra maneira de criar a fonte de mídia para o dispositivo:

  1. Chame MFCreateAttributes para criar um repositório de atributos.
  2. Defina o atributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE como MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID.
  3. Defina o atributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK para o link simbólico.
  4. Chame a função MFCreateDeviceSource ou MFCreateDeviceSourceActivate. O primeiro retorna um ponteiro IMFMediaSource. Este último retorna um ponteiro IMFActivate para um objeto de ativação. Você pode usar o objeto de ativação para criar a origem. (Um objeto de ativação pode ser empacotado para outro processo, portanto, é útil se você quiser criar a origem em outro processo. Para obter mais informações, consulte Objetos de ativação.)

O exemplo a seguir usa o link simbólico de um dispositivo de vídeo e cria uma fonte de mídia.

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

Há uma maneira equivalente de criar um dispositivo de áudio a partir do ID do ponto de extremidade de áudio:

  1. Chame MFCreateAttributes para criar um repositório de atributos.
  2. Defina o atributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE como MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID.
  3. Defina o atributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID para o ID do ponto de extremidade.
  4. Chame a função MFCreateDeviceSource ou MFCreateDeviceSourceActivate.

O exemplo a seguir usa uma ID de ponto de extremidade de áudio e cria uma fonte de mídia.

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

Usar um dispositivo de captura

Depois de criar a fonte de mídia para um dispositivo de captura, use o Leitor de código-fonte para obter dados do dispositivo. O Leitor de Origem fornece amostras de mídia que contêm os dados de áudio de captura ou quadros de vídeo. A próxima etapa depende do cenário do aplicativo:

  • Visualização de vídeo: use o Microsoft Direct3D ou Direct2D para exibir o vídeo.
  • Captura de arquivo: use o Sink Writer para codificar o arquivo.
  • Pré-visualização de áudio: Use WASAPI.

Se você quiser combinar a captura de áudio com a captura de vídeo, use a fonte de mídia agregada. A fonte de mídia agregada contém uma coleção de fontes de mídia e combina todos os seus fluxos em um único objeto de fonte de mídia. Para criar uma instância da fonte de mídia agregada, chame a função MFCreateAggregateSource.

Desligue o dispositivo de captura

Quando o dispositivo de captura não for mais necessário, você deverá desligá-lo chamando Shutdown no objeto IMFMediaSource obtido chamando MFCreateDeviceSource ou IMFActivate::ActivateObject. A falha ao chamar o desligamento pode resultar em vazamentos de memória porque o sistema pode manter uma referência aos recursos do IMFMediaSource até que o desligamento seja chamado.

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

Se você alocou uma cadeia de caracteres contendo o link simbólico para um dispositivo de captura, você deve liberar esse objeto também.

    CoTaskMemFree(g_pwszSymbolicLink);
    g_pwszSymbolicLink = NULL;

    g_cchSymbolicLink = 0;

Captura de áudio/vídeo