audiobuffersplit: Perform discont tracking on running time
authorSebastian Dröge <sebastian@centricular.com>
Fri, 8 May 2020 19:36:01 +0000 (22:36 +0300)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 11 May 2020 07:25:39 +0000 (07:25 +0000)
Otherwise we would have to drain on every segment event. Like this we
can handle segment events that don't cause a discontinuity in running
time to be handled without draining.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1254>

gst/audiobuffersplit/gstaudiobuffersplit.c
gst/audiobuffersplit/gstaudiobuffersplit.h

index ac1c3bd..bd66e9e 100644 (file)
@@ -361,9 +361,9 @@ gst_audio_buffer_split_output (GstAudioBufferSplit * self, gboolean force,
 {
   gint size, avail;
   GstFlowReturn ret = GST_FLOW_OK;
-  GstClockTime resync_time;
+  GstClockTime resync_pts;
 
-  resync_time = self->resync_time;
+  resync_pts = self->resync_pts;
   size = samples_per_buffer * bpf;
 
   /* If we accumulated enough error for one sample, include one
@@ -387,21 +387,21 @@ gst_audio_buffer_split_output (GstAudioBufferSplit * self, gboolean force,
     resync_time_diff =
         gst_util_uint64_scale (self->current_offset, GST_SECOND, rate);
     if (self->out_segment.rate < 0.0) {
-      if (resync_time > resync_time_diff)
-        GST_BUFFER_TIMESTAMP (buffer) = resync_time - resync_time_diff;
+      if (resync_pts > resync_time_diff)
+        GST_BUFFER_PTS (buffer) = resync_pts - resync_time_diff;
       else
-        GST_BUFFER_TIMESTAMP (buffer) = 0;
+        GST_BUFFER_PTS (buffer) = 0;
       GST_BUFFER_DURATION (buffer) =
           gst_util_uint64_scale (size / bpf, GST_SECOND, rate);
 
       self->current_offset += size / bpf;
     } else {
-      GST_BUFFER_TIMESTAMP (buffer) = resync_time + resync_time_diff;
+      GST_BUFFER_PTS (buffer) = resync_pts + resync_time_diff;
       self->current_offset += size / bpf;
       resync_time_diff =
           gst_util_uint64_scale (self->current_offset, GST_SECOND, rate);
       GST_BUFFER_DURATION (buffer) =
-          resync_time_diff - (GST_BUFFER_TIMESTAMP (buffer) - resync_time);
+          resync_time_diff - (GST_BUFFER_PTS (buffer) - resync_pts);
     }
 
     GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
@@ -412,9 +412,12 @@ gst_audio_buffer_split_output (GstAudioBufferSplit * self, gboolean force,
         self->error_per_buffer) % self->output_buffer_duration_d;
 
     GST_LOG_OBJECT (self,
-        "Outputting buffer at timestamp %" GST_TIME_FORMAT " with duration %"
-        GST_TIME_FORMAT " (%u samples)",
-        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
+        "Outputting buffer at running time %" GST_TIME_FORMAT
+        " with timestamp %" GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT
+        " (%u samples)",
+        GST_TIME_ARGS (gst_segment_to_running_time (&self->out_segment,
+                GST_FORMAT_TIME, GST_BUFFER_PTS (buffer))),
+        GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
         GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), size / bpf);
 
     ret = gst_pad_push (self->srcpad, buffer);
@@ -442,16 +445,35 @@ gst_audio_buffer_split_handle_discont (GstAudioBufferSplit * self,
   guint avail = gst_adapter_available (self->adapter);
   guint avail_samples = avail / bpf;
   guint64 new_offset;
-  GstClockTime current_timestamp;
-  GstClockTime current_timestamp_end;
+  GstClockTime input_rt, current_rt;
+  GstClockTime input_duration;
+  GstClockTime current_rt_end;
+
+  input_rt =
+      gst_segment_to_running_time (&self->in_segment, GST_FORMAT_TIME,
+      GST_BUFFER_PTS (buffer));
+  input_duration =
+      (gst_buffer_get_size (buffer) / bpf) / ABS (self->in_segment.rate);
 
   GST_OBJECT_LOCK (self);
+
+  if (self->in_segment.rate < 0) {
+    discont = FALSE;
+  } else {
+    discont = GST_BUFFER_IS_DISCONT (buffer)
+        || GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_RESYNC);
+  }
+
+  /* If the segment rate is changing this is a discontinuity */
+  discont = discont || (self->out_segment.format != GST_FORMAT_UNDEFINED
+      && self->in_segment.rate != self->out_segment.rate);
+
+  /* If this is the very first buffer we also have a discontinuity */
+  discont = discont || self->current_offset == -1;
+
   discont =
       gst_audio_stream_align_process (self->stream_align,
-      self->in_segment.rate < 0 ? FALSE : GST_BUFFER_IS_DISCONT (buffer)
-      || GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_RESYNC),
-      GST_BUFFER_PTS (buffer), gst_buffer_get_size (buffer) / bpf, NULL, NULL,
-      NULL);
+      discont, input_rt, input_duration, NULL, NULL, NULL);
   GST_OBJECT_UNLOCK (self);
 
   if (!discont)
