vmncdec: Port to GStreamer 1.0 API
authorOlivier Crête <olivier.crete@collabora.com>
Sat, 7 Dec 2013 01:58:48 +0000 (20:58 -0500)
committerOlivier Crête <olivier.crete@collabora.com>
Sat, 7 Dec 2013 01:58:48 +0000 (20:58 -0500)
configure.ac
gst/vmnc/Makefile.am
gst/vmnc/vmncdec.c

index 8008c35..4167738 100644 (file)
@@ -342,7 +342,7 @@ GST_PLUGINS_NONPORTED=" cdxaparse \
  mve mythtv nuvdemux \
  patchdetect real \
  sdi tta \
- videomeasure videosignal vmnc \
+ videomeasure videosignal \
  linsys vcd \
  apexsink dc1394 \
  gsettings \
index e7f1060..c32a578 100644 (file)
@@ -2,7 +2,8 @@ plugin_LTLIBRARIES = libgstvmnc.la
 
 libgstvmnc_la_SOURCES = vmncdec.c
 libgstvmnc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
-libgstvmnc_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
+libgstvmnc_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+       $(GST_BASE_LIBS) $(GST_LIBS)
 libgstvmnc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 libgstvmnc_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
 
@@ -18,4 +19,4 @@ Android.mk: Makefile.am $(BUILT_SOURCES)
                   -ldl \
         -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
                       LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
-       > $@
\ No newline at end of file
+       > $@
index 0e8814a..0816327 100644 (file)
@@ -18,9 +18,9 @@
  */
 
 /*
- * This is a decoder for the VMWare VMnc video codec, which VMWare uses for 
+ * This is a decoder for the VMWare VMnc video codec, which VMWare uses for
  * recording * of virtual machine instances.
- * It's essentially a serialisation of RFB (the VNC protocol) 
+ * It's essentially a serialisation of RFB (the VNC protocol)
  * 'FramebufferUpdate' messages, with some special encoding-types for VMnc
  * extensions. There's some documentation (with fixes from VMWare employees) at:
  *   http://wiki.multimedia.cx/index.php?title=VMware_Video
 #  include "config.h"
 #endif
 
-#include <gst/gst.h>
-#include <gst/base/gstadapter.h>
-#include <gst/video/video.h>
+#include "vmncdec.h"
+
 #include <string.h>
 
+static gboolean gst_vmnc_dec_reset (GstVideoDecoder * decoder);
+static gboolean gst_vmnc_dec_set_format (GstVideoDecoder * decoder,
+    GstVideoCodecState * state);
+static GstFlowReturn gst_vmnc_dec_handle_frame (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame);
+static GstFlowReturn gst_vmnc_dec_parse (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
+
 #define GST_CAT_DEFAULT vmnc_debug
 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
 
-#define GST_TYPE_VMNC_DEC \
-  (gst_vmnc_dec_get_type())
-#define GST_VMNC_DEC(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VMNC_DEC,GstVMncDec))
-
 #define RFB_GET_UINT32(ptr) GST_READ_UINT32_BE(ptr)
 #define RFB_GET_UINT16(ptr) GST_READ_UINT16_BE(ptr)
 #define RFB_GET_UINT8(ptr) GST_READ_UINT8(ptr)
@@ -58,87 +60,12 @@ enum
   ERROR_INSUFFICIENT_DATA = -2  /* Haven't received enough data yet */
 };
 
