=====================================================

最简单的基于DirectShow的示例文章列表:

最简单的基于DirectShow的示例:视频播放器

最简单的基于DirectShow的示例:视频播放器图形界面版

最简单的基于DirectShow的示例:视频播放器自定义版

最简单的基于DirectShow的示例:获取Filter信息

=====================================================

本文记录一个获取DirectShow的Filter信息的程序。该程序可以遍历当前系统中的DirectShow Filter并且将它们的信息打印到控制台中。通过本程序可以搞清楚DirectShow中Filter,Pin,MediaType等几个关键结构之间的关系,以及它们的信息的获取方法。


流程图

该程序的流程图如下所示。由于该图的尺寸比较大,在页面中显示不下,所以在相册中上传了一份:

接口

该流程图中涉及到以下接口:

ICreateDevEnum *pSysDevEnum:设备列举接口。
IEnumMoniker *pEnumCat:Moniker(别名)枚举接口。
IMoniker *pMoniker:Moniker(别名)接口。
IPropertyBag *pPropBag:存储属性值的接口。
IBaseFilter *pFilter:Filter接口。
IEnumPins * pinEnum:Filter枚举接口。
IPin * pin: Pin接口。
PIN_INFO pinInfo:存储Pin的信息的结构体。
IEnumMediaTypes *mtEnum:MediaType枚举接口。

AM_MEDIA_TYPE   *mt:描述媒体类型的结构体。

流程图

该流程图中涉及到以下函数:

【初始化】

CoInitialize():初始化COM运行环境。

CoCreateInstance(…,pSysDevEnum):用指定的类标识符创建一个Com对象。在该示例中类标识符为“IID_ICreateDevEnum”,用于创建ICreateDevEnum。

【Filter的枚举】

pSysDevEnum->CreateClassEnumerator(…,pEnumCat):通过ICreateDevEnum查询IEnumMoniker枚举接口,枚举指定类型目录下的设备Moniker(别名)。
pEnumCat->Next(…,pMoniker):通过IEnumMoniker查询下一个IMoniker接口。
pMoniker->BindToStorage(…,pPropBag):通过IMoniker查询IPropertyBag接口(用于获取Filter信息)。
pPropBag->Read("FriendlyName"):通过IPropertyBag获取“FriendlyName”属性的值。

pMoniker->BindToObject(…,pFilter):通过IMoniker查询IBaseFilter接口(用于获取Filter,注意和BindToStorage()区别)。

【Pin的枚举】

pFilter->EnumPins(pinEnum):通过IBaseFilter查询IEnumPins枚举接口。
pinEnum->Next(…,pin):通过IEnumPins查询下一个IPin接口。

pin->QueryPinInfo(PinInfo):通过IPin获取Pin的信息。

【MediaType的枚举】

pin->EnumMediaTypes(&mtEnum):通过IPin查询IEnumMediaTypes枚举接口。
mtEnum->Next(…, &mt):通过IEnumMediaTypes查询下一个AM_MEDIA_TYPE。

GuidToString(mt->majortype):把AM_MEDIA_TYPE的GUID转换成字符串(方便输出)。

【释放】

CoUninitialize():释放CoInitialize()初始化的COM运行环境。

再附上一张代码中涉及到的接口之间的关系:

可以看出从上到下他们之间顺序的排列如下所示:

ICreateDevEnum-->IEnumMoniker-->IMoniker-->IBaseFilter-->IEnumPins-->IPin-->IEnumMediaTypes-->AM_MEDIA_TYPE

源代码

/**
 * 最简单的Directshow信息显示例子
 * Simplest DirectShow Info
 *
 * 雷霄骅 Lei Xiaohua
 * leixiaohua1020@126.com
 * 中国传媒大学/数字电视技术
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 *
 * 本程序是一段获取DirectShow滤镜信息的代码。通过本代码可以获得
 * DirectShow滤镜信息。适合初学者学习DirectShow。
 *
 * This code can be used to get Directshow Filter's information.
 * Suitable for the beginner of DirectShow.
 */

