ext/ffmpeg/gstffmpegdec.c: Fix timestamping for out-of-order incoming buffers. Instea...
authorEdward Hervey <bilboed@bilboed.com>
Wed, 2 May 2007 16:06:09 +0000 (16:06 +0000)
committerEdward Hervey <bilboed@bilboed.com>
Wed, 2 May 2007 16:06:09 +0000 (16:06 +0000)
Original commit message from CVS:
* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_init),
(gst_ffmpegdec_open), (gst_ffmpegdec_save_incoming_values),
(gst_ffmpegdec_get_best_values), (gst_ffmpegdec_video_frame),
(gst_ffmpegdec_sink_event):
Fix timestamping for out-of-order incoming buffers. Instead of blindly
copying the incoming buffer timestamps on the outgoing buffers we cache
the latest 2 incoming buffer timestamps and duration and make a wise
choice as to what the outgoing buffer timestamp and duration should be.
Fixes #342962

ChangeLog
common
ext/ffmpeg/gstffmpegdec.c

index 09c8141..d4cc80a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2007-05-02  Edward Hervey  <edward@fluendo.com>
+
+       * ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_init),
+       (gst_ffmpegdec_open), (gst_ffmpegdec_save_incoming_values),
+       (gst_ffmpegdec_get_best_values), (gst_ffmpegdec_video_frame),
+       (gst_ffmpegdec_sink_event):
+       Fix timestamping for out-of-order incoming buffers. Instead of blindly
+       copying the incoming buffer timestamps on the outgoing buffers we cache
+       the latest 2 incoming buffer timestamps and duration and make a wise
+       choice as to what the outgoing buffer timestamp and duration should be.
+       Fixes #342962
+
 2007-04-25  Edward Hervey  <edward@fluendo.com>
 
        * ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_codecid_to_caps),
diff --git a/common b/common
index a19d235..61edc2d 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit a19d235c89d99ca7849078d501129f521e30d98d
+Subproject commit 61edc2dc7b8eba179d85a6545e46e0d65239e94d
index 6ea54b0..5fbe7b5 100644 (file)
@@ -88,6 +88,11 @@ struct _GstFFMpegDec
 
   /* clipping segment */
   GstSegment segment;
+
+  /* out-of-order incoming buffer special handling */
+  gboolean outoforder;
+  GstClockTime tstamp1, tstamp2;
+  GstClockTime dur1, dur2;
 };
 
 typedef struct _GstFFMpegDecClass GstFFMpegDecClass;
@@ -310,6 +315,9 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
   ffmpegdec->format.video.fps_n = -1;
   ffmpegdec->format.video.old_fps_n = -1;
   gst_segment_init (&ffmpegdec->segment, GST_FORMAT_TIME);
+
+  ffmpegdec->tstamp1 = ffmpegdec->tstamp2 = GST_CLOCK_TIME_NONE;
+  ffmpegdec->dur1 = ffmpegdec->dur2 = GST_CLOCK_TIME_NONE;
 }
 
 static void
@@ -522,6 +530,11 @@ gst_ffmpegdec_open (GstFFMpegDec * ffmpegdec)
     default:
       break;
   }
+
+  /* out-of-order incoming buffer handling */
+  if ((oclass->in_plugin->id == CODEC_ID_H264) && (ffmpegdec->context->extradata_size != 0))
+    ffmpegdec->outoforder = TRUE;
+
   ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
   ffmpegdec->last_buffer = NULL;
   /* FIXME, reset_qos holds the LOCK */
@@ -826,6 +839,64 @@ no_par:
   }
 }
 