-#define MAKE_TYPE(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|d)
-enum
-{
-  TYPE_RAW = 0,
-  TYPE_COPY = 1,
-  TYPE_RRE = 2,
-  TYPE_CoRRE = 4,
-  TYPE_HEXTILE = 5,
-
-  TYPE_WMVd = MAKE_TYPE ('W', 'M', 'V', 'd'),
-  TYPE_WMVe = MAKE_TYPE ('W', 'M', 'V', 'e'),
-  TYPE_WMVf = MAKE_TYPE ('W', 'M', 'V', 'f'),
-  TYPE_WMVg = MAKE_TYPE ('W', 'M', 'V', 'g'),
-  TYPE_WMVh = MAKE_TYPE ('W', 'M', 'V', 'h'),
-  TYPE_WMVi = MAKE_TYPE ('W', 'M', 'V', 'i'),
-  TYPE_WMVj = MAKE_TYPE ('W', 'M', 'V', 'j')
-};
-
-struct RFBFormat
-{
-  int width;
-  int height;
-  int stride;
-  int bytes_per_pixel;
-  int depth;
-  int big_endian;
-
-  guint8 descriptor[16];        /* The raw format descriptor block */
-};
-
-enum CursorType
-{
-  CURSOR_COLOUR = 0,
-  CURSOR_ALPHA = 1
-};
-
-struct Cursor
-{
-  enum CursorType type;
-  int visible;
-  int x;
-  int y;
-  int width;
-  int height;
-  int hot_x;
-  int hot_y;
-  guint8 *cursordata;
-  guint8 *cursormask;
-};
-
-typedef struct
-{
-  GstElement element;
-
-  GstPad *sinkpad;
-  GstPad *srcpad;
-
-  GstCaps *caps;
-  gboolean have_format;
-
-  int parsed;
-  GstAdapter *adapter;
-
-  int framerate_num;
-  int framerate_denom;
-
-  struct Cursor cursor;
-  struct RFBFormat format;
-  guint8 *imagedata;
-} GstVMncDec;
-
-typedef struct
-{
-  GstElementClass parent_class;
-} GstVMncDecClass;
-
 static GstStaticPadTemplate vmnc_dec_src_factory =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("video/x-raw-rgb"));
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBx, BGRx, xRGB, xBGR,"
+            " RGB15, BGR15, RGB16, BGR16, GRAY8 }")));
 
 static GstStaticPadTemplate vmnc_dec_sink_factory =
 GST_STATIC_PAD_TEMPLATE ("sink",
@@ -149,107 +76,60 @@ GST_STATIC_PAD_TEMPLATE ("sink",
         "width=(int)[0, max], " "height=(int)[0, max]")
     );
 
-GType gst_vmnc_dec_get_type (void);
-GST_BOILERPLATE (GstVMncDec, gst_vmnc_dec, GstElement, GST_TYPE_ELEMENT);
-
-static void vmnc_dec_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec);
-static void vmnc_dec_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec);
-
-static GstFlowReturn vmnc_dec_chain (GstPad * pad, GstBuffer * buffer);
-static gboolean vmnc_dec_setcaps (GstPad * pad, GstCaps * caps);
-static GstStateChangeReturn vmnc_dec_change_state (GstElement * element,
-    GstStateChange transition);
-static void vmnc_dec_finalize (GObject * object);
+G_DEFINE_TYPE (GstVMncDec, gst_vmnc_dec, GST_TYPE_VIDEO_DECODER);
 
 static void
-gst_vmnc_dec_base_init (gpointer g_class)
+gst_vmnc_dec_class_init (GstVMncDecClass * klass)
 {
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
+
+  decoder_class->start = gst_vmnc_dec_reset;
+  decoder_class->stop = gst_vmnc_dec_reset;
+  decoder_class->parse = gst_vmnc_dec_parse;
+  decoder_class->handle_frame = gst_vmnc_dec_handle_frame;
+  decoder_class->set_format = gst_vmnc_dec_set_format;
 
-  gst_element_class_add_pad_template (element_class,
+  gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&vmnc_dec_src_factory));
-  gst_element_class_add_pad_template (element_class,
+  gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&vmnc_dec_sink_factory));
-  gst_element_class_set_static_metadata (element_class, "VMnc video decoder",
+  gst_element_class_set_static_metadata (gstelement_class, "VMnc video decoder",
       "Codec/Decoder/Video",
       "Decode VmWare video to raw (RGB) video",
       "Michael Smith <msmith@xiph.org>");
-}
-
-static void
-gst_vmnc_dec_class_init (GstVMncDecClass * klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
-  gobject_class->set_property = vmnc_dec_set_property;
-  gobject_class->get_property = vmnc_dec_get_property;
-
-  gobject_class->finalize = vmnc_dec_finalize;
-
-  gstelement_class->change_state = vmnc_dec_change_state;
 
   GST_DEBUG_CATEGORY_INIT (vmnc_debug, "vmncdec", 0, "VMnc decoder");
 }
 
 static void
