gst/playback/: Fix playback of multiple files. a slightly different approach to handl...
authorWim Taymans <wim.taymans@gmail.com>
Tue, 2 Nov 2004 10:30:36 +0000 (10:30 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 2 Nov 2004 10:30:36 +0000 (10:30 +0000)
Original commit message from CVS:
* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
(try_to_link_1), (get_our_ghost_pad), (remove_element_chain),
(unlinked), (no_more_pads), (close_link):
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_init),
(unknown_type), (add_element_stream), (new_decoded_pad),
(removed_decoded_pad), (setup_source):
* gst/playback/gststreaminfo.c: (gst_stream_info_get_type),
(gst_stream_info_class_init), (gst_stream_info_init),
(gst_stream_info_new), (gst_stream_info_dispose),
(stream_info_mute_pad), (gst_stream_info_set_property),
(gst_stream_info_get_property):
* gst/playback/gststreaminfo.h:
Fix playback of multiple files.
a slightly different approach to handling dynamic pad removals.
This one only looks at pads that we have linked.

ChangeLog
gst/playback/gstdecodebin.c
gst/playback/gstplaybasebin.c
gst/playback/gststreaminfo.c
gst/playback/gststreaminfo.h

index 734c8ba..1bdd0e5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2004-11-02  Wim Taymans  <wim@fluendo.com>
+
+       * gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
+       (try_to_link_1), (get_our_ghost_pad), (remove_element_chain),
+       (unlinked), (no_more_pads), (close_link):
+       * gst/playback/gstplaybasebin.c: (gst_play_base_bin_init),
+       (unknown_type), (add_element_stream), (new_decoded_pad),
+       (removed_decoded_pad), (setup_source):
+       * gst/playback/gststreaminfo.c: (gst_stream_info_get_type),
+       (gst_stream_info_class_init), (gst_stream_info_init),
+       (gst_stream_info_new), (gst_stream_info_dispose),
+       (stream_info_mute_pad), (gst_stream_info_set_property),
+       (gst_stream_info_get_property):
+       * gst/playback/gststreaminfo.h:
+       Fix playback of multiple files.
+       a slightly different approach to handling dynamic pad removals.
+       This one only looks at pads that we have linked.
+
 2004-11-01  Christophe Fergeau  <teuf@gnome.org>
 
        * ext/ogg/gstoggdemux.c: (gst_ogg_demux_finalize): fix an "invalid
index 8ceb96b..382a2fa 100644 (file)
@@ -74,10 +74,10 @@ struct _GstDecodeBinClass
 
   /* signal we fire when a new pad has been decoded into raw audio/video */
   void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last);
+  /* signal we fire when a pad has been removed */
+  void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
   /* signal fired when we found a pad that we cannot decode */
   void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
-  /* called on dynamic pad removal */
-  void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
 };
 
 /* props */
@@ -91,8 +91,8 @@ enum
 enum
 {
   SIGNAL_NEW_DECODED_PAD,
-  SIGNAL_UNKNOWN_TYPE,
   SIGNAL_REMOVED_DECODED_PAD,
+  SIGNAL_UNKNOWN_TYPE,
   LAST_SIGNAL
 };
 
@@ -101,6 +101,7 @@ enum
 typedef struct
 {
   gint np_sig_id;               /* signal id of new_pad */
+  gint unlink_sig_id;           /* signal id of unlinked */
   gint nmp_sig_id;              /* signal id of no_more_pads */
   GstElement *element;          /* the element sending the signal */
   GstDecodeBin *decode_bin;     /* pointer to ourself */
@@ -124,6 +125,8 @@ static GstElement *try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad,
 static void close_link (GstElement * element, GstDecodeBin * decode_bin);
 static void close_pad_link (GstElement * element, GstPad * pad,
     GstCaps * caps, GstDecodeBin * decode_bin, gboolean more);
+static void unlinked (GstPad * pad, GstPad * peerpad,
+    GstDecodeBin * decode_bin);
 
 static GstElementClass *parent_class;
 static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
@@ -189,16 +192,16 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
       G_STRUCT_OFFSET (GstDecodeBinClass, new_decoded_pad), NULL, NULL,
       gst_play_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_OBJECT,
       G_TYPE_BOOLEAN);
+  gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD] =
+      g_signal_new ("removed-decoded-pad", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstDecodeBinClass, removed_decoded_pad), NULL, NULL,
+      gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
   gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE] =
       g_signal_new ("unknown-type", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, unknown_type),
       NULL, NULL, gst_marshal_VOID__OBJECT_BOXED, G_TYPE_NONE, 2,
       GST_TYPE_PAD, GST_TYPE_CAPS);
