mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 19:20:35 +00:00
gst-libs/gst/audio/gstaudiosink.c: Choose to allocate one less segment but require one additional segment as latency.
Original commit message from CVS: * gst-libs/gst/audio/gstaudiosink.c: (gst_audioringbuffer_acquire): Choose to allocate one less segment but require one additional segment as latency. * gst-libs/gst/audio/gstaudiosrc.c: (gst_audioringbuffer_acquire): No need to increment the number of segments in the source. * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_get_time), (clock_convert_external), (gst_base_audio_sink_resample_slaving), (gst_base_audio_sink_skew_slaving), (gst_base_audio_sink_none_slaving), (gst_base_audio_sink_render), (gst_base_audio_sink_async_play): Remove adding latency when returning the internal time while subtracting it again when we use the value a little later. When calculating the end timestamp, we are making a rounding error with the current algorithm. Ensure that we don't accumulate these rounding errors when aligning samples by not resampling at all if we don't need to. Fixes #419351. Make the initial calibration of the clock slaving a little more predictable and accurate. Also handle the case where we don't do clock slaving.
This commit is contained in:
parent
531c6fb462
commit
fc523e047c
4 changed files with 76 additions and 41 deletions
25
ChangeLog
25
ChangeLog
|
@ -1,3 +1,28 @@
|
|||
2008-05-09 Wim Taymans <wim.taymans@collabora.co.uk>
|
||||
|
||||
* gst-libs/gst/audio/gstaudiosink.c: (gst_audioringbuffer_acquire):
|
||||
Choose to allocate one less segment but require one additional segment
|
||||
as latency.
|
||||
|
||||
* gst-libs/gst/audio/gstaudiosrc.c: (gst_audioringbuffer_acquire):
|
||||
No need to increment the number of segments in the source.
|
||||
|
||||
* gst-libs/gst/audio/gstbaseaudiosink.c:
|
||||
(gst_base_audio_sink_get_time), (clock_convert_external),
|
||||
(gst_base_audio_sink_resample_slaving),
|
||||
(gst_base_audio_sink_skew_slaving),
|
||||
(gst_base_audio_sink_none_slaving), (gst_base_audio_sink_render),
|
||||
(gst_base_audio_sink_async_play):
|
||||
Remove adding latency when returning the internal time while subtracting
|
||||
it again when we use the value a little later.
|
||||
When calculating the end timestamp, we are making a rounding error
|
||||
with the current algorithm. Ensure that we don't accumulate these
|
||||
rounding errors when aligning samples by not resampling at all if we
|
||||
don't need to. Fixes #419351.
|
||||
Make the initial calibration of the clock slaving a little more
|
||||
predictable and accurate. Also handle the case where we don't do
|
||||
clock slaving.
|
||||
|
||||
2008-05-09 Sebastian Dröge <slomo@circular-chaos.org>
|
||||
|
||||
Based on a patch by:
|
||||
|
|
|
@ -366,8 +366,8 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
|
|||
if (!result)
|
||||
goto could_not_prepare;
|
||||
|
||||
/* allocate one more segment as we need some headroom */
|
||||
spec->segtotal++;
|
||||
/* set latency to one more segment as we need some headroom */
|
||||
spec->seglatency = spec->segtotal + 1;
|
||||
|
||||
buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
|
||||
memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
|
||||
|
|
|
@ -360,9 +360,6 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
|
|||
if (!result)
|
||||
goto could_not_open;
|
||||
|
||||
/* allocate one more segment as we need some headroom */
|
||||
spec->segtotal++;
|
||||
|
||||
buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
|
||||
memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
|
||||
|
||||
|
|
|
@ -371,7 +371,7 @@ gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
|
|||
{
|
||||
guint64 raw, samples;
|
||||
guint delay;
|
||||
GstClockTime result, us_latency;
|
||||
GstClockTime result;
|
||||
|
||||
if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
|
||||
return GST_CLOCK_TIME_NONE;
|
||||
|
@ -391,15 +391,9 @@ gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
|
|||
result = gst_util_uint64_scale_int (samples, GST_SECOND,
|
||||
sink->ringbuffer->spec.rate);
|
||||
|
||||
/* latency before starting the clock */
|
||||
us_latency = sink->priv->us_latency;
|
||||
|
||||
result += us_latency;
|
||||
|
||||
GST_DEBUG_OBJECT (sink,
|
||||
"processed samples: raw %llu, delay %u, real %llu, time %"
|
||||
GST_TIME_FORMAT ", upstream latency %" GST_TIME_FORMAT, raw, delay,
|
||||
samples, GST_TIME_ARGS (result), GST_TIME_ARGS (us_latency));
|
||||
GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -787,8 +781,7 @@ gst_base_audio_sink_get_offset (GstBaseAudioSink * sink)
|
|||
|
||||
static GstClockTime
|
||||
clock_convert_external (GstClockTime external, GstClockTime cinternal,
|
||||
GstClockTime cexternal, GstClockTime crate_num, GstClockTime crate_denom,
|
||||
GstClockTime us_latency)
|
||||
GstClockTime cexternal, GstClockTime crate_num, GstClockTime crate_denom)
|
||||
{
|
||||
/* adjust for rate and speed */
|
||||
if (external >= cexternal) {
|
||||
|
@ -803,12 +796,6 @@ clock_convert_external (GstClockTime external, GstClockTime cinternal,
|
|||
else
|
||||
external = 0;
|
||||
}
|
||||
/* adjust for offset when slaving started */
|
||||
if (external > us_latency)
|
||||
external -= us_latency;
|
||||
else
|
||||
external = 0;
|
||||
|
||||
return external;
|
||||
}
|
||||
|
||||
|
@ -838,9 +825,9 @@ gst_base_audio_sink_resample_slaving (GstBaseAudioSink * sink,
|
|||
|
||||
/* bring external time to internal time */
|
||||
render_start = clock_convert_external (render_start, cinternal, cexternal,
|
||||
crate_num, crate_denom, sink->priv->us_latency);
|
||||
crate_num, crate_denom);
|
||||
render_stop = clock_convert_external (render_stop, cinternal, cexternal,
|
||||
crate_num, crate_denom, sink->priv->us_latency);
|
||||
crate_num, crate_denom);
|
||||
|
||||
GST_DEBUG_OBJECT (sink,
|
||||
"after slaving: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
|
||||
|
@ -875,6 +862,9 @@ gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink,
|
|||
etime = etime > cexternal ? etime - cexternal : 0;
|
||||
itime = itime > cinternal ? itime - cinternal : 0;
|
||||
|
||||
/* do itime - etime.
|
||||
* positive value means external clock goes slower
|
||||
* negative value means external clock goes faster */
|
||||
skew = GST_CLOCK_DIFF (etime, itime);
|
||||
if (sink->priv->avg_skew == -1) {
|
||||
/* first observation */
|
||||
|
@ -945,9 +935,9 @@ gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink,
|
|||
|
||||
/* convert, ignoring speed */
|
||||
render_start = clock_convert_external (render_start, cinternal, cexternal,
|
||||
crate_num, crate_denom, sink->priv->us_latency);
|
||||
crate_num, crate_denom);
|
||||
render_stop = clock_convert_external (render_stop, cinternal, cexternal,
|
||||
crate_num, crate_denom, sink->priv->us_latency);
|
||||
crate_num, crate_denom);
|
||||
|
||||
*srender_start = render_start;
|
||||
*srender_stop = render_stop;
|
||||
|
@ -967,9 +957,9 @@ gst_base_audio_sink_none_slaving (GstBaseAudioSink * sink,
|
|||
|
||||
/* convert, ignoring speed */
|
||||
render_start = clock_convert_external (render_start, cinternal, cexternal,
|
||||
crate_num, crate_denom, sink->priv->us_latency);
|
||||
crate_num, crate_denom);
|
||||
render_stop = clock_convert_external (render_stop, cinternal, cexternal,
|
||||
crate_num, crate_denom, sink->priv->us_latency);
|
||||
crate_num, crate_denom);
|
||||
|
||||
*srender_start = render_start;
|
||||
*srender_stop = render_stop;
|
||||
|
@ -1153,26 +1143,34 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||
render_stop = gst_util_uint64_scale_int (render_stop,
|
||||
ringbuf->spec.rate, GST_SECOND);
|
||||
|
||||
/* positive playback rate, first sample is render_start, negative rate, first
|
||||
* sample is render_stop. When no rate conversion is active, render exactly
|
||||
* the amount of input samples to avoid aligning to rounding errors. */
|
||||
if (bsink->segment.rate >= 0.0) {
|
||||
sample_offset = render_start;
|
||||
if (bsink->segment.rate == 1.0)
|
||||
render_stop = sample_offset + samples;
|
||||
} else {
|
||||
sample_offset = render_stop;
|
||||
if (bsink->segment.rate == -1.0)
|
||||
render_start = sample_offset + samples;
|
||||
}
|
||||
|
||||
/* always resync after a discont */
|
||||
if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
|
||||
GST_DEBUG_OBJECT (sink, "resync after discont");
|
||||
goto no_align;
|
||||
}
|
||||
|
||||
/* resync when we don't know what to align the sample with */
|
||||
if (G_UNLIKELY (sink->next_sample == -1)) {
|
||||
GST_DEBUG_OBJECT (sink,
|
||||
"no align possible: no previous sample position known");
|
||||
goto no_align;
|
||||
}
|
||||
|
||||
/* positive playback rate, first sample is render_start, negative rate, first
|
||||
* sample is render_stop */
|
||||
if (bsink->segment.rate >= 0.0)
|
||||
sample_offset = render_start;
|
||||
else
|
||||
sample_offset = render_stop;
|
||||
|
||||
/* now try to align the sample to the previous one */
|
||||
/* now try to align the sample to the previous one, first see how big the
|
||||
* difference is. */
|
||||
if (sample_offset >= sink->next_sample)
|
||||
diff = sample_offset - sink->next_sample;
|
||||
else
|
||||
|
@ -1422,12 +1420,22 @@ gst_base_audio_sink_async_play (GstBaseSink * basesink)
|
|||
/* if we are slaved to a clock, we need to set the initial
|
||||
* calibration */
|
||||
/* get external and internal time to set as calibration params */
|
||||
etime = gst_clock_get_time (clock);
|
||||
itime = gst_clock_get_internal_time (sink->provided_clock);
|
||||
|
||||
sink->priv->avg_skew = -1;
|
||||
sink->next_sample = -1;
|
||||
etime = GST_ELEMENT_CAST (sink)->base_time;
|
||||
itime = gst_base_audio_sink_get_time (sink->provided_clock, sink);
|
||||
|
||||
switch (sink->priv->slave_method) {
|
||||
case GST_BASE_AUDIO_SINK_SLAVE_SKEW:
|
||||
case GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE:
|
||||
/* adjust with upstream latency, when we are prerolled, our internal clock
|
||||
* should exactly have been the time of the upstream latency */
|
||||
etime += sink->priv->us_latency;
|
||||
break;
|
||||
case GST_BASE_AUDIO_SINK_SLAVE_NONE:
|
||||
/* no slaving, base_time corresponds to our 0 time */
|
||||
itime = 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
GST_DEBUG_OBJECT (sink,
|
||||
"internal time: %" GST_TIME_FORMAT " external time: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (itime), GST_TIME_ARGS (etime));
|
||||
|
@ -1439,14 +1447,19 @@ gst_base_audio_sink_async_play (GstBaseSink * basesink)
|
|||
|
||||
switch (sink->priv->slave_method) {
|
||||
case GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE:
|
||||
/* only set as master if we need to resample */
|
||||
/* only set as master when we are resampling */
|
||||
GST_DEBUG_OBJECT (sink, "Setting clock as master");
|
||||
gst_clock_set_master (sink->provided_clock, clock);
|
||||
break;
|
||||
case GST_BASE_AUDIO_SINK_SLAVE_SKEW:
|
||||
case GST_BASE_AUDIO_SINK_SLAVE_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sink->priv->avg_skew = -1;
|
||||
sink->next_sample = -1;
|
||||
|
||||
/* start ringbuffer so we can start slaving right away when we need to */
|
||||
gst_ring_buffer_start (sink->ringbuffer);
|
||||
|
||||
|
|
Loading…
Reference in a new issue