ducatividdec: move frame reordering to the base class
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Mon, 15 Oct 2012 11:47:34 +0000 (12:47 +0100)
committerVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Mon, 15 Oct 2012 11:47:34 +0000 (12:47 +0100)
It was made for H264, but MPEG2 is going to need it as well.
When reordering is enabled, the buffer end offset is used as
an opaque value to compare buffer. H264 sets it to the POC,
but it may be set to a timestamp, or anything else.

src/gstducatih264dec.c
src/gstducatih264dec.h
src/gstducatividdec.c
src/gstducatividdec.h

index 9b553505bcf599c3eee66ef2359767fdb43807e1..561b2f07be47871e57cfb8e22c6c5a6edec036ea 100644 (file)
@@ -179,7 +179,7 @@ gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
         latency = 0;
 
       /* Take into account the backlog frames for reordering */
-      latency *= (self->backlog_maxframes + 1);
+      latency *= (vdec->backlog_maxframes + 1);
 
       if (min == GST_CLOCK_TIME_NONE)
         min = latency;
@@ -267,7 +267,6 @@ gst_ducati_h264dec_get_max_dpb_size (GstDucatiVidDec * self, GstCaps * caps)
 static gboolean
 gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
 {
-  GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
   GstStructure *structure;
 
   GST_DEBUG_OBJECT (self, "set_sink_caps: %" GST_PTR_FORMAT, caps);
@@ -302,7 +301,7 @@ gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
   }
 #endif
 
-  h264dec->backlog_maxframes = -1;
+  self->backlog_maxframes = -1;
 
   structure = gst_caps_get_structure (caps, 0);
   if (structure) {
@@ -315,113 +314,29 @@ gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
             &num_reorder_frames)
         && num_reorder_frames >= 0) {
       if (num_reorder_frames > MAX_BACKLOG_FRAMES) {
-        h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
+        self->backlog_maxframes = MAX_BACKLOG_FRAMES;
         GST_WARNING_OBJECT (self,
             "Stream needs %d frames for reordering, we can only accomodate %d",
             num_reorder_frames, MAX_BACKLOG_FRAMES);
       } else {
-        h264dec->backlog_maxframes = num_reorder_frames;
+        self->backlog_maxframes = num_reorder_frames;
         GST_INFO_OBJECT (self, "Num frames for reordering: %d",
-            h264dec->backlog_maxframes);
+            self->backlog_maxframes);
       }
     }
   }
 
   /* If not present, use the spec forumula for a bound */
-  if (h264dec->backlog_maxframes < 0) {
-    h264dec->backlog_maxframes =
-        gst_ducati_h264dec_get_max_dpb_size (self, caps);
+  if (self->backlog_maxframes < 0) {
+    self->backlog_maxframes = gst_ducati_h264dec_get_max_dpb_size (self, caps);
     GST_WARNING_OBJECT (self,
         "num-reorder-frames not found on caps, defaulting to %d",
-        h264dec->backlog_maxframes);
+        self->backlog_maxframes);
   }
 
   return TRUE;
 }
 
-/* The following few functions reorder buffers by "picture order
-   count", which is passed through OFFSET_END by h264parse.
- */
-
-static GstFlowReturn
-gst_ducati_h264dec_push_earliest (GstDucatiH264Dec * self)
-{
-  guint64 earliest_poc = G_MAXUINT64;
-  guint earliest_index = 0, i;
-  GstBuffer *buf;
-
-  if (self->backlog_nframes == 0)
-    return GST_FLOW_OK;
-
-  /* work out which frame has the earliest poc */
-  for (i = 0; i < self->backlog_nframes; i++) {
-    guint64 poc = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
-    if (earliest_poc == G_MAXUINT64 || poc < earliest_poc) {
-      earliest_poc = poc;
-      earliest_index = i;
-    }
-  }
-
-  /* send it, giving away the ref */
-  buf = self->backlog_frames[earliest_index];
-  self->backlog_frames[earliest_index] =
-      self->backlog_frames[--self->backlog_nframes];
-  GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
-      buf);
-  return gst_pad_push (GST_DUCATIVIDDEC (self)->srcpad, buf);
-}
-
-static GstBuffer *
-gst_ducati_h264dec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
-{
-  GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
-
-  /* If we're about to push an IDR frame, then we can flush all the frames
-     we currently have queued. This is necessary as picture order count
-     is local to each IDR + set of non IDR frames, so will restart at 0
-     when next IDR frames comes in. */
-  if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
-    GST_DEBUG_OBJECT (self, "Got keyframe, pushing %u frames",
-        h264dec->backlog_nframes);
-    while (h264dec->backlog_nframes > 0) {
-      gst_ducati_h264dec_push_earliest (h264dec);
-    }
-  }
-
-  return parent_class->push_input (self, buf);
-}
-
-static GstFlowReturn
-gst_ducati_h264dec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
-{
-  GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
-  GstFlowReturn ret = GST_FLOW_OK;
-
-  /* add the frame to the list, the array will own the ref */
-  GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
-  h264dec->backlog_frames[h264dec->backlog_nframes++] = buf;
-
-  /* push till we have no more than the max needed, or error */
-  while (h264dec->backlog_nframes > h264dec->backlog_maxframes) {
-    ret = gst_ducati_h264dec_push_earliest (h264dec);
-    if (ret != GST_FLOW_OK)
-      break;
-  }
-
-  return ret;
-}
-
-static void
-gst_ducati_h264dec_on_flush (GstDucatiVidDec * self, gboolean eos)
-{
-  GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
-
-  /* push everything on the backlog, ignoring errors */
-  while (h264dec->backlog_nframes > 0) {
-    gst_ducati_h264dec_push_earliest (h264dec);
-  }
-}
-
 /* GObject vmethod implementations */
 
 static void
