baseparse: Make sure PTS >= DTS
authorVivia Nikolaidou <vivia@ahiru.eu>
Fri, 11 Oct 2019 14:33:42 +0000 (17:33 +0300)
committerVivia Nikolaidou <vivia@ahiru.eu>
Mon, 18 Nov 2019 12:09:22 +0000 (14:09 +0200)
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

index adfa447..89bb112 100644 (file)
@@ -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;