-  gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD] =
-      g_signal_new ("removed-decoded-pad", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstDecodeBinClass, removed_decoded_pad), NULL, NULL,
-      g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
 
   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_decode_bin_dispose);
 
@@ -464,7 +467,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
     /* make an element from the factory first */
     element = gst_element_factory_create (factory, NULL);
     if (element == NULL) {
-      /* hmm, strange */
+      /* hmm, strange. Like with all things in live, let's move on.. */
       GST_WARNING_OBJECT (decode_bin, "could not create  an element from %s",
           gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
       continue;
@@ -474,6 +477,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
     GST_DEBUG_OBJECT (decode_bin, "adding %s", gst_element_get_name (element));
     gst_bin_add (GST_BIN (decode_bin), element);
 
+    /* set to ready first so it can do negotiation */
     gst_element_set_state (element, GST_STATE_READY);
 
     /* keep out own list of elements */
@@ -486,6 +490,10 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
     if (ret) {
       const gchar *klass;
       GstElementFactory *factory;
+      guint sig;
+
+      GST_DEBUG_OBJECT (decode_bin, "linked on pad %s:%s",
+          GST_DEBUG_PAD_NAME (pad));
 
       /* The link worked, now figure out what it was that we connected */
       factory = gst_element_get_factory (element);
@@ -496,6 +504,11 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
           /* FIXME, do something with threads here */
         }
       }
+      /* make sure we catch unlink signals */
+      sig = g_signal_connect (G_OBJECT (pad), "unlinked",
+          G_CALLBACK (unlinked), decode_bin);
+      /* keep a ref to the signal id so that we can disconnect the signal callback */
+      g_object_set_data (G_OBJECT (pad), "unlinked_id", GINT_TO_POINTER (sig));
 
       /* now that we added the element we can try to continue autoplugging
        * on it until we have a raw type */
@@ -504,6 +517,8 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
       gst_element_sync_state_with_parent (element);
       return element;
     } else {
+      GST_DEBUG_OBJECT (decode_bin, "link failed on pad %s:%s",
+          GST_DEBUG_PAD_NAME (pad));
       /* this element did not work, remove it again and continue trying
        * other elements */
       gst_bin_remove (GST_BIN (decode_bin), element);
@@ -512,6 +527,115 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
   return NULL;
 }
 
+static GstPad *
+get_our_ghost_pad (GstDecodeBin * decode_bin, GstPad * pad)
+{
+  GList *ghostpads;
+
+  if (pad == NULL || !GST_PAD_IS_SRC (pad)) {
+    GST_DEBUG_OBJECT (decode_bin, "pad NULL or not SRC pad");
+    return NULL;
+  }
+
+  if (GST_IS_GHOST_PAD (pad)) {
+    GstElement *parent = gst_pad_get_parent (pad);
+
+    GST_DEBUG_OBJECT (decode_bin, "pad parent %s",
+        gst_element_get_name (parent));
+    if (parent == GST_ELEMENT (decode_bin)) {
+      GST_DEBUG_OBJECT (decode_bin, "pad is our ghostpad");
+      return pad;
+    } else {
+      GST_DEBUG_OBJECT (decode_bin, "pad is ghostpad but not ours");
+      return NULL;
+    }
+  }
+
+  GST_DEBUG_OBJECT (decode_bin, "looping over ghostpads");
+  ghostpads = gst_pad_get_ghost_pad_list (pad);
+  while (ghostpads) {
+    GstPad *ghostpad;
+
+    ghostpad = get_our_ghost_pad (decode_bin, GST_PAD (ghostpads->data));
+    if (ghostpad)
+      return ghostpad;
+
+    ghostpads = g_list_next (ghostpads);
+  }
+  GST_DEBUG_OBJECT (decode_bin, "done looping over ghostpads, nothing found");
+
+  return NULL;
+}
+
+/* remove all downstream elements starting from the given pad.
+ * Also make sure to remove the ghostpad we created for the raw 
+ * decoded stream.
+ */
+static void
+remove_element_chain (GstDecodeBin * decode_bin, GstPad * pad)
+{
+  GList *int_links;
+  GstElement *elem = gst_pad_get_parent (pad);
+
+  GST_DEBUG_OBJECT (decode_bin, "%s:%s", GST_DEBUG_PAD_NAME (pad));
+
+  /* remove all elements linked to this pad up to the ghostpad 
+   * that we created for this stream */
+  for (int_links = gst_pad_get_internal_links (pad);
+      int_links; int_links = g_list_next (int_links)) {
+    GstPad *pad;
+    GstPad *ghostpad;
+    GstPad *peer;
+
+    pad = GST_PAD (int_links->data);
+    GST_DEBUG_OBJECT (decode_bin, "inspecting internal pad %s:%s",
+        GST_DEBUG_PAD_NAME (pad));
+
+    ghostpad = get_our_ghost_pad (decode_bin, pad);
+    if (ghostpad) {
+      GST_DEBUG_OBJECT (decode_bin, "found our ghost pad %s:%s for %s:%s",
+          GST_DEBUG_PAD_NAME (ghostpad), GST_DEBUG_PAD_NAME (pad));
+
+      g_signal_emit (G_OBJECT (decode_bin),
+          gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD], 0, ghostpad);
+
+      gst_element_remove_pad (GST_ELEMENT (decode_bin), ghostpad);
+      continue;
+    } else {
+      GST_DEBUG_OBJECT (decode_bin, "not one of our ghostpads");
+    }
+
+    peer = gst_pad_get_peer (pad);
+    if (peer == NULL)
+      continue;
+
+    GST_DEBUG_OBJECT (decode_bin, "internal pad %s:%s linked to pad %s:%s",
+        GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer));
+
+    if (gst_pad_get_real_parent (peer) != GST_ELEMENT (decode_bin)) {
+      GST_DEBUG_OBJECT (decode_bin, "dead end pad %s:%s",
+          GST_DEBUG_PAD_NAME (peer));
+    } else {
+      GST_DEBUG_OBJECT (decode_bin, "recursing element %s on pad %s:%s",
+          gst_element_get_name (elem), GST_DEBUG_PAD_NAME (pad));
+      remove_element_chain (decode_bin, peer);
+    }
+  }
+  GST_DEBUG_OBJECT (decode_bin, "removing %s", gst_element_get_name (elem));
+  gst_bin_remove (GST_BIN (decode_bin), elem);
+}
+
+/* This function will be called when a pad is disconnected for some reason */
+static void
+unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
+{
+  /* inactivate pad */
+  gst_pad_set_active (pad, FALSE);
+
+  /* remove all elements linked to the peerpad */
+  remove_element_chain (decode_bin, peerpad);
+}
+
 /* This function will be called when a dynamic pad is created on an element.
  * We try to continue autoplugging on this new pad. */
 static void
