diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2017-07-20 16:35:31 +0200 |
---|---|---|
committer | Julien Isorce <jisorce@oblong.com> | 2017-12-14 09:00:31 +0000 |
commit | 533ee7fadcd167b92f263c1676ef7468c0ac2959 (patch) | |
tree | 775fc9f1d84d0ddf137527fccb7a07558482ee5c | |
parent | e55675b7ceb92286d539752c2c83939226304c7e (diff) | |
download | gst-omx-533ee7fadcd167b92f263c1676ef7468c0ac2959.tar.gz |
omxvideoenc: use dynamic buffer mode on input if possible
If the OMX component supports dynamic buffer mode and the input buffers
are properly aligned avoid copying each input frame between OMX and
GStreamer.
Tested on zynqultrascaleplus and rpi (without dynamic buffers).
https://bugzilla.gnome.org/show_bug.cgi?id=787093
-rw-r--r-- | omx/gstomxvideoenc.c | 115 | ||||
-rw-r--r-- | omx/gstomxvideoenc.h | 2 |
2 files changed, 116 insertions, 1 deletions
diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c index 37fd4ac..ce3d55a 100644 --- a/omx/gstomxvideoenc.c +++ b/omx/gstomxvideoenc.c @@ -1123,12 +1123,93 @@ gst_omx_video_enc_configure_input_buffer (GstOMXVideoEnc * self, static gboolean gst_omx_video_enc_allocate_in_buffers (GstOMXVideoEnc * self) { - if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) + switch (self->input_allocation) { + case GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER: + if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) + return FALSE; + break; + case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC: + if (gst_omx_port_use_dynamic_buffers (self->enc_in_port) != OMX_ErrorNone) + return FALSE; + break; + case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER: + default: + /* Not supported */ + g_return_val_if_reached (FALSE); + } + + return TRUE; +} + +static gboolean +check_input_alignment (GstOMXVideoEnc * self, GstMapInfo * map) +{ + OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def; + + if (map->size != port_def->nBufferSize) { + GST_DEBUG_OBJECT (self, + "input buffer has wrong size/stride (%" G_GSIZE_FORMAT + " expected: %u), can't use dynamic allocation", + map->size, (guint32) port_def->nBufferSize); return FALSE; + } + + if (port_def->nBufferAlignment && + (GPOINTER_TO_UINT (map->data) & (port_def->nBufferAlignment - 1)) != 0) { + GST_DEBUG_OBJECT (self, + "input buffer is not properly aligned (address: %p alignment: %u bytes), can't use dynamic allocation", + map->data, (guint32) port_def->nBufferAlignment); + return FALSE; + } return TRUE; } +/* Check if @inbuf's alignment and stride matches the requirements to use the + * dynamic buffer mode. */ +static gboolean +can_use_dynamic_buffer_mode (GstOMXVideoEnc * self, GstBuffer * inbuf) +{ + GstMapInfo map; + gboolean result = FALSE; + + if (gst_buffer_n_memory (inbuf) > 1) { + GST_DEBUG_OBJECT (self, + "input buffer contains more than one memory, can't use dynamic allocation"); + return FALSE; + } + + if (!gst_buffer_map (inbuf, &map, GST_MAP_READ)) { + GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), + ("failed to map input buffer")); + return FALSE; + } + + result = check_input_alignment (self, &map); + + gst_buffer_unmap (inbuf, &map); + return result; +} + +/* Choose the allocation mode for input buffers depending of what's supported by + * the component and the size/alignment of the input buffer. */ +static GstOMXBufferAllocation +gst_omx_video_enc_pick_input_allocation_mode (GstOMXVideoEnc * self, + GstBuffer * inbuf) +{ + if (!gst_omx_is_dynamic_allocation_supported ()) + return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER; + + if (can_use_dynamic_buffer_mode (self, inbuf)) { + GST_DEBUG_OBJECT (self, + "input buffer is properly aligned, use dynamic allocation"); + return GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC; + } + + GST_DEBUG_OBJECT (self, "let input buffer allocate its buffers"); + return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER; +} + static gboolean gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input) { @@ -1139,6 +1220,9 @@ gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input) if (!gst_omx_video_enc_configure_input_buffer (self, input)) return FALSE; + self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self, + input); + GST_DEBUG_OBJECT (self, "Enabling component"); if (self->disabled) { if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone) @@ -1437,6 +1521,35 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, goto done; } + if (self->enc_in_port->allocation == + GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) { + if (gst_buffer_n_memory (inbuf) > 1) { + GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), + ("input buffer now has more than one memory, can't use dynamic allocation any more")); + return FALSE; + } + + /* Map and keep a ref on the buffer while it's being processed + * by the OMX component. */ + if (!gst_omx_buffer_map_frame (outbuf, inbuf, info)) { + GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), + ("failed to map input buffer")); + return FALSE; + } + + if (!check_input_alignment (self, &outbuf->input_frame.map[0])) { + GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), + ("input buffer now has wrong alignment/stride, can't use dynamic allocation any more")); + return FALSE; + } + + GST_LOG_OBJECT (self, "Transfer buffer of %" G_GSIZE_FORMAT " bytes", + gst_buffer_get_size (inbuf)); + + ret = TRUE; + goto done; + } + /* Same strides and everything */ if (gst_buffer_get_size (inbuf) == outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) { diff --git a/omx/gstomxvideoenc.h b/omx/gstomxvideoenc.h index 265d4fe..345b9d1 100644 --- a/omx/gstomxvideoenc.h +++ b/omx/gstomxvideoenc.h @@ -77,6 +77,8 @@ struct _GstOMXVideoEnc guint32 quant_b_frames; GstFlowReturn downstream_flow_ret; + + GstOMXBufferAllocation input_allocation; }; struct _GstOMXVideoEncClass |