omxvideoenc: implement dmabuf import on zynqultrascaleplus

The Zynq UltraScale+ encoder implements a custom OMX extension to
directly import dmabuf saving the need of mapping input buffers.

This can be use with either 'v4l2src io-mode=dmabuf' or an OMX video
decoder upstream.

https://bugzilla.gnome.org/show_bug.cgi?id=792361
This commit is contained in:
Guillaume Desmottes 2017-07-27 11:21:59 +02:00 committed by Nicolas Dufresne
parent 0c5bbbb6ca
commit 9f87b987ef
4 changed files with 98 additions and 15 deletions

View file

@ -25,6 +25,7 @@
#endif
#include <gst/gst.h>
#include <gst/allocators/gstdmabuf.h>
#include <string.h>
#include "gstomx.h"
@ -617,14 +618,18 @@ gst_omx_buffer_unmap (GstOMXBuffer * buffer)
if (buffer->input_frame_mapped) {
g_assert (!buffer->input_mem);
g_assert (!buffer->input_buffer);
g_assert (!buffer->input_buffer_mapped);
gst_video_frame_unmap (&buffer->input_frame);
buffer->input_frame_mapped = FALSE;
} else if (buffer->input_mem) {
g_assert (!buffer->input_buffer);
g_assert (!buffer->input_buffer_mapped);
gst_memory_unmap (buffer->input_mem, &buffer->map);
g_clear_pointer (&buffer->input_mem, gst_memory_unref);
} else if (buffer->input_buffer) {
gst_buffer_unmap (buffer->input_buffer, &buffer->map);
if (buffer->input_buffer_mapped)
gst_buffer_unmap (buffer->input_buffer, &buffer->map);
buffer->input_buffer_mapped = FALSE;
g_clear_pointer (&buffer->input_buffer, gst_buffer_unref);
}
}
@ -1863,6 +1868,7 @@ gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input,
g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
g_return_val_if_fail (!buffer->input_mem, FALSE);
g_return_val_if_fail (!buffer->input_buffer, FALSE);
g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
if (!gst_video_frame_map (&buffer->input_frame, info, input, GST_MAP_READ))
return FALSE;
@ -1884,6 +1890,7 @@ gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
g_return_val_if_fail (!buffer->input_mem, FALSE);
g_return_val_if_fail (!buffer->input_buffer, FALSE);
g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
if (!gst_memory_map (mem, &buffer->map, GST_MAP_READ))
return FALSE;
@ -1896,6 +1903,32 @@ gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
return TRUE;
}
gboolean
gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input)
{
gint fd;
GstMemory *mem;
g_return_val_if_fail (buffer != NULL, FALSE);
g_return_val_if_fail (input != NULL, FALSE);
g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
g_return_val_if_fail (!buffer->input_mem, FALSE);
g_return_val_if_fail (!buffer->input_buffer, FALSE);
g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
mem = gst_buffer_peek_memory (input, 0);
g_return_val_if_fail (gst_is_dmabuf_memory (mem), FALSE);
fd = gst_dmabuf_memory_get_fd (mem);
buffer->input_buffer = gst_buffer_ref (input);
buffer->omx_buf->pBuffer = GUINT_TO_POINTER (fd);
buffer->omx_buf->nAllocLen = gst_memory_get_sizes (mem, NULL, NULL);
buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
return TRUE;
}
gboolean
gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
{
@ -1904,10 +1937,12 @@ gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
g_return_val_if_fail (!buffer->input_mem, FALSE);
g_return_val_if_fail (!buffer->input_buffer, FALSE);
g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
if (!gst_buffer_map (input, &buffer->map, GST_MAP_READ))
return FALSE;
buffer->input_buffer_mapped = TRUE;
buffer->input_buffer = gst_buffer_ref (input);
buffer->omx_buf->pBuffer = buffer->map.data;
buffer->omx_buf->nAllocLen = buffer->map.size;

View file

@ -339,6 +339,7 @@ struct _GstOMXBuffer {
gboolean input_frame_mapped; /* TRUE if input_frame is valid */
GstMemory *input_mem;
GstBuffer *input_buffer;
gboolean input_buffer_mapped;
GstMapInfo map;
};
@ -420,6 +421,7 @@ OMX_ERRORTYPE gst_omx_port_use_dynamic_buffers (GstOMXPort * port);
gboolean gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input, GstVideoInfo * info);
gboolean gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem);
gboolean gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input);
gboolean gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input);
void gst_omx_set_default_role (GstOMXClassData *class_data, const gchar *default_role);

View file

@ -24,6 +24,8 @@
#include <gst/gst.h>
#include <gst/video/gstvideometa.h>
#include <gst/allocators/gstdmabuf.h>
#include <string.h>
#include "gstomxvideo.h"
@ -1222,6 +1224,36 @@ gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self,
input);
self->input_dmabuf = FALSE;
#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
if (gst_is_dmabuf_memory (gst_buffer_peek_memory (input, 0))) {
if (self->input_allocation == GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
OMX_ALG_PORT_PARAM_BUFFER_MODE buffer_mode;
OMX_ERRORTYPE err;
GST_OMX_INIT_STRUCT (&buffer_mode);
buffer_mode.nPortIndex = self->enc_in_port->index;
buffer_mode.eMode = OMX_ALG_BUF_DMA;
GST_DEBUG_OBJECT (self, "Configure encoder to import dmabuf");
err =
gst_omx_component_set_parameter (self->enc,
(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 {
GST_DEBUG_OBJECT (self,
"Wrong input allocation mode (%d); dynamic buffers are required to use dmabuf import",
self->input_allocation);
}
self->input_dmabuf = TRUE;
}
#endif
GST_DEBUG_OBJECT (self, "Enabling component");
if (self->disabled) {
@ -1529,22 +1561,34 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
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 (!self->input_dmabuf) {
/* 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;
}
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));
GST_LOG_OBJECT (self, "Transfer buffer of %" G_GSIZE_FORMAT " bytes",
gst_buffer_get_size (inbuf));
} else {
/* dmabuf input */
if (!gst_omx_buffer_import_fd (outbuf, inbuf)) {
GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
("failed to import dmabuf"));
return FALSE;
}
GST_LOG_OBJECT (self, "Import dmabuf of %" G_GSIZE_FORMAT " bytes",
gst_buffer_get_size (inbuf));
}
ret = TRUE;
goto done;

View file

@ -79,6 +79,8 @@ struct _GstOMXVideoEnc
GstFlowReturn downstream_flow_ret;
GstOMXBufferAllocation input_allocation;
/* TRUE if encoder is passing dmabuf's fd directly to the OMX component */
gboolean input_dmabuf;
};
struct _GstOMXVideoEncClass