选择捕获设备
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
若要选择音频或视频捕获设备,请使用 使用系统设备枚举器主题中所述 的系统设备枚举器。 系统设备枚举器返回按设备类别选择的设备名字对象的集合。 名字对象是包含有关另一个对象的信息的 COM 对象。 名字对象使应用程序无需实际创建对象即可获取有关对象的信息。 稍后,应用程序可以使用名字对象来创建 对象。 有关名字对象的详细信息,请参阅 IMoniker 的文档。
若要使用系统设备枚举器,请执行以下步骤。
调用 CoCreateInstance 以创建系统设备枚举器的实例。
调用 ICreateDevEnum::CreateClassEnumerator 并将设备类别指定为 GUID。 对于捕获设备,以下类别是相关的。
类别 GUID 说明 CLSID_AudioInputDeviceCategory 音频捕获设备 CLSID_VideoInputDeviceCategory 视频捕获设备 如果视频摄像头具有集成麦克风,则它将显示在这两个类别中。 但是,出于枚举、设备创建和数据流式处理的目的,系统将相机和麦克风视为单独的设备。
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”属性适用于在 UI 中显示。
- “FriendlyName”属性可用于每台设备。 它包含设备的用户可读名称。
- “Description”属性仅适用于 DV 和 D-VHS/MPEG 摄像机设备。 有关详细信息,请参阅 MSDV 驱动程序 和 MSTape 驱动程序。 如果可用,它包含比“FriendlyName”属性更具体的设备说明。 通常,它包括供应商名称。
- “DevicePath”属性不是用户可读的字符串,但保证对系统上的每个视频捕获设备都是唯一的。 可以使用此属性来区分同一型号设备的两个或多个实例。
- 如果存在“WaveInID”属性,则表示 DirectShow 捕获筛选器在内部使用 波形音频 API 与设备通信。 “WaveInID”属性的值对应于 waveIn* 函数使用的标识符,如 waveInOpen。
若要从名字对象读取属性,请执行以下步骤。
- 调用 IMoniker::BindToStorage 以获取指向 IPropertyBag 接口的 指针。
- 调用 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");
}
相关主题