gst-plugins-base: decodebin2: Prune old groups before switching to the new one

Sebastian Dröge slomo at kemper.freedesktop.org
Thu Jan 19 00:05:13 PST 2012


Module: gst-plugins-base
Branch: master
Commit: e2a038acee2969ed0b558093fa1c8b7422073e40
URL:    http://cgit.freedesktop.org/gstreamer/gst-plugins-base/commit/?id=e2a038acee2969ed0b558093fa1c8b7422073e40

Author: Youness Alaoui <youness.alaoui at collabora.co.uk>
Date:   Tue Sep 13 23:14:10 2011 +0000

decodebin2: Prune old groups before switching to the new one

In order to allow for proper functionality when a decoder only supports
one instance at a time (dsp), we must block the demuxer pads when they
get created if they are not part of the active group, preventing buffers
from being sent to the decoder (and initializing it through setcaps),
then after we switch to a new group, we unblock the demuxer pads for
the active groups. In the callback for the unblock, we prune the old
groups, making sure the previous decoder instance is destroyed before
we push a buffer to the new instance.

---

 gst/playback/gstdecodebin2.c |  103 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 103 insertions(+), 0 deletions(-)

diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c
index 8bcadde..78b6291 100644
--- a/gst/playback/gstdecodebin2.c
+++ b/gst/playback/gstdecodebin2.c
@@ -446,6 +446,7 @@ static gboolean gst_decode_chain_is_complete (GstDecodeChain * chain);
 static gboolean gst_decode_chain_expose (GstDecodeChain * chain,
     GList ** endpads, gboolean * missing_plugin);
 static gboolean gst_decode_chain_is_drained (GstDecodeChain * chain);
+static void gst_decode_chain_prune (GstDecodeChain * chain);
 static gboolean gst_decode_group_is_complete (GstDecodeGroup * group);
 static GstPad *gst_decode_group_control_demuxer_pad (GstDecodeGroup * group,
     GstPad * pad);
@@ -2320,6 +2321,16 @@ pad_event_cb (GstPad * pad, GstEvent * event, gpointer data)
 }
 
 static void
+demuxer_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodeChain * chain)
+{
+  GstDecodeBin *dbin;
+
+  dbin = chain->dbin;
+  if (!blocked)
+    gst_decode_chain_prune (dbin->decode_chain);
+}
+
+static void
 pad_added_cb (GstElement * element, GstPad * pad, GstDecodeChain * chain)
 {
   GstCaps *caps;
@@ -2335,6 +2346,27 @@ pad_added_cb (GstElement * element, GstPad * pad, GstDecodeChain * chain)
     gst_caps_unref (caps);
 
   EXPOSE_LOCK (dbin);
+  CHAIN_MUTEX_LOCK (chain);
+  if (chain->demuxer &&
+      ((GstDecodeElement *) chain->elements->data)->element == element) {
+    GList *l;
+
+    for (l = chain->next_groups; l; l = l->next) {
+      GstDecodeGroup *group = l->data;
+      GList *l2;
+
+      for (l2 = group->children; l2; l2 = l2->next) {
+        GstDecodeChain *child_chain = l2->data;
+
+        if (!gst_pad_is_blocked (child_chain->pad)) {
+          GST_DEBUG_OBJECT (pad, "blocking next group's pad %p", pad);
+          gst_pad_set_blocked_async (child_chain->pad, TRUE,
+              (GstPadBlockCallback) demuxer_pad_blocked_cb, chain);
+        }
+      }
+    }
+  }
+  CHAIN_MUTEX_UNLOCK (chain);
   if (gst_decode_chain_is_complete (dbin->decode_chain)) {
     GST_LOG_OBJECT (dbin,
         "That was the last dynamic object, now attempting to expose the group");
@@ -2867,6 +2899,76 @@ gst_decode_group_hide (GstDecodeGroup * group)
   gst_decode_group_free_internal (group, TRUE);
 }
 
+static void
+gst_decode_group_prune (GstDecodeGroup * group)
+{
+  GList *l;
+
+  GST_DEBUG_OBJECT (group->dbin, "Pruning group %p", group);
+
+  for (l = group->children; l; l = l->next) {
+    GstDecodeChain *chain = (GstDecodeChain *) l->data;
+
+    gst_decode_chain_prune (chain);
+  }
+
+  GST_DEBUG_OBJECT (group->dbin, "Pruned group %p", group);
+}
+
+static void
+gst_decode_chain_prune (GstDecodeChain * chain)
+{
+  GList *l;
+
+  CHAIN_MUTEX_LOCK (chain);
+
+  GST_DEBUG_OBJECT (chain->dbin, "Pruning chain %p", chain);
+
+  if (chain->active_group)
+    gst_decode_group_prune (chain->active_group);
+
+  for (l = chain->next_groups; l; l = l->next) {
+    gst_decode_group_prune ((GstDecodeGroup *) l->data);
+  }
+
+  for (l = chain->old_groups; l; l = l->next) {
+    GstDecodeGroup *group = l->data;
+
+    /* This calls set_state(NULL) on the old elements and we're
+     * the streaming thread but this is one of the few cases
+     * when this is possible. It's guaranteed at this point
+     * that *this* streaming thread is not inside the elements
+     * currently, because it's *here* now or a different streaming
+     * thread is used for the elements.
+     */
+    gst_decode_group_free (group);
+  }
+  g_list_free (chain->old_groups);
+  chain->old_groups = NULL;
+
+  GST_DEBUG_OBJECT (chain->dbin, "Pruned chain %p", chain);
+  CHAIN_MUTEX_UNLOCK (chain);
+}
+
+static void
+unblock_demuxer_pads (GstDecodeChain * chain)
+{
+  GList *l;
+
+  GST_DEBUG_OBJECT (chain->dbin, "Unblocking demuxer pad for chain %p", chain);
+
+  if (gst_pad_is_blocked (chain->pad))
+    gst_pad_set_blocked_async (chain->pad, FALSE,
+        (GstPadBlockCallback) demuxer_pad_blocked_cb, chain);
+  if (chain->active_group) {
+    for (l = chain->active_group->children; l; l = l->next) {
+      GstDecodeChain *child_chain = l->data;
+
+      unblock_demuxer_pads (child_chain);
+    }
+  }
+}
+
 /* configure queue sizes, this depends on the buffering method and if we are
  * playing or prerolling. */
 static void
@@ -3241,6 +3343,7 @@ gst_decode_pad_handle_eos (GstDecodePad * pad)
     EXPOSE_LOCK (dbin);
     if (gst_decode_chain_is_complete (dbin->decode_chain))
       gst_decode_bin_expose (dbin);
+    unblock_demuxer_pads (dbin->decode_chain);
     EXPOSE_UNLOCK (dbin);
   }
 



More information about the gstreamer-commits mailing list