summaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch
diff options
context:
space:
mode:
authorGerrit Code Review <gerrit@automotivelinux.org>2017-01-19 07:01:22 +0000
committerGerrit Code Review <gerrit@automotivelinux.org>2017-01-19 07:01:22 +0000
commita89b8302db0346269f4202e95ca85dbbb6f75a8e (patch)
tree873e234062fb0fcd8c71bd031bdaa217c877648c /meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch
parent73e6110c6c12a875da9b6da46c8ddaaff79e3c79 (diff)
parent793d8d01d0377dad21f4e1a330f00d822eced086 (diff)
Merge "Merge branch 'chinook_fixed' into chinook" into chinook
Diffstat (limited to 'meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch')
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch2759
1 files changed, 2759 insertions, 0 deletions
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch
new file mode 100644
index 0000000..23a3dfe
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch
@@ -0,0 +1,2759 @@
+From dcf585068bbb591431a999656359627cccd38716 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 25 Aug 2016 18:37:44 +0300
+Subject: [PATCH 03/10] omxvideoenc: export dmafd buffer through own buffer
+ pool
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ configure.ac | 17 +
+ omx/Makefile.am | 1 +
+ omx/gstomxbufferpool.c | 845 +++++++++++++++++++++++++++++++++++++++++++
+ omx/gstomxbufferpool.h | 106 ++++++
+ omx/gstomxvideodec.c | 924 +-----------------------------------------------
+ omx/gstomxvideoenc.c | 578 ++++++++++++++++++++++--------
+ omx/gstomxvideoenc.h | 11 +
+ 7 files changed, 1420 insertions(+), 1062 deletions(-)
+ create mode 100644 omx/gstomxbufferpool.c
+ create mode 100644 omx/gstomxbufferpool.h
+
+diff --git a/configure.ac b/configure.ac
+index 6aae527..57f5ae9 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -245,6 +245,23 @@ AC_CHECK_LIB([mmngrbuf], [mmngr_export_start_in_user],
+ ])
+ fi
+
++dnl check OMXR_Extension_video.h
++AC_CHECK_HEADER([OMXR_Extension_video.h],
++ [AC_DEFINE(HAVE_VIDEOR_EXT, 1, [Define if you have OMXR_Extension_video.h header])],
++ [],
++ [AC_INCLUDES_DEFAULT])
++dnl check OMXR_Extension_vecmn.h
++AC_CHECK_HEADER([OMXR_Extension_vecmn.h],
++ [AC_DEFINE(HAVE_VIDEOENC_EXT, 1, [Define if you have OMXR_Extension_vecmn.h header])],
++ [],
++ [AC_INCLUDES_DEFAULT])
++
++dnl check OMXR_Extension_vdcmn.h
++AC_CHECK_HEADER([OMXR_Extension_vdcmn.h],
++ [AC_DEFINE(HAVE_VIDEODEC_EXT, 1, [Define if you have OMXR_Extension_vdcmn.h header])],
++ [],
++ [AC_INCLUDES_DEFAULT])
++
+ dnl check page alignment option for NV12 planes
+ AC_ARG_ENABLE([nv12-page-alignment],
+ [AS_HELP_STRING([--enable-nv12-page-alignment],
+diff --git a/omx/Makefile.am b/omx/Makefile.am
+index 3ec6173..3619281 100644
+--- a/omx/Makefile.am
++++ b/omx/Makefile.am
+@@ -12,6 +12,7 @@ endif
+
+ libgstomx_la_SOURCES = \
+ gstomx.c \
++ gstomxbufferpool.c \
+ gstomxvideodec.c \
+ gstomxvideoenc.c \
+ gstomxaudioenc.c \
+diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c
+new file mode 100644
+index 0000000..2585a72
+--- /dev/null
++++ b/omx/gstomxbufferpool.c
+@@ -0,0 +1,845 @@
++/*
++ * 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>
++ * Copyright (C) 2015, Renesas Electronics Corporation
++ *
++ * 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"
++#include "gstomxvideodec.h"
++#include "gstomxvideoenc.h"
++#include "gst/allocators/gstdmabuf.h"
++#ifdef HAVE_MMNGRBUF
++#include "mmngr_buf_user_public.h"
++#endif
++#ifdef HAVE_VIDEODEC_EXT
++#include "OMXR_Extension_vdcmn.h"
++#endif
++#ifdef HAVE_VIDEOENC_EXT
++#include "OMXR_Extension_vecmn.h"
++#endif
++#include <unistd.h> /* getpagesize() */
++
++/**
++ * GST_ROUND_UP_N:
++ * @num: integrer value to round up
++ * @align: a power of two to round up to
++ *
++ * Rounds an integer value up to the next multiple of @align. @align MUST be a
++ * power of two.
++ */
++#define GST_ROUND_UP_N(num,align) ((((num) + ((align) - 1)) & ~((align) - 1)))
++
++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;
++ }
++}
++
++#if defined (HAVE_MMNGRBUF) && defined (HAVE_VIDEODEC_EXT)
++static gboolean
++gst_omx_buffer_pool_export_dmabuf (GstOMXBufferPool * pool,
++ guint phys_addr, gint size, gint * id_export, gint * dmabuf_fd)
++{
++ gint res;
++
++ res =
++ mmngr_export_start_in_user (id_export,
++ (gsize) size, phys_addr, dmabuf_fd);
++ if (res != R_MM_OK) {
++ GST_ERROR_OBJECT (pool,
++ "mmngr_export_start_in_user failed (phys_addr:0x%08x)", phys_addr);
++ return FALSE;
++ }
++ GST_DEBUG_OBJECT (pool,
++ "Export dmabuf:%d id_export:%d (phys_addr:0x%08x)", *dmabuf_fd,
++ *id_export, phys_addr);
++
++ return TRUE;
++}
++
++/* This function will create a GstBuffer contain dmabuf_fd of decoded
++ * video got from Media Component
++ */
++static GstBuffer *
++gst_omx_buffer_pool_create_buffer_contain_dmabuf (GstOMXBufferPool * self,
++ GstOMXBuffer * omx_buf, gint * stride, gsize * offset)
++{
++ gint dmabuf_fd[GST_VIDEO_MAX_PLANES];
++ gint plane_size[GST_VIDEO_MAX_PLANES];
++ gint plane_size_ext[GST_VIDEO_MAX_PLANES];
++ gint dmabuf_id[GST_VIDEO_MAX_PLANES];
++ gint page_offset[GST_VIDEO_MAX_PLANES];
++ GstBuffer *new_buf;
++ gint i;
++ gint page_size;
++ guint phys_addr = 0;
++
++ new_buf = gst_buffer_new ();
++ page_size = getpagesize ();
++
++ GST_DEBUG_OBJECT (self, "Creating dmabuf mem pBuffer=%p",
++ omx_buf->omx_buf->pBuffer);
++
++ if (GST_IS_OMX_VIDEO_DEC (self->element)) {
++ OMXR_MC_VIDEO_DECODERESULTTYPE *decode_res =
++ (OMXR_MC_VIDEO_DECODERESULTTYPE *) omx_buf->omx_buf->pOutputPortPrivate;
++ phys_addr = decode_res->pvPhysImageAddressY;
++ } else if (GST_IS_OMX_VIDEO_ENC (self->element)) {
++ /* private data is a physical address of HW buffer */
++ phys_addr = (guint) omx_buf->omx_buf->pInputPortPrivate;
++ }
++
++ if (phys_addr == 0) {
++ GST_ERROR_OBJECT (self, "Invalid phys addr for OMX buffer");
++ return NULL;
++ }
++
++ for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->video_info); i++) {
++ guint plane_addr = 0;
++ GstMemory *mem;
++
++ plane_addr = phys_addr + offset[i];
++ /* Calculate offset between physical address and page boundary */
++ page_offset[i] = plane_addr & (page_size - 1);
++
++ plane_size[i] = stride[i] *
++ GST_VIDEO_INFO_COMP_HEIGHT (&self->video_info, i);
++
++ /* When downstream plugins do mapping from dmabuf fd it requires
++ * mapping from boundary page and size align for page size so
++ * memory for plane must increase to handle for this case */
++ plane_size_ext[i] = GST_ROUND_UP_N (plane_size[i] + page_offset[i],
++ page_size);
++
++ if (!gst_omx_buffer_pool_export_dmabuf (self, plane_addr,
++ plane_size_ext[i], &dmabuf_id[i], &dmabuf_fd[i])) {
++ GST_ERROR_OBJECT (self, "dmabuf exporting failed");
++ return NULL;
++ }
++
++ g_array_append_val (self->id_array, dmabuf_id[i]);
++ /* Set offset's information */
++ mem = gst_dmabuf_allocator_alloc (self->allocator, dmabuf_fd[i],
++ plane_size_ext[i]);
++ mem->offset = page_offset[i];
++ mem->size = plane_size[i];
++ gst_buffer_append_memory (new_buf, mem);
++ }
++
++ g_ptr_array_add (self->buffers, new_buf);
++ gst_buffer_add_video_meta_full (new_buf, GST_VIDEO_FRAME_FLAG_NONE,
++ GST_VIDEO_INFO_FORMAT (&self->video_info),
++ GST_VIDEO_INFO_WIDTH (&self->video_info),
++ GST_VIDEO_INFO_HEIGHT (&self->video_info),
++ GST_VIDEO_INFO_N_PLANES (&self->video_info), offset, stride);
++
++ return new_buf;
++}
++#endif
++
++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, };
++
++ 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 (GST_IS_OMX_VIDEO_DEC (pool->element) &&
++ GST_OMX_VIDEO_DEC (pool->element)->use_dmabuf == TRUE &&
++ (omx_buf->omx_buf->pOutputPortPrivate)) {
++#if defined (HAVE_MMNGRBUF) && defined (HAVE_VIDEODEC_EXT)
++ if (pool->allocator)
++ gst_object_unref (pool->allocator);
++ pool->allocator = gst_dmabuf_allocator_new ();
++ buf = gst_omx_buffer_pool_create_buffer_contain_dmabuf (pool,
++ omx_buf, (gint *) (&stride), (gsize *) (&offset));
++ if (!buf) {
++ GST_ERROR_OBJECT (pool, "Can not create buffer contain dmabuf");
++ return GST_FLOW_ERROR;
++ }
++#else
++ GST_ELEMENT_ERROR (pool->element, STREAM, FAILED, (NULL),
++ ("dmabuf mode is invalid now due to not have MMNGR_BUF or MC does not support getting physical address"));
++ return GST_FLOW_ERROR;
++#endif
++ } else {
++ if (GST_IS_OMX_VIDEO_ENC (pool->element) &&
++ pool->port->port_def.eDir == OMX_DirInput)
++ /* Propose actual area of encoder to upstream */
++ mem = gst_memory_new_wrapped (0, omx_buf->omx_buf->pBuffer,
++ omx_buf->omx_buf->nAllocLen, 0, 0, NULL, NULL);
++ else
++ 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);
++ 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) &&
++ ((GST_OMX_VIDEO_DEC (pool->element)->use_dmabuf) == FALSE)) {
++ 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 {
++ if (GST_IS_OMX_VIDEO_ENC (pool->element)) {
++ GstBuffer *buf;
++ GstOMXBuffer *omx_buf;
++ gint count = 0;
++
++ /* Search on number of OMXBuffer of port to find available GstBuffer
++ * (emptied OMXBuffer) to propose to upstream. If after 3 times searching,
++ * can not find target GstBuffer, return flow error
++ */
++ do {
++ buf = g_ptr_array_index (pool->buffers, pool->enc_buffer_index);
++ g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
++
++ omx_buf =
++ gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf),
++ gst_omx_buffer_data_quark);
++ pool->enc_buffer_index++;
++ if (pool->enc_buffer_index == pool->port->port_def.nBufferCountActual)
++ pool->enc_buffer_index = 0;
++
++ count += 1;
++ } while (omx_buf->used == TRUE &&
++ count < pool->port->port_def.nBufferCountActual * 3);
++
++ if (count == pool->port->port_def.nBufferCountActual * 3) {
++ ret = GST_FLOW_ERROR;
++ GST_ERROR_OBJECT (pool,
++ "Can not acquire buffer after 3 times searching");
++ } else {
++ *buffer = buf;
++ ret = GST_FLOW_OK;
++ }
++ } 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.
++ */
++ if (GST_OMX_VIDEO_ENC (pool->element)->no_copy == FALSE) {
++ 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);
++
++#ifdef HAVE_MMNGRBUF
++ if (GST_OMX_VIDEO_DEC (pool->element)->use_dmabuf) {
++ gint i;
++ gint dmabuf_id;
++
++ for (i = 0; i < pool->id_array->len; i++) {
++ dmabuf_id = g_array_index (pool->id_array, gint, i);
++ if (dmabuf_id >= 0) {
++ GST_DEBUG_OBJECT (pool, "mmngr_export_end_in_user (%d)", dmabuf_id);
++ mmngr_export_end_in_user (dmabuf_id);
++ } else {
++ GST_WARNING_OBJECT (pool, "Invalid dmabuf_id");
++ }
++ }
++ }
++ g_array_free (pool->id_array, TRUE);
++#endif
++
++ 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);
++#ifdef HAVE_MMNGRBUF
++ pool->id_array = g_array_new (FALSE, FALSE, sizeof (gint));
++#endif
++ pool->enc_buffer_index = 0;
++}
++
++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
+new file mode 100644
+index 0000000..09cab8d
+--- /dev/null
++++ b/omx/gstomxbufferpool.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright 2014 Advanced Micro Devices, Inc.
++ * Author: Christian König <christian.koenig@amd.com>
++ * Copyright (C) 2015, Renesas Electronics Corporation
++ *
++ * 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;
++
++ /* Used during acquire for input port */
++ gint enc_buffer_index;
++#ifdef HAVE_MMNGRBUF
++ /* Array use to contain dma_id. It is used in export_end dmabuf area */
++ GArray *id_array;
++#endif
++
++ /* TRUE if the downstream buffer pool can handle
++ "videosink_buffer_creation_request" query */
++ gboolean vsink_buf_req_supported;
++};
++
++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 837c623..25b6b30 100644
+--- a/omx/gstomxvideodec.c
++++ b/omx/gstomxvideodec.c
+@@ -32,6 +32,7 @@
+ #include <unistd.h> /* getpagesize() */
+
+ #include "gstomxvideodec.h"
++#include "gstomxbufferpool.h"
+
+ #ifdef HAVE_MMNGRBUF
+ #include "gst/allocators/gstdmabuf.h"
+@@ -42,898 +43,6 @@
+ GST_DEBUG_CATEGORY_STATIC (gst_omx_video_dec_debug_category);
+ #define GST_CAT_DEFAULT gst_omx_video_dec_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;
+-};
+-
+-/* User data and function for release OMX buffer in no-copy mode */
+-struct GstOMXBufferCallback
+-{
+- GstOMXPort * out_port;
+- GstOMXBuffer * buf;
+-};
+-
+-#define GST_OMX_MEMORY_TYPE "openmax"
+-#define DEFAULT_FRAME_PER_SECOND 30
+-
+-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;
+-}
+-
+-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);
+-}
+-
+-#ifndef HAVE_MMNGRBUF
+-static GstMemory *
+-gst_omx_memory_allocator_alloc (GstAllocator * allocator, GstMemoryFlags flags,
+- GstOMXBuffer * buf, gsize offset, gsize size)
+-{
+- GstOMXMemory *mem;
+-
+- /* 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;
+-
+- 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, buf->port->port_def.nBufferAlignment,
+- offset, size);
+-
+- 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
+- * 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 GST_OMX_BUFFER_POOL(pool) ((GstOMXBufferPool *) pool)
+-typedef struct _GstOMXBufferPool GstOMXBufferPool;
+-typedef struct _GstOMXBufferPoolClass GstOMXBufferPoolClass;
+-
+-typedef struct _GstOMXVideoDecBufferData GstOMXVideoDecBufferData;
+-
+-struct _GstOMXBufferPool
+-{
+- GstVideoBufferPool parent;
+-
+- GstElement *element;
+-
+- GstCaps *caps;
+- gboolean add_videometa;
+- 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;
+-
+- /* TRUE if the downstream buffer pool can handle
+- "videosink_buffer_creation_request" query */
+- gboolean vsink_buf_req_supported;
+-};
+-
+-struct _GstOMXBufferPoolClass
+-{
+- GstVideoBufferPoolClass parent_class;
+-};
+-
+-struct _GstOMXVideoDecBufferData
+-{
+- gboolean already_acquired;
+-
+-#ifdef HAVE_MMNGRBUF
+- gint id_export[GST_VIDEO_MAX_PLANES];
+-#endif
+-};
+-
+-GType gst_omx_buffer_pool_get_type (void);
+-
+-G_DEFINE_TYPE (GstOMXBufferPool, gst_omx_buffer_pool, GST_TYPE_BUFFER_POOL);
+-
+-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;
+- GstOMXVideoDec *self;
+- self = GST_OMX_VIDEO_DEC (pool->element);
+-
+- 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));
+- }
+- }
+- } else {
+- gsize offset[4] = { 0, };
+- gint stride[4] = { 0, };
+- gsize plane_size[4] = { 0, };
+-#ifndef HAVE_MMNGRBUF
+- guint n_planes;
+-#endif
+- gint i;
+- GstOMXVideoDecBufferData *vdbuf_data;
+-
+- switch (pool->video_info.finfo->format) {
+- case GST_VIDEO_FORMAT_I420:
+- offset[0] = 0;
+- stride[0] = pool->port->port_def.format.video.nStride;
+- offset[1] = stride[0] * pool->port->port_def.format.video.nSliceHeight;
+- stride[1] = pool->port->port_def.format.video.nStride / 2;
+- offset[2] =
+- offset[1] +
+- stride[1] * (pool->port->port_def.format.video.nSliceHeight / 2);
+- stride[2] = pool->port->port_def.format.video.nStride / 2;
+- plane_size[0] = pool->port->port_def.format.video.nStride *
+- pool->port->port_def.format.video.nFrameHeight;
+- plane_size[1] = plane_size[2] = plane_size[0] / 4;
+-
+-#ifndef HAVE_MMNGRBUF
+- n_planes = 3;
+-#endif
+- break;
+- case GST_VIDEO_FORMAT_NV12:
+- offset[0] = 0;
+- stride[0] = pool->port->port_def.format.video.nStride;
+- offset[1] = stride[0] * pool->port->port_def.format.video.nSliceHeight;
+- stride[1] = pool->port->port_def.format.video.nStride;
+- plane_size[0] = pool->port->port_def.format.video.nStride *
+- pool->port->port_def.format.video.nFrameHeight;
+- plane_size[1] = plane_size[0] / 2;
+-
+-#ifndef HAVE_MMNGRBUF
+- n_planes = 2;
+-#endif
+- break;
+- default:
+- g_assert_not_reached ();
+- break;
+- }
+-
+- buf = gst_buffer_new ();
+-
+-#ifndef HAVE_MMNGRBUF
+- if (self->use_dmabuf == FALSE)
+- for (i = 0; i < n_planes; i++)
+- gst_buffer_append_memory (buf,
+- gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf,
+- offset[i], plane_size[i]));
+-#endif
+-
+- g_ptr_array_add (pool->buffers, buf);
+-
+- if (pool->add_videometa)
+- 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);
+-
+- /* Initialize an already_acquired flag */
+- vdbuf_data = g_slice_new (GstOMXVideoDecBufferData);
+- vdbuf_data->already_acquired = FALSE;
+-#ifdef HAVE_MMNGRBUF
+- if (self->use_dmabuf)
+- for (i = 0; i < GST_VIDEO_MAX_PLANES; i++)
+- vdbuf_data->id_export[i] = -1;
+-#endif
+-
+- omx_buf->private_data = (void *) vdbuf_data;
+- }
+-
+- 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);
+- GstOMXBuffer *omx_buf;
+- GstOMXVideoDec *self;
+- self = GST_OMX_VIDEO_DEC (pool->element);
+-#ifdef HAVE_MMNGRBUF
+- GstOMXVideoDecBufferData *vdbuf_data;
+- gint i;
+-#endif
+-
+- /* 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);
+-
+- omx_buf =
+- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
+- gst_omx_buffer_data_quark);
+-#ifdef HAVE_MMNGRBUF
+- if (self->use_dmabuf) {
+- vdbuf_data = (GstOMXVideoDecBufferData *) omx_buf->private_data;
+- if (vdbuf_data) {
+- for (i = 0; i < GST_VIDEO_MAX_PLANES; i++)
+- if (vdbuf_data->id_export[i] >= 0)
+- mmngr_export_end_in_user (vdbuf_data->id_export[i]);
+- }
+- }
+-#endif
+- g_slice_free (GstOMXVideoDecBufferData, omx_buf->private_data);
+-
+- 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);
+-}
+-
+-#ifdef HAVE_MMNGRBUF
+-static GstBuffer *
+-gst_omx_buffer_pool_request_videosink_buffer_creation (GstOMXBufferPool * pool,
+- gint dmabuf_fd[GST_VIDEO_MAX_PLANES], gpointer plane_buf[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES])
+-{
+- GstQuery *query;
+- GValue val = { 0, };
+- GstStructure *structure;
+- const GValue *value;
+- GstBuffer *buffer;
+- GArray *dmabuf_array;
+- GArray *stride_array;
+- GArray *planebuf_array;
+- gint n_planes;
+- gint i;
+-
+- g_value_init (&val, G_TYPE_POINTER);
+- g_value_set_pointer (&val, (gpointer) pool->allocator);
+-
+- dmabuf_array = g_array_new (FALSE, FALSE, sizeof (gint));
+- stride_array = g_array_new (FALSE, FALSE, sizeof (gint));
+- planebuf_array = g_array_new (FALSE, FALSE, sizeof (gpointer));
+-
+- n_planes = GST_VIDEO_INFO_N_PLANES (&pool->video_info);
+- for (i = 0; i < n_planes; i++) {
+- g_array_append_val (dmabuf_array, dmabuf_fd[i]);
+- g_array_append_val (stride_array, stride[i]);
+- g_array_append_val (planebuf_array, plane_buf[i]);
+- }
+-
+- structure = gst_structure_new ("videosink_buffer_creation_request",
+- "width", G_TYPE_INT, pool->port->port_def.format.video.nFrameWidth,
+- "height", G_TYPE_INT, pool->port->port_def.format.video.nFrameHeight,
+- "stride", G_TYPE_ARRAY, stride_array,
+- "dmabuf", G_TYPE_ARRAY, dmabuf_array,
+- "planebuf", G_TYPE_ARRAY, planebuf_array,
+- "allocator", G_TYPE_POINTER, &val,
+- "format", G_TYPE_STRING,
+- gst_video_format_to_string (pool->video_info.finfo->format),
+- "n_planes", G_TYPE_INT, n_planes, NULL);
+-
+- query = gst_query_new_custom (GST_QUERY_CUSTOM, structure);
+-
+- GST_DEBUG_OBJECT (pool, "send a videosink_buffer_creation_request query");
+-
+- if (!gst_pad_peer_query (GST_VIDEO_DECODER_SRC_PAD (pool->element), query)) {
+- GST_ERROR_OBJECT (pool, "videosink_buffer_creation_request query failed");
+- return NULL;
+- }
+-
+- value = gst_structure_get_value (structure, "buffer");
+- buffer = gst_value_get_buffer (value);
+- if (buffer == NULL) {
+- GST_ERROR_OBJECT (pool,
+- "could not get a buffer from videosink_buffer_creation query");
+- return NULL;
+- }
+-
+- gst_query_unref (query);
+-
+- g_array_free (dmabuf_array, TRUE);
+- g_array_free (stride_array, TRUE);
+-
+- return buffer;
+-}
+-#endif
+-
+-#ifdef HAVE_MMNGRBUF
+-static gboolean
+-gst_omx_buffer_pool_export_dmabuf (GstOMXBufferPool * pool,
+- guint phys_addr, gint size, gint boundary, gint * id_export,
+- gint * dmabuf_fd)
+-{
+- gint res;
+-
+- res =
+- mmngr_export_start_in_user (id_export,
+- (size + boundary - 1) & ~(boundary - 1), (unsigned long) phys_addr,
+- dmabuf_fd);
+- if (res != R_MM_OK) {
+- GST_ERROR_OBJECT (pool,
+- "mmngr_export_start_in_user failed (phys_addr:0x%08x)", phys_addr);
+- return FALSE;
+- }
+- GST_DEBUG_OBJECT (pool,
+- "Export dmabuf:%d id_export:%d (phys_addr:0x%08x)", *dmabuf_fd,
+- *id_export, phys_addr);
+-
+- return TRUE;
+-}
+-#endif
+-
+-static GstFlowReturn
+-gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
+- GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
+-{
+- GstFlowReturn ret;
+- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
+- GstOMXVideoDec *self;
+- self = GST_OMX_VIDEO_DEC (pool->element);
+-
+- if (pool->port->port_def.eDir == OMX_DirOutput) {
+- GstBuffer *buf;
+- GstOMXBuffer *omx_buf;
+- GstOMXVideoDecBufferData *vdbuf_data;
+-#ifdef HAVE_MMNGRBUF
+- guint n_mem;
+-#endif
+-
+- 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);
+-
+- omx_buf =
+- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf),
+- gst_omx_buffer_data_quark);
+-
+- vdbuf_data = (GstOMXVideoDecBufferData *) omx_buf->private_data;
+-#ifdef HAVE_MMNGRBUF
+- if (self->use_dmabuf)
+- {
+- n_mem = gst_buffer_n_memory (buf);
+- if (n_mem == 0) {
+- GstBuffer *new_buf;
+- GstVideoMeta *vmeta;
+- gint n_planes;
+- gint i;
+- gint dmabuf_fd[GST_VIDEO_MAX_PLANES];
+- gint plane_size[GST_VIDEO_MAX_PLANES];
+- gpointer plane_buf[GST_VIDEO_MAX_PLANES];
+- guint phys_addr;
+- OMXR_MC_VIDEO_DECODERESULTTYPE *decode_res =
+- (OMXR_MC_VIDEO_DECODERESULTTYPE *) omx_buf->
+- omx_buf->pOutputPortPrivate;
+- gint page_size;
+-
+- GST_DEBUG_OBJECT (pool, "Create dmabuf mem pBuffer=%p",
+- omx_buf->omx_buf->pBuffer);
+-
+- vmeta = gst_buffer_get_video_meta (buf);
+-
+- phys_addr = (guint) decode_res->pvPhysImageAddressY;
+- page_size = getpagesize ();
+-
+- /* Export a dmabuf file descriptor from the head of Y plane to
+- * the end of the buffer so that mapping the whole plane as
+- * contiguous memory is available. */
+- if (!gst_omx_buffer_pool_export_dmabuf (pool, phys_addr,
+- pool->port->port_def.nBufferSize, page_size,
+- &vdbuf_data->id_export[0], &dmabuf_fd[0])) {
+- GST_ERROR_OBJECT (pool, "dmabuf exporting failed");
+- return GST_FLOW_ERROR;
+- }
+-
+- plane_size[0] = vmeta->stride[0] *
+- GST_VIDEO_INFO_COMP_HEIGHT (&pool->video_info, 0);
+- plane_buf[0] = omx_buf->omx_buf->pBuffer;
+-
+- /* Export dmabuf file descriptors from second and subsequent planes */
+- n_planes = GST_VIDEO_INFO_N_PLANES (&pool->video_info);
+- for (i = 1; i < n_planes; i++) {
+- phys_addr = (guint) decode_res->pvPhysImageAddressY + vmeta->offset[i];
+- plane_size[i] = vmeta->stride[i] *
+- GST_VIDEO_INFO_COMP_HEIGHT (&pool->video_info, i);
+- plane_buf[i] = omx_buf->omx_buf->pBuffer + vmeta->offset[i];
+-
+- if (!gst_omx_buffer_pool_export_dmabuf (pool, phys_addr, plane_size[i],
+- page_size, &vdbuf_data->id_export[i], &dmabuf_fd[i])) {
+- GST_ERROR_OBJECT (pool, "dmabuf exporting failed");
+- return GST_FLOW_ERROR;
+- }
+- }
+-
+- if (pool->vsink_buf_req_supported)
+- new_buf = gst_omx_buffer_pool_request_videosink_buffer_creation (pool,
+- dmabuf_fd, plane_buf, vmeta->stride);
+- else {
+- GstVideoMeta *new_meta;
+-
+- new_buf = gst_buffer_new ();
+- for (i = 0; i < n_planes; i++)
+- gst_buffer_append_memory (new_buf,
+- gst_dmabuf_allocator_alloc (pool->allocator, dmabuf_fd[i],
+- plane_size[i]));
+-
+- gst_buffer_add_video_meta_full (new_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), vmeta->offset,
+- vmeta->stride);
+-
+- new_meta = gst_buffer_get_video_meta (new_buf);
+- /* To avoid detaching meta data when a buffer returns
+- to the buffer pool */
+- GST_META_FLAG_SET (new_meta, GST_META_FLAG_POOLED);
+- }
+-
+- g_ptr_array_remove_index (pool->buffers, pool->current_buffer_index);
+-
+- gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
+- gst_omx_buffer_data_quark, NULL, NULL);
+-
+- gst_buffer_unref (buf);
+-
+- gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (new_buf),
+- gst_omx_buffer_data_quark, omx_buf, NULL);
+-
+- g_ptr_array_add (pool->buffers, new_buf);
+-
+- *buffer = new_buf;
+- } else
+- *buffer = buf;
+- } else
+-#endif
+- *buffer = buf;
+-
+- vdbuf_data->already_acquired = TRUE;
+-
+- ret = GST_FLOW_OK;
+- } 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) {
+- GstOMXVideoDecBufferData *vdbuf_data;
+-
+- omx_buf =
+- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
+- gst_omx_buffer_data_quark);
+-
+- vdbuf_data = (GstOMXVideoDecBufferData *) omx_buf->private_data;
+-
+- if (pool->port->port_def.eDir == OMX_DirOutput && !omx_buf->used &&
+- vdbuf_data->already_acquired) {
+- /* 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));
+- }
+- vdbuf_data->already_acquired = FALSE;
+- } else if (pool->port->port_def.eDir == OMX_DirInput && !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 ();
+-#ifdef HAVE_MMNGRBUF
+- pool->allocator = gst_dmabuf_allocator_new ();
+-#else
+- pool->allocator = g_object_new (gst_omx_memory_allocator_get_type (), NULL);
+-#endif
+-}
+-
+-static 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;
+- pool->vsink_buf_req_supported = FALSE;
+-
+- return GST_BUFFER_POOL (pool);
+-}
+-
+ typedef struct _BufferIdentification BufferIdentification;
+ struct _BufferIdentification
+ {
+@@ -979,8 +88,9 @@ static void gst_omx_video_dec_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+ static void gst_omx_video_dec_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
++/*
+ static void GstOMXBufCallbackfunc (struct GstOMXBufferCallback *);
+-
++*/
+ enum
+ {
+ PROP_0,
+@@ -999,6 +109,9 @@ enum
+ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec,
+ GST_TYPE_VIDEO_DECODER, DEBUG_INIT);
+
++/* Default fps for input files that does not support fps */
++#define DEFAULT_FRAME_PER_SECOND 30
++
+ static gsize
+ gst_omx_video_dec_copy_frame (GstOMXVideoDec * self, GstBuffer * inbuf,
+ guint offset, GstOMXBuffer * outbuf)
+@@ -1691,6 +804,7 @@ gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
+ return err;
+ }
+
++/*
+ static void GstOMXBufCallbackfunc (struct GstOMXBufferCallback *release)
+ {
+ if (!release)
+@@ -1702,6 +816,7 @@ static void GstOMXBufCallbackfunc (struct GstOMXBufferCallback *release)
+
+ g_free (release);
+ }
++*/
+
+ static GstBuffer *
+ gst_omx_video_dec_create_buffer_from_omx_output (GstOMXVideoDec * self,
+@@ -1762,7 +877,7 @@ gst_omx_video_dec_create_buffer_from_omx_output (GstOMXVideoDec * self,
+ GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, sliceheigh);
+ used_size = stride[i] *
+ GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, height);
+-
++#if 0
+ if (i == 0) {
+ struct GstOMXBufferCallback *release;
+ release = g_malloc (sizeof(struct GstOMXBufferCallback));
+@@ -1774,6 +889,7 @@ gst_omx_video_dec_create_buffer_from_omx_output (GstOMXVideoDec * self,
+ plane_size, 0, used_size, release, GstOMXBufCallbackfunc);
+ }
+ else
++#endif
+ /* Only release OMX buffer one time. Do not add callback
+ * function to other planes
+ * (These planes are from same OMX buffer) */
+@@ -2042,15 +1158,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
+
+ n = port->buffers->len;
+ for (i = 0; i < n; i++) {
+- GstBuffer *outbuf;
+- GstOMXBuffer *tmp;
+-
+- outbuf =
+- g_ptr_array_index (GST_OMX_BUFFER_POOL (self->
+- out_port_pool)->buffers, i);
+- tmp =
+- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (outbuf),
+- gst_omx_buffer_data_quark);
++ GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
+
+ if (tmp == buf)
+ break;
+@@ -2084,15 +1192,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
+
+ n = port->buffers->len;
+ for (i = 0; i < n; i++) {
+- GstBuffer *outbuf;
+- GstOMXBuffer *tmp;
+-
+- outbuf =
+- g_ptr_array_index (GST_OMX_BUFFER_POOL (self->
+- out_port_pool)->buffers, i);
+- tmp =
+- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (outbuf),
+- gst_omx_buffer_data_quark);
++ GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
+
+ if (tmp == buf)
+ break;
+diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c
+index cec44cb..b36c46e 100644
+--- a/omx/gstomxvideoenc.c
++++ b/omx/gstomxvideoenc.c
+@@ -28,6 +28,11 @@
+ #include <string.h>
+
+ #include "gstomxvideoenc.h"
++#include "gstomxbufferpool.h"
++#ifdef HAVE_MMNGRBUF
++#include "mmngr_buf_user_public.h"
++#endif
++#include "gst/allocators/gstdmabuf.h"
+
+ GST_DEBUG_CATEGORY_STATIC (gst_omx_video_enc_debug_category);
+ #define GST_CAT_DEFAULT gst_omx_video_enc_debug_category
+@@ -68,6 +73,13 @@ buffer_identification_free (BufferIdentification * id)
+ g_slice_free (BufferIdentification, id);
+ }
+
++/* Used in dmabuf mode */
++struct _GstOMXVideoEncPrivate
++{
++ /* Array contain id when using mmngrbuf to import fd */
++ GArray *id_array;
++};
++
+ /* prototypes */
+ static void gst_omx_video_enc_finalize (GObject * object);
+ static void gst_omx_video_enc_set_property (GObject * object, guint prop_id,
+@@ -109,7 +121,8 @@ enum
+ PROP_TARGET_BITRATE,
+ PROP_QUANT_I_FRAMES,
+ PROP_QUANT_P_FRAMES,
+- PROP_QUANT_B_FRAMES
++ PROP_QUANT_B_FRAMES,
++ PROP_NO_COPY
+ };
+
+ /* FIXME: Better defaults */
+@@ -175,6 +188,11 @@ gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass)
+ 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_READY));
++ g_object_class_install_property (gobject_class, PROP_NO_COPY,
++ g_param_spec_boolean ("no-copy", "Propose buffer to upstream",
++ "Whether or not to use no copy method",
++ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
++ GST_PARAM_MUTABLE_READY));
+
+ element_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state);
+@@ -210,7 +228,11 @@ gst_omx_video_enc_init (GstOMXVideoEnc * self)
+ self->quant_i_frames = GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT;
+ self->quant_p_frames = GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT;
+ self->quant_b_frames = GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT;
+-
++ self->no_copy = TRUE;
++ self->priv =
++ G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_OMX_VIDEO_ENC,
++ GstOMXVideoEncPrivate);
++ self->priv->id_array = g_array_new (FALSE, FALSE, sizeof (gint));
+ g_mutex_init (&self->drain_lock);
+ g_cond_init (&self->drain_cond);
+ }
+@@ -413,6 +435,16 @@ gst_omx_video_enc_finalize (GObject * object)
+ g_mutex_clear (&self->drain_lock);
+ g_cond_clear (&self->drain_cond);
+
++#ifdef HAVE_MMNGRBUF
++ if (self->priv->id_array->len > 0) {
++ gint i;
++ for (i = 0; i < self->priv->id_array->len; i++)
++ mmngr_import_end_in_user (g_array_index (self->priv->id_array, gint,
++ i));
++ }
++#endif;
++ g_array_free (self->priv->id_array, TRUE);
++
+ G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object);
+ }
+
+@@ -453,6 +485,9 @@ gst_omx_video_enc_set_property (GObject * object, guint prop_id,
+ case PROP_QUANT_B_FRAMES:
+ self->quant_b_frames = g_value_get_uint (value);
+ break;
++ case PROP_NO_COPY:
++ self->no_copy = g_value_get_boolean (value);
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -481,6 +516,9 @@ gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value,
+ case PROP_QUANT_B_FRAMES:
+ g_value_set_uint (value, self->quant_b_frames);
+ break;
++ case PROP_NO_COPY:
++ g_value_set_boolean (value, self->no_copy);
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -1125,163 +1163,168 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
+ GST_DEBUG_OBJECT (self, "Setting new format %s",
+ gst_video_format_to_string (info->finfo->format));
+
+- gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
+-
+- needs_disable =
+- gst_omx_component_get_state (self->enc,
+- GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
+- /* If the component is not in Loaded state and a real format change happens
+- * we have to disable the port and re-allocate all buffers. If no real
+- * format change happened we can just exit here.
++ /* If there is inport pool, it means that OMXBuffer has already allocated on
++ * propose_allocation. Do not allocate OMXBuffer on set_format
+ */
+- if (needs_disable) {
+- GST_DEBUG_OBJECT (self, "Need to disable and drain encoder");
+- gst_omx_video_enc_drain (self, FALSE);
+- gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
+-
+- /* Wait until the srcpad loop is finished,
+- * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
+- * caused by using this lock from inside the loop function */
+- GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
+- gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
+- GST_VIDEO_ENCODER_STREAM_LOCK (self);
+-
+- if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
+- return FALSE;
+- if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
+- return FALSE;
+- if (gst_omx_port_wait_buffers_released (self->enc_in_port,
+- 5 * GST_SECOND) != OMX_ErrorNone)
+- return FALSE;
+- if (gst_omx_port_wait_buffers_released (self->enc_out_port,
+- 1 * GST_SECOND) != OMX_ErrorNone)
+- return FALSE;
+- if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
+- return FALSE;
+- if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
+- return FALSE;
+- if (gst_omx_port_wait_enabled (self->enc_in_port,
+- 1 * GST_SECOND) != OMX_ErrorNone)
+- return FALSE;
+- if (gst_omx_port_wait_enabled (self->enc_out_port,
+- 1 * GST_SECOND) != OMX_ErrorNone)
+- return FALSE;
+-
+- GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
+- }
++ if (!self->in_port_pool) {
++ gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
++
++ needs_disable =
++ gst_omx_component_get_state (self->enc,
++ GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
++ /* If the component is not in Loaded state and a real format change happens
++ * we have to disable the port and re-allocate all buffers. If no real
++ * format change happened we can just exit here.
++ */
++ if (needs_disable) {
++ GST_DEBUG_OBJECT (self, "Need to disable and drain encoder");
++ gst_omx_video_enc_drain (self, FALSE);
++ gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
++
++ /* Wait until the srcpad loop is finished,
++ * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks
++ * caused by using this lock from inside the loop function */
++ GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
++ gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder));
++ GST_VIDEO_ENCODER_STREAM_LOCK (self);
+
+- negotiation_map = gst_omx_video_enc_get_supported_colorformats (self);
+- if (!negotiation_map) {
+- /* Fallback */
+- switch (info->finfo->format) {
+- case GST_VIDEO_FORMAT_I420:
+- port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
+- break;
+- case GST_VIDEO_FORMAT_NV16:
+- case GST_VIDEO_FORMAT_NV12:
+- port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+- break;
+- default:
+- GST_ERROR_OBJECT (self, "Unsupported format %s",
+- gst_video_format_to_string (info->finfo->format));
++ if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
+ return FALSE;
+- break;
++ if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
++ return FALSE;
++ if (gst_omx_port_wait_buffers_released (self->enc_in_port,
++ 5 * GST_SECOND) != OMX_ErrorNone)
++ return FALSE;
++ if (gst_omx_port_wait_buffers_released (self->enc_out_port,
++ 1 * GST_SECOND) != OMX_ErrorNone)
++ return FALSE;
++ if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
++ return FALSE;
++ if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
++ return FALSE;
++ if (gst_omx_port_wait_enabled (self->enc_in_port,
++ 1 * GST_SECOND) != OMX_ErrorNone)
++ return FALSE;
++ if (gst_omx_port_wait_enabled (self->enc_out_port,
++ 1 * GST_SECOND) != OMX_ErrorNone)
++ return FALSE;
++
++ GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
+ }
+- } else {
+- for (l = negotiation_map; l; l = l->next) {
+- VideoNegotiationMap *m = l->data;
+
+- if (m->format == info->finfo->format) {
+- port_def.format.video.eColorFormat = m->type;
+- break;
++ negotiation_map = gst_omx_video_enc_get_supported_colorformats (self);
++ if (!negotiation_map) {
++ /* Fallback */
++ switch (info->finfo->format) {
++ case GST_VIDEO_FORMAT_I420:
++ port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
++ break;
++ case GST_VIDEO_FORMAT_NV16:
++ case GST_VIDEO_FORMAT_NV12:
++ port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
++ break;
++ default:
++ GST_ERROR_OBJECT (self, "Unsupported format %s",
++ gst_video_format_to_string (info->finfo->format));
++ return FALSE;
++ break;
++ }
++ } else {
++ for (l = negotiation_map; l; l = l->next) {
++ VideoNegotiationMap *m = l->data;
++
++ if (m->format == info->finfo->format) {
++ port_def.format.video.eColorFormat = m->type;
++ break;
++ }
+ }
++ g_list_free_full (negotiation_map,
++ (GDestroyNotify) video_negotiation_map_free);
+ }
+- g_list_free_full (negotiation_map,
+- (GDestroyNotify) video_negotiation_map_free);
+- }
+
+- port_def.format.video.nFrameWidth = info->width;
+- if (port_def.nBufferAlignment)
+- port_def.format.video.nStride =
+- (info->width + port_def.nBufferAlignment - 1) &
+- (~(port_def.nBufferAlignment - 1));
+- else
+- {
+- if (klass->cdata.hacks & GST_OMX_HACK_RENESAS_ENCMC_STRIDE_ALIGN)
++ port_def.format.video.nFrameWidth = info->width;
++ if (port_def.nBufferAlignment)
++ port_def.format.video.nStride =
++ (info->width + port_def.nBufferAlignment - 1) &
++ (~(port_def.nBufferAlignment - 1));
++ else
+ {
+- switch (port_def.format.video.eColorFormat) {
+- case OMX_COLOR_FormatYUV420Planar: {
+- /*Renesas encode MC only support following strides*/
+- if (info->width <= 256)
+- port_def.format.video.nStride = 256;
+- else if ((info->width > 256) && (info->width <= 512))
+- port_def.format.video.nStride = 512;
+- else if ((info->width > 512) && (info->width <= 1024))
+- port_def.format.video.nStride = 1024;
+- else
+- port_def.format.video.nStride = 2048;
++ if (klass->cdata.hacks & GST_OMX_HACK_RENESAS_ENCMC_STRIDE_ALIGN)
++ {
++ switch (port_def.format.video.eColorFormat) {
++ case OMX_COLOR_FormatYUV420Planar: {
++ /*Renesas encode MC only support following strides*/
++ if (info->width <= 256)
++ port_def.format.video.nStride = 256;
++ else if ((info->width > 256) && (info->width <= 512))
++ port_def.format.video.nStride = 512;
++ else if ((info->width > 512) && (info->width <= 1024))
++ port_def.format.video.nStride = 1024;
++ else
++ port_def.format.video.nStride = 2048;
++ break;
++ }
++ case OMX_COLOR_FormatYUV420SemiPlanar:
++ port_def.format.video.nStride = ((info->width + 127) & ~ 127); /* Align 128 */
+ break;
+- }
+- case OMX_COLOR_FormatYUV420SemiPlanar:
+- port_def.format.video.nStride = ((info->width + 127) & ~ 127); /* Align 128 */
+- break;
+- default:
++ default:
++ port_def.format.video.nStride = GST_ROUND_UP_4 (info->width); /* Safe (?) default */
++ break;
++ }
++ } else {
+ port_def.format.video.nStride = GST_ROUND_UP_4 (info->width); /* Safe (?) default */
+- break;
+ }
+- } else {
+- port_def.format.video.nStride = GST_ROUND_UP_4 (info->width); /* Safe (?) default */
+ }
+- }
+
+- port_def.format.video.nFrameHeight = info->height;
+- port_def.format.video.nSliceHeight = info->height;
++ port_def.format.video.nFrameHeight = info->height;
++ port_def.format.video.nSliceHeight = info->height;
+
+- switch (port_def.format.video.eColorFormat) {
+- case OMX_COLOR_FormatYUV420Planar:
+- case OMX_COLOR_FormatYUV420PackedPlanar:
+- port_def.nBufferSize =
+- (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
+- 2 * ((port_def.format.video.nStride / 2) *
+- ((port_def.format.video.nFrameHeight + 1) / 2));
+- break;
+-
+- case OMX_COLOR_FormatYUV420SemiPlanar:
+- port_def.nBufferSize =
+- (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
+- (port_def.format.video.nStride *
+- ((port_def.format.video.nFrameHeight + 1) / 2));
+- break;
++ switch (port_def.format.video.eColorFormat) {
++ case OMX_COLOR_FormatYUV420Planar:
++ case OMX_COLOR_FormatYUV420PackedPlanar:
++ port_def.nBufferSize =
++ (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
++ 2 * ((port_def.format.video.nStride / 2) *
++ ((port_def.format.video.nFrameHeight + 1) / 2));
++ break;
+
+- default:
+- g_assert_not_reached ();
+- }
++ case OMX_COLOR_FormatYUV420SemiPlanar:
++ port_def.nBufferSize =
++ (port_def.format.video.nStride * port_def.format.video.nFrameHeight) +
++ (port_def.format.video.nStride *
++ ((port_def.format.video.nFrameHeight + 1) / 2));
++ break;
+
+- if (info->fps_n == 0) {
+- port_def.format.video.xFramerate = 0;
+- } else {
+- if (!(klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER))
+- port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d);
+- else
+- port_def.format.video.xFramerate = (info->fps_n) / (info->fps_d);
+- }
++ default:
++ g_assert_not_reached ();
++ }
+
+- GST_DEBUG_OBJECT (self, "Setting inport port definition");
+- if (gst_omx_port_update_port_definition (self->enc_in_port,
+- &port_def) != OMX_ErrorNone)
+- return FALSE;
++ if (info->fps_n == 0) {
++ port_def.format.video.xFramerate = 0;
++ } else {
++ if (!(klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER))
++ port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d);
++ else
++ port_def.format.video.xFramerate = (info->fps_n) / (info->fps_d);
++ }
+
+- if (klass->set_format) {
+- if (!klass->set_format (self, self->enc_in_port, state)) {
+- GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
++ GST_DEBUG_OBJECT (self, "Setting inport port definition");
++ if (gst_omx_port_update_port_definition (self->enc_in_port,
++ &port_def) != OMX_ErrorNone)
+ return FALSE;
++
++ if (klass->set_format) {
++ if (!klass->set_format (self, self->enc_in_port, state)) {
++ GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
++ return FALSE;
++ }
+ }
+- }
+
+- GST_DEBUG_OBJECT (self, "Updating outport port definition");
+- if (gst_omx_port_update_port_definition (self->enc_out_port,
+- NULL) != OMX_ErrorNone)
+- return FALSE;
++ GST_DEBUG_OBJECT (self, "Updating outport port definition");
++ if (gst_omx_port_update_port_definition (self->enc_out_port,
++ NULL) != OMX_ErrorNone)
++ return FALSE;
++ }
+
+ GST_DEBUG_OBJECT (self, "Enabling component");
+ if (needs_disable) {
+@@ -1299,11 +1342,13 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
+ return FALSE;
+
+ /* Need to allocate buffers to reach Idle state */
+- if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
+- return FALSE;
++ if (!self->in_port_pool) {
++ if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
++ return FALSE;
++ }
+
+ /* Allocate for output port */
+- if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
++ if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
+ return FALSE;
+ if (gst_omx_component_get_state (self->enc,
+ GST_CLOCK_TIME_NONE) != OMX_StateIdle)
+@@ -1349,7 +1394,9 @@ gst_omx_video_enc_reset (GstVideoEncoder * encoder, gboolean hard)
+
+ self = GST_OMX_VIDEO_ENC (encoder);
+
+- GST_DEBUG_OBJECT (self, "Resetting encoder");
++ GST_DEBUG_OBJECT (self, "Resetting encoder %s", hard ? "(hard)" : "");
++
++ return TRUE;
+
+ gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE);
+ gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);
+@@ -1739,11 +1786,50 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
+ gst_omx_error_to_string (err), err);
+ }
+
+- /* Copy the buffer content in chunks of size as requested
+- * by the port */
+- if (!gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) {
+- gst_omx_port_release_buffer (port, buf);
+- goto buffer_fill_error;
++ if (self->in_port_pool) {
++ GstMapInfo in_info;
++ gint count = 0;
++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (self->in_port_pool);
++
++ /* Compare input buffer with buffer got from port to get target data for
++ * encoder
++ */
++ if (!pool->deactivated) {
++ if (!gst_buffer_map (frame->input_buffer, &in_info, GST_MAP_READ)) {
++ GST_ERROR_OBJECT (self, "Can not map input buffer");
++ gst_omx_port_release_buffer (port, buf);
++ goto flow_error;
++ }
++
++ if (buf->omx_buf->pBuffer != in_info.data) {
++ gst_omx_port_release_buffer (port, buf);
++ do {
++ acq_ret = gst_omx_port_acquire_buffer (port, &buf);
++ if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
++ GST_ERROR_OBJECT (self, "Can acquire buffer from input port");
++ return GST_FLOW_ERROR;
++ }
++ if (buf->omx_buf->pBuffer != in_info.data)
++ gst_omx_port_release_buffer (port, buf);
++ count += 1;
++ } while (buf->omx_buf->pBuffer != in_info.data
++ && count < port->port_def.nBufferCountActual * 3);
++ }
++ if (count == port->port_def.nBufferCountActual * 3) {
++ GST_ERROR_OBJECT (self,
++ "Can not get target OMXBuffer after 3 times searching");
++ goto flow_error;
++ }
++ buf->omx_buf->nFilledLen = in_info.size;
++ gst_buffer_unmap (frame->input_buffer, &in_info);
++ }
++ } else {
++ /* Copy the buffer content in chunks of size as requested
++ * by the port */
++ if (!gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) {
++ gst_omx_port_release_buffer (port, buf);
++ goto buffer_fill_error;
++ }
+ }
+
+ timestamp = frame->pts;
+@@ -1920,11 +2006,203 @@ static gboolean
+ gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
+ GstQuery * query)
+ {
+- gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
++ GstOMXVideoEnc *self;
++ GstOMXVideoEncClass *klass;
++
++ self = GST_OMX_VIDEO_ENC (encoder);
++ klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder);
++
++ GST_DEBUG_OBJECT (self, "gst_omx_video_enc_propose_allocation");
++ if (self->no_copy == TRUE) {
++ /* Allocate buffers and propose them to upstream */
++ GstCaps *caps;
++ GstVideoInfo info;
++ guint size;
++ OMX_PARAM_PORTDEFINITIONTYPE port_def;
++ guint max, min;
++
++ gst_omx_port_get_port_definition (self->enc_in_port, &port_def);
++
++ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
++
++ gst_query_parse_allocation (query, &caps, NULL);
++
++ if (caps == NULL)
++ return FALSE;
++
++ if (!gst_video_info_from_caps (&info, caps))
++ return FALSE;
++
++ size = GST_VIDEO_INFO_SIZE (&info);
++
++ if (gst_omx_component_get_state (self->enc,
++ GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
++ return FALSE;
++ switch (info.finfo->format) {
++ case GST_VIDEO_FORMAT_I420:
++ port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
++ break;
++ case GST_VIDEO_FORMAT_NV12:
++ case GST_VIDEO_FORMAT_NV16:
++ port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
++ break;
++ default:
++ GST_ERROR_OBJECT (self, "Unsupported format %s",
++ gst_video_format_to_string (info.finfo->format));
++ return FALSE;
++ break;
++ }
++ port_def.format.video.nFrameWidth = info.width;
++ if (klass->cdata.hacks & GST_OMX_HACK_RENESAS_ENCMC_STRIDE_ALIGN) {
++ switch (port_def.format.video.eColorFormat) {
++ case OMX_COLOR_FormatYUV420Planar:
++ port_def.format.video.nStride = GST_ROUND_UP_64 (info.width);
++ break;
++ case OMX_COLOR_FormatYUV420SemiPlanar:
++ port_def.format.video.nStride = GST_ROUND_UP_32 (info.width);
++ break;
++ default:
++ break;
++ }
++ } else
++ port_def.format.video.nStride = GST_ROUND_UP_4 (info.width); /* safe (?) default */
++ port_def.format.video.nFrameHeight = info.height;
++ port_def.format.video.nSliceHeight = info.height;
++ switch (port_def.format.video.eColorFormat) {
++ case OMX_COLOR_FormatYUV420Planar:
++ case OMX_COLOR_FormatYUV420PackedPlanar:
++ port_def.nBufferSize =
++ (port_def.format.video.nStride *
++ port_def.format.video.nFrameHeight) +
++ 2 * ((port_def.format.video.nStride / 2) *
++ ((port_def.format.video.nFrameHeight + 1) / 2));
++ break;
++
++ case OMX_COLOR_FormatYUV420SemiPlanar:
++ port_def.nBufferSize =
++ (port_def.format.video.nStride *
++ port_def.format.video.nFrameHeight) +
++ (port_def.format.video.nStride *
++ ((port_def.format.video.nFrameHeight + 1) / 2));
++ break;
+
+- return
+- GST_VIDEO_ENCODER_CLASS
+- (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query);
++ default:
++ g_assert_not_reached ();
++ }
++ if (info.fps_n == 0) {
++ port_def.format.video.xFramerate = 0;
++ } else {
++ port_def.format.video.xFramerate = (info.fps_n) / (info.fps_d);
++ }
++
++ if (gst_omx_port_update_port_definition (self->enc_in_port,
++ &port_def) != OMX_ErrorNone)
++ return FALSE;
++
++ if (klass->set_format) {
++ if (!klass->set_format (self, self->enc_in_port, self->input_state)) {
++ GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
++ return FALSE;
++ }
++ }
++ GST_DEBUG_OBJECT (self, "Updating outport port definition");
++ if (gst_omx_port_update_port_definition (self->enc_out_port,
++ NULL) != OMX_ErrorNone)
++ return FALSE;
++
++ if (self->target_bitrate != 0xffffffff) {
++ OMX_VIDEO_PARAM_BITRATETYPE config;
++ OMX_ERRORTYPE err;
++
++ GST_OMX_INIT_STRUCT (&config);
++ config.nPortIndex = self->enc_out_port->index;
++ /* Get default value of eControlRate to avoid setting an invalid value to it */
++ err = gst_omx_component_get_parameter (self->enc,
++ OMX_IndexParamVideoBitrate, &config);
++ if (err != OMX_ErrorNone)
++ GST_ERROR_OBJECT (self,
++ "Fail to get parameter of video bitrate: %s (0x%08x)",
++ gst_omx_error_to_string (err), err);
++
++ config.nTargetBitrate = self->target_bitrate;
++ if (self->control_rate != 0xffffffff)
++ config.eControlRate = self->control_rate;
++
++ err = gst_omx_component_set_parameter (self->enc,
++ OMX_IndexParamVideoBitrate, &config);
++ if (err != OMX_ErrorNone)
++ GST_ERROR_OBJECT (self, "Failed to set bitrate parameter: %s (0x%08x)",
++ gst_omx_error_to_string (err), err);
++ }
++
++ if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone)
++ return FALSE;
++
++ if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
++ return FALSE;
++
++ if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
++ return FALSE;
++
++ GST_DEBUG_OBJECT (self, " gst_query_get_n_allocation_pools = %d",
++ gst_query_get_n_allocation_pools (query));
++ if (gst_query_get_n_allocation_pools (query) == 0) {
++ GstStructure *structure;
++ GstAllocator *allocator = NULL;
++ GstAllocationParams params = { 0, };
++
++ if (gst_query_get_n_allocation_params (query) > 0)
++ gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
++ else
++ gst_query_add_allocation_param (query, allocator, &params);
++
++ self->in_port_pool = gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self),
++ self->enc, self->enc_in_port);
++
++ structure = gst_buffer_pool_get_config (self->in_port_pool);
++ gst_buffer_pool_config_set_params (structure, caps,
++ self->enc_in_port->port_def.nBufferSize,
++ self->enc_in_port->port_def.nBufferCountActual,
++ self->enc_in_port->port_def.nBufferCountActual);
++
++ GST_DEBUG_OBJECT (self, " add allocator");
++ gst_buffer_pool_config_get_params (structure, &caps, NULL, &min, &max);
++ gst_buffer_pool_config_set_allocator (structure, allocator, &params);
++
++ if (allocator)
++ gst_object_unref (allocator);
++
++ if (!gst_buffer_pool_set_config (self->in_port_pool, structure)) {
++ GST_ERROR_OBJECT (self, "failed to set config");
++ gst_object_unref (self->in_port_pool);
++ return FALSE;
++ }
++
++ GST_OMX_BUFFER_POOL (self->in_port_pool)->allocating = TRUE;
++
++ /* Wait for all buffers allocate */
++ GST_DEBUG_OBJECT (self, "Activating pool");
++ while (!gst_buffer_pool_set_active (self->in_port_pool, TRUE)) {
++ }
++
++ GST_OMX_BUFFER_POOL (self->in_port_pool)->allocating = FALSE;
++
++ gst_query_add_allocation_pool (query, self->in_port_pool, size,
++ port_def.nBufferCountActual, port_def.nBufferCountActual);
++
++ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
++
++ }
++
++ return TRUE;
++
++ } else {
++ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
++
++ return
++ GST_VIDEO_ENCODER_CLASS
++ (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query);
++ }
+ }
+
+ static GstCaps *
+diff --git a/omx/gstomxvideoenc.h b/omx/gstomxvideoenc.h
+index e266537..7f80dca 100644
+--- a/omx/gstomxvideoenc.h
++++ b/omx/gstomxvideoenc.h
+@@ -44,6 +44,7 @@ G_BEGIN_DECLS
+
+ typedef struct _GstOMXVideoEnc GstOMXVideoEnc;
+ typedef struct _GstOMXVideoEncClass GstOMXVideoEncClass;
++typedef struct _GstOMXVideoEncPrivate GstOMXVideoEncPrivate;
+
+ struct _GstOMXVideoEnc
+ {
+@@ -53,6 +54,8 @@ struct _GstOMXVideoEnc
+ GstOMXComponent *enc;
+ GstOMXPort *enc_in_port, *enc_out_port;
+
++ GstBufferPool *in_port_pool, *out_port_pool;
++
+ /* < private > */
+ GstVideoCodecState *input_state;
+ /* TRUE if the component is configured and saw
+@@ -78,6 +81,14 @@ struct _GstOMXVideoEnc
+ guint32 quant_b_frames;
+
+ GstFlowReturn downstream_flow_ret;
++
++ /* Set TRUE to use GstBuffer of Bufferpool to transfer data to
++ * downstream
++ */
++ gboolean no_copy;
++
++ /* need? */
++ GstOMXVideoEncPrivate *priv;
+ };
+
+ struct _GstOMXVideoEncClass
+--
+1.7.10.4
+