omxvideoenc: implement dmabuf export on input buffers

Propose pool upstream so input buffers can be allocated by the port and
exported as dmabuf.

The actual OMX buffers are allocated when the pool is activated, so we
don't end up doing useless allocations if the pool isn't used.

https://bugzilla.gnome.org/show_bug.cgi?id=796918
This commit is contained in:
Guillaume Desmottes 2018-05-15 11:59:26 +02:00
parent 34bc02e397
commit 7be54ad091
5 changed files with 309 additions and 62 deletions

View file

@ -418,7 +418,11 @@ gst_omx_component_handle_messages (GstOMXComponent * comp)
port->eos = TRUE; port->eos = TRUE;
} }
g_queue_push_tail (&port->pending_buffers, buf); /* If an input port is managed by a pool, the buffer will be ready to be
* filled again once it's been released to the pool. */
if (port->port_def.eDir == OMX_DirOutput || !port->using_pool) {
g_queue_push_tail (&port->pending_buffers, buf);
}
break; break;
} }
@ -1097,6 +1101,7 @@ gst_omx_component_add_port (GstOMXComponent * comp, guint32 index)
port->enabled_pending = FALSE; port->enabled_pending = FALSE;
port->disabled_pending = FALSE; port->disabled_pending = FALSE;
port->eos = FALSE; port->eos = FALSE;
port->using_pool = FALSE;
if (port->port_def.eDir == OMX_DirInput) if (port->port_def.eDir == OMX_DirInput)
comp->n_in_ports++; comp->n_in_ports++;
@ -2630,6 +2635,34 @@ gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra)
return TRUE; return TRUE;
} }
gboolean
gst_omx_port_update_buffer_count_actual (GstOMXPort * port, guint nb)
{
OMX_PARAM_PORTDEFINITIONTYPE port_def;
gst_omx_port_get_port_definition (port, &port_def);
if (nb < port_def.nBufferCountMin) {
GST_DEBUG_OBJECT (port->comp->parent,
"Requested to use %d buffers on port %d but it's minimum is %d", nb,
(guint) port->index, (guint) port_def.nBufferCountMin);
nb = port_def.nBufferCountMin;
}
if (port_def.nBufferCountActual != nb) {
port_def.nBufferCountActual = nb;
GST_DEBUG_OBJECT (port->comp->parent,
"set port %d nBufferCountActual to %d", (guint) port->index, nb);
if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
return FALSE;
}
return TRUE;
}
gboolean gboolean
gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf) gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf)
{ {

View file

@ -324,6 +324,7 @@ struct _GstOMXPort {
gboolean disabled_pending; /* was done until it took effect */ gboolean disabled_pending; /* was done until it took effect */
gboolean eos; /* TRUE after a buffer with EOS flag was received */ gboolean eos; /* TRUE after a buffer with EOS flag was received */
GstOMXBufferAllocation allocation; GstOMXBufferAllocation allocation;
gboolean using_pool; /* TRUE if the buffers of this port are managed by a pool */
/* Increased whenever the settings of these port change. /* Increased whenever the settings of these port change.
* If settings_cookie != configured_settings_cookie * If settings_cookie != configured_settings_cookie
@ -467,6 +468,7 @@ OMX_ERRORTYPE gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled)
OMX_ERRORTYPE gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout); OMX_ERRORTYPE gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout);
gboolean gst_omx_port_is_enabled (GstOMXPort * port); gboolean gst_omx_port_is_enabled (GstOMXPort * port);
gboolean gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra); gboolean gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra);
gboolean gst_omx_port_update_buffer_count_actual (GstOMXPort * port, guint nb);
gboolean gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf); gboolean gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf);

View file

@ -36,6 +36,14 @@ typedef struct _GstOMXMemory GstOMXMemory;
typedef struct _GstOMXMemoryAllocator GstOMXMemoryAllocator; typedef struct _GstOMXMemoryAllocator GstOMXMemoryAllocator;
typedef struct _GstOMXMemoryAllocatorClass GstOMXMemoryAllocatorClass; typedef struct _GstOMXMemoryAllocatorClass GstOMXMemoryAllocatorClass;
enum
{
SIG_ALLOCATE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
struct _GstOMXMemory struct _GstOMXMemory
{ {
GstMemory mem; GstMemory mem;
@ -171,11 +179,14 @@ gst_omx_memory_allocator_alloc (GstAllocator * allocator, GstMemoryFlags flags,
* pool to the OMX port or provide the OMX buffers directly to other * pool to the OMX port or provide the OMX buffers directly to other
* elements. * elements.
* *
* * An output buffer is in the pool if it is currently owned by the port,
* A buffer is in the pool if it is currently owned by the port, * i.e. after OMX_FillThisBuffer(). An output buffer is outside
* i.e. after OMX_{Fill,Empty}ThisBuffer(). A buffer is outside
* the pool after it was taken from the port after it was handled * the pool after it was taken from the port after it was handled
* by the port, i.e. {Empty,Fill}BufferDone. * by the port, i.e. FillBufferDone.
*
* An input buffer is in the pool if it is currently available to be filled
* upstream. It will be put back into the pool when it has been processed by
* OMX, (EmptyBufferDone).
* *
* Buffers can be allocated by us (OMX_AllocateBuffer()) or allocated * Buffers can be allocated by us (OMX_AllocateBuffer()) or allocated
* by someone else and (temporarily) passed to this pool * by someone else and (temporarily) passed to this pool
@ -188,7 +199,7 @@ gst_omx_memory_allocator_alloc (GstAllocator * allocator, GstMemoryFlags flags,
* They correspond 1:1 to the OMX buffers of the port, which are allocated * They correspond 1:1 to the OMX buffers of the port, which are allocated
* before the pool is started. * before the pool is started.
* *
* Acquiring a buffer from this pool happens after the OMX buffer has * Acquiring an output buffer from this pool happens after the OMX buffer has
* been acquired from the port. gst_buffer_pool_acquire_buffer() is * been acquired from the port. gst_buffer_pool_acquire_buffer() is
* supposed to return the buffer that corresponds to the OMX buffer. * supposed to return the buffer that corresponds to the OMX buffer.
* *
@ -217,6 +228,9 @@ static gboolean
gst_omx_buffer_pool_start (GstBufferPool * bpool) gst_omx_buffer_pool_start (GstBufferPool * bpool)
{ {
GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
gboolean has_buffers;
GstStructure *config;
guint min, max;
/* Only allow to start the pool if we still are attached /* Only allow to start the pool if we still are attached
* to a component and port */ * to a component and port */
@ -225,8 +239,39 @@ gst_omx_buffer_pool_start (GstBufferPool * bpool)
GST_OBJECT_UNLOCK (pool); GST_OBJECT_UNLOCK (pool);
return FALSE; return FALSE;
} }
pool->port->using_pool = TRUE;
has_buffers = (pool->port->buffers != NULL);
GST_OBJECT_UNLOCK (pool); GST_OBJECT_UNLOCK (pool);
config = gst_buffer_pool_get_config (bpool);
gst_buffer_pool_config_get_params (config, NULL, NULL, &min, &max);
gst_structure_free (config);
if (max > min) {
GST_WARNING_OBJECT (bpool,
"max (%d) cannot be higher than min (%d) as pool cannot allocate buffers on the fly",
max, min);
return FALSE;
}
if (!has_buffers) {
gboolean result = FALSE;
GST_DEBUG_OBJECT (bpool, "Buffers not yet allocated on port %d of %s",
pool->port->index, pool->component->name);
g_signal_emit (pool, signals[SIG_ALLOCATE], 0, &result);
if (!result) {
GST_WARNING_OBJECT (bpool,
"Element failed to allocate buffers, can't start pool");
return FALSE;
}
}
g_assert (pool->port->buffers);
return return
GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->start (bpool); GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->start (bpool);
} }
@ -237,12 +282,17 @@ gst_omx_buffer_pool_stop (GstBufferPool * bpool)
GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
gint i = 0; gint i = 0;
/* When not using the default GstBufferPool::GstAtomicQueue then if (pool->buffers) {
* GstBufferPool::free_buffer is not called while stopping the pool /* When not using the default GstBufferPool::GstAtomicQueue then
* (because the queue is empty) */ * GstBufferPool::free_buffer is not called while stopping the pool
for (i = 0; i < pool->buffers->len; i++) * (because the queue is empty) */
GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer for (i = 0; i < pool->buffers->len; i++)
(bpool, g_ptr_array_index (pool->buffers, i)); GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer
(bpool, g_ptr_array_index (pool->buffers, i));
/* Remove any buffers that are there */
g_ptr_array_set_size (pool->buffers, 0);
}
/* Remove any buffers that are there */ /* Remove any buffers that are there */
g_ptr_array_set_size (pool->buffers, 0); g_ptr_array_set_size (pool->buffers, 0);
@ -255,6 +305,8 @@ gst_omx_buffer_pool_stop (GstBufferPool * bpool)
pool->caps = NULL; pool->caps = NULL;
pool->add_videometa = FALSE; pool->add_videometa = FALSE;
pool->deactivated = TRUE;
pool->port->using_pool = TRUE;
return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->stop (bpool); return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->stop (bpool);
} }
@ -284,10 +336,11 @@ gst_omx_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
{ {
GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
GstCaps *caps; GstCaps *caps;
guint size, min;
GST_OBJECT_LOCK (pool); GST_OBJECT_LOCK (pool);
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)) if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min, NULL))
goto wrong_config; goto wrong_config;
if (caps == NULL) if (caps == NULL)
@ -314,6 +367,9 @@ gst_omx_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
gst_caps_unref (pool->caps); gst_caps_unref (pool->caps);
pool->caps = gst_caps_ref (caps); pool->caps = gst_caps_ref (caps);
/* Ensure max=min as the pool won't be able to allocate more buffers while active */
gst_buffer_pool_config_set_params (config, caps, size, min, min);
GST_OBJECT_UNLOCK (pool); GST_OBJECT_UNLOCK (pool);
return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->set_config return GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->set_config
@ -520,6 +576,21 @@ gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
buffer); buffer);
} }
static GstBuffer *
find_buffer_from_omx_buffer (GstOMXBufferPool * pool, GstOMXBuffer * omx_buf)
{
guint i;
for (i = 0; i < pool->buffers->len; i++) {
GstBuffer *buf = g_ptr_array_index (pool->buffers, i);
if (gst_omx_buffer_get_omx_buf (buf) == omx_buf)
return buf;
}
return NULL;
}
static GstFlowReturn static GstFlowReturn
gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool, gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
GstBuffer ** buffer, GstBufferPoolAcquireParams * params) GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
@ -557,9 +628,23 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
} }
} else { } else {
/* Acquire any buffer that is available to be filled by upstream */ /* Acquire any buffer that is available to be filled by upstream */
ret = GstOMXBuffer *omx_buf;
GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->acquire_buffer GstOMXAcquireBufferReturn r;
(bpool, buffer, params); GstOMXWait wait = GST_OMX_WAIT;
if (params && (params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT))
wait = GST_OMX_DONT_WAIT;
r = gst_omx_port_acquire_buffer (pool->port, &omx_buf, wait);
if (r == GST_OMX_ACQUIRE_BUFFER_OK) {
*buffer = find_buffer_from_omx_buffer (pool, omx_buf);
g_return_val_if_fail (*buffer, GST_FLOW_ERROR);
return GST_FLOW_OK;
} else if (r == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
return GST_FLOW_FLUSHING;
} else {
return GST_FLOW_ERROR;
}
} }
return ret; return ret;
@ -574,9 +659,10 @@ gst_omx_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
g_assert (pool->component && pool->port); g_assert (pool->component && pool->port);
if (!pool->allocating && !pool->deactivated) { if (!pool->allocating) {
omx_buf = gst_omx_buffer_get_omx_buf (buffer); omx_buf = gst_omx_buffer_get_omx_buf (buffer);
if (pool->port->port_def.eDir == OMX_DirOutput && !omx_buf->used) { if (pool->port->port_def.eDir == OMX_DirOutput && !omx_buf->used &&
!pool->deactivated) {
/* Release back to the port, can be filled again */ /* Release back to the port, can be filled again */
err = gst_omx_port_release_buffer (pool->port, omx_buf); err = gst_omx_port_release_buffer (pool->port, omx_buf);
if (err != OMX_ErrorNone) { if (err != OMX_ErrorNone) {
@ -584,24 +670,8 @@ gst_omx_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
("Failed to relase output buffer to component: %s (0x%08x)", ("Failed to relase output buffer to component: %s (0x%08x)",
gst_omx_error_to_string (err), err)); gst_omx_error_to_string (err), err));
} }
} else if (!omx_buf->used) { } else if (pool->port->port_def.eDir == OMX_DirInput) {
/* TODO: Implement. g_queue_push_tail (&pool->port->pending_buffers, omx_buf);
*
* If not used (i.e. was not passed to the component) this should do
* the same as EmptyBufferDone.
* If it is used (i.e. was passed to the component) this should do
* nothing until EmptyBufferDone.
*
* EmptyBufferDone should release the buffer to the pool so it can
* be allocated again
*
* Needs something to call back here in EmptyBufferDone, like keeping
* a ref on the buffer in GstOMXBuffer until EmptyBufferDone... which
* would ensure that the buffer is always unused when this is called.
*/
g_assert_not_reached ();
GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer
(bpool, buffer);
} }
} }
} }
@ -653,6 +723,10 @@ gst_omx_buffer_pool_class_init (GstOMXBufferPoolClass * klass)
gstbufferpool_class->release_buffer = gst_omx_buffer_pool_release_buffer; gstbufferpool_class->release_buffer = gst_omx_buffer_pool_release_buffer;
GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE"); GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
signals[SIG_ALLOCATE] = g_signal_new ("allocate",
G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_BOOLEAN, 0);
} }
static void static void

