major rewrite of the spider.
authorBenjamin Otte <otte@gnome.org>
Mon, 11 Feb 2002 08:18:09 +0000 (08:18 +0000)
committerBenjamin Otte <otte@gnome.org>
Mon, 11 Feb 2002 08:18:09 +0000 (08:18 +0000)
Original commit message from CVS:
major rewrite of the spider.
Now uses GstSpiderConnection to track current connections and remember the way they're plugged.
Advantages of this approach:
- function prototypes are now much cleaner.
- Allow event propagation (EOS) to elements that are not connected but plugged.
- Allow deconstruction of plugged pipes. (not implemented)
Disadvantage:
- I screwed up naming (always get src and sink the wrong way). It's very inconsistent in the gstspider.[ch] files
- a little more time and memory are needed to manage the structs

gst/autoplug/gstsearchfuncs.c
gst/autoplug/gstspider.c
gst/autoplug/gstspider.h
gst/autoplug/gstspideridentity.c

index 42d496d..97ef02a 100644 (file)
@@ -309,6 +309,9 @@ gst_autoplug_sp (GstCaps *srccaps, GstCaps *sinkcaps, GList *factories)
   guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */
   GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */
   
   guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */
   GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */
   
+  g_return_val_if_fail (srccaps != NULL, NULL);
+  g_return_val_if_fail (sinkcaps != NULL, NULL);
+  
   GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, "attempting to autoplug via shortest path from %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps));
   /* wrap all factories as GstAutoplugNode 
    * initialize the cost */
   GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, "attempting to autoplug via shortest path from %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps));
   /* wrap all factories as GstAutoplugNode 
    * initialize the cost */
index 9e74877..91f7822 100644 (file)
@@ -71,26 +71,43 @@ GST_PADTEMPLATE_FACTORY (spider_sink_factory,
   GST_PAD_REQUEST,
   NULL      /* no caps */
 );
   GST_PAD_REQUEST,
   NULL      /* no caps */
 );
+
+
+
 /* standard GObject stuff */
 /* standard GObject stuff */
-static void                        gst_spider_class_init                        (GstSpiderClass *klass);
-static void                        gst_spider_init                              (GstSpider *spider);
-static void                        gst_spider_dispose                           (GObject *object);
+static void                     gst_spider_class_init                   (GstSpiderClass *klass);
+static void                     gst_spider_init                         (GstSpider *spider);
+static void                     gst_spider_dispose                      (GObject *object);
 
 /* element class functions */
 
 /* element class functions */
-static GstPad*                     gst_spider_request_new_pad                   (GstElement *element, GstPadTemplate *templ, const gchar *name);
-static void                        gst_spider_set_property                      (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void                        gst_spider_get_property                      (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static GstPad*                  gst_spider_request_new_pad              (GstElement *element, GstPadTemplate *templ, const gchar *name);
+static void                    gst_spider_set_property                 (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void                    gst_spider_get_property                 (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+/* connection functions */
+static GstSpiderConnection *   gst_spider_connection_new               (GstSpiderIdentity *sink, GstSpiderIdentity *src);
+static void                    gst_spider_connection_destroy           (GstSpiderConnection *conn);
+static void                    gst_spider_connection_reset             (GstSpiderConnection *conn, GstElement *to);
+static void                    gst_spider_connection_add               (GstSpiderConnection *conn, GstElement *element);
+static GstSpiderConnection *   gst_spider_connection_find              (GstSpiderIdentity *sink, GstSpiderIdentity *src);
+static GstSpiderConnection *   gst_spider_connection_get               (GstSpiderIdentity *sink, GstSpiderIdentity *src);
 
 /* autoplugging functions */
 
 /* autoplugging functions */
-static GstElement *                gst_spider_find_element_to_plug              (GstElement *src, GstElementFactory *fac, GstPadDirection dir);
-static GstPadConnectReturn         gst_spider_plug_peers                       (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad);
-static GstPadConnectReturn         gst_spider_create_and_plug                   (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath);
+static GstElement *             gst_spider_find_element_to_plug        (GstElement *src, GstElementFactory *fac, GstPadDirection dir);
+static GstPadConnectReturn     gst_spider_plug                         (GstSpiderConnection *conn);
+static GstPadConnectReturn     gst_spider_plug_from_srcpad             (GstSpiderConnection *conn, GstPad *srcpad);
+//static GstPadConnectReturn      gst_spider_plug_peers                        (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad);
+static GstPadConnectReturn     gst_spider_create_and_plug              (GstSpiderConnection *conn, GList *plugpath);
 
 /* random functions */
 
 /* random functions */
-static gchar *                    gst_spider_unused_elementname                 (GstBin *bin, const gchar *startwith);
+static gchar *                 gst_spider_unused_elementname           (GstBin *bin, const gchar *startwith);
+
+/* debugging stuff
+static void                    print_spider_contents                   (GstSpider *spider);
+static void                    print_spider_connection                 (GstSpiderConnection *conn); */
 
 /* === variables === */
 
 /* === variables === */
-static                             GstElementClass                               *parent_class = NULL;
+static                          GstElementClass        *                       parent_class = NULL;
 
 /* no signals yet
 static guint gst_spider_signals[LAST_SIGNAL] = { 0 };*/
 
 /* no signals yet
 static guint gst_spider_signals[LAST_SIGNAL] = { 0 };*/
@@ -145,6 +162,8 @@ gst_spider_init (GstSpider *spider)
   /* use only elements which have sources and sinks and where the sinks have caps */
   /* FIXME: How do we handle factories that are added after the spider was constructed? */
   spider->factories = gst_autoplug_factories_filters_with_sink_caps ((GList *) gst_elementfactory_get_list ());
   /* use only elements which have sources and sinks and where the sinks have caps */
   /* FIXME: How do we handle factories that are added after the spider was constructed? */
   spider->factories = gst_autoplug_factories_filters_with_sink_caps ((GList *) gst_elementfactory_get_list ());
+
+  spider->connections = NULL;
 }
 
 static void
 }
 
 static void
@@ -261,134 +280,121 @@ gst_spider_unused_elementname (GstBin *bin, const gchar *startwith)
   
   return name;
 }
   
   return name;
 }