+static void
+gst_ffmpegdec_save_incoming_values (GstFFMpegDec * ffmpegdec, GstClockTime timestamp,
+                                   GstClockTime duration)
+{
+  GST_LOG_OBJECT (ffmpegdec, "BEFORE timestamp:%"GST_TIME_FORMAT"/%"GST_TIME_FORMAT
+                 " duration:%"GST_TIME_FORMAT"/%"GST_TIME_FORMAT,
+                 GST_TIME_ARGS (ffmpegdec->tstamp1), GST_TIME_ARGS (ffmpegdec->tstamp2),
+                 GST_TIME_ARGS (ffmpegdec->dur1), GST_TIME_ARGS (ffmpegdec->dur2));
+
+  /* shift previous new values to oldest */
+  if (ffmpegdec->tstamp2 != GST_CLOCK_TIME_NONE)
+    ffmpegdec->tstamp1 = ffmpegdec->tstamp2;
+  ffmpegdec->dur1 = ffmpegdec->dur2;
+
+  /* store new values */
+  ffmpegdec->tstamp2 = timestamp;
+  ffmpegdec->dur2 = duration;
+
+  GST_LOG_OBJECT (ffmpegdec, "AFTER timestamp:%"GST_TIME_FORMAT"/%"GST_TIME_FORMAT
+                 " duration:%"GST_TIME_FORMAT"/%"GST_TIME_FORMAT,
+                 GST_TIME_ARGS (ffmpegdec->tstamp1), GST_TIME_ARGS (ffmpegdec->tstamp2),
+                 GST_TIME_ARGS (ffmpegdec->dur1), GST_TIME_ARGS (ffmpegdec->dur2));
+
+}
+
+static void
+gst_ffmpegdec_get_best_values (GstFFMpegDec * ffmpegdec, GstClockTime *timestamp,
+                              GstClockTime *duration)
+{
+  /* Best timestamp is the smallest valid timestamp */
+  if (ffmpegdec->tstamp1 == GST_CLOCK_TIME_NONE) {
+    *timestamp = ffmpegdec->tstamp2;
+    ffmpegdec->tstamp2 = GST_CLOCK_TIME_NONE;
+  } else if (ffmpegdec->tstamp2 == GST_CLOCK_TIME_NONE) {
+    *timestamp = ffmpegdec->tstamp1;
+    ffmpegdec->tstamp1 = GST_CLOCK_TIME_NONE;
+  } else if (ffmpegdec->tstamp1 < ffmpegdec->tstamp2) {
+    *timestamp = ffmpegdec->tstamp1;
+    ffmpegdec->tstamp1 = GST_CLOCK_TIME_NONE;
+  } else {
+    *timestamp = ffmpegdec->tstamp2;
+    ffmpegdec->tstamp2 = GST_CLOCK_TIME_NONE;
+  }
+
+  /* Best duration is the oldest valid one */
+  if (ffmpegdec->dur1 == GST_CLOCK_TIME_NONE) {
+    *duration = ffmpegdec->dur2;
+    ffmpegdec->dur2 = GST_CLOCK_TIME_NONE;
+  } else {
+    *duration = ffmpegdec->dur1;
+    ffmpegdec->dur1 = GST_CLOCK_TIME_NONE;
+  }
+
+  GST_LOG_OBJECT (ffmpegdec, "Returning timestamp:%"GST_TIME_FORMAT" duration:%"GST_TIME_FORMAT,
+                 GST_TIME_ARGS (*timestamp),
+                 GST_TIME_ARGS (*duration));
+}
+
 static gboolean
 gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
 {
@@ -1222,6 +1293,10 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
 
   ffmpegdec->context->opaque = ffmpegdec;
 
+  /* incoming out-of-order buffer timestamp buffering */
+  if (ffmpegdec->outoforder)
+    gst_ffmpegdec_save_incoming_values (ffmpegdec, in_timestamp, in_duration);
+
   /* run QoS code, returns FALSE if we can skip decoding this
    * frame entirely. */
   if (G_UNLIKELY (!gst_ffmpegdec_do_qos (ffmpegdec, in_timestamp,
@@ -1272,6 +1347,10 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
   if (G_UNLIKELY (*ret != GST_FLOW_OK))
     goto no_output;
 
+  /* Special handling for out-of-order incoming buffers */
+  if (ffmpegdec->outoforder)
+    gst_ffmpegdec_get_best_values (ffmpegdec, &in_timestamp, &in_duration);
+
   /*
    * Timestamps:
    *
@@ -1707,6 +1786,8 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
       gst_ffmpegdec_flush_pcache (ffmpegdec);
       ffmpegdec->waiting_for_key = TRUE;
       gst_segment_init (&ffmpegdec->segment, GST_FORMAT_TIME);
+      ffmpegdec->tstamp1 = ffmpegdec->tstamp2 = GST_CLOCK_TIME_NONE;
+      ffmpegdec->dur1 = ffmpegdec->dur2 = GST_CLOCK_TIME_NONE;
       break;
     }
     case GST_EVENT_NEWSEGMENT:{