diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/gstducati.c | 16 | ||||
-rw-r--r-- | src/gstducati.h | 2 | ||||
-rw-r--r-- | src/gstducatibufferpool.c | 239 | ||||
-rw-r--r-- | src/gstducatibufferpool.h | 73 | ||||
-rw-r--r-- | src/gstducatividdec.c | 35 | ||||
-rw-r--r-- | src/gstducatividdec.h | 3 |
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; |