From 1ef38751c7635652a339001dbc8f94383d078677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 1 Nov 2011 16:46:09 +0100 Subject: [PATCH] omxaudioenc: Implement draining of the component and use it This makes sure that all buffers are encoded and pushed downstream before flushing the ports and losing some buffers. --- omx/gstomxaudioenc.c | 69 ++++++++++++++++++++++++++++++++++++++++++-- omx/gstomxaudioenc.h | 6 ++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/omx/gstomxaudioenc.c b/omx/gstomxaudioenc.c index 5d98b4d2fa..e54a11ef52 100644 --- a/omx/gstomxaudioenc.c +++ b/omx/gstomxaudioenc.c @@ -47,6 +47,8 @@ static GstFlowReturn gst_omx_audio_enc_handle_frame (GstBaseAudioEncoder * encoder, GstBuffer * buffer); static void gst_omx_audio_enc_flush (GstBaseAudioEncoder * encoder); +static GstFlowReturn gst_omx_audio_enc_drain (GstOMXAudioEnc * self); + enum { PROP_0 @@ -251,6 +253,8 @@ gst_omx_audio_enc_class_init (GstOMXAudioEncClass * klass) static void gst_omx_audio_enc_init (GstOMXAudioEnc * self, GstOMXAudioEncClass * klass) { + self->drain_lock = g_mutex_new (); + self->drain_cond = g_cond_new (); } static gboolean @@ -311,7 +315,10 @@ gst_omx_audio_enc_close (GstOMXAudioEnc * self) static void gst_omx_audio_enc_finalize (GObject * object) { - /* GstOMXAudioEnc *self = GST_OMX_AUDIO_ENC (object); */ + GstOMXAudioEnc *self = GST_OMX_AUDIO_ENC (object); + + g_mutex_free (self->drain_lock); + g_cond_free (self->drain_cond); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -337,6 +344,11 @@ gst_omx_audio_enc_change_state (GstElement * element, GstStateChange transition) if (self->out_port) gst_omx_port_set_flushing (self->out_port, FALSE); self->downstream_flow_ret = GST_FLOW_OK; + + g_mutex_lock (self->drain_lock); + self->draining = FALSE; + g_cond_broadcast (self->drain_cond); + g_mutex_unlock (self->drain_lock); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; @@ -345,6 +357,11 @@ gst_omx_audio_enc_change_state (GstElement * element, GstStateChange transition) gst_omx_port_set_flushing (self->in_port, TRUE); if (self->out_port) gst_omx_port_set_flushing (self->out_port, TRUE); + + g_mutex_lock (self->drain_lock); + self->draining = FALSE; + g_cond_broadcast (self->drain_cond); + g_mutex_unlock (self->drain_lock); break; default: break; @@ -484,8 +501,16 @@ gst_omx_audio_enc_loop (GstOMXAudioEnc * self) outbuf, n_samples); } - if (flow_ret == GST_FLOW_OK && (buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS)) - flow_ret = GST_FLOW_UNEXPECTED; + if (flow_ret == GST_FLOW_OK && (buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS)) { + g_mutex_lock (self->drain_lock); + if (self->draining) { + self->draining = FALSE; + g_cond_broadcast (self->drain_cond); + } else { + flow_ret = GST_FLOW_UNEXPECTED; + } + g_mutex_unlock (self->drain_lock); + } gst_omx_port_release_buffer (port, buf); @@ -584,6 +609,12 @@ gst_omx_audio_enc_stop (GstBaseAudioEncoder * encoder) gst_omx_component_set_state (self->component, OMX_StateIdle); self->downstream_flow_ret = GST_FLOW_WRONG_STATE; + + g_mutex_lock (self->drain_lock); + self->draining = FALSE; + g_cond_broadcast (self->drain_cond); + g_mutex_unlock (self->drain_lock); + gst_omx_port_set_flushing (self->in_port, TRUE); gst_omx_port_set_flushing (self->out_port, TRUE); @@ -625,6 +656,7 @@ gst_omx_audio_enc_set_format (GstBaseAudioEncoder * encoder, * format change happened we can just exit here. */ if (needs_disable) { + gst_omx_audio_enc_drain (self); if (gst_omx_port_manual_reconfigure (self->in_port, TRUE) != OMX_ErrorNone) return FALSE; if (gst_omx_port_set_enabled (self->in_port, FALSE) != OMX_ErrorNone) @@ -762,6 +794,8 @@ gst_omx_audio_enc_flush (GstBaseAudioEncoder * encoder) GST_DEBUG_OBJECT (self, "Resetting encoder"); if (self->started) { + gst_omx_audio_enc_drain (self); + gst_omx_port_set_flushing (self->in_port, TRUE); gst_omx_port_set_flushing (self->out_port, TRUE); @@ -931,3 +965,32 @@ gst_omx_audio_enc_event (GstBaseAudioEncoder * encoder, GstEvent * event) return TRUE; } + +static GstFlowReturn +gst_omx_audio_enc_drain (GstOMXAudioEnc * self) +{ + GstOMXBuffer *buf; + GstOMXAcquireBufferReturn acq_ret; + + GST_DEBUG_OBJECT (self, "Draining component"); + + /* Send an EOS buffer to the component and let the base + * class drop the EOS event. We will send it later when + * the EOS buffer arrives on the output port. */ + acq_ret = gst_omx_port_acquire_buffer (self->in_port, &buf); + if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) + return GST_FLOW_ERROR; + + GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self); + g_mutex_lock (self->drain_lock); + self->draining = TRUE; + buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS; + gst_omx_port_release_buffer (self->in_port, buf); + GST_DEBUG_OBJECT (self, "Waiting until component is drained"); + g_cond_wait (self->drain_cond, self->drain_lock); + GST_DEBUG_OBJECT (self, "Drained component"); + g_mutex_unlock (self->drain_lock); + GST_BASE_AUDIO_ENCODER_STREAM_LOCK (self); + + return GST_FLOW_OK; +} diff --git a/omx/gstomxaudioenc.h b/omx/gstomxaudioenc.h index f7e0a2fce6..035abc65a6 100644 --- a/omx/gstomxaudioenc.h +++ b/omx/gstomxaudioenc.h @@ -58,6 +58,12 @@ struct _GstOMXAudioEnc * the first buffer */ gboolean started; + /* Draining state */ + GMutex *drain_lock; + GCond *drain_cond; + /* TRUE if EOS buffers shouldn't be forwarded */ + gboolean draining; + GstFlowReturn downstream_flow_ret; };