DirectShow系统概述

1. 关于DirectShow

1.1
DirectX是微软公司开发的一套基于Windows平台的编程接口(API);它能出色地完成高速的实时动画渲染、交互式音乐和环境音效、高效多媒体数据处理等一般API很难完成的任务。
DirectShow是DirectX大家族中的一位成员。DirectX的家族成员很多,而且各有各的本领,就如DirectDraw和Direct3D负责二维图形图像/三维动画加速、DirectMusic和DirectSound负责交互式音乐/环境音效处理一样,DirectShow为Windows平台上处理各种格式的媒体文件播放、音视频采集等高性能要求的多媒体应用,提供了完整的解决方案。

DirectShow是一个开放性的应用框架,也是一套基于COM的编程接口。DirectShow的系统功能参见图1.1。可以看到,图中最大的一块即是DirectShow系统,它的基本工作原理就是“流水线”:将单元组件——Filter——串联在一起,交由Filter Graph Manager统一控制。系统的输入可以是本地文件系统、硬件插卡、因特网等,系统的输出可以是声卡(声音再现)、显卡(视频内容显示)、本地文件系统,当然也可以最终将数据向网络发送。

事实上,计算机应用领域中的很多模块都可以和DirectShow系统交互。也就是说,DirectShow的应用范畴很广。单纯从本地系统来说,DirectShow可以实现不同格式的媒体文件的解码播放、或格式之间的相互转换,可以从本地机器中的采集设备采集音视频数据并保存为文件,可以接收、观看模拟电视等。而从网络应用的角度来说,DirectShow更可用于视频点播、视频会议、视频监控等领域。其实,广义上来说,DirectShow系统适合于一切流式数据的处理,这些数据可以是音频、视频这样的多媒体数据,但又不局限于多媒体数据。

随着信息技术的发展,多媒体技术迎来新的挑战:
(1)多媒体流包含了大量的数据,这些数据要求被迅速处理以达到实时性。
(2)视频流和音频流的同步。
(3) 流的来源非常复杂,包括本地文件、Internet 网络、摄像头、视频卡和电视广播网等。
(4)流的格式也多种多样,包括Audio2Video Interleaved(AVI) ,Advanced Streaming Format (ASF) , Motion Picture Experts Group (MPEG) ,and Digital Video (DV)等。
(5)开发人员事先并不知道终端用户的硬件设备。

Microsoft的DirectShow正是为了适应以上的挑战而设计的多媒体开发工具, Microsoft 设计它的意图就是简化多媒体应用程序的开发,使开发者不必考虑复杂的流数据格式和不同的终端设备,以及数据同步的问题。
Microsoft 通过DirectShow给多媒体程序开发员提供了标准的、统一的、高效的API接口。DirectShow技术是建立在DirectX的DirectDraw和DirectSound 的基础之上的,它通过 DirectDraw 对显卡进行控制以显示视频,通过DirectSound 对声卡进行控制以播放声音。DirectX为了最大限度提高效率而允许用户直接访问硬件,如允许用户直接读写显存,因此,DirectShow也同样具有快速的优势。

为了实现对多种对象(不同流格式和不同的终端设备)的处理,DirectShow使用了组件(COM)封装的实现方法,在DirectShow中组件称为滤波器(Filter) 。
图1为用户程序与DirectShow及外部对象的关系框


图1  DirectShow系统框图
从图1 中可以看到,DirectShow的滤波器支持多种外部设备,包括本地文件系统、视频采集卡、有线电视接口、视频播放卡(通过 DirectDraw 或 Graphic Device Interface) 、音频播放卡(通过DirectSound) 。虽然DirectShow是基于 COM (Component Object Model)技术上的,但是如果只是用DirectShow开发自己的应用程序而不涉及开发自己的DirectShow组件,就不需要了解太多的COM的知识。

尽管Microsoft 提供的标准DirectShow开发包已经支持了很多格式,但毕竟不是囊括一切,如它就不支持的解码。但是 由于 是一个开放系统,它允许用户根据自己的需要按照一定规范编写自己的滤波器(也就是COM) ,扩充DirectShow的功能。

1.2 VC开发环境的配置

(假设DirectX SDK8.1安装在C:/DXSDK目录下。)
1. 编译基类源代码,至少生成两个静态库文件
打开C:/ DXSDK/samples/Multimedia/DirectShow/BaseClasses/baseclasses.dsw,Debug版本生成strmbasd.lib,Release版本生成strmbase.lib。