-gst_vmnc_dec_init (GstVMncDec * dec, GstVMncDecClass * g_class)
+gst_vmnc_dec_init (GstVMncDec * dec)
 {
-  dec->sinkpad =
-      gst_pad_new_from_static_template (&vmnc_dec_sink_factory, "sink");
-  gst_pad_set_chain_function (dec->sinkpad, vmnc_dec_chain);
-  gst_pad_set_setcaps_function (dec->sinkpad, vmnc_dec_setcaps);
-  gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
-
-  dec->srcpad = gst_pad_new_from_static_template (&vmnc_dec_src_factory, "src");
-  gst_pad_use_fixed_caps (dec->srcpad);
-
-  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
-
-  dec->adapter = gst_adapter_new ();
 }
 
-static void
-vmnc_dec_finalize (GObject * object)
+static gboolean
+gst_vmnc_dec_reset (GstVideoDecoder * decoder)
 {
-  GstVMncDec *dec = GST_VMNC_DEC (object);
+  GstVMncDec *dec = GST_VMNC_DEC (decoder);
 
-  g_object_unref (dec->adapter);
+  g_free (dec->imagedata);
+  dec->imagedata = NULL;
 
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
+  g_free (dec->cursor.cursordata);
+  dec->cursor.cursordata = NULL;
 
-static void
-gst_vmnc_dec_reset (GstVMncDec * dec)
-{
-  if (dec->caps) {
-    gst_caps_unref (dec->caps);
-    dec->caps = NULL;
-  }
-  if (dec->imagedata) {
-    g_free (dec->imagedata);
-    dec->imagedata = NULL;
-  }
+  g_free (dec->cursor.cursormask);
+  dec->cursor.cursormask = NULL;
 
-  if (dec->cursor.cursordata) {
-    g_free (dec->cursor.cursordata);
-    dec->cursor.cursordata = NULL;
-  }
-  if (dec->cursor.cursormask) {
-    g_free (dec->cursor.cursormask);
-    dec->cursor.cursormask = NULL;
-  }
   dec->cursor.visible = 0;
 
-  /* Use these as defaults if the container doesn't provide anything */
-  dec->framerate_num = 5;
-  dec->framerate_denom = 1;
-
   dec->have_format = FALSE;
 
-  gst_adapter_clear (dec->adapter);
+  if (dec->input_state)
+    gst_video_codec_state_unref (dec->input_state);
+  dec->input_state = NULL;
+
+  return TRUE;
 }
 
 struct RfbRectangle
@@ -272,7 +152,7 @@ static int
 vmnc_handle_wmvi_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
     const guint8 * data, int len, gboolean decode)
 {
-  GstCaps *caps;
+  GstVideoFormat format;
   gint bpp, tc;
   guint32 redmask, greenmask, bluemask;
   guint32 endianness, dataendianness;
@@ -284,7 +164,7 @@ vmnc_handle_wmvi_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
   }
 
   /* We only compare 13 bytes; ignoring the 3 padding bytes at the end */
-  if (dec->caps && memcmp (data, dec->format.descriptor, 13) == 0) {
+  if (dec->have_format && memcmp (data, dec->format.descriptor, 13) == 0) {
     /* Nothing changed, so just exit */
     return 16;
   }
@@ -346,30 +226,33 @@ vmnc_handle_wmvi_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
     }
   }
 