#include "stdafx.h"
#include <dshow.h>
#include <atlconv.h>

#define OUTPUT_PIN       1
#define OUTPUT_MEDIATYPE 1

char* GuidToString(const GUID &guid)
{
	int buf_len=64;
	char *buf =(char *)malloc(buf_len);
	_snprintf(
		buf,
		buf_len,
		"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
		guid.Data1, guid.Data2, guid.Data3,
		guid.Data4[0], guid.Data4[1],
		guid.Data4[2], guid.Data4[3],
		guid.Data4[4], guid.Data4[5],
		guid.Data4[6], guid.Data4[7]);
	//printf("%s\n",buf);
	return buf;
}

int _tmain(int argc, _TCHAR* argv[])
{
	USES_CONVERSION;
	// Init COM
	HRESULT hr=NULL;
	hr= CoInitialize(NULL);
	if (FAILED(hr)){
		printf("Error, Can not init COM.");
		return -1;
	}
	printf("===============Directshow Filters ===============\n");
	ICreateDevEnum *pSysDevEnum = NULL;
	hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
		IID_ICreateDevEnum, (void **)&pSysDevEnum);
	if (FAILED(hr)){
		return hr;
	}

	IEnumMoniker *pEnumCat = NULL;
	//Category
	/************************************************************************
	Friendly Name	                      CLSID
	-------------------------------------------------------------------------
	Audio Capture Sources	              CLSID_AudioInputDeviceCategory
	Audio Compressors	                  CLSID_AudioCompressorCategory
	Audio Renderers	                      CLSID_AudioRendererCategory
	Device Control Filters	              CLSID_DeviceControlCategory
	DirectShow Filters	                  CLSID_LegacyAmFilterCategory
	External Renderers	                  CLSID_TransmitCategory
	Midi Renderers	                      CLSID_MidiRendererCategory
	Video Capture Sources	              CLSID_VideoInputDeviceCategory
	Video Compressors	                  CLSID_VideoCompressorCategory
	WDM Stream Decompression Devices	  CLSID_DVDHWDecodersCategory
	WDM Streaming Capture Devices	      AM_KSCATEGORY_CAPTURE
	WDM Streaming Crossbar Devices	      AM_KSCATEGORY_CROSSBAR
	WDM Streaming Rendering Devices	      AM_KSCATEGORY_RENDER
	WDM Streaming Tee/Splitter Devices	  AM_KSCATEGORY_SPLITTER
	WDM Streaming TV Audio Devices	      AM_KSCATEGORY_TVAUDIO
	WDM Streaming TV Tuner Devices	      AM_KSCATEGORY_TVTUNER
	WDM Streaming VBI Codecs	          AM_KSCATEGORY_VBICODEC
	************************************************************************/
	hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioCompressorCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_MediaMultiplexerCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_LegacyAmFilterCategory, &pEnumCat, 0);

	if (hr != S_OK) {
		pSysDevEnum->Release();
		return -1;
	}

	IMoniker *pMoniker = NULL;
	ULONG monikerFetched;
	//Filter
	while(pEnumCat->Next(1, &pMoniker, &monikerFetched) == S_OK){
		IPropertyBag *pPropBag;
		VARIANT varName;
		IBaseFilter *pFilter;
		hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,(void **)&pPropBag);
		if (FAILED(hr)){
			pMoniker->Release();
			continue;
		}
		VariantInit(&varName);
		hr = pPropBag->Read(L"FriendlyName", &varName, 0);
		//"FriendlyName": The name of the device.
		//"Description": A description of the device.
		//Filter Info================
		printf("[%s]\n",W2A(varName.bstrVal));
		VariantClear(&varName);
		//========================
