aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen2
diff options
context:
space:
mode:
authorGrigory Kletsko <grigory.kletsko@cogentembedded.com>2016-11-02 17:42:27 +0300
committerHarunobu Kurokawa <harunobu.kurokawa.dn@renesas.com>2016-11-10 14:30:27 +0900
commitfc233fbbe9f83b1269c594378ed4fd83ff3f4692 (patch)
tree2044fe1a9293d11f354d2b4aeb34309f29351cd9 /meta-rcar-gen2
parent25e673803392c937c39c7dd5c1f7d816bdd7a570 (diff)
gst-omx: add export of DMA fd of input port
Change-Id: I19e3595aac8943ce3f348764aca66d2b4132cf28 Signed-off-by: Grigory Kletsko <grigory.kletsko@cogentembedded.com>
Diffstat (limited to 'meta-rcar-gen2')
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0001-omx-videodec-add-planebuf-to-allocation-request.patch85
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0002-Fixed-memory-corruption-and-bad-access.patch65
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch2759
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0004-Export-a-first-dmabuf-file-descriptor-with-the-whole.patch65
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0005-gssomxbufferpool-add-exported-flag.patch75
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0006-gstomxbufferpool-create-dmabuf-for-input-port.patch46
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0007-gstomxbufferpool-add-helper-to-get-omxbuffer-from-gs.patch140
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0008-gstomxenc-do-not-allocate-output-buffers-two-times.patch47
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0009-gstomxenc-move-encoder-disable-code-to-separate-func.patch113
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0010-omxvideodec-support-creating-buffers-using-sink.patch186
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/gstomx.conf62
-rw-r--r--meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx_1.0.0.bbappend29
12 files changed, 3668 insertions, 4 deletions
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0001-omx-videodec-add-planebuf-to-allocation-request.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0001-omx-videodec-add-planebuf-to-allocation-request.patch
new file mode 100644
index 0000000..d863414
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0001-omx-videodec-add-planebuf-to-allocation-request.patch
@@ -0,0 +1,85 @@
+diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c
+index c5b69ab..647ac88 100644
+--- a/omx/gstomxvideodec.c
++++ b/omx/gstomxvideodec.c
+@@ -581,7 +581,7 @@ gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
+ #ifdef HAVE_MMNGRBUF
+ static GstBuffer *
+ gst_omx_buffer_pool_request_videosink_buffer_creation (GstOMXBufferPool * pool,
+- gint dmabuf_fd[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES])
++ 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, };
+@@ -590,6 +590,7 @@ gst_omx_buffer_pool_request_videosink_buffer_creation (GstOMXBufferPool * pool,
+ GstBuffer *buffer;
+ GArray *dmabuf_array;
+ GArray *stride_array;
++ GArray *planebuf_array;
+ gint n_planes;
+ gint i;
+
+@@ -598,11 +599,13 @@ gst_omx_buffer_pool_request_videosink_buffer_creation (GstOMXBufferPool * pool,
+
+ 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",
+@@ -610,6 +613,7 @@ gst_omx_buffer_pool_request_videosink_buffer_creation (GstOMXBufferPool * pool,
+ "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),
+@@ -704,6 +708,7 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
+ 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->
+@@ -730,6 +735,7 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
+
+ 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);
+@@ -737,6 +743,7 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
+ 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])) {
+@@ -747,7 +754,7 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
+
+ if (pool->vsink_buf_req_supported)
+ new_buf = gst_omx_buffer_pool_request_videosink_buffer_creation (pool,
+- dmabuf_fd, vmeta->stride);
++ dmabuf_fd, plane_buf, vmeta->stride);
+ else {
+ GstVideoMeta *new_meta;
+
+@@ -1947,6 +1954,8 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
+ goto caps_failed;
+ }
+
++ /* ...force clearing of reconfiguration flag to prevent subsequent buffers allocation */
++ gst_pad_check_reconfigure(GST_VIDEO_DECODER_SRC_PAD(self));
+ gst_video_codec_state_unref (state);
+
+ GST_VIDEO_DECODER_STREAM_UNLOCK (self);
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0002-Fixed-memory-corruption-and-bad-access.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0002-Fixed-memory-corruption-and-bad-access.patch
new file mode 100644
index 0000000..354a7a9
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0002-Fixed-memory-corruption-and-bad-access.patch
@@ -0,0 +1,65 @@
+From 3e528cda6fb9d0da2be52e18a305096cf6e37528 Mon Sep 17 00:00:00 2001
+From: Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>
+Date: Sat, 18 Jul 2015 15:52:59 +0300
+Subject: [PATCH] Fixed memory corruption and bad access
+
+---
+ omx/gstomxh264dec.c | 4 ++--
+ omx/gstomxvideodec.c | 12 ++++++------
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/omx/gstomxh264dec.c b/omx/gstomxh264dec.c
+index 7799e69..5509cc0 100644
+--- a/omx/gstomxh264dec.c
++++ b/omx/gstomxh264dec.c
+@@ -104,7 +104,7 @@ gst_omx_h264_dec_retrieve_sps_pps (GstOMXH264Dec * self, guint8 * data)
+
+ sps_num = ptr[5] & 0x1f; /* reserved(3bit) + numOfSequenceParameterSets(uint 5bit) */
+
+- sps_size_list = g_malloc (sps_num);
++ sps_size_list = g_malloc (sps_num * sizeof (guint));
+ if (!sps_size_list) {
+ GST_ERROR_OBJECT (self, "failed g_malloc");
+ return NULL;
+@@ -119,7 +119,7 @@ gst_omx_h264_dec_retrieve_sps_pps (GstOMXH264Dec * self, guint8 * data)
+ }
+
+ pps_num = *ptr++; /* numOfPictureParameterSets (unint 8bit) */
+- pps_size_list = g_malloc (pps_num);
++ pps_size_list = g_malloc (pps_num * sizeof (guint));
+ if (!pps_size_list) {
+ GST_ERROR_OBJECT (self, "failed g_malloc");
+ g_free (sps_size_list);
+diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c
+index c5b69ab..4a9706f 100644
+--- a/omx/gstomxvideodec.c
++++ b/omx/gstomxvideodec.c
+@@ -563,10 +563,12 @@ gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
+ gst_omx_buffer_data_quark);
+ #ifdef HAVE_MMNGRBUF
+ if (self->use_dmabuf) {
+- vdbuf_data = (GstOMXVideoDecBufferData *) omx_buf->private_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]);
++ 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);
+@@ -1684,8 +1686,6 @@ gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
+
+ static void GstOMXBufCallbackfunc (struct GstOMXBufferCallback *release)
+ {
+- gint i;
+-
+ if (!release)
+ return;
+
+--
+2.1.4
+
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
+
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0004-Export-a-first-dmabuf-file-descriptor-with-the-whole.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0004-Export-a-first-dmabuf-file-descriptor-with-the-whole.patch
new file mode 100644
index 0000000..6aa5d48
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0004-Export-a-first-dmabuf-file-descriptor-with-the-whole.patch
@@ -0,0 +1,65 @@
+From 1fe52cec8fec530a79eb3ab9f313bb860ec109be Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 1 Sep 2016 18:44:49 +0300
+Subject: [PATCH 04/10] Export a first dmabuf file descriptor with the whole
+ size
+
+This patch exports 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.
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ omx/gstomxbufferpool.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c
+index 2585a72..b9fa769 100644
+--- a/omx/gstomxbufferpool.c
++++ b/omx/gstomxbufferpool.c
+@@ -399,6 +399,7 @@ gst_omx_buffer_pool_create_buffer_contain_dmabuf (GstOMXBufferPool * self,
+ gint i;
+ gint page_size;
+ guint phys_addr = 0;
++ guint phys_size = 0;
+
+ new_buf = gst_buffer_new ();
+ page_size = getpagesize ();
+@@ -410,13 +411,15 @@ gst_omx_buffer_pool_create_buffer_contain_dmabuf (GstOMXBufferPool * self,
+ OMXR_MC_VIDEO_DECODERESULTTYPE *decode_res =
+ (OMXR_MC_VIDEO_DECODERESULTTYPE *) omx_buf->omx_buf->pOutputPortPrivate;
+ phys_addr = decode_res->pvPhysImageAddressY;
++ phys_size = (guint) omx_buf->omx_buf->nAllocLen;
+ } 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;
++ phys_size = (guint) omx_buf->omx_buf->nAllocLen;
+ }
+
+- if (phys_addr == 0) {
+- GST_ERROR_OBJECT (self, "Invalid phys addr for OMX buffer");
++ if ((phys_addr == 0) || (phys_size == 0)) {
++ GST_ERROR_OBJECT (self, "Invalid phys range for OMX buffer");
+ return NULL;
+ }
+
+@@ -428,8 +431,14 @@ gst_omx_buffer_pool_create_buffer_contain_dmabuf (GstOMXBufferPool * self,
+ /* 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);
++ /* 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 (i == 0)
++ plane_size[i] = phys_size;
++ else
++ 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
+--
+1.7.10.4
+
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0005-gssomxbufferpool-add-exported-flag.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0005-gssomxbufferpool-add-exported-flag.patch
new file mode 100644
index 0000000..c6b5c36
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0005-gssomxbufferpool-add-exported-flag.patch
@@ -0,0 +1,75 @@
+From c4e86a58041cd4408d283444dcba6f532a80697c Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 1 Sep 2016 17:33:44 +0300
+Subject: [PATCH 05/10] gssomxbufferpool: add exported flag
+
+This flag indicates that buffer are used outside of OMX component
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ omx/gstomx.c | 1 +
+ omx/gstomx.h | 5 +++++
+ omx/gstomxbufferpool.c | 5 ++++-
+ 3 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/omx/gstomx.c b/omx/gstomx.c
+index c018e72..5a916dc 100644
+--- a/omx/gstomx.c
++++ b/omx/gstomx.c
+@@ -1663,6 +1663,7 @@ gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port,
+ buf = g_slice_new0 (GstOMXBuffer);
+ buf->port = port;
+ buf->used = FALSE;
++ buf->exported = FALSE;
+ buf->settings_cookie = port->settings_cookie;
+ g_ptr_array_add (port->buffers, buf);
+
+diff --git a/omx/gstomx.h b/omx/gstomx.h
+index 84980f3..27cb2a9 100644
+--- a/omx/gstomx.h
++++ b/omx/gstomx.h
+@@ -279,6 +279,11 @@ struct _GstOMXBuffer {
+ */
+ gboolean used;
+
++ /* TRUE if the buffer exported outside the component,
++ * i.e. someone acquired this buffer
++ */
++ gboolean exported;
++
+ /* Cookie of the settings when this buffer was allocated */
+ gint settings_cookie;
+
+diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c
+index b9fa769..1e0a14c 100644
+--- a/omx/gstomxbufferpool.c
++++ b/omx/gstomxbufferpool.c
+@@ -695,7 +695,7 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
+ pool->enc_buffer_index = 0;
+
+ count += 1;
+- } while (omx_buf->used == TRUE &&
++ } while (omx_buf->exported == TRUE &&
+ count < pool->port->port_def.nBufferCountActual * 3);
+
+ if (count == pool->port->port_def.nBufferCountActual * 3) {
+@@ -703,6 +703,7 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
+ GST_ERROR_OBJECT (pool,
+ "Can not acquire buffer after 3 times searching");
+ } else {
++ omx_buf->exported = TRUE;
+ *buffer = buf;
+ ret = GST_FLOW_OK;
+ }
+@@ -731,6 +732,8 @@ gst_omx_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
+ omx_buf =
+ gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
+ gst_omx_buffer_data_quark);
++ if (GST_IS_OMX_VIDEO_ENC (pool->element))
++ omx_buf->exported = FALSE;
+ 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);
+--
+1.7.10.4
+
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0006-gstomxbufferpool-create-dmabuf-for-input-port.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0006-gstomxbufferpool-create-dmabuf-for-input-port.patch
new file mode 100644
index 0000000..93966b2
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0006-gstomxbufferpool-create-dmabuf-for-input-port.patch
@@ -0,0 +1,46 @@
+From 078a91a917a7b81cfcf523ac23b1c3e154506ef9 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 1 Sep 2016 17:43:35 +0300
+Subject: [PATCH 06/10] gstomxbufferpool: create dmabuf for input port
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ omx/gstomxbufferpool.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c
+index 1e0a14c..d86f9d8 100644
+--- a/omx/gstomxbufferpool.c
++++ b/omx/gstomxbufferpool.c
+@@ -518,6 +518,7 @@ gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool,
+
+ pool->need_copy = FALSE;
+ } else {
++ gboolean dmabuf = FALSE;
+ GstMemory *mem;
+ const guint nstride = pool->port->port_def.format.video.nStride;
+ const guint nslice = pool->port->port_def.format.video.nSliceHeight;
+@@ -552,8 +553,17 @@ gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool,
+
+ 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)
++ (omx_buf->omx_buf->pOutputPortPrivate))
++ dmabuf = TRUE;
++
++
++ if (GST_IS_OMX_VIDEO_ENC (pool->element) &&
++ GST_OMX_VIDEO_ENC (pool->element)->no_copy == TRUE &&
++ (omx_buf->omx_buf->pInputPortPrivate))
++ dmabuf = TRUE;
++
++ if (dmabuf) {
++#if defined (HAVE_MMNGRBUF)
+ if (pool->allocator)
+ gst_object_unref (pool->allocator);
+ pool->allocator = gst_dmabuf_allocator_new ();
+--
+1.7.10.4
+
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0007-gstomxbufferpool-add-helper-to-get-omxbuffer-from-gs.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0007-gstomxbufferpool-add-helper-to-get-omxbuffer-from-gs.patch
new file mode 100644
index 0000000..ed9da8d
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0007-gstomxbufferpool-add-helper-to-get-omxbuffer-from-gs.patch
@@ -0,0 +1,140 @@
+From 4abd8ac4f18f5baef5a23c7defdb12469192f9c5 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 1 Sep 2016 17:51:30 +0300
+Subject: [PATCH 07/10] gstomxbufferpool: add helper to get omxbuffer from
+ gstomxbuffer
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ omx/gstomxbufferpool.c | 21 +++++++++++++++------
+ omx/gstomxbufferpool.h | 2 ++
+ omx/gstomxvideoenc.c | 26 ++++++++++++++++----------
+ 3 files changed, 33 insertions(+), 16 deletions(-)
+
+diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c
+index d86f9d8..eb2fe9d 100644
+--- a/omx/gstomxbufferpool.c
++++ b/omx/gstomxbufferpool.c
+@@ -361,6 +361,17 @@ wrong_video_caps:
+ }
+ }
+
++GstOMXBuffer *gst_omx_buffer_get_omxbuffer (GstBuffer * buffer)
++{
++ GstOMXBuffer *omx_buf;
++
++ omx_buf =
++ gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer),
++ gst_omx_buffer_data_quark);
++
++ return omx_buf;
++}
++
+ #if defined (HAVE_MMNGRBUF) && defined (HAVE_VIDEODEC_EXT)
+ static gboolean
+ gst_omx_buffer_pool_export_dmabuf (GstOMXBufferPool * pool,
+@@ -697,9 +708,7 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
+ 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);
++ omx_buf = gst_omx_buffer_get_omxbuffer(buf);
+ pool->enc_buffer_index++;
+ if (pool->enc_buffer_index == pool->port->port_def.nBufferCountActual)
+ pool->enc_buffer_index = 0;
+@@ -739,11 +748,11 @@ gst_omx_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
+ 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);
++ omx_buf = gst_omx_buffer_get_omxbuffer(buffer);
++
+ if (GST_IS_OMX_VIDEO_ENC (pool->element))
+ omx_buf->exported = FALSE;
++
+ 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);
+diff --git a/omx/gstomxbufferpool.h b/omx/gstomxbufferpool.h
+index 09cab8d..0c6f18b 100644
+--- a/omx/gstomxbufferpool.h
++++ b/omx/gstomxbufferpool.h
+@@ -101,6 +101,8 @@ GType gst_omx_buffer_pool_get_type (void);
+
+ GstBufferPool *gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, GstOMXPort * port);
+
++GstOMXBuffer *gst_omx_buffer_get_omxbuffer (GstBuffer * buffer);
++
+ G_END_DECLS
+
+ #endif /* __GST_OMX_BUFFER_POOL_H__ */
+diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c
+index b36c46e..e96ff28 100644
+--- a/omx/gstomxvideoenc.c
++++ b/omx/gstomxvideoenc.c
+@@ -1786,7 +1786,8 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
+ gst_omx_error_to_string (err), err);
+ }
+
+- if (self->in_port_pool) {
++ if ((self->in_port_pool) &&
++ (frame->input_buffer->pool == self->in_port_pool)) {
+ GstMapInfo in_info;
+ gint count = 0;
+ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (self->in_port_pool);
+@@ -1795,13 +1796,15 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
+ * 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;
++ GstOMXBuffer *omx_buf;
++
++ omx_buf = gst_omx_buffer_get_omxbuffer(frame->input_buffer);
++ if (!omx_buf) {
++ GST_ERROR_OBJECT (self, "Can not get OMXBuffer from GstBuffer");
++ return GST_FLOW_ERROR;
+ }
+
+- if (buf->omx_buf->pBuffer != in_info.data) {
++ if (buf != omx_buf) {
+ gst_omx_port_release_buffer (port, buf);
+ do {
+ acq_ret = gst_omx_port_acquire_buffer (port, &buf);
+@@ -1809,10 +1812,10 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
+ GST_ERROR_OBJECT (self, "Can acquire buffer from input port");
+ return GST_FLOW_ERROR;
+ }
+- if (buf->omx_buf->pBuffer != in_info.data)
++ if (buf != omx_buf)
+ gst_omx_port_release_buffer (port, buf);
+ count += 1;
+- } while (buf->omx_buf->pBuffer != in_info.data
++ } while (buf != omx_buf
+ && count < port->port_def.nBufferCountActual * 3);
+ }
+ if (count == port->port_def.nBufferCountActual * 3) {
+@@ -1820,8 +1823,11 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
+ "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);
++ GST_DEBUG_OBJECT (self, "found target OMXBuffer %p", buf);
++ //buf->omx_buf->nFilledLen = gst_buffer_get_size (frame->input_buffer);
++ buf->omx_buf->nFilledLen = buf->omx_buf->nAllocLen - buf->omx_buf->nOffset;
++ GST_DEBUG_OBJECT (self, "set nFilledLen = %d", buf->omx_buf->nFilledLen);
++
+ }
+ } else {
+ /* Copy the buffer content in chunks of size as requested
+--
+1.7.10.4
+
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0008-gstomxenc-do-not-allocate-output-buffers-two-times.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0008-gstomxenc-do-not-allocate-output-buffers-two-times.patch
new file mode 100644
index 0000000..8f97e7f
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0008-gstomxenc-do-not-allocate-output-buffers-two-times.patch
@@ -0,0 +1,47 @@
+From d1025433f05ebeb1a790abefa5cfc48455bf441c Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 1 Sep 2016 17:57:10 +0300
+Subject: [PATCH 08/10] gstomxenc: do not allocate output buffers two times
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ omx/gstomxvideoenc.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c
+index e96ff28..19a0eb9 100644
+--- a/omx/gstomxvideoenc.c
++++ b/omx/gstomxvideoenc.c
+@@ -1338,18 +1338,21 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
+ if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
+ return FALSE;
+ } else {
+- if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone)
+- return FALSE;
+-
+- /* Need to allocate buffers to reach Idle state */
++ /* if is not done in propose_allocation */
+ if (!self->in_port_pool) {
++ if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone)
++ return FALSE;
++
++ /* Need to allocate buffers to reach Idle state */
++ /* Allocate for input port */
+ 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)
++ return FALSE;
+ }
+
+- /* Allocate for output port */
+- 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)
+ return FALSE;
+--
+1.7.10.4
+
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0009-gstomxenc-move-encoder-disable-code-to-separate-func.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0009-gstomxenc-move-encoder-disable-code-to-separate-func.patch
new file mode 100644
index 0000000..8404acd
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0009-gstomxenc-move-encoder-disable-code-to-separate-func.patch
@@ -0,0 +1,113 @@
+From 0a9f0aa8271b0fc18c7e9781e3d0bc215ba2fd02 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 1 Sep 2016 17:58:33 +0300
+Subject: [PATCH 09/10] gstomxenc: move encoder disable code to separate
+ function
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ omx/gstomxvideoenc.c | 79 ++++++++++++++++++++++++++++----------------------
+ 1 file changed, 45 insertions(+), 34 deletions(-)
+
+diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c
+index 19a0eb9..6720648 100644
+--- a/omx/gstomxvideoenc.c
++++ b/omx/gstomxvideoenc.c
+@@ -1147,6 +1147,49 @@ gst_omx_video_enc_get_supported_colorformats (GstOMXVideoEnc * self)
+ }
+
+ static gboolean
++gst_omx_video_enc_disable(GstVideoEncoder * encoder)
++{
++ GstOMXVideoEnc *self;
++
++ self = GST_OMX_VIDEO_ENC (encoder);
++
++ 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");
++ return TRUE;
++}
++
++static gboolean
+ gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
+ GstVideoCodecState * state)
+ {
+@@ -1176,41 +1219,9 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder,
+ * 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);
+-
+- if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
++ if (needs_disable)
++ if (!gst_omx_video_enc_disable(encoder))
+ 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");
+- }
+
+ negotiation_map = gst_omx_video_enc_get_supported_colorformats (self);
+ if (!negotiation_map) {
+--
+1.7.10.4
+
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0010-omxvideodec-support-creating-buffers-using-sink.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0010-omxvideodec-support-creating-buffers-using-sink.patch
new file mode 100644
index 0000000..bd2b91c
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0010-omxvideodec-support-creating-buffers-using-sink.patch
@@ -0,0 +1,186 @@
+From 58d8ea72ec78cb17cf75c82c67a69e9bd383c3b3 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 1 Sep 2016 20:09:03 +0300
+Subject: [PATCH 10/10] omxvideodec: support creating buffers using sink
+
+Used for zero-copy output to wayland/weston
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ omx/gstomxbufferpool.c | 107 +++++++++++++++++++++++++++++++++++++++++++++---
+ omx/gstomxvideodec.c | 11 ++++-
+ 2 files changed, 111 insertions(+), 7 deletions(-)
+
+diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c
+index eb2fe9d..60b25ef 100644
+--- a/omx/gstomxbufferpool.c
++++ b/omx/gstomxbufferpool.c
+@@ -372,6 +372,73 @@ GstOMXBuffer *gst_omx_buffer_get_omxbuffer (GstBuffer * buffer)
+ return omx_buf;
+ }
+
++#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
++
+ #if defined (HAVE_MMNGRBUF) && defined (HAVE_VIDEODEC_EXT)
+ static gboolean
+ gst_omx_buffer_pool_export_dmabuf (GstOMXBufferPool * pool,
+@@ -406,6 +473,7 @@ gst_omx_buffer_pool_create_buffer_contain_dmabuf (GstOMXBufferPool * self,
+ gint plane_size_ext[GST_VIDEO_MAX_PLANES];
+ gint dmabuf_id[GST_VIDEO_MAX_PLANES];
+ gint page_offset[GST_VIDEO_MAX_PLANES];
++ gint plane_buf[GST_VIDEO_MAX_PLANES];
+ GstBuffer *new_buf;
+ gint i;
+ gint page_size;
+@@ -450,6 +518,7 @@ gst_omx_buffer_pool_create_buffer_contain_dmabuf (GstOMXBufferPool * self,
+ else
+ plane_size[i] = stride[i] *
+ GST_VIDEO_INFO_COMP_HEIGHT (&self->video_info, i);
++ plane_buf[i] = omx_buf->omx_buf->pBuffer + offset[i];
+
+ /* When downstream plugins do mapping from dmabuf fd it requires
+ * mapping from boundary page and size align for page size so
+@@ -472,14 +541,40 @@ gst_omx_buffer_pool_create_buffer_contain_dmabuf (GstOMXBufferPool * self,
+ 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);
++ if (self->vsink_buf_req_supported) {
++ new_buf = gst_omx_buffer_pool_request_videosink_buffer_creation (self,
++ dmabuf_fd, plane_buf, stride);
++ if (!new_buf) {
++ GST_ERROR_OBJECT (self, "creating dmabuf using videosink failed");
++ goto err;
++ }
++ new_buf->pool = self;
++ } else {
++ new_buf = gst_buffer_new ();
++ for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->video_info); i++) {
++ GstMemory *mem;
++ /* 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);
++ }
++
++ 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);
++ }
+
++ GST_ERROR_OBJECT (self, "got buffer %p from pool %p",
++ new_buf, new_buf->pool);
++ g_ptr_array_add (self->buffers, new_buf);
+ return new_buf;
++
++err:
++ return NULL;
+ }
+ #endif
+
+diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c
+index 25b6b30..44b706a 100644
+--- a/omx/gstomxvideodec.c
++++ b/omx/gstomxvideodec.c
+@@ -2350,6 +2350,8 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
+ &GST_OMX_BUFFER_POOL (self->out_port_pool)->vsink_buf_req_supported);
+ gst_object_unref (pool);
+ update_pool = TRUE;
++ GST_ERROR_OBJECT (self, "vsink_buf_req_supported %d",
++ GST_OMX_BUFFER_POOL (self->out_port_pool)->vsink_buf_req_supported);
+ }
+
+ /* Set pool parameters to our own configuration */
+@@ -2372,7 +2374,14 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
+ }
+
+ GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = TRUE;
+- gst_buffer_pool_set_active (self->out_port_pool, TRUE);
++ /* This now allocates all the buffers */
++ if (!gst_buffer_pool_set_active (self->out_port_pool, TRUE)) {
++ GST_INFO_OBJECT (self, "Failed to activate internal pool");
++ gst_object_unref (self->out_port_pool);
++ self->out_port_pool = NULL;
++ } else {
++ GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = FALSE;
++ }
+
+ /* This video buffer pool created below will not be used, just setting to
+ * the gstvideodecoder class through a query, because it is
+--
+1.7.10.4
+
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/gstomx.conf b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/gstomx.conf
new file mode 100644
index 0000000..375e201
--- /dev/null
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/gstomx.conf
@@ -0,0 +1,62 @@
+[omxh263dec]
+type-name=GstOMXH263Dec
+core-name=/usr/local/lib/libomxr_core.so
+component-name=OMX.RENESAS.VIDEO.DECODER.H263
+rank=512
+in-port-index=0
+out-port-index=1
+hacks=event-port-settings-changed-ndata-parameter-swap;event-port-settings-changed-port-0-to-1;no-component-role;default-pix-aspect-ratio
+
+[omxh264dec]
+type-name=GstOMXH264Dec
+core-name=/usr/local/lib/libomxr_core.so
+component-name=OMX.RENESAS.VIDEO.DECODER.H264
+rank=512
+in-port-index=0
+out-port-index=1
+hacks=event-port-settings-changed-ndata-parameter-swap;event-port-settings-changed-port-0-to-1;no-component-role;default-pix-aspect-ratio
+
+[omxmpeg2videodec]
+type-name=GstOMXMPEG2VideoDec
+core-name=/usr/local/lib/libomxr_core.so
+component-name=OMX.RENESAS.VIDEO.DECODER.MPEG2
+rank=512
+in-port-index=0
+out-port-index=1
+hacks=event-port-settings-changed-ndata-parameter-swap;event-port-settings-changed-port-0-to-1;no-component-role;default-pix-aspect-ratio
+
+[omxmpeg4videodec]
+type-name=GstOMXMPEG4VideoDec
+core-name=/usr/local/lib/libomxr_core.so
+component-name=OMX.RENESAS.VIDEO.DECODER.MPEG4
+rank=512
+in-port-index=0
+out-port-index=1
+hacks=event-port-settings-changed-ndata-parameter-swap;event-port-settings-changed-port-0-to-1;no-component-role;default-pix-aspect-ratio
+
+[omxvc1videodec]
+type-name=GstOMXVC1VideoDec
+core-name=/usr/local/lib/libomxr_core.so
+component-name=OMX.RENESAS.VIDEO.DECODER.VC1
+rank=512
+in-port-index=0
+out-port-index=1
+hacks=event-port-settings-changed-ndata-parameter-swap;event-port-settings-changed-port-0-to-1;no-component-role;default-pix-aspect-ratio
+
+[omxaacdec]
+type-name=GstOMXAACDec
+core-name=/usr/local/lib/libomxr_core.so
+component-name=OMX.RENESAS.AUDIO.DECODER.AAC
+rank=256
+in-port-index=0
+out-port-index=1
+hacks=
+
+[omxh264enc]
+type-name=GstOMXH264Enc
+core-name=/usr/local/lib/libomxr_core.so
+component-name=OMX.RENESAS.VIDEO.ENCODER.H264
+rank=256
+in-port-index=0
+out-port-index=1
+hacks=renesas-encmc-stride-align
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx_1.0.0.bbappend b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx_1.0.0.bbappend
index 95706e5..426f0c4 100644
--- a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx_1.0.0.bbappend
+++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx_1.0.0.bbappend
@@ -1,20 +1,24 @@
require ../../include/gles-control.inc
SRC_URI_rcar-gen2 = "git://github.com/renesas-devel/gst-omx.git;protocol=git;branch=RCAR-GEN2/1.0.0"
-SRCREV_rcar-gen2 = "05563465faad99243ee2dd30547e3075eb8cf5e3"
+SRCREV_rcar-gen2 = "${@'e0a23fb50ec211a8058eac223847bbcc574fb343' \
+ if '1' in '${USE_GLES_WAYLAND}' else '05563465faad99243ee2dd30547e3075eb8cf5e3'}"
-LIC_FILES_CHKSUM_remove_rcar-gen2 = " file://omx/gstomx.h;beginline=1;endline=21;md5=5c8e1fca32704488e76d2ba9ddfa935f"
+LIC_FILES_CHKSUM_remove_rcar-gen2 = " file://omx/gstomx.h;beginline=1;endline=21;md5=5c8e1fca32704488e76d2ba9ddfa935f"
LIC_FILES_CHKSUM_append_rcar-gen2 = " file://omx/gstomx.h;beginline=1;endline=22;md5=17e5f2943dace9e5cde4a8587a31e8f9"
S = "${WORKDIR}/git"
-do_configure_prepend() {
+do_configure() {
cd ${S}
./autogen.sh --noconfigure
cd ${B}
+ oe_runconf
}
DEPENDS_append_rcar-gen2 = " omx-user-module mmngrbuf-user-module"
-EXTRA_OECONF_append_rcar-gen2 = " --with-omx-target=rcar --enable-experimental \
+EXTRA_OECONF_append_rcar-gen2 = " \
+ --with-omx-target=rcar --enable-experimental \
+ '${@'--enable-nv12-page-alignment' if '${USE_GLES_WAYLAND}' == '1' else ''}' \
'${@'--disable-dmabuf' if '${USE_GLES}' == '0' and '${USE_WAYLAND}' == '1' else ''}'"
# Overwrite do_install[postfuncs] += " set_omx_core_name "
@@ -22,6 +26,23 @@ EXTRA_OECONF_append_rcar-gen2 = " --with-omx-target=rcar --enable-experimental \
revert_omx_core_name() {
sed -i -e "s;^core-name=.*;core-name=/usr/local/lib/libomxr_core.so;" "${D}/etc/xdg/gstomx.conf"
}
+
REVERT_OMX_CORE_NAME = ""
REVERT_OMX_CORE_NAME_rcar-gen2 = "revert_omx_core_name"
do_install[postfuncs] += "${REVERT_OMX_CORE_NAME}"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI_append = " \
+ file://0001-omx-videodec-add-planebuf-to-allocation-request.patch \
+ file://0002-Fixed-memory-corruption-and-bad-access.patch \
+ file://0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch \
+ file://0004-Export-a-first-dmabuf-file-descriptor-with-the-whole.patch \
+ file://0005-gssomxbufferpool-add-exported-flag.patch \
+ file://0006-gstomxbufferpool-create-dmabuf-for-input-port.patch \
+ file://0007-gstomxbufferpool-add-helper-to-get-omxbuffer-from-gs.patch \
+ file://0008-gstomxenc-do-not-allocate-output-buffers-two-times.patch \
+ file://0009-gstomxenc-move-encoder-disable-code-to-separate-func.patch \
+ file://0010-omxvideodec-support-creating-buffers-using-sink.patch \
+ file://gstomx.conf \
+"