+  format = gst_video_format_from_masks (dec->format.depth, bpp, endianness,
+      redmask, greenmask, bluemask, 0);
+
+  GST_DEBUG_OBJECT (dec, "From depth: %d bpp: %u endianess: %s redmask: %X "
+      "greenmask: %X bluemask: %X got format %s",
+      dec->format.depth, bpp, endianness == G_BIG_ENDIAN ? "BE" : "LE",
+      GUINT32_FROM_BE (redmask), GUINT32_FROM_BE (greenmask),
+      GUINT32_FROM_BE (bluemask),
+      format == GST_VIDEO_FORMAT_UNKNOWN ? "UNKOWN" :
+      gst_video_format_to_string (format));
+
+  if (format == GST_VIDEO_FORMAT_UNKNOWN) {
+    GST_WARNING_OBJECT (dec, "Video format unknown to GStreamer");
+    return ERROR_INVALID;
+  }
+
   dec->have_format = TRUE;
   if (!decode) {
-    GST_DEBUG_OBJECT (dec, "Parsing, not setting caps");
+    GST_LOG_OBJECT (dec, "Parsing, not setting caps");
     return 16;
   }
 
-  caps = gst_caps_new_simple ("video/x-raw-rgb",
-      "framerate", GST_TYPE_FRACTION, dec->framerate_num, dec->framerate_denom,
-      "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
-      "width", G_TYPE_INT, rect->width, "height", G_TYPE_INT, rect->height,
-      "bpp", G_TYPE_INT, bpp,
-      "depth", G_TYPE_INT, dec->format.depth,
-      "endianness", G_TYPE_INT, endianness,
-      "red_mask", G_TYPE_INT, redmask,
-      "green_mask", G_TYPE_INT, greenmask,
-      "blue_mask", G_TYPE_INT, bluemask, NULL);
-  gst_pad_set_caps (dec->srcpad, caps);
-
-  if (dec->caps)
-    gst_caps_unref (dec->caps);
-  dec->caps = caps;
-
-  if (dec->imagedata)
-    g_free (dec->imagedata);
+
+  gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), format,
+      rect->width, rect->height, dec->input_state);
+
+  g_free (dec->imagedata);
   dec->imagedata = g_malloc (dec->format.width * dec->format.height *
       dec->format.bytes_per_pixel);
   GST_DEBUG_OBJECT (dec, "Allocated image data at %p", dec->imagedata);
@@ -474,26 +357,29 @@ render_cursor (GstVMncDec * dec, guint8 * data)
   }
 }
 
-static GstBuffer *
-vmnc_make_buffer (GstVMncDec * dec, GstBuffer * inbuf)
+static GstFlowReturn
+vmnc_fill_buffer (GstVMncDec * dec, GstVideoCodecFrame * frame)
 {
-  int size = dec->format.stride * dec->format.height;
-  GstBuffer *buf = gst_buffer_new_and_alloc (size);
-  guint8 *data = GST_BUFFER_DATA (buf);
+  GstFlowReturn ret;
+  GstMapInfo map;
+
+  ret =
+      gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (dec), frame);
+  if (ret != GST_FLOW_OK)
+    return ret;
 
-  memcpy (data, dec->imagedata, size);
+  gst_buffer_map (frame->output_buffer, &map, GST_MAP_READWRITE);
+
+  memcpy (map.data, dec->imagedata, map.size);
 
   if (dec->cursor.visible) {
-    render_cursor (dec, data);
+    render_cursor (dec, map.data);
   }
 
-  if (inbuf) {
-    gst_buffer_copy_metadata (buf, inbuf, GST_BUFFER_COPY_TIMESTAMPS);
-  }
+  gst_buffer_unmap (frame->output_buffer, &map);
 
-  gst_buffer_set_caps (buf, dec->caps);
 
-  return buf;
+  return GST_FLOW_OK;
 }
 
 static int
@@ -505,7 +391,7 @@ vmnc_handle_wmvd_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
   int type, size;
 
   if (len < datalen) {
-    GST_DEBUG_OBJECT (dec, "Cursor data too short");
+    GST_LOG_OBJECT (dec, "Cursor data too short");
     return ERROR_INSUFFICIENT_DATA;
   }
 
@@ -521,7 +407,7 @@ vmnc_handle_wmvd_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
   }
 
   if (len < datalen) {
-    GST_DEBUG_OBJECT (dec, "Cursor data too short");
+    GST_LOG_OBJECT (dec, "Cursor data too short");
     return ERROR_INSUFFICIENT_DATA;
   } else if (!decode)
     return datalen;
