当前位置:文档之家› 最新DirectShow视频采集开发指南

最新DirectShow视频采集开发指南

在开发 DirectShow 应用程序时,通常需要设计一个过滤图表(Filter Graph),向过滤图表中添加 相应的过滤器,最后连接过滤器的引脚就完成了功能的设计。例如,实现一个简单的视频预览功能, 需要向过滤图表中添加一个视 频捕捉源过滤器和一个 Video Renderer 过滤 器,将视频捕捉源过滤 器的输出引脚与 Video Renderer 过滤器的输入引脚相连就可以了。而在程序中只需要按照设计过滤 图表的捕捉添加过滤器并连接过滤器引脚就可以了。在连接过滤器引脚时需要注 意:只能是输出过 滤器引脚与输入过滤器引脚相连,两个输出过滤器或两个输入过滤器引脚是不能相连的。
卡,为 CLSID_VideoCompressorCategory,表示枚举系统中的视频压缩器。下面的代码演示了如何枚 举系统中的视频捕捉卡。 //枚举视频设备 ICreateDevEnum *pDevEnum = NULL; CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc); pMoniker->Release(); break; } pClassEnum->Release(); 而下面的代码则用于判断系统中是否安装了指定的视频压缩器。 ICreateDevEnum *pDevEnum = NULL; CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&pDevEnum); IEnumMoniker *pClassEnum = NULL; //列举视频压缩设备 pDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pClassEnum, 0); while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK) { IPropertyBag* pProp= NULL;
图 2.10 Graph Edit 工具 下面笔者介绍如何使用 Graph Edit 工具设计过滤图表,过滤图表的功能是实现视频的预览功能。具 体步骤如下: (1)在图 2.4 中单击“Graph/Insert Filters”菜单项打开“添加过滤器”窗口,如图 2.11 所示。
图 2.11 添加过滤器窗口 (2)在“Video Capture Sources”节点下选择一个视频捕捉源过滤器,单击“Insert Filter”按 钮将其添加到过滤图表中,如图 2.12 所示
为了在程序中使用 DirectShow,需要单独安装 DirectX,当前 DirectX 的最新版本为 9.0,即 DirectX9.0,用户可以从 Microsoft 的官方网站上免费下载。在安装 DirectX 之后,程序中需要引用 “dshow.h”头文件,并导入 “Strmiids.lib”库文件和“quartz.lib”库文件才可以使用 DirectShow。代码如下:
2.3.1 DirectShow 系统结构分析
表中包含了各种 Filter,这些 Filter 能够按一定顺序连接在一起,构成一条流水线。从功能的角度划分,Filter 大体可以分为 3 类,Source Filters、Transform Filters 和 Rendering Filters。Source Filters 主要负责获取数据,可以是 一个文件、一个采集卡、声卡或数码相机等。Transform Filters 负责数据的转换、传输。例如各种 编码器、解码器等。Rendering Filters 负责数据的最终去向,例如将数据传送到声卡、显卡或存储 为文件。
DirectShow 最新视频采集开发指南
2011.11
2.3 DirectShow 视频采集方案
流媒体处理技术以其复杂性和技术性一直受到人们的关注。随着网络技术的不断发展,流媒体在网络 上得到了广泛地应用。如何能 够简单、有效地进行流媒体处理,已成为一个焦点问题。为此,Microsoft 推出了 DirectShow,DirectShow 是 Microsoft 推 出的基于 Windows 平台的流媒体处理开发包,它与 DirectX 一起发布。DirectShow 对流媒体的捕捉、回放提供了强大的支持,使用它还可以 在基于 WDM 驱动的采集卡上进行数据捕捉。本节将介绍有关 DirectShow 的相关知识。
图 2.14 连接过滤器引脚窗口 (5)单击工具栏中的“ ”按钮运行过滤图表,将显示一个视频预览窗口,如图 2.15 所示。
图 2.15 视频预览窗口
2.3.3 枚举系统设备
使用 Graph Edit 工具,用户可以非常方便地获得与某一系统设备相关的过滤器。但是,在程序中该 如何获得这些过滤器呢? 用户可以采用枚举的方式列举系统中安装的设备。以列举系统中的视频捕捉设备为例,首先定义一个 设备列举接口 ICreateDevEnum 的一个指针,调用 CoCreateInstance 方法创建 ICreateDevEnum 实例, 然后定义一个列举监视器 IEnumMoniker 的一个指针,调用 ICreateDevEnum 实例的 CreateClassEnumerator 方法创建 IEnumMoniker 实例,最后以循环的方式调用 IEnumMoniker 实例的 Next 方法遍历系统设备,调用 IEnumMoniker 实例的 BindToObject 方法将系统设备绑定到过滤器上。 在上面的描述中,ICreateDevEnum 实例的 CreateClassEnumerator 方法的第一个参数确定枚 举的系 统设备。例如,第一个参数为 CLSID_VideoInputDeviceCategory,表示将要枚举系统中的视频捕捉
#pragma comment (lib,"Strmiids")
#pragma comment (lib,"quartz")
#include <dshow.h>
2.3.2 Filter 图表设计
为了方便用户设计过滤图表,DirectX 提供了一个 Graph Edit 工具。用户可以单击“开始”菜单下 的“Microsoft DirectX 9 SDK\DirectX Utilities\Graph Edit”菜单项打开 Graph Edit 工具,如 图 2.10 所示。
每一个过滤器(Filter)至少应有一个引脚(Pin),或者是输入引脚或者是输出引脚。有些过滤器 还拥有多个引脚,即 又输入引脚又有输出引脚。但是过滤器的输入、输出引脚并不是对应的,有些 过滤器可以有多个输入引脚,而只有一个输出引脚或者没有输出引脚。在程序中为了连 接过滤器间 的引脚,通常需要获得过滤器的各个引脚。用户可以使用 IEnumPins 接口来枚举某一个过滤器的输入、 输出引脚。过滤器 IBaseFilter 提供了一个 EnumPins 方法用于生成一个 IEnumPins 接口实例,这样, 通过调用 IEnumPins 的 Next 方法便可以 访问各个引脚了。下面的代码定义了一个 FindPin 函数,用 于获得某个过滤器的输入或输出引脚。 //查找引脚 IPin* CKinescopeDlg::FindPin(IBaseFilter *pFilter, PIN_DIRECTION dir) {
2.3.6 视频预览设计方案
在开发视频应用程序时,一个最基本的功能是视频预览。本节将介绍如何应用 DirectShow 实现视频 预览,效果如图 2.16 所示。
图 2.16 视频预览设计方案 在使用 DirectShow 开发应用程序时,通常需要先设计过滤图表,然后根据图表来设计应用程序。在 设计视频预览过滤图 表时,只需要两个步骤,第一个步骤是添加视频捕捉的源过滤器,第二个步骤 是添加 Video Render 过滤器,并连接两个过滤器引脚。过滤图表具体设计步骤如下: (1)启动 Graph Edit 工具, 在 Graph Edit 工具中单击“Graph \Insert Filters”菜单项打开“添 加过滤器窗口”,在“Video Capture Sources”节点下选择一个视频捕捉源过滤器,单击“Insert Filter”按钮将其添加到过滤图表中,如图 2.11 所示。 (2)在“DirectShow Filters”节点下将“Video Render”过滤器添加到图表中,如图 2.17 所示。
IEnumPins* pEnumPins; IPin* pOutpin; PIN_DIRECTION pDir;
pFilter->EnumPins(&pEnumPins); while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK) {
pOutpin->QueryDirection(&pDir); if (pDir==dir) {
return pOutpin; } } return 0; } 用户可以按下面的方式获得某个过滤器的输入、输出引脚。 IPin * pComOut,*pComIn ; pComIn = FindPin(pCompress,PINDIR_INPUT); pComOut = FindPin(pCompress,PINDIR_OUTPUT);
IID_ICreateDevEnum, (void **)&pDevEnum); IEnumMoniker *pClassEnum = NULL; pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0); ULONG cFetched; while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK) {
相关主题