2. 配置VC的编译环境:Include目录和Lib目录。执行VC的菜单命令Tools | Options…,在随后弹出的对话框中进入Directories一页,在Show directories for一项选择Include files,然后配置如下:(注意,务必将DirectX SDK的目录放在标准的VC目录之前。)
C:/DXSDK/Include
C:/ DXSDK/samples/Multimedia/DirectShow/BaseClasses
C:/ DXSDK/samples/Multimedia/Common/include
C:/Program Files/Microsoft Visual Studio/VC98/INCLUDE
C:/Program Files/Microsoft Visual Studio/VC98/MFC/INCLUDE
C:/Program Files/Microsoft Visual Studio/VC98/ATL/INCLUDE
再在Show directories for一项选择Library files,配置如下:
C:/DXSDK/Lib
C:/ DXSDK/samples/Multimedia/DirectShow/BaseClasses /DEBUG
C:/ DXSDK/samples/Multimedia/DirectShow/BaseClasses /RELEASE
C:/PROGRAM FILES/MICROSOFT SDK/LIB
C:/Program Files/Microsoft Visual Studio/VC98/LIB
C:/Program Files/Microsoft Visual Studio/VC98/MFC/LIB

3. 配置DirectShow应用程序开发项目需要连接的库文件。
执行VC的菜单命令Project | Settings…,在随后弹出的对话框中进入Link一页,在Object/library modules一项,Debug版输入Strmbasd.lib Msvcrtd.lib Winmm.lib,Release版本输入Strmbase.lib Msvcrt.lib Winmm.lib。Ignore default libraries. (In Microsoft® Visual C++® 6.0, choose Settings from the Project menu. Click the Link tab and check Ignore all default libraries.)

4. 如果安装的DirectX SDK的版本是9.0以前的,请确认在编译应用程序的Debug版本之前已经定义了DEBUG宏。执行VC的菜单命令Project | Settings…,在随后弹出的对话框中进入C/C++一页,在Category一项选择Preprocessor,然后确认Preprocessor definitions中有DEBUG(如果没有就自己加上)。
另外,应用程序在调用任何COM库函数之前,务必调用CoInitialize或CoInitializeEx进行COM库的初始化(一般只需在程序启动的时候调用一次);在结束所有COM操作之后,调用CoUninitialize进行反初始化(一般在程序退出之前调用一次)。而当程序中有多个线程都要使用COM库函数时,则每个线程都要进行初始化和反初始化。总之,要保证CoUninitialize和CoInitialize(或CoInitializeEx)调用的一一配对。

2  DirectShow 的组成构架

DirectShow 是一个基于COM(组件对象模型)的系统,由许多模块化的软件组件组成。在这个系统中,最基本的构造模块是称为过滤器(Filter)的软件组件。Filter将多媒体数据的处理过程分为若干步骤,每一步由一个过滤器来完成,对多媒体数据流执行一个简单的操作。过滤器有输入和输出,它接受输入并产生输出。例如,对于一个解码过滤器,它的输入是按某种格式经过编码的多媒体数据流,它输出的是经过过滤器解码的数据流。
在应用程序中,为了完成对多媒体数据的处理,需要将若干过滤器连接起来,一个的输出作为另一个的输入,这样连接在一起的一组过滤器称为过滤器流水线(Filter Graph)。过滤器流水线也掌握着每一步该使用哪一个过滤器及这些过滤器之间是如何连接的。这样,多媒体数据流就在过滤器流水线上,从源过滤器经由中间过滤器移动到播放过滤器,从而得到播放。在这个过程中完成了数据的读取、解码、将数据输出到相应的设备、播放等操作。

过滤器之间数据传输的细节由插头(Pid)来处理。插头实际上是一个COM对象,分为输入插头和输出插头,一个过滤器包含一个输入插头和一个输出插头,或者包含其中的一个。插头相当于过滤器之间的连结点,位于上游的过滤器的输出插头和位于下游的过滤器的输入插头连结在一起。

过滤器及过滤器流水线的管理,是由一个更高一级组件来完成的,即过滤器流水线管理器(Filter Graph Manager),它提供对经过流水线的数据流的高级控制。通常,它会自动地为你处理数据流。应用程序一般不用直接操作过滤器,只需要执行一些较高级的调用,如运行(Run)、停止(Stop)等。
(VC下利用DirectShow播放多媒体文件.PDF)

