vc1dec: add VC-1 Advanced, Main, and Simple profile support
[glsdk/gst-plugin-ducati.git] / src / gstducatividdec.c
index 36e9b8e92466bc725052a79f33c4f5e7c52a2c88..53bc94cfd7a17325e36856478692b5eb7bb4baba 100644 (file)
@@ -148,7 +148,7 @@ codec_create (GstDucatiVidDec * self)
     return FALSE;
   }
 
-  err = VIDDEC3_control(self->codec, XDM_SETPARAMS, self->dynParams, self->status);
+  err = VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams, self->status);
   if (err) {
     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
     return FALSE;
@@ -163,7 +163,8 @@ codec_create (GstDucatiVidDec * self)
   }
 #endif
 
-  self->first_buffer = TRUE;
+  self->first_in_buffer = TRUE;
+  self->first_out_buffer = TRUE;
 
   /* allocate input buffer and initialize inBufs: */
   self->inBufs->numBufs = 1;
@@ -211,8 +212,8 @@ codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer * buf)
     // TODO
   }
 
-  self->outBufs->descs[0].buf = (XDAS_Int8 *)y_paddr;
-  self->outBufs->descs[1].buf = (XDAS_Int8 *)uv_paddr;
+  self->outBufs->descs[0].buf = (XDAS_Int8 *) y_paddr;
+  self->outBufs->descs[1].buf = (XDAS_Int8 *) uv_paddr;
 
   return (XDAS_Int32) buf;      // XXX use lookup table
 }
@@ -236,21 +237,109 @@ codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
   }
 }
 
+static gint
+codec_process (GstDucatiVidDec * self, gboolean send)
+{
+  gint err;
+  GstClockTime t;
+  GstBuffer *outbuf = NULL;
+  gint i;
+
+  t = gst_util_get_timestamp ();
+  err = VIDDEC3_process (self->codec,
+      self->inBufs, self->outBufs, self->inArgs, self->outArgs);
+  GST_INFO_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
+  if (err) {
+    return err;
+  }
+
+  for (i = 0; self->outArgs->outputID[i]; i++) {
+    if (G_UNLIKELY (self->first_out_buffer) && send) {
+      /* send region of interest to sink on first buffer: */
+      XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
+
+      gst_pad_push_event (self->srcpad,
+          gst_event_new_crop (r->topLeft.y, r->topLeft.x,
+              r->bottomRight.x - r->topLeft.x,
+              r->bottomRight.y - r->topLeft.y));
+
+      self->first_out_buffer = FALSE;
+    }
+
+    outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
+    if (send) {
+      gst_pad_push (self->srcpad, outbuf);
+    } else {
+      gst_buffer_unref (outbuf);
+    }
+  }
+
+  for (i = 0; self->outArgs->freeBufID[i]; i++) {
+    codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
+  }
+
+  return err;
+}
+
+/** call control(FLUSH), and then process() to pop out all buffers */
 static gboolean
-codec_flush (GstDucatiVidDec * self)
+codec_flush (GstDucatiVidDec * self, gboolean eos)
 {
+  gint err;
+
+  GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
+
+  if (G_UNLIKELY (self->first_in_buffer)) {
+    return TRUE;
+  }
+
   if (G_UNLIKELY (!self->codec)) {
     GST_WARNING_OBJECT (self, "no codec");
     return TRUE;
   }
 
-  GST_WARNING_OBJECT (self, "TODO");
+  err = VIDDEC3_control (self->codec, XDM_FLUSH,
+      self->dynParams, self->status);
+  if (err) {
+    GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
+    return FALSE;
+  }
 
-  return FALSE;
+  do {
+    err = codec_process (self, eos);
+  } while (err != XDM_EFAIL);
+
+  self->first_in_buffer = TRUE;
+
+  GST_DEBUG_OBJECT (self, "done");
+
+  return TRUE;
 }
 
 /* GstDucatiVidDec vmethod default implementations */
 
