第三章DirectShow简介3.1DirectShow的功用(1)保证数据量庞大的多媒体数据处理的高效性;(2)时刻保持音频和视频的同步;(3)用简单的方法处理复杂的媒体源问题,包括本地文件,计算机网络,广播电视以及其他数码产品;(4)处理各种各样的媒体格式问题,包括AVI,ASF,MPEG,DV,MOV等;(5)支持目标系统中不可预知的硬件;DirectShow的设计初衷就是尽量要让应用程序开发人员从复杂的数据传输,硬件差异,同步性等工作中解放出来,总体应用框架和底层工作由DirectShow来完成。图3.1DirectShow系统Ring0特权级别的硬件设备,Ring3特权级别的应用层。按照功能Filter分为三类:SourceFilters-主要负责获取数据,数据源可以是文件,因特网计算机里的采集卡(WDM驱动或VFM驱动)数字摄像机等;TransformFilters-主要负责数据的格式转换,例如数据流分离/合成,解码/编码等;RenderingFilters-主要负责数据的昀终去向将数据传给显卡,声卡进行多媒体的演示,或者输出到文件进行存储。3.2COM编程基础如何创建COM组件如何得到组件对象上的接口以及调用接口方法如何管理组件对象(COM的引用记数机制)—DirectShow应用程序开发人员COM本身是一种规范,而不是实现COM组件是一个C++类,其接口都是纯虚类—Filter开发人员ClassIfuction//接口{public:virtualMethod1()=0;virtualMethod2()=0;};ClassMyObject:publicIfunction//COM组件{public:virtualMethod1();virtualMethod2();};CoInitialize(NULL);//COM库初始化//DosomethingIUnkown*pUnk=NULL;//COM规范规定,任何组件或接口都必须从IUnkown接口中继承IObject*pObject=NULL;//创建组件对象HRESULThr=CoCreateInstance(CLISD_Object,CLSCTX_INPROC_SERVER,NULL,IID_IUnkown,(void**)&pUnk);if(SUCCEEDED(hr)){//查询得到组件对象上的接口Hr=pUnk-QueryInterface(IID_IObject,(void**)&pObject;//IUnkown中负责组件对象上的接口查询的虚函数If(SUCCEEDED(hr)){//调用接口方法pObject-SomeMethod();//IUnkown中AddRef用于增加引用计数pObject-Release();//IUnkown中Release用于减少引用计数}pUnk-Release;}CoUninitialize();//释放COM库使用资源引用计数是COM中一个非常重要的概念,它很好的解决了组件对象的生命周期问题,即COM组件到底在什么时候被销毁,以及由谁来销毁的问题。COM组件有三种类型:进程内组件,本地进程组件和远程组件。Filter一般是一种进程内组件,以DLL(动态链接库)的形式提供服务。COM规范规定,每个组件都必须实现一个与之相对应的类工厂(ClassFactory).类工厂也是一个COM组件,用IClassFactory接口来实现,在IClassFactory的接口函数CreateInstance中,才能使用new操作生成一个COM组件类对象实例。CoCreateInstance(){IClassFactory*pClassFactory=NULL;CoGetClassObject(CLSID_Object,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(void**)&pClassFactory);//通过每个COM组件唯一标识调用CoGetClassObject来获得创建这个组件对象的类工厂pClassFactory-CreateInstance(NULL,IID_IUnkown,(void**)&pUnk);//调用类工厂接口方法创建CLSID_Object标识的真正组件pClassFactory-Release();}CoGetClassObject(){//通过查询注册表CLSID_Object得知组件DLL文件路径//装入DLL库(调用LoadLibrary)//使用函数GetProcAddress()得到DLL中函数DllGetClassObject的函数指针//调用DllGetClassObject得到类工厂对象指针}DllGetClassObject()//必须实现一个(导出)函数,根据指定的组件GUID创建相应的类工厂对象//返回类工厂IClassFactory接口{//创建类工厂对象CFactory*pFactory=newCFactory;//查询得到IClassFactory指针pFactory-QueryInterface(IID_IClassFactory,(void**)&pClassFactory);pFactory-Release();}CFactory::CreateInstance()//IClassFactory接口的方法,负责昀终创建组件对象实例{//创建CLSID_Object对应的组件对象CObject*pObject=newCObject;//我们的COM组件类,实现COM框架以外的真正组件功能pObject-QueryInterface(IID_IUnkown,(void**)&pUnk);pObject-Release();}典型自注册COM组件DLL所必需的5个(导出)函数:DllMain:DLL的入口函数(DirectShow实现的是DllEntryPoint);DllGetClassObject:在创建Filter对象时被调用,根据CLSID返回对应类工厂指针;DllCanUnloadNow:系统空闲时会调用这个函数,以确定是否可以卸载DLL;DllRegisterServer:将COM组件注册到注册表中;STDAPIDllRegisterServer(){returnAMovieDllRegisterServer2(TRUE);}DllUnregisterServer:删除注册表中COM组件的注册信息;STDAPIDllUnregisterSever(){returnAMovieDllREgisterServer2(FALSE);}第四章Filter原理4.1Filter概述Filter一般由一个或多个Pin组成,Filter之间通过Pin相互连接,构成一条顺序链路。Filter是一种COM组件,为实现在FilterGraph中的统一操作,每个Filter上都至少实现了IBaseFilter接口,实现Filter的文件一般是一个DLL,扩展名可以是dll,但更多的时候是ax.。跟普通的COM组件一样,Filter的创建是通过API函数CoCreateInstance来完成的:STDAPICoCreateInstance{REFCLSIDrclsid,//指定要创建的Filter的CLSIDLPUNKOWNpUnkOutter,//绝大多数情况下创建的Filter不是被“聚合“的,所以pUnkOuter指定为NULLDWORDdwClsContext,//可指定为CLSCTX_INPROC_SERVER,以创建进程内组件对象REFIIDriid,//riid在创建Filter成功后获得的接口的ID,一般为IID_IBaseFilter,也可以是其他特殊接口LPVOID*ppv//用于获得接口对象的指针}4.2Filter的注册Filter的注册程序为regsvr32.exe(位于操作系统目录的system32子目录下)。假设现在有一个Filter文件,它的完整路径为C:\DSFilter\myFilter.ax.注册这个Filter的方法为:在命令行的状态下,执行regsvr32C:\DSFilter\myFilter.ax.随后会弹出一个对话框,告诉Filter是否注册成功。注销Fliter也使用regsvr32.exe程序,方法为加命令行参数/u,即执行regsvr32/uC:\DSFilters\myFilter.ax.判断Filter是否注册BOOLIsFilterRegistered(CLSIDinFilterId){IBaseFilter*pFilter=NULL;If(SUCCEEDED(CoCreateInstance(inFilterId,NULL,CLSCTX_INPRO_SERVER,IID_IBaseFilter,(void)**&pFilter))){pFilter-Release();returnTURE;}ReturnFALSE;}在应用程序中注册(或注销)某个Filter文件只要在应用程序中使用LoadLibrary装载这个Fliter文件,并得到它的导出函数DllRegisterServer(DllUnregisterSever)的入口地址,然后执行。BOOLRegisterFilter(constchar*inFilterAx){typedef(WINAPI*REGISTER_FUNC)(void);REGISTER_FUNCMyFunc=NULL;HMODULEhModule=::LoadLibrary(inFilterAx);If(hModule){MyFunc=(REGISTER_FUNC)GetProAddress(hModule,”DllRegisterServer”);BOOLpass=(MyFunc!=NULL);If(pass){MyFunc();}::FreeLibrary(hModule);returnpass;}returnFLASE;}Filter的注册信息一般包括两部分:基本的COM信息和Filter特有信息。前者是基本的COM组件所必需的信息;后者是描述Filter的信息(包括Filter注册的类型目录,Filter上的Pin数量,支持的媒体类型等),这部分内容会被系统枚举器或者Filter影射器访问到,但不是必须的。4.3Filter的媒体类型类型媒体用来描述格式化的数据流,DirectShow中定义一个数据结构AM_MEDIA_TYPE:typedefstruct_MediaType{GUIDmajortype;//主类型GUIDsubtype;//辅助说明类型BOOLbFixedSizeSample;//BOOLbTemporalcompression;ULONGISampleSize;GUIDformattype;//格式细节类型IUnkown*pUnk;ULONGcbFormat;/*[size_is]*/BYTE*pbFormat;}AM_MEIDA_TYPE;当使用AM_MEDIA_TYPE数据结构描述媒体类型时,如果majortype,subtype和formatype都指定一个特定的GUID值,称为“完全指定媒体类型”;这三个部分只要有一个指定为GUID_NULL,则称之为“不完全指定的媒体类型”。GUID_NULL具有“通配符”的作用。4.4Filter的连接Filter的连接世上是Fliter上Pin的连接,连接的方向总是由上一级Filter(UpstreamFilter)的输出Pin指向下一级Filter(DownstreamFilter)的输入Pin。Pin的连接实际上是连接双方使用的媒体类型的一个“协商”过程。4.4.1连接过程Pin也是一种COM组件,而且每个Pin上都实现了IPin接口。首先连接Filter的是应用程序,一般通过调用接口方法IFilterGraph::ConnectDire