viddec: add fallback support for non-TILER buffers
authorRob Clark <rob@ti.com>
Sat, 4 Dec 2010 23:27:05 +0000 (17:27 -0600)
committerRob Clark <rob@ti.com>
Sun, 5 Dec 2010 02:01:43 +0000 (20:01 -0600)
Add a GstDucatiBufferPool which can allocate TILER output buffers for the
codec, in case the downstream element does not allocate TILER buffers for
us.  This makes use cases like decode to filesink or fakesink and
transcoding work properly.

src/Makefile.am
src/gstducati.c
src/gstducati.h
src/gstducatibufferpool.c [new file with mode: 0644]
src/gstducatibufferpool.h [new file with mode: 0644]
src/gstducatividdec.c
src/gstducatividdec.h

index 6224927b298a2ade558f780ca75181309c957980..f3d69f3a911d9d83520699eb01b74abe204136a4 100644 (file)
@@ -9,6 +9,7 @@ noinst_HEADERS = \
        gstducatimpeg4dec.h \
        gstducatih264dec.h \
        gstducatividdec.h \
+       gstducatibufferpool.h \
        gstducati.h
 
 # sources used to compile this plug-in
@@ -20,6 +21,7 @@ libgstducati_la_SOURCES = \
        gstducatimpeg4dec.c \
        gstducatih264dec.c \
        gstducatividdec.c \
+       gstducatibufferpool.c \
        gstducati.c \
        $(noinst_HEADERS)
 
index 1fcbaa76e87e4bd7a31552640881ad0d7b7b5ac5..d805911af0852ac39017df28836de40436e20255 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <gst/gst.h>
 
+#include "gstducati.h"
 #include "gstducatih264dec.h"
 #include "gstducatimpeg4dec.h"
 #include "gstducatimpeg2dec.h"
@@ -59,22 +60,27 @@ gst_ducati_alloc_1d (gint sz)
 }
 
 void *
-gst_ducati_alloc_2d (gint width, gint height)
+gst_ducati_alloc_2d (gint width, gint height, guint * sz)
 {
   MemAllocBlock block[] = { {
           .pixelFormat = PIXEL_FMT_8BIT,
           .dim = {.area = {
                       .width = width,
-                      .height = height,
-                  }}
+                      .height = ALIGN2 (height, 1),
+                  }},
+          .stride = 4096
       }, {
         .pixelFormat = PIXEL_FMT_16BIT,
         .dim = {.area = {
                     .width = width,
-                    .height = height / 2,
-                }}
+                    .height = ALIGN2 (height, 1) / 2,
+                }},
+        .stride = 4096
       }
   };
+  if (sz) {
+    *sz = (4096 * ALIGN2 (height, 1) * 3) / 2;
+  }
   return MemMgr_Alloc (block, 2);
 }
 
index 60cee7e17a0eacefe935637de0f7706f0c7c7843..3d5031341165b62402f8505ed56e9f5e39e2feac 100644 (file)
@@ -42,7 +42,7 @@ GST_DEBUG_CATEGORY_EXTERN (gst_ducati_debug);
 #define ALIGN2(x,n)   (((x) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1))
 
 void * gst_ducati_alloc_1d (gint sz);
-void * gst_ducati_alloc_2d (gint width, gint height);
+void * gst_ducati_alloc_2d (gint width, gint height, guint * sz);
 XDAS_Int16 gst_ducati_get_mem_type (SSPtr paddr);
 
 G_END_DECLS
