Search
SailfishOS Open Build Service
>
Projects
>
nemo
:
testing:hw
:
oneplus
:
oneplus3
>
gst-omx
> _service:tar_git:0006-Prevent-starvation-when-using-buffer-pools.patch
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File _service:tar_git:0006-Prevent-starvation-when-using-buffer-pools.patch of Package gst-omx
From 193551a059abfd24bd7f9f31e4c3c13174839465 Mon Sep 17 00:00:00 2001 From: Andrew den Exter <andrew.den.exter@jollamobile.com> Date: Thu, 29 May 2014 02:09:20 +0000 Subject: [PATCH 06/14] Prevent starvation when using buffer pools. Contributes to JB#19560 Use a separate task to pull buffers from a buffer pool and feed them to the component rather than relying on a one out one in exchange when a buffer is filled. This also uses buffer meta to associate a GstBuffer with an OMX buffer header rather than an a buffer pool reimplementation, and improves support for different memory types beyond EGL images. --- omx/Makefile.am | 2 - omx/gstomx.c | 279 ++++++++++++++++++---- omx/gstomx.h | 14 +- omx/gstomxbufferpool.c | 633 ------------------------------------------------- omx/gstomxbufferpool.h | 94 -------- omx/gstomxvideodec.c | 395 ++++++++++-------------------- omx/gstomxvideodec.h | 2 - 7 files changed, 361 insertions(+), 1058 deletions(-) delete mode 100644 omx/gstomxbufferpool.c delete mode 100644 omx/gstomxbufferpool.h diff --git a/omx/Makefile.am b/omx/Makefile.am index d2bc117..03dd872 100644 --- a/omx/Makefile.am +++ b/omx/Makefile.am @@ -12,7 +12,6 @@ endif libgstomx_la_SOURCES = \ gstomx.c \ - gstomxbufferpool.c \ gstomxvideo.c \ gstomxvideodec.c \ gstomxvideoenc.c \ @@ -39,7 +38,6 @@ libgstomx_la_SOURCES = \ noinst_HEADERS = \ gstomx.h \ - gstomxbufferpool.h \ gstomxvideo.h \ gstomxvideodec.h \ gstomxvideoenc.h \ diff --git a/omx/gstomx.c b/omx/gstomx.c index a8d202f..480d90d 100644 --- a/omx/gstomx.c +++ b/omx/gstomx.c @@ -54,6 +54,50 @@ GST_DEBUG_CATEGORY (gstomx_debug); #define GST_CAT_DEFAULT gstomx_debug +typedef struct _GstOMXBufferMeta GstOMXBufferMeta; + +static GType gst_omx_buffer_meta_api_get_type (void); +#define GST_OMX_BUFFER_META_API_TYPE (gst_omx_buffer_meta_api_get_type()) +static const GstMetaInfo * gst_omx_buffer_meta_get_info (void); +#define GST_OMX_BUFFER_META_INFO (gst_omx_buffer_meta_get_info()) + +#define gst_buffer_get_omx_buffer_meta(b) ((GstOMXBufferMeta*)gst_buffer_get_meta((b),GST_OMX_BUFFER_META_API_TYPE)) + +struct _GstOMXBufferMeta { + GstMeta meta; + + OMX_BUFFERHEADERTYPE *omx_buf; +}; + +static GType +gst_omx_buffer_meta_api_get_type (void) +{ + static volatile GType type; + static const gchar *tags[] = + { GST_META_TAG_VIDEO_STR, GST_META_TAG_MEMORY_STR, NULL }; + + if (g_once_init_enter (&type)) { + GType _type = gst_meta_api_type_register ("GstOMXBufferMetaAPI", tags); + g_once_init_leave (&type, _type); + } + return type; +} + +static const GstMetaInfo * +gst_omx_buffer_meta_get_info (void) +{ + static const GstMetaInfo *droid_cam_buffer_meta_info = NULL; + + if (g_once_init_enter (&droid_cam_buffer_meta_info)) { + const GstMetaInfo *meta = + gst_meta_register (GST_OMX_BUFFER_META_API_TYPE, "GstOMXBufferMeta", + sizeof (GstOMXBufferMeta), (GstMetaInitFunction) NULL, + (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL); + g_once_init_leave (&droid_cam_buffer_meta_info, meta); + } + return droid_cam_buffer_meta_info; +} + G_LOCK_DEFINE_STATIC (core_handles); static GHashTable *core_handles; @@ -473,6 +517,9 @@ gst_omx_component_handle_messages (GstOMXComponent * comp) if (port->port_def.eDir == OMX_DirOutput && (port->flushing || port->disabled_pending)) { + if (buf->pool_buffer) { + gst_buffer_unref (buf->pool_buffer); + } break; } @@ -807,6 +854,9 @@ gst_omx_component_new (GstObject * parent, const gchar * core_name, comp->n_in_ports = 0; comp->n_out_ports = 0; + comp->fill_task = NULL; + g_rec_mutex_init (&comp->fill_lock); + g_mutex_init (&comp->lock); g_mutex_init (&comp->messages_lock); g_cond_init (&comp->messages_cond); @@ -871,6 +921,12 @@ gst_omx_component_free (GstOMXComponent * comp) comp->ports = NULL; } + if (comp->fill_task) { + gst_task_join (comp->fill_task); + gst_object_unref (comp->fill_task); + } + g_rec_mutex_clear (&comp->fill_lock); + comp->core->free_handle (comp->handle); gst_omx_core_release (comp->core); @@ -1047,6 +1103,7 @@ gst_omx_component_add_port (GstOMXComponent * comp, guint32 index) port = g_slice_new0 (GstOMXPort); port->comp = comp; + port->pool = NULL; port->index = index; port->tunneled = FALSE; @@ -1525,6 +1582,11 @@ gst_omx_port_release_buffer (GstOMXPort * port, GstOMXBuffer * buf) buf->omx_buf->nFilledLen = 0; } + if (buf->pool_buffer) { + gst_buffer_unref (buf->pool_buffer); + goto done; + } + if ((err = comp->last_error) != OMX_ErrorNone) { GST_ERROR_OBJECT (comp->parent, "Component %s is in error state: %s " "(0x%08x)", comp->name, gst_omx_error_to_string (err), err); @@ -1582,6 +1644,7 @@ gst_omx_port_set_flushing (GstOMXPort * port, GstClockTime timeout, comp = port->comp; g_mutex_lock (&comp->lock); + g_rec_mutex_lock (&comp->fill_lock); GST_DEBUG_OBJECT (comp->parent, "Setting %s port %d to %sflushing", comp->name, port->index, (flush ? "" : "not ")); @@ -1606,7 +1669,16 @@ gst_omx_port_set_flushing (GstOMXPort * port, GstClockTime timeout, OMX_ERRORTYPE last_error; if (port->port_def.eDir == OMX_DirOutput) { - g_queue_clear (&port->pending_buffers); + if (port->pool && comp->fill_task) { + gst_task_pause (comp->fill_task); + } + + while (!g_queue_is_empty (&port->pending_buffers)) { + GstOMXBuffer *buf = g_queue_pop_head (&port->pending_buffers); + if (buf->pool_buffer) { + gst_buffer_unref (buf->pool_buffer); + } + } } gst_omx_component_send_message (comp, NULL); @@ -1684,6 +1756,7 @@ done: comp->name, port->index, (flush ? "" : "not "), gst_omx_error_to_string (err), err); gst_omx_component_handle_messages (comp); + g_rec_mutex_unlock (&comp->fill_lock); g_mutex_unlock (&comp->lock); return err; @@ -1716,13 +1789,13 @@ static OMX_ERRORTYPE gst_omx_port_deallocate_buffers_unlocked (GstOMXPort * /* NOTE: Must be called while holding comp->lock, uses comp->messages_lock */ static OMX_ERRORTYPE -gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port, - const GList * buffers, const GList * images, guint n) +gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port, GstBufferPool *pool, + GstOMXPortUseBuffer use_buffer) { GstOMXComponent *comp; OMX_ERRORTYPE err = OMX_ErrorNone; - gint i; - const GList *l; + guint i, n; + GList *buffers = NULL; g_assert (!port->buffers || port->buffers->len == 0); g_assert (port->num_used_buffers == 0); @@ -1731,6 +1804,8 @@ gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port, comp = port->comp; + g_rec_mutex_lock (&comp->fill_lock); + gst_omx_component_handle_messages (port->comp); if ((err = comp->last_error) != OMX_ErrorNone) { GST_ERROR_OBJECT (comp->parent, "Component %s in error state: %s (0x%08x)", @@ -1744,14 +1819,7 @@ gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port, */ gst_omx_port_update_port_definition (port, NULL); - g_return_val_if_fail (n != -1 || (!buffers - && !images), OMX_ErrorBadParameter); - - if (n == -1) - n = port->port_def.nBufferCountActual; - - g_return_val_if_fail (n == port->port_def.nBufferCountActual, - OMX_ErrorBadParameter); + n = port->port_def.nBufferCountActual; GST_INFO_OBJECT (comp->parent, "Allocating %d buffers of size %" G_GSIZE_FORMAT " for %s port %u", n, @@ -1760,31 +1828,52 @@ gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port, if (!port->buffers) port->buffers = g_ptr_array_sized_new (n); - l = (buffers ? buffers : images); for (i = 0; i < n; i++) { GstOMXBuffer *buf; buf = g_slice_new0 (GstOMXBuffer); buf->port = port; + buf->pool_buffer = NULL; buf->used = FALSE; buf->settings_cookie = port->settings_cookie; g_ptr_array_add (port->buffers, buf); - if (buffers) { - err = - OMX_UseBuffer (comp->handle, &buf->omx_buf, port->index, buf, - port->port_def.nBufferSize, l->data); - buf->eglimage = FALSE; - } else if (images) { - err = - OMX_UseEGLImage (comp->handle, &buf->omx_buf, port->index, buf, - l->data); - buf->eglimage = TRUE; + if (pool) { + GstBuffer *buffer; + GstFlowReturn ret; + GstBufferPoolAcquireParams params = { 0, }; + params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT; + + ret = gst_buffer_pool_acquire_buffer (pool, &buffer, ¶ms); + + if (ret != GST_FLOW_OK) { + GST_ERROR_OBJECT (comp->parent, + "Failed to acquire buffer for %s port %u: %s", comp->name, + port->index, gst_flow_get_name (ret)); + gst_omx_port_deallocate_buffers_unlocked (port); + pool = NULL; + goto done; + } + + err = use_buffer (port, buffer, buf, &buf->omx_buf); + + if (err == OMX_ErrorNone) { + GstOMXBufferMeta *meta = (GstOMXBufferMeta *) gst_buffer_add_meta + (buffer, GST_OMX_BUFFER_META_INFO, NULL); + meta->omx_buf = buf->omx_buf; + buf->pool_buffer = buffer; + + GST_META_FLAG_SET ((GstMeta *) meta, GST_META_FLAG_POOLED); + + GST_DEBUG_OBJECT (comp->parent, "Added meta to buffer %p (%p)", + buffer, meta); + } + + buffers = g_list_append (buffers, buffer); } else { err = OMX_AllocateBuffer (comp->handle, &buf->omx_buf, port->index, buf, port->port_def.nBufferSize); - buf->eglimage = FALSE; } if (err != OMX_ErrorNone) { @@ -1792,6 +1881,7 @@ gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port, "Failed to allocate buffer for %s port %u: %s (0x%08x)", comp->name, port->index, gst_omx_error_to_string (err), err); gst_omx_port_deallocate_buffers_unlocked (port); + pool = NULL; goto done; } @@ -1804,13 +1894,20 @@ gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port, /* In the beginning all buffers are not owned by the component */ g_queue_push_tail (&port->pending_buffers, buf); } - if (buffers || images) - l = l->next; } gst_omx_component_handle_messages (comp); done: + if (pool) { + gst_object_ref (pool); + port->pool = pool; + } + + g_rec_mutex_unlock (&comp->fill_lock); + + g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); + gst_omx_port_update_port_definition (port, NULL); GST_INFO_OBJECT (comp->parent, "Allocated buffers for %s port %u: %s " @@ -1819,33 +1916,18 @@ done: return err; } -/* NOTE: Uses comp->lock and comp->messages_lock */ -OMX_ERRORTYPE -gst_omx_port_allocate_buffers (GstOMXPort * port) -{ - OMX_ERRORTYPE err; - - g_return_val_if_fail (port != NULL, OMX_ErrorUndefined); - - g_mutex_lock (&port->comp->lock); - err = gst_omx_port_allocate_buffers_unlocked (port, NULL, NULL, -1); - g_mutex_unlock (&port->comp->lock); - - return err; -} /* NOTE: Uses comp->lock and comp->messages_lock */ OMX_ERRORTYPE -gst_omx_port_use_buffers (GstOMXPort * port, const GList * buffers) +gst_omx_port_use_buffers (GstOMXPort * port, GstBufferPool *pool, + GstOMXPortUseBuffer use_buffer) { OMX_ERRORTYPE err; - guint n; g_return_val_if_fail (port != NULL, OMX_ErrorUndefined); g_mutex_lock (&port->comp->lock); - n = g_list_length ((GList *) buffers); - err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n); + err = gst_omx_port_allocate_buffers_unlocked (port, pool, use_buffer); g_mutex_unlock (&port->comp->lock); return err; @@ -1853,16 +1935,14 @@ gst_omx_port_use_buffers (GstOMXPort * port, const GList * buffers) /* NOTE: Uses comp->lock and comp->messages_lock */ OMX_ERRORTYPE -gst_omx_port_use_eglimages (GstOMXPort * port, const GList * images) +gst_omx_port_allocate_buffers (GstOMXPort * port) { OMX_ERRORTYPE err; - guint n; g_return_val_if_fail (port != NULL, OMX_ErrorUndefined); g_mutex_lock (&port->comp->lock); - n = g_list_length ((GList *) images); - err = gst_omx_port_allocate_buffers_unlocked (port, NULL, images, n); + err = gst_omx_port_allocate_buffers_unlocked (port, NULL, NULL); g_mutex_unlock (&port->comp->lock); return err; @@ -1897,6 +1977,13 @@ gst_omx_port_deallocate_buffers_unlocked (GstOMXPort * port) /* We still try to deallocate all buffers */ } + if (port->pool) { + g_rec_mutex_lock (&comp->fill_lock); + gst_object_unref (port->pool); + port->pool = NULL; + g_rec_mutex_unlock (&comp->fill_lock); + } + /* We only allow deallocation of buffers after they * were all released from the port, either by flushing * the port or by disabling it. @@ -2007,12 +2094,30 @@ gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled) OMX_SendCommand (comp->handle, OMX_CommandPortEnable, port->index, NULL); } else { + g_rec_mutex_lock (&comp->fill_lock); + + if (port->pool) { + gst_buffer_pool_set_active (port->pool, FALSE); + + if (comp->fill_task) { + gst_task_pause (comp->fill_task); + GST_TASK_SIGNAL (comp->fill_task); + } + } + + g_rec_mutex_unlock (&comp->fill_lock); + err = OMX_SendCommand (comp->handle, OMX_CommandPortDisable, port->index, NULL); if (port->port_def.eDir == OMX_DirOutput) { - g_queue_clear (&port->pending_buffers); + while (!g_queue_is_empty (&port->pending_buffers)) { + GstOMXBuffer *buf = g_queue_pop_head (&port->pending_buffers); + if (buf->pool_buffer) { + gst_buffer_unref (buf->pool_buffer); + } + } } } @@ -2137,6 +2242,70 @@ gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled) return err; } +static void +gst_omx_port_fill_loop (GstOMXPort * port) +{ + GstOMXComponent *comp = port->comp; + GstBufferPool *pool = NULL; + GstBuffer *buffer; + GstFlowReturn ret; + GstBufferPoolAcquireParams params = { 0, }; + + GST_DEBUG_OBJECT (comp->parent, "Entering fill task %p %d", port->pool, port->flushing); + + if (!port->pool) { + gst_task_pause (comp->fill_task); + return; + } + + if (port->flushing) { + gst_task_pause (comp->fill_task); + return; + } + + pool = port->pool; + gst_object_ref (pool); + + g_rec_mutex_unlock (&comp->fill_lock); + + ret = gst_buffer_pool_acquire_buffer (pool, &buffer, ¶ms); + + g_rec_mutex_lock (&comp->fill_lock); + + if (port->flushing) { + if (ret == GST_FLOW_OK) { + gst_buffer_unref (buffer); + } + } else if (ret == GST_FLOW_OK) { + OMX_ERRORTYPE err; + GstOMXBufferMeta *meta = gst_buffer_get_omx_buffer_meta (buffer); + + GST_DEBUG_OBJECT (comp->parent, "Filling buffer %p (%p) from %s port %u", + buffer, meta, comp->name, port->index); + + meta->omx_buf->nOffset = 0; + meta->omx_buf->nFilledLen = 0; + meta->omx_buf->nFlags = 0; + + err = OMX_FillThisBuffer (comp->handle, meta->omx_buf); + + if (err != OMX_ErrorNone) { + gst_buffer_unref (buffer); + } else { + GstOMXBuffer *buf = meta->omx_buf->pAppPrivate; + buf->used = TRUE; + + g_mutex_lock (&comp->lock); + ++port->num_used_buffers; + g_mutex_unlock (&comp->lock); + } + } + + GST_DEBUG_OBJECT (comp->parent, "Leaving fill task"); + + gst_object_unref (pool); +} + static OMX_ERRORTYPE gst_omx_port_populate_unlocked (GstOMXPort * port) { @@ -2165,7 +2334,15 @@ gst_omx_port_populate_unlocked (GstOMXPort * port) goto done; } - if (port->port_def.eDir == OMX_DirOutput && port->buffers && !port->tunneled) { + if (port->port_def.eDir == OMX_DirOutput && port->pool) { + if (!comp->fill_task) { + comp->fill_task = gst_task_new ((GstTaskFunction) gst_omx_port_fill_loop, + port, NULL); + gst_task_set_lock (comp->fill_task, &comp->fill_lock); + } + gst_task_start (comp->fill_task); + GST_DEBUG_OBJECT (comp->parent, "Starting fill task"); + } else if (port->port_def.eDir == OMX_DirOutput && port->buffers && !port->tunneled) { /* Enqueue all buffers for the component to fill */ guint i, n = port->buffers->len; diff --git a/omx/gstomx.h b/omx/gstomx.h index 9d5882c..8306808 100644 --- a/omx/gstomx.h +++ b/omx/gstomx.h @@ -53,6 +53,7 @@ #include <OMX_Core.h> #include <OMX_Component.h> + #ifdef USE_OMX_TARGET_RPI #include <OMX_Broadcom.h> #endif @@ -238,6 +239,7 @@ struct _GstOMXMessage { struct _GstOMXPort { GstOMXComponent *comp; + GstBufferPool *pool; guint32 index; gboolean tunneled; @@ -275,6 +277,9 @@ struct _GstOMXComponent { GPtrArray *ports; /* Contains GstOMXPort* */ gint n_in_ports, n_out_ports; + GstTask *fill_task; + GRecMutex fill_lock; + /* Locking order: lock -> messages_lock * * Never hold lock while waiting for messages_cond @@ -297,6 +302,7 @@ struct _GstOMXComponent { struct _GstOMXBuffer { GstOMXPort *port; OMX_BUFFERHEADERTYPE *omx_buf; + GstBuffer *pool_buffer; /* TRUE if the buffer is used by the port, i.e. * between {Empty,Fill}ThisBuffer and the callback @@ -305,9 +311,6 @@ struct _GstOMXBuffer { /* Cookie of the settings when this buffer was allocated */ gint settings_cookie; - - /* TRUE if this is an EGLImage */ - gboolean eglimage; }; struct _GstOMXClassData { @@ -372,9 +375,10 @@ OMX_ERRORTYPE gst_omx_port_release_buffer (GstOMXPort *port, GstOMXBuffer *b OMX_ERRORTYPE gst_omx_port_set_flushing (GstOMXPort *port, GstClockTime timeout, gboolean flush); gboolean gst_omx_port_is_flushing (GstOMXPort *port); +typedef OMX_ERRORTYPE (*GstOMXPortUseBuffer) (GstOMXPort *port, GstBuffer *buffer, gpointer data, OMX_BUFFERHEADERTYPE **header); + OMX_ERRORTYPE gst_omx_port_allocate_buffers (GstOMXPort *port); -OMX_ERRORTYPE gst_omx_port_use_buffers (GstOMXPort *port, const GList *buffers); -OMX_ERRORTYPE gst_omx_port_use_eglimages (GstOMXPort *port, const GList *images); +OMX_ERRORTYPE gst_omx_port_use_buffers (GstOMXPort *port, GstBufferPool *pool, GstOMXPortUseBuffer use_buffer); OMX_ERRORTYPE gst_omx_port_deallocate_buffers (GstOMXPort *port); OMX_ERRORTYPE gst_omx_port_populate (GstOMXPort *port); OMX_ERRORTYPE gst_omx_port_wait_buffers_released (GstOMXPort * port, GstClockTime timeout); diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c deleted file mode 100644 index b57612d..0000000 --- a/omx/gstomxbufferpool.c +++ /dev/null @@ -1,633 +0,0 @@ -/* - * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. - * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd. - * Copyright (C) 2013, Collabora Ltd. - * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk> - * - * 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 - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstomxbufferpool.h" - -GST_DEBUG_CATEGORY_STATIC (gst_omx_buffer_pool_debug_category); -#define GST_CAT_DEFAULT gst_omx_buffer_pool_debug_category - -typedef struct _GstOMXMemory GstOMXMemory; -typedef struct _GstOMXMemoryAllocator GstOMXMemoryAllocator; -typedef struct _GstOMXMemoryAllocatorClass GstOMXMemoryAllocatorClass; - -struct _GstOMXMemory -{ - GstMemory mem; - - GstOMXBuffer *buf; -}; - -struct _GstOMXMemoryAllocator -{ - GstAllocator parent; -}; - -struct _GstOMXMemoryAllocatorClass -{ - GstAllocatorClass parent_class; -}; - -#define GST_OMX_MEMORY_TYPE "openmax" - -static GstMemory * -gst_omx_memory_allocator_alloc_dummy (GstAllocator * allocator, gsize size, - GstAllocationParams * params) -{ - g_assert_not_reached (); - return NULL; -} - -static void -gst_omx_memory_allocator_free (GstAllocator * allocator, GstMemory * mem) -{ - GstOMXMemory *omem = (GstOMXMemory *) mem; - - /* TODO: We need to remember which memories are still used - * so we can wait until everything is released before allocating - * new memory - */ - - g_slice_free (GstOMXMemory, omem); -} - -static gpointer -gst_omx_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) -{ - GstOMXMemory *omem = (GstOMXMemory *) mem; - - return omem->buf->omx_buf->pBuffer + omem->mem.offset; -} - -static void -gst_omx_memory_unmap (GstMemory * mem) -{ -} - -static GstMemory * -gst_omx_memory_share (GstMemory * mem, gssize offset, gssize size) -{ - g_assert_not_reached (); - return NULL; -} - -GType gst_omx_memory_allocator_get_type (void); -G_DEFINE_TYPE (GstOMXMemoryAllocator, gst_omx_memory_allocator, - GST_TYPE_ALLOCATOR); - -#define GST_TYPE_OMX_MEMORY_ALLOCATOR (gst_omx_memory_allocator_get_type()) -#define GST_IS_OMX_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OMX_MEMORY_ALLOCATOR)) - -static void -gst_omx_memory_allocator_class_init (GstOMXMemoryAllocatorClass * klass) -{ - GstAllocatorClass *allocator_class; - - allocator_class = (GstAllocatorClass *) klass; - - allocator_class->alloc = gst_omx_memory_allocator_alloc_dummy; - allocator_class->free = gst_omx_memory_allocator_free; -} - -static void -gst_omx_memory_allocator_init (GstOMXMemoryAllocator * allocator) -{ - GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); - - alloc->mem_type = GST_OMX_MEMORY_TYPE; - alloc->mem_map = gst_omx_memory_map; - alloc->mem_unmap = gst_omx_memory_unmap; - alloc->mem_share = gst_omx_memory_share; - - /* default copy & is_span */ - - GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); -} - -static GstMemory * -gst_omx_memory_allocator_alloc (GstAllocator * allocator, GstMemoryFlags flags, - GstOMXBuffer * buf) -{ - GstOMXMemory *mem; - gint align; - - /* FIXME: We don't allow sharing because we need to know - * when the memory becomes unused and can only then put - * it back to the pool. Which is done in the pool's release - * function - */ - flags |= GST_MEMORY_FLAG_NO_SHARE; - - /* GStreamer uses a bitmask for the alignment while - * OMX uses the alignment itself. So we have to convert - * here */ - align = buf->port->port_def.nBufferAlignment; - if (align > 0) - align -= 1; - if (((align + 1) & align) != 0) { - GST_WARNING ("Invalid alignment that is not a power of two: %u", - (guint) buf->port->port_def.nBufferAlignment); - align = 0; - } - - mem = g_slice_new (GstOMXMemory); - /* the shared memory is always readonly */ - gst_memory_init (GST_MEMORY_CAST (mem), flags, allocator, NULL, - buf->omx_buf->nAllocLen, align, 0, buf->omx_buf->nAllocLen); - - mem->buf = buf; - - return GST_MEMORY_CAST (mem); -} - -/* Buffer pool for the buffers of an OpenMAX port. - * - * This pool is only used if we either passed buffers from another - * pool to the OMX port or provide the OMX buffers directly to other - * elements. - * - * - * A buffer is in the pool if it is currently owned by the port, - * i.e. after OMX_{Fill,Empty}ThisBuffer(). A buffer is outside - * the pool after it was taken from the port after it was handled - * by the port, i.e. {Empty,Fill}BufferDone. - * - * Buffers can be allocated by us (OMX_AllocateBuffer()) or allocated - * by someone else and (temporarily) passed to this pool - * (OMX_UseBuffer(), OMX_UseEGLImage()). In the latter case the pool of - * the buffer will be overriden, and restored in free_buffer(). Other - * buffers are just freed there. - * - * The pool always has a fixed number of minimum and maximum buffers - * and these are allocated while starting the pool and released afterwards. - * They correspond 1:1 to the OMX buffers of the port, which are allocated - * before the pool is started. - * - * Acquiring a buffer from this pool happens after the OMX buffer has - * been acquired from the port. gst_buffer_pool_acquire_buffer() is - * supposed to return the buffer that corresponds to the OMX buffer. - * - * For buffers provided to upstream, the buffer will be passed to - * the component manually when it arrives and then unreffed. If the - * buffer is released before reaching the component it will be just put - * back into the pool as if EmptyBufferDone has happened. If it was - * passed to the component, it will be back into the pool when it was - * released and EmptyBufferDone has happened. - * - * For buffers provided to downstream, the buffer will be returned - * back to the component (OMX_FillThisBuffer()) when it is released. - */ - -static GQuark gst_omx_buffer_data_quark = 0; - -#define DEBUG_INIT \ - GST_DEBUG_CATEGORY_INIT (gst_omx_buffer_pool_debug_category, "omxbufferpool", 0, \ - "debug category for gst-omx buffer pool base class"); - -G_DEFINE_TYPE_WITH_CODE (GstOMXBufferPool, gst_omx_buffer_pool, - GST_TYPE_BUFFER_POOL, DEBUG_INIT); - -static void gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, - GstBuffer * buffer); - -static gboolean -gst_omx_buffer_pool_start (GstBufferPool * bpool) -{ - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); - - /* Only allow to start the pool if we still are attached - * to a component and port */ - GST_OBJECT_LOCK (pool); - if (!pool->component || !pool->port) { - GST_OBJECT_UNLOCK (pool); - return FALSE; - } - GST_OBJECT_UNLOCK (pool); - - return - GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->start (bpool); -} - -static gboolean -gst_omx_buffer_pool_stop (GstBufferPool * bpool) -{ - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); - gint i = 0; - - /* When not using the default GstBufferPool::GstAtomicQueue then - * GstBufferPool::free_buffer is not called while stopping the pool - * (because the queue is empty) */ - for (i = 0; i < pool->buffers->len; i++) - GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer - (bpool, g_ptr_array_index (pool->buffers, i)); - - /* Remove any buffers that are there */ - g_ptr_array_set_size (pool->buffers, 0); - - if (pool->caps) - gst_caps_unref (pool->caps); - pool->caps = NULL; - - pool->add_videometa = FALSE; - - return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->stop (bpool); -} - -static const gchar ** -gst_omx_buffer_pool_get_options (GstBufferPool * bpool) -{ - static const gchar *raw_video_options[] = - { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL }; - static const gchar *options[] = { NULL }; - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); - - GST_OBJECT_LOCK (pool); - if (pool->port && pool->port->port_def.eDomain == OMX_PortDomainVideo - && pool->port->port_def.format.video.eCompressionFormat == - OMX_VIDEO_CodingUnused) { - GST_OBJECT_UNLOCK (pool); - return raw_video_options; - } - GST_OBJECT_UNLOCK (pool); - - return options; -} - -static gboolean -gst_omx_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) -{ - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); - GstCaps *caps; - - GST_OBJECT_LOCK (pool); - - if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)) - goto wrong_config; - - if (caps == NULL) - goto no_caps; - - if (pool->port && pool->port->port_def.eDomain == OMX_PortDomainVideo - && pool->port->port_def.format.video.eCompressionFormat == - OMX_VIDEO_CodingUnused) { - GstVideoInfo info; - - /* now parse the caps from the config */ - if (!gst_video_info_from_caps (&info, caps)) - goto wrong_video_caps; - - /* enable metadata based on config of the pool */ - pool->add_videometa = - gst_buffer_pool_config_has_option (config, - GST_BUFFER_POOL_OPTION_VIDEO_META); - - pool->video_info = info; - } - - if (pool->caps) - gst_caps_unref (pool->caps); - pool->caps = gst_caps_ref (caps); - - GST_OBJECT_UNLOCK (pool); - - return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->set_config - (bpool, config); - - /* ERRORS */ -wrong_config: - { - GST_OBJECT_UNLOCK (pool); - GST_WARNING_OBJECT (pool, "invalid config"); - return FALSE; - } -no_caps: - { - GST_OBJECT_UNLOCK (pool); - GST_WARNING_OBJECT (pool, "no caps in config"); - return FALSE; - } -wrong_video_caps: - { - GST_OBJECT_UNLOCK (pool); - GST_WARNING_OBJECT (pool, - "failed getting geometry from caps %" GST_PTR_FORMAT, caps); - return FALSE; - } -} - -static GstFlowReturn -gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool, - GstBuffer ** buffer, GstBufferPoolAcquireParams * params) -{ - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); - GstBuffer *buf; - GstOMXBuffer *omx_buf; - - g_return_val_if_fail (pool->allocating, GST_FLOW_ERROR); - - omx_buf = g_ptr_array_index (pool->port->buffers, pool->current_buffer_index); - g_return_val_if_fail (omx_buf != NULL, GST_FLOW_ERROR); - - if (pool->other_pool) { - guint i, n; - - buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index); - g_assert (pool->other_pool == buf->pool); - gst_object_replace ((GstObject **) & buf->pool, NULL); - - n = gst_buffer_n_memory (buf); - for (i = 0; i < n; i++) { - GstMemory *mem = gst_buffer_peek_memory (buf, i); - - /* FIXME: We don't allow sharing because we need to know - * when the memory becomes unused and can only then put - * it back to the pool. Which is done in the pool's release - * function - */ - GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_NO_SHARE); - } - - if (pool->add_videometa) { - GstVideoMeta *meta; - - meta = gst_buffer_get_video_meta (buf); - if (!meta) { - gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE, - GST_VIDEO_INFO_FORMAT (&pool->video_info), - GST_VIDEO_INFO_WIDTH (&pool->video_info), - GST_VIDEO_INFO_HEIGHT (&pool->video_info)); - } - } - - pool->need_copy = FALSE; - } else { - GstMemory *mem; - const guint nstride = pool->port->port_def.format.video.nStride; - const guint nslice = pool->port->port_def.format.video.nSliceHeight; - gsize offset[GST_VIDEO_MAX_PLANES] = { 0, }; - gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, }; - - mem = gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf); - buf = gst_buffer_new (); - gst_buffer_append_memory (buf, mem); - g_ptr_array_add (pool->buffers, buf); - - switch (GST_VIDEO_INFO_FORMAT (&pool->video_info)) { - case GST_VIDEO_FORMAT_ABGR: - case GST_VIDEO_FORMAT_ARGB: - case GST_VIDEO_FORMAT_RGB16: - case GST_VIDEO_FORMAT_BGR16: - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: - case GST_VIDEO_FORMAT_YVYU: - case GST_VIDEO_FORMAT_GRAY8: - break; - case GST_VIDEO_FORMAT_I420: - stride[1] = nstride / 2; - offset[1] = offset[0] + stride[0] * nslice; - stride[2] = nstride / 2; - offset[2] = offset[1] + (stride[1] * nslice / 2); - break; - case GST_VIDEO_FORMAT_NV12: - case GST_VIDEO_FORMAT_NV16: - stride[1] = nstride; - offset[1] = offset[0] + stride[0] * nslice; - break; - default: - g_assert_not_reached (); - break; - } - - if (pool->add_videometa) { - pool->need_copy = FALSE; - } else { - GstVideoInfo info; - gboolean need_copy = FALSE; - gint i; - - gst_video_info_init (&info); - gst_video_info_set_format (&info, - GST_VIDEO_INFO_FORMAT (&pool->video_info), - GST_VIDEO_INFO_WIDTH (&pool->video_info), - GST_VIDEO_INFO_HEIGHT (&pool->video_info)); - - for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&pool->video_info); i++) { - if (info.stride[i] != stride[i] || info.offset[i] != offset[i]) { - need_copy = TRUE; - break; - } - } - - pool->need_copy = need_copy; - } - - if (pool->need_copy || pool->add_videometa) { - /* We always add the videometa. It's the job of the user - * to copy the buffer if pool->need_copy is TRUE - */ - gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, - GST_VIDEO_INFO_FORMAT (&pool->video_info), - GST_VIDEO_INFO_WIDTH (&pool->video_info), - GST_VIDEO_INFO_HEIGHT (&pool->video_info), - GST_VIDEO_INFO_N_PLANES (&pool->video_info), offset, stride); - } - } - - gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf), - gst_omx_buffer_data_quark, omx_buf, NULL); - - *buffer = buf; - - pool->current_buffer_index++; - - return GST_FLOW_OK; -} - -static void -gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer) -{ - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); - - /* If the buffers belong to another pool, restore them now */ - GST_OBJECT_LOCK (pool); - if (pool->other_pool) { - gst_object_replace ((GstObject **) & buffer->pool, - (GstObject *) pool->other_pool); - } - GST_OBJECT_UNLOCK (pool); - - gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer), - gst_omx_buffer_data_quark, NULL, NULL); - - GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->free_buffer (bpool, - buffer); -} - -static GstFlowReturn -gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool, - GstBuffer ** buffer, GstBufferPoolAcquireParams * params) -{ - GstFlowReturn ret; - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); - - if (pool->port->port_def.eDir == OMX_DirOutput) { - GstBuffer *buf; - - g_return_val_if_fail (pool->current_buffer_index != -1, GST_FLOW_ERROR); - - buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index); - g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); - *buffer = buf; - ret = GST_FLOW_OK; - - /* If it's our own memory we have to set the sizes */ - if (!pool->other_pool) { - GstMemory *mem = gst_buffer_peek_memory (*buffer, 0); - - g_assert (mem - && g_strcmp0 (mem->allocator->mem_type, GST_OMX_MEMORY_TYPE) == 0); - mem->size = ((GstOMXMemory *) mem)->buf->omx_buf->nFilledLen; - mem->offset = ((GstOMXMemory *) mem)->buf->omx_buf->nOffset; - } - } else { - /* Acquire any buffer that is available to be filled by upstream */ - ret = - GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->acquire_buffer - (bpool, buffer, params); - } - - return ret; -} - -static void -gst_omx_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) -{ - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); - OMX_ERRORTYPE err; - GstOMXBuffer *omx_buf; - - g_assert (pool->component && pool->port); - - if (!pool->allocating && !pool->deactivated) { - omx_buf = - gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer), - gst_omx_buffer_data_quark); - if (pool->port->port_def.eDir == OMX_DirOutput && !omx_buf->used) { - /* Release back to the port, can be filled again */ - err = gst_omx_port_release_buffer (pool->port, omx_buf); - if (err != OMX_ErrorNone) { - GST_ELEMENT_ERROR (pool->element, LIBRARY, SETTINGS, (NULL), - ("Failed to relase output buffer to component: %s (0x%08x)", - gst_omx_error_to_string (err), err)); - } - } else if (!omx_buf->used) { - /* TODO: Implement. - * - * If not used (i.e. was not passed to the component) this should do - * the same as EmptyBufferDone. - * If it is used (i.e. was passed to the component) this should do - * nothing until EmptyBufferDone. - * - * EmptyBufferDone should release the buffer to the pool so it can - * be allocated again - * - * Needs something to call back here in EmptyBufferDone, like keeping - * a ref on the buffer in GstOMXBuffer until EmptyBufferDone... which - * would ensure that the buffer is always unused when this is called. - */ - g_assert_not_reached (); - GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer - (bpool, buffer); - } - } -} - -static void -gst_omx_buffer_pool_finalize (GObject * object) -{ - GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (object); - - if (pool->element) - gst_object_unref (pool->element); - pool->element = NULL; - - if (pool->buffers) - g_ptr_array_unref (pool->buffers); - pool->buffers = NULL; - - if (pool->other_pool) - gst_object_unref (pool->other_pool); - pool->other_pool = NULL; - - if (pool->allocator) - gst_object_unref (pool->allocator); - pool->allocator = NULL; - - if (pool->caps) - gst_caps_unref (pool->caps); - pool->caps = NULL; - - G_OBJECT_CLASS (gst_omx_buffer_pool_parent_class)->finalize (object); -} - -static void -gst_omx_buffer_pool_class_init (GstOMXBufferPoolClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; - - gst_omx_buffer_data_quark = g_quark_from_static_string ("GstOMXBufferData"); - - gobject_class->finalize = gst_omx_buffer_pool_finalize; - gstbufferpool_class->start = gst_omx_buffer_pool_start; - gstbufferpool_class->stop = gst_omx_buffer_pool_stop; - gstbufferpool_class->get_options = gst_omx_buffer_pool_get_options; - gstbufferpool_class->set_config = gst_omx_buffer_pool_set_config; - gstbufferpool_class->alloc_buffer = gst_omx_buffer_pool_alloc_buffer; - gstbufferpool_class->free_buffer = gst_omx_buffer_pool_free_buffer; - gstbufferpool_class->acquire_buffer = gst_omx_buffer_pool_acquire_buffer; - gstbufferpool_class->release_buffer = gst_omx_buffer_pool_release_buffer; -} - -static void -gst_omx_buffer_pool_init (GstOMXBufferPool * pool) -{ - pool->buffers = g_ptr_array_new (); - pool->allocator = g_object_new (gst_omx_memory_allocator_get_type (), NULL); -} - -GstBufferPool * -gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, - GstOMXPort * port) -{ - GstOMXBufferPool *pool; - - pool = g_object_new (gst_omx_buffer_pool_get_type (), NULL); - pool->element = gst_object_ref (element); - pool->component = component; - pool->port = port; - - return GST_BUFFER_POOL (pool); -} diff --git a/omx/gstomxbufferpool.h b/omx/gstomxbufferpool.h deleted file mode 100644 index 76f9680..0000000 --- a/omx/gstomxbufferpool.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2014 Advanced Micro Devices, Inc. - * Author: Christian König <christian.koenig@amd.com> - * - * 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_OMX_BUFFER_POOL_H__ -#define __GST_OMX_BUFFER_POOL_H__ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gst/gst.h> -#include <gst/video/gstvideometa.h> -#include <gst/video/gstvideopool.h> - -#include "gstomx.h" - -G_BEGIN_DECLS - -#define GST_TYPE_OMX_BUFFER_POOL \ - (gst_omx_buffer_pool_get_type()) -#define GST_OMX_BUFFER_POOL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OMX_BUFFER_POOL,GstOMXBufferPool)) -#define GST_IS_OMX_BUFFER_POOL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OMX_BUFFER_POOL)) - -typedef struct _GstOMXBufferPool GstOMXBufferPool; -typedef struct _GstOMXBufferPoolClass GstOMXBufferPoolClass; - -struct _GstOMXBufferPool -{ - GstVideoBufferPool parent; - - GstElement *element; - - GstCaps *caps; - gboolean add_videometa; - gboolean need_copy; - GstVideoInfo video_info; - - /* Owned by element, element has to stop this pool before - * it destroys component or port */ - GstOMXComponent *component; - GstOMXPort *port; - - /* For handling OpenMAX allocated memory */ - GstAllocator *allocator; - - /* Set from outside this pool */ - /* TRUE if we're currently allocating all our buffers */ - gboolean allocating; - /* TRUE if the pool is not used anymore */ - gboolean deactivated; - - /* For populating the pool from another one */ - GstBufferPool *other_pool; - GPtrArray *buffers; - - /* Used during acquire for output ports to - * specify which buffer has to be retrieved - * and during alloc, which buffer has to be - * wrapped - */ - gint current_buffer_index; -}; - -struct _GstOMXBufferPoolClass -{ - GstVideoBufferPoolClass parent_class; -}; - -GType gst_omx_buffer_pool_get_type (void); - -GstBufferPool *gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, GstOMXPort * port); - -G_END_DECLS - -#endif /* __GST_OMX_BUFFER_POOL_H__ */ diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c index e607ed8..802ac18 100644 --- a/omx/gstomxvideodec.c +++ b/omx/gstomxvideodec.c @@ -48,7 +48,6 @@ #include <string.h> -#include "gstomxbufferpool.h" #include "gstomxvideo.h" #include "gstomxvideodec.h" @@ -93,7 +92,6 @@ enum GST_DEBUG_CATEGORY_INIT (gst_omx_video_dec_debug_category, "omxvideodec", 0, \ "debug category for gst-omx video decoder base class"); - G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec, GST_TYPE_VIDEO_DECODER, DEBUG_INIT); @@ -544,6 +542,29 @@ done: return ret; } +#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL) +static OMX_ERRORTYPE +gst_omx_video_dec_use_egl_image (GstOMXPort *port, GstBuffer *buffer, + gointer data, OMX_BUFFERHEADERTYPE **header) +{ + GstMemory *mem; + + if (gst_buffer_n_memory (buffer) != 1 + || !(mem = gst_buffer_peek_memory (buffer, 0)) + || g_strcmp0 (mem->allocator->mem_type, + GST_EGL_IMAGE_MEMORY_TYPE) != 0) { + GST_INFO_OBJECT (port->comp->parent, "Failed to allocated EGLImage"); + return OMX_ErrorUndefined; + } + + gst_egl_image_memory_set_orientation (mem, + GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP); + + return OMX_UseEGLImage (port->comp->handle, header, port->index, data, + gst_egl_image_memory_get_image (mem)); +} +#endif + static OMX_ERRORTYPE gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) { @@ -551,9 +572,14 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) GstOMXPort *port; GstBufferPool *pool; GstStructure *config; - gboolean eglimage = FALSE, add_videometa = FALSE; + gboolean add_videometa = FALSE; + gboolean was_enabled = TRUE; +#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL) + gboolean eglimage = FALSE +#endif GstCaps *caps = NULL; guint min = 0, max = 0; + GstOMXPortUseBuffer use_buffer = NULL; GstVideoCodecState *state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self)); @@ -599,9 +625,6 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL) eglimage = self->eglimage && (allocator && GST_IS_GL_MEMORY_EGL_ALLOCATOR (allocator)); -#else - /* TODO: Implement something that works for other targets too */ - eglimage = FALSE; #endif caps = caps ? gst_caps_ref (caps) : NULL; @@ -624,145 +647,85 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) } #endif - if (caps) - self->out_port_pool = - gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->dec, port); - #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL) if (eglimage) { - GList *buffers = NULL; - GList *images = NULL; - gint i; GstBufferPoolAcquireParams params = { 0, }; EGLDisplay egl_display = EGL_NO_DISPLAY; + GstBuffer *buffer; - GST_DEBUG_OBJECT (self, "Trying to allocate %d EGLImages", min); - - for (i = 0; i < min; i++) { - GstBuffer *buffer; + if (gst_buffer_pool_acquire_buffer (pool, &buffer, ¶ms) + == GST_FLOW_OK) { GstMemory *mem; - GstGLMemoryEGL *gl_mem; - - if (gst_buffer_pool_acquire_buffer (pool, &buffer, ¶ms) != GST_FLOW_OK - || gst_buffer_n_memory (buffer) != 1 - || !(mem = gst_buffer_peek_memory (buffer, 0)) - || !GST_IS_GL_MEMORY_EGL_ALLOCATOR (mem->allocator)) { - GST_INFO_OBJECT (self, "Failed to allocated %d-th EGLImage", i); - g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); - g_list_free (images); - buffers = NULL; - images = NULL; - /* TODO: For non-RPi targets we want to use the normal memory code below */ - /* Retry without EGLImage */ - err = OMX_ErrorUndefined; - goto done; - } - gl_mem = (GstGLMemoryEGL *) mem; - buffers = g_list_append (buffers, buffer); - /* FIXME: replace with the affine transformation meta */ - gl_mem->image->orientation = - GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP; - images = g_list_append (images, gst_gl_memory_egl_get_image (gl_mem)); - if (egl_display == EGL_NO_DISPLAY) + if (gst_buffer_n_memory (buffer) == 1 + && (mem = gst_buffer_peek_memory (buffer, 0)) + && g_strcmp0 (mem->allocator->mem_type, + GST_EGL_IMAGE_MEMORY_TYPE) == 0) { egl_display = gst_gl_memory_egl_get_display (gl_mem); + } + gst_buffer_unref (buffer); } - GST_DEBUG_OBJECT (self, "Allocated %d EGLImages successfully", min); - - /* Everything went fine? */ - if (eglimage) { - GST_DEBUG_OBJECT (self, "Setting EGLDisplay"); - self->egl_out_port->port_def.format.video.pNativeWindow = egl_display; - err = - gst_omx_port_update_port_definition (self->egl_out_port, - &self->egl_out_port->port_def); - if (err != OMX_ErrorNone) { - GST_INFO_OBJECT (self, - "Failed to set EGLDisplay on port: %s (0x%08x)", - gst_omx_error_to_string (err), err); - g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); - g_list_free (images); - /* TODO: For non-RPi targets we want to use the normal memory code below */ - /* Retry without EGLImage */ - goto done; - } else { - GList *l; - - if (min != port->port_def.nBufferCountActual) { - err = gst_omx_port_update_port_definition (port, NULL); - if (err == OMX_ErrorNone) { - port->port_def.nBufferCountActual = min; - err = gst_omx_port_update_port_definition (port, &port->port_def); - } - - if (err != OMX_ErrorNone) { - GST_INFO_OBJECT (self, - "Failed to configure %u output buffers: %s (0x%08x)", min, - gst_omx_error_to_string (err), err); - g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); - g_list_free (images); - /* TODO: For non-RPi targets we want to use the normal memory code below */ - /* Retry without EGLImage */ - - goto done; - } - } + if (egl_display == EGL_NO_DISPLAY) { + GST_WARN_OBJECT (self, "Failed to query EGLDisplay"); + err = OMX_ErrorUndefined; + goto done; + } - if (!gst_omx_port_is_enabled (port)) { - err = gst_omx_port_set_enabled (port, TRUE); - if (err != OMX_ErrorNone) { - GST_INFO_OBJECT (self, - "Failed to enable port: %s (0x%08x)", - gst_omx_error_to_string (err), err); - g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); - g_list_free (images); - /* TODO: For non-RPi targets we want to use the normal memory code below */ - /* Retry without EGLImage */ - goto done; - } - } + GST_DEBUG_OBJECT (self, "Setting EGLDisplay"); + self->egl_out_port->port_def.format.video.pNativeWindow = egl_display; + err = + gst_omx_port_update_port_definition (self->egl_out_port, + &self->egl_out_port->port_def); + if (err != OMX_ErrorNone) { + GST_INFO_OBJECT (self, + "Failed to set EGLDisplay on port: %s (0x%08x)", + gst_omx_error_to_string (err), err); + goto done; + } - err = gst_omx_port_use_eglimages (port, images); - g_list_free (images); + use_buffer = gst_omx_video_dec_use_egl_image; + } +#endif - if (err != OMX_ErrorNone) { - GST_INFO_OBJECT (self, - "Failed to pass EGLImages to port: %s (0x%08x)", - gst_omx_error_to_string (err), err); - g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); - /* TODO: For non-RPi targets we want to use the normal memory code below */ - /* Retry without EGLImage */ - goto done; - } + if (min != port->port_def.nBufferCountActual) { + err = gst_omx_port_update_port_definition (port, NULL); + if (err == OMX_ErrorNone) { + port->port_def.nBufferCountActual = min; + err = gst_omx_port_update_port_definition (port, &port->port_def); + } - err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND); - if (err != OMX_ErrorNone) { - GST_INFO_OBJECT (self, - "Failed to wait until port is enabled: %s (0x%08x)", - gst_omx_error_to_string (err), err); - g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); - /* TODO: For non-RPi targets we want to use the normal memory code below */ - /* Retry without EGLImage */ - goto done; - } + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "Failed to configure %u output buffers: %s (0x%08x)", min, + gst_omx_error_to_string (err), err); + goto done; + } + } - GST_DEBUG_OBJECT (self, "Populating internal buffer pool"); - GST_OMX_BUFFER_POOL (self->out_port_pool)->other_pool = - GST_BUFFER_POOL (gst_object_ref (pool)); - for (l = buffers; l; l = l->next) { - g_ptr_array_add (GST_OMX_BUFFER_POOL (self->out_port_pool)->buffers, - l->data); - } - g_list_free (buffers); - /* All good and done, set caps below */ - } + if (!gst_omx_port_is_enabled (port)) { + err = gst_omx_port_set_enabled (port, TRUE); + if (err != OMX_ErrorNone) { + GST_INFO_OBJECT (self, + "Failed to enable port: %s (0x%08x)", + gst_omx_error_to_string (err), err); + goto done; } + was_enabled = FALSE; } -#endif - /* If not using EGLImage or trying to use EGLImage failed */ - if (!eglimage) { - gboolean was_enabled = TRUE; + if (use_buffer) { + err = gst_omx_port_use_buffers (port, pool, use_buffer); + } else { + err = gst_omx_port_allocate_buffers (port); + } + if (err != OMX_ErrorNone && min > port->port_def.nBufferCountMin) { + GST_ERROR_OBJECT (self, + "Failed to allocate required number of buffers %d, trying less and copying", + min); + min = port->port_def.nBufferCountMin; + + if (!was_enabled) + gst_omx_port_set_enabled (port, FALSE); if (min != port->port_def.nBufferCountActual) { err = gst_omx_port_update_port_definition (port, NULL); @@ -779,17 +742,6 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) } } - if (!gst_omx_port_is_enabled (port)) { - err = gst_omx_port_set_enabled (port, TRUE); - if (err != OMX_ErrorNone) { - GST_INFO_OBJECT (self, - "Failed to enable port: %s (0x%08x)", - gst_omx_error_to_string (err), err); - goto done; - } - was_enabled = FALSE; - } - err = gst_omx_port_allocate_buffers (port); if (err != OMX_ErrorNone && min > port->port_def.nBufferCountMin) { GST_ERROR_OBJECT (self, @@ -823,68 +775,31 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) } err = gst_omx_port_allocate_buffers (port); + } /* Can't provide buffers downstream in this case */ - gst_caps_replace (&caps, NULL); - } + gst_caps_replace (&caps, NULL); + } + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, "Failed to allocate %d buffers: %s (0x%08x)", min, + gst_omx_error_to_string (err), err); + goto done; + } + + if (!was_enabled) { + err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND); if (err != OMX_ErrorNone) { - GST_ERROR_OBJECT (self, "Failed to allocate %d buffers: %s (0x%08x)", min, + GST_ERROR_OBJECT (self, + "Failed to wait until port is enabled: %s (0x%08x)", gst_omx_error_to_string (err), err); goto done; } - - if (!was_enabled) { - err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND); - if (err != OMX_ErrorNone) { - GST_ERROR_OBJECT (self, - "Failed to wait until port is enabled: %s (0x%08x)", - gst_omx_error_to_string (err), err); - goto done; - } - } - - } err = OMX_ErrorNone; - if (caps) { - config = gst_buffer_pool_get_config (self->out_port_pool); - - if (add_videometa) - gst_buffer_pool_config_add_option (config, - GST_BUFFER_POOL_OPTION_VIDEO_META); - - gst_buffer_pool_config_set_params (config, caps, - self->dec_out_port->port_def.nBufferSize, min, max); - - if (!gst_buffer_pool_set_config (self->out_port_pool, config)) { - GST_INFO_OBJECT (self, "Failed to set config on internal pool"); - gst_object_unref (self->out_port_pool); - self->out_port_pool = NULL; - goto done; - } - - GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = TRUE; - /* This now allocates all the buffers */ - if (!gst_buffer_pool_set_active (self->out_port_pool, TRUE)) { - GST_INFO_OBJECT (self, "Failed to activate internal pool"); - gst_object_unref (self->out_port_pool); - self->out_port_pool = NULL; - } else { - GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = FALSE; - } - } else if (self->out_port_pool) { - gst_object_unref (self->out_port_pool); - self->out_port_pool = NULL; - } - done: - if (!self->out_port_pool && err == OMX_ErrorNone) - GST_DEBUG_OBJECT (self, - "Not using our internal pool and copying buffers for downstream"); - if (caps) gst_caps_unref (caps); if (pool) @@ -900,15 +815,6 @@ gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self) { OMX_ERRORTYPE err; - if (self->out_port_pool) { - gst_buffer_pool_set_active (self->out_port_pool, FALSE); -#if 0 - gst_buffer_pool_wait_released (self->out_port_pool); -#endif - GST_OMX_BUFFER_POOL (self->out_port_pool)->deactivated = TRUE; - gst_object_unref (self->out_port_pool); - self->out_port_pool = NULL; - } #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL) err = gst_omx_port_deallocate_buffers (self->eglimage ? self-> @@ -1390,44 +1296,12 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) GST_TIME_ARGS (-deadline)); flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); frame = NULL; - } else if (!frame && (buf->omx_buf->nFilledLen > 0 || buf->eglimage)) { + } else if (!frame && (buf->omx_buf->nFilledLen > 0 || buf->pool_buffer)) { GstBuffer *outbuf = NULL; - /* This sometimes happens at EOS or if the input is not properly framed, - * let's handle it gracefully by allocating a new buffer for the current - * caps and filling it - */ - - GST_ERROR_OBJECT (self, "No corresponding frame found"); - - if (self->out_port_pool) { - gint i, n; - GstBufferPoolAcquireParams params = { 0, }; - - n = port->buffers->len; - for (i = 0; i < n; i++) { - GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i); - - if (tmp == buf) - break; - } - g_assert (i != n); - - GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i; - flow_ret = - gst_buffer_pool_acquire_buffer (self->out_port_pool, &outbuf, - ¶ms); - if (flow_ret != GST_FLOW_OK) { - gst_omx_port_release_buffer (port, buf); - goto invalid_buffer; - } - - if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy) - outbuf = - copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info, - outbuf); - - buf = NULL; + if (buf->pool_buffer) { + gst_buffer_ref (buf->pool_buffer); + outbuf = buf->pool_buffer; } else { outbuf = gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self)); @@ -1439,40 +1313,9 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) } flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf); - } else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) { - if (self->out_port_pool) { - gint i, n; - GstBuffer *outbuf; - GstBufferPoolAcquireParams params = { 0, }; - - n = port->buffers->len; - for (i = 0; i < n; i++) { - GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i); - - if (tmp == buf) - break; - } - g_assert (i != n); - - GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i; - flow_ret = - gst_buffer_pool_acquire_buffer (self->out_port_pool, - &outbuf, ¶ms); - if (flow_ret != GST_FLOW_OK) { - flow_ret = - gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); - frame = NULL; - gst_omx_port_release_buffer (port, buf); - goto invalid_buffer; - } - - if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy) - outbuf = - copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info, - outbuf); - - frame->output_buffer = outbuf; - + } else if (buf->omx_buf->nFilledLen > 0 || buf->pool_buffer) { + if (buf->pool_buffer) { + frame->output_buffer = buf->pool_buffer; flow_ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); frame = NULL; @@ -2535,16 +2378,22 @@ gst_omx_video_dec_drain (GstVideoDecoder * decoder) static gboolean gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query) { + GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (bdec); GstBufferPool *pool; + GstCaps *caps; GstStructure *config; + OMX_PARAM_PORTDEFINITIONTYPE port_def; + guint min, max; + + gst_query_parse_allocation (query, &caps, NULL); + + gst_omx_port_get_port_definition (self->dec_out_port, &port_def); #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL) { - GstCaps *caps; gint i, n; GstVideoInfo info; - gst_query_parse_allocation (query, &caps, NULL); if (caps && gst_video_info_from_caps (&info, caps) && info.finfo->format == GST_VIDEO_FORMAT_RGBA) { gboolean found = FALSE; @@ -2587,7 +2436,7 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query) return FALSE; g_assert (gst_query_get_n_allocation_pools (query) > 0); - gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL); + gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, &min, &max); g_assert (pool != NULL); config = gst_buffer_pool_get_config (pool); @@ -2595,6 +2444,10 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query) gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); } + + gst_buffer_pool_config_set_params (config, caps, port_def.nBufferSize, + port_def.nBufferCountActual, port_def.nBufferCountActual); + gst_buffer_pool_set_config (pool, config); gst_object_unref (pool); diff --git a/omx/gstomxvideodec.h b/omx/gstomxvideodec.h index c79b66d..3f7b489 100644 --- a/omx/gstomxvideodec.h +++ b/omx/gstomxvideodec.h @@ -56,8 +56,6 @@ struct _GstOMXVideoDec /* < protected > */ GstOMXComponent *dec; GstOMXPort *dec_in_port, *dec_out_port; - - GstBufferPool *in_port_pool, *out_port_pool; /* < private > */ GstVideoCodecState *input_state; -- 2.14.1