From fa8312472f08d468677d188d5cf1ad52c5b5b0a0 Mon Sep 17 00:00:00 2001 From: Vivia Nikolaidou Date: Fri, 11 Oct 2019 17:33:42 +0300 Subject: [PATCH] baseparse: Make sure PTS >= DTS If, for example, we are accumulating rounding errors from the buffer duration when calculating the PTS/DTS, it can happen that the buffer thinks it should be presented before it's decoded. In that case we just clamp the DTS. --- libs/gst/base/gstbaseparse.c | 54 ++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/libs/gst/base/gstbaseparse.c b/libs/gst/base/gstbaseparse.c index adfa447418..89bb112d1b 100644 --- a/libs/gst/base/gstbaseparse.c +++ b/libs/gst/base/gstbaseparse.c @@ -990,15 +990,59 @@ static GstFlowReturn gst_base_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstBuffer *buffer = frame->buffer; + gboolean must_approximate_pts = !GST_BUFFER_PTS_IS_VALID (buffer) + && GST_CLOCK_TIME_IS_VALID (parse->priv->next_pts); + gboolean must_approximate_dts = !GST_BUFFER_DTS_IS_VALID (buffer) + && GST_CLOCK_TIME_IS_VALID (parse->priv->next_dts); - if (!GST_BUFFER_PTS_IS_VALID (buffer) && - GST_CLOCK_TIME_IS_VALID (parse->priv->next_pts)) { + if (must_approximate_pts) { GST_BUFFER_PTS (buffer) = parse->priv->next_pts; + if (!must_approximate_dts + && GST_BUFFER_DTS (buffer) > parse->priv->next_pts) { + /* Can't present a frame before it's decoded: change the pts! This can + * happen, for example, when accumulating rounding errors from the + * buffer durations. Assume DTS is correct because only PTS is + * approximated here */ + GST_LOG_OBJECT (parse, + "Found DTS (%" GST_TIME_FORMAT ") > PTS (%" GST_TIME_FORMAT + "), set PTS = DTS", GST_TIME_ARGS (GST_BUFFER_DTS (buffer)), + GST_TIME_ARGS (GST_BUFFER_PTS (buffer))); + GST_BUFFER_PTS (buffer) = GST_BUFFER_DTS (buffer); + } } - if (!GST_BUFFER_DTS_IS_VALID (buffer) && - GST_CLOCK_TIME_IS_VALID (parse->priv->next_dts)) { - GST_BUFFER_DTS (buffer) = parse->priv->next_dts; + + if (must_approximate_dts) { + if (!must_approximate_pts + && GST_BUFFER_PTS (buffer) < parse->priv->next_dts) { + /* Can't present a frame before it's decoded: change the dts! This can + * happen, for example, when accumulating rounding errors from the + * buffer durations. Assume PTS is correct because only DTS is + * approximated here */ + GST_LOG_OBJECT (parse, + "Found DTS (%" GST_TIME_FORMAT ") > PTS (%" GST_TIME_FORMAT + "), set DTS = PTS", GST_TIME_ARGS (GST_BUFFER_DTS (buffer)), + GST_TIME_ARGS (GST_BUFFER_PTS (buffer))); + GST_BUFFER_DTS (buffer) = GST_BUFFER_PTS (buffer); + } else { + GST_BUFFER_DTS (buffer) = parse->priv->next_dts; + } } + + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)) + && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (buffer)) + && GST_BUFFER_PTS (buffer) < GST_BUFFER_DTS (buffer)) { + /* Can't present a frame before it's decoded: change the pts! This can + * happen, for example, when accumulating rounding errors from the buffer + * durations. PTS and DTS are either both approximated or both from the + * original buffer timestamp. Set PTS = DTS because the opposite has been + * observed to cause DTS going backwards */ + GST_LOG_OBJECT (parse, + "Found DTS (%" GST_TIME_FORMAT ") > PTS (%" GST_TIME_FORMAT + "), set PTS = DTS", GST_TIME_ARGS (GST_BUFFER_DTS (buffer)), + GST_TIME_ARGS (GST_BUFFER_PTS (buffer))); + GST_BUFFER_PTS (buffer) = GST_BUFFER_DTS (buffer); + } + if (!GST_BUFFER_DURATION_IS_VALID (buffer) && GST_CLOCK_TIME_IS_VALID (parse->priv->frame_duration)) { GST_BUFFER_DURATION (buffer) = parse->priv->frame_duration;