]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blobdiff - src/gstducatih264dec.c
Realigned code on new Ducati header files
[glsdk/gst-plugin-ducati.git] / src / gstducatih264dec.c
index fedb46fe6bd93a66ef5cff2d44a53a66107e8650..05e1c94d491376ac94347b1e06325e441a064ce0 100644 (file)
@@ -34,6 +34,7 @@
 #  include <config.h>
 #endif
 
+#include <math.h>
 #include "gstducatih264dec.h"
 
 
 #define PADX  32
 #define PADY  24
 
+/* This structure is not public, this should be replaced by
+   sizeof(sErrConcealLayerStr) when it is made so. */
+#define SIZE_OF_CONCEALMENT_DATA 65536
+
 
 GST_BOILERPLATE (GstDucatiH264Dec, gst_ducati_h264dec, GstDucatiVidDec,
     GST_TYPE_DUCATIVIDDEC);
 
+/* *INDENT-OFF* */
 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("video/x-h264, "
         "stream-format = byte-stream, "   /* only byte-stream */
-        "align = au, "          /* only entire frames */
+        "alignment = au, "          /* only entire frames */
         "width = (int)[ 16, 2048 ], "
         "height = (int)[ 16, 2048 ], "
         "framerate = (fraction)[ 0, max ],"
         "profile = (string){constrained-baseline, baseline, main, extended};"
         "video/x-h264, "
         "stream-format = byte-stream, "   /* only byte-stream */
-        "align = au, "          /* only entire frames */
+        "alignment = au, "          /* only entire frames */
         "width = (int)[ 16, 2048 ], "
         "height = (int)[ 16, 2048 ], "
         "framerate = (fraction)[ 0, max ],"
         "profile = (string) {high, high-10-intra, high-10, high-4:2:2-intra, "
         "high-4:2:2, high-4:4:4-intra, high-4:4:4, cavlc-4:4:4-intra}, "
-        "level = (string) {1, 1b, 1.1, 1.2, 1.3, 2, 2.1, 2.2, 3, 3.1, 3.2, 4, 4.1, 4.2};"
-        )
+        "level = (string) {1, 1b, 1.1, 1.2, 1.3, 2, 2.1, 2.2, 3, 3.1, 3.2, 4, 4.1, 4.2, 5.1};")
     );
 
+static const struct
+{
+  const char *level;
+  gint kb;
+} max_dpb_by_level[] = {
+  { "1", 149 },
+  { "1b", 149 }, /* That one's not in the spec ?? */
+  { "1.1", 338 },
+  { "1.2", 891 },
+  { "1.3", 891 },
+  { "2", 891 },
+  { "2.1", 1782 },
+  { "2.2", 3038 },
+  { "3", 3038 },
+  { "3.1", 6750 },
+  { "3.2", 7680 },
+  { "4", 12288 },
+  { "4.1", 12288 },
+  { "4.2", 12288 },
+  { "5", 41400 },
+  { "5.1", 69120 },
+};
+/* *INDENT-ON* */
+
 /* GstDucatiVidDec vmethod implementations */
 
 static void
@@ -92,12 +121,32 @@ gst_ducati_h264dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
 
   if (ret) {
     IH264VDEC_Params *params = (IH264VDEC_Params *) self->params;
-    self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_1;
-    params->maxNumRefFrames = IH264VDEC_NUM_REFFRAMES_AUTO;
+
+    self->params->displayDelay = IVIDDEC3_DECODE_ORDER;
+    params->dpbSizeInFrames = IH264VDEC_DPB_NUMFRAMES_AUTO;
     params->pConstantMemory = 0;
     params->presetLevelIdc = IH264VDEC_LEVEL41;
     params->errConcealmentMode = IH264VDEC_APPLY_CONCEALMENT;
     params->temporalDirModePred = TRUE;
+
+    if (self->codec_debug_info) {
+      /* We must allocate a byte per MB, plus the size of some struture which
+         is not public. Place this in the first metadata buffer slot, and ask
+         for MBINFO metadata for it. */
+      GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
+      unsigned mbw = (self->width + 15) / 16;
+      unsigned mbh = (self->height + 15) / 16;
+      unsigned nmb = mbw * mbh;
+
+      h264dec->bo_mberror =
+          omap_bo_new (self->device, nmb + SIZE_OF_CONCEALMENT_DATA,
+          OMAP_BO_WC);
+      self->outBufs->descs[2].memType = XDM_MEMTYPE_BO;
+      self->outBufs->descs[2].buf =
+          (XDAS_Int8 *) omap_bo_handle (h264dec->bo_mberror);
+      self->outBufs->descs[2].bufSize.bytes = nmb + SIZE_OF_CONCEALMENT_DATA;
+      self->params->metadataType[0] = IVIDEO_METADATAPLANE_MBINFO;
+    }
   }
 
   return ret;
