gst-libs/gst/audio/gstbaseaudiosink.c: Improve debugging.

Original commit message from CVS:
* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_base_audio_sink_setcaps), (gst_base_audio_sink_event),
(gst_base_audio_sink_preroll), (gst_base_audio_sink_render):
Improve debugging.
Post error when caps cannot be parsed.
Resync on discontinuity in the stream.
Clip samples to segment boundaries.
return WRONG_STATE sooner when we are flushing.

* gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_init),
(gst_base_audio_src_get_time), (gst_base_audio_src_create):
Make audiosrc operate in TIME.
Set TIMESTAMP and DURATION on buffers.
This commit is contained in:
Wim Taymans 2006-01-25 09:27:01 +00:00
parent 8eb4e006a2
commit 2bc5ca1786
3 changed files with 124 additions and 55 deletions

View file

@ -1,3 +1,19 @@
2006-01-25 Wim Taymans <wim@fluendo.com>
* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_base_audio_sink_setcaps), (gst_base_audio_sink_event),
(gst_base_audio_sink_preroll), (gst_base_audio_sink_render):
Improve debugging.
Post error when caps cannot be parsed.
Resync on discontinuity in the stream.
Clip samples to segment boundaries.
return WRONG_STATE sooner when we are flushing.
* gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_init),
(gst_base_audio_src_get_time), (gst_base_audio_src_create):
Make audiosrc operate in TIME.
Set TIMESTAMP and DURATION on buffers.
2006-01-24 Tim-Philipp Müller <tim at centricular dot net>
* tests/examples/seek/seek.c: (main):

View file

