摘要:本篇文档中主要讲述了Graph图表中数据流是如何传递的,如果你是做Directshow的应用开发也许对于这些细节并不需要了解,如果你要开发自己的Filter,就很有必要了解这些细节。
Directshow数据流动概述 Filter之间的数据是通过Sample来传送的。Sample是一个COM组件,拥有自己的一段数据缓冲buffer,这个com组件暴露了IMediaSample接口。这个sample一般都有一个叫做内存分配器(alloctor)的com对象来创建管理,这个对象具有IMemAllocator接口。如下图所示:
图1 |
两个Filter之间的连接都要指定一个allocator,有时也有几个Filter连接同用一个allocator。每一个allocator都要创建一个media sample池,并且给每一个sample分配一个内存buffer。每当一个Filter需要一个buffer来填充数据,它就通过allocator的函数IMemAllocator::GetBuffer.来获得一个sample。如果分配器allocator正好有空闲的sample,GetBuffer立即返回一个指向该sample的指针。如果没有空闲的sample,该方法就阻塞,直到有一个sample可用为止。当该函数返回一个sample时,Filter就将数据填充到buffer里,设置好标识,然后就将sample传递给下一个Filter。
当一个Render Filter接收到一个sample时,它就检查该sample的时间戳,直到Fliter Graph的参考时钟表明该数据可用播放,Filter就开始播放该数据。当数据播放完毕,Filter释放sample,直到所有的Filter都释放对该sample的引用,该sample的引用计数为0时,这个sample才返回到sample池。
图2 |
有时也许数据流的上游对buffer的填充比播放要快,即使这样,render Filter也要按照时间戳播放数据,这样sample池中的sample数量就少,从而填充的速度减慢。
下面描述了在流中只有一个allocator的情景,实际上,在每条数据流中总是有好几个allocator,当一个sample被释放的时候,也许此时有好几个allocator都在等着该sample,这就有新的问题了,也许有的alloctor永远都不能被分配sample,陷入互锁状态。下面的图就演示了这种情形,Decoder有数据需要压缩,因此它在等待Renderer释放sample,但是,Parser也在请求sample,它在等待decoder释放sample。
图3 |
传输(Transports) 为了在过滤器图表中传送媒体数据,DirectShow过滤器需要支持一些协议,称之为传输协议(transport)。相连的过滤器必须支持同样的传输协议,否则不能交换媒体数据。
大多数的DirectShow过滤器把媒体数据保存在主存储器中,并通过引脚把数据提交给其它的过滤器,这种传输称为局部存储器传输(local memory transport)。虽然局部存储器传输在DirectShow中最常用,但并不是所有的过滤器都使用它。例如,有些过滤器通过硬件传送媒体数据,引脚只是用来提交控制信息,如IOverlay接口。
DirectShow为局部存储器传输定义了两种机制:推模式(push model)和拉模式(pull model)。在推模式中,源过滤器生成数据并提交给下一级过滤器。下一级过滤器被动的接收数据,完成处理后再传送给再下一级过滤器。在拉模式中,源过滤器与一个Render过滤器相连。Render过滤器向源过滤器请求数据后,源过滤器才传送数据以响应请求。推模式使用的是IMemInputPin接口,拉模式使用IAsyncReader接口,推模式比拉模式要更常用。