-/* callback and struct for the data supplied to the callback that is used to connect dynamic pads */
-typedef struct {
-  GstSpider *spider;
-  GstElement *sink;
-  gulong signal_id;
-} GstSpiderConnectSometimes;
 static void
 static void
-gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnectSometimes *data)
+gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnection *conn)
 {
   gboolean restart = FALSE;
 {
   gboolean restart = FALSE;
-  GstPad *sinkpad;
-  GList *sinkpads = gst_element_get_pad_list (data->sink);
+  gulong signal_id = conn->signal_id;
+  GstPad *sinkpad = conn->src->sink;
+  GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (conn->sink));
   
   
-  if (gst_element_get_state ((GstElement *) data->spider) == GST_STATE_PLAYING)
+  /* check if restarting is necessary */
+  if (gst_element_get_state ((GstElement *) spider) == GST_STATE_PLAYING)
   {
     restart = TRUE;
   {
     restart = TRUE;
-    gst_element_set_state ((GstElement *) data->spider, GST_STATE_PAUSED);
+    gst_element_set_state ((GstElement *) spider, GST_STATE_PAUSED);
   }
   }
+  
   /* try to autoplug the elements */
   /* try to autoplug the elements */
-  while (sinkpads)
-  {
-    sinkpad = (GstPad *) sinkpads->data;
-    if ((GST_RPAD_DIRECTION (sinkpad) == GST_PAD_SINK) && gst_spider_plug_peers (data->spider, pad, sinkpad) != GST_PAD_CONNECT_REFUSED) {
-      GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%s:%s was autoplugged to %s:%s, removing callback\n", GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (sinkpad));
-      g_signal_handler_disconnect (src, data->signal_id);
-      /* do the restarting here, because we want to free the data */
-      if (restart)
-      {
-       gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING);
-      }
-      restart = FALSE;
-      g_free (data);
-      break;
-    }
-    sinkpads = g_list_next (sinkpads);
+  if (gst_spider_plug_from_srcpad (conn, pad) != GST_PAD_CONNECT_REFUSED) {
+    GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%s:%s was autoplugged to %s:%s, removing callback\n", GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (sinkpad));
+    g_signal_handler_disconnect (src, signal_id);
+    signal_id = 0;
   }
   }
+  
+  /* restart if needed */
   if (restart)
   {
   if (restart)
   {
-    gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING);
+    gst_element_set_state ((GstElement *) spider, GST_STATE_PLAYING);
   }
   }
-  /* do we need this? */
-  gst_element_interrupt (src);
 }
 }
