vc1dec: add VC-1 Advanced, Main, and Simple profile support
authorRob Clark <rob@ti.com>
Fri, 26 Nov 2010 18:22:06 +0000 (12:22 -0600)
committerRob Clark <rob@ti.com>
Fri, 26 Nov 2010 19:34:57 +0000 (13:34 -0600)
README
src/Makefile.am
src/gstducati.c
src/gstducatih264dec.c
src/gstducatimpeg4dec.c
src/gstducativc1dec.c [new file with mode: 0644]
src/gstducativc1dec.h [new file with mode: 0644]
src/gstducatividdec.c
src/gstducatividdec.h

diff --git a/README b/README
index 38157594365617fcc7490f89fc7654659ef011c8..0a93b70c55525b35e7d255ac174e40537f75b544 100644 (file)
--- a/README
+++ b/README
@@ -14,7 +14,7 @@ was an interesting project for me to try on my free time.
 
 TODO
 ----
-+ vc1, vp6, vp7, realvideo
++ vp6, vp7, realvideo
 + fallbacks for sink elements not providing TILER buffers to decode into
 + search the code for XXX or TODO ;-)
 
index 793d921402c1bf2afd56c22df5bdb27983838c63..bd44995a2427703b559429bce2aaef648455b707 100644 (file)
@@ -2,6 +2,7 @@ plugin_LTLIBRARIES = libgstducati.la
 
 # headers we need but don't want installed
 noinst_HEADERS = \
+       gstducativc1dec.h \
        gstducatimpeg4dec.h \
        gstducatih264dec.h \
        gstducatividdec.h \
@@ -9,6 +10,7 @@ noinst_HEADERS = \
 
 # sources used to compile this plug-in
 libgstducati_la_SOURCES = \
+       gstducativc1dec.c \
        gstducatimpeg4dec.c \
        gstducatih264dec.c \
        gstducatividdec.c \
index bbe9a5c5fde9f2408a44bcce449cbe4d1f625699..7ed7e69a40ea376fbe1c4d6b05e8763da6c724b7 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "gstducatih264dec.h"
 #include "gstducatimpeg4dec.h"
+#include "gstducativc1dec.h"
 
 GST_DEBUG_CATEGORY (gst_ducati_debug);
 
@@ -33,8 +34,12 @@ plugin_init (GstPlugin * plugin)
 {
   GST_DEBUG_CATEGORY_INIT (gst_ducati_debug, "ducati", 0, "ducati");
 
+  /* TODO .. find some way to reasonably detect if the corresponding
+   * codecs are actually available..
+   */
   return gst_element_register (plugin, "ducatih264dec", GST_RANK_PRIMARY, GST_TYPE_DUCATIH264DEC) &&
-      gst_element_register (plugin, "ducatimpeg4dec", GST_RANK_PRIMARY, GST_TYPE_DUCATIMPEG4DEC);
+      gst_element_register (plugin, "ducatimpeg4dec", GST_RANK_PRIMARY, GST_TYPE_DUCATIMPEG4DEC) &&
+      gst_element_register (plugin, "ducativc1dec", GST_RANK_PRIMARY, GST_TYPE_DUCATIVC1DEC);
 }
 
 void *
index d62148ab88d9d6ca364b9f84d63097d1aeadba5d..af7ddc2267e16776c7da312d3947b48546324e70 100644 (file)
@@ -58,7 +58,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
         "framerate = (fraction)[ 0, max ];")
     );
 
-/* GstDucatiVideDec vmethod implementations */
+/* GstDucatiVidDec vmethod implementations */
 
 static void
 gst_ducati_h264dec_update_buffer_size (GstDucatiVidDec * self)
index acb3acdf86c2cbf9ffb5df81c7dcd01ad232c5ce..4c7904487c820835afe42172f983c1b7af27227d 100644 (file)
@@ -70,7 +70,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
         )
     );
 
-/* GstDucatiVideDec vmethod implementations */
+/* GstDucatiVidDec vmethod implementations */
 
 static void
 gst_ducati_mpeg4dec_update_buffer_size (GstDucatiVidDec * self)
