omxvideodec: use OMX_UseBuffer

For example this allows the omx decoder to directly fill the
pixmaps coming from the video sink.

It only avoids a buffer copy when the decoder uses a pool provided
by a downstream element. So let's restrict this usage to situations
where the decoder decides to use a downstream buffer pool.

Tested with Tizonia/OMX.Aratelia.video_decoder.vp8
and with Bellagio/OMX.mesa.video_decoder.avc.

If it fails to setup buffers with OMX_UseBuffer the decoders
fallbacks to usual OMX_AllocateBuffer.

Also it allows to test on desktop the GstOMXBufferPool->other_pool
management which was previously only used in the OMX_UseEGLImage
case, i.e. on Rpi.

https://bugzilla.gnome.org/show_bug.cgi?id=784069
This commit is contained in:
Julien Isorce 2017-06-29 22:48:47 +01:00
parent e60ac7e1c0
commit 80c6dd46a1
2 changed files with 106 additions and 1 deletions

View file

@ -358,6 +358,7 @@ gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition)
self->downstream_flow_ret = GST_FLOW_OK;
self->draining = FALSE;
self->started = FALSE;
self->use_buffers = FALSE;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
@ -757,6 +758,8 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
/* If not using EGLImage or trying to use EGLImage failed */
if (!eglimage) {
gboolean was_enabled = TRUE;
GList *buffers = NULL;
GList *l = NULL;
if (min != port->port_def.nBufferCountActual) {
err = gst_omx_port_update_port_definition (port, NULL);
@ -784,7 +787,86 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
was_enabled = FALSE;
}
err = gst_omx_port_allocate_buffers (port);
if (self->use_buffers) {
GList *images = NULL;
GList *frames = NULL;
GstVideoInfo v_info;
gint i;
GstBufferPoolAcquireParams params = { 0, };
if (!gst_video_info_from_caps (&v_info, caps)) {
GST_INFO_OBJECT (self,
"Failed to get video info from caps %" GST_PTR_FORMAT, caps);
err = OMX_ErrorUndefined;
self->use_buffers = FALSE;
}
GST_DEBUG_OBJECT (self, "Trying to use %d buffers", min);
for (i = 0; i < min && self->use_buffers; i++) {
GstBuffer *buffer = NULL;
GstMemory *mem = NULL;
GstVideoFrame *frame = g_slice_new0 (GstVideoFrame);
GstMapFlags flags = GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF;
gboolean is_mapped = FALSE;
if (gst_buffer_pool_acquire_buffer (pool, &buffer,
&params) != GST_FLOW_OK || gst_buffer_n_memory (buffer) != 1
|| !(mem = gst_buffer_peek_memory (buffer, 0))
|| !(is_mapped =
gst_video_frame_map (frame, &v_info, buffer, flags))
|| GST_VIDEO_FRAME_SIZE (frame) < port->port_def.nBufferSize) {
/* buffer does not match minimal requirement to try OMX_UseBuffer */
GST_INFO_OBJECT (self,
"Failed to allocated %d-th buffer of type %s, n_mem: %d, "
"is mapped: %d, frame size: %" G_GSIZE_FORMAT, i,
mem ? mem->allocator->mem_type : "(null)",
buffer ? gst_buffer_n_memory (buffer) : -1, is_mapped,
is_mapped ? GST_VIDEO_FRAME_SIZE (frame) : 0);
if (is_mapped)
gst_video_frame_unmap (frame);
g_slice_free (GstVideoFrame, frame);
gst_buffer_replace (&buffer, NULL);
g_list_free (images);
g_list_free_full (frames, (GDestroyNotify) gst_video_frame_unmap);
g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
buffers = NULL;
images = NULL;
err = OMX_ErrorUndefined;
self->use_buffers = FALSE;
break;
} else {
/* if downstream pool is 1 n_mem then always try to use buffers
* and retry without using them if it fails */
buffers = g_list_append (buffers, buffer);
frames = g_list_append (frames, frame);
images =
g_list_append (images, GST_VIDEO_FRAME_PLANE_DATA (frame, 0));
}
}
/* buffers match minimal requirements then
* now try to actually use them */
if (images) {
err = gst_omx_port_use_buffers (port, images);
g_list_free (images);
g_list_free_full (frames, (GDestroyNotify) gst_video_frame_unmap);
if (err == OMX_ErrorNone) {
GST_DEBUG_OBJECT (self, "Using %d buffers", min);
} else {
GST_INFO_OBJECT (self,
"Failed to OMX_UseBuffer on port: %s (0x%08x)",
gst_omx_error_to_string (err), err);
g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
self->use_buffers = FALSE;
}
}
}
if (!self->use_buffers)
err = gst_omx_port_allocate_buffers (port);
if (err != OMX_ErrorNone && min > port->port_def.nBufferCountMin) {
GST_ERROR_OBJECT (self,
"Failed to allocate required number of buffers %d, trying less and copying",
@ -838,6 +920,16 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
}
}
if (self->use_buffers) {
GST_DEBUG_OBJECT (self, "Populating internal buffer pool");
GST_OMX_BUFFER_POOL (self->out_port_pool)->other_pool =
GST_BUFFER_POOL (gst_object_ref (pool));
for (l = buffers; l; l = l->next) {
g_ptr_array_add (GST_OMX_BUFFER_POOL (self->out_port_pool)->buffers,
l->data);
}
g_list_free (buffers);
}
}
@ -1667,6 +1759,7 @@ gst_omx_video_dec_start (GstVideoDecoder * decoder)
self->last_upstream_ts = 0;
self->downstream_flow_ret = GST_FLOW_OK;
self->use_buffers = FALSE;
return TRUE;
}
@ -2527,6 +2620,7 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
{
GstBufferPool *pool;
GstStructure *config;
GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (bdec);
#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
{
@ -2572,6 +2666,12 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
}
#endif
self->use_buffers = FALSE;
if (gst_query_get_n_allocation_pools (query) > 0) {
GST_DEBUG_OBJECT (self, "Try using downstream buffers with OMX_UseBuffer");
self->use_buffers = TRUE;
}
if (!GST_VIDEO_DECODER_CLASS
(gst_omx_video_dec_parent_class)->decide_allocation (bdec, query))
return FALSE;

View file

@ -75,6 +75,11 @@ struct _GstOMXVideoDec
gboolean draining;
GstFlowReturn downstream_flow_ret;
/* Initially FALSE. Switched to TRUE when all requirements
* are met to try setting up the decoder with OMX_UseBuffer.
* Switched to FALSE if this trial fails so that the decoder
* can fallback to OMX_AllocateBuffer. */
gboolean use_buffers;
#ifdef USE_OMX_TARGET_RPI
GstOMXComponent *egl_render;
GstOMXPort *egl_in_port, *egl_out_port;