DirectShow学习指南之数据流结束通知

来源:百度文库 编辑:神马文学网 时间:2024/04/23 22:53:39
http://dev.21tx.com 2006年10月28日天极网 智慧的鱼
当一个源filter结束发送数据流时,它调用和它连接的filter的输入pin的IPin::EndOfStream,然后下游的filter再依次通知与之相连的filter。当EndOfStream方法一直调用到rendererfilter的时候,最后的一个filter就给filter图表管理器发送一个EC_COMPLETE事件通知。如果renderer有多个输入pin,当所有的输入pin都接收到end of stream通知的时候,它才会给filter图表管理器发送一个EC_COMPLETE事件通知。
Filter必须在其他函数调用之后调用EndOfStream函数,比如IMemInputPin::Receive.。
在一些情况下,下游的filter可能比源filter更早的发现数据流的结束。在这种情况下,下游filter发送结束stream的通知,同时,IMemInputPin::Receive函数返回S_FALSE直到图表管理器停止。这个返回值提示源filter停止发送数据。
对EC_COMPLETE事件的缺省处理
缺省的情况下,filter图表管理器并不将EC_COMPLETE事件通知发送给应用程序,当所有的数据流都发送了EC_COMPLETE事件通知后,它才给应用程序发送一个EC_COMPLETE事件通知。所以,应用程序只有在所有的数据流停止的时候才能接收到这个通知。
filter图表管理器通过计算支持seeking接口的filter,并且具有一个renderer pin,没有相应的输出pin,就可以确定数据流的数目。Filter图表管理器通过下面的方法来决定一个pin是否是个renderer 。
1、pin的IPin::QueryInternalConnections方法通过nPin参数返回0;
2、filter保露一个IAMFilterMiscFlags接口,并且返回一个AM_FILTER_MISC_FLAGS_IS_RENDERER标志。
在拉模式下的数据流结束通知
在IAsyncReader连接中,源filter并不发送数据流结束的通知,相应的发送数据流结束的通知是有renderer filter发出的。
New Segments
一个段就是一组media samples,这些sample具有共同的开始时间,结束时间,播放速率。
The IPin::NewSegment 方法用来通知一个new segments的开始。源filter通过这种方法来通知下游的filtersegment的开始时间和播放速率。例如,如果源filter在数据流中改变了新的开始点,它就用新的时间做参数来通知下游的filter。
下游的filter在处理sample的时候需要segment。例如,在桢间压缩的时候,if the stop time falls on adelta frame, the source filter may need to send additional samplesafter the stop time. This enables the decoder to decode the final deltaframe.为了确定正确的结束桢,解码器指向色gement的停止时间。另外一个例子,在音频播放的过程中,播放filter利用segment的速度和音频sample速度来产生正确的输出。
在推模式中,源filter产生一个新的segment,并初始化。在拉模式,这个工作是由剖析器(parser)来完成的。两种情况下,filter都调用下游filter的输入pin上的NewSegment,一直到达renderfilter。当filters调用数据流时候,必须序列化NewSegment。
当每一个新的segment,数据流的时间都被重新设置为零,当segment从零开始的时候,samples 重新贴上了time标签。
Flushing
当graph运行的时候,在整个graph中会有大量的数据流动。同时也有一些数据排在队列里等到传递。当graph移动这些未决的数据,并在该内存块中写入新的数据是需要一定的时间的。例如,在seek命令后,源filter在生成新的sample,这些是需要一定时间的。为了减小延迟,下游的filter在seek命令必须丢掉以前的sample。这个抛弃sample的过程就叫flushing。
当事件改变了数据的流向时,这可以使garph响应的更及时一些。
推模式和拉模式在处理flushing的时候有点不同。我们先讨论一下推模式,然后再讨论拉模式。
下面两种情况下发生flushing
1、源filter调用下游filter输入pin的IPin::BeginFlush方法,然后下游的filter就开始拒绝从上游filter接收数据流。然后它开始抛弃它正在处理的samples,继续调用下游filter的IPin::BeginFlush方法。
2、当源filter准备好新的数据时,它调用输入pin的IPin::EndFlush方法,这就告诉下游的filter可以接收新的samples,然后继续调用下游的filter的IPin::EndFlush。
在BeginFlush方法中,输入pin进行了下列工作:
1、首先调用下游filter的输入pin上的Calls BeginFlush方法
2、拒绝处理数据流,包括Receive和endofstream方法
3、取消那些正在阻塞等待filter释放allocator的等待,
4、如果filter正处于阻塞数据状态,那么filter就退出阻塞。例如当停止的时候Renderer filter就阻塞,此时,filter就要取消阻塞。
在EndFlush方法中,输入pin做了下列工作:
1、等待所有正在队列中的samples被抛弃
2、释放存放数据的buffer,这一步也可能在BeginFlush方法里,但是,beginflush方法streaming 线程是不同步的。Filter在BeginFlush和EndFlush方法之间不能够处理如何数据
3、清除所有的EC_COMPLETE通知
4、调用下游filter的EndFlush方法
此时,filter可以再次接收sample。
在拉模式中,parser Filter初始化flushing,而不是由sourcefilter,它不仅调用了下游filterIPin::BeginFlush andIPin::EndFlush方法,它又调用了源filter输出pin上的IAsyncReader::BeginFlush andIAsyncReader::EndFlush,如果此时,源filter有未决的read请求,它就抛弃
Seeking
Filter通过IMediaSeeking接口支持seeking。应用程序从filter图表管理器请求IMediaSeeking接口,然后通过这个接口,执行seek命令。Filter图表管理器传递到graph里所有的rendererfilter。每个renderer通过上游filter的输出pin来传递seek命令,直到某一个filter可以执行这个seek命令。一般来说,源filter,或者parserfilter可以执行seek 命令。
当一个filter执行seek命令的时候,它就flushes所有的未决的数据,这是为了减少seek命令的迟延。当一个seek命令后,stream time设置为零。
下面的图表演示了seek过程

图1
如果一个parser filter 的输出pin不止一个的话,它就指定一个pin来接收seek commands,其他的pin当接收到seek 命令时,就拒绝或者忽略seek 命令。这样,parser就保持了所有的数据流同步。
pin连接时数据格式的动态改变
当两个filter连接的时候,他们会就某种媒体类型达成协议。这种数据类型用来描述上游filter将传递什么格式的数据。大多数情况下,在连接的持续过程中,这个媒体类型是不变的,但是,directshow也支持动态改变媒体类型。
Directshow定义了一些机制来支持动态改变媒体类型。关键在于filter graph的状态和将要改变的类型。
如果graph处于停止状态,pin可以重新连接,重新就某个媒体类型达成协议。
一些filter还支持动态的连接,
当graph处于活动状态,并且不支持动态的重新连接的时候,有三种机制支持媒体类型的改变。
QueryAccept (Downstream) 适用于输出pin向下游的filter提出改变媒体类型,并且新的媒体格式的大小不超过原来的buffer。
QueryAccept (Upstream) 适用于输入pin首先向上游的filter提出媒体类型的改变,新的媒体类型格式可以和原来的大小一致,也可以大于。
ReceiveConnection适用于输出pin首先提出改变媒体类型,但是新的媒体类型的格式大于原来的buffer。