#if OUTPUT_PIN
		hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,(void**)&pFilter);
		if (!pFilter){
			continue;
		}

		IEnumPins * pinEnum = NULL;
		IPin * pin = NULL;
		ULONG pinFetched = 0;
		if (FAILED(pFilter->EnumPins(&pinEnum))){
			pinEnum->Release();
			continue;
		}
		pinEnum->Reset();
		//Pin Info
		while (SUCCEEDED(pinEnum->Next(1, &pin, &pinFetched)) && pinFetched){
			if (!pin){
				continue;
			}
			PIN_INFO pinInfo;
			if (FAILED(pin->QueryPinInfo(&pinInfo))){
				continue;
			}
			printf("\t[Pin] ");
				switch(pinInfo.dir){
				case PINDIR_INPUT:printf("Dir:Input  \t");break;
				case PINDIR_OUTPUT:printf("Dir:Output \t");break;
				default:printf("Dir:Unknown\n");break;
			}
			printf("Name:%s\n",W2A(pinInfo.achName));

			//MediaType
#if OUTPUT_MEDIATYPE
			IEnumMediaTypes *mtEnum=NULL;
			AM_MEDIA_TYPE   *mt=NULL;
			if( FAILED( pin->EnumMediaTypes( &mtEnum )) )
				break;
			mtEnum->Reset();

			ULONG mtFetched = 0;

			while (SUCCEEDED(mtEnum->Next(1, &mt, &mtFetched)) && mtFetched){

				printf("\t\t[MediaType]\n");
				//Video
				char *MEDIATYPE_Video_str=GuidToString(MEDIATYPE_Video);
				//Audio
				char *MEDIATYPE_Audio_str=GuidToString(MEDIATYPE_Audio);
				//Stream
				char *MEDIATYPE_Stream_str=GuidToString(MEDIATYPE_Stream);
				//Majortype
				char *majortype_str=GuidToString(mt->majortype);
				//Subtype
				char *subtype_str=GuidToString(mt->subtype);

				printf("\t\t  Majortype:");
				if(strcmp(majortype_str,MEDIATYPE_Video_str)==0){
					printf("Video\n");
				}else if(strcmp(majortype_str,MEDIATYPE_Audio_str)==0){
					printf("Audio\n");
				}else if(strcmp(majortype_str,MEDIATYPE_Stream_str)==0){
					printf("Stream\n");
				}else{
					printf("Other\n");
				}
				printf("\t\t  Subtype GUID:%s",subtype_str);

				free(MEDIATYPE_Video_str);
				free(MEDIATYPE_Audio_str);
				free(MEDIATYPE_Stream_str);
				free(subtype_str);
				free(majortype_str);
				printf("\n");

			}
#endif
			pin->Release();

		}
		pinEnum->Release();

		pFilter->Release();
#endif

		pPropBag->Release();
		pMoniker->Release();
	}
	pEnumCat->Release();
	pSysDevEnum->Release();
	printf("=================================================\n");
	CoUninitialize();
	return 0;
}

运行结果

程序运行的结果如下图所示。从图中可以看出,程序打印出了系统中DirectShow的Filter信息。每个Filter的信息中包含了它的Pin的信息。每个Pin中又包含了Pin中的MediaType信息。

可以通过定义在代码最前面宏 控制输出的Filter信息的类型。定义成“0”的话则不会输出该类的信息。如下所示。

#define OUTPUT_PIN       1
#define OUTPUT_MEDIATYPE 1

下载

Simplest DirectShow Example

项目主页

SourceForge:https://sourceforge.net/projects/simplestdirectshowexample/

Github:https://github.com/leixiaohua1020/simplest_directshow_example

开源中国:http://git.oschina.net/leixiaohua1020/simplest_directshow_example

CDSN下载地址:http://download.csdn.net/detail/leixiaohua1020/8348163

本程序包含了DirectShow开发的示例程序。适合DirectShow初学者进行学习。
它包含了以下几个子程序:
simplest_directshow_player: 最简单的基于DirectShow的视频播放器。
simplest_directshow_player_custom: 最简单的基于DirectShow的视频播放器(Custom)。
playerGUI: 最简单的基于DirectShow的播放器-图形界面版。
simplest_directshow_info: 最简单的Directshow信息显示例子。
simplest_directshow_filter: 目前还未完成。

