DirectShow入门之Directshow的基本技巧 3

 

DirectShow入门之Directshow的基本技巧

2006-10-13 07:00作者:智慧的鱼出处:天极开发责任编辑:方舟

如何枚举系统的设备和过虑器

  有时,应用程序需要查看系统中所有的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图中。


图1

// 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();

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
//指定视频采集设备的友好名字,为它创建一个Filter IBaseFilter * CTestPreviewDlg::CreateVideoDevice(const char * inFriendlyName) { return CreateHardwareFilter(CLSID_VideoInputDeviceCategory,inFriendlyName); } //根据设备的友好名字,创建一个代表该设备的Filter IBaseFilter * CTestPreviewDlg::CreateHardwareFilter(GUID inCategory,const char * inFriendlyName) { //创建一个系统枚举组件对象 ICreateDevEnum * enumHardware = NULL; HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_ALL, IID_ICreateDevEnum,(void**)&enumHardware); if(FAILED(hr)) { return NULL; } IBaseFilter * hardwareFilter = NULL; IEnumMoniker * enumMoniker = NULL; //为指定的目录创建枚举器 hr = enumHardware->CreateClassEnumerator(inCategory,&enumMoniker,0); if(enumMoniker) { enumMoniker->Reset(); ULONG fetched = 0; IMoniker * moniker = NULL; char friendlyName[256]; //枚举得到该目录下所有的设备,逐个进行名字匹配 while(!hardwareFilter && SUCCEEDED(enumMoniker->Next(1,&moniker, &fetched)) && fetched) { if(moniker) { IPropertyBag * propertyBag = NULL; VARIANT name; friendlyName[0] = 0; hr = moniker->BindToStorage(0,0,IID_IPropertyBag,(void**)&propertyBag); //读取设备的友好名字 if(SUCCEEDED(hr)) { name.vt = VT_BSTR; hr = propertyBag->Read(L"Friendlyname",&name,NULL); } if(SUCCEEDED(hr)) { WideCharToMultiByte(CP_ACP,0,name.bstrVal,-1, friendlyName,256,NULL,NULL); //如果当前设备的友好名字与用户指定的设备名字相同, //则将当前设备标识绑定为Filter形式 if(strcmp(friendlyName,inFriendlyName) == 0) { moniker->BindToObject(0,0,IID_IBaseFilter, (void**)&hardwareFilter); } } //释放使用过的接口 if(propertyBag) { propertyBag->Release(); propertyBag = NULL; } moniker->Release(); } } enumMoniker->Release(); } enumHardware->Release(); return hardwareFilter; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值