diff options
author | Gerrit Code Review <gerrit@automotivelinux.org> | 2017-01-19 07:01:22 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@automotivelinux.org> | 2017-01-19 07:01:22 +0000 |
commit | a89b8302db0346269f4202e95ca85dbbb6f75a8e (patch) | |
tree | 873e234062fb0fcd8c71bd031bdaa217c877648c /meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch | |
parent | 73e6110c6c12a875da9b6da46c8ddaaff79e3c79 (diff) | |
parent | 793d8d01d0377dad21f4e1a330f00d822eced086 (diff) |
Merge "Merge branch 'chinook_fixed' into chinook" into chinook
Diffstat (limited to 'meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch')
-rw-r--r-- | meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch | 2759 |
1 files changed, 2759 insertions, 0 deletions
diff --git a/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch new file mode 100644 index 0000000..23a3dfe --- /dev/null +++ b/meta-rcar-gen2/recipes-multimedia/gstreamer/gstreamer1.0-omx/0003-omxvideoenc-export-dmafd-buffer-through-own-buffer-p.patch @@ -0,0 +1,2759 @@ +From dcf585068bbb591431a999656359627cccd38716 Mon Sep 17 00:00:00 2001 +From: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Date: Thu, 25 Aug 2016 18:37:44 +0300 +Subject: [PATCH 03/10] omxvideoenc: export dmafd buffer through own buffer + pool + + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +--- + configure.ac | 17 + + omx/Makefile.am | 1 + + omx/gstomxbufferpool.c | 845 +++++++++++++++++++++++++++++++++++++++++++ + omx/gstomxbufferpool.h | 106 ++++++ + omx/gstomxvideodec.c | 924 +----------------------------------------------- + omx/gstomxvideoenc.c | 578 ++++++++++++++++++++++-------- + omx/gstomxvideoenc.h | 11 + + 7 files changed, 1420 insertions(+), 1062 deletions(-) + create mode 100644 omx/gstomxbufferpool.c + create mode 100644 omx/gstomxbufferpool.h + +diff --git a/configure.ac b/configure.ac +index 6aae527..57f5ae9 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -245,6 +245,23 @@ AC_CHECK_LIB([mmngrbuf], [mmngr_export_start_in_user], + ]) + fi + ++dnl check OMXR_Extension_video.h ++AC_CHECK_HEADER([OMXR_Extension_video.h], ++ [AC_DEFINE(HAVE_VIDEOR_EXT, 1, [Define if you have OMXR_Extension_video.h header])], ++ [], ++ [AC_INCLUDES_DEFAULT]) ++dnl check OMXR_Extension_vecmn.h ++AC_CHECK_HEADER([OMXR_Extension_vecmn.h], ++ [AC_DEFINE(HAVE_VIDEOENC_EXT, 1, [Define if you have OMXR_Extension_vecmn.h header])], ++ [], ++ [AC_INCLUDES_DEFAULT]) ++ ++dnl check OMXR_Extension_vdcmn.h ++AC_CHECK_HEADER([OMXR_Extension_vdcmn.h], ++ [AC_DEFINE(HAVE_VIDEODEC_EXT, 1, [Define if you have OMXR_Extension_vdcmn.h header])], ++ [], ++ [AC_INCLUDES_DEFAULT]) ++ + dnl check page alignment option for NV12 planes + AC_ARG_ENABLE([nv12-page-alignment], + [AS_HELP_STRING([--enable-nv12-page-alignment], +diff --git a/omx/Makefile.am b/omx/Makefile.am +index 3ec6173..3619281 100644 +--- a/omx/Makefile.am ++++ b/omx/Makefile.am +@@ -12,6 +12,7 @@ endif + + libgstomx_la_SOURCES = \ + gstomx.c \ ++ gstomxbufferpool.c \ + gstomxvideodec.c \ + gstomxvideoenc.c \ + gstomxaudioenc.c \ +diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c +new file mode 100644 +index 0000000..2585a72 +--- /dev/null ++++ b/omx/gstomxbufferpool.c +@@ -0,0 +1,845 @@ ++/* ++ * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. ++ * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd. ++ * Copyright (C) 2013, Collabora Ltd. ++ * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk> ++ * Copyright (C) 2015, Renesas Electronics Corporation ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation ++ * version 2.1 of the License. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "gstomxbufferpool.h" ++#include "gstomxvideodec.h" ++#include "gstomxvideoenc.h" ++#include "gst/allocators/gstdmabuf.h" ++#ifdef HAVE_MMNGRBUF ++#include "mmngr_buf_user_public.h" ++#endif ++#ifdef HAVE_VIDEODEC_EXT ++#include "OMXR_Extension_vdcmn.h" ++#endif ++#ifdef HAVE_VIDEOENC_EXT ++#include "OMXR_Extension_vecmn.h" ++#endif ++#include <unistd.h> /* getpagesize() */ ++ ++/** ++ * GST_ROUND_UP_N: ++ * @num: integrer value to round up ++ * @align: a power of two to round up to ++ * ++ * Rounds an integer value up to the next multiple of @align. @align MUST be a ++ * power of two. ++ */ ++#define GST_ROUND_UP_N(num,align) ((((num) + ((align) - 1)) & ~((align) - 1))) ++ ++GST_DEBUG_CATEGORY_STATIC (gst_omx_buffer_pool_debug_category); ++#define GST_CAT_DEFAULT gst_omx_buffer_pool_debug_category ++ ++typedef struct _GstOMXMemory GstOMXMemory; ++typedef struct _GstOMXMemoryAllocator GstOMXMemoryAllocator; ++typedef struct _GstOMXMemoryAllocatorClass GstOMXMemoryAllocatorClass; ++ ++struct _GstOMXMemory ++{ ++ GstMemory mem; ++ ++ GstOMXBuffer *buf; ++}; ++ ++struct _GstOMXMemoryAllocator ++{ ++ GstAllocator parent; ++}; ++ ++struct _GstOMXMemoryAllocatorClass ++{ ++ GstAllocatorClass parent_class; ++}; ++ ++#define GST_OMX_MEMORY_TYPE "openmax" ++ ++static GstMemory * ++gst_omx_memory_allocator_alloc_dummy (GstAllocator * allocator, gsize size, ++ GstAllocationParams * params) ++{ ++ g_assert_not_reached (); ++ return NULL; ++} ++ ++static void ++gst_omx_memory_allocator_free (GstAllocator * allocator, GstMemory * mem) ++{ ++ GstOMXMemory *omem = (GstOMXMemory *) mem; ++ ++ /* TODO: We need to remember which memories are still used ++ * so we can wait until everything is released before allocating ++ * new memory ++ */ ++ ++ g_slice_free (GstOMXMemory, omem); ++} ++ ++static gpointer ++gst_omx_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) ++{ ++ GstOMXMemory *omem = (GstOMXMemory *) mem; ++ ++ return omem->buf->omx_buf->pBuffer + omem->mem.offset; ++} ++ ++static void ++gst_omx_memory_unmap (GstMemory * mem) ++{ ++} ++ ++static GstMemory * ++gst_omx_memory_share (GstMemory * mem, gssize offset, gssize size) ++{ ++ g_assert_not_reached (); ++ return NULL; ++} ++ ++GType gst_omx_memory_allocator_get_type (void); ++G_DEFINE_TYPE (GstOMXMemoryAllocator, gst_omx_memory_allocator, ++ GST_TYPE_ALLOCATOR); ++ ++#define GST_TYPE_OMX_MEMORY_ALLOCATOR (gst_omx_memory_allocator_get_type()) ++#define GST_IS_OMX_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OMX_MEMORY_ALLOCATOR)) ++ ++static void ++gst_omx_memory_allocator_class_init (GstOMXMemoryAllocatorClass * klass) ++{ ++ GstAllocatorClass *allocator_class; ++ ++ allocator_class = (GstAllocatorClass *) klass; ++ ++ allocator_class->alloc = gst_omx_memory_allocator_alloc_dummy; ++ allocator_class->free = gst_omx_memory_allocator_free; ++} ++ ++static void ++gst_omx_memory_allocator_init (GstOMXMemoryAllocator * allocator) ++{ ++ GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); ++ ++ alloc->mem_type = GST_OMX_MEMORY_TYPE; ++ alloc->mem_map = gst_omx_memory_map; ++ alloc->mem_unmap = gst_omx_memory_unmap; ++ alloc->mem_share = gst_omx_memory_share; ++ ++ /* default copy & is_span */ ++ ++ GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); ++} ++ ++static GstMemory * ++gst_omx_memory_allocator_alloc (GstAllocator * allocator, GstMemoryFlags flags, ++ GstOMXBuffer * buf) ++{ ++ GstOMXMemory *mem; ++ gint align; ++ ++ /* FIXME: We don't allow sharing because we need to know ++ * when the memory becomes unused and can only then put ++ * it back to the pool. Which is done in the pool's release ++ * function ++ */ ++ flags |= GST_MEMORY_FLAG_NO_SHARE; ++ ++ /* GStreamer uses a bitmask for the alignment while ++ * OMX uses the alignment itself. So we have to convert ++ * here */ ++ align = buf->port->port_def.nBufferAlignment; ++ if (align > 0) ++ align -= 1; ++ if (((align + 1) & align) != 0) { ++ GST_WARNING ("Invalid alignment that is not a power of two: %u", ++ (guint) buf->port->port_def.nBufferAlignment); ++ align = 0; ++ } ++ ++ mem = g_slice_new (GstOMXMemory); ++ /* the shared memory is always readonly */ ++ gst_memory_init (GST_MEMORY_CAST (mem), flags, allocator, NULL, ++ buf->omx_buf->nAllocLen, align, 0, buf->omx_buf->nAllocLen); ++ ++ mem->buf = buf; ++ ++ return GST_MEMORY_CAST (mem); ++} ++ ++/* Buffer pool for the buffers of an OpenMAX port. ++ * ++ * This pool is only used if we either passed buffers from another ++ * pool to the OMX port or provide the OMX buffers directly to other ++ * elements. ++ * ++ * ++ * A buffer is in the pool if it is currently owned by the port, ++ * i.e. after OMX_{Fill,Empty}ThisBuffer(). A buffer is outside ++ * the pool after it was taken from the port after it was handled ++ * by the port, i.e. {Empty,Fill}BufferDone. ++ * ++ * Buffers can be allocated by us (OMX_AllocateBuffer()) or allocated ++ * by someone else and (temporarily) passed to this pool ++ * (OMX_UseBuffer(), OMX_UseEGLImage()). In the latter case the pool of ++ * the buffer will be overriden, and restored in free_buffer(). Other ++ * buffers are just freed there. ++ * ++ * The pool always has a fixed number of minimum and maximum buffers ++ * and these are allocated while starting the pool and released afterwards. ++ * They correspond 1:1 to the OMX buffers of the port, which are allocated ++ * before the pool is started. ++ * ++ * Acquiring a buffer from this pool happens after the OMX buffer has ++ * been acquired from the port. gst_buffer_pool_acquire_buffer() is ++ * supposed to return the buffer that corresponds to the OMX buffer. ++ * ++ * For buffers provided to upstream, the buffer will be passed to ++ * the component manually when it arrives and then unreffed. If the ++ * buffer is released before reaching the component it will be just put ++ * back into the pool as if EmptyBufferDone has happened. If it was ++ * passed to the component, it will be back into the pool when it was ++ * released and EmptyBufferDone has happened. ++ * ++ * For buffers provided to downstream, the buffer will be returned ++ * back to the component (OMX_FillThisBuffer()) when it is released. ++ */ ++ ++static GQuark gst_omx_buffer_data_quark = 0; ++ ++#define DEBUG_INIT \ ++ GST_DEBUG_CATEGORY_INIT (gst_omx_buffer_pool_debug_category, "omxbufferpool", 0, \ ++ "debug category for gst-omx buffer pool base class"); ++ ++G_DEFINE_TYPE_WITH_CODE (GstOMXBufferPool, gst_omx_buffer_pool, ++ GST_TYPE_BUFFER_POOL, DEBUG_INIT); ++ ++static void gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, ++ GstBuffer * buffer); ++ ++static gboolean ++gst_omx_buffer_pool_start (GstBufferPool * bpool) ++{ ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); ++ ++ /* Only allow to start the pool if we still are attached ++ * to a component and port */ ++ GST_OBJECT_LOCK (pool); ++ if (!pool->component || !pool->port) { ++ GST_OBJECT_UNLOCK (pool); ++ return FALSE; ++ } ++ GST_OBJECT_UNLOCK (pool); ++ ++ return ++ GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->start (bpool); ++} ++ ++static gboolean ++gst_omx_buffer_pool_stop (GstBufferPool * bpool) ++{ ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); ++ gint i = 0; ++ ++ /* When not using the default GstBufferPool::GstAtomicQueue then ++ * GstBufferPool::free_buffer is not called while stopping the pool ++ * (because the queue is empty) */ ++ for (i = 0; i < pool->buffers->len; i++) ++ GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer ++ (bpool, g_ptr_array_index (pool->buffers, i)); ++ ++ /* Remove any buffers that are there */ ++ g_ptr_array_set_size (pool->buffers, 0); ++ ++ if (pool->caps) ++ gst_caps_unref (pool->caps); ++ pool->caps = NULL; ++ ++ pool->add_videometa = FALSE; ++ ++ return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->stop (bpool); ++} ++ ++static const gchar ** ++gst_omx_buffer_pool_get_options (GstBufferPool * bpool) ++{ ++ static const gchar *raw_video_options[] = ++ { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL }; ++ static const gchar *options[] = { NULL }; ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); ++ ++ GST_OBJECT_LOCK (pool); ++ if (pool->port && pool->port->port_def.eDomain == OMX_PortDomainVideo ++ && pool->port->port_def.format.video.eCompressionFormat == ++ OMX_VIDEO_CodingUnused) { ++ GST_OBJECT_UNLOCK (pool); ++ return raw_video_options; ++ } ++ GST_OBJECT_UNLOCK (pool); ++ ++ return options; ++} ++ ++static gboolean ++gst_omx_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) ++{ ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); ++ GstCaps *caps; ++ ++ GST_OBJECT_LOCK (pool); ++ ++ if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)) ++ goto wrong_config; ++ ++ if (caps == NULL) ++ goto no_caps; ++ ++ if (pool->port && pool->port->port_def.eDomain == OMX_PortDomainVideo ++ && pool->port->port_def.format.video.eCompressionFormat == ++ OMX_VIDEO_CodingUnused) { ++ GstVideoInfo info; ++ ++ /* now parse the caps from the config */ ++ if (!gst_video_info_from_caps (&info, caps)) ++ goto wrong_video_caps; ++ ++ /* enable metadata based on config of the pool */ ++ pool->add_videometa = ++ gst_buffer_pool_config_has_option (config, ++ GST_BUFFER_POOL_OPTION_VIDEO_META); ++ ++ pool->video_info = info; ++ } ++ ++ if (pool->caps) ++ gst_caps_unref (pool->caps); ++ pool->caps = gst_caps_ref (caps); ++ ++ GST_OBJECT_UNLOCK (pool); ++ ++ return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->set_config ++ (bpool, config); ++ ++ /* ERRORS */ ++wrong_config: ++ { ++ GST_OBJECT_UNLOCK (pool); ++ GST_WARNING_OBJECT (pool, "invalid config"); ++ return FALSE; ++ } ++no_caps: ++ { ++ GST_OBJECT_UNLOCK (pool); ++ GST_WARNING_OBJECT (pool, "no caps in config"); ++ return FALSE; ++ } ++wrong_video_caps: ++ { ++ GST_OBJECT_UNLOCK (pool); ++ GST_WARNING_OBJECT (pool, ++ "failed getting geometry from caps %" GST_PTR_FORMAT, caps); ++ return FALSE; ++ } ++} ++ ++#if defined (HAVE_MMNGRBUF) && defined (HAVE_VIDEODEC_EXT) ++static gboolean ++gst_omx_buffer_pool_export_dmabuf (GstOMXBufferPool * pool, ++ guint phys_addr, gint size, gint * id_export, gint * dmabuf_fd) ++{ ++ gint res; ++ ++ res = ++ mmngr_export_start_in_user (id_export, ++ (gsize) size, phys_addr, dmabuf_fd); ++ if (res != R_MM_OK) { ++ GST_ERROR_OBJECT (pool, ++ "mmngr_export_start_in_user failed (phys_addr:0x%08x)", phys_addr); ++ return FALSE; ++ } ++ GST_DEBUG_OBJECT (pool, ++ "Export dmabuf:%d id_export:%d (phys_addr:0x%08x)", *dmabuf_fd, ++ *id_export, phys_addr); ++ ++ return TRUE; ++} ++ ++/* This function will create a GstBuffer contain dmabuf_fd of decoded ++ * video got from Media Component ++ */ ++static GstBuffer * ++gst_omx_buffer_pool_create_buffer_contain_dmabuf (GstOMXBufferPool * self, ++ GstOMXBuffer * omx_buf, gint * stride, gsize * offset) ++{ ++ gint dmabuf_fd[GST_VIDEO_MAX_PLANES]; ++ gint plane_size[GST_VIDEO_MAX_PLANES]; ++ gint plane_size_ext[GST_VIDEO_MAX_PLANES]; ++ gint dmabuf_id[GST_VIDEO_MAX_PLANES]; ++ gint page_offset[GST_VIDEO_MAX_PLANES]; ++ GstBuffer *new_buf; ++ gint i; ++ gint page_size; ++ guint phys_addr = 0; ++ ++ new_buf = gst_buffer_new (); ++ page_size = getpagesize (); ++ ++ GST_DEBUG_OBJECT (self, "Creating dmabuf mem pBuffer=%p", ++ omx_buf->omx_buf->pBuffer); ++ ++ if (GST_IS_OMX_VIDEO_DEC (self->element)) { ++ OMXR_MC_VIDEO_DECODERESULTTYPE *decode_res = ++ (OMXR_MC_VIDEO_DECODERESULTTYPE *) omx_buf->omx_buf->pOutputPortPrivate; ++ phys_addr = decode_res->pvPhysImageAddressY; ++ } else if (GST_IS_OMX_VIDEO_ENC (self->element)) { ++ /* private data is a physical address of HW buffer */ ++ phys_addr = (guint) omx_buf->omx_buf->pInputPortPrivate; ++ } ++ ++ if (phys_addr == 0) { ++ GST_ERROR_OBJECT (self, "Invalid phys addr for OMX buffer"); ++ return NULL; ++ } ++ ++ for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->video_info); i++) { ++ guint plane_addr = 0; ++ GstMemory *mem; ++ ++ plane_addr = phys_addr + offset[i]; ++ /* Calculate offset between physical address and page boundary */ ++ page_offset[i] = plane_addr & (page_size - 1); ++ ++ plane_size[i] = stride[i] * ++ GST_VIDEO_INFO_COMP_HEIGHT (&self->video_info, i); ++ ++ /* When downstream plugins do mapping from dmabuf fd it requires ++ * mapping from boundary page and size align for page size so ++ * memory for plane must increase to handle for this case */ ++ plane_size_ext[i] = GST_ROUND_UP_N (plane_size[i] + page_offset[i], ++ page_size); ++ ++ if (!gst_omx_buffer_pool_export_dmabuf (self, plane_addr, ++ plane_size_ext[i], &dmabuf_id[i], &dmabuf_fd[i])) { ++ GST_ERROR_OBJECT (self, "dmabuf exporting failed"); ++ return NULL; ++ } ++ ++ g_array_append_val (self->id_array, dmabuf_id[i]); ++ /* Set offset's information */ ++ mem = gst_dmabuf_allocator_alloc (self->allocator, dmabuf_fd[i], ++ plane_size_ext[i]); ++ mem->offset = page_offset[i]; ++ mem->size = plane_size[i]; ++ gst_buffer_append_memory (new_buf, mem); ++ } ++ ++ g_ptr_array_add (self->buffers, new_buf); ++ gst_buffer_add_video_meta_full (new_buf, GST_VIDEO_FRAME_FLAG_NONE, ++ GST_VIDEO_INFO_FORMAT (&self->video_info), ++ GST_VIDEO_INFO_WIDTH (&self->video_info), ++ GST_VIDEO_INFO_HEIGHT (&self->video_info), ++ GST_VIDEO_INFO_N_PLANES (&self->video_info), offset, stride); ++ ++ return new_buf; ++} ++#endif ++ ++static GstFlowReturn ++gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool, ++ GstBuffer ** buffer, GstBufferPoolAcquireParams * params) ++{ ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); ++ GstBuffer *buf; ++ GstOMXBuffer *omx_buf; ++ ++ g_return_val_if_fail (pool->allocating, GST_FLOW_ERROR); ++ ++ omx_buf = g_ptr_array_index (pool->port->buffers, pool->current_buffer_index); ++ g_return_val_if_fail (omx_buf != NULL, GST_FLOW_ERROR); ++ ++ if (pool->other_pool) { ++ guint i, n; ++ ++ buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index); ++ g_assert (pool->other_pool == buf->pool); ++ gst_object_replace ((GstObject **) & buf->pool, NULL); ++ ++ n = gst_buffer_n_memory (buf); ++ for (i = 0; i < n; i++) { ++ GstMemory *mem = gst_buffer_peek_memory (buf, i); ++ ++ /* FIXME: We don't allow sharing because we need to know ++ * when the memory becomes unused and can only then put ++ * it back to the pool. Which is done in the pool's release ++ * function ++ */ ++ GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_NO_SHARE); ++ } ++ ++ if (pool->add_videometa) { ++ GstVideoMeta *meta; ++ ++ meta = gst_buffer_get_video_meta (buf); ++ if (!meta) { ++ gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE, ++ GST_VIDEO_INFO_FORMAT (&pool->video_info), ++ GST_VIDEO_INFO_WIDTH (&pool->video_info), ++ GST_VIDEO_INFO_HEIGHT (&pool->video_info)); ++ } ++ } ++ ++ pool->need_copy = FALSE; ++ } else { ++ GstMemory *mem; ++ const guint nstride = pool->port->port_def.format.video.nStride; ++ const guint nslice = pool->port->port_def.format.video.nSliceHeight; ++ gsize offset[GST_VIDEO_MAX_PLANES] = { 0, }; ++ gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, }; ++ ++ switch (GST_VIDEO_INFO_FORMAT (&pool->video_info)) { ++ case GST_VIDEO_FORMAT_ABGR: ++ case GST_VIDEO_FORMAT_ARGB: ++ case GST_VIDEO_FORMAT_RGB16: ++ case GST_VIDEO_FORMAT_BGR16: ++ case GST_VIDEO_FORMAT_YUY2: ++ case GST_VIDEO_FORMAT_UYVY: ++ case GST_VIDEO_FORMAT_YVYU: ++ case GST_VIDEO_FORMAT_GRAY8: ++ break; ++ case GST_VIDEO_FORMAT_I420: ++ stride[1] = nstride / 2; ++ offset[1] = offset[0] + stride[0] * nslice; ++ stride[2] = nstride / 2; ++ offset[2] = offset[1] + (stride[1] * nslice / 2); ++ break; ++ case GST_VIDEO_FORMAT_NV12: ++ case GST_VIDEO_FORMAT_NV16: ++ stride[1] = nstride; ++ offset[1] = offset[0] + stride[0] * nslice; ++ break; ++ default: ++ g_assert_not_reached (); ++ break; ++ } ++ ++ if (GST_IS_OMX_VIDEO_DEC (pool->element) && ++ GST_OMX_VIDEO_DEC (pool->element)->use_dmabuf == TRUE && ++ (omx_buf->omx_buf->pOutputPortPrivate)) { ++#if defined (HAVE_MMNGRBUF) && defined (HAVE_VIDEODEC_EXT) ++ if (pool->allocator) ++ gst_object_unref (pool->allocator); ++ pool->allocator = gst_dmabuf_allocator_new (); ++ buf = gst_omx_buffer_pool_create_buffer_contain_dmabuf (pool, ++ omx_buf, (gint *) (&stride), (gsize *) (&offset)); ++ if (!buf) { ++ GST_ERROR_OBJECT (pool, "Can not create buffer contain dmabuf"); ++ return GST_FLOW_ERROR; ++ } ++#else ++ GST_ELEMENT_ERROR (pool->element, STREAM, FAILED, (NULL), ++ ("dmabuf mode is invalid now due to not have MMNGR_BUF or MC does not support getting physical address")); ++ return GST_FLOW_ERROR; ++#endif ++ } else { ++ if (GST_IS_OMX_VIDEO_ENC (pool->element) && ++ pool->port->port_def.eDir == OMX_DirInput) ++ /* Propose actual area of encoder to upstream */ ++ mem = gst_memory_new_wrapped (0, omx_buf->omx_buf->pBuffer, ++ omx_buf->omx_buf->nAllocLen, 0, 0, NULL, NULL); ++ else ++ mem = gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf); ++ ++ buf = gst_buffer_new (); ++ gst_buffer_append_memory (buf, mem); ++ g_ptr_array_add (pool->buffers, buf); ++ if (pool->add_videometa) { ++ pool->need_copy = FALSE; ++ } else { ++ GstVideoInfo info; ++ gboolean need_copy = FALSE; ++ gint i; ++ ++ gst_video_info_init (&info); ++ gst_video_info_set_format (&info, ++ GST_VIDEO_INFO_FORMAT (&pool->video_info), ++ GST_VIDEO_INFO_WIDTH (&pool->video_info), ++ GST_VIDEO_INFO_HEIGHT (&pool->video_info)); ++ ++ for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&pool->video_info); i++) { ++ if (info.stride[i] != stride[i] || info.offset[i] != offset[i]) { ++ need_copy = TRUE; ++ break; ++ } ++ } ++ ++ pool->need_copy = need_copy; ++ } ++ ++ if (pool->need_copy || pool->add_videometa) { ++ /* We always add the videometa. It's the job of the user ++ * to copy the buffer if pool->need_copy is TRUE ++ */ ++ gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, ++ GST_VIDEO_INFO_FORMAT (&pool->video_info), ++ GST_VIDEO_INFO_WIDTH (&pool->video_info), ++ GST_VIDEO_INFO_HEIGHT (&pool->video_info), ++ GST_VIDEO_INFO_N_PLANES (&pool->video_info), offset, stride); ++ } ++ } ++ } ++ ++ gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf), ++ gst_omx_buffer_data_quark, omx_buf, NULL); ++ ++ *buffer = buf; ++ ++ pool->current_buffer_index++; ++ ++ return GST_FLOW_OK; ++} ++ ++static void ++gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer) ++{ ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); ++ ++ /* If the buffers belong to another pool, restore them now */ ++ GST_OBJECT_LOCK (pool); ++ if (pool->other_pool) { ++ gst_object_replace ((GstObject **) & buffer->pool, ++ (GstObject *) pool->other_pool); ++ } ++ GST_OBJECT_UNLOCK (pool); ++ ++ gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer), ++ gst_omx_buffer_data_quark, NULL, NULL); ++ ++ GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->free_buffer (bpool, ++ buffer); ++} ++ ++static GstFlowReturn ++gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool, ++ GstBuffer ** buffer, GstBufferPoolAcquireParams * params) ++{ ++ GstFlowReturn ret; ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); ++ ++ if (pool->port->port_def.eDir == OMX_DirOutput) { ++ GstBuffer *buf; ++ ++ g_return_val_if_fail (pool->current_buffer_index != -1, GST_FLOW_ERROR); ++ ++ buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index); ++ g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); ++ *buffer = buf; ++ ret = GST_FLOW_OK; ++ ++ /* If it's our own memory we have to set the sizes */ ++ if ((!pool->other_pool) && ++ ((GST_OMX_VIDEO_DEC (pool->element)->use_dmabuf) == FALSE)) { ++ GstMemory *mem = gst_buffer_peek_memory (*buffer, 0); ++ ++ g_assert (mem ++ && g_strcmp0 (mem->allocator->mem_type, GST_OMX_MEMORY_TYPE) == 0); ++ mem->size = ((GstOMXMemory *) mem)->buf->omx_buf->nFilledLen; ++ mem->offset = ((GstOMXMemory *) mem)->buf->omx_buf->nOffset; ++ } ++ } else { ++ if (GST_IS_OMX_VIDEO_ENC (pool->element)) { ++ GstBuffer *buf; ++ GstOMXBuffer *omx_buf; ++ gint count = 0; ++ ++ /* Search on number of OMXBuffer of port to find available GstBuffer ++ * (emptied OMXBuffer) to propose to upstream. If after 3 times searching, ++ * can not find target GstBuffer, return flow error ++ */ ++ do { ++ buf = g_ptr_array_index (pool->buffers, pool->enc_buffer_index); ++ g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); ++ ++ omx_buf = ++ gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf), ++ gst_omx_buffer_data_quark); ++ pool->enc_buffer_index++; ++ if (pool->enc_buffer_index == pool->port->port_def.nBufferCountActual) ++ pool->enc_buffer_index = 0; ++ ++ count += 1; ++ } while (omx_buf->used == TRUE && ++ count < pool->port->port_def.nBufferCountActual * 3); ++ ++ if (count == pool->port->port_def.nBufferCountActual * 3) { ++ ret = GST_FLOW_ERROR; ++ GST_ERROR_OBJECT (pool, ++ "Can not acquire buffer after 3 times searching"); ++ } else { ++ *buffer = buf; ++ ret = GST_FLOW_OK; ++ } ++ } else { ++ /* Acquire any buffer that is available to be filled by upstream */ ++ ret = ++ GST_BUFFER_POOL_CLASS ++ (gst_omx_buffer_pool_parent_class)->acquire_buffer (bpool, buffer, ++ params); ++ } ++ } ++ ++ return ret; ++} ++ ++static void ++gst_omx_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) ++{ ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); ++ OMX_ERRORTYPE err; ++ GstOMXBuffer *omx_buf; ++ ++ g_assert (pool->component && pool->port); ++ ++ if (!pool->allocating && !pool->deactivated) { ++ omx_buf = ++ gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer), ++ gst_omx_buffer_data_quark); ++ if (pool->port->port_def.eDir == OMX_DirOutput && !omx_buf->used) { ++ /* Release back to the port, can be filled again */ ++ err = gst_omx_port_release_buffer (pool->port, omx_buf); ++ if (err != OMX_ErrorNone) { ++ GST_ELEMENT_ERROR (pool->element, LIBRARY, SETTINGS, (NULL), ++ ("Failed to relase output buffer to component: %s (0x%08x)", ++ gst_omx_error_to_string (err), err)); ++ } ++ } else if (!omx_buf->used) { ++ /* TODO: Implement. ++ * ++ * If not used (i.e. was not passed to the component) this should do ++ * the same as EmptyBufferDone. ++ * If it is used (i.e. was passed to the component) this should do ++ * nothing until EmptyBufferDone. ++ * ++ * EmptyBufferDone should release the buffer to the pool so it can ++ * be allocated again ++ * ++ * Needs something to call back here in EmptyBufferDone, like keeping ++ * a ref on the buffer in GstOMXBuffer until EmptyBufferDone... which ++ * would ensure that the buffer is always unused when this is called. ++ */ ++ if (GST_OMX_VIDEO_ENC (pool->element)->no_copy == FALSE) { ++ g_assert_not_reached (); ++ GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer ++ (bpool, buffer); ++ } ++ } ++ } ++} ++ ++static void ++gst_omx_buffer_pool_finalize (GObject * object) ++{ ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (object); ++ ++#ifdef HAVE_MMNGRBUF ++ if (GST_OMX_VIDEO_DEC (pool->element)->use_dmabuf) { ++ gint i; ++ gint dmabuf_id; ++ ++ for (i = 0; i < pool->id_array->len; i++) { ++ dmabuf_id = g_array_index (pool->id_array, gint, i); ++ if (dmabuf_id >= 0) { ++ GST_DEBUG_OBJECT (pool, "mmngr_export_end_in_user (%d)", dmabuf_id); ++ mmngr_export_end_in_user (dmabuf_id); ++ } else { ++ GST_WARNING_OBJECT (pool, "Invalid dmabuf_id"); ++ } ++ } ++ } ++ g_array_free (pool->id_array, TRUE); ++#endif ++ ++ if (pool->element) ++ gst_object_unref (pool->element); ++ pool->element = NULL; ++ ++ if (pool->buffers) ++ g_ptr_array_unref (pool->buffers); ++ pool->buffers = NULL; ++ ++ if (pool->other_pool) ++ gst_object_unref (pool->other_pool); ++ pool->other_pool = NULL; ++ ++ if (pool->allocator) ++ gst_object_unref (pool->allocator); ++ pool->allocator = NULL; ++ ++ if (pool->caps) ++ gst_caps_unref (pool->caps); ++ pool->caps = NULL; ++ ++ G_OBJECT_CLASS (gst_omx_buffer_pool_parent_class)->finalize (object); ++} ++ ++static void ++gst_omx_buffer_pool_class_init (GstOMXBufferPoolClass * klass) ++{ ++ GObjectClass *gobject_class = (GObjectClass *) klass; ++ GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; ++ ++ gst_omx_buffer_data_quark = g_quark_from_static_string ("GstOMXBufferData"); ++ ++ gobject_class->finalize = gst_omx_buffer_pool_finalize; ++ gstbufferpool_class->start = gst_omx_buffer_pool_start; ++ gstbufferpool_class->stop = gst_omx_buffer_pool_stop; ++ gstbufferpool_class->get_options = gst_omx_buffer_pool_get_options; ++ gstbufferpool_class->set_config = gst_omx_buffer_pool_set_config; ++ gstbufferpool_class->alloc_buffer = gst_omx_buffer_pool_alloc_buffer; ++ gstbufferpool_class->free_buffer = gst_omx_buffer_pool_free_buffer; ++ gstbufferpool_class->acquire_buffer = gst_omx_buffer_pool_acquire_buffer; ++ gstbufferpool_class->release_buffer = gst_omx_buffer_pool_release_buffer; ++} ++ ++static void ++gst_omx_buffer_pool_init (GstOMXBufferPool * pool) ++{ ++ pool->buffers = g_ptr_array_new (); ++ pool->allocator = g_object_new (gst_omx_memory_allocator_get_type (), NULL); ++#ifdef HAVE_MMNGRBUF ++ pool->id_array = g_array_new (FALSE, FALSE, sizeof (gint)); ++#endif ++ pool->enc_buffer_index = 0; ++} ++ ++GstBufferPool * ++gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, ++ GstOMXPort * port) ++{ ++ GstOMXBufferPool *pool; ++ ++ pool = g_object_new (gst_omx_buffer_pool_get_type (), NULL); ++ pool->element = gst_object_ref (element); ++ pool->component = component; ++ pool->port = port; ++ ++ return GST_BUFFER_POOL (pool); ++} +diff --git a/omx/gstomxbufferpool.h b/omx/gstomxbufferpool.h +new file mode 100644 +index 0000000..09cab8d +--- /dev/null ++++ b/omx/gstomxbufferpool.h +@@ -0,0 +1,106 @@ ++/* ++ * Copyright 2014 Advanced Micro Devices, Inc. ++ * Author: Christian König <christian.koenig@amd.com> ++ * Copyright (C) 2015, Renesas Electronics Corporation ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation ++ * version 2.1 of the License. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#ifndef __GST_OMX_BUFFER_POOL_H__ ++#define __GST_OMX_BUFFER_POOL_H__ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include <gst/gst.h> ++#include <gst/video/gstvideometa.h> ++#include <gst/video/gstvideopool.h> ++ ++#include "gstomx.h" ++ ++G_BEGIN_DECLS ++ ++#define GST_TYPE_OMX_BUFFER_POOL \ ++ (gst_omx_buffer_pool_get_type()) ++#define GST_OMX_BUFFER_POOL(obj) \ ++ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OMX_BUFFER_POOL,GstOMXBufferPool)) ++#define GST_IS_OMX_BUFFER_POOL(obj) \ ++ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OMX_BUFFER_POOL)) ++ ++typedef struct _GstOMXBufferPool GstOMXBufferPool; ++typedef struct _GstOMXBufferPoolClass GstOMXBufferPoolClass; ++ ++struct _GstOMXBufferPool ++{ ++ GstVideoBufferPool parent; ++ ++ GstElement *element; ++ ++ GstCaps *caps; ++ gboolean add_videometa; ++ gboolean need_copy; ++ GstVideoInfo video_info; ++ ++ /* Owned by element, element has to stop this pool before ++ * it destroys component or port */ ++ GstOMXComponent *component; ++ GstOMXPort *port; ++ ++ /* For handling OpenMAX allocated memory */ ++ GstAllocator *allocator; ++ ++ /* Set from outside this pool */ ++ /* TRUE if we're currently allocating all our buffers */ ++ gboolean allocating; ++ /* TRUE if the pool is not used anymore */ ++ gboolean deactivated; ++ ++ /* For populating the pool from another one */ ++ GstBufferPool *other_pool; ++ GPtrArray *buffers; ++ ++ /* Used during acquire for output ports to ++ * specify which buffer has to be retrieved ++ * and during alloc, which buffer has to be ++ * wrapped ++ */ ++ gint current_buffer_index; ++ ++ /* Used during acquire for input port */ ++ gint enc_buffer_index; ++#ifdef HAVE_MMNGRBUF ++ /* Array use to contain dma_id. It is used in export_end dmabuf area */ ++ GArray *id_array; ++#endif ++ ++ /* TRUE if the downstream buffer pool can handle ++ "videosink_buffer_creation_request" query */ ++ gboolean vsink_buf_req_supported; ++}; ++ ++struct _GstOMXBufferPoolClass ++{ ++ GstVideoBufferPoolClass parent_class; ++}; ++ ++GType gst_omx_buffer_pool_get_type (void); ++ ++GstBufferPool *gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, GstOMXPort * port); ++ ++G_END_DECLS ++ ++#endif /* __GST_OMX_BUFFER_POOL_H__ */ +diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c +index 837c623..25b6b30 100644 +--- a/omx/gstomxvideodec.c ++++ b/omx/gstomxvideodec.c +@@ -32,6 +32,7 @@ + #include <unistd.h> /* getpagesize() */ + + #include "gstomxvideodec.h" ++#include "gstomxbufferpool.h" + + #ifdef HAVE_MMNGRBUF + #include "gst/allocators/gstdmabuf.h" +@@ -42,898 +43,6 @@ + GST_DEBUG_CATEGORY_STATIC (gst_omx_video_dec_debug_category); + #define GST_CAT_DEFAULT gst_omx_video_dec_debug_category + +-typedef struct _GstOMXMemory GstOMXMemory; +-typedef struct _GstOMXMemoryAllocator GstOMXMemoryAllocator; +-typedef struct _GstOMXMemoryAllocatorClass GstOMXMemoryAllocatorClass; +- +-struct _GstOMXMemory +-{ +- GstMemory mem; +- +- GstOMXBuffer *buf; +-}; +- +-struct _GstOMXMemoryAllocator +-{ +- GstAllocator parent; +-}; +- +-struct _GstOMXMemoryAllocatorClass +-{ +- GstAllocatorClass parent_class; +-}; +- +-/* User data and function for release OMX buffer in no-copy mode */ +-struct GstOMXBufferCallback +-{ +- GstOMXPort * out_port; +- GstOMXBuffer * buf; +-}; +- +-#define GST_OMX_MEMORY_TYPE "openmax" +-#define DEFAULT_FRAME_PER_SECOND 30 +- +-static GstMemory * +-gst_omx_memory_allocator_alloc_dummy (GstAllocator * allocator, gsize size, +- GstAllocationParams * params) +-{ +- g_assert_not_reached (); +- return NULL; +-} +- +-static void +-gst_omx_memory_allocator_free (GstAllocator * allocator, GstMemory * mem) +-{ +- GstOMXMemory *omem = (GstOMXMemory *) mem; +- +- /* TODO: We need to remember which memories are still used +- * so we can wait until everything is released before allocating +- * new memory +- */ +- +- g_slice_free (GstOMXMemory, omem); +-} +- +-static gpointer +-gst_omx_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) +-{ +- GstOMXMemory *omem = (GstOMXMemory *) mem; +- +- return omem->buf->omx_buf->pBuffer; +-} +- +-static void +-gst_omx_memory_unmap (GstMemory * mem) +-{ +-} +- +-static GstMemory * +-gst_omx_memory_share (GstMemory * mem, gssize offset, gssize size) +-{ +- g_assert_not_reached (); +- return NULL; +-} +- +-GType gst_omx_memory_allocator_get_type (void); +-G_DEFINE_TYPE (GstOMXMemoryAllocator, gst_omx_memory_allocator, +- GST_TYPE_ALLOCATOR); +- +-#define GST_TYPE_OMX_MEMORY_ALLOCATOR (gst_omx_memory_allocator_get_type()) +-#define GST_IS_OMX_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OMX_MEMORY_ALLOCATOR)) +- +-static void +-gst_omx_memory_allocator_class_init (GstOMXMemoryAllocatorClass * klass) +-{ +- GstAllocatorClass *allocator_class; +- +- allocator_class = (GstAllocatorClass *) klass; +- +- allocator_class->alloc = gst_omx_memory_allocator_alloc_dummy; +- allocator_class->free = gst_omx_memory_allocator_free; +-} +- +-static void +-gst_omx_memory_allocator_init (GstOMXMemoryAllocator * allocator) +-{ +- GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); +- +- alloc->mem_type = GST_OMX_MEMORY_TYPE; +- alloc->mem_map = gst_omx_memory_map; +- alloc->mem_unmap = gst_omx_memory_unmap; +- alloc->mem_share = gst_omx_memory_share; +- +- /* default copy & is_span */ +- +- GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); +-} +- +-#ifndef HAVE_MMNGRBUF +-static GstMemory * +-gst_omx_memory_allocator_alloc (GstAllocator * allocator, GstMemoryFlags flags, +- GstOMXBuffer * buf, gsize offset, gsize size) +-{ +- GstOMXMemory *mem; +- +- /* FIXME: We don't allow sharing because we need to know +- * when the memory becomes unused and can only then put +- * it back to the pool. Which is done in the pool's release +- * function +- */ +- flags |= GST_MEMORY_FLAG_NO_SHARE; +- +- mem = g_slice_new (GstOMXMemory); +- /* the shared memory is always readonly */ +- gst_memory_init (GST_MEMORY_CAST (mem), flags, allocator, NULL, +- buf->omx_buf->nAllocLen, buf->port->port_def.nBufferAlignment, +- offset, size); +- +- mem->buf = buf; +- +- return GST_MEMORY_CAST (mem); +-} +-#endif +- +-/* Buffer pool for the buffers of an OpenMAX port. +- * +- * This pool is only used if we either passed buffers from another +- * pool to the OMX port or provide the OMX buffers directly to other +- * elements. +- * +- * +- * A buffer is in the pool if it is currently owned by the port, +- * i.e. after OMX_{Fill,Empty}ThisBuffer(). A buffer is outside +- * the pool after it was taken from the port after it was handled +- * by the port, i.e. {Empty,Fill}BufferDone. +- * +- * Buffers can be allocated by us (OMX_AllocateBuffer()) or allocated +- * by someone else and (temporarily) passed to this pool +- * (OMX_UseBuffer(), OMX_UseEGLImage()). In the latter case the pool of +- * the buffer will be overriden, and restored in free_buffer(). Other +- * buffers are just freed there. +- * +- * The pool always has a fixed number of minimum and maximum buffers +- * and these are allocated while starting the pool and released afterwards. +- * They correspond 1:1 to the OMX buffers of the port, which are allocated +- * before the pool is started. +- * +- * Acquiring a buffer from this pool happens after the OMX buffer has +- * been acquired from the port. gst_buffer_pool_acquire_buffer() is +- * supposed to return the buffer that corresponds to the OMX buffer. +- * +- * For buffers provided to upstream, the buffer will be passed to +- * the component manually when it arrives and then unreffed. If the +- * buffer is released before reaching the component it will be just put +- * back into the pool as if EmptyBufferDone has happened. If it was +- * passed to the component, it will be back into the pool when it was +- * released and EmptyBufferDone has happened. +- * +- * For buffers provided to downstream, the buffer will be returned +- * back to the component (OMX_FillThisBuffer()) when it is released. +- */ +- +-static GQuark gst_omx_buffer_data_quark = 0; +- +-#define GST_OMX_BUFFER_POOL(pool) ((GstOMXBufferPool *) pool) +-typedef struct _GstOMXBufferPool GstOMXBufferPool; +-typedef struct _GstOMXBufferPoolClass GstOMXBufferPoolClass; +- +-typedef struct _GstOMXVideoDecBufferData GstOMXVideoDecBufferData; +- +-struct _GstOMXBufferPool +-{ +- GstVideoBufferPool parent; +- +- GstElement *element; +- +- GstCaps *caps; +- gboolean add_videometa; +- GstVideoInfo video_info; +- +- /* Owned by element, element has to stop this pool before +- * it destroys component or port */ +- GstOMXComponent *component; +- GstOMXPort *port; +- +- /* For handling OpenMAX allocated memory */ +- GstAllocator *allocator; +- +- /* Set from outside this pool */ +- /* TRUE if we're currently allocating all our buffers */ +- gboolean allocating; +- +- /* TRUE if the pool is not used anymore */ +- gboolean deactivated; +- +- /* For populating the pool from another one */ +- GstBufferPool *other_pool; +- GPtrArray *buffers; +- +- /* Used during acquire for output ports to +- * specify which buffer has to be retrieved +- * and during alloc, which buffer has to be +- * wrapped +- */ +- gint current_buffer_index; +- +- /* TRUE if the downstream buffer pool can handle +- "videosink_buffer_creation_request" query */ +- gboolean vsink_buf_req_supported; +-}; +- +-struct _GstOMXBufferPoolClass +-{ +- GstVideoBufferPoolClass parent_class; +-}; +- +-struct _GstOMXVideoDecBufferData +-{ +- gboolean already_acquired; +- +-#ifdef HAVE_MMNGRBUF +- gint id_export[GST_VIDEO_MAX_PLANES]; +-#endif +-}; +- +-GType gst_omx_buffer_pool_get_type (void); +- +-G_DEFINE_TYPE (GstOMXBufferPool, gst_omx_buffer_pool, GST_TYPE_BUFFER_POOL); +- +-static void gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, +- GstBuffer * buffer); +- +-static gboolean +-gst_omx_buffer_pool_start (GstBufferPool * bpool) +-{ +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); +- +- /* Only allow to start the pool if we still are attached +- * to a component and port */ +- GST_OBJECT_LOCK (pool); +- if (!pool->component || !pool->port) { +- GST_OBJECT_UNLOCK (pool); +- return FALSE; +- } +- GST_OBJECT_UNLOCK (pool); +- +- return +- GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->start (bpool); +-} +- +-static gboolean +-gst_omx_buffer_pool_stop (GstBufferPool * bpool) +-{ +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); +- gint i = 0; +- +- /* When not using the default GstBufferPool::GstAtomicQueue then +- * GstBufferPool::free_buffer is not called while stopping the pool +- * (because the queue is empty) */ +- for (i = 0; i < pool->buffers->len; i++) +- GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer +- (bpool, g_ptr_array_index (pool->buffers, i)); +- +- /* Remove any buffers that are there */ +- g_ptr_array_set_size (pool->buffers, 0); +- +- if (pool->caps) +- gst_caps_unref (pool->caps); +- pool->caps = NULL; +- +- pool->add_videometa = FALSE; +- +- return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->stop (bpool); +-} +- +-static const gchar ** +-gst_omx_buffer_pool_get_options (GstBufferPool * bpool) +-{ +- static const gchar *raw_video_options[] = +- { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL }; +- static const gchar *options[] = { NULL }; +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); +- +- GST_OBJECT_LOCK (pool); +- if (pool->port && pool->port->port_def.eDomain == OMX_PortDomainVideo +- && pool->port->port_def.format.video.eCompressionFormat == +- OMX_VIDEO_CodingUnused) { +- GST_OBJECT_UNLOCK (pool); +- return raw_video_options; +- } +- GST_OBJECT_UNLOCK (pool); +- +- return options; +-} +- +-static gboolean +-gst_omx_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) +-{ +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); +- GstCaps *caps; +- +- GST_OBJECT_LOCK (pool); +- +- if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)) +- goto wrong_config; +- +- if (caps == NULL) +- goto no_caps; +- +- if (pool->port && pool->port->port_def.eDomain == OMX_PortDomainVideo +- && pool->port->port_def.format.video.eCompressionFormat == +- OMX_VIDEO_CodingUnused) { +- GstVideoInfo info; +- +- /* now parse the caps from the config */ +- if (!gst_video_info_from_caps (&info, caps)) +- goto wrong_video_caps; +- +- /* enable metadata based on config of the pool */ +- pool->add_videometa = +- gst_buffer_pool_config_has_option (config, +- GST_BUFFER_POOL_OPTION_VIDEO_META); +- +- pool->video_info = info; +- } +- +- if (pool->caps) +- gst_caps_unref (pool->caps); +- pool->caps = gst_caps_ref (caps); +- +- GST_OBJECT_UNLOCK (pool); +- +- return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->set_config +- (bpool, config); +- +- /* ERRORS */ +-wrong_config: +- { +- GST_OBJECT_UNLOCK (pool); +- GST_WARNING_OBJECT (pool, "invalid config"); +- return FALSE; +- } +-no_caps: +- { +- GST_OBJECT_UNLOCK (pool); +- GST_WARNING_OBJECT (pool, "no caps in config"); +- return FALSE; +- } +-wrong_video_caps: +- { +- GST_OBJECT_UNLOCK (pool); +- GST_WARNING_OBJECT (pool, +- "failed getting geometry from caps %" GST_PTR_FORMAT, caps); +- return FALSE; +- } +-} +- +-static GstFlowReturn +-gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool, +- GstBuffer ** buffer, GstBufferPoolAcquireParams * params) +-{ +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); +- GstBuffer *buf; +- GstOMXBuffer *omx_buf; +- GstOMXVideoDec *self; +- self = GST_OMX_VIDEO_DEC (pool->element); +- +- g_return_val_if_fail (pool->allocating, GST_FLOW_ERROR); +- +- omx_buf = g_ptr_array_index (pool->port->buffers, pool->current_buffer_index); +- g_return_val_if_fail (omx_buf != NULL, GST_FLOW_ERROR); +- +- if (pool->other_pool) { +- guint i, n; +- +- buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index); +- g_assert (pool->other_pool == buf->pool); +- gst_object_replace ((GstObject **) & buf->pool, NULL); +- +- n = gst_buffer_n_memory (buf); +- for (i = 0; i < n; i++) { +- GstMemory *mem = gst_buffer_peek_memory (buf, i); +- +- /* FIXME: We don't allow sharing because we need to know +- * when the memory becomes unused and can only then put +- * it back to the pool. Which is done in the pool's release +- * function +- */ +- GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_NO_SHARE); +- } +- +- if (pool->add_videometa) { +- GstVideoMeta *meta; +- +- meta = gst_buffer_get_video_meta (buf); +- if (!meta) { +- gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE, +- GST_VIDEO_INFO_FORMAT (&pool->video_info), +- GST_VIDEO_INFO_WIDTH (&pool->video_info), +- GST_VIDEO_INFO_HEIGHT (&pool->video_info)); +- } +- } +- } else { +- gsize offset[4] = { 0, }; +- gint stride[4] = { 0, }; +- gsize plane_size[4] = { 0, }; +-#ifndef HAVE_MMNGRBUF +- guint n_planes; +-#endif +- gint i; +- GstOMXVideoDecBufferData *vdbuf_data; +- +- switch (pool->video_info.finfo->format) { +- case GST_VIDEO_FORMAT_I420: +- offset[0] = 0; +- stride[0] = pool->port->port_def.format.video.nStride; +- offset[1] = stride[0] * pool->port->port_def.format.video.nSliceHeight; +- stride[1] = pool->port->port_def.format.video.nStride / 2; +- offset[2] = +- offset[1] + +- stride[1] * (pool->port->port_def.format.video.nSliceHeight / 2); +- stride[2] = pool->port->port_def.format.video.nStride / 2; +- plane_size[0] = pool->port->port_def.format.video.nStride * +- pool->port->port_def.format.video.nFrameHeight; +- plane_size[1] = plane_size[2] = plane_size[0] / 4; +- +-#ifndef HAVE_MMNGRBUF +- n_planes = 3; +-#endif +- break; +- case GST_VIDEO_FORMAT_NV12: +- offset[0] = 0; +- stride[0] = pool->port->port_def.format.video.nStride; +- offset[1] = stride[0] * pool->port->port_def.format.video.nSliceHeight; +- stride[1] = pool->port->port_def.format.video.nStride; +- plane_size[0] = pool->port->port_def.format.video.nStride * +- pool->port->port_def.format.video.nFrameHeight; +- plane_size[1] = plane_size[0] / 2; +- +-#ifndef HAVE_MMNGRBUF +- n_planes = 2; +-#endif +- break; +- default: +- g_assert_not_reached (); +- break; +- } +- +- buf = gst_buffer_new (); +- +-#ifndef HAVE_MMNGRBUF +- if (self->use_dmabuf == FALSE) +- for (i = 0; i < n_planes; i++) +- gst_buffer_append_memory (buf, +- gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf, +- offset[i], plane_size[i])); +-#endif +- +- g_ptr_array_add (pool->buffers, buf); +- +- if (pool->add_videometa) +- gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, +- GST_VIDEO_INFO_FORMAT (&pool->video_info), +- GST_VIDEO_INFO_WIDTH (&pool->video_info), +- GST_VIDEO_INFO_HEIGHT (&pool->video_info), +- GST_VIDEO_INFO_N_PLANES (&pool->video_info), offset, stride); +- +- /* Initialize an already_acquired flag */ +- vdbuf_data = g_slice_new (GstOMXVideoDecBufferData); +- vdbuf_data->already_acquired = FALSE; +-#ifdef HAVE_MMNGRBUF +- if (self->use_dmabuf) +- for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) +- vdbuf_data->id_export[i] = -1; +-#endif +- +- omx_buf->private_data = (void *) vdbuf_data; +- } +- +- gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf), +- gst_omx_buffer_data_quark, omx_buf, NULL); +- +- *buffer = buf; +- +- pool->current_buffer_index++; +- +- return GST_FLOW_OK; +-} +- +-static void +-gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer) +-{ +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); +- GstOMXBuffer *omx_buf; +- GstOMXVideoDec *self; +- self = GST_OMX_VIDEO_DEC (pool->element); +-#ifdef HAVE_MMNGRBUF +- GstOMXVideoDecBufferData *vdbuf_data; +- gint i; +-#endif +- +- /* If the buffers belong to another pool, restore them now */ +- GST_OBJECT_LOCK (pool); +- if (pool->other_pool) { +- gst_object_replace ((GstObject **) & buffer->pool, +- (GstObject *) pool->other_pool); +- } +- GST_OBJECT_UNLOCK (pool); +- +- omx_buf = +- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer), +- gst_omx_buffer_data_quark); +-#ifdef HAVE_MMNGRBUF +- if (self->use_dmabuf) { +- vdbuf_data = (GstOMXVideoDecBufferData *) omx_buf->private_data; +- if (vdbuf_data) { +- for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) +- if (vdbuf_data->id_export[i] >= 0) +- mmngr_export_end_in_user (vdbuf_data->id_export[i]); +- } +- } +-#endif +- g_slice_free (GstOMXVideoDecBufferData, omx_buf->private_data); +- +- gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer), +- gst_omx_buffer_data_quark, NULL, NULL); +- +- GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->free_buffer (bpool, +- buffer); +-} +- +-#ifdef HAVE_MMNGRBUF +-static GstBuffer * +-gst_omx_buffer_pool_request_videosink_buffer_creation (GstOMXBufferPool * pool, +- gint dmabuf_fd[GST_VIDEO_MAX_PLANES], gpointer plane_buf[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES]) +-{ +- GstQuery *query; +- GValue val = { 0, }; +- GstStructure *structure; +- const GValue *value; +- GstBuffer *buffer; +- GArray *dmabuf_array; +- GArray *stride_array; +- GArray *planebuf_array; +- gint n_planes; +- gint i; +- +- g_value_init (&val, G_TYPE_POINTER); +- g_value_set_pointer (&val, (gpointer) pool->allocator); +- +- dmabuf_array = g_array_new (FALSE, FALSE, sizeof (gint)); +- stride_array = g_array_new (FALSE, FALSE, sizeof (gint)); +- planebuf_array = g_array_new (FALSE, FALSE, sizeof (gpointer)); +- +- n_planes = GST_VIDEO_INFO_N_PLANES (&pool->video_info); +- for (i = 0; i < n_planes; i++) { +- g_array_append_val (dmabuf_array, dmabuf_fd[i]); +- g_array_append_val (stride_array, stride[i]); +- g_array_append_val (planebuf_array, plane_buf[i]); +- } +- +- structure = gst_structure_new ("videosink_buffer_creation_request", +- "width", G_TYPE_INT, pool->port->port_def.format.video.nFrameWidth, +- "height", G_TYPE_INT, pool->port->port_def.format.video.nFrameHeight, +- "stride", G_TYPE_ARRAY, stride_array, +- "dmabuf", G_TYPE_ARRAY, dmabuf_array, +- "planebuf", G_TYPE_ARRAY, planebuf_array, +- "allocator", G_TYPE_POINTER, &val, +- "format", G_TYPE_STRING, +- gst_video_format_to_string (pool->video_info.finfo->format), +- "n_planes", G_TYPE_INT, n_planes, NULL); +- +- query = gst_query_new_custom (GST_QUERY_CUSTOM, structure); +- +- GST_DEBUG_OBJECT (pool, "send a videosink_buffer_creation_request query"); +- +- if (!gst_pad_peer_query (GST_VIDEO_DECODER_SRC_PAD (pool->element), query)) { +- GST_ERROR_OBJECT (pool, "videosink_buffer_creation_request query failed"); +- return NULL; +- } +- +- value = gst_structure_get_value (structure, "buffer"); +- buffer = gst_value_get_buffer (value); +- if (buffer == NULL) { +- GST_ERROR_OBJECT (pool, +- "could not get a buffer from videosink_buffer_creation query"); +- return NULL; +- } +- +- gst_query_unref (query); +- +- g_array_free (dmabuf_array, TRUE); +- g_array_free (stride_array, TRUE); +- +- return buffer; +-} +-#endif +- +-#ifdef HAVE_MMNGRBUF +-static gboolean +-gst_omx_buffer_pool_export_dmabuf (GstOMXBufferPool * pool, +- guint phys_addr, gint size, gint boundary, gint * id_export, +- gint * dmabuf_fd) +-{ +- gint res; +- +- res = +- mmngr_export_start_in_user (id_export, +- (size + boundary - 1) & ~(boundary - 1), (unsigned long) phys_addr, +- dmabuf_fd); +- if (res != R_MM_OK) { +- GST_ERROR_OBJECT (pool, +- "mmngr_export_start_in_user failed (phys_addr:0x%08x)", phys_addr); +- return FALSE; +- } +- GST_DEBUG_OBJECT (pool, +- "Export dmabuf:%d id_export:%d (phys_addr:0x%08x)", *dmabuf_fd, +- *id_export, phys_addr); +- +- return TRUE; +-} +-#endif +- +-static GstFlowReturn +-gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool, +- GstBuffer ** buffer, GstBufferPoolAcquireParams * params) +-{ +- GstFlowReturn ret; +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); +- GstOMXVideoDec *self; +- self = GST_OMX_VIDEO_DEC (pool->element); +- +- if (pool->port->port_def.eDir == OMX_DirOutput) { +- GstBuffer *buf; +- GstOMXBuffer *omx_buf; +- GstOMXVideoDecBufferData *vdbuf_data; +-#ifdef HAVE_MMNGRBUF +- guint n_mem; +-#endif +- +- g_return_val_if_fail (pool->current_buffer_index != -1, GST_FLOW_ERROR); +- +- buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index); +- g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); +- +- omx_buf = +- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf), +- gst_omx_buffer_data_quark); +- +- vdbuf_data = (GstOMXVideoDecBufferData *) omx_buf->private_data; +-#ifdef HAVE_MMNGRBUF +- if (self->use_dmabuf) +- { +- n_mem = gst_buffer_n_memory (buf); +- if (n_mem == 0) { +- GstBuffer *new_buf; +- GstVideoMeta *vmeta; +- gint n_planes; +- gint i; +- gint dmabuf_fd[GST_VIDEO_MAX_PLANES]; +- gint plane_size[GST_VIDEO_MAX_PLANES]; +- gpointer plane_buf[GST_VIDEO_MAX_PLANES]; +- guint phys_addr; +- OMXR_MC_VIDEO_DECODERESULTTYPE *decode_res = +- (OMXR_MC_VIDEO_DECODERESULTTYPE *) omx_buf-> +- omx_buf->pOutputPortPrivate; +- gint page_size; +- +- GST_DEBUG_OBJECT (pool, "Create dmabuf mem pBuffer=%p", +- omx_buf->omx_buf->pBuffer); +- +- vmeta = gst_buffer_get_video_meta (buf); +- +- phys_addr = (guint) decode_res->pvPhysImageAddressY; +- page_size = getpagesize (); +- +- /* Export a dmabuf file descriptor from the head of Y plane to +- * the end of the buffer so that mapping the whole plane as +- * contiguous memory is available. */ +- if (!gst_omx_buffer_pool_export_dmabuf (pool, phys_addr, +- pool->port->port_def.nBufferSize, page_size, +- &vdbuf_data->id_export[0], &dmabuf_fd[0])) { +- GST_ERROR_OBJECT (pool, "dmabuf exporting failed"); +- return GST_FLOW_ERROR; +- } +- +- plane_size[0] = vmeta->stride[0] * +- GST_VIDEO_INFO_COMP_HEIGHT (&pool->video_info, 0); +- plane_buf[0] = omx_buf->omx_buf->pBuffer; +- +- /* Export dmabuf file descriptors from second and subsequent planes */ +- n_planes = GST_VIDEO_INFO_N_PLANES (&pool->video_info); +- for (i = 1; i < n_planes; i++) { +- phys_addr = (guint) decode_res->pvPhysImageAddressY + vmeta->offset[i]; +- plane_size[i] = vmeta->stride[i] * +- GST_VIDEO_INFO_COMP_HEIGHT (&pool->video_info, i); +- plane_buf[i] = omx_buf->omx_buf->pBuffer + vmeta->offset[i]; +- +- if (!gst_omx_buffer_pool_export_dmabuf (pool, phys_addr, plane_size[i], +- page_size, &vdbuf_data->id_export[i], &dmabuf_fd[i])) { +- GST_ERROR_OBJECT (pool, "dmabuf exporting failed"); +- return GST_FLOW_ERROR; +- } +- } +- +- if (pool->vsink_buf_req_supported) +- new_buf = gst_omx_buffer_pool_request_videosink_buffer_creation (pool, +- dmabuf_fd, plane_buf, vmeta->stride); +- else { +- GstVideoMeta *new_meta; +- +- new_buf = gst_buffer_new (); +- for (i = 0; i < n_planes; i++) +- gst_buffer_append_memory (new_buf, +- gst_dmabuf_allocator_alloc (pool->allocator, dmabuf_fd[i], +- plane_size[i])); +- +- gst_buffer_add_video_meta_full (new_buf, GST_VIDEO_FRAME_FLAG_NONE, +- GST_VIDEO_INFO_FORMAT (&pool->video_info), +- GST_VIDEO_INFO_WIDTH (&pool->video_info), +- GST_VIDEO_INFO_HEIGHT (&pool->video_info), +- GST_VIDEO_INFO_N_PLANES (&pool->video_info), vmeta->offset, +- vmeta->stride); +- +- new_meta = gst_buffer_get_video_meta (new_buf); +- /* To avoid detaching meta data when a buffer returns +- to the buffer pool */ +- GST_META_FLAG_SET (new_meta, GST_META_FLAG_POOLED); +- } +- +- g_ptr_array_remove_index (pool->buffers, pool->current_buffer_index); +- +- gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf), +- gst_omx_buffer_data_quark, NULL, NULL); +- +- gst_buffer_unref (buf); +- +- gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (new_buf), +- gst_omx_buffer_data_quark, omx_buf, NULL); +- +- g_ptr_array_add (pool->buffers, new_buf); +- +- *buffer = new_buf; +- } else +- *buffer = buf; +- } else +-#endif +- *buffer = buf; +- +- vdbuf_data->already_acquired = TRUE; +- +- ret = GST_FLOW_OK; +- } else { +- /* Acquire any buffer that is available to be filled by upstream */ +- ret = +- GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->acquire_buffer +- (bpool, buffer, params); +- } +- +- return ret; +-} +- +-static void +-gst_omx_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) +-{ +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); +- OMX_ERRORTYPE err; +- GstOMXBuffer *omx_buf; +- +- g_assert (pool->component && pool->port); +- +- if (pool->allocating && !pool->deactivated) { +- GstOMXVideoDecBufferData *vdbuf_data; +- +- omx_buf = +- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer), +- gst_omx_buffer_data_quark); +- +- vdbuf_data = (GstOMXVideoDecBufferData *) omx_buf->private_data; +- +- if (pool->port->port_def.eDir == OMX_DirOutput && !omx_buf->used && +- vdbuf_data->already_acquired) { +- /* Release back to the port, can be filled again */ +- err = gst_omx_port_release_buffer (pool->port, omx_buf); +- if (err != OMX_ErrorNone) { +- GST_ELEMENT_ERROR (pool->element, LIBRARY, SETTINGS, (NULL), +- ("Failed to relase output buffer to component: %s (0x%08x)", +- gst_omx_error_to_string (err), err)); +- } +- vdbuf_data->already_acquired = FALSE; +- } else if (pool->port->port_def.eDir == OMX_DirInput && !omx_buf->used) { +- /* TODO: Implement. +- * +- * If not used (i.e. was not passed to the component) this should do +- * the same as EmptyBufferDone. +- * If it is used (i.e. was passed to the component) this should do +- * nothing until EmptyBufferDone. +- * +- * EmptyBufferDone should release the buffer to the pool so it can +- * be allocated again +- * +- * Needs something to call back here in EmptyBufferDone, like keeping +- * a ref on the buffer in GstOMXBuffer until EmptyBufferDone... which +- * would ensure that the buffer is always unused when this is called. +- */ +- g_assert_not_reached (); +- GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer +- (bpool, buffer); +- } +- } +-} +- +-static void +-gst_omx_buffer_pool_finalize (GObject * object) +-{ +- GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (object); +- +- if (pool->element) +- gst_object_unref (pool->element); +- pool->element = NULL; +- +- if (pool->buffers) +- g_ptr_array_unref (pool->buffers); +- pool->buffers = NULL; +- +- if (pool->other_pool) +- gst_object_unref (pool->other_pool); +- pool->other_pool = NULL; +- +- if (pool->allocator) +- gst_object_unref (pool->allocator); +- pool->allocator = NULL; +- +- if (pool->caps) +- gst_caps_unref (pool->caps); +- pool->caps = NULL; +- +- G_OBJECT_CLASS (gst_omx_buffer_pool_parent_class)->finalize (object); +-} +- +-static void +-gst_omx_buffer_pool_class_init (GstOMXBufferPoolClass * klass) +-{ +- GObjectClass *gobject_class = (GObjectClass *) klass; +- GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; +- +- gst_omx_buffer_data_quark = g_quark_from_static_string ("GstOMXBufferData"); +- +- gobject_class->finalize = gst_omx_buffer_pool_finalize; +- gstbufferpool_class->start = gst_omx_buffer_pool_start; +- gstbufferpool_class->stop = gst_omx_buffer_pool_stop; +- gstbufferpool_class->get_options = gst_omx_buffer_pool_get_options; +- gstbufferpool_class->set_config = gst_omx_buffer_pool_set_config; +- gstbufferpool_class->alloc_buffer = gst_omx_buffer_pool_alloc_buffer; +- gstbufferpool_class->free_buffer = gst_omx_buffer_pool_free_buffer; +- gstbufferpool_class->acquire_buffer = gst_omx_buffer_pool_acquire_buffer; +- gstbufferpool_class->release_buffer = gst_omx_buffer_pool_release_buffer; +-} +- +-static void +-gst_omx_buffer_pool_init (GstOMXBufferPool * pool) +-{ +- pool->buffers = g_ptr_array_new (); +-#ifdef HAVE_MMNGRBUF +- pool->allocator = gst_dmabuf_allocator_new (); +-#else +- pool->allocator = g_object_new (gst_omx_memory_allocator_get_type (), NULL); +-#endif +-} +- +-static GstBufferPool * +-gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, +- GstOMXPort * port) +-{ +- GstOMXBufferPool *pool; +- +- pool = g_object_new (gst_omx_buffer_pool_get_type (), NULL); +- pool->element = gst_object_ref (element); +- pool->component = component; +- pool->port = port; +- pool->vsink_buf_req_supported = FALSE; +- +- return GST_BUFFER_POOL (pool); +-} +- + typedef struct _BufferIdentification BufferIdentification; + struct _BufferIdentification + { +@@ -979,8 +88,9 @@ static void gst_omx_video_dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + static void gst_omx_video_dec_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); ++/* + static void GstOMXBufCallbackfunc (struct GstOMXBufferCallback *); +- ++*/ + enum + { + PROP_0, +@@ -999,6 +109,9 @@ enum + G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec, + GST_TYPE_VIDEO_DECODER, DEBUG_INIT); + ++/* Default fps for input files that does not support fps */ ++#define DEFAULT_FRAME_PER_SECOND 30 ++ + static gsize + gst_omx_video_dec_copy_frame (GstOMXVideoDec * self, GstBuffer * inbuf, + guint offset, GstOMXBuffer * outbuf) +@@ -1691,6 +804,7 @@ gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self) + return err; + } + ++/* + static void GstOMXBufCallbackfunc (struct GstOMXBufferCallback *release) + { + if (!release) +@@ -1702,6 +816,7 @@ static void GstOMXBufCallbackfunc (struct GstOMXBufferCallback *release) + + g_free (release); + } ++*/ + + static GstBuffer * + gst_omx_video_dec_create_buffer_from_omx_output (GstOMXVideoDec * self, +@@ -1762,7 +877,7 @@ gst_omx_video_dec_create_buffer_from_omx_output (GstOMXVideoDec * self, + GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, sliceheigh); + used_size = stride[i] * + GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, height); +- ++#if 0 + if (i == 0) { + struct GstOMXBufferCallback *release; + release = g_malloc (sizeof(struct GstOMXBufferCallback)); +@@ -1774,6 +889,7 @@ gst_omx_video_dec_create_buffer_from_omx_output (GstOMXVideoDec * self, + plane_size, 0, used_size, release, GstOMXBufCallbackfunc); + } + else ++#endif + /* Only release OMX buffer one time. Do not add callback + * function to other planes + * (These planes are from same OMX buffer) */ +@@ -2042,15 +1158,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) + + n = port->buffers->len; + for (i = 0; i < n; i++) { +- GstBuffer *outbuf; +- GstOMXBuffer *tmp; +- +- outbuf = +- g_ptr_array_index (GST_OMX_BUFFER_POOL (self-> +- out_port_pool)->buffers, i); +- tmp = +- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (outbuf), +- gst_omx_buffer_data_quark); ++ GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i); + + if (tmp == buf) + break; +@@ -2084,15 +1192,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) + + n = port->buffers->len; + for (i = 0; i < n; i++) { +- GstBuffer *outbuf; +- GstOMXBuffer *tmp; +- +- outbuf = +- g_ptr_array_index (GST_OMX_BUFFER_POOL (self-> +- out_port_pool)->buffers, i); +- tmp = +- gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (outbuf), +- gst_omx_buffer_data_quark); ++ GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i); + + if (tmp == buf) + break; +diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c +index cec44cb..b36c46e 100644 +--- a/omx/gstomxvideoenc.c ++++ b/omx/gstomxvideoenc.c +@@ -28,6 +28,11 @@ + #include <string.h> + + #include "gstomxvideoenc.h" ++#include "gstomxbufferpool.h" ++#ifdef HAVE_MMNGRBUF ++#include "mmngr_buf_user_public.h" ++#endif ++#include "gst/allocators/gstdmabuf.h" + + GST_DEBUG_CATEGORY_STATIC (gst_omx_video_enc_debug_category); + #define GST_CAT_DEFAULT gst_omx_video_enc_debug_category +@@ -68,6 +73,13 @@ buffer_identification_free (BufferIdentification * id) + g_slice_free (BufferIdentification, id); + } + ++/* Used in dmabuf mode */ ++struct _GstOMXVideoEncPrivate ++{ ++ /* Array contain id when using mmngrbuf to import fd */ ++ GArray *id_array; ++}; ++ + /* prototypes */ + static void gst_omx_video_enc_finalize (GObject * object); + static void gst_omx_video_enc_set_property (GObject * object, guint prop_id, +@@ -109,7 +121,8 @@ enum + PROP_TARGET_BITRATE, + PROP_QUANT_I_FRAMES, + PROP_QUANT_P_FRAMES, +- PROP_QUANT_B_FRAMES ++ PROP_QUANT_B_FRAMES, ++ PROP_NO_COPY + }; + + /* FIXME: Better defaults */ +@@ -175,6 +188,11 @@ gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) + 0, G_MAXUINT, GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); ++ g_object_class_install_property (gobject_class, PROP_NO_COPY, ++ g_param_spec_boolean ("no-copy", "Propose buffer to upstream", ++ "Whether or not to use no copy method", ++ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | ++ GST_PARAM_MUTABLE_READY)); + + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state); +@@ -210,7 +228,11 @@ gst_omx_video_enc_init (GstOMXVideoEnc * self) + self->quant_i_frames = GST_OMX_VIDEO_ENC_QUANT_I_FRAMES_DEFAULT; + self->quant_p_frames = GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT; + self->quant_b_frames = GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT; +- ++ self->no_copy = TRUE; ++ self->priv = ++ G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_OMX_VIDEO_ENC, ++ GstOMXVideoEncPrivate); ++ self->priv->id_array = g_array_new (FALSE, FALSE, sizeof (gint)); + g_mutex_init (&self->drain_lock); + g_cond_init (&self->drain_cond); + } +@@ -413,6 +435,16 @@ gst_omx_video_enc_finalize (GObject * object) + g_mutex_clear (&self->drain_lock); + g_cond_clear (&self->drain_cond); + ++#ifdef HAVE_MMNGRBUF ++ if (self->priv->id_array->len > 0) { ++ gint i; ++ for (i = 0; i < self->priv->id_array->len; i++) ++ mmngr_import_end_in_user (g_array_index (self->priv->id_array, gint, ++ i)); ++ } ++#endif; ++ g_array_free (self->priv->id_array, TRUE); ++ + G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object); + } + +@@ -453,6 +485,9 @@ gst_omx_video_enc_set_property (GObject * object, guint prop_id, + case PROP_QUANT_B_FRAMES: + self->quant_b_frames = g_value_get_uint (value); + break; ++ case PROP_NO_COPY: ++ self->no_copy = g_value_get_boolean (value); ++ break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +@@ -481,6 +516,9 @@ gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value, + case PROP_QUANT_B_FRAMES: + g_value_set_uint (value, self->quant_b_frames); + break; ++ case PROP_NO_COPY: ++ g_value_set_boolean (value, self->no_copy); ++ break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +@@ -1125,163 +1163,168 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, + GST_DEBUG_OBJECT (self, "Setting new format %s", + gst_video_format_to_string (info->finfo->format)); + +- gst_omx_port_get_port_definition (self->enc_in_port, &port_def); +- +- needs_disable = +- gst_omx_component_get_state (self->enc, +- GST_CLOCK_TIME_NONE) != OMX_StateLoaded; +- /* If the component is not in Loaded state and a real format change happens +- * we have to disable the port and re-allocate all buffers. If no real +- * format change happened we can just exit here. ++ /* If there is inport pool, it means that OMXBuffer has already allocated on ++ * propose_allocation. Do not allocate OMXBuffer on set_format + */ +- if (needs_disable) { +- GST_DEBUG_OBJECT (self, "Need to disable and drain encoder"); +- gst_omx_video_enc_drain (self, FALSE); +- gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE); +- +- /* Wait until the srcpad loop is finished, +- * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks +- * caused by using this lock from inside the loop function */ +- GST_VIDEO_ENCODER_STREAM_UNLOCK (self); +- gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder)); +- GST_VIDEO_ENCODER_STREAM_LOCK (self); +- +- if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone) +- return FALSE; +- if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone) +- return FALSE; +- if (gst_omx_port_wait_buffers_released (self->enc_in_port, +- 5 * GST_SECOND) != OMX_ErrorNone) +- return FALSE; +- if (gst_omx_port_wait_buffers_released (self->enc_out_port, +- 1 * GST_SECOND) != OMX_ErrorNone) +- return FALSE; +- if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone) +- return FALSE; +- if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone) +- return FALSE; +- if (gst_omx_port_wait_enabled (self->enc_in_port, +- 1 * GST_SECOND) != OMX_ErrorNone) +- return FALSE; +- if (gst_omx_port_wait_enabled (self->enc_out_port, +- 1 * GST_SECOND) != OMX_ErrorNone) +- return FALSE; +- +- GST_DEBUG_OBJECT (self, "Encoder drained and disabled"); +- } ++ if (!self->in_port_pool) { ++ gst_omx_port_get_port_definition (self->enc_in_port, &port_def); ++ ++ needs_disable = ++ gst_omx_component_get_state (self->enc, ++ GST_CLOCK_TIME_NONE) != OMX_StateLoaded; ++ /* If the component is not in Loaded state and a real format change happens ++ * we have to disable the port and re-allocate all buffers. If no real ++ * format change happened we can just exit here. ++ */ ++ if (needs_disable) { ++ GST_DEBUG_OBJECT (self, "Need to disable and drain encoder"); ++ gst_omx_video_enc_drain (self, FALSE); ++ gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE); ++ ++ /* Wait until the srcpad loop is finished, ++ * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks ++ * caused by using this lock from inside the loop function */ ++ GST_VIDEO_ENCODER_STREAM_UNLOCK (self); ++ gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder)); ++ GST_VIDEO_ENCODER_STREAM_LOCK (self); + +- negotiation_map = gst_omx_video_enc_get_supported_colorformats (self); +- if (!negotiation_map) { +- /* Fallback */ +- switch (info->finfo->format) { +- case GST_VIDEO_FORMAT_I420: +- port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; +- break; +- case GST_VIDEO_FORMAT_NV16: +- case GST_VIDEO_FORMAT_NV12: +- port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; +- break; +- default: +- GST_ERROR_OBJECT (self, "Unsupported format %s", +- gst_video_format_to_string (info->finfo->format)); ++ if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone) + return FALSE; +- break; ++ if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone) ++ return FALSE; ++ if (gst_omx_port_wait_buffers_released (self->enc_in_port, ++ 5 * GST_SECOND) != OMX_ErrorNone) ++ return FALSE; ++ if (gst_omx_port_wait_buffers_released (self->enc_out_port, ++ 1 * GST_SECOND) != OMX_ErrorNone) ++ return FALSE; ++ if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone) ++ return FALSE; ++ if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone) ++ return FALSE; ++ if (gst_omx_port_wait_enabled (self->enc_in_port, ++ 1 * GST_SECOND) != OMX_ErrorNone) ++ return FALSE; ++ if (gst_omx_port_wait_enabled (self->enc_out_port, ++ 1 * GST_SECOND) != OMX_ErrorNone) ++ return FALSE; ++ ++ GST_DEBUG_OBJECT (self, "Encoder drained and disabled"); + } +- } else { +- for (l = negotiation_map; l; l = l->next) { +- VideoNegotiationMap *m = l->data; + +- if (m->format == info->finfo->format) { +- port_def.format.video.eColorFormat = m->type; +- break; ++ negotiation_map = gst_omx_video_enc_get_supported_colorformats (self); ++ if (!negotiation_map) { ++ /* Fallback */ ++ switch (info->finfo->format) { ++ case GST_VIDEO_FORMAT_I420: ++ port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; ++ break; ++ case GST_VIDEO_FORMAT_NV16: ++ case GST_VIDEO_FORMAT_NV12: ++ port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; ++ break; ++ default: ++ GST_ERROR_OBJECT (self, "Unsupported format %s", ++ gst_video_format_to_string (info->finfo->format)); ++ return FALSE; ++ break; ++ } ++ } else { ++ for (l = negotiation_map; l; l = l->next) { ++ VideoNegotiationMap *m = l->data; ++ ++ if (m->format == info->finfo->format) { ++ port_def.format.video.eColorFormat = m->type; ++ break; ++ } + } ++ g_list_free_full (negotiation_map, ++ (GDestroyNotify) video_negotiation_map_free); + } +- g_list_free_full (negotiation_map, +- (GDestroyNotify) video_negotiation_map_free); +- } + +- port_def.format.video.nFrameWidth = info->width; +- if (port_def.nBufferAlignment) +- port_def.format.video.nStride = +- (info->width + port_def.nBufferAlignment - 1) & +- (~(port_def.nBufferAlignment - 1)); +- else +- { +- if (klass->cdata.hacks & GST_OMX_HACK_RENESAS_ENCMC_STRIDE_ALIGN) ++ port_def.format.video.nFrameWidth = info->width; ++ if (port_def.nBufferAlignment) ++ port_def.format.video.nStride = ++ (info->width + port_def.nBufferAlignment - 1) & ++ (~(port_def.nBufferAlignment - 1)); ++ else + { +- switch (port_def.format.video.eColorFormat) { +- case OMX_COLOR_FormatYUV420Planar: { +- /*Renesas encode MC only support following strides*/ +- if (info->width <= 256) +- port_def.format.video.nStride = 256; +- else if ((info->width > 256) && (info->width <= 512)) +- port_def.format.video.nStride = 512; +- else if ((info->width > 512) && (info->width <= 1024)) +- port_def.format.video.nStride = 1024; +- else +- port_def.format.video.nStride = 2048; ++ if (klass->cdata.hacks & GST_OMX_HACK_RENESAS_ENCMC_STRIDE_ALIGN) ++ { ++ switch (port_def.format.video.eColorFormat) { ++ case OMX_COLOR_FormatYUV420Planar: { ++ /*Renesas encode MC only support following strides*/ ++ if (info->width <= 256) ++ port_def.format.video.nStride = 256; ++ else if ((info->width > 256) && (info->width <= 512)) ++ port_def.format.video.nStride = 512; ++ else if ((info->width > 512) && (info->width <= 1024)) ++ port_def.format.video.nStride = 1024; ++ else ++ port_def.format.video.nStride = 2048; ++ break; ++ } ++ case OMX_COLOR_FormatYUV420SemiPlanar: ++ port_def.format.video.nStride = ((info->width + 127) & ~ 127); /* Align 128 */ + break; +- } +- case OMX_COLOR_FormatYUV420SemiPlanar: +- port_def.format.video.nStride = ((info->width + 127) & ~ 127); /* Align 128 */ +- break; +- default: ++ default: ++ port_def.format.video.nStride = GST_ROUND_UP_4 (info->width); /* Safe (?) default */ ++ break; ++ } ++ } else { + port_def.format.video.nStride = GST_ROUND_UP_4 (info->width); /* Safe (?) default */ +- break; + } +- } else { +- port_def.format.video.nStride = GST_ROUND_UP_4 (info->width); /* Safe (?) default */ + } +- } + +- port_def.format.video.nFrameHeight = info->height; +- port_def.format.video.nSliceHeight = info->height; ++ port_def.format.video.nFrameHeight = info->height; ++ port_def.format.video.nSliceHeight = info->height; + +- switch (port_def.format.video.eColorFormat) { +- case OMX_COLOR_FormatYUV420Planar: +- case OMX_COLOR_FormatYUV420PackedPlanar: +- port_def.nBufferSize = +- (port_def.format.video.nStride * port_def.format.video.nFrameHeight) + +- 2 * ((port_def.format.video.nStride / 2) * +- ((port_def.format.video.nFrameHeight + 1) / 2)); +- break; +- +- case OMX_COLOR_FormatYUV420SemiPlanar: +- port_def.nBufferSize = +- (port_def.format.video.nStride * port_def.format.video.nFrameHeight) + +- (port_def.format.video.nStride * +- ((port_def.format.video.nFrameHeight + 1) / 2)); +- break; ++ switch (port_def.format.video.eColorFormat) { ++ case OMX_COLOR_FormatYUV420Planar: ++ case OMX_COLOR_FormatYUV420PackedPlanar: ++ port_def.nBufferSize = ++ (port_def.format.video.nStride * port_def.format.video.nFrameHeight) + ++ 2 * ((port_def.format.video.nStride / 2) * ++ ((port_def.format.video.nFrameHeight + 1) / 2)); ++ break; + +- default: +- g_assert_not_reached (); +- } ++ case OMX_COLOR_FormatYUV420SemiPlanar: ++ port_def.nBufferSize = ++ (port_def.format.video.nStride * port_def.format.video.nFrameHeight) + ++ (port_def.format.video.nStride * ++ ((port_def.format.video.nFrameHeight + 1) / 2)); ++ break; + +- if (info->fps_n == 0) { +- port_def.format.video.xFramerate = 0; +- } else { +- if (!(klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER)) +- port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d); +- else +- port_def.format.video.xFramerate = (info->fps_n) / (info->fps_d); +- } ++ default: ++ g_assert_not_reached (); ++ } + +- GST_DEBUG_OBJECT (self, "Setting inport port definition"); +- if (gst_omx_port_update_port_definition (self->enc_in_port, +- &port_def) != OMX_ErrorNone) +- return FALSE; ++ if (info->fps_n == 0) { ++ port_def.format.video.xFramerate = 0; ++ } else { ++ if (!(klass->cdata.hacks & GST_OMX_HACK_VIDEO_FRAMERATE_INTEGER)) ++ port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d); ++ else ++ port_def.format.video.xFramerate = (info->fps_n) / (info->fps_d); ++ } + +- if (klass->set_format) { +- if (!klass->set_format (self, self->enc_in_port, state)) { +- GST_ERROR_OBJECT (self, "Subclass failed to set the new format"); ++ GST_DEBUG_OBJECT (self, "Setting inport port definition"); ++ if (gst_omx_port_update_port_definition (self->enc_in_port, ++ &port_def) != OMX_ErrorNone) + return FALSE; ++ ++ if (klass->set_format) { ++ if (!klass->set_format (self, self->enc_in_port, state)) { ++ GST_ERROR_OBJECT (self, "Subclass failed to set the new format"); ++ return FALSE; ++ } + } +- } + +- GST_DEBUG_OBJECT (self, "Updating outport port definition"); +- if (gst_omx_port_update_port_definition (self->enc_out_port, +- NULL) != OMX_ErrorNone) +- return FALSE; ++ GST_DEBUG_OBJECT (self, "Updating outport port definition"); ++ if (gst_omx_port_update_port_definition (self->enc_out_port, ++ NULL) != OMX_ErrorNone) ++ return FALSE; ++ } + + GST_DEBUG_OBJECT (self, "Enabling component"); + if (needs_disable) { +@@ -1299,11 +1342,13 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, + return FALSE; + + /* Need to allocate buffers to reach Idle state */ +- if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) +- return FALSE; ++ if (!self->in_port_pool) { ++ if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) ++ return FALSE; ++ } + + /* Allocate for output port */ +- if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone) ++ if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone) + return FALSE; + if (gst_omx_component_get_state (self->enc, + GST_CLOCK_TIME_NONE) != OMX_StateIdle) +@@ -1349,7 +1394,9 @@ gst_omx_video_enc_reset (GstVideoEncoder * encoder, gboolean hard) + + self = GST_OMX_VIDEO_ENC (encoder); + +- GST_DEBUG_OBJECT (self, "Resetting encoder"); ++ GST_DEBUG_OBJECT (self, "Resetting encoder %s", hard ? "(hard)" : ""); ++ ++ return TRUE; + + gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE); + gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE); +@@ -1739,11 +1786,50 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder, + gst_omx_error_to_string (err), err); + } + +- /* Copy the buffer content in chunks of size as requested +- * by the port */ +- if (!gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) { +- gst_omx_port_release_buffer (port, buf); +- goto buffer_fill_error; ++ if (self->in_port_pool) { ++ GstMapInfo in_info; ++ gint count = 0; ++ GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (self->in_port_pool); ++ ++ /* Compare input buffer with buffer got from port to get target data for ++ * encoder ++ */ ++ if (!pool->deactivated) { ++ if (!gst_buffer_map (frame->input_buffer, &in_info, GST_MAP_READ)) { ++ GST_ERROR_OBJECT (self, "Can not map input buffer"); ++ gst_omx_port_release_buffer (port, buf); ++ goto flow_error; ++ } ++ ++ if (buf->omx_buf->pBuffer != in_info.data) { ++ gst_omx_port_release_buffer (port, buf); ++ do { ++ acq_ret = gst_omx_port_acquire_buffer (port, &buf); ++ if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) { ++ GST_ERROR_OBJECT (self, "Can acquire buffer from input port"); ++ return GST_FLOW_ERROR; ++ } ++ if (buf->omx_buf->pBuffer != in_info.data) ++ gst_omx_port_release_buffer (port, buf); ++ count += 1; ++ } while (buf->omx_buf->pBuffer != in_info.data ++ && count < port->port_def.nBufferCountActual * 3); ++ } ++ if (count == port->port_def.nBufferCountActual * 3) { ++ GST_ERROR_OBJECT (self, ++ "Can not get target OMXBuffer after 3 times searching"); ++ goto flow_error; ++ } ++ buf->omx_buf->nFilledLen = in_info.size; ++ gst_buffer_unmap (frame->input_buffer, &in_info); ++ } ++ } else { ++ /* Copy the buffer content in chunks of size as requested ++ * by the port */ ++ if (!gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) { ++ gst_omx_port_release_buffer (port, buf); ++ goto buffer_fill_error; ++ } + } + + timestamp = frame->pts; +@@ -1920,11 +2006,203 @@ static gboolean + gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder, + GstQuery * query) + { +- gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); ++ GstOMXVideoEnc *self; ++ GstOMXVideoEncClass *klass; ++ ++ self = GST_OMX_VIDEO_ENC (encoder); ++ klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder); ++ ++ GST_DEBUG_OBJECT (self, "gst_omx_video_enc_propose_allocation"); ++ if (self->no_copy == TRUE) { ++ /* Allocate buffers and propose them to upstream */ ++ GstCaps *caps; ++ GstVideoInfo info; ++ guint size; ++ OMX_PARAM_PORTDEFINITIONTYPE port_def; ++ guint max, min; ++ ++ gst_omx_port_get_port_definition (self->enc_in_port, &port_def); ++ ++ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); ++ ++ gst_query_parse_allocation (query, &caps, NULL); ++ ++ if (caps == NULL) ++ return FALSE; ++ ++ if (!gst_video_info_from_caps (&info, caps)) ++ return FALSE; ++ ++ size = GST_VIDEO_INFO_SIZE (&info); ++ ++ if (gst_omx_component_get_state (self->enc, ++ GST_CLOCK_TIME_NONE) != OMX_StateLoaded) ++ return FALSE; ++ switch (info.finfo->format) { ++ case GST_VIDEO_FORMAT_I420: ++ port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; ++ break; ++ case GST_VIDEO_FORMAT_NV12: ++ case GST_VIDEO_FORMAT_NV16: ++ port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; ++ break; ++ default: ++ GST_ERROR_OBJECT (self, "Unsupported format %s", ++ gst_video_format_to_string (info.finfo->format)); ++ return FALSE; ++ break; ++ } ++ port_def.format.video.nFrameWidth = info.width; ++ if (klass->cdata.hacks & GST_OMX_HACK_RENESAS_ENCMC_STRIDE_ALIGN) { ++ switch (port_def.format.video.eColorFormat) { ++ case OMX_COLOR_FormatYUV420Planar: ++ port_def.format.video.nStride = GST_ROUND_UP_64 (info.width); ++ break; ++ case OMX_COLOR_FormatYUV420SemiPlanar: ++ port_def.format.video.nStride = GST_ROUND_UP_32 (info.width); ++ break; ++ default: ++ break; ++ } ++ } else ++ port_def.format.video.nStride = GST_ROUND_UP_4 (info.width); /* safe (?) default */ ++ port_def.format.video.nFrameHeight = info.height; ++ port_def.format.video.nSliceHeight = info.height; ++ switch (port_def.format.video.eColorFormat) { ++ case OMX_COLOR_FormatYUV420Planar: ++ case OMX_COLOR_FormatYUV420PackedPlanar: ++ port_def.nBufferSize = ++ (port_def.format.video.nStride * ++ port_def.format.video.nFrameHeight) + ++ 2 * ((port_def.format.video.nStride / 2) * ++ ((port_def.format.video.nFrameHeight + 1) / 2)); ++ break; ++ ++ case OMX_COLOR_FormatYUV420SemiPlanar: ++ port_def.nBufferSize = ++ (port_def.format.video.nStride * ++ port_def.format.video.nFrameHeight) + ++ (port_def.format.video.nStride * ++ ((port_def.format.video.nFrameHeight + 1) / 2)); ++ break; + +- return +- GST_VIDEO_ENCODER_CLASS +- (gst_omx_video_enc_parent_class)->propose_allocation (encoder, query); ++ default: ++ g_assert_not_reached (); ++ } ++ if (info.fps_n == 0) { ++ port_def.format.video.xFramerate = 0; ++ } else { ++ port_def.format.video.xFramerate = (info.fps_n) / (info.fps_d); ++ } ++ ++ if (gst_omx_port_update_port_definition (self->enc_in_port, ++ &port_def) != OMX_ErrorNone) ++ return FALSE; ++ ++ if (klass->set_format) { ++ if (!klass->set_format (self, self->enc_in_port, self->input_state)) { ++ GST_ERROR_OBJECT (self, "Subclass failed to set the new format"); ++ return FALSE; ++ } ++ } ++ GST_DEBUG_OBJECT (self, "Updating outport port definition"); ++ if (gst_omx_port_update_port_definition (self->enc_out_port, ++ NULL) != OMX_ErrorNone) ++ return FALSE; ++ ++ if (self->target_bitrate != 0xffffffff) { ++ OMX_VIDEO_PARAM_BITRATETYPE config; ++ OMX_ERRORTYPE err; ++ ++ GST_OMX_INIT_STRUCT (&config); ++ config.nPortIndex = self->enc_out_port->index; ++ /* Get default value of eControlRate to avoid setting an invalid value to it */ ++ err = gst_omx_component_get_parameter (self->enc, ++ OMX_IndexParamVideoBitrate, &config); ++ if (err != OMX_ErrorNone) ++ GST_ERROR_OBJECT (self, ++ "Fail to get parameter of video bitrate: %s (0x%08x)", ++ gst_omx_error_to_string (err), err); ++ ++ config.nTargetBitrate = self->target_bitrate; ++ if (self->control_rate != 0xffffffff) ++ config.eControlRate = self->control_rate; ++ ++ err = gst_omx_component_set_parameter (self->enc, ++ OMX_IndexParamVideoBitrate, &config); ++ if (err != OMX_ErrorNone) ++ GST_ERROR_OBJECT (self, "Failed to set bitrate parameter: %s (0x%08x)", ++ gst_omx_error_to_string (err), err); ++ } ++ ++ if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone) ++ return FALSE; ++ ++ if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) ++ return FALSE; ++ ++ if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone) ++ return FALSE; ++ ++ GST_DEBUG_OBJECT (self, " gst_query_get_n_allocation_pools = %d", ++ gst_query_get_n_allocation_pools (query)); ++ if (gst_query_get_n_allocation_pools (query) == 0) { ++ GstStructure *structure; ++ GstAllocator *allocator = NULL; ++ GstAllocationParams params = { 0, }; ++ ++ if (gst_query_get_n_allocation_params (query) > 0) ++ gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶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 + |