@ -262,12 +262,12 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
spec = &sink->ringbuffer->spec;
GST_DEBUG ("release old ringbuffer");
GST_DEBUG_OBJECT (sink, "release old ringbuffer");
/* release old ringbuffer */
gst_ring_buffer_release (sink->ringbuffer);
GST_DEBUG ("parse caps");
GST_DEBUG_OBJECT (sink, "parse caps");
spec->buffer_time = sink->buffer_time;
spec->latency_time = sink->latency_time;
@ -278,7 +278,7 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
gst_ring_buffer_debug_spec_buff (spec);
GST_DEBUG ("acquire new ringbuffer");
GST_DEBUG_OBJECT (sink, "acquire new ringbuffer");
if (!gst_ring_buffer_acquire (sink->ringbuffer, spec))
goto acquire_error;
@ -297,12 +297,14 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
/* ERRORS */
parse_error:
{
GST_DEBUG ("could not parse caps");
GST_DEBUG_OBJECT (sink, "could not parse caps");
GST_ELEMENT_ERROR (sink, STREAM, FORMAT,
("cannot parse audio format."), ("cannot parse audio format."));
return FALSE;
}
acquire_error:
{
GST_DEBUG ("could not acquire ringbuffer");
GST_DEBUG_OBJECT (sink, "could not acquire ringbuffer");
return FALSE;
}
}
@ -332,7 +334,9 @@ gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
break;
case GST_EVENT_EOS:
/* need to start playback when we reach EOS */
gst_ring_buffer_start (sink->ringbuffer);
/* now wait till we played everything */
break;
default:
break;
@ -355,7 +359,7 @@ gst_base_audio_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
wrong_state:
{
GST_DEBUG ("ringbuffer in wrong state");
GST_DEBUG_OBJECT (sink, "ringbuffer in wrong state");
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
("sink not negotiated."), ("sink not negotiated."));
return GST_FLOW_NOT_NEGOTIATED;
@ -396,11 +400,10 @@ static GstFlowReturn
gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{
guint64 render_offset, in_offset;
GstClockTime time, render_time, duration;
GstClockTimeDiff render_diff;
GstClockTime time, stop, render_time, duration;
GstBaseAudioSink *sink;
GstRingBuffer *ringbuf;
gint64 diff;
gint64 diff, ctime, cstop;
guint8 *data;
guint size;
guint samples;
@ -412,6 +415,11 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
sink = GST_BASE_AUDIO_SINK (bsink);
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
/* always resync after a discont */
sink->next_sample = -1;
}
ringbuf = sink->ringbuffer;
/* can't do anything when we don't have the device */
@ -431,80 +439,109 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
duration = GST_BUFFER_DURATION (buf);
data = GST_BUFFER_DATA (buf);
GST_DEBUG ("time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT,
GST_DEBUG_OBJECT (sink,
"time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT,
GST_TIME_ARGS (time), in_offset, GST_TIME_ARGS (bsink->segment.start));
/* if not valid timestamp or we don't need to sync, try to play
* sample ASAP */
if (!GST_CLOCK_TIME_IS_VALID (time) || !bsink->sync) {
render_offset = gst_base_audio_sink_get_offset (sink);
GST_DEBUG ("Buffer of size %u has no time. Using render_offset=%"
G_GUINT64_FORMAT, GST_BUFFER_SIZE (buf), render_offset);
stop = -1;
GST_DEBUG_OBJECT (sink,
"Buffer of size %u has no time. Using render_offset=%" G_GUINT64_FORMAT,
GST_BUFFER_SIZE (buf), render_offset);
goto no_sync;
}
render_diff = time - bsink->segment.start;
/* samples should be rendered based on their timestamp. All samples
* arriving before the segment.start are to be thrown away */
/* FIXME, for now we drop the sample completely, we should
* in fact clip the sample. Same for the segment.stop, actually. */
if (render_diff < 0)
* arriving before the segment.start or after segment.stop are to be
* thrown away. All samples should also be clipped to the segment
* boundaries */
stop =
time + gst_util_uint64_scale_int (samples, GST_SECOND,
ringbuf->spec.rate);
if (!gst_segment_clip (&bsink->segment, GST_FORMAT_TIME, time, stop, &ctime,
&cstop))
goto out_of_segment;
/* see if some clipping happened */
diff = ctime - time;
if (diff > 0) {
diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND);
GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %"
G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff);
samples -= diff;
data += samples * bps;
time = ctime;
}
diff = stop - cstop;
if (diff > 0) {
diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND);
GST_DEBUG_OBJECT (sink, "clipping stop to %" GST_TIME_FORMAT " %"
G_GUINT64_FORMAT " samples", GST_TIME_ARGS (cstop), diff);
samples -= diff;
stop = cstop;
}
gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
&crate_num, &crate_denom);
/* bring buffer timestamp to stream time */
render_time = render_diff;
/* adjust for rate */
render_time /= ABS (bsink->segment.rate);
/* adjust for accumulated segments */
render_time += bsink->segment.accum;
/* bring buffer timestamp to running time */
render_time =
gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, time);
/* add base time to get absolute clock time */
render_time +=
(gst_element_get_base_time (GST_ELEMENT_CAST (bsink)) - cexternal) +
cinternal;
/* and bring the time to the offset in the buffer */
render_offset = render_time * ringbuf->spec.rate / GST_SECOND;
render_offset =
gst_util_uint64_scale_int (render_time, ringbuf->spec.rate, GST_SECOND);
GST_DEBUG_OBJECT (sink, "render time %" GST_TIME_FORMAT
", render offset %llu, samples %lu",
GST_TIME_ARGS (render_time), render_offset, samples);
/* roundoff errors in timestamp conversion */
if (sink->next_sample != -1)
if (sink->next_sample != -1) {
diff = ABS ((gint64) render_offset - (gint64) sink->next_sample);
else
diff = ringbuf->spec.rate;
GST_DEBUG ("render time %" GST_TIME_FORMAT
", render offset %llu, diff %lld, samples %lu",
GST_TIME_ARGS (render_time), render_offset, diff, samples);
/* we tollerate a 10th of a second diff before we start resyncing. This
* should be enough to compensate for various rounding errors in the timestamp
* and sample offset position. */
if (diff < ringbuf->spec.rate / DIFF_TOLERANCE) {
GST_DEBUG ("align with prev sample, %" G_GINT64_FORMAT " < %lu", diff,
ringbuf->spec.rate / DIFF_TOLERANCE);
/* just align with previous sample then */
render_offset = sink->next_sample;
/* we tollerate a 10th of a second diff before we start resyncing. This
* should be enough to compensate for various rounding errors in the timestamp
* and sample offset position. */
if (diff < ringbuf->spec.rate / DIFF_TOLERANCE) {
GST_DEBUG_OBJECT (sink,
"align with prev sample, %" G_GINT64_FORMAT " < %lu", diff,
ringbuf->spec.rate / DIFF_TOLERANCE);
/* just align with previous sample then */
render_offset = sink->next_sample;
} else {
GST_DEBUG_OBJECT (sink,
"resync after discont with previous sample of diff: %lu", diff);
}
} else {
GST_DEBUG ("resync");
GST_DEBUG_OBJECT (sink, "resync after discont");
}
crate = ((gdouble) crate_num) / crate_denom;
GST_DEBUG_OBJECT (sink,
"internal %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", rate %g",
cinternal, cexternal, crate);
no_sync:
/* clip length based on rate */
samples = MIN (samples, samples / (crate * ABS (bsink->segment.rate)));
samples = MIN (samples, samples / (crate * bsink->segment.abs_rate));
/* the next sample should be current sample and its length */
sink->next_sample = render_offset + samples;
gst_ring_buffer_commit (ringbuf, render_offset, data, samples);
samples = gst_ring_buffer_commit (ringbuf, render_offset, data, samples);
if (samples == -1)
goto stopping;
if (GST_CLOCK_TIME_IS_VALID (time) && time + duration >= bsink->segment.stop) {
GST_DEBUG ("start playback because we are at the end of segment");
if (GST_CLOCK_TIME_IS_VALID (stop) && stop >= bsink->segment.stop) {
GST_DEBUG_OBJECT (sink,
"start playback because we are at the end of segment");
gst_ring_buffer_start (ringbuf);
}
@ -512,26 +549,32 @@ no_sync:
out_of_segment:
{
GST_DEBUG ("dropping sample out of segment time %" GST_TIME_FORMAT
", start %" GST_TIME_FORMAT,
GST_TIME_ARGS (time), GST_TIME_ARGS (bsink->segment.start));
GST_DEBUG_OBJECT (sink,
"dropping sample out of segment time %" GST_TIME_FORMAT ", start %"
GST_TIME_FORMAT, GST_TIME_ARGS (time),
GST_TIME_ARGS (bsink->segment.start));
return GST_FLOW_OK;
}
wrong_state:
{
GST_DEBUG ("ringbuffer not negotiated");
GST_DEBUG_OBJECT (sink, "ringbuffer not negotiated");
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
("sink not negotiated."), ("sink not negotiated."));
return GST_FLOW_NOT_NEGOTIATED;
}
wrong_size:
{
GST_DEBUG ("wrong size");
GST_DEBUG_OBJECT (sink, "wrong size");
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
("sink received buffer of wrong size."),
("sink received buffer of wrong size."));
return GST_FLOW_ERROR;
}
stopping:
{
GST_DEBUG_OBJECT (sink, "ringbuffer is stopping");
return GST_FLOW_WRONG_STATE;
}
}
GstRingBuffer *

