docs: go over design docs and fix things
[platform/upstream/gstreamer.git] / docs / design / part-synchronisation.txt
1 Synchronisation
2 ---------------
3
4 This document outlines the techniques used for doing synchronised playback of
5 multiple streams.
6
7 Synchronisation in a GstPipeline is achieved using the following 3 components:
8
9  - a GstClock, which is global for all elements in a GstPipeline.
10  - Timestamps on a GstBuffer.
11  - the SEGMENT event preceding the buffers.
12
13
14 A GstClock
15 ~~~~~~~~~~
16
17 This object provides a counter that represents the current time in nanoseconds.
18 This value is called the absolute_time.
19
20 Different sources exist for this counter:
21
22  - the system time (with g_get_current_time() and with microsecond accuracy)
23  - an audio device (based on number of samples played)
24  - a network source based on packets received + timestamps in those packets (a
25    typical example is an RTP source)
26  - ...
27
28 In GStreamer any element can provide a GstClock object that can be used in the
29 pipeline. The GstPipeline object will select a clock from all the providers and
30 will distribute it to all other elements (see part-gstpipeline.txt).
31
32 A GstClock always counts time upwards and does not necessarily start at 0.
33
34
35 Running time
36 ~~~~~~~~~~~~
37
38 After a pipeline selected a clock it will maintain the running_time based on the
39 selected clock. This running_time represents the total time spent in the PLAYING
40 state and is calculated as follows:
41
42  - If the pipeline is NULL/READY, the running_time is undefined.
43  - In PAUSED, the running_time remains at the time when it was last
44    PAUSED. When the stream is PAUSED for the first time, the running_time
45    is 0.
46  - In PLAYING, the running_time is the delta between the absolute_time
47    and the base time. The base time is defined as the absolute_time minus
48    the running_time at the time when the pipeline is set to PLAYING.
49  - after a flushing seek, the running_time is set to 0 (see part-seeking.txt).
50    This is accomplished by redistributing a new base_time to the elements that
51    got flushed.
52
53 This algorithm captures the running_time when the pipeline is set from PLAYING
54 to PAUSED and restores this time based on the current absolute_time when going
55 back to PLAYING. This allows for both clocks that progress when in the PAUSED
56 state (systemclock) and clocks that don't (audioclock).
57
58 The clock and pipeline now provide a running_time to all elements that want to
59 perform synchronisation. Indeed, the running time can be observed in each
60 element (during the PLAYING state) as:
61   
62   C.running_time = absolute_time - base_time
63
64 We note C.running_time as the running_time obtained by looking at the clock.
65 This value is monotonically increasing at the rate of the clock.
66
67
68 Timestamps
69 ~~~~~~~~~~
70  
71 The GstBuffer timestamps and the preceeding SEGMENT event (See
72 part-streams.txt) define a transformation of the buffer timestamps to
73 running_time as follows:
74
75 The following notation is used:
76
77  B: GstBuffer 
78   - B.timestamp = buffer timestamp (GST_BUFFER_TIMESTAMP)
79
80  NS:  SEGMENT event preceeding the buffers.
81   - NS.start: start field in the SEGMENT event
82   - NS.stop: stop field in the SEGMENT event
83   - NS.rate: rate field of SEGMENT event
84   - NS.abs_rate: absolute value of rate field of SEGMENT event
85   - NS.time: time field in the SEGMENT event
86   - NS.accum: total accumulated time of all previous SEGMENT events. This
87               field is kept in the GstSegment structure.
88
89 Valid buffers for synchronisation are those with B.timestamp between NS.start
90 and NS.stop. All other buffers outside this range should be dropped or clipped
91 to these boundaries (see also part-segments.txt).
92
93 The following transformation to running_time exist:
94
95     if (NS.rate > 0.0)
96       B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
97     else
98       B.running_time = (NS.stop - B.timestamp) / NS.abs_rate + NS.accum
99
100 We write B.running_time as the running_time obtained from the SEGMENT event
101 and the buffers of that segment.
102
103 The first displayable buffer will yield a value of 0 (since B.timestamp ==
104 NS.start and NS.accum == 0).
105
106 For NS.rate > 1.0, the timestamps will be scaled down to increase the playback
107 rate. Likewise, a rate between 0.0 and 1.0 will slow down playback.
108
109 For negative rates, timestamps are received stop NS.stop to NS.start so that the
110 first buffer received will be transformed into B.running_time of 0 (B.timestamp ==
111 NS.stop and NS.accum == 0).
112
113
114 Synchronisation
115 ~~~~~~~~~~~~~~~
116
117 As we have seen, we can get a running_time:
118
119  - using the clock and the element's base_time with:
120
121     C.running_time = absolute_time - base_time
122
123  - using the buffer timestamp and the preceeding SEGMENT event as (assuming
124    positive playback rate):
125
126     B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
127
128 We prefix C. and B. before the two running times to note how they were
129 calculated.
130
131 The task of synchronized playback is to make sure that we play a buffer with
132 B.running_time at the moment when the clock reaches the same C.running_time.
133
134 Thus the following must hold:
135
136    B.running_time = C.running_time
137
138 expaning:
139
140    B.running_time = absolute_time - base_time
141
142 or:
143
144    absolute_time = B.running_time + base_time
145
146 The absolute_time when a buffer with B.running_time should be played is noted
147 with B.sync_time. Thus:
148
149   B.sync_time = B.running_time + base_time
150
151 One then waits for the clock to reach B.sync_time before rendering the buffer in
152 the sink (See also part-clocks.txt).
153
154 For multiple streams this means that buffers with the same running_time are to
155 be displayed at the same time. 
156
157 A demuxer must make sure that the SEGMENT it emits on its output pads yield
158 the same running_time for buffers that should be played synchronized. This
159 usually means sending the same SEGMENT on all pads and making sure that the
160 synchronized buffers have the same timestamps.
161
162
163 Stream time
164 ~~~~~~~~~~~
165
166 The stream time is also known as the position in the stream and is a value
167 between 0 and the total duration of the media file.
168
169 It is the stream time that is used for:
170
171   - report the POSITION query in the pipeline
172   - the position used in seek events/queries
173   - the position used to synchronize controller values
174
175 Stream time is calculated using the buffer times and the preceeding SEGMENT
176 event as follows:
177
178     stream_time = (B.timestamp - NS.start) * NS.abs_applied_rate + NS.time
179  
180 For negative rates, B.timestamp will go backwards from NS.stop to NS.start,
181 making the stream time go backwards.
182
183 In the PLAYING state, it is also possible to use the pipeline clock to derive
184 the current stream_time.
185
186 Give the two formulas above to match the clock times with buffer timestamps
187 allows us to rewrite the above formula for stream_time (and for positive rates).
188
189     C.running_time = absolute_time - base_time
190     B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
191
192   =>
193     (B.timestamp - NS.start) / NS.abs_rate + NS.accum = absolute_time - base_time;
194
195   =>
196     (B.timestamp - NS.start) / NS.abs_rate = absolute_time - base_time - NS.accum;
197
198   =>
199     (B.timestamp - NS.start) = (absolute_time - base_time - NS.accum) * NS.abs_rate
200
201   filling (B.timestamp - NS.start) in the above formule for stream time
202
203   =>
204     stream_time = (absolute_time - base_time - NS.accum) * NS.abs_rate * NS.abs_applied_rate + NS.time
205
206 This last formula is typically used in sinks to report the current position in
207 an accurate and efficient way.
208
209 Note that the stream time is never used for synchronisation against the clock.
210