@@ -547,7 +671,7 @@ no_more_pads (GstElement * element, GstDynamic * dynamic)
   decode_bin->dynamics = g_list_remove (decode_bin->dynamics, dynamic);
   g_free (dynamic);
 
-  /* if we have no more dynamic elements, we have no change of creating
+  /* if we have no more dynamic elements, we have no chance of creating
    * more pads, so we fire the no_more_pads signal */
   if (decode_bin->dynamics == NULL) {
     GST_DEBUG_OBJECT (decode_bin,
@@ -558,110 +682,6 @@ no_more_pads (GstElement * element, GstDynamic * dynamic)
   }
 }
 
-/* get unconnected element (after unlink/pad-remove). */
-static GstElement *
-get_unconnected_element (GstDecodeBin * decode_bin)
-{
-  const GList *walk;
-
-  for (walk = gst_bin_get_list (GST_BIN (decode_bin));
-      walk != NULL; walk = walk->next) {
-    GstElement *element = walk->data;
-    const GList *pwalk;
-
-    for (pwalk = gst_element_get_pad_list (GST_ELEMENT (element));
-        pwalk != NULL; pwalk = pwalk->next) {
-      GstPad *pad = pwalk->data;
-
-      if (GST_PAD_IS_SINK (pad) && GST_PAD_PEER (pad) == NULL)
-        return element;
-    }
-  }
-
-  return NULL;
-}
-
-/* remove all elements linked forward from this element on from the bin */
-static void
-remove_starting_from (GstDecodeBin * decode_bin, GstElement * start)
-{
-  const GList *pwalk;
-
-  for (pwalk = gst_element_get_pad_list (start);
-      pwalk != NULL; pwalk = pwalk->next) {
-    GstPad *pad = pwalk->data;
-
-    if (GST_PAD_IS_SRC (pad)) {
-      GstPad *peer = GST_PAD_PEER (pad);
-      GstElement *peer_parent = NULL;
-
-      if (peer)
-        peer_parent = gst_pad_get_parent (peer);
-
-      /* be recursive */
-      if (peer_parent != NULL) {
-        if (gst_object_get_parent (GST_OBJECT (peer_parent))
-            == GST_OBJECT (decode_bin)) {
-          remove_starting_from (decode_bin, peer_parent);
-        } else {
-          /* linked outside us - signal pad removal */
-          g_signal_emit (decode_bin,
-              gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD], 0, pad);
-        }
-      }
-    }
-  }
-
-  /* now remove ourselves */
-  gst_bin_remove (GST_BIN (decode_bin), start);
-}
-
-/* This function will be called for elements with dynamic elements when
- * they remove pads. This might just be because they're disposed, in
- * which case we don't care. It might also be because they're changing
- * chain, in which case we want to re-plug afterwards. */
-
-static void
-pad_removed (GstElement * element, GstPad * pad, GstDecodeBin * decode_bin)
-{
-  GList *walk;
-  GstElement *peer;
-  GstDynamic *dyn;
-
-  /* don't care about disposal - it's really only for replugging.
-   * We only need to check for pending is ready because if pending
-   * is NULL, then state is READY. */
-  if (GST_STATE (element) <= GST_STATE_READY ||
-      GST_STATE_PENDING (element) == GST_STATE_READY)
-    return;
-
-  /* clean up. FIXME: getting peer of removed pad is dirty. */
-  peer = get_unconnected_element (decode_bin);
-  g_assert (peer);
-  remove_starting_from (decode_bin, peer);
-
-  /* if an element removes two pads, then we don't want this twice */
-  for (walk = decode_bin->dynamics; walk != NULL; walk = walk->next) {
-    dyn = walk->data;
-    if (dyn->element == element)
-      return;
-  }
-
-  GST_DEBUG_OBJECT (decode_bin, "pad removal while alive - chained?");
-
-  /* re-setup dynamic plugging */
-  dyn = g_new0 (GstDynamic, 1);
-  dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
-      G_CALLBACK (new_pad), dyn);
-  dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
-      G_CALLBACK (no_more_pads), dyn);
-  dyn->element = element;
-  dyn->decode_bin = decode_bin;
-
-  /* and add this element to the dynamic elements */
-  decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
-}
-
 /* this function inspects the given element and tries to connect something
  * on the srcpads. If there are dynamic pads, it sets up a signal handler to
  * continue autoplugging when they become available */
