7. DirectShow-内部时钟与音画同步

内部时钟ReferenceTime

Filter Graph 管理器的一个功能是将图形中的所有filter同步到同一时钟(称为 ReferenceTime)。

任何公开 IReferenceClock 接口的对象都可以充当ReferenceTimeReferenceTime可能由 DirectShow filter提供,通常是音频呈现器,它有权访问硬件计时器。 作为回退,Filter Graph 管理器可以使用系统时间。

从名义上说,ReferenceTime以 100 纳秒的间隔测量时间,尽管时钟的实际准确度可能较低。 若要检索时钟的当前时间,请调用 IReferenceClock::GetTime 方法。 时钟的基线(开始计数的时间)取决于实现,因此 GetTime 返回的值本质上没有意义。 重要的是图形开始运行时的增量。

尽管ReferenceTime的准确性可能会有所不同,但 GetTime 方法返回的时间保证单调增加。 换句话说,时钟时间永远不会倒退。 如果ReferenceTime正在从硬件源生成时钟时间,并且硬件时钟向后跳 (例如,如果对时钟) 进行调整, 则 GetTime 方法应继续返回上次报告的时间,直到硬件时钟赶上为止。 有关详细信息,请参阅 CBaseReferenceClock 类。

默认的ReferenceTime来源(不重要)

filter图形管理器在图形运行时自动选择ReferenceTime。 它使用以下算法来选择时钟:

  • 如果应用程序选择了一个时钟 (请参阅下面) ,请使用该时钟。
  • 如果图形包含支持 IReferenceClock 的实时源filter,请使用该filter。 有关实时源的定义,请参阅 实时源。
  • 如果图形不包含任何实时源filter,请在图形中使用支持 IReferenceClock 的任何filter,从呈现器开始,上游工作。 首选连接的filter,而不是未连接的filter
  • 如果图形呈现音频流,则算法中的此步骤通常会选择音频呈现器filter
  • 如果没有filter提供合适的时钟,请使用基于系统时间的系统 ReferenceTime

设置ReferenceTime(不重要)

应用程序可以通过在 Filter Graph Manager 上调用 IMediaFilter::SetSyncSource 方法来选择时钟。 仅当有特定原因首选另一个时钟时,才应执行此操作。

可以通过调用值为 NULL 的 SetSyncSource 来指示 Filter Graph 管理器不要使用ReferenceTime。 例如,可以执行此操作以尽快处理MediaSample。 若要还原默认ReferenceTime,请在 Filter Graph 管理器上调用 IFilterGraph::SetDefaultSyncSource 方法。

每当ReferenceTime更改时,Filter Graph 管理器都会通过调用其 IMediaFilter::SetSyncSource 方法通知每个filter。 应用程序绝不应在filter上调用此方法。

引用时间和流时间

DirectShow 定义了两个相关的时钟时间:引用时间和流时间。引用时间 是ReferenceTime返回的绝对时间。 (请参阅 ReferenceTime.)。流时间 相对于图形上次开始运行的时间进行定义。

  • 当图形运行时,流时间等于引用时间减去开始时间。
  • 当图形暂停时,流时间将停留在暂停的流时间。
  • 执行查找操作后,流时间将重置为零。
  • 当图形停止时,流时间未定义。
  • MediaSample具有时间戳 t 时,这意味着应在流时间 t 呈现该MediaSample。 因此,流时间也称为 演示时间。

当应用程序调用 IMediaControl::Run 来运行filter图时,Filter Graph 管理器在每个filter上调用 IMediaFilter::Run 。 为了补偿filter开始运行所花费的轻微时间,Filter Graph 管理器在将来会稍微指定一个启动时间。

时间戳

时间戳采用流时间

时间戳定义MediaSample的开始和完成时间,以流时间度量。 时间戳有时称为 呈现时间。 阅读本文的其余部分时,请务必记住,并非所有格式都以相同的方式使用时间戳。 例如,并非所有 MPEG 样本都带有时间戳。 在 MPEG filter图中,时间戳不会应用于每个帧,直到它们从解码器输出。