-/* connects newsrc to newsink using the elementfactories in plugpath */
-static GstPadConnectReturn
-gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath)
+/* create a new connection from those two elements */
+static GstSpiderConnection *
+gst_spider_connection_new (GstSpiderIdentity *sink, GstSpiderIdentity *src)
 {
 {
-  GstElement *element;
+  GstSpider *spider;
+  
+  GstSpiderConnection *conn = g_new0 (GstSpiderConnection, 1);
+  conn->src = src;
+  conn->sink = sink;
+  conn->current = (GstElement *) sink;
+  conn->path = NULL;
+  spider = GST_SPIDER (GST_OBJECT_PARENT (src));
+  spider->connections = g_list_prepend (spider->connections, conn);
   
   
-  /* g_print ("C&P: from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); */
-  /* get the next element */
-  if (plugpath == NULL)
+  return conn;
+}
+static void
+gst_spider_connection_destroy (GstSpiderConnection *conn)
+{
+  /* reset connection to unplugged */
+  gst_spider_connection_reset (conn, (GstElement *) conn->sink);
+  g_free (conn);
+}
+static void
+gst_spider_connection_reset (GstSpiderConnection *conn, GstElement *to)
+{
+  GST_DEBUG (GST_CAT_AUTOPLUG, "resetting connection from %s to %s, currently at %s to %s\n", GST_ELEMENT_NAME (conn->sink), 
+            GST_ELEMENT_NAME (conn->src), GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (to));
+  while ((conn->path != NULL) && ((GstElement *) conn->path->data != to))
   {
   {
-    element = sink;
-  } else {
-    element = gst_elementfactory_create ((GstElementFactory *) plugpath->data, 
-                             gst_spider_unused_elementname (GST_BIN (spider), GST_OBJECT_NAME (plugpath->data)));
-    gst_bin_add (GST_BIN (spider), element);
-    /* g_print ("C&P: trying element %s\n", GST_ELEMENT_NAME (element)); */
+    gst_object_unref ((GstObject *) conn->path->data);
+    conn->path = g_list_delete_link (conn->path, conn->path);
   }
   }
-  /* insert and connect new element */
-  if (!gst_element_connect_elements (src, element))
+  if (conn->path == NULL)
   {
   {
-    /* check if the src has SOMETIMES templates. If so, connect a callback */
-    GList *templs = gst_element_get_padtemplate_list (src);
-        
-    /* remove element that couldn't be connected, if it wasn't the endpoint */
-    if (element != sink)
-      gst_bin_remove (GST_BIN (spider), element);
-    
-    while (templs) {
-      GstPadTemplate *templ = (GstPadTemplate *) templs->data;
-      if ((GST_PADTEMPLATE_DIRECTION (templ) == GST_PAD_SRC) && (GST_PADTEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES))
-      {
-       GstSpiderConnectSometimes *data = g_new (GstSpiderConnectSometimes, 1);
-        GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "adding callback to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
-       data->spider = spider;
-       data->sink = sink;
-       data->signal_id = g_signal_connect (G_OBJECT (src), "new_pad", 
-                                           G_CALLBACK (gst_spider_connect_sometimes), data);
-       return GST_PAD_CONNECT_DELAYED;
-      }
-      templs = g_list_next (templs);
-    }
-    GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
-    return GST_PAD_CONNECT_REFUSED;
-  }
-  GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "added element %s and attached it to element %s\n", GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (src));
-  plugpath = g_list_next (plugpath);
-  
-  /* recursively connect the rest of the elements */
-  if (element != sink) {
-    return gst_spider_create_and_plug (spider, element, sink, plugpath);
+    conn->current = (GstElement *) conn->sink;
+  } else {
+    conn->current = to;
   }
   }
-  
-  return GST_PAD_CONNECT_DONE;
 }
 }
-/* checks, if src is already connected to an element from factory fac on direction dir */
-static GstElement *
-gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir)
+/* add an element to the connection */
+static void
+gst_spider_connection_add (GstSpiderConnection *conn, GstElement *element)
 {
 {
-  GList *padlist = GST_ELEMENT_PADS (src);
+  gst_object_ref ((GstObject *) element);
+  gst_object_sink ((GstObject *) element);
+  conn->path = g_list_prepend (conn->path, element);
+  conn->current = element;
+}
+/* find the connection from those two elements */
+static GstSpiderConnection *
+gst_spider_connection_find (GstSpiderIdentity *sink, GstSpiderIdentity *src)
+{
+  GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (src);
+  GList *list = spider->connections;
   
   
-  while (padlist)
+  g_assert (spider == (GstSpider *) GST_OBJECT_PARENT (sink));
+  
+  while (list)
   {
   {
-    GstPad *pad = (GstPad *) GST_PAD_REALIZE (padlist->data);
-    /* is the pad on the right side and is it connected? */
-    if ((GST_PAD_DIRECTION (pad) == dir) && (pad = GST_PAD (GST_RPAD_PEER (pad))))
-    {
-      /* is the element the pad is connected to of the right type? */
-      GstElement *element = GST_PAD_PARENT (pad);
-      if (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))->elementfactory == fac) {
-        return element;
-      }
-    }
-    padlist = g_list_next (padlist);
+    GstSpiderConnection *conn = (GstSpiderConnection *) list->data;
+    if (conn->src == src && conn->sink == sink)
+      return conn;
+    list = g_list_next(list);
   }
   }
-  
   return NULL;
 }
   return NULL;
 }
