DirectShow组件开发入门级一

来源:互联网 发布:支付宝能登录淘宝吗 编辑:程序博客网 时间:2024/06/06 02:58

DirectShow组件开发入门级一

 

一、先来段directShow简介吧:

 

         DirectShow是一个windows平台上的流媒体框架,提供了高质量的多媒体流采集和回放功能。它支持多种多样的媒体文件格式,包括ASF、MPEG、AVI、MP3和WAV文件,同时支持使用WDM驱动或早期的VFW驱动来进行多媒体流的采集。DirectShow整合了其它的DirectX技术,能自动地侦测并使用可利用的音视频硬件加速,也能支持没有硬件加速的系统。
         DirectShow大大简化了媒体回放、格式转换和采集工作。但与此同时,它也为用户自定义的解决方案提供了底层流控制框架,从而使用户可以自行创建支持新的文件格式或其它用途的DirectShow组件。
        以下是几个使用DirectShow编写的典型应用:DVD播放器、视频编辑应用、AVI到ASF转换器、MP3播放器和数字视频采集应用。
        同时,DirectShow是建立在组件对象模型(COM)上的,因此当你编写DirectShow应用时,你必须具备COM客户端程序编写的知识。对于大部分的应用,你不需要实现自己的COM对象,DirectShow提供了大部分你需要的DirectShow组件,但是假如你需要编写自己的DirectShow组件,你还需要具备编写COM组件的知识。因此在开发Filter组件时,每个Filter组件都是相应的一个COM模型,该模型提供了相应的接口,以及数据处理的方式,当然要细究COM模型,就得对COM编程有一定程度的学习,这里只是做下简介,要学习directshow的组件编程不用着急,下面小菜徐徐道来:

 