@@ -751,10 +771,6 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
 
     /* and add this element to the dynamic elements */
     decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
-
-    /* let's keep this one around longer than the lifetime of dynamicity */
-    g_signal_connect (G_OBJECT (element), "pad-removed",
-        G_CALLBACK (pad_removed), decode_bin);
   }
 
   /* Check if this is an element with more than 1 pad. If this element
index 92ef040..256f05b 100644 (file)
@@ -166,7 +166,6 @@ static void
 gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
 {
   play_base_bin->uri = NULL;
-  play_base_bin->threaded = FALSE;
   play_base_bin->need_rebuild = TRUE;
   play_base_bin->source = NULL;
   play_base_bin->decoder = NULL;
@@ -282,6 +281,7 @@ unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
   /* add the stream to the list */
   info = gst_stream_info_new (GST_OBJECT (pad), GST_STREAM_TYPE_UNKNOWN,
       NULL, caps);
+  info->origin = GST_OBJECT (pad);
   play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
 
   g_free (capsstr);
@@ -301,6 +301,7 @@ add_element_stream (GstElement * element, GstPlayBaseBin * play_base_bin)
   info =
       gst_stream_info_new (GST_OBJECT (element), GST_STREAM_TYPE_ELEMENT,
       NULL, NULL);
+  info->origin = GST_OBJECT (element);
   play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
 }
 
@@ -393,6 +394,7 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
 
   /* add the stream to the list */
   info = gst_stream_info_new (GST_OBJECT (srcpad), type, NULL, caps);
+  info->origin = GST_OBJECT (pad);
   play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
 
   /* signal the no more pads after adding the stream */
@@ -400,6 +402,35 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
     no_more_pads (NULL, play_base_bin);
 }
 