当呈现器filter收到MediaSample时,它会根据时间戳计划呈现。 如果样本迟到或没有时间戳,filter将立即呈现样本。 否则,filter将等到MediaSample的开始时间,然后才呈现MediaSample。 (它通过调用 IReferenceClock::AdviseTime 方法等待开始时间。)

filter和分析程序filter负责为其处理的样本设置正确的时间戳。 请遵循以下准则。

  • 文件播放:第一个MediaSample带有时间戳,开始时间为零。 后续时间戳由样本长度和播放速率决定,后者本身由文件格式决定。 分析文件的filter负责计算正确的时间戳, (例如 AVI 拆分器) 。
  • 视频和音频捕获:每个样本都标有时间戳,其开始时间等于捕获时的流时间,但需要注意预览引脚中的视频帧 (而不是捕获引脚) 没有时间戳。 由于图形延迟,带有捕获时间标记的视频帧将始终晚于视频呈现器到达。 这可能会导致呈现器在试图进行质量控制时删除帧。 有关质量控制的信息,请参阅 质量控制管理。
  • 音频捕获:音频捕获filter使用自己的一组缓冲区,这些缓冲区与音频驱动程序使用的缓冲区是分开的。 音频驱动程序按固定间隔填充捕获filter的缓冲区。 间隔取决于驱动程序,但通常不超过 10 毫秒。 音频样本上的时间戳反映了驱动程序填充音频捕获filter缓冲区的时间。 这些时间可能略有不准确,尤其是在应用程序使用非常小的缓冲区时。 但是,媒体时间将准确反映缓冲区中的音频样本数。
  • 复用filter:根据输出格式,多路复用filter可能需要生成时间戳,也可能不需要生成时间戳。 例如,AVI 文件格式使用没有时间戳的固定帧速率,因此 AVI Mux filter假定样本在大约正确的时间到达。 但是,如果传入时间戳显示大于一帧的间隙,AVI 复用器会写入一个索引条目,其大小为零,以指示丢弃的帧。 在文件播放时,会在运行时生成新的时间戳,如前所述。
    若要在MediaSample上设置时间戳,请调用 IMediaSample::SetTime 方法。

MediaTime

(可选)filter还可以指定样本的 媒体时间 。 在视频流中,媒体时间表示帧数。 在音频流中,媒体时间表示数据包中的样本数。 例如,如果每个数据包包含 44.1 千赫 (kHz) 音频的 1 秒,则第一个数据包的媒体开始时间为 0,媒体停止时间为 44100。 在可查找流中,媒体时间始终相对于流的开始时间。 例如,假设你从 15-fps 视频流的开始时间开始 2 秒。 搜寻后的第一个MediaSample的时间戳为零,但媒体时间为 30。

呈现器和复用器filter可以使用媒体时间,通过检查间隙来确定帧或样本是否已丢弃。 但是,不需要filter来设置媒体时间。 若要在MediaSample上设置媒体时间,请调用 IMediaSample::SetMediaTime 方法。

实时源(也称为 推送源)实时接收数据。

MediaSample包括视频捕获和网络广播。 通常,实时源无法控制数据的到达速率。如果存在以下任一情况,则filter被视为实时源:

  • filter从 IAMFilterMiscFlags::GetMiscFlags 方法返回AM_FILTER_MISC_FLAGS_IS_SOURCE标志,并且至少一个其输出引脚公开 IAMPushSource 接口。
  • filter公开 IKsPropertySet 接口,并具有捕获引脚 (PIN_CATEGORY_CAPTURE) 。 有关详细信息 ,请参阅固定属性集 。
    如果实时源filter提供时钟,filter关系图管理器在选择图形ReferenceTime时会首选该时钟。 有关详细信息 ,请参阅ReferenceTime

延迟

