From 887d43c2903e9bd34558c0ee6977c3e68d392667 Mon Sep 17 00:00:00 2001 From: Jonas Larsson Date: Wed, 14 Dec 2011 10:09:34 +0100 Subject: [PATCH] omxaudioenc: Add hack for encoder components that don't allow empty EOS buffers --- omx/gstomxaudioenc.c | 172 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 106 insertions(+), 66 deletions(-) diff --git a/omx/gstomxaudioenc.c b/omx/gstomxaudioenc.c index 4fb7811..18beb26 100644 --- a/omx/gstomxaudioenc.c +++ b/omx/gstomxaudioenc.c @@ -463,87 +463,106 @@ gst_omx_audio_enc_loop (GstOMXAudioEnc * 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) { - GST_AUDIO_ENCODER_STREAM_LOCK (self); - is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); - - if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) - && buf->omx_buf->nFilledLen > 0) { - GstCaps *caps; - GstBuffer *codec_data; + GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags, + buf->omx_buf->nTimeStamp); - caps = gst_caps_copy (GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (self))); - codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); - memcpy (GST_BUFFER_DATA (codec_data), - buf->omx_buf->pBuffer + buf->omx_buf->nOffset, - buf->omx_buf->nFilledLen); - - gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); - if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (self), caps)) { - gst_caps_unref (caps); - if (buf) - gst_omx_port_release_buffer (self->out_port, buf); - GST_AUDIO_ENCODER_STREAM_UNLOCK (self); - goto caps_failed; + /* 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_caps_unref (caps); - flow_ret = GST_FLOW_OK; - } else if (buf->omx_buf->nFilledLen > 0) { - GstBuffer *outbuf; - guint n_samples; - n_samples = - klass->get_num_samples (self, self->out_port, - gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (self)), buf); + GST_AUDIO_ENCODER_STREAM_LOCK (self); + is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); - if (buf->omx_buf->nFilledLen > 0) { - outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); + if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) + && buf->omx_buf->nFilledLen > 0) { + GstCaps *caps; + GstBuffer *codec_data; - memcpy (GST_BUFFER_DATA (outbuf), + caps = gst_caps_copy (GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (self))); + codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); + memcpy (GST_BUFFER_DATA (codec_data), buf->omx_buf->pBuffer + buf->omx_buf->nOffset, buf->omx_buf->nFilledLen); - } else { - outbuf = gst_buffer_new (); - } - - gst_buffer_set_caps (outbuf, - GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (self))); - GST_BUFFER_TIMESTAMP (outbuf) = - gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND, - OMX_TICKS_PER_SECOND); - if (buf->omx_buf->nTickCount != 0) - GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND, + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, + NULL); + if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (self), caps)) { + gst_caps_unref (caps); + if (buf) + gst_omx_port_release_buffer (self->out_port, buf); + GST_AUDIO_ENCODER_STREAM_UNLOCK (self); + goto caps_failed; + } + gst_caps_unref (caps); + flow_ret = GST_FLOW_OK; + } else if (buf->omx_buf->nFilledLen > 0) { + GstBuffer *outbuf; + guint n_samples; + + n_samples = + klass->get_num_samples (self, self->out_port, + gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (self)), buf); + + if (buf->omx_buf->nFilledLen > 0) { + outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); + + memcpy (GST_BUFFER_DATA (outbuf), + buf->omx_buf->pBuffer + buf->omx_buf->nOffset, + buf->omx_buf->nFilledLen); + } else { + outbuf = gst_buffer_new (); + } + + gst_buffer_set_caps (outbuf, + GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (self))); + + GST_BUFFER_TIMESTAMP (outbuf) = + gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND, OMX_TICKS_PER_SECOND); + if (buf->omx_buf->nTickCount != 0) + GST_BUFFER_DURATION (outbuf) = + gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND, + OMX_TICKS_PER_SECOND); + + flow_ret = + gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (self), + outbuf, n_samples); + } - flow_ret = - gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (self), - outbuf, n_samples); - } - - 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; + 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)); + GST_AUDIO_ENCODER_STREAM_LOCK (self); + flow_ret = GST_FLOW_UNEXPECTED; + } if (flow_ret != GST_FLOW_OK) goto flow_error; @@ -993,8 +1012,10 @@ static gboolean gst_omx_audio_enc_event (GstAudioEncoder * encoder, GstEvent * event) { GstOMXAudioEnc *self; + GstOMXAudioEncClass *klass; self = GST_OMX_AUDIO_ENC (encoder); + klass = GST_OMX_AUDIO_ENC_GET_CLASS (self); if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { GstOMXBuffer *buf; @@ -1009,6 +1030,17 @@ gst_omx_audio_enc_event (GstAudioEncoder * encoder, GstEvent * event) } 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 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 */ @@ -1042,11 +1074,14 @@ gst_omx_audio_enc_event (GstAudioEncoder * encoder, GstEvent * event) static GstFlowReturn gst_omx_audio_enc_drain (GstOMXAudioEnc * self) { + GstOMXAudioEncClass *klass; GstOMXBuffer *buf; GstOMXAcquireBufferReturn acq_ret; GST_DEBUG_OBJECT (self, "Draining component"); + klass = GST_OMX_AUDIO_ENC_GET_CLASS (self); + if (!self->started) { GST_DEBUG_OBJECT (self, "Component not started yet"); return GST_FLOW_OK; @@ -1059,6 +1094,11 @@ gst_omx_audio_enc_drain (GstOMXAudioEnc * 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