有時,應用程序需要查看系統中所有的filter。例如,視頻應用程序需要列出系統中可用的捕捉設備。因爲dshow基於com結構的,你在設計程序的時候是沒法知道系統中正在使用的過濾器。Directshow提供了兩種方法來枚舉系統中註冊的過慮器。
1 系統設備枚舉器
系統設備枚舉器提供了一個很好的方法根據種類來枚舉系統中註冊的過慮器。也許枚一種不同的硬件都會有自己的過慮器,或許所有的硬件設備共用同一個filter。這個對於採用WDM驅動程序的硬件很有用。
系統設備枚舉器根據不同的種類創建了一個枚舉器,例如,音頻壓縮,視頻捕捉。不同種類的枚舉器對於每一種設備返回一個獨立的名稱(moniker)。種類枚舉器自動將相關的即插即用,演播設備包括進來。
按照下面的步驟使用設備枚舉器
1 創建枚舉器組件,CLSID爲CLSID_SystemDeviceEnum
2 指定某一種類型設備,參數CLSID,通過ICreateDevEnum::CreateClassEnumerator獲取某一種類的枚舉器,這個函數返回一個IEnumMoniker接口指針,如果該種類的空或者不存在,這個方法就返回S_FALSE。因此,當你調用這個函數時一定要檢查返回值是否爲S_OK,而不要用SUCCEEDED宏。
3 然後IEnumMoniker::Next枚舉每一個moniker。這個方法返回一個IMoniker接口指針。
4 要想知道設備的名稱,可以通過下面的函數IMoniker::BindToStorage
5 然後利用IMoniker::BindToObject生成綁定道設備上的filter。調用IFilterGraph::AddFilter將filter添加到Graph圖中。
// 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); //生成一個filter綁定到設備上。
// Now add the filter to the graph.
//Remember to release pFilter later.
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
在上面我們用IMoniker::BindToObject生成綁定道設備上的filter,當然我們還可以用另外的一種方法來生成綁定到設備上的filter
利用IMoniker::GetDisplayName得到moniker的名字。然後你把moniker的名字做參數傳遞給IFilterGraph2::AddSourceFilterForMoniker,就可以創建一個綁定到設備的filter了。在上面我們是調用IMoniker::BindToObject生成filter的,還是上面的簡單些。看看代碼吧。
LPOLESTR strName = NULL;
IBaseFilter pSrc = NULL;
hr = pMoniker->GetDisplayName(NULL, NULL, &strName);
if (SUCCEEDED(hr))
{
// Query the Filter Graph Manager for IFilterGraph2.
IFilterGraph2 *pFG2 = NULL;
hr = pGraph->QueryInterface(IID_IFilterGraph2, (void**)&pFG2);
if (SUCCEEDED(hr))
{
hr = pFG2->AddSourceFilterForMoniker(pMoniker, 0, L"Source", &pSrc);
pFG2->Release();
}
CoTaskMemFree(strName);
}
// If successful, remember to release pSrc.
2 Filter Mapper
搜索系統中的filter的另一個方法就是採用Filer Mapper。Filter mapper是一個com對象,它按照一定的條件來搜索系統的filer,它比系統設備枚舉器(System Device Enumerator)的效率要低一些。所以當你要枚舉某特定種類的filter時,你應該使用系統設備枚舉器,但是當你搜索支持某種媒體類型的filter時,同時也找不到清晰的filter,你應該使用filter mapper。
Filter Mapper 暴露一個IFilerMapper2接口,要想搜索一個接口,你可以調用該接口的IFilterMapper2::EnumMatchingFilters方法,這個方法需要傳遞一些參數來定義搜索條件,同時該方法返回一個適合條件的filter的枚舉器,這個枚舉器提供一個IEnumMoniker接口,並且對於每個適合的filter都提供一個單獨的moniker。
下面的例子演示了,枚舉所有的支持DV,並且至少有一個輸出pin的filter,這個filter支持任何媒體類型。
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;
//////////下面就是枚舉filter了,就是系統枚舉設備filter
while (pEnumCat->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();