媒體基礎中的音訊/視訊擷取

Microsoft Media Foundation 支援音訊和視訊擷取。 視訊擷取裝置可透過UVC類別驅動程式支援,且必須與UVC 1.1相容。 音訊擷取裝置可透過 Windows 音訊工作階段 API (WASAPI) 支援。

擷取裝置是由媒體來源對象在媒體基礎中表示,該物件會 公開IMFMediaSource 介面。 在大部分情況下,應用程式不會直接使用此介面,但會使用較高層級的 API,例如 來源讀取器 來控制擷取裝置。

列舉擷取裝置

若要列舉系統上的擷取裝置,請執行下列步驟:

  1. 呼叫 MFCreateAttributes 函式來建立屬性存放區。

  2. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE 屬性設定為下列其中一個值:

    Description
    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_SYMBOLIC_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_SYMBOLIC_LINK 屬性設定為符號連結。
  4. 呼叫 MFCreateDeviceSourceMFCreateDeviceSourceActivate 函式。 前者會傳 回IMFMediaSource 指標。 後者會傳 回啟用物件的IMFActivate 指標。 您可以使用啟用物件來建立來源。 (啟用物件可以封送處理至另一個進程,因此如果您想要在另一個進程中建立來源,這會很有用。如需詳細資訊,請參閱 Activation Objects。)

下列範例會採用視訊裝置的符號連結,並建立媒體來源。

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. 呼叫 MFCreateDeviceSourceMFCreateDeviceSourceActivate 函式。

下列範例會採用音訊端點標識符,並建立媒體來源。

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 函式。

關閉擷取裝置

當不再需要擷取裝置時,您必須在呼叫 MFCreateDeviceSourceIMFActivate::ActivateObject 取得的 IMFMediaSource 物件上呼叫 Shutdown 來關閉裝置。 呼叫 Shutdown 可能會導致記憶體流失,因為系統可能會保留 IMFMediaSource 資源的參考,直到呼叫 Shutdown 為止。

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

如果您配置了包含擷取裝置符號連結的字串,則也應該釋放此物件。

    CoTaskMemFree(g_pwszSymbolicLink);
    g_pwszSymbolicLink = NULL;

    g_cchSymbolicLink = 0;

音訊/視訊擷取