@@ -107,16 +156,56 @@ static gint
 gst_ducati_h264dec_handle_error (GstDucatiVidDec * self, gint ret,
     gint extended_error, gint status_extended_error)
 {
+  GstDucatiH264Dec *h264dec = GST_DUCATIH264DEC (self);
+  const unsigned char *mberror, *mbcon;
+  unsigned mbw, mbh, nmb;
+  uint16_t mbwr, mbhr;
+  size_t n, nerr = 0;
+  char *line;
+  unsigned x, y;
+
+  if (h264dec->bo_mberror) {
+    mberror = omap_bo_map (h264dec->bo_mberror);
+    mbw = (self->width + 15) / 16;
+    mbh = (self->height + 15) / 16;
+    nmb = mbw * mbh;
+    mbcon = mberror + nmb;
+    mbwr = ((const uint16_t *) mbcon)[21];      /* not a public struct */
+    mbhr = ((const uint16_t *) mbcon)[22];      /* not a public struct */
+    if (nmb != mbwr * mbhr) {
+      GST_WARNING_OBJECT (self, "Failed to find MB size - "
+          "corruption might have happened");
+    } else {
+      for (n = 0; n < nmb; ++n) {
+        if (mberror[n])
+          ++nerr;
+      }
+      GST_INFO_OBJECT (self, "Frame has %zu MB errors over %zu (%u x %u) MBs",
+          nerr, nmb, mbwr, mbhr);
+      line = g_malloc (mbw + 1);
+      for (y = 0; y < mbh; y++) {
+        line[mbw] = 0;
+        for (x = 0; x < mbw; x++) {
+          line[x] = mberror[x + y * mbw] ? '!' : '.';
+        }
+        GST_INFO_OBJECT (self, "MB: %4u: %s", y, line);
+      }
+      g_free (line);
+    }
+  }
+
   if (extended_error & 0x00000001) {
     /* No valid slice. This seems to be bad enough that it's better to flush and
      * skip to the next keyframe.
      */
 
-    /* the codec doesn't unlock the input buffer in this case... */
-    gst_buffer_unref ((GstBuffer *) self->inArgs->inputID);
-    self->inArgs->inputID = 0;
+    if (extended_error == 0x00000201) {
+      /* the codec doesn't unlock the input buffer in this case... */
+      gst_buffer_unref ((GstBuffer *) self->inArgs->inputID);
+      self->inArgs->inputID = 0;
+    }
 
-    gst_ducati_viddec_codec_flush (self, FALSE);
+    self->needs_flushing = TRUE;
   }
 
   ret = parent_class->handle_error (self, ret, extended_error,
@@ -129,7 +218,7 @@ static gboolean
 gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
     GstQuery * query, gboolean * forward)
 {
-  GstDucatiH264Dec * self = GST_DUCATIH264DEC (vdec);
+  GstDucatiH264Dec *self = GST_DUCATIH264DEC (vdec);
   gboolean res = TRUE;
 
   switch (GST_QUERY_TYPE (query)) {
@@ -146,11 +235,13 @@ gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
 
       gst_query_parse_latency (query, &live, &min, &max);
       if (vdec->fps_n != 0)
-        latency = gst_util_uint64_scale (GST_SECOND,
-            vdec->fps_d, vdec->fps_n);
+        latency = gst_util_uint64_scale (GST_SECOND, vdec->fps_d, vdec->fps_n);
       else
         latency = 0;
 
+      /* Take into account the backlog frames for reordering */
+      latency *= (vdec->backlog_maxframes + 1);
+
       if (min == GST_CLOCK_TIME_NONE)
         min = latency;
       else
@@ -159,7 +250,8 @@ gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
       if (max != GST_CLOCK_TIME_NONE)
         max += latency;
 
-      GST_INFO_OBJECT (self, "latency %"GST_TIME_FORMAT " ours %"GST_TIME_FORMAT,
+      GST_INFO_OBJECT (self,
+          "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
           GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
       gst_query_set_latency (query, live, min, max);
       break;
@@ -175,7 +267,7 @@ gst_ducati_h264dec_query (GstDucatiVidDec * vdec, GstPad * pad,
 }
 
 static gboolean
-gst_ducati_h264dec_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
+gst_ducati_h264dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
     gint64 diff)
 {
   gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf,
@@ -187,6 +279,148 @@ gst_ducati_h264dec_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
   return FALSE;
 }
 
+static gint
+gst_ducati_h264dec_find_max_dpb_from_level (GstDucatiVidDec * self,
+    const char *level)
+{
+  guint n;
+
+  for (n = 0; n < G_N_ELEMENTS (max_dpb_by_level); ++n)
+    if (!strcmp (level, max_dpb_by_level[n].level))
+      return max_dpb_by_level[n].kb;
+
+  GST_WARNING_OBJECT (self, "Max DBP not found for level %s", level);
+  return -1;
+}
+
+static gint
+gst_ducati_h264dec_get_max_dpb_size (GstDucatiVidDec * self, GstCaps * caps)
+{
+  gint wmb = (self->width + 15) / 16;
+  gint hmb = (self->height + 15) / 16;
+  gint max_dpb, max_dpb_size;
+  GstStructure *structure;
+  const char *level;
+  float chroma_factor = 1.5;    /* We only support NV12, which is 4:2:0 */
+
+  /* Min( 1024 * MaxDPB / ( PicWidthInMbs * FrameHeightInMbs * 256 * ChromaFormatFactor ), 16 ) */
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!structure)
+    return -1;
+
+  level = gst_structure_get_string (structure, "level");
+  if (!level)
+    return -1;
+
+  max_dpb = gst_ducati_h264dec_find_max_dpb_from_level (self, level);
+  if (max_dpb < 0)
+    return -1;
+
+  max_dpb_size =
+      lrint (ceil (1024 * max_dpb / (wmb * hmb * 256 * chroma_factor)));
+  if (max_dpb_size > MAX_BACKLOG_FRAMES)
+    max_dpb_size = MAX_BACKLOG_FRAMES;
+
+  return max_dpb_size;
+}
+
+static gboolean
+gst_ducati_h264dec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
+{
+  GstStructure *structure;
+
+  GST_DEBUG_OBJECT (self, "set_sink_caps: %" GST_PTR_FORMAT, caps);
+
+  if (!GST_CALL_PARENT_WITH_DEFAULT (GST_DUCATIVIDDEC_CLASS, set_sink_caps,
+          (self, caps), TRUE))
+    return FALSE;
+
+  /* HW decoder fails in GETSTATUS */
+#if 0
+  /* When we have the first decoded buffer, we ask the decoder for the
+     max number of frames needed to reorder */
+  int err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
+      self->dynParams, self->status);
+  if (!err) {
+    IH264VDEC_Status *s = (IH264VDEC_Status *) self->status;
+    if (s->spsMaxRefFrames > MAX_BACKLOG_FRAMES) {
+      h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
+      GST_WARNING_OBJECT (self,
+          "Stream needs %d frames for reordering, we can only accomodate %d",
+          s->spsMaxRefFrames, MAX_BACKLOG_FRAMES);
+    } else {
+      h264dec->backlog_maxframes = s->spsMaxRefFrames;
+      GST_INFO_OBJECT (self, "Num frames for reordering: %d",
+          h264dec->backlog_maxframes);
+    }
+  } else {
+    h264dec->backlog_maxframes = MAX_BACKLOG_FRAMES;
+    GST_WARNING_OBJECT (self,
+        "Failed to request num frames for reordering, defaulting to %d",
+        h264dec->backlog_maxframes);
+  }
+#endif
+
+  self->backlog_maxframes = -1;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (structure) {
+    gint num_ref_frames = -1, num_reorder_frames = -1;
+    const char *profile;
+
+    /* baseline profile does not use B frames (and I'll say constrained-baseline
+       is unlikely either from the name, it's not present in my H264 spec... */
+    profile = gst_structure_get_string (structure, "profile");
+    if (profile && (!strcmp (profile, "baseline")
+            || !strcmp (profile, "constrained-baseline"))) {
+      GST_DEBUG_OBJECT (self, "No need for reordering for %s profile", profile);
+      self->backlog_maxframes = 0;
+      goto no_b_frames;
+    }
+
+
+    if (gst_structure_get_int (structure, "num-ref-frames", &num_ref_frames)
+        && num_ref_frames >= 0) {
+      ((IH264VDEC_Params *) self->params)->dpbSizeInFrames = num_ref_frames;
+    }
+    if (gst_structure_get_int (structure, "num-reorder-frames",
+            &num_reorder_frames)
+        && num_reorder_frames >= 0) {
+      if (num_reorder_frames > 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 {
+        self->backlog_maxframes = num_reorder_frames;
+        GST_INFO_OBJECT (self, "Num frames for reordering: %d",
+            self->backlog_maxframes);
+      }
+    }
+  }
+
+  /* If not present, use the spec forumula for a bound */
+  if (self->backlog_maxframes < 0) {
+    self->backlog_maxframes = gst_ducati_h264dec_get_max_dpb_size (self, caps);
+    if (self->backlog_maxframes >= 0) {
+      GST_WARNING_OBJECT (self,
+          "num-reorder-frames not found on caps, calculation from stream parameters gives %d",
+          self->backlog_maxframes);
+    } else {
+      self->backlog_maxframes = MAX_H264_BACKLOG_FRAMES;
+    }
+  }
+  if (self->backlog_maxframes > self->backlog_max_maxframes)
+    self->backlog_maxframes = self->backlog_max_maxframes;
+  GST_WARNING_OBJECT (self,
+      "Using %d frames for reordering", self->backlog_maxframes);
+
+no_b_frames:
+
+  return TRUE;
+}
+
 /* GObject vmethod implementations */
 
 static void
@@ -204,22 +438,63 @@ gst_ducati_h264dec_base_init (gpointer gclass)
       gst_static_pad_template_get (&sink_factory));
 }
 
+static void
+gst_ducati_h264dec_finalize (GObject * obj)
+{
+  GstDucatiH264Dec *self = GST_DUCATIH264DEC (obj);
+  if (self->bo_mberror)
+    omap_bo_del (self->bo_mberror);
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
 static void
 gst_ducati_h264dec_class_init (GstDucatiH264DecClass * klass)
 {
   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   bclass->codec_name = "ivahd_h264dec";
   bclass->update_buffer_size =
       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_update_buffer_size);
   bclass->allocate_params =
       GST_DEBUG_FUNCPTR (gst_ducati_h264dec_allocate_params);
   bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_handle_error);
-  bclass->drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_drop_frame);
+  bclass->can_drop_frame =
+      GST_DEBUG_FUNCPTR (gst_ducati_h264dec_can_drop_frame);
   bclass->query = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_query);
