gst-libs/gst/audio/gstbaseaudiosink.c: Improve debugging.
authorWim Taymans <wim.taymans@gmail.com>
Wed, 25 Jan 2006 09:27:01 +0000 (09:27 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Wed, 25 Jan 2006 09:27:01 +0000 (09:27 +0000)
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.

ChangeLog
gst-libs/gst/audio/gstbaseaudiosink.c
gst-libs/gst/audio/gstbaseaudiosrc.c

index 0d7fa19..3ebbd0b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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):
index ea08500..cc3e00b 100644 (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 *
index 31638d7..1b057f7 100644 (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;
+
+  ringbuffer = src->ringbuffer;
 
-  if (!gst_ring_buffer_is_acquired (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)));