2.1  滤波器(Filter)
滤波器是 DirectShow的最基本的组成元件。DirectShow对数据流的处理大致可以分成几个独立的过程,每个过程完成不同的工作。而滤波器正是完成这些过程的基本单元。事实上,用户的一个应用程序就是几个不同功能的滤波器合在一起的滤波器图(Filter Graph) 。
DirectShow Filter 可以分为以下几个种类:
(1)源滤波器(Source Filter)
源滤波器是整个滤波器图(Filter Graph)中处理输入数据的滤波器。它从外部设备获取原始数据并作简单处理,再将数据往下一级滤波器送。外部设备可以是文件系统、Internet 数据流、视频采集卡等。
(2)变换滤波器(Transform Filter)
变换滤波器是整个滤波器图(Filter Graph) 的核心,它从上一级滤波器获取数据并对它进行处理:把原始数据流转换成其它形式的多媒体数据流;压缩编码或解码;把一个数据流分解成多个数据流(Parse) ,如把一个音频视频混合流分解成单独的音频流和单独的视频流;把多个数据流组合成一个数据流等。
(3)提交滤波器(Render Filter)
提交滤波器在滤波器图里处于最后一级,它的作用就是把经过处理的数据流提交给外部设备。这里说的外部设备包括文件系统、显示卡、声卡、网卡等。

2.2  滤波器图(Filter Graph)
任何用DirectShow开发的应用程序,都必须创建多个滤波器并进行恰当的连接,于是数据流就可以从源滤波器经传送到 Render Filter 输出,被用户所使用。这些滤波器的集合就叫做滤波器图(Filter Graph) 。图2 就是一个 Filter Graph的例子。


图2  一个典型的滤波器图

2.3  Pin
Pin就是两个滤波器相连的接口。每一个 Pin 都是从Ipin这个 COM对象派生出来的。每个 Pin 都是滤波器私有对象,滤波器可以动态地创建 Pin,销毁 Pin,自由地控制 Pin的生存时间。Pin 可以分为两类:输入 Pin 和输出 Pin。两个相连的 Pin必须是不同种类的,就是输入Pin只能同输出 Pin 相连。数据就从相连的 Pin 中流动,从上一级滤波器到下一级滤波器。两个滤波器的Pin 相连的时候,有一个协商的过程,两者必须统一数据流的类型、缓存的大小、数据传送的机制等。如果协商没有统一,这两个滤波器就无法连接。

2.4  多媒体数据样本和多媒体数据类型
两个滤波器相连时,它们必须使用相同的数据类型。这样能保证下一级滤波器可以处理从上一级滤波器得到的数据。滤波器之间传输的数据也是经过了COM封装,称为多媒体数据样本(Media Type) ,使用了MediaSample 或 IMediaSample2 接口。在实际数据中,还包含了时间戳以求得同步。

2.5  时钟(Clock)
DirectShow的滤波器图管理器为整个滤波器图保持了统一的参考时钟,它对数据流的播放和同步有非常重要的作用。在每个MediaSample 中也使用了时间戳。

3  应用DirectShow 开发应用程序

3.1  COMLibrary的调用
由于DirectShow Filter 都是以COM的形式存在的,因此用户使用DirectShow Filter 开发自己的应用程序的时候必须在开始时初始化 COMLibrary,调用 CoInitialize 函数嵌入所有的动态链接库和资源。而且在程序结束的时候调用 CoUninitialize 函数释放所有的动态链接库和资源。

