mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
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:
parent
34bc02e397
commit
7be54ad091
5 changed files with 309 additions and 62 deletions
35
omx/gstomx.c
35
omx/gstomx.c
|
@ -418,7 +418,11 @@ gst_omx_component_handle_messages (GstOMXComponent * comp)
|
|||
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;
|
||||
}
|
||||
|
@ -1097,6 +1101,7 @@ gst_omx_component_add_port (GstOMXComponent * comp, guint32 index)
|
|||
port->enabled_pending = FALSE;
|
||||
port->disabled_pending = FALSE;
|
||||
port->eos = FALSE;
|
||||
port->using_pool = FALSE;
|
||||
|
||||
if (port->port_def.eDir == OMX_DirInput)
|
||||
comp->n_in_ports++;
|
||||
|
@ -2630,6 +2635,34 @@ gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port, guint extra)
|
|||
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
|
||||
gst_omx_port_set_dmabuf (GstOMXPort * port, gboolean dmabuf)
|
||||
{
|
||||
|
|
|
@ -324,6 +324,7 @@ struct _GstOMXPort {
|
|||
gboolean disabled_pending; /* was done until it took effect */
|
||||
gboolean eos; /* TRUE after a buffer with EOS flag was received */
|
||||
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.
|
||||
* 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);
|
||||
gboolean gst_omx_port_is_enabled (GstOMXPort * port);
|
||||
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);
|
||||
|
||||
|
|
|
@ -36,6 +36,14 @@ typedef struct _GstOMXMemory GstOMXMemory;
|
|||
typedef struct _GstOMXMemoryAllocator GstOMXMemoryAllocator;
|
||||
typedef struct _GstOMXMemoryAllocatorClass GstOMXMemoryAllocatorClass;
|
||||
|
||||
enum
|
||||
{
|
||||
SIG_ALLOCATE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
struct _GstOMXMemory
|
||||
{
|
||||
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
|
||||
* elements.
|
||||
*
|
||||
*
|
||||
* A buffer is in the pool if it is currently owned by the port,
|
||||
* i.e. after OMX_{Fill,Empty}ThisBuffer(). A buffer is outside
|
||||
* An output buffer is in the pool if it is currently owned by the port,
|
||||
* i.e. after OMX_FillThisBuffer(). An output buffer is outside
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* supposed to return the buffer that corresponds to the OMX buffer.
|
||||
*
|
||||
|
@ -217,6 +228,9 @@ static gboolean
|
|||
gst_omx_buffer_pool_start (GstBufferPool * 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
|
||||
* to a component and port */
|
||||
|
@ -225,8 +239,39 @@ gst_omx_buffer_pool_start (GstBufferPool * bpool)
|
|||
GST_OBJECT_UNLOCK (pool);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pool->port->using_pool = TRUE;
|
||||
|
||||
has_buffers = (pool->port->buffers != NULL);
|
||||
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
|
||||
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);
|
||||
gint i = 0;
|
||||
|
||||
/* When not using the default GstBufferPool::GstAtomicQueue then
|
||||
* GstBufferPool::free_buffer is not called while stopping the pool
|
||||
* (because the queue is empty) */
|
||||
for (i = 0; i < pool->buffers->len; i++)
|
||||
GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->release_buffer
|
||||
(bpool, g_ptr_array_index (pool->buffers, i));
|
||||
if (pool->buffers) {
|
||||
/* When not using the default GstBufferPool::GstAtomicQueue then
|
||||
* GstBufferPool::free_buffer is not called while stopping the pool
|
||||
* (because the queue is empty) */
|
||||
for (i = 0; i < pool->buffers->len; 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 */
|
||||
g_ptr_array_set_size (pool->buffers, 0);
|
||||
|
@ -255,6 +305,8 @@ gst_omx_buffer_pool_stop (GstBufferPool * bpool)
|
|||
pool->caps = NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -284,10 +336,11 @@ gst_omx_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
|
|||
{
|
||||
GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
|
||||
GstCaps *caps;
|
||||
guint size, min;
|
||||
|
||||
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;
|
||||
|
||||
if (caps == NULL)
|
||||
|
@ -314,6 +367,9 @@ gst_omx_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
|
|||
gst_caps_unref (pool->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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
|
||||
GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
|
||||
|
@ -557,9 +628,23 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool,
|
|||
}
|
||||
} else {
|
||||
/* Acquire any buffer that is available to be filled by upstream */
|
||||
ret =
|
||||
GST_BUFFER_POOL_CLASS (gst_omx_buffer_pool_parent_class)->acquire_buffer
|
||||
(bpool, buffer, params);
|
||||
GstOMXBuffer *omx_buf;
|
||||
GstOMXAcquireBufferReturn r;
|
||||
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;
|
||||
|
@ -574,9 +659,10 @@ gst_omx_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
|
|||
|
||||
g_assert (pool->component && pool->port);
|
||||
|
||||
if (!pool->allocating && !pool->deactivated) {
|
||||
if (!pool->allocating) {
|
||||
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 */
|
||||
err = gst_omx_port_release_buffer (pool->port, omx_buf);
|
||||
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)",
|
||||
gst_omx_error_to_string (err), err));
|
||||
}
|
||||
} else if (!omx_buf->used) {
|
||||
/* TODO: Implement.
|
||||
*
|
||||
* 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);
|
||||
} else if (pool->port->port_def.eDir == OMX_DirInput) {
|
||||
g_queue_push_tail (&pool->port->pending_buffers, omx_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -653,6 +723,10 @@ gst_omx_buffer_pool_class_init (GstOMXBufferPoolClass * klass)
|
|||
gstbufferpool_class->release_buffer = gst_omx_buffer_pool_release_buffer;
|
||||
|
||||
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
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "gstomxbufferpool.h"
|
||||
#include "gstomxvideo.h"
|
||||
#include "gstomxvideoenc.h"
|
||||
|
||||
|
@ -917,7 +918,9 @@ gst_omx_video_enc_open (GstVideoEncoder * encoder)
|
|||
static gboolean
|
||||
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 TRUE;
|
||||
|
@ -1659,6 +1662,7 @@ gst_omx_video_enc_start (GstVideoEncoder * encoder)
|
|||
self->last_upstream_ts = 0;
|
||||
self->downstream_flow_ret = GST_FLOW_OK;
|
||||
self->nb_downstream_buffers = 0;
|
||||
self->in_pool_used = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -2035,6 +2039,20 @@ gst_omx_video_enc_set_to_idle (GstOMXVideoEnc * self)
|
|||
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
|
||||
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);
|
||||
|
||||
if (!gst_omx_video_enc_configure_input_buffer (self, input))
|
||||
return FALSE;
|
||||
/* Is downstream using our buffer pool? */
|
||||
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,
|
||||
input);
|
||||
self->input_dmabuf = FALSE;
|
||||
if (!self->in_pool_used) {
|
||||
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);
|
||||
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) {
|
||||
GST_DEBUG_OBJECT (self, "Configure encoder input to import dmabuf");
|
||||
gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Wrong input allocation mode (%d); dynamic buffers are required to use dmabuf import",
|
||||
self->input_allocation);
|
||||
}
|
||||
if (gst_is_dmabuf_memory (gst_buffer_peek_memory (input, 0))) {
|
||||
if (self->input_allocation ==
|
||||
GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
|
||||
GST_DEBUG_OBJECT (self, "Configure encoder input to import dmabuf");
|
||||
gst_omx_port_set_dmabuf (self->enc_in_port, TRUE);
|
||||
} 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;
|
||||
}
|
||||
self->input_dmabuf = TRUE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Enabling component");
|
||||
|
||||
if (!gst_omx_video_enc_ensure_nb_in_buffers (self))
|
||||
return FALSE;
|
||||
if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
|
||||
return FALSE;
|
||||
if (!self->in_pool_used) {
|
||||
if (!gst_omx_video_enc_ensure_nb_in_buffers (self))
|
||||
return FALSE;
|
||||
if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (self->disabled) {
|
||||
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)
|
||||
return FALSE;
|
||||
} else {
|
||||
if (!gst_omx_video_enc_set_to_idle (self))
|
||||
return FALSE;
|
||||
/* If the input pool is active we already allocated buffers and set the component to Idle. */
|
||||
if (!self->in_pool_used) {
|
||||
if (!gst_omx_video_enc_set_to_idle (self))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gst_omx_component_set_state (self->enc,
|
||||
OMX_StateExecuting) != OMX_ErrorNone)
|
||||
|
@ -2668,12 +2701,32 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
|
|||
|
||||
while (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
|
||||
GstClockTime timestamp, duration;
|
||||
gboolean fill_buffer = TRUE;
|
||||
|
||||
/* Make sure to release the base class stream lock, otherwise
|
||||
* _loop() can't call _finish_frame() and we might block forever
|
||||
* because no input buffers are released */
|
||||
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) {
|
||||
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
|
||||
* 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);
|
||||
goto buffer_fill_error;
|
||||
}
|
||||
|
@ -2968,6 +3022,71 @@ gst_omx_video_enc_drain (GstOMXVideoEnc * self)
|
|||
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
|
||||
gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
|
||||
GstQuery * query)
|
||||
|
@ -2976,6 +3095,7 @@ gst_omx_video_enc_propose_allocation (GstVideoEncoder * encoder,
|
|||
guint num_buffers;
|
||||
GstCaps *caps;
|
||||
GstVideoInfo info;
|
||||
GstBufferPool *pool = 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);
|
||||
|
||||
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,
|
||||
"request at least %d buffers of size %" G_GSIZE_FORMAT, num_buffers,
|
||||
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
|
||||
GST_VIDEO_ENCODER_CLASS
|
||||
|
|
|
@ -104,6 +104,9 @@ struct _GstOMXVideoEnc
|
|||
/* Number of buffers requested downstream */
|
||||
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
|
||||
GEnumClass *alg_roi_quality_enum_class;
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue