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
This commit is contained in:
Nicolas Dufresne 2015-04-03 17:54:50 -04:00
parent 5cab2e14c4
commit b5e4f7bd9d
3 changed files with 115 additions and 5 deletions

View 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);

View file

@ -103,6 +103,31 @@ 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
@ -110,6 +135,7 @@ typedef enum {
* @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);

View 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);