mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
omx: add API to implement dynamic buffers support
OMX 1.2.0 introduced a third way to manage buffers by allowing components to only allocate buffers header during their initialization and change their pBuffer pointer at runtime. This new feature can save us a copy between GStreamer and OMX for each input buffer. This patch adds API to allocate and use such buffers. https://bugzilla.gnome.org/show_bug.cgi?id=787093
This commit is contained in:
parent
47c341de21
commit
da07a647b8
2 changed files with 166 additions and 0 deletions
143
omx/gstomx.c
143
omx/gstomx.c
|
@ -609,6 +609,26 @@ EventHandler (OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_EVENTTYPE eEvent,
|
|||
return OMX_ErrorNone;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_omx_buffer_unmap (GstOMXBuffer * buffer)
|
||||
{
|
||||
g_return_if_fail (buffer != NULL);
|
||||
|
||||
if (buffer->input_frame_mapped) {
|
||||
g_assert (!buffer->input_mem);
|
||||
g_assert (!buffer->input_buffer);
|
||||
gst_video_frame_unmap (&buffer->input_frame);
|
||||
buffer->input_frame_mapped = FALSE;
|
||||
} else if (buffer->input_mem) {
|
||||
g_assert (!buffer->input_buffer);
|
||||
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);
|
||||
g_clear_pointer (&buffer->input_buffer, gst_buffer_unref);
|
||||
}
|
||||
}
|
||||
|
||||
static OMX_ERRORTYPE
|
||||
EmptyBufferDone (OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
|
||||
OMX_BUFFERHEADERTYPE * pBuffer)
|
||||
|
@ -630,6 +650,9 @@ EmptyBufferDone (OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
|
|||
return OMX_ErrorBadParameter;
|
||||
}
|
||||
|
||||
/* Release and unmap the parent buffer, if any */
|
||||
gst_omx_buffer_unmap (buf);
|
||||
|
||||
comp = buf->port->comp;
|
||||
|
||||
msg = g_slice_new (GstOMXMessage);
|
||||
|
@ -1751,6 +1774,7 @@ gst_omx_port_allocate_buffers (GstOMXPort * port)
|
|||
|
||||
g_mutex_lock (&port->comp->lock);
|
||||
err = gst_omx_port_allocate_buffers_unlocked (port, NULL, NULL, -1);
|
||||
port->allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
|
||||
g_mutex_unlock (&port->comp->lock);
|
||||
|
||||
return err;
|
||||
|
@ -1768,11 +1792,130 @@ gst_omx_port_use_buffers (GstOMXPort * port, const GList * buffers)
|
|||
g_mutex_lock (&port->comp->lock);
|
||||
n = g_list_length ((GList *) buffers);
|
||||
err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
|
||||
port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER;
|
||||
g_mutex_unlock (&port->comp->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_omx_is_dynamic_allocation_supported (void)
|
||||
{
|
||||
/* The Zynqultrascaleplus stack implements OMX 1.1.0 but supports the dynamic
|
||||
* allocation mode from 1.2.0 as an extension. */
|
||||
#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
|
||||
return TRUE;
|
||||
#endif
|
||||
|
||||
#if OMX_VERSION_MINOR == 2
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* OMX 1.2.0 introduced a dynamic allocation mode where only buffer headers are
|
||||
* being allocated during component's initialization. The actual buffers are
|
||||
* allocated upstream and passed to OMX by setting the pBuffer dynamically
|
||||
* for each input buffer.
|
||||
*
|
||||
* This function takes care of allocating the buffer headers. Element should
|
||||
* then use one of the gst_omx_buffer_map_*() method to update buffer's pBuffer
|
||||
* pointers for each incoming buffer.
|
||||
*
|
||||
* NOTE: Uses comp->lock and comp->messages_lock */
|
||||
OMX_ERRORTYPE
|
||||
gst_omx_port_use_dynamic_buffers (GstOMXPort * port)
|
||||
{
|
||||
OMX_ERRORTYPE err;
|
||||
GList *buffers = NULL;
|
||||
guint i, n;
|
||||
|
||||
g_return_val_if_fail (port != NULL, OMX_ErrorUndefined);
|
||||
|
||||
n = port->port_def.nBufferCountActual;
|
||||
for (i = 0; i < port->port_def.nBufferCountActual; i++)
|
||||
/* Pass NULL to UseBuffer() as the buffer is dynamic and so its payload
|
||||
* will be set each time before being passed to OMX. */
|
||||
buffers = g_list_prepend (buffers, GUINT_TO_POINTER (NULL));
|
||||
|
||||
g_mutex_lock (&port->comp->lock);
|
||||
err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n);
|
||||
port->allocation = GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
|
||||
g_mutex_unlock (&port->comp->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* gst_omx_buffer_map_* methods are used in dynamic buffer mode to map
|
||||
* a frame/memory/buffer and update @buffer so its pBuffer points to the
|
||||
* mapped data. It also ensures that the input will stay alive until
|
||||
* gst_omx_buffer_unmap() is called.
|
||||
* This is used in OMX 1.2.0 dynamic allocation mode so an OMX component can
|
||||
* safely process @buffer's content without having to copy it.
|
||||
* The input will be automatically unmapped when @buffer is released by OMX.
|
||||
*/
|
||||
gboolean
|
||||
gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input,
|
||||
GstVideoInfo * info)
|
||||
{
|
||||
g_return_val_if_fail (buffer != 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);
|
||||
|
||||
if (!gst_video_frame_map (&buffer->input_frame, info, input, GST_MAP_READ))
|
||||
return FALSE;
|
||||
|
||||
buffer->input_frame_mapped = TRUE;
|
||||
buffer->omx_buf->pBuffer =
|
||||
GST_VIDEO_FRAME_PLANE_DATA (&buffer->input_frame, 0);
|
||||
buffer->omx_buf->nAllocLen = gst_buffer_get_size (input);
|
||||
buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
|
||||
{
|
||||
g_return_val_if_fail (buffer != NULL, FALSE);
|
||||
g_return_val_if_fail (mem != 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);
|
||||
|
||||
if (!gst_memory_map (mem, &buffer->map, GST_MAP_READ))
|
||||
return FALSE;
|
||||
|
||||
buffer->input_mem = gst_memory_ref (mem);
|
||||
buffer->omx_buf->pBuffer = buffer->map.data;
|
||||
buffer->omx_buf->nAllocLen = buffer->map.size;
|
||||
buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
|
||||
{
|
||||
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);
|
||||
|
||||
if (!gst_buffer_map (input, &buffer->map, GST_MAP_READ))
|
||||
return FALSE;
|
||||
|
||||
buffer->input_buffer = gst_buffer_ref (input);
|
||||
buffer->omx_buf->pBuffer = buffer->map.data;
|
||||
buffer->omx_buf->nAllocLen = buffer->map.size;
|
||||
buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* NOTE: Uses comp->lock and comp->messages_lock */
|
||||
OMX_ERRORTYPE
|
||||
gst_omx_port_use_eglimages (GstOMXPort * port, const GList * images)
|
||||
|
|
23
omx/gstomx.h
23
omx/gstomx.h
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <gmodule.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -220,6 +221,13 @@ typedef enum {
|
|||
GST_OMX_COMPONENT_TYPE_FILTER
|
||||
} GstOmxComponentType;
|
||||
|
||||
/* How the port's buffers are allocated */
|
||||
typedef enum {
|
||||
GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER,
|
||||
GST_OMX_BUFFER_ALLOCATION_USE_BUFFER,
|
||||
GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC, /* Only supported by OMX 1.2.0 */
|
||||
} GstOMXBufferAllocation;
|
||||
|
||||
struct _GstOMXMessage {
|
||||
GstOMXMessageType type;
|
||||
|
||||
|
@ -267,6 +275,7 @@ struct _GstOMXPort {
|
|||
gboolean enabled_pending; /* TRUE after OMX_Command{En,Dis}able */
|
||||
gboolean disabled_pending; /* was done until it took effect */
|
||||
gboolean eos; /* TRUE after a buffer with EOS flag was received */
|
||||
GstOMXBufferAllocation allocation;
|
||||
|
||||
/* Increased whenever the settings of these port change.
|
||||
* If settings_cookie != configured_settings_cookie
|
||||
|
@ -323,6 +332,14 @@ struct _GstOMXBuffer {
|
|||
|
||||
/* TRUE if this is an EGLImage */
|
||||
gboolean eglimage;
|
||||
|
||||
/* Used in dynamic buffer mode to keep track of the mapped content while it's
|
||||
* being processed by the OMX component. */
|
||||
GstVideoFrame input_frame;
|
||||
gboolean input_frame_mapped; /* TRUE if input_frame is valid */
|
||||
GstMemory *input_mem;
|
||||
GstBuffer *input_buffer;
|
||||
GstMapInfo map;
|
||||
};
|
||||
|
||||
struct _GstOMXClassData {
|
||||
|
@ -397,6 +414,12 @@ OMX_ERRORTYPE gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled)
|
|||
OMX_ERRORTYPE gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout);
|
||||
gboolean gst_omx_port_is_enabled (GstOMXPort * port);
|
||||
|
||||
/* OMX 1.2.0 dynamic allocation mode */
|
||||
gboolean gst_omx_is_dynamic_allocation_supported (void);
|
||||
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);
|
||||
|
||||
void gst_omx_set_default_role (GstOMXClassData *class_data, const gchar *default_role);
|
||||
|
||||
|
|
Loading…
Reference in a new issue