View file

@ -28,6 +28,7 @@
#include <string.h> #include <string.h>
#include "gstomxbufferpool.h"
#include "gstomxvideo.h" #include "gstomxvideo.h"
#include "gstomxvideoenc.h" #include "gstomxvideoenc.h"
@ -917,7 +918,9 @@ gst_omx_video_enc_open (GstVideoEncoder * encoder)
static gboolean static gboolean
gst_omx_video_enc_deallocate_in_buffers (GstOMXVideoEnc * self) gst_omx_video_enc_deallocate_in_buffers (GstOMXVideoEnc * self)
{ {
if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone) /* Pool will take care of deallocating buffers when deactivated upstream */
if (!self->in_pool_used
&& gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
return FALSE; return FALSE;
return TRUE; return TRUE;
@ -1659,6 +1662,7 @@ gst_omx_video_enc_start (GstVideoEncoder * encoder)
self->last_upstream_ts = 0; self->last_upstream_ts = 0;
self->downstream_flow_ret = GST_FLOW_OK; self->downstream_flow_ret = GST_FLOW_OK;
self->nb_downstream_buffers = 0; self->nb_downstream_buffers = 0;
self->in_pool_used = FALSE;
return TRUE; return TRUE;
} }
@ -2035,6 +2039,20 @@ gst_omx_video_enc_set_to_idle (GstOMXVideoEnc * self)
return TRUE; return TRUE;
} }
static gboolean
buffer_is_from_input_pool (GstOMXVideoEnc * self, GstBuffer * buffer)
{
/* Buffer from our input pool will already have a GstOMXBuffer associated
* with our input port. */
GstOMXBuffer *buf;
buf = gst_omx_buffer_get_omx_buf (buffer);
if (!buf)
return FALSE;
return buf->port == self->enc_in_port;
}
static gboolean static gboolean
gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input) gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
{ {
@ -2042,34 +2060,46 @@ gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
klass = GST_OMX_VIDEO_ENC_GET_CLASS (self); klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
if (!gst_omx_video_enc_configure_input_buffer (self, input)) /* Is downstream using our buffer pool? */
return FALSE; if (buffer_is_from_input_pool (self, input)) {
/* We're done allocating as we received the first buffer from upstream */
GST_OMX_BUFFER_POOL (input->pool)->allocating = FALSE;
self->in_pool_used = TRUE;
}
self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self, if (!self->in_pool_used) {
input); if (!gst_omx_video_enc_configure_input_buffer (self, input))
self->input_dmabuf = FALSE; return FALSE;
self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self,
input);
self->input_dmabuf = FALSE;
#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
if (gst_is_dmabuf_memory (gst_buffer_peek_memory (input, 0))) { if (gst_is_dmabuf_memory (gst_buffer_peek_memory (input, 0))) {
if (self->input_allocation == GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) { if (self->input_allocation ==
GST_DEBUG_OBJECT (self, "Configure encoder input to import dmabuf"); GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
gst_omx_port_set_dmabuf (self->enc_in_port, TRUE); GST_DEBUG_OBJECT (self, "Configure encoder input to import dmabuf");
} else { gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
GST_DEBUG_OBJECT (self, } else {
"Wrong input allocation mode (%d); dynamic buffers are required to use dmabuf import", GST_DEBUG_OBJECT (self,
self->input_allocation); "Wrong input allocation mode (%d); dynamic buffers are required to use dmabuf import",
} self->input_allocation);
}
self->input_dmabuf = TRUE; self->input_dmabuf = TRUE;
} }
#endif #endif
}
GST_DEBUG_OBJECT (self, "Enabling component"); GST_DEBUG_OBJECT (self, "Enabling component");
if (!gst_omx_video_enc_ensure_nb_in_buffers (self)) if (!self->in_pool_used) {
return FALSE; if (!gst_omx_video_enc_ensure_nb_in_buffers (self))
if (!gst_omx_video_enc_ensure_nb_out_buffers (self)) return FALSE;
return FALSE; if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
return FALSE;
}
if (self->disabled) { if (self->disabled) {
if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone) if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
@ -2094,8 +2124,11 @@ gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone) if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
return FALSE; return FALSE;
} else { } else {
if (!gst_omx_video_enc_set_to_idle (self)) /* If the input pool is active we already allocated buffers and set the component to Idle. */
return FALSE; if (!self->in_pool_used) {
if (!gst_omx_video_enc_set_to_idle (self))
return FALSE;
}
if (gst_omx_component_set_state (self->enc, if (gst_omx_component_set_state (self->enc,
OMX_StateExecuting) != OMX_ErrorNone) OMX_StateExecuting) != OMX_ErrorNone)
@ -2668,12 +2701,32 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) { while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
GstClockTime timestamp, duration; GstClockTime timestamp, duration;
gboolean fill_buffer = TRUE;
/* Make sure to release the base class stream lock, otherwise /* Make sure to release the base class stream lock, otherwise
* _loop() can't call _finish_frame() and we might block forever * _loop() can't call _finish_frame() and we might block forever
* because no input buffers are released */ * because no input buffers are released */
GST_VIDEO_ENCODER_STREAM_UNLOCK (self); GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
acq_ret = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
if (buffer_is_from_input_pool (self, frame->input_buffer)) {
/* Receiving a buffer from our input pool */
buf = gst_omx_buffer_get_omx_buf (frame->input_buffer);
GST_LOG_OBJECT (self,
"Input buffer %p already has a OMX buffer associated: %p",
frame->input_buffer, buf);
g_assert (!buf->input_buffer);
/* Prevent the buffer to be released to the pool while it's being
* processed by OMX. The reference will be dropped in EmptyBufferDone() */
buf->input_buffer = gst_buffer_ref (frame->input_buffer);
acq_ret = GST_OMX_ACQUIRE_BUFFER_OK;
fill_buffer = FALSE;
buf->omx_buf->nFilledLen = gst_buffer_get_size (frame->input_buffer);
} else {
acq_ret = gst_omx_port_acquire_buffer (port, &buf, GST_OMX_WAIT);
}
if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) { if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
GST_VIDEO_ENCODER_STREAM_LOCK (self); GST_VIDEO_ENCODER_STREAM_LOCK (self);
@ -2789,7 +2842,8 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
/* Copy the buffer content in chunks of size as requested /* Copy the buffer content in chunks of size as requested
* by the port */ * by the port */
if (!gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) { if (fill_buffer
&& !gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) {
gst_omx_port_release_buffer (port, buf); gst_omx_port_release_buffer (port, buf);
goto buffer_fill_error; goto buffer_fill_error;
} }
@ -2968,6 +3022,71 @@ gst_omx_video_enc_drain (GstOMXVideoEnc * self)
return GST_FLOW_OK; return GST_FLOW_OK;
} }
#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
static gboolean
pool_request_allocate_cb (GstBufferPool * pool, GstOMXVideoEnc * self)
{
GstStructure *config;
guint min;
gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
config = gst_buffer_pool_get_config (pool);
if (!gst_buffer_pool_config_get_params (config, NULL, NULL, &min, NULL)) {
gst_structure_free (config);
return FALSE;
}
gst_structure_free (config);
GST_DEBUG_OBJECT (self,
"input pool configured for %d buffers, adjust nBufferCountActual", min);
if (!gst_omx_port_update_buffer_count_actual (self->enc_in_port, min))
return FALSE;
if (!gst_omx_video_enc_set_to_idle (self))
return FALSE;
self->input_allocation = GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
self->input_dmabuf = TRUE;
/* gst_omx_port_acquire_buffer() will fail if the input port is stil flushing
* which will prevent upstream from acquiring buffers. */
gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
return TRUE;
}
static GstBufferPool *
create_input_pool (GstOMXVideoEnc * self, GstCaps * caps, guint num_buffers)
{
GstBufferPool *pool;
GstStructure *config;
pool =
gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->enc,
self->enc_in_port, GST_OMX_BUFFER_MODE_DMABUF);
GST_OMX_BUFFER_POOL (pool)->allocating = TRUE;
g_signal_connect_object (pool, "allocate",
G_CALLBACK (pool_request_allocate_cb), self, 0);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps,
self->enc_in_port->port_def.nBufferSize, num_buffers, 0);
if (!gst_buffer_pool_set_config (pool, config)) {
GST_INFO_OBJECT (self, "Failed to set config on input pool");
gst_object_unref (pool);
return NULL;
}
return pool;
}
#endif
static gboolean static gboolean
gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder, gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
GstQuery * query) GstQuery * query)
@ -2976,6 +3095,7 @@ gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
guint num_buffers; guint num_buffers;
GstCaps *caps; GstCaps *caps;
GstVideoInfo info; GstVideoInfo info;
GstBufferPool *pool = NULL;
gst_query_parse_allocation (query, &caps, NULL); gst_query_parse_allocation (query, &caps, NULL);
@ -2992,10 +3112,25 @@ gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
num_buffers = self->enc_in_port->port_def.nBufferCountMin + 1; num_buffers = self->enc_in_port->port_def.nBufferCountMin + 1;
#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
/* dmabuf export is currently only supported on Zynqultrascaleplus */
pool = create_input_pool (self, caps, num_buffers);
if (!pool) {
GST_WARNING_OBJECT (self, "Failed to create and configure pool");
return FALSE;
}
#endif
GST_DEBUG_OBJECT (self, GST_DEBUG_OBJECT (self,
"request at least %d buffers of size %" G_GSIZE_FORMAT, num_buffers, "request at least %d buffers of size %" G_GSIZE_FORMAT, num_buffers,
info.size); info.size);
gst_query_add_allocation_pool (query, NULL, info.size, num_buffers, 0); gst_query_add_allocation_pool (query, pool,
self->enc_in_port->port_def.nBufferSize, num_buffers, 0);
self->in_pool_used = FALSE;
g_clear_object (&pool);
return return
GST_VIDEO_ENCODER_CLASS GST_VIDEO_ENCODER_CLASS

View file

@ -104,6 +104,9 @@ struct _GstOMXVideoEnc
/* Number of buffers requested downstream */ /* Number of buffers requested downstream */
guint nb_downstream_buffers; guint nb_downstream_buffers;
/* TRUE if input buffers are from the pool we proposed to upstream */
gboolean in_pool_used;
#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
GEnumClass *alg_roi_quality_enum_class; GEnumClass *alg_roi_quality_enum_class;
#endif #endif