mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
omx: Add hack for encoder components that don't allow empty EOS buffers
This commit is contained in:
parent
b8b64ac746
commit
9e6665e8f8
3 changed files with 81 additions and 39 deletions
15
omx/gstomx.c
15
omx/gstomx.c
|
@ -974,7 +974,7 @@ retry:
|
||||||
"Output port %u needs reconfiguration but has buffers pending",
|
"Output port %u needs reconfiguration but has buffers pending",
|
||||||
port->index);
|
port->index);
|
||||||
_buf = g_queue_pop_head (port->pending_buffers);
|
_buf = g_queue_pop_head (port->pending_buffers);
|
||||||
g_assert (_buf != NULL);
|
|
||||||
ret = GST_OMX_ACQUIRE_BUFFER_OK;
|
ret = GST_OMX_ACQUIRE_BUFFER_OK;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1184,7 +1184,7 @@ gst_omx_port_set_flushing (GstOMXPort * port, gboolean flush)
|
||||||
signalled = TRUE;
|
signalled = TRUE;
|
||||||
last_error = OMX_ErrorNone;
|
last_error = OMX_ErrorNone;
|
||||||
while (signalled && last_error == OMX_ErrorNone && !port->flushed
|
while (signalled && last_error == OMX_ErrorNone && !port->flushed
|
||||||
&& port->buffers->len != g_queue_get_length (port->pending_buffers)) {
|
&& port->buffers->len > g_queue_get_length (port->pending_buffers)) {
|
||||||
signalled = g_cond_timed_wait (port->port_cond, port->port_lock, timeval);
|
signalled = g_cond_timed_wait (port->port_cond, port->port_lock, timeval);
|
||||||
|
|
||||||
last_error = gst_omx_component_get_last_error (comp);
|
last_error = gst_omx_component_get_last_error (comp);
|
||||||
|
@ -1210,6 +1210,9 @@ gst_omx_port_set_flushing (GstOMXPort * port, gboolean flush)
|
||||||
|
|
||||||
/* Enqueue all buffers for the component to fill */
|
/* Enqueue all buffers for the component to fill */
|
||||||
while ((buf = g_queue_pop_head (port->pending_buffers))) {
|
while ((buf = g_queue_pop_head (port->pending_buffers))) {
|
||||||
|
if (!buf)
|
||||||
|
continue;
|
||||||
|
|
||||||
g_assert (!buf->used);
|
g_assert (!buf->used);
|
||||||
|
|
||||||
/* Reset all flags, some implementations don't
|
/* Reset all flags, some implementations don't
|
||||||
|
@ -1548,8 +1551,7 @@ gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
|
||||||
signalled = TRUE;
|
signalled = TRUE;
|
||||||
last_error = OMX_ErrorNone;
|
last_error = OMX_ErrorNone;
|
||||||
while (signalled && last_error == OMX_ErrorNone && (port->buffers
|
while (signalled && last_error == OMX_ErrorNone && (port->buffers
|
||||||
&& port->buffers->len !=
|
&& port->buffers->len > g_queue_get_length (port->pending_buffers))) {
|
||||||
g_queue_get_length (port->pending_buffers))) {
|
|
||||||
signalled = g_cond_timed_wait (port->port_cond, port->port_lock, timeval);
|
signalled = g_cond_timed_wait (port->port_cond, port->port_lock, timeval);
|
||||||
last_error = gst_omx_component_get_last_error (comp);
|
last_error = gst_omx_component_get_last_error (comp);
|
||||||
}
|
}
|
||||||
|
@ -1619,6 +1621,9 @@ gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
|
||||||
|
|
||||||
/* Enqueue all buffers for the component to fill */
|
/* Enqueue all buffers for the component to fill */
|
||||||
while ((buf = g_queue_pop_head (port->pending_buffers))) {
|
while ((buf = g_queue_pop_head (port->pending_buffers))) {
|
||||||
|
if (!buf)
|
||||||
|
continue;
|
||||||
|
|
||||||
g_assert (!buf->used);
|
g_assert (!buf->used);
|
||||||
|
|
||||||
/* Reset all flags, some implementations don't
|
/* Reset all flags, some implementations don't
|
||||||
|
@ -1954,6 +1959,8 @@ gst_omx_parse_hacks (gchar ** hacks)
|
||||||
hacks_flags |= GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED;
|
hacks_flags |= GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED;
|
||||||
else if (g_str_equal (*hacks, "no-component-reconfigure"))
|
else if (g_str_equal (*hacks, "no-component-reconfigure"))
|
||||||
hacks_flags |= GST_OMX_HACK_NO_COMPONENT_RECONFIGURE;
|
hacks_flags |= GST_OMX_HACK_NO_COMPONENT_RECONFIGURE;
|
||||||
|
else if (g_str_equal (*hacks, "no-empty-eos-buffer"))
|
||||||
|
hacks_flags |= GST_OMX_HACK_NO_EMPTY_EOS_BUFFER;
|
||||||
else
|
else
|
||||||
GST_WARNING ("Unknown hack: %s", *hacks);
|
GST_WARNING ("Unknown hack: %s", *hacks);
|
||||||
hacks++;
|
hacks++;
|
||||||
|
|
|
@ -60,6 +60,11 @@ G_BEGIN_DECLS
|
||||||
*/
|
*/
|
||||||
#define GST_OMX_HACK_NO_COMPONENT_RECONFIGURE G_GUINT64_CONSTANT (0x0000000000000010)
|
#define GST_OMX_HACK_NO_COMPONENT_RECONFIGURE G_GUINT64_CONSTANT (0x0000000000000010)
|
||||||
|
|
||||||
|
/* If the component does not accept empty EOS buffers.
|
||||||
|
* Happens with Qualcomm's OpenMAX implementation.
|
||||||
|
*/
|
||||||
|
#define GST_OMX_HACK_NO_EMPTY_EOS_BUFFER G_GUINT64_CONSTANT (0x0000000000000020)
|
||||||
|
|
||||||
|
|
||||||
typedef struct _GstOMXCore GstOMXCore;
|
typedef struct _GstOMXCore GstOMXCore;
|
||||||
typedef struct _GstOMXPort GstOMXPort;
|
typedef struct _GstOMXPort GstOMXPort;
|
||||||
|
|
|
@ -858,48 +858,56 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
|
g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags,
|
if (buf) {
|
||||||
buf->omx_buf->nTimeStamp);
|
|
||||||
|
|
||||||
/* This prevents a deadlock between the srcpad stream
|
GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags,
|
||||||
* lock and the videocodec stream lock, if ::reset()
|
buf->omx_buf->nTimeStamp);
|
||||||
* is called at the wrong time
|
|
||||||
*/
|
|
||||||
if (gst_omx_port_is_flushing (self->out_port)) {
|
|
||||||
GST_DEBUG_OBJECT (self, "Flushing");
|
|
||||||
gst_omx_port_release_buffer (self->out_port, buf);
|
|
||||||
goto flushing;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_BASE_VIDEO_CODEC_STREAM_LOCK (self);
|
/* This prevents a deadlock between the srcpad stream
|
||||||
frame = _find_nearest_frame (self, buf);
|
* lock and the videocodec stream lock, if ::reset()
|
||||||
|
* is called at the wrong time
|
||||||
is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS);
|
*/
|
||||||
|
if (gst_omx_port_is_flushing (self->out_port)) {
|
||||||
g_assert (klass->handle_output_frame);
|
GST_DEBUG_OBJECT (self, "Flushing");
|
||||||
flow_ret = klass->handle_output_frame (self, self->out_port, buf, frame);
|
gst_omx_port_release_buffer (self->out_port, buf);
|
||||||
|
goto flushing;
|
||||||
if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) {
|
|
||||||
g_mutex_lock (self->drain_lock);
|
|
||||||
if (self->draining) {
|
|
||||||
GST_DEBUG_OBJECT (self, "Drained");
|
|
||||||
self->draining = FALSE;
|
|
||||||
g_cond_broadcast (self->drain_cond);
|
|
||||||
} else if (flow_ret == GST_FLOW_OK) {
|
|
||||||
GST_DEBUG_OBJECT (self, "Component signalled EOS");
|
|
||||||
flow_ret = GST_FLOW_UNEXPECTED;
|
|
||||||
}
|
}
|
||||||
g_mutex_unlock (self->drain_lock);
|
|
||||||
|
GST_BASE_VIDEO_CODEC_STREAM_LOCK (self);
|
||||||
|
frame = _find_nearest_frame (self, buf);
|
||||||
|
|
||||||
|
is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS);
|
||||||
|
|
||||||
|
g_assert (klass->handle_output_frame);
|
||||||
|
flow_ret = klass->handle_output_frame (self, self->out_port, buf, frame);
|
||||||
|
|
||||||
|
if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) {
|
||||||
|
g_mutex_lock (self->drain_lock);
|
||||||
|
if (self->draining) {
|
||||||
|
GST_DEBUG_OBJECT (self, "Drained");
|
||||||
|
self->draining = FALSE;
|
||||||
|
g_cond_broadcast (self->drain_cond);
|
||||||
|
} else if (flow_ret == GST_FLOW_OK) {
|
||||||
|
GST_DEBUG_OBJECT (self, "Component signalled EOS");
|
||||||
|
flow_ret = GST_FLOW_UNEXPECTED;
|
||||||
|
}
|
||||||
|
g_mutex_unlock (self->drain_lock);
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (self, "Finished frame: %s",
|
||||||
|
gst_flow_get_name (flow_ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_omx_port_release_buffer (port, buf);
|
||||||
|
|
||||||
|
self->downstream_flow_ret = flow_ret;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
|
g_assert ((klass->hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER));
|
||||||
|
flow_ret = GST_FLOW_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_omx_port_release_buffer (port, buf);
|
|
||||||
|
|
||||||
self->downstream_flow_ret = flow_ret;
|
|
||||||
|
|
||||||
if (flow_ret != GST_FLOW_OK)
|
if (flow_ret != GST_FLOW_OK)
|
||||||
goto flow_error;
|
goto flow_error;
|
||||||
|
|
||||||
|
@ -1513,10 +1521,12 @@ static GstFlowReturn
|
||||||
gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder)
|
gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder)
|
||||||
{
|
{
|
||||||
GstOMXVideoEnc *self;
|
GstOMXVideoEnc *self;
|
||||||
|
GstOMXVideoEncClass *klass;
|
||||||
GstOMXBuffer *buf;
|
GstOMXBuffer *buf;
|
||||||
GstOMXAcquireBufferReturn acq_ret;
|
GstOMXAcquireBufferReturn acq_ret;
|
||||||
|
|
||||||
self = GST_OMX_VIDEO_ENC (encoder);
|
self = GST_OMX_VIDEO_ENC (encoder);
|
||||||
|
klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Sending EOS to the component");
|
GST_DEBUG_OBJECT (self, "Sending EOS to the component");
|
||||||
|
|
||||||
|
@ -1527,6 +1537,18 @@ gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder)
|
||||||
}
|
}
|
||||||
self->eos = TRUE;
|
self->eos = TRUE;
|
||||||
|
|
||||||
|
if ((klass->hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
|
||||||
|
GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
|
||||||
|
|
||||||
|
/* Insert a NULL into the queue to signal EOS */
|
||||||
|
g_mutex_lock (self->out_port->port_lock);
|
||||||
|
g_queue_push_tail (self->out_port->pending_buffers, NULL);
|
||||||
|
g_cond_broadcast (self->out_port->port_cond);
|
||||||
|
g_mutex_unlock (self->out_port->port_lock);
|
||||||
|
|
||||||
|
return GST_BASE_VIDEO_ENCODER_FLOW_DROPPED;
|
||||||
|
}
|
||||||
|
|
||||||
/* 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 */
|
||||||
|
@ -1557,11 +1579,14 @@ gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder)
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_omx_video_enc_drain (GstOMXVideoEnc * self)
|
gst_omx_video_enc_drain (GstOMXVideoEnc * self)
|
||||||
{
|
{
|
||||||
|
GstOMXVideoEncClass *klass;
|
||||||
GstOMXBuffer *buf;
|
GstOMXBuffer *buf;
|
||||||
GstOMXAcquireBufferReturn acq_ret;
|
GstOMXAcquireBufferReturn acq_ret;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Draining component");
|
GST_DEBUG_OBJECT (self, "Draining component");
|
||||||
|
|
||||||
|
klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
|
||||||
|
|
||||||
if (!self->started) {
|
if (!self->started) {
|
||||||
GST_DEBUG_OBJECT (self, "Component not started yet");
|
GST_DEBUG_OBJECT (self, "Component not started yet");
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
@ -1574,6 +1599,11 @@ gst_omx_video_enc_drain (GstOMXVideoEnc * self)
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((klass->hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
|
||||||
|
GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* 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 */
|
||||||
|
|
Loading…
Reference in a new issue