omxvideodec: add dmabuf support for output

The zynqultrascaleplus OMX implementation has a custom extension
allowing decoders to output dmabuf and so avoid buffers copy between OMX
and GStreamer.

Make use of this extension when built on the zynqultrascaleplus. The
buffer pool code should be re-usable for other platforms as well.

https://bugzilla.gnome.org/show_bug.cgi?id=784847
This commit is contained in:
Guillaume Desmottes 2017-07-04 12:16:39 +02:00 committed by Julien Isorce
parent a9a3087021
commit 136714c6ed
8 changed files with 111 additions and 11 deletions

View file

@ -155,6 +155,7 @@ PKG_CHECK_MODULES([GST_GL], [gstreamer-gl-1.0 >= $GST_REQ], [
GST_GL=yes
], [GST_GL=no])
AM_CONDITIONAL(HAVE_GST_GL, test "x$GST_GL" = "xyes")
PKG_CHECK_MODULES([GST_ALLOCATORS], [gstreamer-allocators-1.0])
dnl Check for documentation xrefs
GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`"

View file

@ -136,6 +136,8 @@ gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req,
fallback : ['gstreamer', 'gst_base_dep'])
gstcontroller_dep = dependency('gstreamer-controller-1.0', version : gst_req,
fallback : ['gstreamer', 'gst_controller_dep'])
gstallocators_dep = dependency('gstreamer-allocators-1.0', version : gst_req,
fallback : ['gst-plugins-base', 'allocators_dep'])
gstpbutils_dep = dependency('gstreamer-pbutils-1.0', version : gst_req,
fallback : ['gst-plugins-base', 'pbutils_dep'])

View file

@ -79,6 +79,7 @@ libgstomx_la_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS) \
$(GST_ALLOCATORS_CFLAGS) \
$(GMODULE_NO_EXPORT_CFLAGS)
libgstomx_la_LIBADD = \
$(GST_GL_LIBS) \
@ -88,6 +89,7 @@ libgstomx_la_LIBADD = \
-lgstvideo-@GST_API_VERSION@ \
$(GST_BASE_LIBS) \
$(GST_LIBS) \
$(GST_ALLOCATORS_LIBS) \
$(GMODULE_NO_EXPORT_LIBS)
libgstomx_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)

View file

@ -26,6 +26,8 @@
#include "gstomxbufferpool.h"
#include <gst/allocators/gstdmabuf.h>
GST_DEBUG_CATEGORY_STATIC (gst_omx_buffer_pool_debug_category);
#define GST_CAT_DEFAULT gst_omx_buffer_pool_debug_category
@ -389,7 +391,32 @@ gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool,
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
mem = gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf);
if (pool->output_mode == GST_OMX_BUFFER_MODE_DMABUF) {
gint fd;
GstMapInfo map;
fd = GPOINTER_TO_INT (omx_buf->omx_buf->pBuffer);
mem =
gst_dmabuf_allocator_alloc (pool->allocator, fd,
omx_buf->omx_buf->nAllocLen);
if (!gst_caps_features_contains (gst_caps_get_features (pool->caps, 0),
GST_CAPS_FEATURE_MEMORY_DMABUF)) {
/* Check if the memory is actually mappable */
if (!gst_memory_map (mem, &map, GST_MAP_READWRITE)) {
GST_ERROR_OBJECT (pool,
"dmabuf memory is not mappable but caps does not have the 'memory:DMABuf' feature");
gst_memory_unref (mem);
return GST_FLOW_ERROR;
}
gst_memory_unmap (mem, &map);
}
} 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);
@ -505,11 +532,22 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
/* If it's our own memory we have to set the sizes */
if (!pool->other_pool) {
GstMemory *mem = gst_buffer_peek_memory (*buffer, 0);
GstOMXBuffer *omx_buf;
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;
if (pool->output_mode == GST_OMX_BUFFER_MODE_DMABUF) {
omx_buf =
gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf),
gst_omx_buffer_data_quark);
} else {
g_assert (mem
&& g_strcmp0 (mem->allocator->mem_type, GST_OMX_MEMORY_TYPE) == 0);
/* We already have a pointer to the GstOMXBuffer, no need to retrieve it
* from the qdata */
omx_buf = ((GstOMXMemory *) mem)->buf;
}
mem->size = omx_buf->omx_buf->nFilledLen;
mem->offset = omx_buf->omx_buf->nOffset;
}
} else {
/* Acquire any buffer that is available to be filled by upstream */
@ -615,12 +653,11 @@ 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);
}
GstBufferPool *
gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component,
GstOMXPort * port)
GstOMXPort * port, GstOMXBufferMode output_mode)
{
GstOMXBufferPool *pool;
@ -628,6 +665,19 @@ gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component,
pool->element = gst_object_ref (element);
pool->component = component;
pool->port = port;
pool->output_mode = output_mode;
switch (output_mode) {
case GST_OMX_BUFFER_MODE_DMABUF:
pool->allocator = gst_dmabuf_allocator_new ();
break;
case GST_OMX_BUFFER_MODE_SYSTEM_MEMORY:
pool->allocator =
g_object_new (gst_omx_memory_allocator_get_type (), NULL);
break;
default:
g_assert_not_reached ();
}
return GST_BUFFER_POOL (pool);
}

View file

@ -43,6 +43,11 @@ G_BEGIN_DECLS
typedef struct _GstOMXBufferPool GstOMXBufferPool;
typedef struct _GstOMXBufferPoolClass GstOMXBufferPoolClass;
typedef enum {
GST_OMX_BUFFER_MODE_SYSTEM_MEMORY,
GST_OMX_BUFFER_MODE_DMABUF,
} GstOMXBufferMode;
struct _GstOMXBufferPool
{
GstVideoBufferPool parent;
@ -78,6 +83,9 @@ struct _GstOMXBufferPool
* wrapped
*/
gint current_buffer_index;
/* The type of buffers produced by the decoder */
GstOMXBufferMode output_mode;
};
struct _GstOMXBufferPoolClass
@ -87,7 +95,7 @@ struct _GstOMXBufferPoolClass
GType gst_omx_buffer_pool_get_type (void);
GstBufferPool *gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, GstOMXPort * port);
GstBufferPool *gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, GstOMXPort * port, GstOMXBufferMode output_mode);
G_END_DECLS

View file

@ -25,6 +25,7 @@
#endif
#include <gst/gst.h>
#include <gst/allocators/gstdmabuf.h>
#if defined (USE_OMX_TARGET_RPI) && defined(__GNUC__)
#ifndef __VCCOREVER__
@ -137,6 +138,8 @@ gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass)
static void
gst_omx_video_dec_init (GstOMXVideoDec * self)
{
self->dmabuf = FALSE;
gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
(self), TRUE);
@ -196,6 +199,29 @@ gst_omx_video_dec_open (GstVideoDecoder * decoder)
self->dec_in_port = gst_omx_component_add_port (self->dec, in_port_index);
self->dec_out_port = gst_omx_component_add_port (self->dec, out_port_index);
#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
{
/* Configure OMX decoder to produce dmabuf */
OMX_ALG_PORT_PARAM_BUFFER_MODE buffer_mode;
OMX_ERRORTYPE err;
GST_OMX_INIT_STRUCT (&buffer_mode);
buffer_mode.nPortIndex = self->dec_out_port->index;
buffer_mode.eMode = OMX_ALG_BUF_DMA;
GST_DEBUG_OBJECT (self, "Configure decoder to produce dmabuf");
err =
gst_omx_component_set_parameter (self->dec,
(OMX_INDEXTYPE) OMX_ALG_IndexPortParamBufferMode, &buffer_mode);
if (err != OMX_ErrorNone)
GST_WARNING_OBJECT (self, "Failed to set output buffer mode: %s (0x%08x)",
gst_omx_error_to_string (err), err);
else
self->dmabuf = TRUE;
}
#endif
if (!self->dec_in_port || !self->dec_out_port)
return FALSE;
@ -624,8 +650,8 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
if (caps)
self->out_port_pool =
gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->dec, port);
gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->dec, port,
self->dmabuf);
#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
if (eglimage) {
GList *buffers = NULL;
@ -1942,6 +1968,14 @@ gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, state->caps);
if (!self->dmabuf
&& gst_caps_features_contains (gst_caps_get_features (state->caps, 0),
GST_CAPS_FEATURE_MEMORY_DMABUF)) {
GST_WARNING_OBJECT (self,
"caps has the 'memory:DMABuf' feature but decoder cannot produce dmabuf");
return FALSE;
}
gst_omx_port_get_port_definition (self->dec_in_port, &port_def);
/* Check if the caps change is a real format change or if only irrelevant

View file

@ -85,6 +85,9 @@ struct _GstOMXVideoDec
GstOMXPort *egl_in_port, *egl_out_port;
gboolean eglimage;
#endif
/* TRUE if decoder is producing dmabuf */
gboolean dmabuf;
};
struct _GstOMXVideoDecClass

View file

@ -53,7 +53,7 @@ gstomx = library('gstomx',
# link_args : noseh_link_args,
include_directories : [configinc] + extra_inc,
dependencies : [gstvideo_dep, gstaudio_dep, gstbase_dep, gstcontroller_dep,
libm, gmodule_dep] + optional_deps,
libm, gmodule_dep, gstallocators_dep] + optional_deps,
install : true,
install_dir : plugins_install_dir,
)