本人对gstreamer 设计文档part-synchronisation.txt的翻译,英语水平有限,主要方便自己日后查看。
Synchronisation
---------------
同步
This document outlines the techniques used for doing synchronised playback of
multiple streams.
本文档概要的描述回放时多路流同步使用的方法
Synchronisation in a GstPipeline is achieved using the following 3 components:
同步是在管线(GSTPipeline)中使用如下三个组件实现的:
- a GstClock, which is global for all elements in a GstPipeline.
GstClock GST时钟对于管线中的所有元件来说是全局的
- Timestamps on a GstBuffer.
Gst缓冲(GstBuffer)上的时间戳
- the NEW_SEGMENT event preceding the buffers.
在缓冲之前的NEW_SEGMENT事件
A GstClock
~~~~~~~~~~
一个GST时钟
This object provides a counter that represents the current time in nanoseconds.
这个对象以纳秒为单位提供一个描述当前时间的计数器
This value is called the absolute_time.
这个值被叫做绝对时间
Different sources exist for this counter:
这个计数器存在不同的来源:
- the system time (with g_get_current_time() and with microsecond accuracy)
系统时间(使用g_get_current_time()获取,提供毫秒级的精度
- an audio device (based on number of samples played)
一个音频设备(基于播放的采样数)
- a network source based on packets received + timestamps in those packets (a
typical example is an RTP source)
一个基于从网络接收到的包及存在于这些包内的时间戳(一个典型的例子是一个RTP源)
- ...
In GStreamer any element can provide a GstClock object that can be used in the
pipeline. The GstPipeline object will select a clock from all the providers and
will distribute it to all other elements (see part-gstpipeline.txt).
在GStreamer中,任何元件都可提供一个可用于管线的时钟。管线从所有元件提供的时钟中选择一个分配到所有其它的元件(参见part-gstpipeline.txt)。
A GstClock always counts time upwards and does not necessarily start at 0.
一个GstClock总是向上计数(增大),而且不一定是从0开始。
Running time
~~~~~~~~~~~~
运行时间
After a pipeline selected a clock it will maintain the running_time based on the
selected clock. This running_time represents the total time spent in the PLAYING
state and is calculated as follows:
管线选择一个时钟后将基于选择的时钟维护一个运行时钟。这个运行时钟描述播放(从转到PLAYING状态到现在)的时间。运行时间下面的方式计算:
- If the pipeline is NULL/READY, the running_time is undefined.
如果管线是NULL/READY状态,运行时间是未定义的。
- In PAUSED, the running_time remains at the time when it was last
PAUSED. When the stream is PAUSED for the first time, the running_time
is 0.
在PAUSED状态,运行时间保持暂停时的时间。当流是第一次暂停时,运行时间是0.
- In PLAYING, the running_time is the delta between the absolute_time
and the base time. The base time is defined as the absolute_time minus
the running_time at the time when the pipeline is set to PLAYING.
在播放状态,运行时间是绝对时间与基准时间之差。
- after a flushing seek, the running_time is set to 0 (see part-seeking.txt).
This is accomplished by redistributing a new base_time to the elements that
got flushed.
在flushing seek后,运行时间设定为0,这是通过重新分配一个新的基准时间给元件来实现的。
This algorithm captures the running_time when the pipeline is set from PLAYING
to PAUSED and restores this time based on the current absolute_time when going
back to PLAYING. This allows for both clocks that progress when in the PAUSED
state (systemclock) and clocks that don't (audioclock).
这个算法在从播放状态设定到暂停状态时捕获运行时间,当继续播放时,基于绝对时间恢复运行时间。当暂停时,允许系统时钟和音频时钟两个时钟继续增长。
The clock and pipeline now provide a running_time to all elements that want to
perform synchronisation. Indeed, the running time can be observed in each
element (during the PLAYING state) as:
时钟和管线现在提供一个运行时钟给所有想要同步的元件。实际上,运行时间可以在每个元件中使用如下的方式观察到(在播放状态):
C.running_time = absolute_time - base_time
We note C.running_time as the running_time obtained by looking at the clock.
我们注意到,作为运行时间的C.running_time是通过查看时钟获得的。
This value is monotonically increasing at the rate of the clock.
这个值是基于时钟的分辨率单调递增的。
Timestamps
~~~~~~~~~~
时间戳
The GstBuffer timestamps and the preceeding NEW_SEGMENT event (See
part-streams.txt) define a transformation of the buffer timestamps to
running_time as follows:
GstBuffer的时间戳和预先到的NEW_SEGMENT事件定义了缓冲时间戳到运行时间的转换:
The following notation is used:
使用如下的标记法:
B: GstBuffer
- B.timestamp = buffer timestamp (GST_BUFFER_TIMESTAMP)
B表示GstBuffer,B.timestamp表示缓冲时间戳。
NS: NEWSEGMENT event preceeding the buffers.
NS:表示在缓冲之前来到的NEW_SEGMENT事件
- NS.start: start field in the NEWSEGMENT event
NS.start:在NEWSEGMENT事件中的开始域
- NS.stop: stop field in the NEWSEGMENT event
NS.stop:在NEWSEGMENT中的停止域
- NS.rate: rate field of NEWSEGMENT event
NS.rate:在NEWSEGMENT中的速率域
- NS.abs_rate: absolute value of rate field of NEWSEGMENT event
NS.abs_rate:在NEWSEGMENT事件中的速率域的绝对值
- NS.time: time field in the NEWSEGMENT event
NS.time:在NEWSEGMENT事件中的时间域
- NS.accum: total accumulated time of all previous NEWSEGMENT events. This
field is kept in the GstSegment structure.
NS.accum:所有先前到达的NEWSEGMENT事件的累积时间。这个域是保持在GstSegment结构中
Valid buffers for synchronisation are those with B.timestamp between NS.start
and NS.stop. All other buffers outside this range should be dropped or clipped
to these boundaries (see also part-segments.txt).
对于同步一说,时间戳介于NS.start与NS.stop之间才是有效的缓冲。所有在这个范围之外的缓冲都应该丢掉或剪掉超出范围的部份。
The following transformation to running_time exist:
可用如下方式转换到运行时间:
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
We write B.running_time as the running_time obtained from the NEWSEGMENT event
and the buffers of that segment.
我们把从NEWSEGMENT事件和片段的缓冲获取的运行时写到B.running。
The first displayable buffer will yield a value of 0 (since B.timestamp ==
NS.start and NS.accum == 0).
第一个可显示的缓冲将产生一个0值。
For NS.rate > 1.0, the timestamps will be scaled down to increase the playback
rate. Likewise, a rate between 0.0 and 1.0 will slow down playback.
当NS.rate 大于1.0时,时间戳将被增加到合适的播放速率。同样的,当速率在0与1之间时,将放慢播放速度。
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).
当速率为负值时,接收到的时间戳从停止到开始,所以接收到的第一个缓冲B.runing_time将被转换到0
Synchronisation
~~~~~~~~~~~~~~~
同步
As we have seen, we can get a running_time:
正如我们知道的,我们可以得到运行时间:
- using the clock and the element's base_time with:
使用时钟和元件的基准时间
C.running_time = absolute_time - base_time
- using the buffer timestamp and the preceeding NEWSEGMENT event as (assuming
positive playback rate):
使用缓冲的时间戳与先前的NEWSEGMENT事件(假定播放速度为正):
B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
We prefix C. and B. before the two running times to note how they were
calculated.
The task of synchronized playback is to make sure that we play a buffer with
B.running_time at the moment when the clock reaches the same C.running_time.
回放同步的任务是确保在达到C.running_time时的瞬间播放带有B.running_time的缓冲。
Thus the following must hold:
因此如下条件必需保持:
B.running_time = C.running_time
expaning:
B.running_time = absolute_time - base_time
or:
absolute_time = B.running_time + base_time
The absolute_time when a buffer with B.running_time should be played is noted
with B.sync_time. Thus:
当一个带时间戳的缓冲被播放时,绝对时间可以用B.sync_time标注。因此:
B.sync_time = B.running_time + base_time
One then waits for the clock to reach B.sync_time before rendering the buffer in
the sink (See also part-clocks.txt).
在渲染sink内的缓冲前,需等待时钟到达B.sync_time
For multiple streams this means that buffers with the same running_time are to
be displayed at the same time.
多路流同步意思是多路流内有相同的运行时间缓冲在相同的时间被播放。
A demuxer must make sure that the NEWSEGMENT it emits on its output pads yield
the same running_time for buffers that should be played synchronized. This
usually means sending the same NEWSEGMENT on all pads and making sure that the
synchronized buffers have the same timestamps.
一个多路器必须确保在它的输出衬垫发出的NEWSEGMENT给需被同步播放的缓冲产生相同的运行时间。这通常意味着在所有的衬垫上发送相同的NEWSEGMENT及确保需同步的缓冲有相同的时间戳。
Stream time
~~~~~~~~~~~
流时间
The stream time is also known as the position in the stream and is a value
between 0 and the total duration of the media file.
流时间表示流的位置,是一个介于0与流的持续时间之间的值。
It is the stream time that is used for:
流时间用于:
- report the POSITION query in the pipeline
在管线查询时报告当前的位置
- the position used in seek events/queries
在seek时定位
- the position used to synchronize controller values
用于同步控制器定位
Stream time is calculated using the buffer times and the preceeding NEWSEGMENT
event as follows:
流时间使用缓冲时间和NEWSEGMENT事件,用如下方法计算得来:
stream_time = (B.timestamp - NS.start) * NS.abs_applied_rate + NS.time
For negative rates, B.timestamp will go backwards from NS.stop to NS.start,
making the stream time go backwards.
当速度为负时,B.timestamp将从NS.stop到NS.start回退,将使流时间回退。
In the PLAYING state, it is also possible to use the pipeline clock to derive
the current 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
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
This last formula is typically used in sinks to report the current position in
an accurate and efficient way.
Note that the stream time is never used for synchronisation against the clock.