audiodecoder: Delay sending of serialized events to finish_frame()
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 26 Sep 2011 14:19:42 +0000 (16:19 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 26 Sep 2011 14:19:42 +0000 (16:19 +0200)
gst-libs/gst/audio/gstaudiodecoder.c

index 21c75bc..84729cb 100644 (file)
@@ -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");