+/* signal fired when decodebin has removed a raw pad. We remove
+ * the preroll element if needed and the appropriate streaminfo.
+ */
+static void
+removed_decoded_pad (GstElement * element, GstPad * pad,
+    GstPlayBaseBin * play_base_bin)
+{
+  GList *streams;
+
+  GST_DEBUG ("removing decoded pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+
+  /* first find the stream to decode this pad */
+  streams = play_base_bin->streaminfo;
+  while (streams) {
+    GstStreamInfo *info = GST_STREAM_INFO (streams->data);
+
+    if (info->origin == GST_OBJECT (pad)) {
+      GST_DEBUG ("removing stream %p", info);
+      play_base_bin->streaminfo =
+          g_list_remove (play_base_bin->streaminfo, info);
+      g_object_unref (info);
+      return;
+    } else {
+      GST_DEBUG ("skipping stream %p", info);
+    }
+    streams = g_list_next (streams);
+  }
+}
+
 /*
  * Cache errors...
  */
@@ -448,6 +479,8 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
   if (!play_base_bin->need_rebuild)
     return TRUE;
 
+  play_base_bin->threaded = FALSE;
+
   /* keep ref to old souce in case creating the new source fails */
   old_src = play_base_bin->source;
 
@@ -537,7 +570,7 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
 
   {
     gboolean res;
-    gint sig1, sig2, sig3, sig4, sig5;
+    gint sig1, sig2, sig3, sig4, sig5, sig6;
 
     /* now create the decoder element */
     play_base_bin->decoder = gst_element_factory_make ("decodebin", "decoder");
@@ -559,11 +592,13 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
     }
     sig1 = g_signal_connect (G_OBJECT (play_base_bin->decoder),
         "new-decoded-pad", G_CALLBACK (new_decoded_pad), play_base_bin);
-    sig2 = g_signal_connect (G_OBJECT (play_base_bin->decoder), "no-more-pads",
+    sig2 = g_signal_connect (G_OBJECT (play_base_bin->decoder),
+        "removed-decoded-pad", G_CALLBACK (removed_decoded_pad), play_base_bin);
+    sig3 = g_signal_connect (G_OBJECT (play_base_bin->decoder), "no-more-pads",
         G_CALLBACK (no_more_pads), play_base_bin);
-    sig3 = g_signal_connect (G_OBJECT (play_base_bin->decoder), "unknown-type",
+    sig4 = g_signal_connect (G_OBJECT (play_base_bin->decoder), "unknown-type",
         G_CALLBACK (unknown_type), play_base_bin);
-    sig4 = g_signal_connect (G_OBJECT (play_base_bin->thread), "error",
+    sig5 = g_signal_connect (G_OBJECT (play_base_bin->thread), "error",
         G_CALLBACK (thread_error), error);
 
     /* either when the queues are filled or when the decoder element has no more
@@ -575,7 +610,7 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
       GList *prerolls;
 
       GST_DEBUG ("waiting for preroll...");
-      sig5 = g_signal_connect (G_OBJECT (play_base_bin->thread),
+      sig6 = g_signal_connect (G_OBJECT (play_base_bin->thread),
           "state-change", G_CALLBACK (state_change), play_base_bin);
       g_cond_wait (play_base_bin->preroll_cond, play_base_bin->preroll_lock);
       GST_DEBUG ("preroll done !");
@@ -595,16 +630,18 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
       }
     } else {
       GST_DEBUG ("state change failed, media cannot be loaded");
-      sig5 = 0;
+      sig6 = 0;
     }
     g_mutex_unlock (play_base_bin->preroll_lock);
 
-    if (sig5 != 0)
-      g_signal_handler_disconnect (G_OBJECT (play_base_bin->thread), sig5);
-    g_signal_handler_disconnect (G_OBJECT (play_base_bin->thread), sig4);
+    if (sig6 != 0)
+      g_signal_handler_disconnect (G_OBJECT (play_base_bin->thread), sig6);
+
+    g_signal_handler_disconnect (G_OBJECT (play_base_bin->thread), sig5);
+    g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig4);
     g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig3);
-    g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig2);
-    g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig1);
+    //g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig2);
+    //g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig1);
 
     play_base_bin->need_rebuild = FALSE;
   }
index 4c1b22f..4716f5c 100644 (file)
@@ -147,6 +147,7 @@ static void
 gst_stream_info_init (GstStreamInfo * stream_info)
 {
   stream_info->object = NULL;
+  stream_info->origin = NULL;
   stream_info->type = GST_STREAM_TYPE_UNKNOWN;
   stream_info->decoder = NULL;
   stream_info->mute = FALSE;
@@ -165,6 +166,7 @@ gst_stream_info_new (GstObject * object,
   info->object = object;
   info->type = type;
   info->decoder = g_strdup (decoder);
+  info->origin = object;
   if (caps) {
     info->caps = gst_caps_copy (caps);
   }
@@ -181,6 +183,7 @@ gst_stream_info_dispose (GObject * object)
 
   gst_object_unref (stream_info->object);
   stream_info->object = NULL;
+  stream_info->origin = NULL;
   stream_info->type = GST_STREAM_TYPE_UNKNOWN;
   g_free (stream_info->decoder);
   stream_info->decoder = NULL;
index 41f09a1..b5381ed 100644 (file)
@@ -49,6 +49,7 @@ struct _GstStreamInfo {
   GstStreamType         type;
   gchar        *decoder;
   gboolean      mute;
+  GstObject    *origin;
   GstCaps      *caps;
 };