diff --git a/src/gstducativc1dec.c b/src/gstducativc1dec.c
new file mode 100644 (file)
index 0000000..ace7baf
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * GStreamer
+ * Copyright (c) 2010, Texas Instruments Incorporated
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * SECTION:element-ducativc1dec
+ *
+ * FIXME:Describe ducativc1dec here.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch -v -m fakesrc ! ducativc1dec ! fakesink silent=TRUE
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include "gstducativc1dec.h"
+
+
+#define PADX  32
+#define PADY  40
+
+
+GST_BOILERPLATE (GstDucatiVC1Dec, gst_ducati_vc1dec, GstDucatiVidDec,
+    GST_TYPE_DUCATIVIDDEC);
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-wmv, "
+        "wmvversion = (int)[ 2, 3 ], "
+        "format = (fourcc){ WVC1, WMV3, WMV2, WMV1 }, "
+        "width = (int)[ 16, 2048 ], "
+        "height = (int)[ 16, 2048 ], "
+        "framerate = (fraction)[ 0, max ];")
+    );
+
+/* GstDucatiVidDec vmethod implementations */
+
+static gboolean
+gst_ducati_vc1dec_parse_caps (GstDucatiVidDec * vdec, GstStructure * s)
+{
+  GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec);
+
+  if (parent_class->parse_caps (vdec, s)) {
+    guint32 format;
+    gboolean ret = gst_structure_get_fourcc (s, "format", &format);
+    if (ret) {
+      switch (format) {
+        case GST_MAKE_FOURCC ('W', 'V', 'C', '1'):
+          self->level = 4;
+          break;
+        case GST_MAKE_FOURCC ('W', 'M', 'V', '3'):
+          self->level = 3;
+          break;
+        case GST_MAKE_FOURCC ('W', 'M', 'V', '2'):
+          self->level = 2;
+          break;
+        case GST_MAKE_FOURCC ('W', 'M', 'V', '1'):
+          self->level = 1;
+          break;
+        default:
+          ret = FALSE;
+          break;
+      }
+    }
+    return ret;
+  }
+
+  return FALSE;
+}
+
+static void
+gst_ducati_vc1dec_update_buffer_size (GstDucatiVidDec * self)
+{
+  gint w = self->width;
+  gint h = self->height;
+
+  /* calculate output buffer parameters: */
+  self->padded_width = (w + (2 * PADX) + 0x7f) & ~0x7f;
+  self->padded_height = (((h / 2 + 0xf) & ~0xf) * 2) + 2 * PADY;
+  self->min_buffers = 8;
+}
+
+static gboolean
+gst_ducati_vc1dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
+    gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
+{
+  gboolean ret = parent_class->allocate_params (self,
+      sizeof (IVC1VDEC_Params), sizeof (IVC1VDEC_DynamicParams),
+      sizeof (IVC1VDEC_Status), sizeof (IVC1VDEC_InArgs),
+      sizeof (IVC1VDEC_OutArgs));
+
+  if (ret) {
+    IVC1VDEC_Params *params = (IVC1VDEC_Params *) self->params;
+    self->params->maxBitRate = 45000000;
+    self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_1;
+    params->FrameLayerDataPresentFlag = FALSE;
+  }
+
+  return ret;
+}
+
+static GstBuffer *
+gst_ducati_vc1dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
+{
+  GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec);
+
+  if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) {
+    if (self->level == 4) {
+      /* for VC-1 Advanced Profile, strip off first byte, and
+       * send rest of codec_data unmodified;
+       */
+      push_input (vdec, GST_BUFFER_DATA (vdec->codec_data) + 1,
+          GST_BUFFER_SIZE (vdec->codec_data) - 1);
+    } else {
+      guint32 val;
+
+      /* for VC-1 Simple and Main Profile, build the Table 265 Sequence
+       * Layer Data Structure header (refer to VC-1 spec, Annex L):
+       */
+
+      val = 0xc5ffffff;         /* we don't know the number of frames */
+      push_input (vdec, (guint8 *) & val, 4);
+
+      /* STRUCT_C (preceded by length).. see Table 263, 264 */
+      val = GST_BUFFER_SIZE (vdec->codec_data);
+      push_input (vdec, (guint8 *) & val, 4);
+      push_input (vdec, GST_BUFFER_DATA (vdec->codec_data), val);
+
+      /* STRUCT_A.. see Table 260 and Annex J.2 */
+      push_input (vdec, (guint8 *) & vdec->height, 4);
+      push_input (vdec, (guint8 *) & vdec->width, 4);
+
+      val = 0x0000000c;
+      push_input (vdec, (guint8 *) & val, 4);
+
+      /* STRUCT_B.. see Table 261, 262 */
+      val = 0x00000000;         /* not sure how to populate, but codec ignores anyways */
+      push_input (vdec, (guint8 *) & val, 4);
+      push_input (vdec, (guint8 *) & val, 4);
+      push_input (vdec, (guint8 *) & val, 4);
+    }
+  }
+
+  /* VC-1 Advanced profile needs start-code prepended: */
+  if (self->level == 4) {
+    static guint8 sc[] = { 0x00, 0x00, 0x01, 0x0d };    /* start code */
+    push_input (vdec, sc, sizeof (sc));
+  }
+
+  push_input (vdec, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+  gst_buffer_unref (buf);
+
+  return NULL;
+}
+
+
+/* GObject vmethod implementations */
+
+static void
+gst_ducati_vc1dec_base_init (gpointer gclass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+  gst_element_class_set_details_simple (element_class,
+      "DucatiVC1Dec",
+      "Codec/Decoder/Video",
+      "Decodes video in WMV/VC-1 format with ducati",
+      "Rob Clark <rob@ti.com>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sink_factory));
+}
+
+static void
+gst_ducati_vc1dec_class_init (GstDucatiVC1DecClass * klass)
+{
+  GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
+  bclass->codec_name = "ivahd_vc1vdec";
+  bclass->parse_caps =
+      GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_parse_caps);
+  bclass->update_buffer_size =
+      GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_update_buffer_size);
+  bclass->allocate_params =
+      GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_allocate_params);
+  bclass->push_input =
+      GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_push_input);
+}
+
+static void
+gst_ducati_vc1dec_init (GstDucatiVC1Dec * self,
+    GstDucatiVC1DecClass * gclass)
+{
+}
diff --git a/src/gstducativc1dec.h b/src/gstducativc1dec.h
new file mode 100644 (file)
index 0000000..1031cdf
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * GStreamer
+ * Copyright (c) 2010, Texas Instruments Incorporated
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GST_DUCATIVC1DEC_H__
+#define __GST_DUCATIVC1DEC_H__
+
+#include <gst/gst.h>
+
+#include "gstducatividdec.h"
+
+#include <ti/sdo/codecs/vc1vdec/ivc1vdec.h>
+
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DUCATIVC1DEC              (gst_ducati_vc1dec_get_type())
+#define GST_DUCATIVC1DEC(obj)              (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_DUCATIVC1DEC, GstDucatiVC1Dec))
+#define GST_DUCATIVC1DEC_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_DUCATIVC1DEC, GstDucatiVC1DecClass))
+#define GST_IS_DUCATIVC1DEC(obj)           (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_DUCATIVC1DEC))
+#define GST_IS_DUCATIVC1DEC_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_DUCATIVC1DEC))
+
+typedef struct _GstDucatiVC1Dec      GstDucatiVC1Dec;
+typedef struct _GstDucatiVC1DecClass GstDucatiVC1DecClass;
+
+struct _GstDucatiVC1Dec
+{
+  GstDucatiVidDec parent;
+
+  gint level;
+};
+
+struct _GstDucatiVC1DecClass
+{
+  GstDucatiVidDecClass parent_class;
+};
+
+GType gst_ducati_vc1dec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DUCATIVC1DEC_H__ */
index 953d94a0284868fbe55be9b3f18bd0851b847217..53bc94cfd7a17325e36856478692b5eb7bb4baba 100644 (file)
@@ -318,6 +318,28 @@ codec_flush (GstDucatiVidDec * self, gboolean eos)
 
 /* 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)
@@ -332,17 +354,12 @@ gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
   self->params->maxFrameRate = 30000;
   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;
 
-  //vc1:
-  //self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_1;
-
   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
@@ -393,26 +410,16 @@ gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
   self->outArgs->size = outargs_sz;
 }
 
-static inline void
-push_input (GstDucatiVidDec * self, GstBuffer * buf)
-{
-  gint sz = GST_BUFFER_SIZE (buf);
-  GST_DEBUG_OBJECT (self, "push: %d bytes)", sz);
-  memcpy (self->input + self->in_size, GST_BUFFER_DATA (buf), sz);
-  self->in_size += sz;
-}
-
 static GstBuffer *
 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
 {
-  gint sz;
-
-  if (self->first_in_buffer && self->codec_data) {
-    push_input (self, self->codec_data);
+  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 */
-  push_input (self, buf);
+  push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
   gst_buffer_unref (buf);
 
   return NULL;