3.2  Filter Graph Manager接口
IGraphBuilder: 负责 Filter Graph的创建
应用程序通过此接口建立过滤器流水线。主要方法为:RenderFile,自动识别多媒体文件的类型、格式,建立适用于该格式的过滤器流水线。
IMediaControl: 操作Filter Graph 中的多媒体数据流
控制过滤器流水线的运行。主要方法为:Run开始运行;Pause,暂停运行;Stop,停止运行。
IMediaEvent(Ex): 处理 Filter Graph (Event)的事件
应用程序通过此接口获得播放过程中发生的事件,如 EC_COMPLETE(播放完毕)等。主要方法为:SetNotifyWindow,指定处理事件通知的窗口;GetEvent,获得事件。
IVideoWindow: 用于设置多媒体播放窗口的属性
控制视频窗口的属性。主要方法为:put_Owner,指定视频窗口的父窗口;put_FullScreenMode,指定全屏播放模式;SetWindowPosition,指定视频窗口的位置;put_MessagerDrain,指定一个窗口,用于接收视频窗口发出的鼠标等消息。
IMediaSeeking:提供了一些简单的搜索功能
提供了对多媒体数据流的播放位置等属性的精确控制。主要方法为:SetPositons,设置播放的起始和终止位置;GetCurrentPosition,获得当前播放位置。
IFilterMapper2:对注册表中的滤波器进行枚举
IBasicAudio:
控制音频数据流的基本属性:音量和均衡。主要方法:put_Volume、get_Volume,设置或获得音量;put_Balance、get_Balance,设置或获得均衡。

在实现多媒体文件的播放时需要用到上述的接口,这些接口的每个方法只执行一个简单的操作。因此,有必要对这些接口进行封装,见(VC下利用DirectShow播放多媒体文件.PDF)

3.3  创建 Filter Graph Manager接口
以下是创建 Filter Graph Manager接口的例子:
//首先申明并且初始化必需的接口。由于接口的索引值是自动加1 ,所以不要调用
// Iunknow::Addref
IGraphBuilder pGraph = NULL;
IMediaControl pMediaControl = NULL;
IMediaEvent pEvent = NULL;
IVideoWindow pVW = NULL;
IMediaSeeking pMS = NULL;
IFilterMapper2 pMapper = NULL;
// 实例化一个 Filter Graph Manager ,并且查询各接口
CoCreateInstance(CLSID_FilterGraph, NULL , CLSCTX_ INPROC_SERVER,
IID_ IGraphBuilder , (void **) &pGraph) ;
pGraph -> QueryInterface ( IID_IMediaControl , ( void **)&pMediaControl2 ) ;
pGraph ->QueryInterface(IID_IMediaEvent , (void** ) &pEvent) ;
pGraph ->QueryInterface(IID_IVideoWindow, (void**) &pVW) ;
pGraph2>QueryInterface IID_IMediaSeeking, void(**)&pMS ;
CoCreateInstance(CLSID_FilterMapper2 , NULL , CLSCTX _INPROC,
IID_IFilterMapper2 ,(void **) &pMapper) ;

3.4  创建 Filter Graph
所有的DirectShow Filter 都必须在 Windows 注册表中注册,它对应了一个 GUID(Globally unique identifier)和一些其它滤波器的属性,如支持的多媒体类型,滤波器的种类等等。Filter Graph Manager 就是通过搜索 Windows注册表来得到滤波器的信息,并采用合乎需要的滤波器来构建 Filter Graph。
应用DirectShow创建 Filter Graph可以完全不用用户操心系统使用了哪一类滤波器,滤波器是怎样连接的。只要调用IGraphBuilder::RenderFile函数,一个完整的Filter Graph就将诞生。下面分析一下 IGraphBuilder::RenderFile 的内部动作。
首先,IGraphBuilder 调用AddSourceFilter 去检测文件的类型,以确定应该使用哪一类的源滤波器。确定源滤波器后,再用 IFilterMapper2::EnumMatchingFilters 来搜索注册表中的滤波器,根据源滤波器的输出类型来确定传送滤波器(Transform Filter) ,接着,用 IFilterGraph::AddFil2
ter添加搜索到的滤波器。IFilterGraph 可以由 IGraphBuilder::AddSourceFilter后得到的一个 GUID,再用 CoCreateInstance 来得到。接下去就可以使用IGraph Builder::Connect 去连接两个滤波器。还可以用同样的方法添加其它滤波器,整个 Filter Graph就这样建立起来了。

3.5  使用 DirectShow的事件响应机制
DirectShow的事件响应机制是Filter Graph Manager与用户进行交互的接口,DirectShow可以处理的可以是一些事先可以预期的事件,比如数据流的结束;也可以是一些无法预期的错误。有的事件可以由 Filter Graph Manager自己处理,但如果 Filter Graph Manager 自己无法处理这些事件,它就把事件的通知放在事件队列里。用户程序就可以通过 IMediaEvent 接口得到事件,并对它作出响应。

你可能感兴趣的:(windows,manager,filter,Microsoft,Graph,preprocessor)