DirectShow SDK笔记【关于DirectShow(4)】

6      Time and Clocks in DirectShow
 
       6.1    Reference Clocks
       参考时钟是 Filter Graph Manager 用来同步所有 Filter 的。任何一个暴露了 IReferenceClock 接口的对象都可以作为参考时钟。参考时钟可以是 Filter 提供,例如声卡就可以提供一个硬件的时钟。作为应变, Filter Graph Manager 也可采用系统的时间。名义上,参考时钟的精确度在 100 纳秒,但实际上,没有那么精确。调用 IReferenceClock::GetTime 可以获取时钟的当前时间。时间的基准是开始计时的时间,根据实现的不同, GetTime 的返回值不是绝对的。关键的是从时间开始的变化量。
       尽管时钟的精确性还有所变动,但是 GetTime 方法返回的保证时间是增加的。也就是说,时钟不会倒退回去,比如,对硬件时钟进行了调整, GetTime 方法就返回上次的时间,直到硬件时钟赶上。更多信息可参考 CBaseReferenceClock 类。
 
       6.1.1 Default Reference Clock
       Graph 运行的时候, Filter Graph Manager 会自动选择一个参考时钟的,选择的法则如下
       1 、如果应用程序选择了时钟,就采用应用程序选择的时钟
       2 、如果 Graph 包含活动的源 Filter ,并且有 IReferenceClock 接口,那么就用这个时钟。
       3 、如果 Graph 没有活动的源 Filter ,就用 Graph 中任何有 IReferenceClock 接口的 Filter ,选择的方法是从 Renderers 逆流向上,连接的 Filter 优先,没有连接的 Filter 次之。
       4 、如果没有任何 Filter 符合条件,就采用系统参考时钟 System Reference Clock
 
       6.1.2 Setting the Reference Clock
       应用程序可以调用 Filter Graph Manager 的接口 IMediaFilter SetSyncSource 方法来设置新的参考时钟。只有因为特殊原因需要设置其他时钟时才调用此函数。
       如果你给 SetSyncSource 传递的参数为 NULL Graph 不设置任何参考时钟。如果想恢复缺省的时钟,调用 IFilterGraph::SetDefaultSyncSource 。当 Graph 的参考时钟改变时, Filter Graph Manager 调用 IMediaFilter::SetSyncSource 通知所有的每个 Filter
 
       6.3    Clock Times
       DirectShow 定义了两个相关的时间:参考时间和流时间。
       ·参考时间:是参考时钟返回的绝对时间
       ·流时间:和 Graph 最近异常开始运行的时间有关。
              ·当 Graph 正在运行,流时间就等于从开始时间减去开始时间
              ·当 Graph 暂停,流时间就等于它暂停开始的时间
              ·在进行 Seek 操作后,流时间重新设置为 0
              ·当 Graph 停止时,流时间没有定义。
       当一个 Sample 具有时间戳 T ,就表示 Sample 应该在流时间 T 播放,因此流时间也叫播放时间。
       应用程序调用 IMediaControl::Run 运行 Graph 时, Filter Graph Manager 会调用每个 Filter IMediaFilter::Run 方法。为了补偿调用每个 Filter 的时间延迟, Filter Graph Manager 会指定一个稍微将来的时间进行补偿。
 
       6.4    Time Stamps
       时间戳定义了媒体 Sample 的开始和结束时间,用流时间表示。时间戳也叫播放时间。通过后面的知识你会了解到,并不是所有格式的数据流都采用同一种样式的时间戳。比如,并不是所有的 MPEG Sample 都有时间戳。在 MPEG Filter Graph ,时间戳并不应用在每帧上直到它们从解码器输出。
       Render Filter 接收到 Sample ,根据 Sample 的时间戳进行提交。如果 Sample 达到晚了或者没有时间戳, Filter 立即提交 Sample 。否则,在提交 Sample 前, Filter 会一直等到 Sample 的开始时间。(通过调用 IReferenceClock::AdviseTime 方法等待开始时间。)
       Source Filter Parse Filter 有责任给处理的 Sample 设置正确的时间戳。使用如下规则:
       ·文件回放:第一个 Sample 的时间戳为 0 ,随后的时间戳根据 Sample 的长度和播放的速率来确定。这些又由文件格式确定。解析 Filter 有责任计算正确的时间戳(例如 AVI Splitter )。
       ·视频和音频的捕捉:每个 Sample 都打上开始时间,它等于捕捉的流时间。注意下面两点:
              ·预览 PIN (与捕捉 PIN 相反)出来的视频帧没有时间戳。因为 Graph 延迟,打上捕捉时间的视频帧到达视频 Renerer 时总是有延迟。这样就会使 Renderer 丢帧以尝试质量控制。关于质量控制可参考 Quality-Control Management
              ·音频捕捉:音频捕捉 Filter 使用自己的缓冲,与音频驱动所使用的不同。音频捕捉驱动以固定间隔时间填充捕捉 Filter 的缓冲。间隔时间取决于驱动,但通常不超过 10 毫秒。在音频 Sample 上的时间戳反应了驱动填充捕捉 Filter 缓冲的时间。这些时间有稍微不准确,特别是如果应用程序使用更小的缓冲。但是,媒体时间能准确反应缓冲中音频 Sample 的数量。
       · Mux Filter: 根据输出数据流的格式, Mux Filter 可能需要生成时间戳,也许不需要。比如 AVI 文件格式使用固定的帧率,没有时间戳,因此 AVI Mux Filter 假定 Sample 都是在大约正确的时间达到。如果到达时间比时间戳晚就会丢帧。而对于文件回放,新的时间戳是运行时生成的。
       可以通过调用 IMediaSample::SetTime 来给 Sample 设置时间。
       另一个可选功能是 Filter 可以给 Sample 指定 Media Time 。在视频流, Media Time 表示帧数。在音频流,表示数据包中的 Sample 数量。比如,如果每个包有 1 秒的 444.1KHZ 的音频,第一个包的媒体开始时间是 0 媒体结束时间是 44100 。在支持 Seek 的流,总是与流的开始时间有关。比如,如果对一个 15FPS 的视频从开始定位到 2 秒。定位后的 Media Sample 的时间戳是 0 但是 Media Time 30
       Renderer Mux Filter 可通过检测间隔用 Media Time 判断帧或者 Sample 是否被丢弃。但是, Filter 并不要求设置 Media Time 。设置 Media Time 可调用 IMediaSample::SetMediaTime.
 
       6.5    Live Source
       活动的 Live Filter ,就是推模式的源,实时的接收数据。视频捕捉和网络广播就是例子,活动源通常无法控制数据流得速率。
       Filter 如果有下面的任意一个特征,通常被认为是 Live Filter
       1 IAMFilterMiscFlags::GetMiscFlags 时返回 AM_FILTER_MISC_FLAGS_IS_SOURCE ,并且至少有一个输出 Pin 暴露了 IAMPushSource 接口
       2 Filter 暴露 IKsPropertySet 接口,并且有个捕捉 Pin PIN_CATEGORY_CAPTURE ),更多信息可参考 Pin Property Set.
       如果 Live Source Filter 提供时钟,那么 Filter Graph Manager 首先采用它作为参考时钟。
 
       6.5.1 Latency
       Filter 的反映时间就是 Filter 处理 Sample 所花费的时间。对于 Live Source ,反应时间由 Sample 的内存大小决定。例如,假设一个 Filter 有一个 33ms 反应时间的视频源,一个 500ms 反应时间的音频源,每一个视频祯( video frame )比相应的音频 Sample 要早 470ms ,除非 Graph 进行补偿,否则视频和音频是不同步的。
       Live Source 可以通过 IAMPushSource 接口来进行同步。 Filter Graph Manager 在应用程序调用 IAMGraphStreams::SyncUsingStreamOffset 方法后就不会对源进行同步。如果开启同步, Filter Graph Manager 在每个 Source Filter 查询 IAMPushSource 接口,如果支持接口, Filter Graph Manager 就用 IAMLatency::GetLatency 来得到 Filter 期望的反应时间。( IAMPushSource IAMLatency 继承)。通过组合这些反应值, Filter Graph Manager 决定 Graph 的最大反应时间。然后调用 IAMPushSource::SetStreamOffset 给每个源 Filter 设置一个数据流偏移时间, Filter 给它产生的 Sample 打时间戳的时候会加上偏移时间的。
     这种方法主要用于实时预览。但是,实时捕捉设备的 ( 比如摄像机 ) 并不在 Sample 上设置时间戳。因此,在实时捕捉设备上用此方法,必须从捕捉 PIN 进行预览。可参考 DirectShow Video Capture Filter.   现在, VFW Capture Filter Audio Capture Filter. 都支持 IAMPushSource 接口。
 
       6.5.2 Rate Matching
       Render Filter 利用参考时钟安排播放顺序的时候,如果源 Filter 采用另一种时钟,在重放的时候就会发生故障。播放的速度大于源产生的速度,就会产生间隙停顿,或者播放速度小于源的产生速度,就会形成数据的堆积,直到 Graph 丢帧。源一般来说是无法控制数据的产生速度的,因此,播放速度要随着源的速度改变而改变。
       现在,只有在音频播放 Filter 才能进行速率匹配,因为音频中的故障比视频中的更容易捕捉到。为了匹配播放速率,音频 Renderer 必须要选择一个匹配标准。使用如下规则:
       ·如果 Graph 没有使用参考时钟,没法进行速率匹配。(只要没有参考时钟 Sample 都是立即提交)
       ·如果 Graph 有参考时钟, Renderer 的上一级必须要有一个活动的源。否则不进行匹配。
       ·如果上一级有 Live Source, 并且支持 IAMPushSource 接口,调用 GetPushSourceFlags
              ·返回 AM_PUSHSOURCECAPS_INTERNAL_RM ,表示 Source 有自己的匹配机制
              ·返回 AM_PUSHSOURCECAPS_NOT_LIVE ,表示不是 Live Source ,即使有 IAMPushSource 接口,因此 Audio Renderer 不匹配。
              ·返回 AM_PUSHSOURCECAPS_PRIVATE_CLOCK ,表示 Source 用私有时钟生成时间戳。此时, Audio Renderer 用时间戳匹配。(如果没有时间戳,但是 Renderer 忽略 Flag .
       ·如果 GetPushSourceFlags 返回 0 ,播放 Filter 就根据 Graph 时钟和 Sample 的时间戳来自己决定播放速率。
              ·如果 Audio Renderer 不是 Graph 时钟并且 Sample 有时间戳,就与时间戳匹配。
              ·如果 Sample 没有时间戳, Audio Renderer 尝试与进入 Audio Data 的频率匹配。
              ·如果 Audio Renderer Graph 时钟,尝试与进入 Audio Data 匹配。

       最后一种情况的原因是:如果Audio Renderer是参考时钟,Source Filter用同样的时钟生成时间戳,然后Audio Renderer不能与时间戳匹配。如果这么做了,就可能尝试与自己匹配,这样会引起时钟混乱。因此,Audio Renderer就与进入Audio Data的频率匹配。 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值