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=yes
], [GST_GL=no]) ], [GST_GL=no])
AM_CONDITIONAL(HAVE_GST_GL, test "x$GST_GL" = "xyes") AM_CONDITIONAL(HAVE_GST_GL, test "x$GST_GL" = "xyes")
PKG_CHECK_MODULES([GST_ALLOCATORS], [gstreamer-allocators-1.0])
dnl Check for documentation xrefs dnl Check for documentation xrefs
GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" 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']) fallback : ['gstreamer', 'gst_base_dep'])
gstcontroller_dep = dependency('gstreamer-controller-1.0', version : gst_req, gstcontroller_dep = dependency('gstreamer-controller-1.0', version : gst_req,
fallback : ['gstreamer', 'gst_controller_dep']) 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, gstpbutils_dep = dependency('gstreamer-pbutils-1.0', version : gst_req,
fallback : ['gst-plugins-base', 'pbutils_dep']) fallback : ['gst-plugins-base', 'pbutils_dep'])

View file

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

View file

@ -26,6 +26,8 @@
#include "gstomxbufferpool.h" #include "gstomxbufferpool.h"
#include <gst/allocators/gstdmabuf.h>
GST_DEBUG_CATEGORY_STATIC (gst_omx_buffer_pool_debug_category); GST_DEBUG_CATEGORY_STATIC (gst_omx_buffer_pool_debug_category);
#define GST_CAT_DEFAULT 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, }; gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, }; gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
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); mem = gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf);
}
buf = gst_buffer_new (); buf = gst_buffer_new ();
gst_buffer_append_memory (buf, mem); gst_buffer_append_memory (buf, mem);
g_ptr_array_add (pool->buffers, buf); 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 it's our own memory we have to set the sizes */
if (!pool->other_pool) { if (!pool->other_pool) {
GstMemory *mem = gst_buffer_peek_memory (*buffer, 0); GstMemory *mem = gst_buffer_peek_memory (*buffer, 0);
GstOMXBuffer *omx_buf;
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_assert (mem
&& g_strcmp0 (mem->allocator->mem_type, GST_OMX_MEMORY_TYPE) == 0); && g_strcmp0 (mem->allocator->mem_type, GST_OMX_MEMORY_TYPE) == 0);
mem->size = ((GstOMXMemory *) mem)->buf->omx_buf->nFilledLen; /* We already have a pointer to the GstOMXBuffer, no need to retrieve it
mem->offset = ((GstOMXMemory *) mem)->buf->omx_buf->nOffset; * from the qdata */
omx_buf = ((GstOMXMemory *) mem)->buf;
}
mem->size = omx_buf->omx_buf->nFilledLen;
mem->offset = omx_buf->omx_buf->nOffset;
} }
} else { } else {
/* Acquire any buffer that is available to be filled by upstream */ /* Acquire any buffer that is available to be filled by upstream */
@ -615,12 +653,11 @@ static void
gst_omx_buffer_pool_init (GstOMXBufferPool * pool) gst_omx_buffer_pool_init (GstOMXBufferPool * pool)
{ {
pool->buffers = g_ptr_array_new (); pool->buffers = g_ptr_array_new ();
pool->allocator = g_object_new (gst_omx_memory_allocator_get_type (), NULL);
} }
GstBufferPool * GstBufferPool *
gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component,
GstOMXPort * port) GstOMXPort * port, GstOMXBufferMode output_mode)
{ {
GstOMXBufferPool *pool; GstOMXBufferPool *pool;
@ -628,6 +665,19 @@ gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component,
pool->element = gst_object_ref (element); pool->element = gst_object_ref (element);
pool->component = component; pool->component = component;
pool->port = port; 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); return GST_BUFFER_POOL (pool);
} }

View file

@ -43,6 +43,11 @@ G_BEGIN_DECLS
typedef struct _GstOMXBufferPool GstOMXBufferPool; typedef struct _GstOMXBufferPool GstOMXBufferPool;
typedef struct _GstOMXBufferPoolClass GstOMXBufferPoolClass; typedef struct _GstOMXBufferPoolClass GstOMXBufferPoolClass;
typedef enum {
GST_OMX_BUFFER_MODE_SYSTEM_MEMORY,
GST_OMX_BUFFER_MODE_DMABUF,
} GstOMXBufferMode;
struct _GstOMXBufferPool struct _GstOMXBufferPool
{ {
GstVideoBufferPool parent; GstVideoBufferPool parent;
@ -78,6 +83,9 @@ struct _GstOMXBufferPool
* wrapped * wrapped
*/ */
gint current_buffer_index; gint current_buffer_index;
/* The type of buffers produced by the decoder */
GstOMXBufferMode output_mode;
}; };
struct _GstOMXBufferPoolClass struct _GstOMXBufferPoolClass
@ -87,7 +95,7 @@ struct _GstOMXBufferPoolClass
GType gst_omx_buffer_pool_get_type (void); 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 G_END_DECLS

View file

@ -25,6 +25,7 @@
#endif #endif
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/allocators/gstdmabuf.h>
#if defined (USE_OMX_TARGET_RPI) && defined(__GNUC__) #if defined (USE_OMX_TARGET_RPI) && defined(__GNUC__)
#ifndef __VCCOREVER__ #ifndef __VCCOREVER__
@ -137,6 +138,8 @@ gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass)
static void static void
gst_omx_video_dec_init (GstOMXVideoDec * self) gst_omx_video_dec_init (GstOMXVideoDec * self)
{ {
self->dmabuf = FALSE;
gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE); gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
(self), TRUE); (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_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); 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) if (!self->dec_in_port || !self->dec_out_port)
return FALSE; return FALSE;
@ -624,8 +650,8 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
if (caps) if (caps)
self->out_port_pool = 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 defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
if (eglimage) { if (eglimage) {
GList *buffers = NULL; 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); 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); 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 /* 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; GstOMXPort *egl_in_port, *egl_out_port;
gboolean eglimage; gboolean eglimage;
#endif #endif
/* TRUE if decoder is producing dmabuf */
gboolean dmabuf;
}; };
struct _GstOMXVideoDecClass struct _GstOMXVideoDecClass

View file

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