omx: Add hack for encoder components that don't allow empty EOS buffers

This commit is contained in:
Sebastian Dröge 2011-12-09 12:17:29 +01:00
parent b8b64ac746
commit 9e6665e8f8
3 changed files with 81 additions and 39 deletions

View file

@ -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++;

View file

@ -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;

View file

@ -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 */