閱讀英文

共用方式為


選取擷取裝置

[與此頁面相關聯的功能,DirectShow是舊版功能。 它已被 MediaPlayerIMFMediaEngine和媒體基金會中的 音訊/視訊擷取取代。 這些功能已針對 Windows 10 和 Windows 11 進行優化。 Microsoft強烈建議新程式代碼盡可能在媒體 基礎中使用 MediaPlayerIMFMediaEngine 音訊/視訊擷取,而不是 DirectShow。 Microsoft建議使用舊版 API 的現有程式代碼,盡可能改寫成使用新的 API。]

若要選取音訊或視訊擷取裝置,請使用 System Device Enumerator,相關內容請參閱使用系統裝置列舉值主題。 系統裝置列舉程式會傳回依據裝置類別選取的裝置標識集合。 moniker 是一個 COM物件,其中包含另一個對象的相關信息。 Monikers 可讓應用程式取得對象的相關信息,而不需要實際建立物件。 之後,應用程式可以使用名稱(Moniker)來建立物件。 如需關於monikers的詳細資訊,請參閱 IMoniker的文件。

若要使用系統裝置列舉值,請執行下列步驟。

  1. 呼叫 CoCreateInstance,以建立系統裝置列舉值的實例。

  2. 呼叫 ICreateDevEnum::CreateClassEnumerator,並將裝置類別指定為 GUID。 針對擷取裝置,下列類別是相關的。

    類別 GUID 描述
    CLSID_AudioInputDeviceCategory 音訊擷取裝置
    CLSID_VideoInputDeviceCategory 視訊擷取裝置

     

    如果攝像機具有整合式麥克風,則會出現在這兩種類別中。 不過,相機和麥克風會依系統視為個別的裝置,以便進行列舉、裝置建立和數據串流。

  3. CreateClassEnumerator 方法會傳回 IEnumMoniker 介面的指標。 若要列舉Moniker,請呼叫 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 介面的清單,其中每個介面都代表裝置 Moniker。 應用程式可以從代稱讀取屬性,或使用代稱來為裝置創建 DirectShow 捕捉過濾器。 Moniker 屬性會以 VARIANT 值傳回。 下列屬性由裝置 moniker 支援。

財產 描述 VARIANT 類型
“FriendlyName” 裝置的名稱。 VT_BSTR
描述 裝置的描述。 VT_BSTR
“DevicePath” 識別裝置的唯一字串。 (僅限視訊擷取裝置。 VT_BSTR
“WaveInID” 音訊擷取裝置的標識碼。 (僅限音訊擷取裝置。 VT_I4

 

“FriendlyName” 和 “Description” 屬性適合在 UI 中顯示。

  • 每個裝置都可以使用 「FriendlyName」 屬性。 它包含易於人類閱讀的裝置名稱。
  • “Description” 屬性僅適用於 DV 和 D-VHS/MPEG 攝影機裝置。 如需詳細資訊,請參閱 MSDV 驅動程式MSTape 驅動程式。 如果有的話,它會包含比 「FriendlyName」 屬性更具體之裝置的描述。 通常它包含廠商名稱。
  • “DevicePath” 屬性不是人類可讀取的字串,但保證對於系統上的每個視訊擷取裝置而言都是唯一的。 您可以使用這個屬性來區分相同裝置型號的兩個或多個實例。
  • 如果存在 「WaveInID」 屬性,表示 DirectShow 擷取篩選器會在內部使用 波音頻 API 來與裝置通訊。 “WaveInID” 屬性的值會對應至 waveIn* 函式所使用的標識符,例如 waveInOpen

若要從Moniker讀取屬性,請執行下列步驟。

  1. 呼叫 IMoniker::BindToStorage,以取得 IPropertyBag 介面的指標。
  2. 呼叫 IPropertyBag::Read 來讀取屬性。

下列程式代碼範例示範如何列舉裝置Moniker清單並取得屬性。

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

音訊擷取

視訊擷取