Using the System Device Enumerator
System Device Enumerator提供了一种统一的方法来枚举按类别枚举在用户系统上注册的过滤器。 而且,它可以区分单个硬件设备,即使同一个过滤器支持它们。 这对于使用Windows驱动程序模型(WDM)和KSProxy过滤器的设备特别有用。 例如,用户可能有几个WDM视频捕捉设备,全部由相同的过滤器支持。 系统设备枚举器将它们视为独立的设备实例。
System Device Enumerator通过为特定类别创建枚举器来工作,如音频捕获或视频压缩。 类别枚举器为类别中的每个设备返回一个唯一的名字对象。 类别枚举器自动在类别中包含任何相关的即插即用设备。
按照如下方式使用System Device Enumerator:
1.通过调用CoCreateInstance来创建系统设备枚举器。 类标识符(CLSID)是CLSID_SystemDeviceEnum。
2.通过使用所需类别的CLSID调用ICreateDevEnum :: CreateClassEnumerator来获取类别枚举器。 该方法返回一个IEnumMoniker接口指针。 如果类别为空(或不存在),该方法将返回S_FALSE而不是错误代码。 如果是这样,则返回的IEnumMoniker指针为NULL,并且解引用它将导致异常。 因此,在调用CreateClassEnumerator时显式测试S_OK,而不是调用通常的SUCCEEDED宏。
3.使用IEnumMoniker :: Next方法枚举每个名字对象。 该方法返回一个IMoniker接口指针。 当Next方法到达枚举的末尾时,它也返回S_FALSE,所以再次检查S_OK。
4.要检索设备的友好名称(例如,显示在用户界面中),请调用IMoniker :: BindToStorage方法。
5.要创建和初始化管理设备的DirectShow过滤器,请在名字对象上调用IMoniker :: BindToObject。 调用IFilterGraph :: AddFilter将过滤器添加到图中。
下图说明了这个过程:
以下示例显示如何枚举安装在用户系统上的视频压缩器。 为了简洁,该示例执行最小的错误检查。
// Create the System Device Enumerator.
HRESULT hr;
ICreateDevEnum *pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&pSysDevEnum);
if (FAILED(hr))
{
return hr;
}
// Obtain a class enumerator for the video compressor category.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0);
if (hr == S_OK)
{
// Enumerate the monikers.
IMoniker *pMoniker = NULL;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if (SUCCEEDED(hr))
{
// To retrieve the filter's friendly name, do the following:
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
// Display the name in your UI somehow.
}
VariantClear(&varName);
// To create an instance of the filter, do the following:
IBaseFilter *pFilter;
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
(void**)&pFilter);
// Now add the filter to the graph.
//Remember to release pFilter later.
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
Device Monikers
对于设备标记符,可以将名字对象传递给IFilterGraph2 :: AddSourceFilterForMoniker方法以为设备创建捕获过滤器
IMoniker :: GetDisplayName方法返回名字对象的显示名称。 尽管显示名称是可读的,但您通常不会将其显示给最终用户。 如前所述,取而代之的是从物业包中获取友好名称。
IMoniker :: ParseDisplayName方法或MkParseDisplayName函数可用于为给定的过滤器类别创建默认设备名字对象。 使用@device:*:{category-clsid}形式的显示名称,其中category-clsid是类别GUID的字符串表示形式。 默认名称是设备枚举器为该类别返回的第一个名字对象。
Using the Filter Mapper
Filter Mapper是一个COM对象,它基于各种搜索条件枚举DirectShow过滤器。 Filter Mapper的效率可能低于System Device Enumerator,因此如果您需要特定类别的过滤器,则应使用System Device Enumerator。 但是,如果您需要找到支持媒体类型的某种组合的过滤器,但不属于明确的类别,则可能需要使用“过滤器映射器”。
Filter Mapper公开了IFilterMapper2接口。 要搜索过滤器,请调用IFilterMapper2 :: EnumMatchingFilters方法。 此方法使用几个参数来定义搜索条件,并返回匹配过滤器的枚举器。 枚举器支持IEnumMoniker接口,并为每个匹配过滤器提供一个唯一的名字对象。
以下示例列举了接受数字视频(DV)输入且具有至少一个任何媒体类型的输出引脚的滤镜
IFilterMapper2 *pMapper = NULL;
IEnumMoniker *pEnum = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2,
NULL, CLSCTX_INPROC, IID_IFilterMapper2,
(void **) &pMapper);
if (FAILED(hr))
{
// Error handling omitted for clarity.
}
GUID arrayInTypes[2];
arrayInTypes[0] = MEDIATYPE_Video;
arrayInTypes[1] = MEDIASUBTYPE_dvsd;
hr = pMapper->EnumMatchingFilters(
&pEnum,
0, // Reserved.
TRUE, // Use exact match?
MERIT_DO_NOT_USE+1, // Minimum merit.
TRUE, // At least one input pin?
1, // Number of major type/subtype pairs for input.
arrayInTypes, // Array of major type/subtype pairs for input.
NULL, // Input medium.
NULL, // Input pin category.
FALSE, // Must be a renderer?
TRUE, // At least one output pin?
0, // Number of major type/subtype pairs for output.
NULL, // Array of major type/subtype pairs for output.
NULL, // Output medium.
NULL); // Output pin category.
// Enumerate the monikers.
IMoniker *pMoniker;
ULONG cFetched;
while (pEnum->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag *pPropBag = NULL;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if (SUCCEEDED(hr))
{
// To retrieve the friendly name of the filter, do the following:
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
// Display the name in your UI somehow.
}
VariantClear(&varName);
// To create an instance of the filter, do the following:
IBaseFilter *pFilter;
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter);
// Now add the filter to the graph. Remember to release pFilter later.
// Clean up.
pPropBag->Release();
}
pMoniker->Release();
}
// Clean up.
pMapper->Release();
pEnum->Release();
该例子的主要内容包括:
·Minimum merit value:滤波器的优值必须高于MERIT_DO_NOT_USE;
·input types:调用者传递一个包含主要类型和子类型对的数组。 只有支持这些对中的至少一个的过滤器才会匹配。
·Exact match:过滤器可以为主要类型,子类型,引脚类别或介质注册NULL值。 除非指定完全匹配,否则NULL值将充当通配符,匹配您指定的任何值。 使用完全匹配,过滤器必须完全符合您的条件。 但是,如果您在搜索条件中提供NULL参数,则它始终充当通配符或“不关心”值,匹配任何过滤器。
参考:
https://www.yuque.com/docs/share/8e163cf7-7463-4c99-bfec-46c09471537f