+  bclass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_set_sink_caps);
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_h264dec_finalize);
 }
 
 static void
 gst_ducati_h264dec_init (GstDucatiH264Dec * self,
     GstDucatiH264DecClass * gclass)
 {
+#ifndef GST_DISABLE_GST_DEBUG
+  GstDucatiVidDec *dec = GST_DUCATIVIDDEC (self);
+
+  dec->error_strings[0] = "no error-free slice";
+  dec->error_strings[1] = "error parsing SPS";
+  dec->error_strings[2] = "error parsing PPS";
+  dec->error_strings[3] = "error parsing slice header";
+  dec->error_strings[4] = "error parsing MB data";
+  dec->error_strings[5] = "unknown SPS";
+  dec->error_strings[6] = "unknown PPS";
+  dec->error_strings[7] = "invalid parameter";
+  dec->error_strings[16] = "unsupported feature";
+  dec->error_strings[17] = "SEI buffer overflow";
+  dec->error_strings[18] = "stream end";
+  dec->error_strings[19] = "no free buffers";
+  dec->error_strings[20] = "resolution change";
+  dec->error_strings[21] = "unsupported resolution";
+  dec->error_strings[22] = "invalid maxNumRefFrames";
+  dec->error_strings[23] = "invalid mbox message";
+  dec->error_strings[24] = "bad datasync input";
+  dec->error_strings[25] = "missing slice";
+  dec->error_strings[26] = "bad datasync param";
+  dec->error_strings[27] = "bad hw state";
+  dec->error_strings[28] = "temporal direct mode";
+  dec->error_strings[29] = "display width too small";
+  dec->error_strings[30] = "no SPS/PPS header";
+  dec->error_strings[31] = "gap in frame num";
+#endif
 }