summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2010-12-04 17:27:05 -0600
committerRob Clark <rob@ti.com>2010-12-04 20:01:43 -0600
commit458caf01e62d48ffb688275e29e3152d390d3f06 (patch)
treeea5a08ab5e6fdfe9ef6a688744a4f234a656a133
parent21dfa9d19a3398298a6647a60f20e6e6444f7322 (diff)
viddec: add fallback support for non-TILER buffers
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.
-rw-r--r--src/Makefile.am2
-rw-r--r--src/gstducati.c16
-rw-r--r--src/gstducati.h2
-rw-r--r--src/gstducatibufferpool.c239
-rw-r--r--src/gstducatibufferpool.h73
-rw-r--r--src/gstducatividdec.c35
-rw-r--r--src/gstducatividdec.h3
7 files changed, 357 insertions, 13 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 6224927..f3d69f3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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)
diff --git a/src/gstducati.c b/src/gstducati.c
index 1fcbaa7..d805911 100644
--- a/src/gstducati.c
+++ b/src/gstducati.c
@@ -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);
}
diff --git a/src/gstducati.h b/src/gstducati.h
index 60cee7e..3d50313 100644
--- a/src/gstducati.h
+++ b/src/gstducati.h
@@ -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
index 0000000..6be3727
--- /dev/null
+++ b/src/gstducatibufferpool.c
@@ -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
index 0000000..cbf48e9
--- /dev/null
+++ b/src/gstducatibufferpool.h
@@ -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__ */
diff --git a/src/gstducatividdec.c b/src/gstducatividdec.c
index ed6c7a5..486efd8 100644
--- a/src/gstducatividdec.c
+++ b/src/gstducatividdec.c
@@ -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)) {
diff --git a/src/gstducatividdec.h b/src/gstducatividdec.h
index 9be1d91..4075da3 100644
--- a/src/gstducatividdec.h
+++ b/src/gstducatividdec.h
@@ -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;