@@ -452,9 +367,6 @@ gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
   bclass->can_drop_frame =
       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
   bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
-  bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_push_input);
-  bclass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_push_output);
-  bclass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_on_flush);
   bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
 }
 
@@ -462,6 +374,4 @@ static void
 gst_ducati_h264dec_init (GstDucatiH264Dec * self,
     GstDucatiH264DecClass * gclass)
 {
-  self->backlog_maxframes = 0;
-  self->backlog_nframes = 0;
 }
index d48500876e268cb33ae8d026e1fa27f1ff1ccf18..7ca65ddca04d006e8cfeb8f9406b7fd379ec94d6 100644 (file)
@@ -37,16 +37,11 @@ typedef struct _GstDucatiH264Dec      GstDucatiH264Dec;
 typedef struct _GstDucatiH264DecClass GstDucatiH264DecClass;
 
 /* The H.264 spec has a hard limit of 16 */
-#define MAX_BACKLOG_FRAMES 16
+#define MAX_H264_BACKLOG_FRAMES 16
 
 struct _GstDucatiH264Dec
 {
   GstDucatiVidDec parent;
-
-  /* Frames waiting to be reordered */
-  GstBuffer *backlog_frames[MAX_BACKLOG_FRAMES + 1];
-  gint backlog_maxframes;
-  gint backlog_nframes;
 };
 
 struct _GstDucatiH264DecClass 
index 4bdd40b852a533caecee86b7dc1fd51e0ebe546f..ab3147dd4fb54cea58833c8dfefad6c4adf38278 100644 (file)
@@ -294,9 +294,41 @@ codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
   }
 }
 
+static GstFlowReturn
+gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
+{
+  guint64 earliest_order = G_MAXUINT64;
+  guint earliest_index = 0, i;
+  GstBuffer *buf;
+
+  if (self->backlog_nframes == 0)
+    return GST_FLOW_OK;
+
+  /* work out which frame has the earliest poc */
+  for (i = 0; i < self->backlog_nframes; i++) {
+    guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
+    if (earliest_order == G_MAXUINT64 || order < earliest_order) {
+      earliest_order = order;
+      earliest_index = i;
+    }
+  }
+
+  /* send it, giving away the ref */
+  buf = self->backlog_frames[earliest_index];
+  self->backlog_frames[earliest_index] =
+      self->backlog_frames[--self->backlog_nframes];
+  GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
+      buf);
+  return gst_pad_push (self->srcpad, buf);
+}
+
 static void
 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
 {
+  /* push everything on the backlog, ignoring errors */
+  while (self->backlog_nframes > 0) {
+    gst_ducati_viddec_push_earliest (self);
+  }
 }
 
 static gint
@@ -686,6 +718,20 @@ gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
 static GstBuffer *
 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
 {
+  /* If we're about to push a keyframe, then we can flush all the frames
+     we currently have queued. For formats such as H264, this is actually
+     necessary as picture order count is local to each IDR + set of non
+     IDR frames, so will restart at 0 when next IDR frames comes in. For
+     other formats, it is not necessary, but avoids buffering frames that
+     do not need to be. */
+  if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
+    GST_DEBUG_OBJECT (self, "Got keyframe, pushing %u frames",
+        self->backlog_nframes);
+    while (self->backlog_nframes > 0) {
+      gst_ducati_viddec_push_earliest (self);
+    }
+  }
+
   if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
     push_input (self, GST_BUFFER_DATA (self->codec_data),
         GST_BUFFER_SIZE (self->codec_data));
@@ -701,7 +747,20 @@ gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
 static GstFlowReturn
 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
 {
-  return gst_pad_push (self->srcpad, buf);
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* add the frame to the list, the array will own the ref */
+  GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
+  self->backlog_frames[self->backlog_nframes++] = buf;
+
+  /* push till we have no more than the max needed, or error */
+  while (self->backlog_nframes > self->backlog_maxframes) {
+    ret = gst_ducati_viddec_push_earliest (self);
+    if (ret != GST_FLOW_OK)
+      break;
+  }
+
+  return ret;
 }
 
 static gint
@@ -809,6 +868,9 @@ gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
 
   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
 
+  /* default to no reordering */
+  self->backlog_maxframes = 0;
+
 out:
   if (outcaps)
     gst_caps_unref (outcaps);
@@ -1466,6 +1528,9 @@ gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
   self->device = NULL;
   self->input_bo = NULL;
 
+  self->backlog_maxframes = 0;
+  self->backlog_nframes = 0;
+
   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
       NULL, (GDestroyNotify) gst_buffer_unref);
 }
index d21d8ca6adb4bf7b67af95fafff49f270745a50e..def8247a4dbad57f8f06952a60f4f968a63086b3 100644 (file)
@@ -44,6 +44,8 @@ G_BEGIN_DECLS
 typedef struct _GstDucatiVidDec      GstDucatiVidDec;
 typedef struct _GstDucatiVidDecClass GstDucatiVidDecClass;
 
+#define MAX_BACKLOG_FRAMES 16
+
 struct _GstDucatiVidDec
 {
   GstElement parent;
@@ -135,6 +137,11 @@ struct _GstDucatiVidDec
 
   XDAS_Int16 pageMemType;
   struct omap_device *device;
+
+  /* Frames waiting to be reordered */
+  GstBuffer *backlog_frames[MAX_BACKLOG_FRAMES + 1];
+  gint backlog_maxframes;
+  gint backlog_nframes;
 };
 
 struct _GstDucatiVidDecClass