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
This commit is contained in:
Guillaume Desmottes 2017-07-20 16:35:31 +02:00 committed by Julien Isorce
parent e55675b7ce
commit 533ee7fadc
2 changed files with 117 additions and 2 deletions

View file

@ -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)
return FALSE;
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) {

View file

@ -77,6 +77,8 @@ struct _GstOMXVideoEnc
guint32 quant_b_frames;
GstFlowReturn downstream_flow_ret;
GstOMXBufferAllocation input_allocation;
};
struct _GstOMXVideoEncClass