@@ -461,45 +483,39 @@ gst_audio_buffer_split_handle_discont (GstAudioBufferSplit * self,
   self->drop_samples = 0;
 
   if (self->in_segment.rate < 0.0) {
-    current_timestamp =
-        self->resync_time - gst_util_uint64_scale (self->current_offset +
-        avail_samples, GST_SECOND, rate);
-    current_timestamp_end =
-        self->resync_time - gst_util_uint64_scale (self->current_offset,
-        GST_SECOND, rate);
+    current_rt =
+        self->resync_rt - gst_util_uint64_scale (self->current_offset +
+        avail_samples, GST_SECOND, rate * ABS (self->in_segment.rate));
+    current_rt_end =
+        self->resync_rt - gst_util_uint64_scale (self->current_offset,
+        GST_SECOND, rate * ABS (self->in_segment.rate));
   } else {
-    current_timestamp =
-        self->resync_time + gst_util_uint64_scale (self->current_offset,
-        GST_SECOND, rate);
-    current_timestamp_end =
-        self->resync_time + gst_util_uint64_scale (self->current_offset +
-        avail_samples, GST_SECOND, rate);
+    current_rt =
+        self->resync_rt + gst_util_uint64_scale (self->current_offset,
+        GST_SECOND, rate * self->in_segment.rate);
+    current_rt_end =
+        self->resync_rt + gst_util_uint64_scale (self->current_offset +
+        avail_samples, GST_SECOND, rate * self->in_segment.rate);
   }
 
   if (self->gapless) {
-    if (self->current_offset == -1) {
-      /* We only set resync time on the very first buffer */
-      self->current_offset = 0;
-      self->resync_time = GST_BUFFER_PTS (buffer);
-      discont = FALSE;
-    } else {
+    if (self->current_offset != -1) {
       GST_DEBUG_OBJECT (self,
-          "Got discont in gapless mode: Current timestamp %" GST_TIME_FORMAT
-          ", current end timestamp %" GST_TIME_FORMAT
-          ", timestamp after discont %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (current_timestamp),
-          GST_TIME_ARGS (current_timestamp_end),
-          GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
+          "Got discont in gapless mode: Current running time %" GST_TIME_FORMAT
+          ", current end running time %" GST_TIME_FORMAT
+          ", running time after discont %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (current_rt),
+          GST_TIME_ARGS (current_rt_end), GST_TIME_ARGS (input_rt));
 
       new_offset =
-          gst_util_uint64_scale (GST_BUFFER_PTS (buffer) - self->resync_time,
-          rate, GST_SECOND);
-      if (GST_BUFFER_PTS (buffer) < self->resync_time) {
+          gst_util_uint64_scale (current_rt - self->resync_rt,
+          rate * ABS (self->in_segment.rate), GST_SECOND);
+      if (current_rt < self->resync_rt) {
         guint64 drop_samples;
 
         new_offset =
-            gst_util_uint64_scale (self->resync_time -
-            GST_BUFFER_PTS (buffer), rate, GST_SECOND);
+            gst_util_uint64_scale (self->resync_rt -
+            current_rt, rate * ABS (self->in_segment.rate), GST_SECOND);
         drop_samples = self->current_offset + avail_samples + new_offset;
 
         GST_DEBUG_OBJECT (self,
@@ -567,12 +583,12 @@ gst_audio_buffer_split_handle_discont (GstAudioBufferSplit * self,
     /* We might end up in here also in gapless mode, if the above code decided
      * that no silence is to be inserted, because e.g. the gap is too big */
     GST_DEBUG_OBJECT (self,
-        "Got discont: Current timestamp %" GST_TIME_FORMAT
-        ", current end timestamp %" GST_TIME_FORMAT
-        ", timestamp after discont %" GST_TIME_FORMAT,
-        GST_TIME_ARGS (current_timestamp),
-        GST_TIME_ARGS (current_timestamp_end),
-        GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
+        "Got %s: Current running time %" GST_TIME_FORMAT
+        ", current end running time %" GST_TIME_FORMAT
+        ", running time after discont %" GST_TIME_FORMAT,
+        self->current_offset == -1 ? "first buffer" : "discont",
+        GST_TIME_ARGS (current_rt),
+        GST_TIME_ARGS (current_rt_end), GST_TIME_ARGS (input_rt));
 
     if (self->strict_buffer_size) {
       gst_adapter_clear (self->adapter);
@@ -585,7 +601,8 @@ gst_audio_buffer_split_handle_discont (GstAudioBufferSplit * self,
 
     self->current_offset = 0;
     self->accumulated_error = 0;
-    self->resync_time = GST_BUFFER_PTS (buffer);
+    self->resync_pts = GST_BUFFER_PTS (buffer);
+    self->resync_rt = input_rt;
 
     if (self->segment_pending) {
       GstEvent *event;
@@ -663,6 +680,16 @@ gst_audio_buffer_split_sink_chain (GstPad * pad, GstObject * parent,
   samples_per_buffer = self->samples_per_buffer;
   GST_OBJECT_UNLOCK (self);
 
+  GST_LOG_OBJECT (self,
+      "Processing buffer at running time %" GST_TIME_FORMAT
+      " with timestamp %" GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT
+      " (%u samples)",
+      GST_TIME_ARGS (gst_segment_to_running_time (&self->in_segment,
+              GST_FORMAT_TIME, GST_BUFFER_PTS (buffer))),
+      GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
+      (guint) (gst_buffer_get_size (buffer) / bpf));
+
   if (format == GST_AUDIO_FORMAT_UNKNOWN || samples_per_buffer == 0) {
     gst_buffer_unref (buffer);
     return GST_FLOW_NOT_NEGOTIATED;
index d22eba6..d902cbd 100644 (file)
@@ -55,7 +55,7 @@ struct _GstAudioBufferSplit {
   GstAdapter *adapter;
 
   GstAudioStreamAlign *stream_align;
-  GstClockTime resync_time;
+  GstClockTime resync_pts, resync_rt;
   guint64 current_offset; /* offset from start time in samples */
   guint64 drop_samples; /* number of samples to drop in gapless mode */