+static gboolean
+gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
+{
+  const GValue *codec_data;
+
+  if (gst_structure_get_int (s, "width", &self->width) &&
+      gst_structure_get_int (s, "height", &self->height)) {
+
+    const GValue *codec_data = gst_structure_get_value (s, "codec_data");
+
+    if (codec_data) {
+      GstBuffer *buffer = gst_value_get_buffer (codec_data);
+      GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
+      self->codec_data = gst_buffer_ref (buffer);
+    }
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
 static gboolean
 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
@@ -263,23 +352,14 @@ gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
   }
   self->params->size = params_sz;
   self->params->maxFrameRate = 30000;
-  //h264, mpeg4:
-  //note mpeg4 and h263 are same..
   self->params->maxBitRate = 10000000;
-  //vc1:
-  //self->params->maxBitRate = 45000000;
+
+  //vc6/vc7/rv??
 
   self->params->dataEndianness = XDM_BYTE;
   self->params->forceChromaFormat = XDM_YUV_420SP;
   self->params->operatingMode = IVIDEO_DECODE_ONLY;
 
-  //mpeg4:
-  //self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_1;
-
-  //vc1:
-  //self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_1;
-
-
   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
@@ -295,12 +375,6 @@ gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
 
-  //mpeg4:
-  //((IMPEG4VDEC_Params *) self->params)->outloopDeBlocking = 0;
-  //((IMPEG4VDEC_Params *) self->params)->sorensonSparkStream = 0;
-  //((IMPEG4VDEC_Params *) self->params)->ErrorConcealmentON = 1;
-
-
   /* allocate dynParams: */
   self->dynParams = dce_alloc (dynparams_sz);
   if (G_UNLIKELY (!self->dynParams)) {
@@ -312,9 +386,6 @@ gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
   self->dynParams->newFrameFlag = XDAS_TRUE;
 
-  //mpeg4:
-  //self->dynParams->lateAcquireArg = IRES_HDVICP2_UNKNOWNLATEACQUIREARG;
-
   /* allocate status: */
   self->status = dce_alloc (status_sz);
   if (G_UNLIKELY (!self->status)) {
@@ -342,12 +413,15 @@ gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
 static GstBuffer *
 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
 {
+  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));
+  }
+
   /* just copy entire buffer */
-  self->inArgs->numBytes = GST_BUFFER_SIZE (buf);
-  self->inBufs->descs[0].bufSize.bytes = self->inArgs->numBytes;
-  GST_DEBUG_OBJECT (self, "push: %d bytes)", self->inArgs->numBytes);
-  memcpy (self->input, GST_BUFFER_DATA (buf), self->inArgs->numBytes);
+  push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
   gst_buffer_unref (buf);
+
   return NULL;
 }
 