@@ -425,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);
@@ -433,32 +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)) {
-      const GValue *codec_data;
+    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;
-      self->stride = 4096;      /* TODO: don't hardcode */
+      gst_structure_get_fraction (s, "framerate", &frn, &frd);
 
-      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);
-      }
+      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;
@@ -539,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;
   }
@@ -696,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 =
index 622383b133e4e3d4d0b3877b29d24d92a14cd128..9be1d917560c1ebdf5f05b6228be08881a2dcd25 100644 (file)
@@ -94,12 +94,22 @@ struct _GstDucatiVidDecClass
 
   const gchar *codec_name;
 
+  /**
+   * Parse codec specific fields the given caps structure.  The base-
+   * class implementation of this method handles standard stuff like
+   * width/height/framerate/codec_data.
+   */
+  gboolean (*parse_caps) (GstDucatiVidDec * self, GstStructure * s);
+
   /**
    * Called when the input buffer size changes, to recalculate codec required
    * output buffer size and minimum count
    */
   void (*update_buffer_size) (GstDucatiVidDec * self);
 
+  /**
+   * Called to allocate/initialize  params/dynParams/status/inArgs/outArgs
+   */
   gboolean (*allocate_params) (GstDucatiVidDec * self, gint params_sz,
       gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz);
 
@@ -112,6 +122,16 @@ struct _GstDucatiVidDecClass
 
 GType gst_ducati_viddec_get_type (void);
 
+/* helper methods for derived classes: */
+
+static inline void
+push_input (GstDucatiVidDec * self, guint8 *in, gint sz)
+{
+  GST_DEBUG_OBJECT (self, "push: %d bytes)", sz);
+  memcpy (self->input + self->in_size, in, sz);
+  self->in_size += sz;
+}
+
 G_END_DECLS
 
 #endif /* __GST_DUCATIVIDDEC_H__ */