-/* plugs a pad into the autoplugger if it isn't plugged yet */
-void
-gst_spider_plug (GstSpiderIdentity *ident)
+/* get a new connection from those two elements
+ * search first; if none is found, create a new one */
+static GstSpiderConnection *
+gst_spider_connection_get (GstSpiderIdentity *sink, GstSpiderIdentity *src)
+{
+  GstSpiderConnection *ret;
+  
+  if ((ret = gst_spider_connection_find (sink, src)) != NULL)
+  {
+    return ret;
+  }
+  return gst_spider_connection_new (sink, src);
+}  
+void                   
+gst_spider_identity_plug (GstSpiderIdentity *ident)
 {
   GstSpider *spider;
 {
   GstSpider *spider;
-  GList *plugto;
-  GstPad *plugpad;
+  GList *padlist;
+  GstPadDirection dir;
+  GstSpiderConnection *conn;
   
   /* checks */
   g_return_if_fail (ident != NULL);
   
   /* checks */
   g_return_if_fail (ident != NULL);
@@ -397,23 +403,24 @@ gst_spider_plug (GstSpiderIdentity *ident)
   g_assert (spider != NULL);
   g_assert (GST_IS_SPIDER (spider));
   
   g_assert (spider != NULL);
   g_assert (GST_IS_SPIDER (spider));
   
-  /* return, if we're already plugged */
+  /* return if we're already plugged */
   if (ident->plugged) return;
   if (ident->plugged) return;
-  
-  if (ident->sink && GST_PAD_PEER (ident->sink))
+
+  /* get the direction of our ident */
+  if (GST_PAD_PEER (ident->sink))
   {
   {
-    if (ident->src && GST_PAD_PEER (ident->src))
+    if (GST_PAD_PEER (ident->src))
     {
       /* Hey, the ident is connected on both sides */
       g_warning ("Trying to autoplug a connected element. Aborting...");
       return;
     } else {
     {
       /* Hey, the ident is connected on both sides */
       g_warning ("Trying to autoplug a connected element. Aborting...");
       return;
     } else {
-      plugpad = ident->sink;
+      dir = GST_PAD_SINK;
     }
   } else {
     }
   } else {
-    if (ident->src && GST_PAD_PEER (ident->src))
+    if (GST_PAD_PEER (ident->src))
     {
     {
-      plugpad = ident->src;
+      dir = GST_PAD_SRC;
     } else {
       /* the ident isn't connected on either side */
       g_warning ("Trying to autoplug an unconnected element. Aborting...");
     } else {
       /* the ident isn't connected on either side */
       g_warning ("Trying to autoplug an unconnected element. Aborting...");
@@ -421,66 +428,204 @@ gst_spider_plug (GstSpiderIdentity *ident)
     }
   }
 
     }
   }
 
-  /* now iterate all possible pads and connect */
-  plugto = gst_element_get_pad_list (GST_ELEMENT (spider));
-  while (plugto)
+  /* now iterate all possible pads and connect when needed */
+  padlist = gst_element_get_pad_list (GST_ELEMENT (spider));
+  while (padlist)
   {
   {
-    GstPad *otherpad = (GstPad *) GST_GPAD_REALPAD (plugto->data);
+    GstPad *otherpad = (GstPad *) GST_GPAD_REALPAD (padlist->data);
     GstSpiderIdentity *peer = (GstSpiderIdentity *) GST_PAD_PARENT (otherpad);
     /* we only want to connect to the other side */
     GstSpiderIdentity *peer = (GstSpiderIdentity *) GST_PAD_PARENT (otherpad);
     /* we only want to connect to the other side */
-    if (GST_PAD_DIRECTION (plugpad) != GST_PAD_DIRECTION (otherpad))
+    if (dir != GST_PAD_DIRECTION (otherpad))
     {
       /* we only connect to plugged in elements */
       if (peer->plugged == TRUE) 
       {
         /* plug in the right direction */
     {
       /* we only connect to plugged in elements */
       if (peer->plugged == TRUE) 
       {
         /* plug in the right direction */
-        if (plugpad == ident->src)
+        if (dir == GST_PAD_SINK)
         {
         {
-          gst_spider_plug_peers (spider, peer->src, ident->sink);
+         conn = gst_spider_connection_get (ident, peer);
         } else {
         } else {
-          gst_spider_plug_peers (spider, ident->src, peer->sink);
+         conn = gst_spider_connection_get (peer, ident);
         }
         }
+       if ((GstElement *) conn->sink == conn->current)
+       {
+         gst_spider_plug (conn);
+       }
       }
     }
       }
     }
-    plugto = g_list_next (plugto);
+    padlist = g_list_next (padlist);
   }
   
   }
   
-  ident->plugged = TRUE;
+  ident->plugged = TRUE; 
 }
 }
