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