在上两讲中,笔者介绍了DirectShow的应用原理以及开发Filter之前的一些预备知识。这一讲,笔者就要手把手教你如何写自己的Filter啦。
首先,从VC++的项目开始(请确认你已经给VC++配置好了DirectX的开发环境)。写自己的Filter,第一步是使用VC++建立一个Filter的项目。由于DirectX SDK提供了很多Filter的例子项目(位于DXSDK/samples/Multimedia/DirectShow/ Filters目录下),最简单的方法就是拷贝一个,然后再在此基础上修改。但如果你是Filter开发的初学者,笔者并不赞成这么做。
自己新建一个Filter项目也很简单。使用VC++的向导,建立一个空的”Win32 Dynamic-link Library”项目。注意,几个文件是必须有的:.def文件,定义四个导出函数;定义Filter类的.cpp文件和.h文件,并在.cpp文件中定义Filter的注册信息以及两个Filter的注册函数:DllRegisterServer和DllUnregisterServer。(注:Filter的注册信息是Filter在注册时写到注册表里的内容,格式可以参考SDK的示例代码,Filter相关的GUID务必使用GuidGen.exe产生。)接下去进行项目的设置(Project->Settings…)。此时,你可以打开一个SDK的例子项目进行对比,有些宏定义完全可以照抄,最后注意将输出文件的扩展名改为.ax。
上一讲曾经提到过,在写Filter之前,选择一个合适的Filter基类是至关重要的。为此,你必须对几个Filter的基类有相当的了解。在实际应用中,Filter的基类并不总是选择CBaseFilter的。相反,因为我们绝大部分写的都是中间的传输Filter(Transform Filter),所以基类选择CTransformFilter和CTransInPlaceFilter的居多。如果我们写的是源Filter,我们可以选择CSource作为基类;如果是Renderer Filter,可以选择CBaseRenderer或CBaseVideoRenderer等。
总之,选择好Filter的基类是很重要的。当然,选择Filter的基类也是很灵活的,没有绝对的标准。能够通过CTransformFilter实现的Filter当然也能从CBaseFilter一步一步实现。下面,笔者就从本人的实际经验出发,对Filter基类的选择提出几点建议供大家参考。
首先,你必须明确这个Filter要完成什么样的功能,即要对Filter项目进行需求分析。请尽量保持Filter实现的功能的单一性。如果必要的话,你可以将需求分解,由两个(或者更多的)功能单一的Filter去实现总的功能需求。
其次,你应该明确这个Filter大致在整个Filter Graph的位置,这个Filter的输入是什么数据,输出是什么数据,有几个输入Pin、几个输出Pin等等。你可以画出这个Filter的草图。弄清这一点十分重要,这将直接决定你使用哪种“模型”的Filter。比如,如果Filter仅有一个输入Pin和一个输出Pin,而且一进一处的媒体类型相同,则一般采用CTransInPlaceFilter作为Filter的基类;如果媒体类型不一样,则一般选择CTransformFilter作为基类。
再者,考虑一些数据传输、处理的特殊性要求。比如Filter的输入和输出的Sample并不是一一对应的,这就一般要在输入Pin上进行数据的缓存,而在输出Pin上使用专门的线程进行数据处理。这种情况下,Filter的基类选择CSource为宜(虽然这个Filter并不是源Filter)。
当Filter的基类选定了之后,Pin的基类也就相应选定了。接下去,就是Filter和Pin上的代码实现了。有一点需要注意的是,从软件设计的角度上来说,应该将你的逻辑类代码同Filter的代码分开。下面,我们一起来看一下输入Pin的实现。你需要实现基类所有的纯虚函数,比如CheckMediaType等。在CheckMediaType内,你可以对媒体类型进行检验,看是否是你期望的那种。因为大部分Filter采用的是推模式传输数据,所以在输入Pin上一般都实现了Receive方法。有的基类里面已经实现了Receive,而在Filter类上留一个纯虚函数供用户重载进行数据处理。这种情况下一般是无需重载Receive方法的,除非基类的实现不符合你的实际要求。而如果你重载了Receive方法,一般会同时重载以下三个函数EndOfStream、BeginFlush和EndFlush。我们再来看一下输出Pin的实现。一般情况下,你要实现基类所有的纯虚函数,除了CheckMediaType进行媒体类型检查外,一般还有DecideBufferSize以决定Sample使用内存的大小,GetMediaType提供支持的媒体类型。最后,我们看一下Filter类的实现。首先当然也要实现基类的所有纯虚函数。除此之外,Filter还要实现CreateInstance以提供COM的入口,实现NonDelegatingQueryInterface以暴露支持的接口。如果我们创建了自定义的输入、输出Pin,一般我们还要重载GetPinCount和GetPin两个函数。
Filter框架的实现大致就是这样。你或许还想知道怎样在Filter上实现一个自定义的接口,以及怎么实现Filter的属性页等等。限于篇幅,笔者就不展开阐述了。其实,这些问题都能在SDK的示例项目中找到答案。其他的,关于在实际编程中应该注意的一些问题,笔者整理了一下,供大家参考。
1.锁(Lock)问题
DirectShow应用程序至少包含有两条线程:一条主线程和一条数据传输线程。既然是多线程,肯定会碰到线程同步的问题。Filter有两种锁:Filter对象锁和数据流锁。Filter对象锁用于Filter级别的如Filter状态转换、BeginFlush、EndFlush等;数据流锁用于数据处理线程内,比如Receive、EndOfStream等。如果这两种锁没有搞清楚,很容易产生程序的死锁,这一点特别需要提醒。
2.EndOfStream问题
当Filter接收到这个“消息”,意味着上一级Filter的数据都已经发送完毕。在这之后,如果Receive再有数据接收,也不应该去理睬它。如果Filter对输入Pin上的数据进行了缓存,在接收到EndOfStream后应确保所有缓存的数据都已经处理过了才能返回。
3.Media Seeking问题
一般情况下,你只需要在Filter的输出Pin上实现NonDelegatingQueryInterface方法,当用户申请得到IID_ImediaPosition接口或IID_IMediaSeeking接口时将请求往上一级Filter的输出Pin上传递。当Filter Graph进行Mediaseeking的时候,一般会调用Filter上的BeginFlush、EndFlush和NewSegment。如果你的Filter对数据进行了缓存,你就要重载它们,并做出相应的处理。如果你的Filter负责给发送出去的Sample打时间戳,那么,在Mediaseeking之后应该重新从零开始打起。
4.关于使用专门的线程
如果你使用了专门的线程进行数据的处理和发送,你需要特别小心,不要让线程进行死循环,并且要让线程处理函数能够去时时检查线程命令。应该确保在Filter结束工作的时候,线程也能正常地结束。有时候,你把GraphEdit程序关掉,但GraphEdit进程仍在内存中,往往就是因为数据线程没有安全关闭这个原因。
5.如何从媒体类型中获取信息
比如,你想在输入Pin连接的媒体类型中,获取视频图像的宽、高等信息,你应该在输入Pin的CompleteConnect方法中实现,而不要在SetMediaType中。
分享到:
相关推荐
基于directShow,打造全能播放器系列之二——简易播放器的补充 源码 对应博客地址: http://blog.csdn.net/harvic880925/article/details/7987798# 此博文仅供交流,转载请标明出处,谢谢
三、DirectShow开发流程 1. 创建过滤图:首先,你需要创建一个Filter Graph Manager,它是整个过滤图的管理者,负责建立和管理滤镜间的连接。 2. 添加滤镜:根据应用需求,向过滤图中添加适当的滤镜,例如,使用File...
### 利用DirectShow开发自定义Filter的知识点详解 #### 一、DirectShow简介与COM组件基础 **DirectShow**是Microsoft Windows操作系统中用于处理多媒体流的一种架构和技术框架。它支持实时音频视频流的捕获、压缩...
DirectShow 是微软开发的一个强大的多媒体框架,用于处理视频和音频流。它提供了一种标准的接口和组件模型,使得开发者可以构建复杂的媒体处理应用程序。在本主题中,我们将深入探讨如何利用DirectShow来实现图像的...
在本压缩包中,"利用 DirectShow 开发自己的 Filter_源码.rar" 提供了关于如何自定义 DirectShow Filter 的源代码,这对于理解 DirectShow 工作原理以及进行多媒体应用程序开发非常有帮助。 一个 DirectShow Filter...
这是我系统博文《基于directShow,打造全能播放器系列》第一篇“简易播放器的实现”源码,有兴趣的可以下载 博客地址: http://blog.csdn.net/harvic880925/article/details/7978566
DirectShow Filter 编写是Windows平台上进行多媒体处理和流媒体播放的重要技术。在这个例程中,我们将探讨如何从文件直接读取数据,而非一次性将整个文件加载到内存中,这通常被称为异步读取。这个过程涉及到对...
Directshow的Filter开发简要步骤-C++技术文章-C++-程序设计-技术资料
开发自己的 Filter 意味着你需要创建一个自定义的 COM 组件来扩展 DirectShow 的功能。 Filter 实质上是一个实现特定接口的 COM 组件,这些接口定义了 Filter 的行为和与其他 Filter 的交互方式。因此,要开发 ...
本资料包"利用 DirectShow 开发自己的 Filter_源码.zip"显然专注于如何利用DirectShow API来创建自定义的Filter,以扩展其功能或适应特定需求。 Filter是DirectShow中的核心组件,它们负责处理媒体数据的各个阶段,...
Directshow是一种由微软开发的多媒体框架,用于处理视频和音频流。它提供了低级的访问权限,使得开发者能够创建复杂的媒体处理应用程序,如播放器、捕获设备、视频编辑工具等。本技术资料深入浅出地讲解了Directshow...
### DirectShow SDK 开发知识点详解 #### 一、DirectShow概览 DirectShow是微软推出的一款强大且灵活的媒体框架,旨在为Windows平台上的多媒体应用提供流媒体处理能力。它是DirectX开发包的一部分,主要专注于视频...
- **熟悉DirectShow基类**:理解DirectShow提供的基础类是开发自定义Filter的前提。 - **Filter设计**:确定Filter的功能定位,如源Filter、变换Filter还是渲染Filter。 - **Pin连接**:设计Filter之间的数据传输...
### 基于DirectShow的虚拟摄像头开发框架详解 #### 概述 随着网络通信的日益普及,虚拟摄像头技术作为一种创新的数据输入解决方案,为网络会议、视频聊天等应用提供了更丰富的交互体验。传统虚拟摄像头技术通常...
这个压缩包“商业编程-源码-利用 DirectShow 开发自己的 Filter.zip”显然包含了关于如何利用 DirectShow 创建自定义滤镜(Filter)的源代码示例。在本文中,我们将深入探讨 DirectShow 技术及其在开发自定义 Filter...
DirectShow的核心概念是Filter Graph,它由一系列的Filter组成。每个Filter都是一个COM组件,负责特定的功能,例如源Filter从文件中读取数据,AVI Splitter Filter分离视频和音频流,Decoder Filters解码视频流,...
在探讨VS(Visual Studio)与DirectShow开发版本问题时,我们首先需要理解DirectShow是什么、它与DirectX的关系,以及如何确保使用的版本与VisualStudio版本兼容。本文将围绕这些核心内容进行详细介绍,帮助读者更好...
在Windows平台上,如果你计划进行DirectShow的开发工作,需要进行一系列的配置步骤来搭建合适的开发环境。下面我们将详细介绍DirectShow开发环境的配置过程。 首先,你需要安装基本的开发工具。这通常包括Visual ...
刚接触DirectShow的时候看代码无从下手,看SDK里面的例子也看不懂,网上也很少有适合初学者的资料,这是我用DirectShow连接的第一个filter,功能是把一组图片播放在指定的窗体上,控件是用MFC对话框中的图形控件做的