-/* connect the src Identity element to the sink identity element
- * Returns: DONE, if item could be plugged, DELAYED, if a callback is needed or REFUSED,
- * if no connection was possible
- */
+void
+gst_spider_identity_unplug (GstSpiderIdentity *ident)
+{
+  GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (ident);
+  GList *list = spider->connections;
+  
+  while (list)
+  {
+    GstSpiderConnection *conn = list->data;
+    GList *cur = list;
+    list = g_list_next (list);
+    if ((conn->src == ident) || (conn->sink == ident))
+    {
+      g_list_delete_link (spider->connections, cur);
+      gst_spider_connection_destroy (conn);
+    }
+  }
+  ident->plugged = FALSE;
+}
+/* connects src to sink using the elementfactories in plugpath
+ * plugpath will be removed afterwards */
 static GstPadConnectReturn
 static GstPadConnectReturn
-gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad)
+gst_spider_create_and_plug (GstSpiderConnection *conn, GList *plugpath)
 {
 {
-  GstElement *element, *src, *sink, *newsrc, *newsink;
+  GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->sink);
+  GList *endelements = NULL, *templist = NULL;
+  GstElement *element;
+  
+  /* exit if plugging is already done */
+  if ((GstElement *) conn->src == conn->current)
+    return GST_PAD_CONNECT_DONE;
+  
+  /* try to shorten the list at the end and not duplicate connection code */
+  if (plugpath != NULL)
+  {
+    templist = g_list_last (plugpath);
+    element = (GstElement *) conn->src;
+    while ((plugpath != NULL) && (element = gst_spider_find_element_to_plug (element, (GstElementFactory *) plugpath->data, GST_PAD_SINK)))
+    {
+      GList *cur = templist;
+      endelements = g_list_prepend (endelements, element);
+      templist = g_list_previous (templist);
+      g_list_delete_link (cur, cur);    
+    }
+  }
+  
+  /* do the connecting */
+  while (conn->current != (GstElement *) (endelements == NULL ? conn->src : endelements->data))
+  {
+    /* get sink element to plug, src is conn->current */
+    if (plugpath == NULL)
+    {
+      element = (GstElement *) (endelements == NULL ? conn->src : endelements->data);
+    } else {
+      element = gst_elementfactory_create ((GstElementFactory *) plugpath->data, 
+                             gst_spider_unused_elementname (GST_BIN (spider), GST_OBJECT_NAME (plugpath->data)));
+      gst_bin_add (GST_BIN (spider), element);
+    }
+    /* insert and connect new element */
+    if (!gst_element_connect_elements (conn->current, element))
+    {
+      /* check if the src has SOMETIMES templates. If so, connect a callback */
+      GList *templs = gst_element_get_padtemplate_list (conn->current);
+        
+      /* remove element that couldn't be connected, if it wasn't the endpoint */
+      if (element != (GstElement *) conn->src)
+        gst_bin_remove (GST_BIN (spider), element);
+    
+      while (templs) {
+        GstPadTemplate *templ = (GstPadTemplate *) templs->data;
+        if ((GST_PADTEMPLATE_DIRECTION (templ) == GST_PAD_SRC) && (GST_PADTEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES))
+        {
+          GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "adding callback to connect element %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
+          conn->signal_id = g_signal_connect (G_OBJECT (conn->current), "new_pad", 
+                                             G_CALLBACK (gst_spider_connect_sometimes), conn);
+         g_list_free (plugpath);
+         return GST_PAD_CONNECT_DELAYED;
+        }
+        templs = g_list_next (templs);
+      }
+      GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to connect element %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
+      g_list_free (plugpath);
+      return GST_PAD_CONNECT_REFUSED;
+    }
+    GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "added element %s and attached it to element %s\n", GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (conn->current));
+    gst_spider_connection_add (conn, element);
+    if (plugpath != NULL)
+      plugpath = g_list_delete_link (plugpath, plugpath);
+  }
+  
+  /* ref all elements at the end */
+  while (endelements)
+  {
+    gst_spider_connection_add (conn, endelements->data);
+    endelements = g_list_delete_link (endelements, endelements);
+  }
+  
+  return GST_PAD_CONNECT_DONE;
+}
+/* checks, if src is already connected to an element from factory fac on direction dir */
+static GstElement *
+gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir)
+{
+  GList *padlist = GST_ELEMENT_PADS (src);
+  
+  while (padlist)
+  {
+    GstPad *pad = (GstPad *) GST_PAD_REALIZE (padlist->data);
+    /* is the pad on the right side and is it connected? */
+    if ((GST_PAD_DIRECTION (pad) == dir) && (pad = GST_PAD (GST_RPAD_PEER (pad))))
+    {
+      /* is the element the pad is connected to of the right type? */
+      GstElement *element = GST_PAD_PARENT (pad);
+      if (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))->elementfactory == fac) {
+        return element;
+      }
+    }
+    padlist = g_list_next (padlist);
+  }
+  
+  return NULL;
+}
+/* try to establish the connection */
+static GstPadConnectReturn
+gst_spider_plug        (GstSpiderConnection *conn)
+{
+  if ((GstElement *) conn->src == conn->current)
+    return GST_PAD_CONNECT_DONE;
+  if ((GstElement *) conn->sink == conn->current)
+    return gst_spider_plug_from_srcpad (conn, conn->sink->src);
+  g_warning ("FIXME: autoplugging only possible from GstSpiderIdentity conn->sink yet (yep, that's technical)\n");
+  return GST_PAD_CONNECT_REFUSED;
+}
+/* try to establish the connection using this pad */
+static GstPadConnectReturn
+gst_spider_plug_from_srcpad (GstSpiderConnection *conn, GstPad *srcpad)
+{
+  GstElement *element;
   GList *plugpath;
   GList *templist;
   gboolean result = TRUE;
   GList *plugpath;
   GList *templist;
   gboolean result = TRUE;
-  
-  GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug from %s:%s to %s:%s\n", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
-  
-  /* get src and sink element */
-  src = (GstElement *) GST_PAD_PARENT (srcpad);
-  sink = (GstElement *) GST_PAD_PARENT (sinkpad);
+  GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src);
+  GstElement *startelement = conn->current;
 
 
-  /* find a path from src to sink */
-  plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (sinkpad), spider->factories);
+  g_assert ((GstElement *) GST_OBJECT_PARENT (srcpad) == conn->current);
+  GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug from %s:%s to %s\n", GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (conn->src));
   
   
+  /* find a path from src to sink */
+  /* FIXME: make that if go away and work anyway */
+  if (srcpad == conn->sink->src)
+  {
+    plugpath = gst_autoplug_sp (gst_pad_get_caps ((GstPad *) GST_RPAD_PEER (conn->sink->sink)), gst_pad_get_caps (conn->src->sink), spider->factories);
+  } else {
+    plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (conn->src->sink), spider->factories);
+  }
   
   
-  /* prints out the path that was found for plugging
+  /* prints out the path that was found for plugging */
+  /* g_print ("found path from %s to %s:\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
   templist = plugpath;
   while (templist)
   {
     g_print("%s\n", GST_OBJECT_NAME (templist->data));
     templist = g_list_next (templist);
   templist = plugpath;
   while (templist)
   {
     g_print("%s\n", GST_OBJECT_NAME (templist->data));
     templist = g_list_next (templist);
-  } */
+  }*/
     
     
-  
   /* if there is no way to plug: return */
   if (plugpath == NULL) {
   /* if there is no way to plug: return */
   if (plugpath == NULL) {
-    GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to plug from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
+    GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to plug from %s to %s\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
     return GST_PAD_CONNECT_REFUSED;
   }
   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a connection that needs %d elements\n", g_list_length (plugpath));
     return GST_PAD_CONNECT_REFUSED;
   }
   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a connection that needs %d elements\n", g_list_length (plugpath));
