audioencoder: Delay sending of serialized events to finish_frame()
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 26 Sep 2011 13:42:14 +0000 (15:42 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 26 Sep 2011 13:42:14 +0000 (15:42 +0200)
This makes sure that the caps are already set before any serialized
events are sent downstream.

gst-libs/gst/audio/gstaudioencoder.c

index 9a3d75c..c5c6524 100644 (file)
@@ -243,6 +243,8 @@ struct _GstAudioEncoderPrivate
 
   /* pending tags */
   GstTagList *tags;
+  /* pending serialized sink events, will be sent from finish_frame() */
+  GList *pending_events;
 };
 
 static void gst_audio_encoder_finalize (GObject * object);
@@ -394,6 +396,10 @@ gst_audio_encoder_reset (GstAudioEncoder * enc, gboolean full)
     if (enc->priv->tags)
       gst_tag_list_free (enc->priv->tags);
     enc->priv->tags = NULL;
+
+    g_list_foreach (enc->priv->pending_events, (GFunc) gst_event_unref, NULL);
+    g_list_free (enc->priv->pending_events);
+    enc->priv->pending_events = NULL;
   }
 
   gst_segment_init (&enc->segment, GST_FORMAT_TIME);
@@ -485,6 +491,19 @@ gst_audio_encoder_finish_frame (GstAudioEncoder * enc, GstBuffer * buf,
   /* mark subclass still alive and providing */
   priv->got_data = TRUE;
 
+  if (priv->pending_events) {
+    GList *pending_events, *l;
+    GST_OBJECT_LOCK (enc);
+    pending_events = priv->pending_events;
+    priv->pending_events = NULL;
+    GST_OBJECT_UNLOCK (enc);
+
+    GST_DEBUG_OBJECT (enc, "Pushing pending events");
+    for (l = priv->pending_events; l; l = l->next)
+      gst_pad_push_event (enc->srcpad, l->data);
+    g_list_free (pending_events);
+  }
+
   /* remove corresponding samples from input */
   if (samples < 0)
     samples = (enc->priv->offset / ctx->info.bpf);
@@ -1192,6 +1211,13 @@ gst_audio_encoder_sink_eventfunc (GstAudioEncoder * enc, GstEvent * event)
         klass->flush (enc);
       /* and get (re)set for the sequel */
       gst_audio_encoder_reset (enc, FALSE);
+
+      GST_OBJECT_LOCK (enc);
+      g_list_foreach (enc->priv->pending_events, (GFunc) gst_event_unref, NULL);
+      g_list_free (enc->priv->pending_events);
+      enc->priv->pending_events = NULL;
+      GST_OBJECT_UNLOCK (enc);
+
       break;
 
     case GST_EVENT_EOS:
@@ -1209,7 +1235,10 @@ gst_audio_encoder_sink_eventfunc (GstAudioEncoder * enc, GstEvent * event)
       gst_tag_list_remove_tag (tags, GST_TAG_AUDIO_CODEC);
       event = gst_event_new_tag (tags);
 
-      gst_pad_push_event (enc->srcpad, event);
+      GST_OBJECT_LOCK (enc);
+      enc->priv->pending_events =
+          g_list_append (enc->priv->pending_events, event);
+      GST_OBJECT_UNLOCK (enc);
       handled = TRUE;
       break;
     }
@@ -1241,8 +1270,27 @@ gst_audio_encoder_sink_event (GstPad * pad, GstEvent * event)
   if (!handled)
     handled = gst_audio_encoder_sink_eventfunc (enc, 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 (enc);
+      enc->priv->pending_events =
+          g_list_append (enc->priv->pending_events, event);
+      GST_OBJECT_UNLOCK (enc);
+      ret = TRUE;
+    }
+  }
 
   GST_DEBUG_OBJECT (enc, "event handled");