collectpads: Add negative DTS support
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Fri, 3 Apr 2015 21:54:50 +0000 (17:54 -0400)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Fri, 12 Jun 2015 21:20:16 +0000 (17:20 -0400)
Make gst_collect_pads_clip_running_time() function also store the
signed DTS in the CollectData. This signed DTS value can be used by
muxers to properly handle streams where DTS can be negative initially.

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

libs/gst/base/gstcollectpads.c
libs/gst/base/gstcollectpads.h
tests/check/libs/collectpads.c

index 8866790..1973cdb 100644 (file)
@@ -495,6 +495,10 @@ gst_collect_pads_set_query_function (GstCollectPads * pads,
 *
 * Convenience clipping function that converts incoming buffer's timestamp
 * to running time, or clips the buffer if outside configured segment.
+*
+* Since 1.6, this clipping function also sets the DTS parameter of the
+* GstCollectData structure. This version of the running time DTS can be
+* negative. G_MININT64 is used to indicate invalid value.
 */
 GstFlowReturn
 gst_collect_pads_clip_running_time (GstCollectPads * pads,
@@ -515,13 +519,32 @@ gst_collect_pads_clip_running_time (GstCollectPads * pads,
       gst_buffer_unref (buf);
       *outbuf = NULL;
     } else {
-      GST_LOG_OBJECT (cdata->pad, "buffer ts %" GST_TIME_FORMAT " -> %"
+      GstClockTime buf_dts, abs_dts;
+      gint dts_sign;
+
+      GST_LOG_OBJECT (cdata->pad, "buffer pts %" GST_TIME_FORMAT " -> %"
           GST_TIME_FORMAT " running time",
           GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (time));
       *outbuf = gst_buffer_make_writable (buf);
       GST_BUFFER_PTS (*outbuf) = time;
-      GST_BUFFER_DTS (*outbuf) = gst_segment_to_running_time (&cdata->segment,
-          GST_FORMAT_TIME, GST_BUFFER_DTS (*outbuf));
+
+      dts_sign = gst_segment_to_running_time_full (&cdata->segment,
+          GST_FORMAT_TIME, GST_BUFFER_DTS (*outbuf), &abs_dts);
+      buf_dts = GST_BUFFER_DTS (*outbuf);
+      if (dts_sign > 0) {
+        GST_BUFFER_DTS (*outbuf) = abs_dts;
+        GST_COLLECT_PADS_DTS (cdata) = abs_dts;
+      } else if (dts_sign < 0) {
+        GST_BUFFER_DTS (*outbuf) = GST_CLOCK_TIME_NONE;
+        GST_COLLECT_PADS_DTS (cdata) = -((gint64) abs_dts);
+      } else {
+        GST_BUFFER_DTS (*outbuf) = GST_CLOCK_TIME_NONE;
+        GST_COLLECT_PADS_DTS (cdata) = GST_CLOCK_STIME_NONE;
+      }
+
+      GST_LOG_OBJECT (cdata->pad, "buffer dts %" GST_TIME_FORMAT " -> %"
+          GST_STIME_FORMAT " running time", GST_TIME_ARGS (buf_dts),
+          GST_STIME_ARGS (GST_COLLECT_PADS_DTS (cdata)));
     }
   }
 
@@ -634,6 +657,7 @@ gst_collect_pads_add_pad (GstCollectPads * pads, GstPad * pad, guint size,
   data->state |= lock ? GST_COLLECT_PADS_STATE_LOCKED : 0;
   data->priv->refcount = 1;
   data->priv->destroy_notify = destroy_notify;
+  data->ABI.abi.dts = G_MININT64;
 
   GST_OBJECT_LOCK (pads);
   GST_OBJECT_LOCK (pad);
index 9d56614..bfebaef 100644 (file)
@@ -104,12 +104,38 @@ typedef enum {
 #define GST_COLLECT_PADS_STATE_UNSET(data,flag)      (GST_COLLECT_PADS_STATE (data) &= ~(flag))
 
 /**
+ * GST_COLLECT_PADS_DTS:
+ * @data: A #GstCollectData.
+ *
+ * Returns the DTS that has been converted to running time when using
+ * gst_collect_pads_clip_running_time(). Unlike the value saved into
+ * the buffer, this value is of type gint64 and may be negative. This allow
+ * properly handling streams with frame reordering where the first DTS may
+ * be negative. If the initial DTS was not set, this value will be
+ * set to %G_MININT64.
+ *
+ * Since 1.6
+ */
+#define GST_COLLECT_PADS_DTS(data)                   (((GstCollectData *) data)->ABI.abi.dts)
+
+/**
+ * GST_COLLECT_PADS_DTS_IS_VALID:
+ * @data: A #GstCollectData.
+ *
+ * Check if running DTS value store is valid.
+ *
+ * Since 1.6
+ */
+#define GST_COLLECT_PADS_DTS_IS_VALID(data)          (GST_CLOCK_STIME_IS_VALID (GST_COLLECT_PADS_DTS (data)))
+
+/**
  * GstCollectData:
  * @collect: owner #GstCollectPads
  * @pad: #GstPad managed by this data
  * @buffer: currently queued buffer.
  * @pos: position in the buffer
  * @segment: last segment received.
+ * @dts: the signed version of the DTS converted to running time. Since 1.6
  *
  * Structure used by the collect_pads.
  */
@@ -129,7 +155,14 @@ struct _GstCollectData
 
   GstCollectDataPrivate *priv;
 
-  gpointer _gst_reserved[GST_PADDING];
+  /*< public >*/
+  union {
+    struct {
+      gint64 dts;
+    } abi;
+    /*< private >*/
+    gpointer _gst_reserved[GST_PADDING];
+  } ABI;
 };
 
 /**
@@ -363,7 +396,7 @@ void            gst_collect_pads_set_waiting   (GstCollectPads *pads, GstCollect
 
 /* convenience helper */
 GstFlowReturn  gst_collect_pads_clip_running_time (GstCollectPads * pads,
-                                                   GstCollectData * cdata,
+                                                    GstCollectData * cdata,
                                                     GstBuffer * buf, GstBuffer ** outbuf,
                                                     gpointer user_data);
 
index 9a3cb5d..4ad0c2a 100644 (file)
@@ -1005,6 +1005,58 @@ GST_START_TEST (test_flushing_seek)
 
 GST_END_TEST;
 
+GST_START_TEST (test_clip_running_time)
+{
+  GstBuffer *buf;
+  GstCollectData data = { 0 };
+
+  buf = gst_buffer_new ();
+  data.pad = gst_pad_new ("clip_test", GST_PAD_SRC);
+
+  GST_BUFFER_PTS (buf) = 0;
+  GST_BUFFER_DTS (buf) = 0;
+  gst_segment_init (&data.segment, GST_FORMAT_TIME);
+
+  gst_collect_pads_clip_running_time (NULL, &data, buf, &buf, NULL);
+
+  fail_unless (buf != NULL);
+  fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), 0);
+  fail_unless_equals_uint64 (GST_BUFFER_DTS (buf), 0);
+  fail_unless_equals_int64 (GST_COLLECT_PADS_DTS (&data), 0);
+
+  GST_BUFFER_PTS (buf) = 1000;
+  GST_BUFFER_DTS (buf) = 0;
+  data.segment.start = 1000;
+
+  gst_collect_pads_clip_running_time (NULL, &data, buf, &buf, NULL);
+
+  fail_unless (buf != NULL);
+  fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), 0);
+  fail_unless_equals_uint64 (GST_BUFFER_DTS (buf), GST_CLOCK_TIME_NONE);
+  fail_unless_equals_int64 (GST_COLLECT_PADS_DTS (&data), -1000);
+
+  GST_BUFFER_PTS (buf) = 1000;
+  GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
+
+  gst_collect_pads_clip_running_time (NULL, &data, buf, &buf, NULL);
+
+  fail_unless (buf != NULL);
+  fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), 0);
+  fail_unless_equals_uint64 (GST_BUFFER_DTS (buf), GST_CLOCK_TIME_NONE);
+  fail_if (GST_COLLECT_PADS_DTS_IS_VALID (&data));
+
+  GST_BUFFER_PTS (buf) = 0;
+  GST_BUFFER_DTS (buf) = 0;
+
+  gst_collect_pads_clip_running_time (NULL, &data, buf, &buf, NULL);
+
+  fail_unless (buf == NULL);
+  gst_object_unref (data.pad);
+}
+
+GST_END_TEST;
+
+
 static Suite *
 gst_collect_pads_suite (void)
 {
@@ -1022,6 +1074,7 @@ gst_collect_pads_suite (void)
   tcase_add_test (general, test_collect);
   tcase_add_test (general, test_collect_eos);
   tcase_add_test (general, test_collect_twice);
+  tcase_add_test (general, test_clip_running_time);
 
   buffers = tcase_create ("buffers");
   suite_add_tcase (suite, buffers);