@@ -489,29 +634,22 @@ gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad)
    * alter src to point to the new element where we need to start 
    * plugging and alter the plugpath to represent the elements, that must be plugged
    */
    * alter src to point to the new element where we need to start 
    * plugging and alter the plugpath to represent the elements, that must be plugged
    */
-  newsrc = src;
-  while ((element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC)))
+  element = conn->current;
+  while ((plugpath != NULL) && (element = gst_spider_find_element_to_plug (element, (GstElementFactory *) plugpath->data, GST_PAD_SRC)))
   {
   {
-    newsrc = element;
+    gst_spider_connection_add (conn, element);
     plugpath = g_list_delete_link (plugpath, plugpath);
   }
     plugpath = g_list_delete_link (plugpath, plugpath);
   }
-  /* now do the same at the end */
-  newsink = sink;
-  templist = g_list_last (plugpath);
-  while ((element = gst_spider_find_element_to_plug (newsink, (GstElementFactory *) plugpath->data, GST_PAD_SINK)))
-  {
-    GList *cur = templist;
-    newsink = element;
-    templist = g_list_previous (templist);
-    g_list_delete_link (cur, cur);    
-  }
   
   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%d elements must be inserted to establish the connection\n", g_list_length (plugpath));
   /* create the elements and plug them */
   
   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "%d elements must be inserted to establish the connection\n", g_list_length (plugpath));
   /* create the elements and plug them */
-  result = gst_spider_create_and_plug (spider, newsrc, newsink, plugpath);
-
-  /* free no longer needed data */
-  g_list_free (plugpath);
+  result = gst_spider_create_and_plug (conn, plugpath);
+  
+  /* reset the "current" element */
+  if (result == GST_PAD_CONNECT_REFUSED)
+  {
+     gst_spider_connection_reset (conn, startelement);
+  }
   
   return result;  
 }
   
   return result;  
 }
