From b5e4f7bd9dc4380b13fb7370efec581abbd2e6af Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 3 Apr 2015 17:54:50 -0400 Subject: [PATCH] collectpads: Add negative DTS support 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 | 30 +++++++++++++++++++++--- libs/gst/base/gstcollectpads.h | 37 +++++++++++++++++++++++++++-- tests/check/libs/collectpads.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 5 deletions(-) diff --git a/libs/gst/base/gstcollectpads.c b/libs/gst/base/gstcollectpads.c index 8866790..1973cdb 100644 --- a/libs/gst/base/gstcollectpads.c +++ b/libs/gst/base/gstcollectpads.c @@ -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); diff --git a/libs/gst/base/gstcollectpads.h b/libs/gst/base/gstcollectpads.h index 9d56614..bfebaef 100644 --- a/libs/gst/base/gstcollectpads.h +++ b/libs/gst/base/gstcollectpads.h @@ -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); diff --git a/tests/check/libs/collectpads.c b/tests/check/libs/collectpads.c index 9a3cb5d..4ad0c2a 100644 --- a/tests/check/libs/collectpads.c +++ b/tests/check/libs/collectpads.c @@ -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); -- 2.7.4