二、要学习directShow编程,起码要掌握简单的Com编程思想,这里也稍微谈下COM思想:

 

       COM是一种跨应用和语言共享二进制代码的方法,同C++不同,它提倡源代码重用。ATL便是一个很好的例证。源码级重用虽然好,但只能用于C++。它还带来了名字冲突的可能性,更不用说不断拷贝重用代码而导致工程膨胀和臃肿。

       Windows使用DLLs在二进制级共享代码,本身也是windows程序运行的关键,正如重用的kernel32.dll, user32.dll,另外在MFC下引入了一种MFC扩展DDLs二进制共享机制,但该使用受限在MFC程序下;由于COM通过定义二进制标准通过的是二进制级别的方式,可以独立于任何编程语言,通过制定所需要的接口,任何编程语言都可以轻松的从中获取相应的模块,这就是COM编程的好处丫,当然以上如有讲的不全,各位大牛请提出批评指点
       接下来细说下COM组件的接口,COM组件都是由一系列接口提供方法来对外实现的,接口下其实就是一个申明了一系列函数的类,称为接口类,接口类对应的内部实现一般都是在以C开头的实现类下,正如DirectShow下的CBaseFilter是相应的实现类,该实现类有提供的一个接口IBaseFilter,大家可以查看里面相应的代码,就会发现IBaseFilter下的函数方法只是一个申明,并没有相应的实现,实现该内部的方法都是在CBaseFilter下的;因此在编写规范上,接口名字以大写的I开头,再如C++中的IShellLink,接口被设计成一个抽象基类,其中只有纯粹的虚拟函数。

       接口也可以从其他接口继承,其实正如C++下的单继承,接口是不允许多继承的;coclass(简称组件对象类——component object class)被包含在DLL或EXE中,并且包含着一个或者多个接口的代码。组件对象类(coclasss)实现这些接口。COM对象在内存中表现为组件对象类(coclasss)的一个实例。另外对于每一个COM组件,都有一个相应的表示ID,称之为GUID,该标识是全球唯一的,组件的使用需要经过注册阶段,是一个通过创建注册表入口的过程,告诉了windows操作系统COM服务器放在什么位置。而取消注册则是删除这些注册入口。对于GUID有很多中应用,在COM编程中有对于组件标识的CLSID和对应接口命名的IID。

       在组件的开发中,组件中的接口具有多个,如何获取组件的不同功能下的接口呢?其实在组件编程中,如下图所示,组件中的每个接口都是继承在IUnknow接口下,每个接口中都有相应的三个方法,Release(),AddRef(),QueryInterface(),当中的QueryInterface()就是主要针对接口查询而由来的,通过QueryInterface加上GUID表示,你就可以获得你注册过的相应接口或者组件;而AddRef(),则是用来通知COM对象增加它的引用计数。如果你进行了一次接口指针的拷贝,就必须调用一次这个方法,并且原始的值和拷贝的值两者都要用到。Release组要是用来进行资源的统计,通知COM对象减少它的引用计数,当引用计数值为0时,COM组件的所有资源将会被释放。当然这个资源的释放一般在COM组件中如若没有自动进行释放,则需要我们对其进行释放,因此在编写COM组件时,要记得在必要时刻进行资源的释放,这里先讲下可以通过JoinFilterGraph这个方法来得知如何应当进行资源的释放。具体的释放过程会以后慢慢的进行分析,呵呵。

             HRESULT IUnknown::QueryInterface (REFIID iid,void** ppv );

            以下是参数解释:

           iid:所请求的接口的IID。

           ppv:接口指针的地址,QueryInterface()通过这个参数在成功时返回这个接口。

                  

 

       除了IUnknown接口外,还有另一个重要的接口IClassFactory,COM组件实际上是一个C++类,对于组件的外部使用者来说,这个类名一般不可知,如何创建这个类的实例呢,由谁创建?COM规范规定,每个组件都必须实现一个与之相对应的类厂,类厂也是一个COM组件,它实现了IClassFactory接口,在IClassFactory的接口函数CreateInstance中,才能使用new操作生成一个COM组件类对象实例。

       COM组件有三种类型:进程内组件,本地进程组件和远程组件。Filter一般是一种进程内组件,以DLL动态链接库的形式提供服务。

                  

       在CocreateInstance函数中,相应实现了CoGetClassObject方法,创建了一个COM库,通过查询注册表CLSID_Object得知组件DLL文件路径,装入DLL库,该方法通过调用DLLGetClassObject来获得类工厂对象指针,最后并通过CreateInstance方法来实现一个组件对象的实例,也就是利用queryInterface接口查询来的相对应注册表下的组件对象实例后的指针。

 

三、对于COM组件的开发,大致有了一个认识后,我们了解下COM组件的应用过程:

 

COM组件的应用,首先会先调用CoCreateInstance方法来创建一个COM对象的Filter Graph Manager组件,代码如下:

          IgraphBuilder*pGraph = NULL;

          HRESULT  hr = CoCreateInstance(CLSID_FilterGraph,NULL,

                                     CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(Void**)pGraph);

       紧接着,如果在COM组件下实现了相关的接口,这可以通过上面描述过的QueryInterface方法来结合IID接口查询,便可以得到相应的接口,针对AVI文件,便可以直接通过RenderFile方法直接创建一条完整的链路,如下所示

Hr =pGraph->RenderFile(L”D:\\123.avi”,NULL);

       最后一个阶段,就是调用Filter Graph Manager上的各个接口方法进行控制,并且完成Filter Graph Manager与应用程序的事件进行交互,如调用IMediaControl接口方法控制Filter Graph的状态转换,代码如下:

          IMediaControl*pControl = NULL;

          Hr =pGraph->QueryInterface(IID_IMediaControl,(Void O**)pControl);

          Hr =pControl->Run();            //运行Filter Graph

       以上简单的讲述了关于COM编程的简单思想以及COM组件的DirectShow应用流程,下一步将进一步深入的分析COM组件下的DirectShow开发的相关知识体系,讲之不全之处,还望各位共同学习交流一起指出,本人也将会不断更新每一篇文章进行错误纠正。

 

 

相关知识点摘要:陆其明的《DirectShow开发指南》

原创粉丝点击