最简单的基于DirectShow的示例:获取Filter信息的更多相关文章

  1. 最简单的基于DirectShow的示例:视频播放器自定义版

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

  2. 最简单的基于DirectShow的示例:视频播放器图形界面版

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

  3. 最简单的基于DirectShow的示例:视频播放器

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

  4. 转:最简单的基于 DirectShow 的视频播放器

    50行代码实现的一个最简单的基于 DirectShow 的视频播放器 本文介绍一个最简单的基于 DirectShow 的视频播放器.该播放器对于初学者来说是十分有用的,它包含了使用 DirectSho ...

  5. 最简单的基于librtmp的示例:发布H.264(H.264通过RTMP发布)

    ===================================================== 最简单的基于libRTMP的示例系列文章列表: 最简单的基于librtmp的示例:接收(RT ...

  6. 最简单的基于librtmp的示例:发布(FLV通过RTMP发布)

    ===================================================== 最简单的基于libRTMP的示例系列文章列表: 最简单的基于librtmp的示例:接收(RT ...

  7. 最简单的基于librtmp的示例:接收(RTMP保存为FLV)

    ===================================================== 最简单的基于libRTMP的示例系列文章列表: 最简单的基于librtmp的示例:接收(RT ...

  8. 50行代码实现的一个最简单的基于 DirectShow 的视频播放器

    本文介绍一个最简单的基于 DirectShow 的视频播放器.该播放器对于初学者来说是十分有用的,它包含了使用 DirectShow 播放视频所有必备的函数. 直接贴上代码,具体代码的含义都写在注释中 ...

  9. 一个简单的基于 DirectShow 的播放器 2(对话框类)

    上篇文章分析了一个封装DirectShow各种接口的封装类(CDXGraph):一个简单的基于 DirectShow 的播放器  1(封装类) 本文继续上篇文章,分析一下调用这个封装类(CDXGrap ...

随机推荐

  1. 【USACO12JAN】视频游戏的连击Video Game Combos

    题目描述 Bessie is playing a video game! In the game, the three letters 'A', 'B', and 'C' are the only v ...

  2. hdu 5441 (并查集)

    题意:给你n个点,m条边构成无向图.q个询问,每次一个值,求有多少条路,路中的边权都小于这个值 a->b 和 b->a算两种 思路:把权值从小到大排序,询问从小到大排序,如果相连则用并查集 ...

  3. POJ 3233 (矩阵)

    题意:对于矩阵A,求A^1 + ...... + A^k 按照矩阵十大经典题的思路大致做了下. 在k为奇数时:  A^( k / 2+1)+ 1) * (A^1 + ....... A^(k/2)) ...

  4. 智能指针之 auto_ptr

    C++的auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理,该智能指针在C++11中已经被弃用,转而由unique_ptr替代, 那这次使用和实现,就具体讲一下auto_pt ...

  5. JS按照指定的周期来调用函数方法

    setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式. setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭.由 s ...

  6. Python 编程规范

    原文传送符:请点击

  7. Vue2学习(3)

    子组件索引 尽管有 props 和 events,但是有时仍然需要在 JavaScript 中直接访问子组件.为此可以使用 ref 为子组件指定一个索引 ID.例如: <div id=" ...

  8. redis和spring集成

    redis和spring框架的整合 我这里创建的是maven工程,通过maven锁定版本号,管理jar包之间的依赖 1.在pom文件中,引入spring和redis的jar包的坐标: <prop ...

  9. vue+node.js+webpack开发微信公众号功能填坑——v -for循环

    页面整体框架实现,实现小功能,循环出数据,整体代码是上一篇 vue+node.js+webpack开发微信公众号功能填坑--组件按需引入 修改部门代码 app.vue <yd-flexbox&g ...

  10. ORA-01207: file is more recent than control file - old control file的处理方法

    1. 连接数据库 sqlplus / as sysdba2. 启动数据库,此时会报标题中的错误startup 3.备份创建控制文件的脚本语句,并从中拷贝出相关的NORESETLOGS模式的创建控制文件 ...