qtmux: Fix ctts generation for streams that don't start at 0 timestamps
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Fri, 9 Sep 2011 12:12:56 +0000 (09:12 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Mon, 12 Sep 2011 10:37:10 +0000 (07:37 -0300)
Subtract the first timestamp of a stream from all input buffers to
get 0-based timestamps for creating a sane ctts table. Without this
patch the ctts could have larger values than needed, causing the
playback to have a delay at startup.

As the first timestamp is only found after a few buffers are queued
(due to possible reordered buffers), once we find the first timestamp
we subtract it from all buffers on the queue, from that point on,
all buffers have their timestamps subtract when they are collected.

https://bugzilla.gnome.org/show_bug.cgi?id=658659

gst/isomp4/gstqtmux.c

index 0f5c468..c6f2b4b 100644 (file)
@@ -2029,6 +2029,39 @@ gst_qt_mux_push_ts (GstQTMux * qtmux, GstQTPad * pad, GstClockTime ts)
   pad->ts_n_entries++;
 }
 
+static void
+check_and_subtract_ts (GstQTMux * qtmux, GstClockTime * ts_a, GstClockTime ts_b)
+{
+  if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (*ts_a))) {
+    if (G_LIKELY (*ts_a > ts_b)) {
+      *ts_a -= ts_b;
+    } else {
+      *ts_a = 0;
+      GST_WARNING_OBJECT (qtmux, "Subtraction would result in negative value, "
+          "using 0 as result");
+    }
+  }
+}
+
+/* subtract ts from all buffers enqueued on the pad */
+static void
+gst_qt_mux_subtract_ts (GstQTMux * qtmux, GstQTPad * pad, GstClockTime ts)
+{
+  gint i;
+
+  for (i = 0; (i < QTMUX_NO_OF_TS) && (i < pad->ts_n_entries); i++) {
+    check_and_subtract_ts (qtmux, &pad->ts_entries[i], ts);
+  }
+  for (i = 0; i < G_N_ELEMENTS (pad->buf_entries); i++) {
+    if (pad->buf_entries[i]) {
+      check_and_subtract_ts (qtmux, &GST_BUFFER_TIMESTAMP (pad->buf_entries[i]),
+          ts);
+      check_and_subtract_ts (qtmux,
+          &GST_BUFFER_OFFSET_END (pad->buf_entries[i]), ts);
+    }
+  }
+}
+
 /* takes ownership of @buf */
 static GstBuffer *
 gst_qt_mux_get_asc_buffer_ts (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf)
@@ -2085,6 +2118,13 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf)
     buf = pad->prepare_buf_func (pad, buf, qtmux);
   }
 
+  if (G_LIKELY (buf != NULL && GST_CLOCK_TIME_IS_VALID (pad->first_ts))) {
+    buf = gst_buffer_make_metadata_writable (buf);
+    check_and_subtract_ts (qtmux, &GST_BUFFER_TIMESTAMP (buf), pad->first_ts);
+  }
+  /* when we obtain the first_ts we subtract from all stored buffers we have,
+   * after that we can subtract on input */
+
 again:
   last_buf = pad->last_buf;
   if (qtmux->dts_method == DTS_METHOD_REORDER) {
@@ -2158,6 +2198,31 @@ again:
     goto no_order;
   }
 
+  /* if this is the first buffer, store the timestamp */
+  if (G_UNLIKELY (pad->first_ts == GST_CLOCK_TIME_NONE) && last_buf) {
+    if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (last_buf))) {
+      pad->first_ts = GST_BUFFER_TIMESTAMP (last_buf);
+    } else {
+      GST_DEBUG_OBJECT (qtmux, "First buffer for pad %s has no timestamp, "
+          "using 0 as first timestamp", GST_PAD_NAME (pad->collect.pad));
+      pad->first_ts = 0;
+    }
+    GST_DEBUG_OBJECT (qtmux, "Stored first timestamp for pad %s %"
+        GST_TIME_FORMAT, GST_PAD_NAME (pad->collect.pad),
+        GST_TIME_ARGS (pad->first_ts));
+
+    gst_qt_mux_subtract_ts (qtmux, pad, pad->first_ts);
+
+    GST_BUFFER_TIMESTAMP (last_buf) = 0;
+    check_and_subtract_ts (qtmux, &GST_BUFFER_OFFSET_END (last_buf),
+        pad->first_ts);
+    if (buf) {
+      check_and_subtract_ts (qtmux, &GST_BUFFER_TIMESTAMP (buf), pad->first_ts);
+      check_and_subtract_ts (qtmux, &GST_BUFFER_OFFSET_END (buf),
+          pad->first_ts);
+    }
+  }
+
   /* fall back to duration if last buffer or
    * out-of-order (determined previously), otherwise use input ts */
   if (buf == NULL ||
@@ -2317,20 +2382,6 @@ again:
     qtmux->longest_chunk = duration;
   }
 
-  /* if this is the first buffer, store the timestamp */
-  if (G_UNLIKELY (pad->first_ts == GST_CLOCK_TIME_NONE) && last_buf) {
-    if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (last_buf))) {
-      pad->first_ts = GST_BUFFER_TIMESTAMP (last_buf);
-    } else {
-      GST_DEBUG_OBJECT (qtmux, "First buffer for pad %s has no timestamp, "
-          "using 0 as first timestamp", GST_PAD_NAME (pad->collect.pad));
-      pad->first_ts = 0;
-    }
-    GST_DEBUG_OBJECT (qtmux, "Stored first timestamp for pad %s %"
-        GST_TIME_FORMAT, GST_PAD_NAME (pad->collect.pad),
-        GST_TIME_ARGS (pad->first_ts));
-  }
-
   /* now we go and register this buffer/sample all over */
   /* note that a new chunk is started each time (not fancy but works) */
   if (qtmux->moov_recov_file) {