From 9e6665e8f81a77e91ca31ff3a7c0dab957465679 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 9 Dec 2011 12:17:29 +0100 Subject: [PATCH] omx: Add hack for encoder components that don't allow empty EOS buffers --- omx/gstomx.c | 15 ++++++--- omx/gstomx.h | 5 +++ omx/gstomxvideoenc.c | 94 ++++++++++++++++++++++++++++++++++------------------ 3 files changed, 78 insertions(+), 36 deletions(-) diff --git a/omx/gstomx.c b/omx/gstomx.c index 385483d..c70d980 100644 --- a/omx/gstomx.c +++ b/omx/gstomx.c @@ -974,7 +974,7 @@ retry: "Output port %u needs reconfiguration but has buffers pending", port->index); _buf = g_queue_pop_head (port->pending_buffers); - g_assert (_buf != NULL); + ret = GST_OMX_ACQUIRE_BUFFER_OK; goto done; } @@ -1184,7 +1184,7 @@ gst_omx_port_set_flushing (GstOMXPort * port, gboolean flush) signalled = TRUE; last_error = OMX_ErrorNone; 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); 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 */ while ((buf = g_queue_pop_head (port->pending_buffers))) { + if (!buf) + continue; + g_assert (!buf->used); /* Reset all flags, some implementations don't @@ -1548,8 +1551,7 @@ gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled) signalled = TRUE; last_error = OMX_ErrorNone; while (signalled && last_error == OMX_ErrorNone && (port->buffers - && 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); 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 */ while ((buf = g_queue_pop_head (port->pending_buffers))) { + if (!buf) + continue; + g_assert (!buf->used); /* 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; else if (g_str_equal (*hacks, "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 GST_WARNING ("Unknown hack: %s", *hacks); hacks++; diff --git a/omx/gstomx.h b/omx/gstomx.h index 55efb4b..6ef3beb 100644 --- a/omx/gstomx.h +++ b/omx/gstomx.h @@ -60,6 +60,11 @@ G_BEGIN_DECLS */ #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 _GstOMXPort GstOMXPort; diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c index 9ac382a..04a41f6 100644 --- a/omx/gstomxvideoenc.c +++ b/omx/gstomxvideoenc.c @@ -858,47 +858,55 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self) 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, - buf->omx_buf->nTimeStamp); + if (buf) { - /* This prevents a deadlock between the srcpad stream - * lock and the videocodec stream lock, if ::reset() - * 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_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags, + buf->omx_buf->nTimeStamp); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); - frame = _find_nearest_frame (self, buf); + /* This prevents a deadlock between the srcpad stream + * lock and the videocodec stream lock, if ::reset() + * 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; + } - is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); + GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + frame = _find_nearest_frame (self, buf); - g_assert (klass->handle_output_frame); - flow_ret = klass->handle_output_frame (self, self->out_port, buf, frame); + is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); - 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_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)); } - 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); + gst_omx_port_release_buffer (port, buf); - self->downstream_flow_ret = flow_ret; + self->downstream_flow_ret = flow_ret; + + } else { + g_assert ((klass->hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)); + flow_ret = GST_FLOW_UNEXPECTED; + } if (flow_ret != GST_FLOW_OK) goto flow_error; @@ -1513,10 +1521,12 @@ static GstFlowReturn gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder) { GstOMXVideoEnc *self; + GstOMXVideoEncClass *klass; GstOMXBuffer *buf; GstOMXAcquireBufferReturn acq_ret; self = GST_OMX_VIDEO_ENC (encoder); + klass = GST_OMX_VIDEO_ENC_GET_CLASS (self); GST_DEBUG_OBJECT (self, "Sending EOS to the component"); @@ -1527,6 +1537,18 @@ gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder) } 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 * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ @@ -1557,11 +1579,14 @@ gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder) static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self) { + GstOMXVideoEncClass *klass; GstOMXBuffer *buf; GstOMXAcquireBufferReturn acq_ret; GST_DEBUG_OBJECT (self, "Draining component"); + klass = GST_OMX_VIDEO_ENC_GET_CLASS (self); + if (!self->started) { GST_DEBUG_OBJECT (self, "Component not started yet"); return GST_FLOW_OK; @@ -1574,6 +1599,11 @@ gst_omx_video_enc_drain (GstOMXVideoEnc * self) 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 * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ -- 2.7.4