gst-libs/gst/audio/gstbaseaudiosrc.c: Implement skew clock slaving. Fixes #552559.

Original commit message from CVS:
Patch by: Håvard Graff <havard dot graff at tandberg dot com>
* gst-libs/gst/audio/gstbaseaudiosrc.c:
(gst_base_audio_src_create):
Implement skew clock slaving. Fixes #552559.
This commit is contained in:
Håvard Graff 2008-10-08 09:12:36 +00:00 committed by Wim Taymans
parent dd01a1e56a
commit 11086cf6f8
2 changed files with 121 additions and 3 deletions

View file

@ -1,3 +1,11 @@
2008-10-08 Wim Taymans <wim.taymans@collabora.co.uk>
Patch by: Håvard Graff <havard dot graff at tandberg dot com>
* gst-libs/gst/audio/gstbaseaudiosrc.c:
(gst_base_audio_src_create):
Implement skew clock slaving. Fixes #552559.
2008-10-08 Wim Taymans <wim.taymans@collabora.co.uk> 2008-10-08 Wim Taymans <wim.taymans@collabora.co.uk>
* gst-libs/gst/audio/multichannel.c: * gst-libs/gst/audio/multichannel.c:

View file

@ -823,12 +823,122 @@ gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
/* we are slaved, check how to handle this */ /* we are slaved, check how to handle this */
switch (src->priv->slave_method) { switch (src->priv->slave_method) {
case GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE: case GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE:
/* not implemented, use retimestamp algorithm. This algorithm should /* not implemented, use skew algorithm. This algorithm should
* work on the readout pointer and produces more or less samples based * work on the readout pointer and produces more or less samples based
* on the clock drift */ * on the clock drift */
case GST_BASE_AUDIO_SRC_SLAVE_SKEW: case GST_BASE_AUDIO_SRC_SLAVE_SKEW:
/* not implemented, use retimestamp algorithm. This algortihm should work {
* on the readout pointer above and creates small jumps when needed. */ GstClockTime running_time;
GstClockTime base_time;
GstClockTime current_time;
guint64 running_time_sample;
gint running_time_segment;
gint current_segment;
gint segment_skew;
gint sps;
/* samples per segment */
sps = ringbuffer->samples_per_seg;
/* get the current time */
current_time = gst_clock_get_time (clock);
/* get the basetime */
base_time = GST_ELEMENT_CAST (src)->base_time;
/* get the running_time */
running_time = current_time - base_time;
/* the running_time converted to a sample (relative to the ringbuffer) */
running_time_sample =
gst_util_uint64_scale_int (running_time, spec->rate, GST_SECOND);
/* the segmentnr corrensponding to running_time, round down */
running_time_segment = running_time_sample / sps;
/* the segment currently read from the ringbuffer */
current_segment = sample / sps;
/* the skew we have between running_time and the ringbuffertime */
segment_skew = running_time_segment - current_segment;
GST_DEBUG_OBJECT (bsrc, "\n running_time = % " GST_TIME_FORMAT
"\n timestamp = % " GST_TIME_FORMAT
"\n running_time_segment = %d"
"\n current_segment = %d"
"\n segment_skew = %d",
GST_TIME_ARGS (running_time),
GST_TIME_ARGS (timestamp),
running_time_segment, current_segment, segment_skew);
/* Resync the ringbuffer if:
* 1. We get one segment into the future.
* This is clearly a lie, because we can't
* possibly have a buffer with timestamp 1 at
* time 0. (unless it has time-travelled...)
*
* 2. We are more than the length of the ringbuffer behind.
* The length of the ringbuffer then gets to dictate
* the threshold for what is concidered "too late"
*
* 3. If this is our first buffer.
* We know that we should catch up to running_time
* the first time we are ran.
*/
if ((segment_skew < 0) ||
(segment_skew >= ringbuffer->spec.segtotal) ||
(current_segment == 0)) {
gint segments_written;
gint first_segment;
gint last_segment;
gint new_last_segment;
gint segment_diff;
gint new_first_segment;
guint64 new_sample;
/* we are going to say that the last segment was captured at the current time
(running_time), minus one segment of creation-latency in the ringbuffer.
This can be thought of as: The segment arrived in the ringbuffer at time X, and
that means it was created at time X - (one segment). */
new_last_segment = running_time_segment - 1;
/* for better readablity */
first_segment = current_segment;
/* get the amount of segments written from the device by now */
segments_written = g_atomic_int_get (&ringbuffer->segdone);
/* subtract the base to segments_written to get the number of the
last written segment in the ringbuffer (one segment written = segment 0) */
last_segment = segments_written - ringbuffer->segbase - 1;
/* we see how many segments the ringbuffer was timeshifted */
segment_diff = new_last_segment - last_segment;
/* we move the first segment an equal amount */
new_first_segment = first_segment + segment_diff;
/* and we also move the segmentbase the same amount */
ringbuffer->segbase -= segment_diff;
/* we calculate the new sample value */
new_sample = new_first_segment * sps;
/* and get the relative time to this -> our new timestamp */
timestamp =
gst_util_uint64_scale_int (new_sample, GST_SECOND, spec->rate);
/* we update the next sample accordingly */
src->next_sample = new_sample + samples;
GST_DEBUG_OBJECT (bsrc,
"Timeshifted the ringbuffer with %d segments: "
"Updating the timestamp to % " GST_TIME_FORMAT ", "
"and src->next_sample to % " G_GUINT64_FORMAT, segment_diff,
GST_TIME_ARGS (timestamp), src->next_sample);
}
break;
}
case GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP: case GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP:
{ {
GstClockTime base_time, latency; GstClockTime base_time, latency;