@@ -533,10 +419,8 @@ vmnc_handle_wmvd_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
   dec->cursor.hot_x = rect->x;
   dec->cursor.hot_y = rect->y;
 
-  if (dec->cursor.cursordata)
-    g_free (dec->cursor.cursordata);
-  if (dec->cursor.cursormask)
-    g_free (dec->cursor.cursormask);
+  g_free (dec->cursor.cursordata);
+  g_free (dec->cursor.cursormask);
 
   if (type == 0) {
     size = rect->width * rect->height * dec->format.bytes_per_pixel;
@@ -560,7 +444,7 @@ vmnc_handle_wmve_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
 
   /* Cursor state. */
   if (len < 2) {
-    GST_DEBUG_OBJECT (dec, "Cursor data too short");
+    GST_LOG_OBJECT (dec, "Cursor data too short");
     return ERROR_INSUFFICIENT_DATA;
   } else if (!decode)
     return 2;
@@ -587,7 +471,7 @@ vmnc_handle_wmvg_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
 {
   /* Keyboard stuff; not interesting for playback */
   if (len < 10) {
-    GST_DEBUG_OBJECT (dec, "Keyboard data too short");
+    GST_LOG_OBJECT (dec, "Keyboard data too short");
     return ERROR_INSUFFICIENT_DATA;
   }
   return 10;
@@ -599,7 +483,7 @@ vmnc_handle_wmvh_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
 {
   /* More keyboard stuff; not interesting for playback */
   if (len < 4) {
-    GST_DEBUG_OBJECT (dec, "Keyboard data too short");
+    GST_LOG_OBJECT (dec, "Keyboard data too short");
     return ERROR_INSUFFICIENT_DATA;
   }
   return 4;
@@ -611,7 +495,7 @@ vmnc_handle_wmvj_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
 {
   /* VM state info, not interesting for playback */
   if (len < 2) {
-    GST_DEBUG_OBJECT (dec, "VM state data too short");
+    GST_LOG_OBJECT (dec, "VM state data too short");
     return ERROR_INSUFFICIENT_DATA;
   }
   return 2;
@@ -665,7 +549,7 @@ vmnc_handle_raw_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
   int datalen = rect->width * rect->height * dec->format.bytes_per_pixel;
 
   if (len < datalen) {
-    GST_DEBUG_OBJECT (dec, "Raw data too short");
+    GST_LOG_OBJECT (dec, "Raw data too short");
     return ERROR_INSUFFICIENT_DATA;
   }
 
@@ -684,7 +568,7 @@ vmnc_handle_copy_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,
   int i;
 
   if (len < 4) {
-    GST_DEBUG_OBJECT (dec, "Copy data too short");
+    GST_LOG_OBJECT (dec, "Copy data too short");
     return ERROR_INSUFFICIENT_DATA;
   } else if (!decode)
     return 4;
@@ -856,7 +740,7 @@ vmnc_handle_packet (GstVMncDec * dec, const guint8 * data, int len,
   int offset = 0;
 
   if (len < 4) {
-    GST_DEBUG_OBJECT (dec, "Packet too short");
+    GST_LOG_OBJECT (dec, "Packet too short");
     return ERROR_INSUFFICIENT_DATA;
   }
 
@@ -876,12 +760,12 @@ vmnc_handle_packet (GstVMncDec * dec, const guint8 * data, int len,
         rectangle_handler handler;
 
         if (len < offset + 12) {
-          GST_DEBUG_OBJECT (dec,
+          GST_LOG_OBJECT (dec,
               "Packet too short for rectangle header: %d < %d",
               len, offset + 12);
           return ERROR_INSUFFICIENT_DATA;
         }
-        GST_DEBUG_OBJECT (dec, "Reading rectangle %d", i);
+        GST_LOG_OBJECT (dec, "Reading rectangle %d", i);
         r.x = RFB_GET_UINT16 (data + offset);
         r.y = RFB_GET_UINT16 (data + offset + 2);
         r.width = RFB_GET_UINT16 (data + offset + 4);
@@ -957,174 +841,90 @@ vmnc_handle_packet (GstVMncDec * dec, const guint8 * data, int len,
 }
 
 static gboolean
-vmnc_dec_setcaps (GstPad * pad, GstCaps * caps)
+gst_vmnc_dec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
 {
+  GstVMncDec *dec = GST_VMNC_DEC (decoder);
+
   /* We require a format descriptor in-stream, so we ignore the info from the
    * container here. We just use the framerate */
-  GstVMncDec *dec = GST_VMNC_DEC (gst_pad_get_parent (pad));
-
-  if (gst_caps_get_size (caps) > 0) {
-    GstStructure *structure = gst_caps_get_structure (caps, 0);
 
-    /* We gave these a default in reset(), so we don't need to check for failure
-     * here */
-    gst_structure_get_fraction (structure, "framerate",
-        &dec->framerate_num, &dec->framerate_denom);
+  /* Declare it packetized if a valid framerate was parsed, not ideal */
+  gst_video_decoder_set_packetized (decoder,
+      state->info.fps_n && state->info.fps_d);
 
-    dec->parsed = TRUE;
-  } else {
-    GST_DEBUG_OBJECT (dec, "Unparsed input");
-    dec->parsed = FALSE;
-  }
-
-  gst_object_unref (dec);
+  if (dec->input_state)
+    gst_video_codec_state_unref (dec->input_state);
+  dec->input_state = gst_video_codec_state_ref (state);
 
   return TRUE;
 }
 
 static GstFlowReturn
-vmnc_dec_chain_frame (GstVMncDec * dec, GstBuffer * inbuf,
-    const guint8 * data, int len)
+gst_vmnc_dec_handle_frame (GstVideoDecoder * decoder,
+    GstVideoCodecFrame * frame)
 {
+  GstVMncDec *dec = GST_VMNC_DEC (decoder);
   int res;
   GstFlowReturn ret = GST_FLOW_OK;
-  GstBuffer *outbuf;
+  GstMapInfo map;
+
+  if (!gst_buffer_map (frame->input_buffer, &map, GST_MAP_READ))
+    return GST_FLOW_ERROR;
 
-  res = vmnc_handle_packet (dec, data, len, TRUE);
+  res = vmnc_handle_packet (dec, map.data, map.size, TRUE);
 
-  if (res < 0) {
+  gst_buffer_unmap (frame->input_buffer, &map);
+
+  if (!dec->have_format) {
+    GST_VIDEO_DECODER_ERROR (decoder, 2, STREAM, DECODE, (NULL),
+        ("Data found before header"), ret);
+    gst_video_decoder_drop_frame (decoder, frame);
+  } else if (res < 0) {
     ret = GST_FLOW_ERROR;
-    GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Couldn't decode packet"));
+    gst_video_decoder_drop_frame (decoder, frame);
+    GST_VIDEO_DECODER_ERROR (decoder, 1, STREAM, DECODE, (NULL),
+        ("Couldn't decode packet"), ret);
   } else {
-    GST_DEBUG_OBJECT (dec, "read %d bytes of %d", res, len);
+    GST_LOG_OBJECT (dec, "read %d bytes of %" G_GSIZE_FORMAT, res,
+        gst_buffer_get_size (frame->input_buffer));
     /* inbuf may be NULL; that's ok */
-    outbuf = vmnc_make_buffer (dec, inbuf);
-    ret = gst_pad_push (dec->srcpad, outbuf);
+    ret = vmnc_fill_buffer (dec, frame);
+    if (ret == GST_FLOW_OK)
+      gst_video_decoder_finish_frame (decoder, frame);
+    else
+      gst_video_decoder_drop_frame (decoder, frame);
   }
 
   return ret;
 }
 
+
 static GstFlowReturn
-vmnc_dec_chain (GstPad * pad, GstBuffer * buf)
+gst_vmnc_dec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame,
+    GstAdapter * adapter, gboolean at_eos)
 {
-  GstVMncDec *dec;
-  GstFlowReturn ret = GST_FLOW_OK;
-
-  dec = GST_VMNC_DEC (gst_pad_get_parent (pad));
-
-  if (!dec->parsed) {
-    /* Submit our input buffer to adapter, then parse. Push each frame found
-     * through the decoder
-     */
-    int avail;
-    const guint8 *data;
-    int read = 0;
-
-    gst_adapter_push (dec->adapter, buf);
-
+  GstVMncDec *dec = GST_VMNC_DEC (decoder);
+  const guint8 *data;
+  int avail;
+  int len;
 
-    avail = gst_adapter_available (dec->adapter);
-    data = gst_adapter_peek (dec->adapter, avail);
+  avail = gst_adapter_available (adapter);
+  data = gst_adapter_map (adapter, avail);
 
-    GST_DEBUG_OBJECT (dec, "Parsing %d bytes", avail);
+  GST_LOG_OBJECT (dec, "Parsing %d bytes", avail);
 
-    while (TRUE) {
-      int len = vmnc_handle_packet (dec, data, avail, FALSE);
+  len = vmnc_handle_packet (dec, data, avail, FALSE);
 
-      if (len == ERROR_INSUFFICIENT_DATA) {
-        GST_DEBUG_OBJECT (dec, "Not enough data yet");
-        ret = GST_FLOW_OK;
-        break;
-      } else if (len < 0) {
-        GST_DEBUG_OBJECT (dec, "Fatal error in bitstream");
-        ret = GST_FLOW_ERROR;
-        break;
-      }
-
-      GST_DEBUG_OBJECT (dec, "Parsed packet: %d bytes", len);
-
-      ret = vmnc_dec_chain_frame (dec, NULL, data, len);
-      avail -= len;
-      data += len;
-
-      read += len;
-
-      if (ret != GST_FLOW_OK)
-        break;
-    }
-    GST_DEBUG_OBJECT (dec, "Flushing %d bytes", read);
-
-    gst_adapter_flush (dec->adapter, read);
+  if (len == ERROR_INSUFFICIENT_DATA) {
+    GST_LOG_OBJECT (dec, "Not enough data yet");
+    return GST_VIDEO_DECODER_FLOW_NEED_DATA;
+  } else if (len < 0) {
+    GST_ERROR_OBJECT (dec, "Fatal error in bitstream");
+    return GST_FLOW_ERROR;
   } else {
-    ret = vmnc_dec_chain_frame (dec, buf, GST_BUFFER_DATA (buf),
-        GST_BUFFER_SIZE (buf));
-    gst_buffer_unref (buf);
-  }
-
-  gst_object_unref (dec);
-
-  return ret;
-}
-
-static GstStateChangeReturn
-vmnc_dec_change_state (GstElement * element, GstStateChange transition)
-{
-  GstVMncDec *dec = GST_VMNC_DEC (element);
-  GstStateChangeReturn ret;
-
-  switch (transition) {
-    case GST_STATE_CHANGE_NULL_TO_READY:
-      break;
-    case GST_STATE_CHANGE_READY_TO_PAUSED:
-      gst_vmnc_dec_reset (dec);
-      break;
-    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
-      break;
-    default:
-      break;
-  }
-
-  ret = parent_class->change_state (element, transition);
-
-  switch (transition) {
-    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
-      break;
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-      gst_vmnc_dec_reset (dec);
-      break;
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      break;
-    default:
-      break;
-  }
-
-  return ret;
-}
-
-static void
-vmnc_dec_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  /*GstVMncDec *dec = GST_VMNC_DEC (object); */
-
-  switch (prop_id) {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-vmnc_dec_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec)
-{
-  /*GstVMncDec *dec = GST_VMNC_DEC (object); */
-
-  switch (prop_id) {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
+    GST_LOG_OBJECT (dec, "Parsed packet: %d bytes", len);
+    gst_video_decoder_add_to_frame (decoder, len);
+    return gst_video_decoder_have_frame (decoder);
   }
 }
 
@@ -1132,7 +932,7 @@ static gboolean
 plugin_init (GstPlugin * plugin)
 {
   if (!gst_element_register (plugin, "vmncdec", GST_RANK_PRIMARY,
-          gst_vmnc_dec_get_type ()))
+          GST_TYPE_VMNC_DEC))
     return FALSE;
   return TRUE;
 }