diff options
author | Grigory Kletsko <grigory.kletsko@cogentembedded.com> | 2016-11-02 17:42:27 +0300 |
---|---|---|
committer | Jan-Simon Moeller <jsmoeller@linuxfoundation.org> | 2016-12-17 17:26:06 +0000 |
commit | d21c6598eff91f6ff739e340f708b13a566f9b57 (patch) | |
tree | c29b3dcaa09e7a5187641f682c34b7132cc1e800 | |
parent | 284877cb63856744f2af7145d722d2ce9c6d9cb8 (diff) |
patch to gst to add export of DMA fd of input port
This patch adds h264 decode plugin using DMA for gstreamer.
This plugin is supposed to be used to encode video data for
CES2017 cluster demo.
Change-Id: I19e3595aac8943ce3f348764aca66d2b4132cf28
Signed-off-by: Grigory Kletsko <grigory.kletsko@cogentembedded.com>
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, ¶ms); ++ else ++ gst_query_add_allocation_param (query, allocator, ¶ms); ++ ++ 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, ¶ms); ++ ++ 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 \ +" |