From d21c6598eff91f6ff739e340f708b13a566f9b57 Mon Sep 17 00:00:00 2001 From: Grigory Kletsko Date: Wed, 2 Nov 2016 17:42:27 +0300 Subject: 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 --- ...-export-dmafd-buffer-through-own-buffer-p.patch | 2759 ++++++++++++++++++++ 1 file changed, 2759 insertions(+) create mode 100644 meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch (limited to 'meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch') 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 +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 +--- + 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 , Collabora Ltd. ++ * Copyright (C) 2013, Collabora Ltd. ++ * Author: Sebastian Dröge ++ * 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 /* 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 ++ * 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 ++#include ++#include ++ ++#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 /* 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 + + #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 + -- cgit 1.2.3-korg