diff --git a/src/gstducatibufferpool.c b/src/gstducatibufferpool.c
new file mode 100644 (file)
index 0000000..6be3727
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * 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
+ */
+
+#include "gstducatibufferpool.h"
+
+/*
+ * GstDucatiBuffer
+ */
+
+static GstBufferClass *buffer_parent_class;
+
+/* Get the original buffer, or whatever is the best output buffer.
+ * Consumes the input reference, produces the output reference
+ */
+GstBuffer *
+gst_ducati_buffer_get (GstDucatiBuffer * self)
+{
+  if (self->orig) {
+    // TODO copy to orig buffer.. if needed.
+    gst_buffer_unref (self->orig);
+    self->orig = NULL;
+  }
+  return GST_BUFFER (self);
+}
+
+static GstDucatiBuffer *
+gst_ducati_buffer_new (GstDucatiBufferPool * pool)
+{
+  GstDucatiBuffer *self = (GstDucatiBuffer *)
+      gst_mini_object_new (GST_TYPE_DUCATIBUFFER);
+  guint sz;
+
+  GST_LOG_OBJECT (pool->element, "creating buffer %p in pool %p", self, pool);
+
+  self->pool = (GstDucatiBufferPool *)
+      gst_mini_object_ref (GST_MINI_OBJECT (pool));
+
+  GST_BUFFER_DATA (self) =
+      gst_ducati_alloc_2d (pool->padded_width, pool->padded_height, &sz);
+  GST_BUFFER_SIZE (self) = sz;
+
+  gst_buffer_set_caps (GST_BUFFER (self), pool->caps);
+
+  return self;
+}
+
+static void
+gst_ducati_buffer_finalize (GstDucatiBuffer * self)
+{
+  GstDucatiBufferPool *pool = self->pool;
+  gboolean resuscitated = FALSE;
+
+  GST_LOG_OBJECT (pool->element, "finalizing buffer %p", self);
+
+  GST_DUCATI_BUFFERPOOL_LOCK (pool);
+  if (pool->running) {
+    resuscitated = TRUE;
+
+    GST_LOG_OBJECT (pool->element, "reviving buffer %p", self);
+    gst_buffer_ref (GST_BUFFER (self));
+
+    /* insert self into freelist */
+    self->next = pool->freelist;
+    pool->freelist = self;
+  } else {
+    GST_LOG_OBJECT (pool->element, "the pool is shutting down");
+  }
+  GST_DUCATI_BUFFERPOOL_UNLOCK (pool);
+
+  if (!resuscitated) {
+    GST_LOG_OBJECT (pool->element,
+        "buffer %p (data %p, len %u) not recovered, freeing",
+        self, GST_BUFFER_DATA (self), GST_BUFFER_SIZE (self));
+    MemMgr_Free ((void *) GST_BUFFER_DATA (self));
+    GST_BUFFER_DATA (self) = NULL;
+    gst_mini_object_unref (GST_MINI_OBJECT (pool));
+    GST_MINI_OBJECT_CLASS (buffer_parent_class)->
+        finalize (GST_MINI_OBJECT (self));
+  }
+}
+
+static void
+gst_ducati_buffer_class_init (gpointer g_class, gpointer class_data)
+{
+  GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+
+  buffer_parent_class = g_type_class_peek_parent (g_class);
+
+  mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
+        GST_DEBUG_FUNCPTR (gst_ducati_buffer_finalize);
+}
+
+GType
+gst_ducati_buffer_get_type (void)
+{
+  static GType type;
+
+  if (G_UNLIKELY (type == 0)) {
+    static const GTypeInfo info = {
+      .class_size = sizeof (GstBufferClass),
+      .class_init = gst_ducati_buffer_class_init,
+      .instance_size = sizeof (GstDucatiBuffer),
+    };
+    type = g_type_register_static (GST_TYPE_BUFFER,
+        "GstDucatiBuffer", &info, 0);
+  }
+  return type;
+}
+
+/*
+ * GstDucatiBufferPool
+ */
+
+static GstMiniObjectClass *bufferpool_parent_class = NULL;
+
+/** create new bufferpool */
+GstDucatiBufferPool *
+gst_ducati_bufferpool_new (GstElement * element, GstCaps * caps)
+{
+  GstDucatiBufferPool *self = (GstDucatiBufferPool *)
+      gst_mini_object_new (GST_TYPE_DUCATIBUFFERPOOL);
+  GstStructure *s = gst_caps_get_structure (caps, 0);
+
+  self->element = gst_object_ref (element);
+  gst_structure_get_int (s, "width", &self->padded_width);
+  gst_structure_get_int (s, "height", &self->padded_height);
+  self->caps = gst_caps_ref (caps);
+  self->freelist = NULL;
+  self->lock = g_mutex_new ();
+  self->running = TRUE;
+
+  return self;
+}
+
+/** destroy existing bufferpool */
+void
+gst_ducati_bufferpool_destroy (GstDucatiBufferPool * self)
+{
+  g_return_if_fail (self);
+
+  GST_DUCATI_BUFFERPOOL_LOCK (self);
+  self->running = FALSE;
+  GST_DUCATI_BUFFERPOOL_UNLOCK (self);
+
+  GST_DEBUG_OBJECT (self->element, "destroy pool");
+
+  /* free all buffers on the freelist */
+  while (self->freelist) {
+    GstDucatiBuffer *buf = self->freelist;
+    self->freelist = buf->next;
+    gst_buffer_unref (GST_BUFFER (buf));
+  }
+
+  gst_mini_object_unref (GST_MINI_OBJECT (self));
+}
+
+/** get buffer from bufferpool, allocate new buffer if needed */
+GstDucatiBuffer *
+gst_ducati_bufferpool_get (GstDucatiBufferPool * self, GstBuffer * orig)
+{
+  GstDucatiBuffer *buf = NULL;
+
+  g_return_if_fail (self);
+
+  GST_DUCATI_BUFFERPOOL_LOCK (self);
+  if (self->running) {
+    /* re-use a buffer off the freelist if any are available
+     */
+    if (self->freelist) {
+      buf = self->freelist;
+      self->freelist = buf->next;
+    } else {
+      buf = gst_ducati_buffer_new (self);
+    }
+    buf->orig = orig;
+  }
+  GST_DUCATI_BUFFERPOOL_UNLOCK (self);
+
+  if (buf && orig) {
+    GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_TIMESTAMP (orig);
+    GST_BUFFER_DURATION (buf) = GST_BUFFER_DURATION (orig);
+  }
+
+  return buf;
+}
+
+static void
+gst_ducati_bufferpool_finalize (GstDucatiBufferPool * self)
+{
+  g_mutex_free (self->lock);
+  gst_caps_unref (self->caps);
+  gst_object_unref (self->element);
+  GST_MINI_OBJECT_CLASS (bufferpool_parent_class)->
+      finalize (GST_MINI_OBJECT (self));
+}
+
+static void
+gst_ducati_bufferpool_class_init (gpointer g_class, gpointer class_data)
+{
+  GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+
+  bufferpool_parent_class = g_type_class_peek_parent (g_class);
+
+  mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
+        GST_DEBUG_FUNCPTR (gst_ducati_bufferpool_finalize);
+}
+
+GType
+gst_ducati_bufferpool_get_type (void)
+{
+  static GType type;
+
+  if (G_UNLIKELY (type == 0)) {
+    static const GTypeInfo info = {
+      .class_size = sizeof (GstMiniObjectClass),
+      .class_init = gst_ducati_bufferpool_class_init,
+      .instance_size = sizeof (GstDucatiBufferPool),
+    };
+    type = g_type_register_static (GST_TYPE_MINI_OBJECT,
+        "GstDucatiBufferPool", &info, 0);
+  }
+  return type;
+}
diff --git a/src/gstducatibufferpool.h b/src/gstducatibufferpool.h
new file mode 100644 (file)
index 0000000..cbf48e9
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 __GSTDUCATIBUFFERPOOL_H__
+#define __GSTDUCATIBUFFERPOOL_H__
+
+#include "gstducati.h"
+
+G_BEGIN_DECLS
+
+GType gst_ducati_buffer_get_type (void);
+#define GST_TYPE_DUCATIBUFFER (gst_ducati_buffer_get_type())
+#define GST_IS_DUCATIBUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DUCATIBUFFER))
+#define GST_DUCATIBUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DUCATIBUFFER, GstDucatiBuffer))
+
+GType gst_ducati_bufferpool_get_type (void);
+#define GST_TYPE_DUCATIBUFFERPOOL (gst_ducati_bufferpool_get_type())
+#define GST_IS_DUCATIBUFFERPOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DUCATIBUFFERPOOL))
+#define GST_DUCATIBUFFERPOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DUCATIBUFFERPOOL, GstDucatiBufferPool))
+
+typedef struct _GstDucatiBufferPool GstDucatiBufferPool;
+typedef struct _GstDucatiBuffer GstDucatiBuffer;
+
+struct _GstDucatiBufferPool
+{
+  GstMiniObject parent;
+
+  /* output (padded) size including any codec padding: */
+  gint padded_width, padded_height;
+
+  GstCaps         *caps;
+  GMutex          *lock;
+  gboolean         running;  /* with lock */
+  GstElement      *element;  /* the element that owns us.. */
+  GstDucatiBuffer *freelist; /* list of available buffers */
+};
+
+GstDucatiBufferPool * gst_ducati_bufferpool_new (GstElement * element, GstCaps * caps);
+void gst_ducati_bufferpool_destroy (GstDucatiBufferPool * pool);
+GstDucatiBuffer * gst_ducati_bufferpool_get (GstDucatiBufferPool * self, GstBuffer * orig);
+
+#define GST_DUCATI_BUFFERPOOL_LOCK(self)     g_mutex_lock ((self)->lock)
+#define GST_DUCATI_BUFFERPOOL_UNLOCK(self)   g_mutex_unlock ((self)->lock)
+
+struct _GstDucatiBuffer {
+  GstBuffer parent;
+
+  GstDucatiBufferPool *pool; /* buffer-pool that this buffer belongs to */
+  GstBuffer       *orig;     /* original buffer, if we need to copy output */
+  GstDucatiBuffer *next;     /* next in freelist, if not in use */
+};
+
+GstBuffer * gst_ducati_buffer_get (GstDucatiBuffer * self);
+
+G_END_DECLS
+
+#endif /* __GSTDUCATIBUFFERPOOL_H__ */
index ed6c7a53f2ccbb1117e90a466abee7f1c0148284..486efd8afc77d6edbab81b6c52e2d633880d5301 100644 (file)
@@ -109,6 +109,11 @@ engine_open (GstDucatiVidDec * self)
 static void
 codec_delete (GstDucatiVidDec * self)
 {
+  if (self->pool) {
+    gst_ducati_bufferpool_destroy (self->pool);
+    self->pool = NULL;
+  }
+
   if (self->codec) {
     VIDDEC3_delete(self->codec);
     self->codec = NULL;
@@ -174,6 +179,17 @@ codec_create (GstDucatiVidDec * self)
   return TRUE;
 }
 
+static inline GstBuffer *
+codec_bufferpool_get (GstDucatiVidDec * self, GstBuffer * buf)
+{
+  if (G_UNLIKELY (!self->pool)) {
+    GST_DEBUG_OBJECT (self, "creating bufferpool");
+    self->pool = gst_ducati_bufferpool_new (GST_ELEMENT (self),
+        GST_PAD_CAPS (self->srcpad));
+  }
+  return GST_BUFFER (gst_ducati_bufferpool_get (self->pool, buf));
+}
+
 static XDAS_Int32
 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer * buf)
 {
@@ -191,7 +207,8 @@ codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer * buf)
   uv_type = gst_ducati_get_mem_type (uv_paddr);
 
   if ((y_type < 0) || (uv_type < 0)) {
-    return 0;
+    GST_DEBUG_OBJECT (self, "non TILER buffer, fallback to bufferpool");
+    return codec_prepare_outbuf (self, codec_bufferpool_get (self, buf));
   }
 
   if (!self->outBufs->numBufs) {
@@ -208,7 +225,11 @@ codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer * buf)
     /* verify output buffer type matches what we've already given
      * to the codec
      */