filter的延迟是filter处理样本所需的时间。 对于实时源,延迟取决于用于保存样本的缓冲区的大小。 例如,假设filter图的延迟为 33 毫秒 (毫秒的视频源) ,音频源的延迟为 500 毫秒。 在匹配的音频样本到达音频呈现器之前,每个视频帧到达视频呈现器大约 470 毫秒。 除非图形补偿差异,否则音频和视频不会同步。

可以通过 IAMPushSource 接口同步实时源。 Filter Graph 管理器不会同步实时源,除非应用程序通过调用 IAMGraphStreams::SyncUsingStreamOffset 方法启用同步。 如果启用了同步,filter关系图管理器将查询 IAMPushSource 的每个源filter。 如果filter支持 IAMPushSource,filter关系图管理器会调用 IAMLatency::GetLatency 来检索filter的预期延迟。 (IAMPushSource 接口从组合的延迟值继承 IAMLatency.) ,filter关系图管理器确定图中的最大预期延迟。 然后,它调用 IAMPushSource::SetStreamOffset 为每个源filter提供流偏移量,该filter会将该偏移量添加到它生成的时间戳中。

此方法主要用于实时预览版。 但请注意,实时捕获设备上的预览固定 ((如相机) )不会在它提供的MediaSample上设置时间戳。 因此,若要将此方法用于实时捕获设备,必须从捕获引脚预览。 有关详细信息,请参阅 DirectShow 视频捕获filter

目前,VFW 捕获filter和音频捕获filter支持 IAMPushSource 接口。

速率匹配

如果呈现器filter使用一个ReferenceTime计划样本,但源filter使用不同的时钟生成样本,则播放时可能会出现故障。 呈现器运行速度可能比源快,从而导致数据间隙。 或者,它的运行速度可能比源慢,导致样本“堆起来”,直到图在某个时候会丢弃样本。 通常,实时源无法控制其生产速率,因此呈现器应将速率与源匹配。

目前,只有音频呈现器执行速率匹配,因为音频播放中的故障比视频中的故障更明显。 若要执行速率匹配,音频呈现器必须选择与速率匹配的内容。 它使用以下算法:

  • 如果图形未使用ReferenceTime,则音频呈现器不会尝试匹配速率。 (每当图形没有ReferenceTime时,样本始终在到达时立即呈现。) 否则,如果有图形的ReferenceTime,音频呈现器将使用前面所述的条件检查是否存在实时源上游。 否则,音频呈现器与速率不匹配。
  • 如果存在实时源上游,并且该源在其输出引脚上公开 IAMPushSource 接口,则音频呈现器将调用 IAMPushSource::GetPushSourceFlags。 它会查找以下标志之一:
    • AM_PUSHSOURCECAPS_INTERNAL_RM。 此标志表示源filter具有自己的速率匹配机制,因此音频呈现器不匹配速率。
    • AM_PUSHSOURCECAPS_NOT_LIVE。 此标志意味着源filter不是真正的实时源,即使它公开了 IAMPushSource 接口。 因此,音频呈现器与速率不匹配。
    • AM_PUSHSOURCECAPS_PRIVATE_CLOCK。 此标志表示源filter使用专用时钟生成时间戳。 在这种情况下,音频呈现器将速率与时间戳匹配。 (如果MediaSample没有时间戳,呈现器将忽略此标志。)
  • 如果 GetPushSourceFlags 未返回任何标志 (零) ,则音频呈现器的行为取决于图形时钟以及样本是否具有时间戳:
    • 如果音频呈现器不是图形时钟,并且样本具有时间戳,则音频呈现器会将速率与时间戳匹配。
    • 如果样本没有时间戳,音频呈现器会尝试匹配传入音频数据的速率。
    • 如果音频呈现器是图形时钟,它将尝试匹配传入的数据速率。
      最后一种情况的原因如下:如果音频呈现器是ReferenceTime,并且源filter使用相同的时钟来生成时间戳,则音频呈现器无法将速率与时间戳匹配。 如果确实如此,实际上它会尝试将速率与自身匹配,这可能导致时钟偏移。 因此,在这种情况下,呈现器与传入音频数据的速率匹配。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容