@@ -358,6 +432,7 @@ gst_ducati_viddec_set_caps (GstPad * pad, GstCaps * caps)
 {
   gboolean ret = TRUE;
   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
+  GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
   GstStructure *s;
 
   g_return_val_if_fail (caps, FALSE);
@@ -366,24 +441,19 @@ gst_ducati_viddec_set_caps (GstPad * pad, GstCaps * caps)
   s = gst_caps_get_structure (caps, 0);
 
   if (pad == self->sinkpad) {
-    gint width, height, frn, frd;
+    gint frn = 0, frd = 1;
     GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
 
-    if (gst_structure_get_int (s, "width", &width) &&
-        gst_structure_get_int (s, "height", &height) &&
-        gst_structure_get_fraction (s, "framerate", &frn, &frd)) {
+    if (klass->parse_caps (self, s)) {
       GstCaps *outcaps;
 
-      /* ok, these caps seem sane.. grab the required values and construct
-       * appropriate output caps
-       */
-      self->width = width;
-      self->height = height;
+      gst_structure_get_fraction (s, "framerate", &frn, &frd);
+
       self->stride = 4096;      /* TODO: don't hardcode */
 
       /* update output/padded sizes:
        */
-      GST_DUCATIVIDDEC_GET_CLASS (self)->update_buffer_size (self);
+      klass->update_buffer_size (self);
 
       self->outsize =
           GST_ROUND_UP_2 (self->stride * self->padded_height * 3) / 2;
@@ -447,7 +517,6 @@ gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
   GstFlowReturn ret;
   Int32 err;
-  gint i;
   GstBuffer *outbuf = NULL;
 
   if (G_UNLIKELY (!self->engine)) {
@@ -465,7 +534,6 @@ gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
     /* TODO: if we had our own buffer class, we could allocate our own
      * output buffer from TILER...
      */
- GST_WARNING_OBJECT (self, "ret=%d", ret);
     GST_WARNING_OBJECT (self, "TODO: allocate output TILER buffer");
     return ret;
   }
@@ -480,13 +548,17 @@ gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
 
+  /* pass new output buffer as to the decoder to decode into: */
   self->inArgs->inputID = codec_prepare_outbuf (self, outbuf);
   if (!self->inArgs->inputID) {
     GST_ERROR_OBJECT (self, "could not prepare output buffer");
     return GST_FLOW_ERROR;
   }
 
+  self->in_size = 0;
   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
+  self->inArgs->numBytes = self->in_size;
+  self->inBufs->descs[0].bufSize.bytes = self->in_size;
 
   if (buf) {
     // XXX
@@ -495,38 +567,14 @@ gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
     buf = NULL;
   }
 
-  //XXX t = mark (NULL);
-  err = VIDDEC3_process (self->codec,
-      self->inBufs, self->outBufs,
-      self->inArgs, self->outArgs);
-  //XXX GST_DEBUG_OBJECT (self, "processed returned in: %dus", mark (&t));
+  err = codec_process (self, TRUE);
   if (err) {
     GST_ERROR_OBJECT (self, "process returned error: %d %08x",
         err, self->outArgs->extendedError);
     return GST_FLOW_ERROR;
   }
 
-  for (i = 0; self->outArgs->outputID[i]; i++) {
-    if (G_UNLIKELY (self->first_buffer)) {
-      /* send region of interest to sink on first buffer: */
-      XDM_Rect *r =
-          &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
-
-      gst_pad_push_event (self->srcpad,
-          gst_event_new_crop (r->topLeft.y, r->topLeft.x,
-              r->bottomRight.x - r->topLeft.x,
-              r->bottomRight.y - r->topLeft.y));
-
-      self->first_buffer = FALSE;
-    }
-
-    outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
-    gst_pad_push (self->srcpad, outbuf);
-  }
-
-  for (i = 0; self->outArgs->freeBufID[i]; i++) {
-    codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
-  }
+  self->first_in_buffer = FALSE;
 
   if (self->outArgs->outBufsInUseFlag) {
     GST_WARNING_OBJECT (self, "TODO... outBufsInUseFlag");      // XXX
@@ -540,13 +588,16 @@ gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
 {
   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
   gboolean ret = TRUE;
+  gboolean eos = FALSE;
 
   GST_INFO_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_EOS:
+      eos = TRUE;
+      /* fall-through */
     case GST_EVENT_FLUSH_STOP:
-      if (!codec_flush (self)) {
+      if (!codec_flush (self, eos)) {
         GST_ERROR_OBJECT (self, "could not flush");
         return FALSE;
       }
@@ -613,6 +664,11 @@ gst_ducati_viddec_finalize (GObject * obj)
   codec_delete (self);
   engine_close (self);
 
+  if (self->codec_data) {
+      gst_buffer_unref (self->codec_data);
+      self->codec_data = NULL;
+  }
+
   G_OBJECT_CLASS (parent_class)->finalize (obj);
 }
 
@@ -634,6 +690,8 @@ gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
   gobject_class->finalize = gst_ducati_viddec_finalize;
   gstelement_class->change_state = gst_ducati_viddec_change_state;
 
+  klass->parse_caps =
+      GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
   klass->allocate_params =
       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
   klass->push_input =