-    // TODO
+    if ((self->outBufs->descs[0].memType != y_type) ||
+        (self->outBufs->descs[1].memType != uv_type)) {
+      GST_DEBUG_OBJECT (self, "buffer mismatch, fallback to bufferpool");
+      return codec_prepare_outbuf (self, codec_bufferpool_get (self, buf));
+    }
   }
 
   self->outBufs->descs[0].buf = (XDAS_Int8 *) y_paddr;
@@ -276,6 +297,9 @@ codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush)
 
     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
     if (send) {
+      if (GST_IS_DUCATIBUFFER (outbuf)) {
+        outbuf = gst_ducati_buffer_get (GST_DUCATIBUFFER (outbuf));
+      }
       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
           i, outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
       gst_pad_push (self->srcpad, outbuf);
@@ -544,11 +568,8 @@ gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
       GST_PAD_CAPS (self->srcpad), &outbuf);
 
   if (ret != GST_FLOW_OK) {
-    /* TODO: if we had our own buffer class, we could allocate our own
-     * output buffer from TILER...
-     */
-    GST_WARNING_OBJECT (self, "TODO: allocate output TILER buffer");
-    return ret;
+    outbuf = codec_bufferpool_get (self, NULL);
+    ret = GST_FLOW_OK;
   }
 
   if (G_UNLIKELY (!self->codec)) {
index 9be1d917560c1ebdf5f05b6228be08881a2dcd25..4075da335ff2b8bdaf7d9ace967fb13a26eefe4d 100644 (file)
@@ -23,6 +23,7 @@
 #include <gst/gst.h>
 
 #include "gstducati.h"
+#include "gstducatibufferpool.h"
 
 
 G_BEGIN_DECLS
@@ -47,6 +48,8 @@ struct _GstDucatiVidDec
 
   GstPad *sinkpad, *srcpad;
 
+  GstDucatiBufferPool *pool;
+
   /* minimum output size required by the codec: */
   gint outsize;