diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index 21c75bcd6e..84729cb1c9 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -260,6 +260,8 @@ struct _GstAudioDecoderPrivate GstClockTime tolerance; gboolean plc; + /* pending serialized sink events, will be sent from finish_frame() */ + GList *pending_events; }; @@ -417,6 +419,10 @@ gst_audio_decoder_reset (GstAudioDecoder * dec, gboolean full) } gst_segment_init (&dec->segment, GST_FORMAT_TIME); + + g_list_foreach (dec->priv->pending_events, (GFunc) gst_event_unref, NULL); + g_list_free (dec->priv->pending_events); + dec->priv->pending_events = NULL; } g_queue_foreach (&dec->priv->frames, (GFunc) gst_buffer_unref, NULL); @@ -707,6 +713,20 @@ gst_audio_decoder_finish_frame (GstAudioDecoder * dec, GstBuffer * buf, buf ? GST_BUFFER_SIZE (buf) : -1, buf ? GST_BUFFER_SIZE (buf) / ctx->info.bpf : -1, frames); + if (priv->pending_events) { + GList *pending_events, *l; + + GST_OBJECT_LOCK (dec); + pending_events = priv->pending_events; + priv->pending_events = NULL; + GST_OBJECT_UNLOCK (dec); + + GST_DEBUG_OBJECT (dec, "Pushing pending events"); + for (l = priv->pending_events; l; l = l->next) + gst_pad_push_event (dec->srcpad, l->data); + g_list_free (pending_events); + } + /* output shoud be whole number of sample frames */ if (G_LIKELY (buf && ctx->info.bpf)) { if (GST_BUFFER_SIZE (buf) % ctx->info.bpf) @@ -1374,6 +1394,12 @@ gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event) case GST_EVENT_FLUSH_STOP: /* prepare for fresh start */ gst_audio_decoder_flush (dec, TRUE); + + GST_OBJECT_LOCK (dec); + g_list_foreach (dec->priv->pending_events, (GFunc) gst_event_unref, NULL); + g_list_free (dec->priv->pending_events); + dec->priv->pending_events = NULL; + GST_OBJECT_UNLOCK (dec); break; case GST_EVENT_EOS: @@ -1407,8 +1433,27 @@ gst_audio_decoder_sink_event (GstPad * pad, GstEvent * event) if (!handled) handled = gst_audio_decoder_sink_eventfunc (dec, event); - if (!handled) - ret = gst_pad_event_default (pad, event); + if (!handled) { + /* Forward non-serialized events and EOS/FLUSH_STOP immediately. + * For EOS this is required because no buffer or serialized event + * will come after EOS and nothing could trigger another + * _finish_frame() call. + * + * For FLUSH_STOP this is required because it is expected + * to be forwarded immediately and no buffers are queued anyway. + */ + if (!GST_EVENT_IS_SERIALIZED (event) + || GST_EVENT_TYPE (event) == GST_EVENT_EOS + || GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) { + ret = gst_pad_event_default (pad, event); + } else { + GST_OBJECT_LOCK (dec); + dec->priv->pending_events = + g_list_append (dec->priv->pending_events, event); + GST_OBJECT_UNLOCK (dec); + ret = TRUE; + } + } GST_DEBUG_OBJECT (dec, "event handled");