--- /dev/null
--- /dev/null
++install_data (['gstomx.conf'], install_dir : omx_conf_dir)
--- /dev/null
--- /dev/null
++install_data (['gstomx.conf'], install_dir : omx_conf_dir)
--- /dev/null
--- /dev/null
++install_data (['gstomx.conf'], install_dir : omx_conf_dir)
cdata.set('TIZONIA_LIBDIR', tizil_dep.get_pkgconfig_variable('libdir'))
tizil_includedir = tizil_dep.get_pkgconfig_variable('includedir')
gst_omx_args += ['-I' + tizil_includedir + '/tizonia']
+ omx_inc = []
++elif omx_target == 'exynos64'
++ cdata.set('USE_OMX_TARGET_EXYNOS64', 1)
++elif omx_target == 'exynos'
++ cdata.set('USE_OMX_TARGET_EXYNOS', 1)
else
error ('Unsupported omx target specified. Use the -Dtarget option')
endif
+message ('OMX target: ' + omx_target)
+
++# Tizen options
++tbm_dep = dependency('libtbm', required : true)
++have_omx_vp9 = get_option('vp9')
++cdata.set ('HAVE_VP9', have_omx_vp9)
++
extra_video_headers = ''
# Check for optional OpenMAX extension headers
option('header_path', type : 'string', value : '',
description : 'An extra include directory to find the OpenMax headers')
option('target', type : 'combo',
-- choices : ['none', 'generic', 'rpi', 'bellagio', 'tizonia', 'zynqultrascaleplus'], value : 'none',
++ choices : ['none', 'generic', 'rpi', 'bellagio', 'tizonia', 'zynqultrascaleplus', 'exynos64', 'exynos'], value : 'none',
description : 'The OMX platform to target')
option('struct_packing', type : 'combo',
choices : ['0', '1', '2', '4', '8'], value : '0',
option('examples', type : 'feature', value : 'auto', yield : true)
option('tests', type : 'feature', value : 'auto', yield : true)
option('tools', type : 'feature', value : 'auto', yield : true)
+option('doc', type : 'feature', value : 'auto', yield : true)
++
++# Tizen options
++option('vp9', type : 'boolean', value : false,
++ description : 'VP9 decoder for exynos')
++
--- /dev/null
+/*
+ * Copyright (C) 2019, Collabora Ltd.
+ * Author: George Kiagiadakis <george.kiagiadakis@collabora.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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstomxallocator.h"
+#include <gst/allocators/gstdmabuf.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_omx_allocator_debug_category);
+#define GST_CAT_DEFAULT gst_omx_allocator_debug_category
+
+#define DEBUG_INIT \
+ GST_DEBUG_CATEGORY_INIT (gst_omx_allocator_debug_category, "omxallocator", 0, \
+ "debug category for gst-omx allocator class");
+
+G_DEFINE_TYPE_WITH_CODE (GstOMXAllocator, gst_omx_allocator, GST_TYPE_ALLOCATOR,
+ DEBUG_INIT);
+
+enum
+{
+ SIG_OMXBUF_RELEASED,
+ SIG_FOREIGN_MEM_RELEASED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* Custom allocator for memory associated with OpenMAX buffers
+ *
+ * The main purpose of this allocator is to track memory that is associated
+ * with OpenMAX buffers, so that we know when the buffers can be released
+ * back to OpenMAX.
+ *
+ * This allocator looks and behaves more like a buffer pool. It allocates
+ * the memory objects before starting and sets a miniobject dispose function
+ * on them, which allows them to return when their last ref count is dropped.
+ *
+ * The type of memory that this allocator manages is GstOMXMemory. However, it
+ * is possible to manage a different type of memory, in which case the
+ * GstOMXMemory object is used only internally. There are two supported cases:
+ * - Allocate memory from the dmabuf allocator
+ * - Take memory that was allocated externally and manage it here
+ *
+ * In both cases, this allocator will replace the miniobject dispose function
+ * of these memory objects, so if they were acquired from here, they will also
+ * return here on their last unref.
+ *
+ * The caller initially needs to configure how many memory objects will be
+ * managed here by calling configure(). After that it needs to call
+ * set_active(TRUE) and finally allocate() for each memory. Allocation is done
+ * like this to facilitate calling allocate() from the alloc() function of
+ * the buffer pool for each OMX buffer on the port.
+ *
+ * After the allocator has been activated and all buffers have been allocated,
+ * the acquire() method can be called to retrieve a memory object. acquire() can
+ * be given an OMX buffer index or pointer to locate and return the memory
+ * object that corresponds to this OMX buffer. If the buffer is already
+ * acquired, this will result in a GST_FLOW_ERROR.
+ *
+ * When the last reference count is dropped on a memory that was acquired from
+ * here, its dispose function will ref it again and allow it to be acquired
+ * again. In addition, the omxbuf-released signal is fired to let the caller
+ * know that it can return this OMX buffer to the port, as it is no longer
+ * used outside this allocator.
+ */
+
+/******************/
+/** GstOMXMemory **/
+/******************/
+
+#define GST_OMX_MEMORY_TYPE "openmax"
+
+GQuark
+gst_omx_memory_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (quark == 0)
+ quark = g_quark_from_static_string ("GstOMXMemory");
+
+ return quark;
+}
+
+static GstOMXMemory *
+gst_omx_memory_new (GstOMXAllocator * allocator, GstOMXBuffer * omx_buf,
+ GstMemoryFlags flags, GstMemory * parent, gssize offset, gssize size)
+{
+ GstOMXMemory *mem;
+ gint align;
+ gsize maxsize;
+
+ /* GStreamer uses a bitmask for the alignment while
+ * OMX uses the alignment itself. So we have to convert
+ * here */
+ align = allocator->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) allocator->port->port_def.nBufferAlignment);
+ align = 0;
+ }
+
+ maxsize = omx_buf->omx_buf->nAllocLen;
+
+ if (size == -1) {
+ size = maxsize - offset;
+ }
+
+ mem = g_slice_new0 (GstOMXMemory);
+ gst_memory_init (GST_MEMORY_CAST (mem), flags, (GstAllocator *) allocator,
+ parent, maxsize, align, offset, size);
+
+ mem->buf = omx_buf;
+
+ return mem;
+}
+
+static gpointer
+gst_omx_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
+{
+ GstOMXMemory *omem = (GstOMXMemory *) mem;
+
++#ifdef TIZEN_FEATURE_OMX
++ int err;
++ gpointer data = NULL;
++ tbm_surface_info_s info;
++ GstTizenMemory *tmem = (GstTizenMemory *)omem->foreign_mem;
++
++ g_mutex_lock (&tmem->lock);
++ err = tbm_surface_map (tmem->surface, TBM_SURF_OPTION_WRITE|TBM_SURF_OPTION_READ, &info);
++ if (err == TBM_SURFACE_ERROR_NONE)
++ data = info.planes[0].ptr;
++ g_mutex_unlock (&tmem->lock);
++
++ return data;
++#else
+ /* if we are using foreign_mem, the GstOMXMemory should never appear
+ * anywhere outside this allocator, therefore it should never be mapped */
+ g_return_val_if_fail (!omem->foreign_mem, NULL);
+
+ return omem->buf->omx_buf->pBuffer;
++#endif
+}
+
+static void
+gst_omx_memory_unmap (GstMemory * mem)
+{
++#ifdef TIZEN_FEATURE_OMX
++ GstOMXMemory *omem = (GstOMXMemory *) mem;
++ GstTizenMemory *tmem = (GstTizenMemory *)omem->foreign_mem;
++
++ g_mutex_lock (&tmem->lock);
++ tbm_surface_unmap (tmem->surface);
++ g_mutex_unlock (&tmem->lock);
++#endif
+}
+
+static GstMemory *
+gst_omx_memory_share (GstMemory * mem, gssize offset, gssize size)
+{
+ GstOMXMemory *omem = (GstOMXMemory *) mem;
+ GstOMXMemory *sub;
+ GstMemory *parent;
+
+ /* find the real parent */
+ if ((parent = mem->parent) == NULL)
+ parent = mem;
+
+ if (size == -1)
+ size = mem->size - offset;
+
+ /* the shared memory is always readonly */
+ sub = gst_omx_memory_new ((GstOMXAllocator *) mem->allocator, omem->buf,
+ GST_MINI_OBJECT_FLAGS (parent) | GST_MINI_OBJECT_FLAG_LOCK_READONLY,
+ parent, offset, size);
+
+ return (GstMemory *) sub;
+}
+
+GstOMXBuffer *
+gst_omx_memory_get_omx_buf (GstMemory * mem)
+{
+ GstOMXMemory *omx_mem;
+
+ if (GST_IS_OMX_ALLOCATOR (mem->allocator))
+ omx_mem = (GstOMXMemory *) mem;
+ else
+ omx_mem = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
+ GST_OMX_MEMORY_QUARK);
+
+ if (!omx_mem)
+ return NULL;
+
+ return omx_mem->buf;
+}
+
+/*********************/
+/** GstOMXAllocator **/
+/*********************/
+
+static void
+gst_omx_allocator_init (GstOMXAllocator * 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);
+
+ g_mutex_init (&allocator->lock);
+ g_cond_init (&allocator->cond);
+}
+
+GstOMXAllocator *
+gst_omx_allocator_new (GstOMXComponent * component, GstOMXPort * port)
+{
+ GstOMXAllocator *allocator;
+
+ allocator = g_object_new (gst_omx_allocator_get_type (), NULL);
+ allocator->component = gst_omx_component_ref (component);
+ allocator->port = port;
+
+ return allocator;
+}
+
+static void
+gst_omx_allocator_finalize (GObject * object)
+{
+ GstOMXAllocator *allocator = GST_OMX_ALLOCATOR (object);
+
+ gst_omx_component_unref (allocator->component);
+ g_mutex_clear (&allocator->lock);
+ g_cond_clear (&allocator->cond);
+
+ G_OBJECT_CLASS (gst_omx_allocator_parent_class)->finalize (object);
+}
+
+gboolean
+gst_omx_allocator_configure (GstOMXAllocator * allocator, guint count,
+ GstOMXAllocatorForeignMemMode mode)
+{
+ /* check if already configured */
+ if (allocator->n_memories > 0)
+ return FALSE;
+
+ allocator->n_memories = count;
+ allocator->foreign_mode = mode;
+ if (mode == GST_OMX_ALLOCATOR_FOREIGN_MEM_DMABUF)
+ allocator->foreign_allocator = gst_dmabuf_allocator_new ();
++#ifdef TIZEN_FEATURE_OMX
++ else if (mode == GST_OMX_ALLOCATOR_FOREIGN_MEM_TBM)
++ allocator->foreign_allocator = gst_tizen_allocator_new ();
++#endif
+
+ return TRUE;
+}
+
+/* must be protected with allocator->lock */
+static void
+gst_omx_allocator_dealloc (GstOMXAllocator * allocator)
+{
+ /* might be called more than once */
+ if (!allocator->memories)
+ return;
+
+ /* return foreign memory back to whoever lended it to us.
+ * the signal handler is expected to increase the ref count of foreign_mem */
+ if (allocator->foreign_mode == GST_OMX_ALLOCATOR_FOREIGN_MEM_OTHER_POOL) {
+ gint i;
+ GstOMXMemory *m;
+
+ for (i = 0; i < allocator->memories->len; i++) {
+ m = g_ptr_array_index (allocator->memories, i);
+
+ /* this should not happen, but let's not crash for this */
+ if (!m->foreign_mem) {
+ GST_WARNING_OBJECT (allocator, "no foreign_mem to release");
+ continue;
+ }
+
+ /* restore the original dispose function */
+ GST_MINI_OBJECT_CAST (m->foreign_mem)->dispose =
+ (GstMiniObjectDisposeFunction) m->foreign_dispose;
+
+ g_signal_emit (allocator, signals[SIG_FOREIGN_MEM_RELEASED], 0, i,
+ m->foreign_mem);
+ }
+ }
+
+ g_ptr_array_foreach (allocator->memories, (GFunc) gst_memory_unref, NULL);
+ g_ptr_array_free (allocator->memories, TRUE);
+ allocator->memories = NULL;
+ allocator->n_memories = 0;
+ allocator->foreign_mode = GST_OMX_ALLOCATOR_FOREIGN_MEM_NONE;
+ if (allocator->foreign_allocator) {
+ g_object_unref (allocator->foreign_allocator);
+ allocator->foreign_allocator = NULL;
+ }
+
+ g_cond_broadcast (&allocator->cond);
+}
+
+gboolean
+gst_omx_allocator_set_active (GstOMXAllocator * allocator, gboolean active)
+{
+ gboolean changed = FALSE;
+
+ /* on activation, _configure() must be called first */
+ g_return_val_if_fail (!active || allocator->n_memories > 0, FALSE);
+
+ g_mutex_lock (&allocator->lock);
+
+ if (allocator->active != active)
+ changed = TRUE;
+
+ if (changed) {
+ if (active) {
+ allocator->memories = g_ptr_array_sized_new (allocator->n_memories);
+ g_ptr_array_set_size (allocator->memories, allocator->n_memories);
+ } else {
+ if (g_atomic_int_get (&allocator->n_outstanding) == 0)
+ gst_omx_allocator_dealloc (allocator);
+ }
+ }
+
+ allocator->active = active;
+ g_mutex_unlock (&allocator->lock);
+
+ return changed;
+}
+
+void
+gst_omx_allocator_wait_inactive (GstOMXAllocator * allocator)
+{
+ g_mutex_lock (&allocator->lock);
+ while (allocator->memories)
+ g_cond_wait (&allocator->cond, &allocator->lock);
+ g_mutex_unlock (&allocator->lock);
+}
+
+static inline void
+dec_outstanding (GstOMXAllocator * allocator)
+{
+ if (g_atomic_int_dec_and_test (&allocator->n_outstanding)) {
+ /* keep a ref to the allocator because _dealloc() will free
+ * all the memories and the memories might be the only thing holding
+ * a reference to the allocator; we need to keep it alive until the
+ * end of this function call */
+ g_object_ref (allocator);
+
+ /* take the lock so that _set_active() is not run concurrently */
+ g_mutex_lock (&allocator->lock);
+
+ /* now that we have the lock, check if we have been de-activated with
+ * outstanding buffers */
+ if (!allocator->active)
+ gst_omx_allocator_dealloc (allocator);
+
+ g_mutex_unlock (&allocator->lock);
+ g_object_unref (allocator);
+ }
+}
+
+GstFlowReturn
+gst_omx_allocator_acquire (GstOMXAllocator * allocator, GstMemory ** memory,
+ gint index, GstOMXBuffer * omx_buf)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstOMXMemory *omx_mem = NULL;
+
+ /* ensure memories are not going to disappear concurrently */
+ g_atomic_int_inc (&allocator->n_outstanding);
+
+ if (!allocator->active) {
+ ret = GST_FLOW_FLUSHING;
+ goto beach;
+ }
+
+ if (index >= 0 && index < allocator->n_memories)
+ omx_mem = g_ptr_array_index (allocator->memories, index);
+ else if (omx_buf) {
+ for (index = 0; index < allocator->n_memories; index++) {
+ omx_mem = g_ptr_array_index (allocator->memories, index);
+ if (omx_mem->buf == omx_buf)
+ break;
+ }
+ }
+
+ if (G_UNLIKELY (!omx_mem || index >= allocator->n_memories)) {
+ GST_ERROR_OBJECT (allocator, "Failed to find OMX memory");
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
+
+ if (G_UNLIKELY (omx_mem->buf->used)) {
+ GST_ERROR_OBJECT (allocator,
+ "Trying to acquire a buffer that is being used by the OMX port");
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
+
+ omx_mem->acquired = TRUE;
+
+ if (omx_mem->foreign_mem)
+ *memory = omx_mem->foreign_mem;
+ else
+ *memory = GST_MEMORY_CAST (omx_mem);
+
+beach:
+ if (ret != GST_FLOW_OK)
+ dec_outstanding (allocator);
+ return ret;
+}
+
++#ifdef TIZEN_FEATURE_OMX
++static void
++_destroy_tbm_surface (tbm_surface_h surface)
++{
++ GST_DEBUG ("destroy surface %p", surface);
++ tbm_surface_internal_destroy (surface);
++}
++#endif
++
+/* installed as the GstMiniObject::dispose function of the acquired GstMemory */
+static gboolean
+gst_omx_allocator_memory_dispose (GstMemory * mem)
+{
+ GstOMXMemory *omx_mem;
+ GstOMXAllocator *allocator;
+
+ /* memory may be from our allocator, but
+ * may as well be from the dmabuf allocator */
+ if (GST_IS_OMX_ALLOCATOR (mem->allocator))
+ omx_mem = (GstOMXMemory *) mem;
+ else
+ omx_mem = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
+ GST_OMX_MEMORY_QUARK);
+
+ if (omx_mem->acquired) {
+ /* keep the memory alive */
+ gst_memory_ref (mem);
+
+ omx_mem->acquired = FALSE;
+
+ allocator = GST_OMX_ALLOCATOR (GST_MEMORY_CAST (omx_mem)->allocator);
+
+ /* inform the upper layer that we are no longer using this GstOMXBuffer */
+ g_signal_emit (allocator, signals[SIG_OMXBUF_RELEASED], 0, omx_mem->buf);
+
+ dec_outstanding (allocator);
+
+ /* be careful here, both the memory and the allocator
+ * may have been free'd as part of the call to dec_outstanding() */
+
+ return FALSE;
+ }
+
+ /* if the foreign memory had a dispose function, let that one decide
+ * the fate of this memory. We are no longer going to be using it here */
+ if (omx_mem->foreign_dispose)
+ return omx_mem->foreign_dispose (GST_MINI_OBJECT_CAST (mem));
+
+ return TRUE;
+}
+
+static inline void
+install_mem_dispose (GstOMXMemory * mem)
+{
+ GstMemory *managed_mem = (GstMemory *) mem;
+
+ if (mem->foreign_mem) {
+ managed_mem = mem->foreign_mem;
+ mem->foreign_dispose = GST_MINI_OBJECT_CAST (managed_mem)->dispose;
+ }
+
+ GST_MINI_OBJECT_CAST (managed_mem)->dispose =
+ (GstMiniObjectDisposeFunction) gst_omx_allocator_memory_dispose;
+}
+
+/* the returned memory is transfer:none, ref still belongs to the allocator */
+GstMemory *
+gst_omx_allocator_allocate (GstOMXAllocator * allocator, gint index,
+ GstMemory * foreign_mem)
+{
+ GstOMXMemory *mem;
+ GstOMXBuffer *omx_buf;
+
+ g_return_val_if_fail (allocator->port->buffers, NULL);
+ g_return_val_if_fail (allocator->memories, NULL);
+ g_return_val_if_fail (index >= 0 && index < allocator->n_memories, NULL);
+ g_return_val_if_fail ((foreign_mem == NULL &&
+ allocator->foreign_mode != GST_OMX_ALLOCATOR_FOREIGN_MEM_OTHER_POOL)
+ || (foreign_mem != NULL
+ && allocator->foreign_mode ==
+ GST_OMX_ALLOCATOR_FOREIGN_MEM_OTHER_POOL), NULL);
+
+ omx_buf = g_ptr_array_index (allocator->port->buffers, index);
+ g_return_val_if_fail (omx_buf != NULL, NULL);
+
+ mem = gst_omx_memory_new (allocator, omx_buf, 0, NULL, 0, -1);
+
+ switch (allocator->foreign_mode) {
+ case GST_OMX_ALLOCATOR_FOREIGN_MEM_NONE:
+ install_mem_dispose (mem);
+ break;
+ case GST_OMX_ALLOCATOR_FOREIGN_MEM_DMABUF:
+ {
+ gint fd = GPOINTER_TO_INT (omx_buf->omx_buf->pBuffer);
+ mem->foreign_mem =
+ gst_dmabuf_allocator_alloc (allocator->foreign_allocator, fd,
+ omx_buf->omx_buf->nAllocLen);
+ gst_mini_object_set_qdata (GST_MINI_OBJECT (mem->foreign_mem),
+ GST_OMX_MEMORY_QUARK, mem, NULL);
+ install_mem_dispose (mem);
+ break;
+ }
++#ifdef TIZEN_FEATURE_OMX
++ case GST_OMX_ALLOCATOR_FOREIGN_MEM_TBM:
++ {
++ tbm_surface_h surface = (tbm_surface_h) omx_buf->omx_buf->pBuffer;
++ mem->foreign_mem = gst_tizen_allocator_alloc_surface (allocator->foreign_allocator,
++ &allocator->video_info, surface, omx_buf, (GDestroyNotify)_destroy_tbm_surface);
++ break;
++ }
++#endif
+ case GST_OMX_ALLOCATOR_FOREIGN_MEM_OTHER_POOL:
+ mem->foreign_mem = foreign_mem;
+ gst_mini_object_set_qdata (GST_MINI_OBJECT (mem->foreign_mem),
+ GST_OMX_MEMORY_QUARK, mem, NULL);
+ install_mem_dispose (mem);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_ptr_array_index (allocator->memories, index) = mem;
+ return mem->foreign_mem ? mem->foreign_mem : (GstMemory *) mem;
+}
+
+static void
+gst_omx_allocator_free (GstAllocator * allocator, GstMemory * mem)
+{
+ GstOMXMemory *omem = (GstOMXMemory *) mem;
+
+ g_warn_if_fail (!omem->acquired);
+
+ if (omem->foreign_mem)
+ gst_memory_unref (omem->foreign_mem);
+
+ g_slice_free (GstOMXMemory, omem);
+}
+
+static void
+gst_omx_allocator_class_init (GstOMXAllocatorClass * klass)
+{
+ GObjectClass *object_class;
+ GstAllocatorClass *allocator_class;
+
+ object_class = (GObjectClass *) klass;
+ allocator_class = (GstAllocatorClass *) klass;
+
+ object_class->finalize = gst_omx_allocator_finalize;
+ allocator_class->alloc = NULL;
+ allocator_class->free = gst_omx_allocator_free;
+
+ signals[SIG_OMXBUF_RELEASED] = g_signal_new ("omxbuf-released",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0,
+ NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ signals[SIG_FOREIGN_MEM_RELEASED] = g_signal_new ("foreign-mem-released",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0,
+ NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
+}
--- /dev/null
+/*
+ * Copyright (C) 2019, Collabora Ltd.
+ * Author: George Kiagiadakis <george.kiagiadakis@collabora.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_ALLOCATOR_H__
+#define __GST_OMX_ALLOCATOR_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstomx.h"
+
+G_BEGIN_DECLS
+
+#define GST_OMX_MEMORY_QUARK gst_omx_memory_quark ()
+
+#define GST_TYPE_OMX_ALLOCATOR (gst_omx_allocator_get_type())
+#define GST_IS_OMX_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OMX_ALLOCATOR))
+#define GST_OMX_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OMX_ALLOCATOR, GstOMXAllocator))
+
+typedef struct _GstOMXMemory GstOMXMemory;
+typedef struct _GstOMXAllocator GstOMXAllocator;
+typedef struct _GstOMXAllocatorClass GstOMXAllocatorClass;
+
+typedef enum {
+ GST_OMX_ALLOCATOR_FOREIGN_MEM_NONE,
+ GST_OMX_ALLOCATOR_FOREIGN_MEM_DMABUF,
++#ifdef TIZEN_FEATURE_OMX
++ GST_OMX_ALLOCATOR_FOREIGN_MEM_TBM,
++#endif
+ GST_OMX_ALLOCATOR_FOREIGN_MEM_OTHER_POOL,
+} GstOMXAllocatorForeignMemMode;
+
+struct _GstOMXMemory
+{
+ GstMemory mem;
+ GstOMXBuffer *buf;
+
+ /* TRUE if the memory is in use outside the allocator */
+ gboolean acquired;
+
+ /* memory allocated from the foreign_allocator
+ * or planted externally when using a foreign buffer pool */
+ GstMemory *foreign_mem;
++
+ /* the original dispose function of foreign_mem */
+ GstMiniObjectDisposeFunction foreign_dispose;
+};
+
+struct _GstOMXAllocator
+{
+ GstAllocator parent;
+
+ GstOMXComponent *component;
+ GstOMXPort *port;
+
+ GstOMXAllocatorForeignMemMode foreign_mode;
+ GstAllocator *foreign_allocator;
+
+ /* array of GstOMXMemory */
+ GPtrArray *memories;
+ guint n_memories;
+
+ guint n_outstanding;
+ gboolean active;
+
+ GMutex lock;
+ GCond cond;
++#ifdef TIZEN_FEATURE_OMX
++ GstVideoInfo video_info;
++#endif
+};
+
+struct _GstOMXAllocatorClass
+{
+ GstAllocatorClass parent_class;
+};
+
+GType gst_omx_allocator_get_type (void);
+
+GQuark gst_omx_memory_quark (void);
+
+GstOMXBuffer * gst_omx_memory_get_omx_buf (GstMemory * mem);
+
+GstOMXAllocator * gst_omx_allocator_new (GstOMXComponent * component,
+ GstOMXPort * port);
+
+gboolean gst_omx_allocator_configure (GstOMXAllocator * allocator, guint count,
+ GstOMXAllocatorForeignMemMode mode);
+gboolean gst_omx_allocator_set_active (GstOMXAllocator * allocator,
+ gboolean active);
+void gst_omx_allocator_wait_inactive (GstOMXAllocator * allocator);
+
+GstFlowReturn gst_omx_allocator_acquire (GstOMXAllocator * allocator,
+ GstMemory ** memory, gint index, GstOMXBuffer * omx_buf);
+
+GstMemory * gst_omx_allocator_allocate (GstOMXAllocator * allocator, gint index,
+ GstMemory * foreign_mem);
+
+G_END_DECLS
+
+#endif
static guint signals[LAST_SIGNAL] = { 0 };
-struct _GstOMXMemory
-{
-#ifdef TIZEN_FEATURE_OMX
- GstTizenMemory mem;
-#else
- GstMemory mem;
-#endif
-
- 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);
-}
-
-#ifdef TIZEN_FEATURE_OMX
-static void
-_destroy_tbm_surface (tbm_surface_h surface)
-{
- GST_DEBUG ("destroy surface %p", surface);
- tbm_surface_internal_destroy (surface);
-}
-#endif
-
-static gpointer
-gst_omx_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
-{
-#ifdef TIZEN_FEATURE_OMX
- int err;
- gpointer data = NULL;
- tbm_surface_info_s info;
- GstTizenMemory *tmem = (GstTizenMemory *)mem;
-
- g_mutex_lock (&tmem->lock);
- err = tbm_surface_map (tmem->surface, TBM_SURF_OPTION_WRITE|TBM_SURF_OPTION_READ, &info);
- if (err == TBM_SURFACE_ERROR_NONE)
- data = info.planes[0].ptr;
- g_mutex_unlock (&tmem->lock);
-
- return data;
-#else
- GstOMXMemory *omem = (GstOMXMemory *) mem;
-
- return omem->buf->omx_buf->pBuffer + omem->mem.offset;
-#endif
-}
-
-static void
-gst_omx_memory_unmap (GstMemory * mem)
-{
-#ifdef TIZEN_FEATURE_OMX
- GstTizenMemory *tmem = (GstTizenMemory *)mem;
-
- g_mutex_lock (&tmem->lock);
- tbm_surface_unmap (tmem->surface);
- g_mutex_unlock (&tmem->lock);
-#endif
-}
-
-static GstMemory *
-gst_omx_memory_share (GstMemory * mem, gssize offset, gssize size)
-{
- g_assert_not_reached ();
- return NULL;
-}
-
+ #ifdef TIZEN_FEATURE_OMX
+ gboolean
+ gst_omx_video_memory_map (GstVideoMeta * meta, guint plane, GstMapInfo * info,
+ gpointer * data, gint * stride, GstMapFlags flags)
+ {
+ gint err;
+ tbm_surface_info_s surface_info;
+ GstBuffer *buffer = meta->buffer;
+ GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
+
+ if (!gst_is_tizen_memory (mem)) {
+ GST_ERROR ("Invalid memory");
+ return FALSE;
+ }
+
+ err = tbm_surface_map (((GstTizenMemory *)mem)->surface, TBM_SURF_OPTION_WRITE|TBM_SURF_OPTION_READ, &surface_info);
+ if (err != TBM_SURFACE_ERROR_NONE) {
+ GST_ERROR ("Failed to map memory");
+ return FALSE;
+ }
+
+ tbm_surface_unmap (((GstTizenMemory *)mem)->surface);
+
+ if (surface_info.num_planes <= plane) {
+ GST_ERROR ("Invalid format");
+ return FALSE;
+ }
+
+ *data = surface_info.planes[plane].ptr;
+ *stride = surface_info.planes[plane].stride;
+
+ GST_DEBUG ("_video_memory_map -> plane : %d, data : %p, stride : %d",
+ plane, *data, *stride);
+
+ return TRUE;
+ }
+
+ gboolean
+ gst_omx_video_memory_unmap (GstVideoMeta * meta, guint plane, GstMapInfo * info)
+ {
+ GstBuffer *buffer = meta->buffer;
+ GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
+
+ if (!gst_is_tizen_memory (mem)) {
+ GST_ERROR ("Invalid memory");
+ return FALSE;
+ }
+
+ GST_DEBUG ("_video_memory_unmap -> plane : %d", plane);
+
+ return TRUE;
+ }
+ #endif
+
-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);
-}
-
-#ifndef TIZEN_FEATURE_OMX
-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);
-}
-#endif
-
/* Buffer pool for the buffers of an OpenMAX port.
*
* This pool is only used if we either passed buffers from another
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, };
+ #ifdef TIZEN_FEATURE_OMX
+ tbm_surface_h surface = NULL;
+ uint32_t _offset = 0;
+ uint32_t _stride = 0;
+ #endif
- if (pool->output_mode == GST_OMX_BUFFER_MODE_DMABUF) {
- gint fd;
- GstMapInfo map;
-
- fd = GPOINTER_TO_INT (omx_buf->omx_buf->pBuffer);
-
- mem =
- gst_dmabuf_allocator_alloc (pool->allocator, fd,
- omx_buf->omx_buf->nAllocLen);
-
- if (!gst_caps_features_contains (gst_caps_get_features (pool->caps, 0),
- GST_CAPS_FEATURE_MEMORY_DMABUF)) {
- /* Check if the memory is actually mappable */
- if (!gst_memory_map (mem, &map, GST_MAP_READWRITE)) {
- GST_ERROR_OBJECT (pool,
- "dmabuf memory is not mappable but caps does not have the 'memory:DMABuf' feature");
- gst_memory_unref (mem);
- return GST_FLOW_ERROR;
- }
-
- gst_memory_unmap (mem, &map);
- }
-#ifdef TIZEN_FEATURE_OMX
- } else {
- surface = (tbm_surface_h) omx_buf->omx_buf->pBuffer;
-
- mem = gst_tizen_allocator_alloc_surface (pool->allocator, &pool->video_info,
- surface, omx_buf, (GDestroyNotify)_destroy_tbm_surface);
-#else
- } else {
- mem = gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf);
-#endif
- }
-
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:
GST_VIDEO_INFO_WIDTH (&pool->video_info),
GST_VIDEO_INFO_HEIGHT (&pool->video_info),
GST_VIDEO_INFO_N_PLANES (&pool->video_info), offset, stride);
+
+ if (gst_omx_video_get_port_padding (pool->port, &pool->video_info,
+ &align))
+ gst_video_meta_set_alignment (meta, align);
+ #ifdef TIZEN_FEATURE_OMX
+ meta->map = gst_omx_video_memory_map;
+ meta->unmap = gst_omx_video_memory_unmap;
+ #endif
}
}
pool->component = gst_omx_component_ref (component);
pool->port = port;
pool->output_mode = output_mode;
-
- switch (output_mode) {
- case GST_OMX_BUFFER_MODE_DMABUF:
- pool->allocator = gst_dmabuf_allocator_new ();
- break;
- case GST_OMX_BUFFER_MODE_SYSTEM_MEMORY:
- pool->allocator =
- g_object_new (gst_omx_memory_allocator_get_type (), NULL);
- break;
+ pool->allocator = gst_omx_allocator_new (component, port);
+ #ifdef TIZEN_FEATURE_OMX
- case GST_OMX_BUFFER_MODE_TBM:
- pool->allocator = gst_tizen_allocator_new ();
- break;
++ pool->allocator->video_info = pool->video_info;
+ #endif
- default:
- g_assert_not_reached ();
- }
+
+ g_signal_connect_object (pool->allocator, "omxbuf-released",
+ (GCallback) on_allocator_omxbuf_released, pool, 0);
+ g_signal_connect_object (pool->allocator, "foreign-mem-released",
+ (GCallback) on_allocator_foreign_mem_released, pool, 0);
return GST_BUFFER_POOL (pool);
}
G_DEFINE_TYPE_WITH_CODE (GstOMXH264Dec, gst_omx_h264_dec,
GST_TYPE_OMX_VIDEO_DEC, DEBUG_INIT);
++#ifdef TIZEN_FEATURE_OMX
++#define MAKE_CAPS(alignment) \
++ "video/x-h264, " \
++ "alignment=(string) " alignment ", " \
++ "stream-format=(string) byte-stream, " \
++ "width=(int) [1,MAX], height=(int) [1,MAX], " \
++ "framerate = (fraction) [0/1, MAX]"
++#else
+#define MAKE_CAPS(alignment) \
+ "video/x-h264, " \
+ "alignment=(string) " alignment ", " \
+ "stream-format=(string) byte-stream, " \
+ "width=(int) [1,MAX], height=(int) [1,MAX]"
++#endif
+
+/* The Zynq supports decoding subframes, though we want "au" to be the
+ * default, so we keep it prepended. This is the only way that it works with
+ * rtph264depay. */
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+#define SINK_CAPS MAKE_CAPS ("au") ";" MAKE_CAPS ("nal")
+#else
+#define SINK_CAPS MAKE_CAPS ("au")
+#endif
+
static void
gst_omx_h264_dec_class_init (GstOMXH264DecClass * klass)
{
#ifdef USE_OMX_TARGET_RPI
#define GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT TRUE
#endif
+ #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
+ #define GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT (0x00000001)
+ #define GST_OMX_VIDEO_ENC_NUM_REF_FRAME_MAX (0x00000002)
+ #define GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT (0x00000001)
+ #define GST_OMX_VIDEO_ENC_NUM_B_FRAME_MAX (0x00000002)
+ #endif
#define GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT (0xffffffff)
#define GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT (0xffffffff)
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+#define GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT (0)
+#define ALIGNMENT "{ au, nal }"
+#else
#define GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT (0xffffffff)
+#define ALIGNMENT "au"
+#endif
#define GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT (0xffffffff)
#define GST_OMX_H264_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT (FALSE)
#define GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT (0xffffffff)
GstVideoInfo *vinfo = &state->info;
OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->dec_out_port->port_def;
gboolean ret = FALSE;
+ #ifndef TIZEN_FEATURE_OMX
GstVideoFrame frame;
+ #endif
if (vinfo->width != port_def->format.video.nFrameWidth ||
- vinfo->height != port_def->format.video.nFrameHeight) {
+ GST_VIDEO_INFO_FIELD_HEIGHT (vinfo) !=
+ port_def->format.video.nFrameHeight) {
GST_ERROR_OBJECT (self, "Resolution do not match: port=%ux%u vinfo=%dx%d",
(guint) port_def->format.video.nFrameWidth,
(guint) port_def->format.video.nFrameHeight,
guint src_size[GST_VIDEO_MAX_PLANES] = { nstride * nslice, 0, };
gint dst_width[GST_VIDEO_MAX_PLANES] = { 0, };
gint dst_height[GST_VIDEO_MAX_PLANES] =
- { GST_VIDEO_INFO_HEIGHT (vinfo), 0, };
+ { GST_VIDEO_INFO_FIELD_HEIGHT (vinfo), 0, };
const guint8 *src;
guint p;
+ #endif
switch (GST_VIDEO_INFO_FORMAT (vinfo)) {
+ #ifndef TIZEN_FEATURE_OMX
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_ARGB:
dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 4;
dst_width[1] = dst_width[0];
src_stride[1] = nstride;
src_size[1] = src_stride[1] * nslice;
- dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo);
+ dst_height[1] = GST_VIDEO_INFO_FIELD_HEIGHT (vinfo);
break;
+ #endif
+ #ifdef TIZEN_FEATURE_OMX
+ case GST_VIDEO_FORMAT_SN12:
+ case GST_VIDEO_FORMAT_ST12:
+ ret = TRUE;
+ break;
+ #endif
default:
g_assert_not_reached ();
break;
err = gst_omx_video_dec_reconfigure_output_port (self);
if (err != OMX_ErrorNone)
goto reconfigure_error;
+ #ifdef TIZEN_FEATURE_OMX
+ msg = gst_message_new_element (GST_OBJECT_CAST (self), gst_structure_new ("prepare-decode-buffers",
+ "num_buffers", G_TYPE_INT, self->dec_out_port->port_def.nBufferCountActual,
+ "extra_num_buffers", G_TYPE_INT, EXTRA_DECODER_OUTPUT_BUF, NULL));
+
+ gst_element_post_message (GST_ELEMENT_CAST (self), msg);
+ #endif
} else {
+ GstVideoInterlaceMode interlace_mode;
+
/* Just update caps */
GST_VIDEO_DECODER_STREAM_LOCK (self);
}
if (!self->started) {
- if (!GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
+ if (!GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame) && !header) {
+ #ifdef TIZEN_FEATURE_OMX
+ if (!self->codec_data) {
-#endif /* TIZEN_FEATURE_OMX */
++#endif
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
return GST_FLOW_OK;
-#endif /* TIZEN_FEATURE_OMX */
+ #ifdef TIZEN_FEATURE_OMX
+ }
+ GST_WARNING_OBJECT (self, "Not I frame[%"GST_TIME_FORMAT"], but keep going...", GST_TIME_ARGS (frame->pts));
++#endif
}
if (gst_omx_port_is_flushing (self->dec_out_port)) {
}
buf->omx_buf->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
- buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
+ #ifdef CODEC_DEC_INTPUT_DUMP
+ decoder_input_dump (buf, port->use_buffer);
+ #endif
+
if (GST_CLOCK_TIME_IS_VALID (timestamp))
GST_OMX_SET_TICKS (buf->omx_buf->nTimeStamp,
gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND,
i = 0;
while (i < gst_query_get_n_allocation_pools (query)) {
gst_query_parse_nth_allocation_pool (query, i, &pool, NULL, NULL, NULL);
-#else /* TIZEN_FEATURE_OMX */
+ #ifdef TIZEN_FEATURE_OMX
+ gst_query_remove_nth_allocation_pool (query, i);
+ GST_WARNING_OBJECT (self, "remove pool from downstream %u", gst_query_get_n_allocation_pools (query));
++#else
if (GST_IS_OMX_BUFFER_POOL (pool)) {
GST_DEBUG_OBJECT (self, "Discard OMX pool from downstream");
gst_query_remove_nth_allocation_pool (query, i);
self->use_buffers = TRUE;
i++;
}
-#endif /* TIZEN_FEATURE_OMX */
++#endif
if (pool)
gst_object_unref (pool);
#define GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT (0)
#define GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT (FALSE)
#define GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY OMX_ALG_ROI_QUALITY_HIGH
+#define GST_OMX_VIDEO_ENC_LONGTERM_REF_DEFAULT (FALSE)
+#define GST_OMX_VIDEO_ENC_LONGTERM_FREQUENCY_DEFAULT (0)
+#define GST_OMX_VIDEO_ENC_LOOK_AHEAD_DEFAULT (0)
+
+/* ZYNQ_USCALE_PLUS encoder custom events */
+#define OMX_ALG_GST_EVENT_INSERT_LONGTERM "omx-alg/insert-longterm"
+#define OMX_ALG_GST_EVENT_USE_LONGTERM "omx-alg/use-longterm"
+
/* class initialization */
#define do_init \
{ \
return FALSE;
#endif
-#endif /* USE_OMX_TARGET_EXYNOS || USE_OMX_TARGET_EXYNOS64 */
-#endif /* TIZEN_FEATURE_OMX */
+ #ifdef TIZEN_FEATURE_OMX
+ self->enc_in_port->use_buffer = klass->cdata.in_port_usebuffer;
+ self->enc_out_port->use_buffer = klass->cdata.out_port_usebuffer;
+
+ /* get extension index and set platform specific buffer enable */
+ #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
+ {
+ OMX_ERRORTYPE err;
+ OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
+ EnableGemBuffersParams gem_param;
+
+ err = gst_omx_component_get_extension_index (self->enc, (OMX_STRING) EXYNOS_INDEX_PARAM_STORE_METADATA_BUFFER, &index);
+ if (err != OMX_ErrorNone) {
+ GST_WARNING_OBJECT (self, "Failed to get extension index : %s (0x%08x)",
+ gst_omx_error_to_string (err), err);
+ }
+
+ OMX_INIT_PARAM (gem_param);
+ gem_param.enable = OMX_TRUE;
+ gem_param.nPortIndex = 0;
+
+ err = gst_omx_component_set_parameter (self->enc, index, &gem_param);
+ if (err != OMX_ErrorNone) {
+ GST_ERROR_OBJECT (self, "Failed to set platform specific buffer: %s (0x%08x)",
+ gst_omx_error_to_string (err), err);
+ }
+
+ }
++#endif
++#endif
+
return TRUE;
}
"Downstream element refused to negotiate codec_data in the caps");
return GST_FLOW_NOT_NEGOTIATED;
}
+ gst_video_codec_frame_unref (frame);
flow_ret = GST_FLOW_OK;
+ #endif
} else if (buf->omx_buf->nFilledLen > 0) {
GstBuffer *outbuf;
GstMapInfo map = GST_MAP_INFO_INIT;
err = gst_omx_port_set_enabled (port, TRUE);
if (err != OMX_ErrorNone)
goto reconfigure_error;
- err = gst_omx_port_tbm_allocate_enc_buffers (port);
+
+ #ifdef TIZEN_FEATURE_OMX
- err = gst_omx_port_allocate_buffers (port);
++ if (!gst_omx_port_tbm_allocate_enc_buffers (port))
+ #else
- if (err != OMX_ErrorNone)
+ if (!gst_omx_video_enc_allocate_out_buffers (self))
+ #endif
goto reconfigure_error;
err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
goto done;
}
+ #ifndef TIZEN_FEATURE_OMX
/* Same strides and everything */
- if (gst_buffer_get_size (inbuf) ==
- outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) {
+ if ((gst_buffer_get_size (inbuf) ==
+ outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) &&
+ (stride == port_def->format.video.nStride)) {
outbuf->omx_buf->nFilledLen = gst_buffer_get_size (inbuf);
GST_LOG_OBJECT (self, "Matched strides - direct copy %u bytes",
gst_omx_video_enc_semi_planar_manual_copy (self, inbuf, outbuf,
info->finfo);
break;
-#endif /* CODEC_ENC_INPUT_DUMP */
+ case GST_VIDEO_FORMAT_GRAY8:
+ {
+ if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) {
+ GST_ERROR_OBJECT (self, "Failed to map input buffer");
+ ret = FALSE;
+ goto done;
+ }
+
+ ret = gst_omx_video_enc_copy_plane (self, 0, &frame, outbuf, info->finfo);
+ gst_video_frame_unmap (&frame);
+ }
+ break;
+ #ifdef TIZEN_FEATURE_OMX
+ case GST_VIDEO_FORMAT_ST12:
+ case GST_VIDEO_FORMAT_SN12: {
+ tbm_surface_h surface;
+ GstMemory *mem = gst_buffer_peek_memory (inbuf, 0);
+
+ if (!gst_is_tizen_memory (mem)) {
+ GST_ERROR_OBJECT (self, "Invalid input buffer");
+ ret = FALSE;
+ break;
+ }
+
+ if (!(surface = gst_tizen_memory_get_surface (mem))) {
+ GST_ERROR_OBJECT (self, "Failed to get surface from tizen memory");
+ ret = FALSE;
+ break;
+ }
+ outbuf->omx_buf->pBuffer = (OMX_U8 *) surface;
+ outbuf->omx_buf->nAllocLen = (OMX_U32) tbm_surface_internal_get_size (surface);
+ outbuf->omx_buf->nFilledLen = (OMX_U32) tbm_surface_internal_get_size (surface);
+ #ifdef CODEC_ENC_INPUT_DUMP
+ gst_omx_video_enc_input_dump (inbuf);
-#endif /* TIZEN_FEATURE_OMX */
++#endif
+ ret = TRUE;
+ break;
+ }
++#endif
default:
GST_ERROR_OBJECT (self, "Unsupported format");
goto done;
GList *next;
switch (nmap->format) {
-#endif /* TIZEN_FEATURE_OMX */
+ #ifdef TIZEN_FEATURE_OMX
+ case GST_VIDEO_FORMAT_SN12:
+ case GST_VIDEO_FORMAT_ST12:
++#endif
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV12_10LE32:
omx_sources += 'gstomxvp8dec.c'
endif
++if have_omx_vp9
++ omx_sources += 'gstomxvp9dec.c'
++endif
++
if have_omx_theora
omx_sources += 'gstomxtheoradec.c'
endif
# link_args : noseh_link_args,
include_directories : [configinc, omx_inc],
dependencies : [gstvideo_dep, gstaudio_dep, gstbase_dep, gstcontroller_dep,
-- libm, gmodule_dep, gstallocators_dep] + optional_deps,
++ libm, gmodule_dep, gstallocators_dep, tbm_dep] + optional_deps,
install : true,
install_dir : plugins_install_dir,
)
- plugins = [gstomx]
+
++plugins = [gstomx]
--- /dev/null
-Version: 1.16.2
-Release: 8
+ Name: gst-omx
+ Summary: GStreamer plug-in that allows communication with OpenMAX IL components
-Source100: common.tar.gz
-Source1001: gst-omx.manifest
++Version: 1.19.2
++Release: 0
+ License: LGPL-2.1+
+ Group: Multimedia/Framework
+ Source0: %{name}-%{version}.tar.gz
-%setup -q
-%setup -q -T -D -a 100
-cp %{SOURCE1001} .
+ BuildRequires: which
++BuildRequires: meson >= 0.48.0
+ BuildRequires: pkgconfig(gstreamer-1.0)
+ BuildRequires: pkgconfig(gstreamer-plugins-base-1.0)
+ BuildRequires: pkgconfig(libtbm)
+ BuildRequires: pkgconfig(mm-common)
+ %if "%{target}" == "rpi"
+ BuildRequires: pkgconfig(bcm_host)
+ BuildRequires: pkgconfig(brcmegl)
+ %endif
+ ExclusiveArch: %arm aarch64
+
+ %description
+ gst-openmax is a GStreamer plug-in that allows communication with OpenMAX IL components.
+ Multiple OpenMAX IL implementations can be used.
+
+ %prep
-./autogen.sh --noconfigure
-
-export CFLAGS+=" -DTIZEN_FEATURE_OMX"
-
++%setup -q -n %{name}-%{version}
+
+ %build
-%configure \
- --disable-static \
- --prefix=/usr \
- --with-omx-target=rpi \
- --with-omx-header-path=/opt/vc/include/interface/vmcs_host/khronos/IL \
- sysconfdir=%{_hal_sysconfdir}
++export CFLAGS+=" -Wall -g -fPIC -DTIZEN_FEATURE_OMX"
++%meson --auto-features=auto --sysconfdir=%{_hal_sysconfdir}\
+ %if "%{target}" == "rpi"
-%configure \
- --disable-static \
- --prefix=/usr \
- --with-omx-target=exynos64 \
- sysconfdir=%{_hal_sysconfdir}
++ -D target=rpi\
++ -D header_path=/opt/vc/include/interface/vmcs_host/khronos/IL
+ %else
+ %ifarch aarch64
-%configure \
- --disable-static \
- --prefix=/usr \
- --with-omx-target=exynos \
- --enable-vp9 \
- sysconfdir=%{_hal_sysconfdir}
++ -D target=exynos64
+ %else
-
-make %{?jobs:-j%jobs}
-
++ -D target=exynos\
++ -D vp9=true
+ %endif
+ %endif
-%make_install
++%meson_build
+
+ %install
+ rm -rf %{buildroot}
-%manifest gst-omx.manifest
++%meson_install
+
+ %files
++%manifest %{name}.manifest
+ %defattr(-,root,root,-)
+ %{_libdir}/gstreamer-1.0/libgstomx.so
+ %license COPYING
+