index 3632992..a59996b 100644 (file)
@@ -32,6 +32,31 @@ extern "C" {
        
 extern GstElementDetails gst_spider_details;
 
        
 extern GstElementDetails gst_spider_details;
 
+/**
+ * Theory of operation:
+ * When connecting a sink to a source, GstSpiderConnections are used to keep track
+ * of the current status of the connection. sink -> src is the path we intend to
+ * plug. current is how far we've come. If current equals
+ * - NULL, there is no possible path, 
+ * - src, the connection is established.
+ * - sink, it wasn't tried to establish a connection.
+ * - something else, we have come that far while plugging.
+ * signal_id is used to remember the signal_id when we are waiting for a "new_pad"
+ * callback during connection.
+ * When a path is established, the elements in the path (excluding sink and src)
+ * are refcounted once for every path.
+ * A GstSpider keeps a list of all GstSpiderConnections in it.
+ */
+typedef struct {
+  GstSpiderIdentity *sink;
+  GstSpiderIdentity *src;
+  /* dunno if the path should stay here or if its too much load.
+   * it's at least easier then always searching it */
+  GList *path;
+  GstElement *current;
+  gulong signal_id;
+} GstSpiderConnection;
+
 #define GST_TYPE_SPIDER \
   (gst_spider_get_type())
 #define GST_SPIDER(obj) \
 #define GST_TYPE_SPIDER \
   (gst_spider_get_type())
 #define GST_SPIDER(obj) \
@@ -49,7 +74,9 @@ typedef struct _GstSpiderClass GstSpiderClass;
 struct _GstSpider {
   GstBin        parent;
        
 struct _GstSpider {
   GstBin        parent;
        
-  GList *      factories; /* factories to use for plugging */          
+  GList *      factories; /* factories to use for plugging */
+
+  GList *      connections; /* GStSpiderConnection list of all connections */
 };
        
 struct _GstSpiderClass {
 };
        
 struct _GstSpiderClass {
@@ -59,8 +86,9 @@ struct _GstSpiderClass {
 /* default initialization stuff */
 GType          gst_spider_get_type             (void);
 
 /* default initialization stuff */
 GType          gst_spider_get_type             (void);
 
-/* private functions to be called by GstSpiderIdentity */
-void           gst_spider_plug                 (GstSpiderIdentity *ident);
+/* private connection functions to be called by GstSpiderIdentity */
+void           gst_spider_identity_plug        (GstSpiderIdentity *ident);
+void           gst_spider_identity_unplug      (GstSpiderIdentity *ident);
 
        
 #ifdef __cplusplus
 
        
 #ifdef __cplusplus
index 8d5ce64..f9311f5 100644 (file)
@@ -64,31 +64,30 @@ enum {
 };
 
 /* GObject stuff */
 };
 
 /* GObject stuff */
-static void                   gst_spider_identity_class_init            (GstSpiderIdentityClass *klass);
-static void                   gst_spider_identity_init                  (GstSpiderIdentity *spider_identity);
+static void                    gst_spider_identity_class_init          (GstSpiderIdentityClass *klass);
+static void                    gst_spider_identity_init                (GstSpiderIdentity *spider_identity);
 
 /* functions set in pads, elements and stuff */
 
 /* functions set in pads, elements and stuff */
-static void                   gst_spider_identity_chain                  (GstPad *pad, GstBuffer *buf);
-static GstElementStateReturn  gst_spider_identity_change_state          (GstElement *element);
-static GstPadConnectReturn    gst_spider_identity_connect                (GstPad *pad, GstCaps *caps);
-static GstCaps*                gst_spider_identity_getcaps                (GstPad *pad, GstCaps *caps);
+static void                    gst_spider_identity_chain               (GstPad *pad, GstBuffer *buf);
+static GstElementStateReturn   gst_spider_identity_change_state        (GstElement *element);
+static GstPadConnectReturn     gst_spider_identity_connect             (GstPad *pad, GstCaps *caps);
+static GstCaps *               gst_spider_identity_getcaps             (GstPad *pad, GstCaps *caps);
 /* loop functions */
 /* loop functions */
-static void                    gst_spider_identity_dumb_loop              (GstSpiderIdentity *ident);
-static void                    gst_spider_identity_src_loop              (GstSpiderIdentity *ident);
-static void                    gst_spider_identity_sink_loop_typefinding  (GstSpiderIdentity *ident);
-static void                    gst_spider_identity_sink_loop_emptycache  (GstSpiderIdentity *ident);
+static void                    gst_spider_identity_dumb_loop           (GstSpiderIdentity *ident);
+static void                     gst_spider_identity_src_loop           (GstSpiderIdentity *ident);
+static void                     gst_spider_identity_sink_loop_typefinding (GstSpiderIdentity *ident);
+static void                     gst_spider_identity_sink_loop_emptycache (GstSpiderIdentity *ident);
 
 /* set/get functions */
 
 /* set/get functions */
-gboolean                      gst_spider_identity_is_plugged            (GstSpiderIdentity *identity);
-void                          gst_spider_identity_set_caps              (GstSpiderIdentity *identity, GstCaps *caps);
+static void                    gst_spider_identity_set_caps            (GstSpiderIdentity *identity, GstCaps *caps);
 
 /* callback */
 
 /* callback */
-static void                    callback_typefind_have_type                (GstElement *typefind, GstCaps *caps, GstSpiderIdentity *identity);
+static void                    callback_typefind_have_type             (GstElement *typefind, GstCaps *caps, GstSpiderIdentity *identity);
 
 /* other functions */
 
 /* other functions */
-static void                    gst_spider_identity_start_typefinding      (GstSpiderIdentity *ident);
+static void                    gst_spider_identity_start_typefinding   (GstSpiderIdentity *ident);
 
 
-static                        GstElementClass                           *parent_class = NULL;
+static GstElementClass *       parent_class                            = NULL;
 /* no signals
 static guint gst_spider_identity_signals[LAST_SIGNAL] = { 0 }; */
 
 /* no signals
 static guint gst_spider_identity_signals[LAST_SIGNAL] = { 0 }; */
 
@@ -166,6 +165,7 @@ static void
 gst_spider_identity_chain (GstPad *pad, GstBuffer *buf) 
 {
   GstSpiderIdentity *ident;
 gst_spider_identity_chain (GstPad *pad, GstBuffer *buf) 
 {
   GstSpiderIdentity *ident;
+  GstPad *peerpad;
   
   /* g_print ("chaining on pad %s:%s with buffer %p\n", GST_DEBUG_PAD_NAME (pad), buf); */
 
   
   /* g_print ("chaining on pad %s:%s with buffer %p\n", GST_DEBUG_PAD_NAME (pad), buf); */
 
@@ -176,6 +176,25 @@ gst_spider_identity_chain (GstPad *pad, GstBuffer *buf)
   ident = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
 
   if (GST_IS_EVENT (buf)) {
   ident = GST_SPIDER_IDENTITY (gst_pad_get_parent (pad));
 
   if (GST_IS_EVENT (buf)) {
+    /* start hack for current event stuff here */
+    /* check for unconnected elements and send them the EOS event, too */
+    if (GST_EVENT_TYPE (GST_EVENT (buf)) == GST_EVENT_EOS)
+    {
+      GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (ident);
+      GList *list = spider->connections;
+      while (list)
+      {
+       GstSpiderConnection *conn = (GstSpiderConnection *) list->data;
+       list = g_list_next (list);
+       if (conn->sink == ident && (GstElement *) conn->src != conn->current)
+       {
+         gst_element_set_eos (conn->src);
+          gst_pad_push (conn->src->src, gst_event_new (GST_EVENT_EOS));  
+       }
+      }
+    }
+    /* end hack for current event stuff here */
+
     gst_pad_event_default (ident->sink, GST_EVENT (buf));
     return;
   }
     gst_pad_event_default (ident->sink, GST_EVENT (buf));
     return;
   }
@@ -317,13 +336,13 @@ gst_spider_identity_change_state (GstElement *element)
           gst_spider_identity_start_typefinding (ident);
           break;
         } else {
           gst_spider_identity_start_typefinding (ident);
           break;
         } else {
-          gst_spider_plug (ident);
+          gst_spider_identity_plug (ident);
         }
       }
       /* autoplug on src */
       if ((GST_RPAD_PEER (ident->src) != NULL) && (GST_RPAD_PEER (ident->sink) == NULL))
       {
         }
       }
       /* autoplug on src */
       if ((GST_RPAD_PEER (ident->src) != NULL) && (GST_RPAD_PEER (ident->sink) == NULL))
       {
-        gst_spider_plug (ident);
+        gst_spider_identity_plug (ident);
       }
     default:
       break;
       }
     default:
       break;
@@ -396,7 +415,7 @@ callback_typefind_have_type (GstElement *typefind, GstCaps *caps, GstSpiderIdent
   gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_sink_loop_emptycache));
   
   /* autoplug this pad */
   gst_element_set_loop_function (GST_ELEMENT (ident), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_sink_loop_emptycache));
   
   /* autoplug this pad */
-  gst_spider_plug (ident);  
+  gst_spider_identity_plug (ident);  
   
   /* restart autoplugger */
   if (restart_spider)
   
   /* restart autoplugger */
   if (restart_spider)