*
* 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,
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)));
}
}
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);
#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.
*/
GstCollectDataPrivate *priv;
- gpointer _gst_reserved[GST_PADDING];
+ /*< public >*/
+ union {
+ struct {
+ gint64 dts;
+ } abi;
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING];
+ } ABI;
};
/**
/* convenience helper */
GstFlowReturn gst_collect_pads_clip_running_time (GstCollectPads * pads,
- GstCollectData * cdata,
+ GstCollectData * cdata,
GstBuffer * buf, GstBuffer ** outbuf,
gpointer user_data);
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)
{
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);