教做美食网站源码,佛山h5模板建站,云南网站建设公司排行,做电信宽带合适做网站吗文章来源#xff1a;http://tech.163.com/school 2005-08-18 10:21:32 来源: 天极网摘要#xff1a;本篇文档概括性的介绍了DirectShow的主要组成部分#xff0c;以及一些Directshow的基本概念。熟悉这些基本的知识对于Directshow的应用开发或者过滤器的开发者都会有所帮助…文章来源http://tech.163.com/school · 2005-08-18 10:21:32 · 来源: 天极网摘要本篇文档概括性的介绍了DirectShow的主要组成部分以及一些Directshow的基本概念。熟悉这些基本的知识对于Directshow的应用开发或者过滤器的开发者都会有所帮助。 DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包与DirectX开发包一起发布。那么DirectShow能够做些什么呢且看DirectShow为多媒体流的捕捉和回放提供了强有力的支持。运用DirectShow我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据并且进行相应的后期处理乃至存储到文件中。它广泛地支持各种媒体格式包括Asf、Mpeg、Avi、Dv、Mp3、Wave等等使得多媒体数据的回放变得轻而易举。另外DirectShow还集成了DirectX其它部分比如DirectDraw、DirectSound的技术直接支持DVD的播放视频的非线性编辑以及与数字摄像机的数据交换。更值得一提的是DirectShow提供的是一种开放式的开发环境我们可以根据自己的需要定制自己的组件。 应用程序与DirectShow组件以及DirectShow所支持的软硬件之间的关系如图1所示。
图1 DirectShow系统框图 1、DirectShow的 FilterDirectshow是基于模块化每个功能模块都采取COM组件方式称为Filter。Directshow提供了一系列的标准的模块可用于应用开发开发者也可以开发自己的功能Filter来扩展Directshow的应用。下面我们用一个例子来说明如何采取Filter来播放一个AVI的视频文件。1) 首先从一个文件中读取AVI数据形成字节流。这个工作由源Filter完成2) 检查AVI数据流的头格式然后通过AVI分割Filter将视频流和音频流分开。3) 解码视频流根据压缩格式的不同选取不同的decoder filters 。4) 通过Renderer Filter重画视频
图像。5) 音频流送到声卡进行播放一般采用缺省的 DirectSound
DeviceFilter。流程见下图。图2 音频流播放Graph图 从上面的图表看每一个filter都一个其他的一个或者两个filter相连接。两个Filter相连接的连接点也是com对象我们称为Pin。 Filter通过pin将数据从一个filter传递到另一个filter中从而可以使数据在由filter组成的链表中流动。图中的箭头表示 filter链表中的数据流的方向。在Directshow中像上面的这样一个filter 链表我们称为filter Graph。Filter具有三个状态运行停止暂停。当一个filter运行时它就处理媒体数据流当停止时filter就不在处理数据暂停状态常用来给运行状态之前cure data。Data Flow in the Filter Graph一章详细描述了这些概念可以参考。除了一些特别的例外 Filter graph中所有的filter的状态的改变都是统一的也就说filte graph中的所有的filter 的状态改变是一致协调的。也就是说我们也可以用filter graph也可以有运行停止暂停三种状态。Filter 一般分为下面几种类型。1源过滤器
sourcefilter源过滤器引入数据到过滤器图表中数据来源可以是文件、网络、
照相机等。不同的源过滤器处理不同类型的数据源。2变换过滤器transform filter变换过滤器的工作是获取输入流处理数据并生成输出流。变换过滤器对数据的处理包括
编解码、格式转换、压缩解压缩等。3提交过滤器renderer filter提交过滤器在过滤器图表里处于最后
一级它们接收数据并把数据提交给外设。4分割过滤器splitter filter分割过滤器把输入流分割成多个输出。例如AVI分割过滤器把一个AVI格式的字节流分割成视频流和音频流。5混合过滤器mux filter混合过滤器把多个输入组合成一个单独的数据流。例如AVI混合过滤器把视频流和音频流合成一个AVI格式的字节流。过滤器的这些分类并不是绝对的例如一个ASF读过滤器ASF Reader filter既是一个源过滤器又是一个分割过滤器。2、关于Filter Graph ManagerFilter Graph Manager也是一个com对象用来控制Filter graph中的所有的filter主要有以下的功能1) 用来协调filter之间的状态改变从而使graph 中的所有的filter的状态的改变应该一致。2) 建立一个参考时钟。3) 将filter 的消息通知返回给应用程序4) 提供用来建立 filter graph的方法。这里只是简单的描述一下详细地可以参考文档。状态改变Graph中的filter的状态改变应该一致因此应用程序并将状态改变的命令直接发给filter而是将相应的状态改变的命令发送给 Filter graph Manager由manager将命令分发给graph中每一个filter。Seeking也是同样的方式工作首先由应用程序将seek命令发送到 filter graph 管理器然后由其分发给每个filter。参考时钟graph中的filter都采用的同一个时钟称 为参考时钟reference clock参考时钟可以确保所有的数据流同步视频桢或者音频桢应该被提交的时间称为presentation time.presentation time 是相对于参考时钟来确定的。Filter graph Manager应该选择一个参考时钟可以选择声卡上的时钟也可以选择系统时钟。Graph事件 Graph 管理器采用事件机制将graph中发生的事件通知给应用程序这个机制类似于
windows的消息循环机制。Graph构建的方法graph管理器给应用程序提供了将filter添加进graph的方法连接filter的方法断开filter连接的方法。但是graph 管理器没有提供如何将数据从一个filter发送到另一个filter的方法这个工作是由filter在内部通过pin来独立完成的3、媒体类型 因为Directshow是基于com组件的就需要有一种方式来描述filter graph每一个点的数据格式例如我们还以播放AVI文件为例数据以RIFF块的形式进入graph中然后被分割成视频和音频流视频流有一系列的压缩的视频桢组成解压后视频流由一系列的无压缩的位图组成音频流也要走同样的步骤。Media Types: How DirectShow Represents Formats 媒体类型是一种很普遍的可以扩展的用来描述数字媒体格式的方法当两个filter连接的时候他们会就采用某一种媒体类型达成一致的协议。媒体类型定义了处于源头的filter将要给下游的filter发送什么样的数据以及数据的physical layout。如果两个filter不能够支持同一种的媒体类型那么他们就没法连接起来。 对于大多数的应用来说也许你不用考虑媒体类型但是有些应用程序中你会直接应用到媒体类型的。 媒体类型是通过AM_MEDIA_TYPE结构定义的看看原始定义吧typedef struct _MediaType { GUID majortype; GUID subtype; BOOL bFixedSizeSamples; BOOL bTemporalCompression; ULONG lSampleSize; GUID formattype; IUnknown *pUnk; ULONG cbFormat; [size_is(cbFormat)] BYTE *pbFormat;} AM_MEDIA_TYPE; Major type:是一个GUID用来定义数据的主类型包括音频视频unparsed字节流MIDI数据等等具体可以参考msdn。 Subtype:子类型也是一个GUID用来进一步的细化数据格式例如在视频主类型中还包括RGB-24, RGB-32, UYVY等等一些子类型在音频主类型中还包括PCM audio, MPEG-1 payload等类型子类型提供了比主类型更详细的信息但是并没有定义所有的格式例如视频的子类型并没有定义图像大小桢率。这些由下面的字段定义。 bFixedSizeSamples当这个值为TRUE时表示sample大小固定。 bTemporalCompression当这个值为TRUE时表示sample采用了临时压缩格式表明不是所有的桢都是关键桢如果为FALSE表明所有的都是关键桢。 lSampleSize 表示sample的大小。对于压缩的数据这个值可能为零。 Formattype一个GUID值用来表明内存块的格式。包括如下FORMAT_NoneFORMAT_DvInfoFORMAT_MPEGVideoFORMAT_MPEG2VideoFORMAT_VideoInfoFORMAT_VideoInfo2FORMAT_WaveFormatExGUID_NULL。 pUnk该参数没有用到。 cbFormat内存块的大小。 pbFormat指向内存块的指针。 下面我们看一段代码看看filter如何检测媒体类型的。HRESULT CheckMediaType(AM_MEDIA_TYPE *pmt){ if (pmt NULL) return E_POINTER; // Check the major type. We’re looking for video. if (pmt-majortype ! MEDIATYPE_Video) { return VFW_E_INVALIDMEDIATYPE; } // Check the subtype. We’re looking for 24-bit RGB. if (pmt-subtype ! MEDIASUBTYPE_RGB24) { return VFW_E_INVALIDMEDIATYPE; } // Check the format type and the size of the format block. if ((pmt-formattype FORMAT_VideoInfo) (pmt-cbFormat sizeof(VIDEOINFOHEADER) (pmt-pbFormat ! NULL)) { // Now it’s safe to coerce the format block pointer to the // correct structure, as defined by the formattype GUID. VIDEOINFOHEADER *pVIH (VIDEOINFOHEADER*)pmt-pbFormat; // Examine pVIH (not shown). If it looks OK, return S_OK. return S_OK; } return VFW_E_INVALIDMEDIATYPE;} 下面简单介绍几个和 Media Type相关的函数 AM_MEDIA_TYPE结构包含一个指向数据块的指针因此当你使用这个结构的时候一定要小心内存分配以防内存泄漏。 分配函数 1) AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc ); 这个函数分配一个新的AM_MEDIA_TYPE结构包含特定格式的数据块。释放由这个函数分配的内存可以调用DeleteMediaType函数 2) STDAPI CreateAudioMediaType(const WAVEFORMATEX *pwfx,AM_MEDIA_TYPE *pmt,BOOL bSetFormat); 该函数利用一个给定的WAVEFORMATIEX结构来初始化媒体类型如果bsetFormat参数为TRUE该函数就分配一块新的内存如果原来的pmt已经包含内存就有可能发生内存泄漏。为了避免内存泄漏在调用这个函数前要调用FreeMediaType在这个函数返回之后再次调用 FreeMediaType释放format block。 3) HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget,const AM_MEDIA_TYPE *pmtSource); 这个函数复制了一个结构到另一个结构中去。这个函数也要重新分配内存给目的结构如果pmtTarget,已经包含一个内存块就要内存泄漏因此在调用该函数前后都要调用FreeMediaType函数。 释放函数 4) void WINAPI DeleteMediaType( AM_MEDIA_TYPE *pmt); 无论是采用CoTaskMemAlloc函数还是用CreateMediaType函数分配的内存都可以用这个函数来释放如果你没有连接基类的动态库你可以用下面的代码void MyDeleteMediaType(AM_MEDIA_TYPE *pmt){ if (pmt ! NULL) { MyFreeMediaType(*pmt); // 见下面的 FreeMediaType 函数 CoTaskMemFree(pmt); }} 5) void WINAPI FreeMediaType( AM_MEDIA_TYPE mt); 这个函数用来释放数据块的内存如果要删除AM_MEDIA_TYPE结构可以使用DeleteMediaType函数。void MyFreeMediaType(AM_MEDIA_TYPE mt){ if (mt.cbFormat ! 0) { CoTaskMemFree((PVOID)mt.pbFormat); mt.cbFormat 0; mt.pbFormat NULL; } if (mt.pUnk ! NULL) { // Unecessary because pUnk should not be used, but safest. mt.pUnk-Release(); mt.pUnk NULL; }}
4、媒体Samples和Allocators Filters通过pin的连接来传递数据数据流是从一个filter的输出pin流向相连的filter的输入pin。输出pin常用的传递数据的方式是调用输入pin上的IMemInputPin::Receive方法。 对于filter来说可以有好几种方式来分配媒体数据使用的内存块可以在堆上分配可以在DirectDraw的表面也可以采用GDI共享内存还有其他的一些方法在Directshow中用来进行内存分配任务的是内存分配器allocator也是一个COM对象暴露了一个 IMemAllocator接口。 当两个pin连接的时候必须有一个pin提供一个allocatorDirectshow定义了一系列函数调用用来确定由哪个pin提供allocator以及buffer的数量和大小。 在数据流开始之前allocator会创建一个内存池pool of buffer在开始发送数据流以后源filter就会将数据填充到内存池中一个空闲的buffer中然后传递给下面的filter。但是源 filter并不是直接将内存buffer的指针直接传递给下游的filter而是通过一个media samples的COM对象这个sample是allocator创建的用来管理内存buffer。Media sample暴露了IMediaSample接口一个sample包含了下面的内容 一个指向没有发送的内存的指针。 一个时间戳 一些标志 媒体类型。 时间戳表明了presentation timeRenderer filter就是根据这个时间来安排render顺序的。标志是用来标示数据是否中断等等媒体类型提供了中途改变数据格式的一种方法不过一般 sample没有媒体类型表明它们的媒体类型一直没有改变。 当一个filter正在使用buffer它就会保持一个sample 的引用计数allocator通过sample的引用计数用来确定是否可以重新使用一个buffer。这样就防止了buffer的使用冲突当所有的 filter都释放了对sample的引用sample才返回到allocator的内存池供重新使用。 5、硬件设备在graph中的作用 下面的这段话借用的是陆其明的一段文档特此标记2005-1-26我觉得他对硬件的表述比较清楚。 大家知道为了提高系统的稳定性Windows操作系统对硬件操作进行了隔离应用程序一般不能直接访问硬件。DirectShow Filter工作在用户模式User mode操作系统特权级别为Ring 3而硬件工作在内核模式Kernel mode操作系统特权级别为Ring 0那么它们之间怎么协同工作呢 DirectShow解决的方法是为这些硬件设计包装Filter这种Filter能够工作在用户模式下外观、控制方法跟普通Filter一样而包装Filter内部完成与硬件驱动程序的交互。这样的设计使得编写DirectShow应用程序的开发人员从为支持硬件而需做出的特殊处理中解脱出来。DirectShow已经集成的包装Filter包括Audio Capture Filterqcap.dll、VfW Capture Filterqcap.dllFilter的Class Id为CLSID_VfwCapture、TV Tuner FilterKSTVTune.axFilter的Class Id为CLSID_CTVTunerFilter、Analog Video Crossbar Filterksxbar.ax、TV Audio FilterFilter的Class Id为CLSID_TVAudioFilter等另外DirectShow为采用WDM驱动程序的硬件设计了KsProxy FilterKsproxy.ax,。我们可以看一下结构图见图1 我们可以看出Ksproxy.ax、Kstune.ax、 Ksxbar.ax这些包装Filter跟其它普通的DirectShow Filter处于同一个级别可以协同工作用户模式下的Filter通过Stream Class控制硬件的驱动程序minidriver由硬件厂商提供的实现对硬件控制功能的DLLStream Class和minidriver一起向上层提供系统底层级别的服务。值得注意的是这里的Stream Class是一种驱动模型它负责调用硬件的minidriver另外Stream Class的功能还在于协调minidriver之间的工作使得一些数据可以直接在Kernel mode下从一个硬件传输到另一个硬件或同一个硬件上的不同功能模块提高了系统的工作效率。更多的关于底层驱动程序的细节请读者参阅 Windows DDK。 下面我们分别来看一下几种常见的硬件。 VfW视频采集卡。这类硬件在市场上已经处于一种淘汰的趋势新生产的视频采集卡一般采用WDM驱动模型。但是DirectShow为了保持向后兼容还是专门提供了一个包装Filter支持这种硬件。和其他硬件的包装Filter一样这种包装Filter的创建不是像普通Filter一样使用CoCreateInstance而要通过系统枚举然后BindToObject。 音频采集卡声卡。声卡的采集功能也是通过包装Filter来实现的而且现在的声卡大部分都有混音的功能。这个Filter一般有几个Input pin每个pin都代表一个输入如Line In、Microphone、CD、MIDI等。值得注意的是这些pin代表的是声卡上的物理输入端子在Filter Graph中是永远不会连接到其他Filter上的。声卡的输出功能可以有两个Filter供选择DirectSound Renderer Filter和Audio Renderer (WaveOut) Filter。注意这两个Filter不是上述意义上的包装Filter它们能够同硬件交互是因为它们使用了API函数前者使用了 DirectSound API后者使用了waveOut API。这两个Filter的区别还在于后者输出音频的同时不支持混音。顺便说明一下Video Renderer Filter能够访问显卡也是因为使用了GDI、DirectDraw或Direct3D API。如果你的机器上有声卡的话你可以通过GraphEdit在Audio Capture Sources目录下看到这个声卡的包装Filter。 WDM驱动的硬件包括视频捕捉卡、硬件解压卡等。这类硬件都使用 Ksproxy.ax这个包装Filter。Ksproxy.ax实现了很多功能所以有“瑞士军刀”的美誉它还被称作为“变色龙Filter”因为该Filter上定义了统一的接口而接口的实现因具体的硬件驱动程序而异。在Filter Graph中Ksproxy Filter显示的名字为硬件的Friendly name一般在驱动程序的.inf文件中定义。我们可以通过GraphEdit在WDM Streaming开头的目录中找到本机系统中安装的WDM硬件。因为KsProxy.ax能够代表各种WDM的音视频设备所以这个包装Filter的工作流程有点复杂。这个Filter不会预先知道要代表哪种类型的设备它必须首先访问驱动程序的属性集然后动态配置Filter上应该实现的接口。 当Ksproxy Filter上的接口方法被应用程序或其他Filter调用时它会将调用方法以及参数传递给驱动程序由驱动程序最终完成指定功能。除此以外WDM硬件还支持内核流Kernel Streaming即内核模式下的数据传输而无需经过到用户模式的转换。因为内核模式与用户模式之间的相互转换需要花费很大的计算量。如果使用内核流不仅可以避免大量的计算还避免了内核数据与主机内存之间的拷贝过程。在这种情况下用户模式的Filter Graph中即使pin之间是连接的也不会有实际的数据流动。典型的情况如带有Video Port Pin的视频捕捉卡Preview时显示的图像就是在内核模式下直接传送到显卡的显存的。所以你也休想在VP Pin后面截获数据流。 讲到这里我想大家应该对DirectShow对硬件的支持问题有了一个总体的认识。对于应用程序开发人员来说这方面的内容不用研究得太透而只需作为背景知识了解一下就好了。其实大量繁琐的工作DirectShow已经帮我们做好了。