本文编译自gstreamer源代码中的文档,原文的路径是gstreamer/docs/design/part-synchronisation.txt。
本文描述了Gstreamer的同步机制,Gstreamer中实现同步的组件如下:
GstClock
GstClock是精确到纳秒的表示当前时间的一个计数。其值用absolute_time表示。这个计数的源的选择如下:
在Gstreamer中任何element都可以提供GstClock,pipeline从所有可用的GstClock中选定一个并用于pipeline中所有的elements。时间计数单调递增,可以不是从0开始计数。
Running time
选定了clock之后pipeline会维护一个基于选定时钟的running_time。running_time指的是pipeline处于PLAYING状态下的时间总和,计算方法如下:
上述的计算方法在pipeline的状态从PLAYING状态设定为PAUSE状态时记录running_time,当从PAUSE状态转变为PLAYING状态后基于absolute_time恢复running_time。针对PAUSE后继续计数的clock,比如system clock,以及PAUSE后不再计数的clock,比如audioclock都是适用的。
running_time的计算方法如下:
GstBuffer的timestamps以及NEW_SEGMENT event定义了 buffer timestamps 到 running_time的变换
B: GstBuffer
NS: NEWSEGMENT event preceeding the buffers.
符合同步要求的buffers其B.timestamp需在NS.start和NS.stop之间,B.timestamp不在这个范围内的buffers需要丢掉或者进行修正。
对于running_time存在如下变换:
可显示的第一个buffer的running_time的值为0。
对于 NS.rate > 1.0,timestamps的值缩小从而使得播放速度加快。
For negative rates, timestamps are received stop NS.stop to NS.start so that the first buffer received will be transformed into B.running_time of 0 (B.timestamp == NS.stop and NS.accum == 0).
Synchronisation
对于running_time的计算方法如下:
同步播放的目的就是确保running_time为B.running_time的buffer在C.running_time的时刻播放。
这需要满足如下条件:
或者
dumuxer必须确保向输出pads发出的NEWSEGMENT能为buffers生成一样的running_time,从而使之保持同步。通常向pads发出同样的NEWSEGMENT来确保同步的buffer具有一样的timestamp。
Stream time
stream time,也称作在流中的位置,是一个在0和媒体文件长度(时间)之间的值。具有如下用途:
通过buffer和其前面的NEWSEGMENT event来计算stream time:
C.running_time = absolute_time - base_time
B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
=>
(B.timestamp - NS.start) / NS.abs_rate + NS.accum = absolute_time - base_time;
=>
(B.timestamp - NS.start) / NS.abs_rate = absolute_time - base_time - NS.accum;
=>
(B.timestamp - NS.start) = (absolute_time - base_time - NS.accum) * NS.abs_rate
filling (B.timestamp - NS.start) in the above formule for stream time
=>
stream_time = (absolute_time - base_time - NS.accum) * NS.abs_rate * NS.abs_applied_rate + NS.time
最后的计算公式通常是sink用于report当前的position的准确和有效的方式。Note that the stream time is never used for synchronisation against the clock.
本文描述了Gstreamer的同步机制,Gstreamer中实现同步的组件如下:
- GstClock,是全局的,用于pipeline中的所有elements。
- GstBuffer的timestamps。
- buffers之前的NEW_SEGMENT event。
GstClock
GstClock是精确到纳秒的表示当前时间的一个计数。其值用absolute_time表示。这个计数的源的选择如下:
- 系统时间,精度是微妙。
- 音频设备。
- 基于网络的数据包,比如RTP数据包。
- 其它。
在Gstreamer中任何element都可以提供GstClock,pipeline从所有可用的GstClock中选定一个并用于pipeline中所有的elements。时间计数单调递增,可以不是从0开始计数。
Running time
选定了clock之后pipeline会维护一个基于选定时钟的running_time。running_time指的是pipeline处于PLAYING状态下的时间总和,计算方法如下:
- 如果pipeline处于NULL或者READY状态则running_time处于undefined。
- PAUSE状态下,running_time的值保持不变,如果处于刚开始启动时的PAUSE状态,running_time的值为0。
- flushing seek之后,running_time被置为0。这需要向所有被flush的elemnt指定一个新的base_time。
上述的计算方法在pipeline的状态从PLAYING状态设定为PAUSE状态时记录running_time,当从PAUSE状态转变为PLAYING状态后基于absolute_time恢复running_time。针对PAUSE后继续计数的clock,比如system clock,以及PAUSE后不再计数的clock,比如audioclock都是适用的。
running_time的计算方法如下:
C.running_time = absolute_time - base_time
Timestamps
GstBuffer的timestamps以及NEW_SEGMENT event定义了 buffer timestamps 到 running_time的变换
B: GstBuffer
- B.timestamp = buffer timestamp (GST_BUFFER_TIMESTAMP)
NS:
- NS.start: start field in the NEWSEGMENT event
- NS.stop: stop field in the NEWSEGMENT event
- NS.rate: rate field of NEWSEGMENT event
- NS.abs_rate: absolute value of rate field of NEWSEGMENT event
- NS.time: time field in the NEWSEGMENT event
- NS.accum: total accumulated time of all previous NEWSEGMENT events. This field is kept in the GstSegment structure.
符合同步要求的buffers其B.timestamp需在NS.start和NS.stop之间,B.timestamp不在这个范围内的buffers需要丢掉或者进行修正。
对于running_time存在如下变换:
if (NS.rate > 0.0)
B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
else
B.running_time = (NS.stop - B.timestamp) / NS.abs_rate + NS.accum
B.running_time由NEWSEGMENT event以及该segment的buffers得到。
else
可显示的第一个buffer的running_time的值为0。
对于 NS.rate > 1.0,timestamps的值缩小从而使得播放速度加快。
For negative rates, timestamps are received stop NS.stop to NS.start so that the first buffer received will be transformed into B.running_time of 0 (B.timestamp == NS.stop and NS.accum == 0).
Synchronisation
对于running_time的计算方法如下:
- 采用clock以及element的base_time:
C.running_time = absolute_time - base_time
- 采用buffer timestamp和其前面的NEWSEGMENT event,假定为正向播放:
B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
这里的前缀C.和B.代表不同的计算方法。
同步播放的目的就是确保running_time为B.running_time的buffer在C.running_time的时刻播放。
这需要满足如下条件:
B.running_time = C.running_time
也就是:
B.running_time = absolute_time - base_time
或者
absolute_time = B.running_time + base_time
具有B.running_time的buffer应当被播放时的absolute_time记为B.sync_time,那么:
B.sync_time = B.running_time + base_time
这意味着等到clock到了B.sync_time的时候才播放buffer,对于多个流中具有相同的running_time的buffer应该同时播放。
dumuxer必须确保向输出pads发出的NEWSEGMENT能为buffers生成一样的running_time,从而使之保持同步。通常向pads发出同样的NEWSEGMENT来确保同步的buffer具有一样的timestamp。
Stream time
stream time,也称作在流中的位置,是一个在0和媒体文件长度(时间)之间的值。具有如下用途:
- report the POSITION query in the pipeline
- the position used in seek events/queries
- the position used to synchronize controller values
通过buffer和其前面的NEWSEGMENT event来计算stream time:
stream_time = (B.timestamp - NS.start) * NS.abs_applied_rate + NS.time
对于播放速度为负的情况,B.timestamp将从NS.stop 到 NS.start,使得stream time反向。在PLAYING 状态,也可以采用pipeline clock 计算当前的stream_time。 Give the two formulas above to match the clock times with buffer timestamps allows us to rewrite the above formula for stream_time (and for positive rates).
C.running_time = absolute_time - base_time
B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
=>
(B.timestamp - NS.start) / NS.abs_rate + NS.accum = absolute_time - base_time;
=>
(B.timestamp - NS.start) / NS.abs_rate = absolute_time - base_time - NS.accum;
=>
(B.timestamp - NS.start) = (absolute_time - base_time - NS.accum) * NS.abs_rate
=>
stream_time = (absolute_time - base_time - NS.accum) * NS.abs_rate * NS.abs_applied_rate + NS.time
最后的计算公式通常是sink用于report当前的position的准确和有效的方式。Note that the stream time is never used for synchronisation against the clock.