View file

@ -138,6 +138,8 @@ gst_base_audio_src_init (GstBaseAudioSrc * baseaudiosrc,
gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (baseaudiosrc),
gst_base_audio_src_fixate);
gst_base_src_set_format (GST_BASE_SRC (baseaudiosrc), GST_FORMAT_TIME);
}
static GstClock *
@ -161,7 +163,8 @@ gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src)
samples = gst_ring_buffer_samples_done (src->ringbuffer);
result = samples * GST_SECOND / src->ringbuffer->spec.rate;
result = gst_util_uint64_scale_int (samples, GST_SECOND,
src->ringbuffer->spec.rate);
return result;
}
@ -319,11 +322,14 @@ gst_base_audio_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
guint len, samples;
guint res;
guint64 sample;
GstRingBuffer *ringbuffer;
if (!gst_ring_buffer_is_acquired (src->ringbuffer))
ringbuffer = src->ringbuffer;
if (!gst_ring_buffer_is_acquired (ringbuffer))
goto wrong_state;
buf = gst_buffer_new_and_alloc (src->ringbuffer->spec.segsize);
buf = gst_buffer_new_and_alloc (ringbuffer->spec.segsize);
data = GST_BUFFER_DATA (buf);
len = GST_BUFFER_SIZE (buf);
@ -334,13 +340,17 @@ gst_base_audio_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
sample = 0;
}
samples = len / src->ringbuffer->spec.bytes_per_sample;
samples = len / ringbuffer->spec.bytes_per_sample;
res = gst_ring_buffer_read (src->ringbuffer, sample, data, samples);
res = gst_ring_buffer_read (ringbuffer, sample, data, samples);
if (res == -1)
goto stopped;
GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (sample,
GST_SECOND, ringbuffer->spec.rate);
src->next_sample = sample + samples;
GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (src->next_sample,
GST_SECOND, ringbuffer->spec.rate) - GST_BUFFER_TIMESTAMP (buf);
gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (psrc)));