- use autoplugging instead of predefined way on sometimes pads
authorBenjamin Otte <otte@gnome.org>
Tue, 5 Feb 2002 17:08:08 +0000 (17:08 +0000)
committerBenjamin Otte <otte@gnome.org>
Tue, 5 Feb 2002 17:08:08 +0000 (17:08 +0000)
Original commit message from CVS:
- use autoplugging instead of predefined way on sometimes pads
- exchange plugtype with factories in the spider
- revamp the spider, now messier than before...
- bugfixing
- style corrections

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

index 080588f..936c0dc 100644 (file)
 #include "gstsearchfuncs.h"
 
 /* function that really misses in GLib
+ * though the GLib version should take a function as argument...
  */
 void
 g_list_free_list_and_elements (GList *list)
 {
-       GList *walk = list;
-       
-       while (walk)
-       {
-               g_free (walk->data);
-               walk = g_list_next (walk);
-       }
-       g_list_free (list);
+  GList *walk = list;
+  
+  while (walk)
+  {
+    g_free (walk->data);
+    walk = g_list_next (walk);
+  }
+  g_list_free (list);
 }
 
 /**
@@ -50,20 +51,20 @@ g_list_free_list_and_elements (GList *list)
 GstPadTemplate *
 gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src)
 {
-       GList *templs;
-       
-       templs = fac->padtemplates;
-       
-       while (templs)
-       {
-               if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && gst_caps_check_compatibility(src, GST_PADTEMPLATE_CAPS (templs->data)))
-               {
-                       return GST_PADTEMPLATE (templs->data);
-               }
+  GList *templs;
+  
+  templs = fac->padtemplates;
+  
+  while (templs)
+  {
+    if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && gst_caps_check_compatibility(src, GST_PADTEMPLATE_CAPS (templs->data)))
+    {
+      return GST_PADTEMPLATE (templs->data);
+    }
     templs = g_list_next (templs);
-       }
-       
-       return NULL;    
+  }
+  
+  return NULL;  
 }
 /**
  * gst_autoplug_can_connect_sink:
@@ -77,20 +78,20 @@ gst_autoplug_can_connect_src (GstElementFactory *fac, GstCaps *src)
 GstPadTemplate *
 gst_autoplug_can_connect_sink (GstElementFactory *fac, GstCaps *sink)
 {
-       GList *templs;
-       
-       templs = fac->padtemplates;
-       
-       while (templs)
-       {
-               if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) && gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (templs->data), sink))
-               {
-                       return GST_PADTEMPLATE (templs->data);
-               }
+  GList *templs;
+  
+  templs = fac->padtemplates;
+  
+  while (templs)
+  {
+    if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC) && gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (templs->data), sink))
+    {
+      return GST_PADTEMPLATE (templs->data);
+    }
     templs = g_list_next (templs);
-       }
-       
-       return NULL;    
+  }
+  
+  return NULL;  
 }
 GstPadTemplate *
 gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
@@ -113,9 +114,9 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
               gst_padtemplate_get_caps (desttemp))) {
             GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
                        "factory \"%s\" can connect with factory \"%s\"\n", 
-                                                                      GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
+                       GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
             return desttemp;
-              }
+         }
       }
 
       desttemps = g_list_next (desttemps);
@@ -123,8 +124,8 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
     srctemps = g_list_next (srctemps);
   }
   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
-                        "factory \"%s\" cannot connect with factory \"%s\"\n", 
-                  GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
+             "factory \"%s\" cannot connect with factory \"%s\"\n", 
+             GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
   return NULL;
 }
 
@@ -132,18 +133,18 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
 gboolean
 gst_autoplug_factory_has_direction (GstElementFactory *fac, GstPadDirection dir)
 {
-       GList *templs = fac->padtemplates;
-       
-       while (templs)
-       {
-               if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
-               {
-                       return TRUE;
-               }
-               templs = g_list_next (templs);
-       }
-       
-       return FALSE;
+  GList *templs = fac->padtemplates;
+  
+  while (templs)
+  {
+    if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
+    {
+      return TRUE;
+    }
+    templs = g_list_next (templs);
+  }
+  
+  return FALSE;
 }
 
 /* Decisions are based on the padtemplates. 
@@ -152,42 +153,42 @@ gst_autoplug_factory_has_direction (GstElementFactory *fac, GstPadDirection dir)
 GList *
 gst_autoplug_factories_sinks (GList *factories)
 {
-       GList *ret = NULL;
-       
-       while (factories)
-       {
-               if (gst_autoplug_factory_has_sink (factories->data))
-                       ret = g_list_prepend (ret, factories->data);
-               factories = g_list_next (factories);
+  GList *ret = NULL;
+  
+  while (factories)
+  {
+    if (gst_autoplug_factory_has_sink (factories->data))
+      ret = g_list_prepend (ret, factories->data);
+    factories = g_list_next (factories);
   }
-       return ret;     
+  return ret;  
 }
 GList *
 gst_autoplug_factories_srcs (GList *factories)
 {
-       GList *ret = NULL;
-       
-       while (factories)
-       {
-               if (gst_autoplug_factory_has_src (factories->data))
-                       ret = g_list_prepend (ret, factories->data);
-               factories = g_list_next (factories);
+  GList *ret = NULL;
+  
+  while (factories)
+  {
+    if (gst_autoplug_factory_has_src (factories->data))
+      ret = g_list_prepend (ret, factories->data);
+    factories = g_list_next (factories);
   }
-       return ret;     
+  return ret;  
 }
-GList *        
+GList *  
 gst_autoplug_factories_filters (GList *factories)
 {
-       GList *ret = NULL;
-       
-       while (factories)
-       {
-               /* if you want it faster do src/sink check at once, don't call two functions */
-               if (gst_autoplug_factory_has_src (factories->data) && gst_autoplug_factory_has_sink (factories->data))
-                       ret = g_list_prepend (ret, factories->data);
-               factories = g_list_next (factories);
+  GList *ret = NULL;
+  
+  while (factories)
+  {
+    /* if you want it faster do src/sink check at once, don't call two functions */
+    if (gst_autoplug_factory_has_src (factories->data) && gst_autoplug_factory_has_sink (factories->data))
+      ret = g_list_prepend (ret, factories->data);
+    factories = g_list_next (factories);
   }
-       return ret;     
+  return ret;  
 }
 
 
@@ -197,33 +198,33 @@ gst_autoplug_factories_filters (GList *factories)
 GList *
 gst_autoplug_factories_filters_with_sink_caps (GList *factories)
 {
-       GList *ret = NULL;
-       
-       while (factories)
-       {
-               GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
-               gboolean have_src = FALSE;
-               gboolean have_sink = FALSE;
-               while (templs)
-               {
-                       if (GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC)
-                       {
-                               have_src = TRUE;
-                       }       
-                       if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && (GST_PADTEMPLATE_CAPS (templs->data) != NULL))
-                       {
-                               have_sink = TRUE;
-                       }
-                       if (have_src && have_sink)
-                       {
-                               ret = g_list_prepend (ret, factories->data);
-                               break;
-                       }
-                       templs = g_list_next (templs);
-               }
-               factories = g_list_next (factories);
-       }
-       return ret;
+  GList *ret = NULL;
+  
+  while (factories)
+  {
+    GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
+    gboolean have_src = FALSE;
+    gboolean have_sink = FALSE;
+    while (templs)
+    {
+      if (GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SRC)
+      {
+        have_src = TRUE;
+      }  
+      if ((GST_PADTEMPLATE_DIRECTION (templs->data) == GST_PAD_SINK) && (GST_PADTEMPLATE_CAPS (templs->data) != NULL))
+      {
+        have_sink = TRUE;
+      }
+      if (have_src && have_sink)
+      {
+        ret = g_list_prepend (ret, factories->data);
+        break;
+      }
+      templs = g_list_next (templs);
+    }
+    factories = g_list_next (factories);
+  }
+  return ret;
 }
 
 
@@ -233,29 +234,29 @@ gst_autoplug_factories_filters_with_sink_caps (GList *factories)
 GList *
 gst_autoplug_factories_at_most_templates(GList *factories, GstPadDirection dir, guint maxtemplates)
 {
-       GList *ret = NULL;
-       
-       while (factories)
-       {
-               guint count = 0;
-               GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
+  GList *ret = NULL;
+  
+  while (factories)
+  {
+    guint count = 0;
+    GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
 
-               while (templs)
-               {
-                       if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
-                       {
-                               count++;
-                       }
-                       if (count > maxtemplates)
-                               break;
-                       templs = g_list_next (templs);
-               }
-               if (count <= maxtemplates)
-                 ret = g_list_prepend (ret, factories->data);
-               
-               factories = g_list_next (factories);
-       }
-       return ret;
+    while (templs)
+    {
+      if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
+      {
+        count++;
+      }
+      if (count > maxtemplates)
+        break;
+      templs = g_list_next (templs);
+    }
+    if (count <= maxtemplates)
+      ret = g_list_prepend (ret, factories->data);
+    
+    factories = g_list_next (factories);
+  }
+  return ret;
 }
 /*********************************************************************
  *
@@ -275,117 +276,109 @@ gst_autoplug_factories_at_most_templates(GList *factories, GstPadDirection dir,
 GList *
 gst_autoplug_sp (GstCaps *srccaps, GstCaps *sinkcaps, GList *factories)
 {
-       GList *factory_nodes = NULL;
-       guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */
-       GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */
-       
-       GST_INFO (GST_CAT_AUTOPLUG_ATTEMPT, "attempting to autoplug via shortest path");
-  GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps));
-  /* g_print ("trying to plug %s to %s\n", gst_caps_get_mime (srccaps), gst_caps_get_mime (sinkcaps)); */
-       /* wrap all factories as GstAutoplugNode 
-        * initialize the cost */
-       while (factories)
-       {
-               GstAutoplugNode *node = g_new0 (GstAutoplugNode, 1);
-               node->prev = NULL;
-               node->fac = (GstElementFactory *) factories->data;
-               node->templ = gst_autoplug_can_connect_src (node->fac, srccaps);
-               node->cost = (node->templ ? gst_autoplug_get_cost (node->fac) : GST_AUTOPLUG_MAX_COST);
-               node->endpoint = gst_autoplug_can_connect_sink (node->fac, sinkcaps);
-               if ((node->endpoint != NULL) && (bestnode == NULL || (node->cost < bestnode->cost)))
-               {
-                       bestnode = node;
-               }
-               factory_nodes = g_list_prepend (factory_nodes, node);
-               /* make curcost the minimum cost of any plugin */
-               curcost = node->cost < curcost ? node->cost : curcost;
-               factories = g_list_next (factories);
-       }
-       
-       /* check if we even have possible endpoints */
-       if (bestnode == NULL)
-       {
-               GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no factory found that could connect to sink caps\n");
-               g_list_free_list_and_elements (factory_nodes);
-               return NULL;
-       }
-       
-       /* iterate until we found the best path */
-       while (curcost < GST_AUTOPLUG_MAX_COST)
-       {
-               GList *nodes = factory_nodes;
-               guint nextcost = GST_AUTOPLUG_MAX_COST; /* next cost to check */
-               GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "iterating at current cost %d, bestnode %s at %d\n", curcost, GST_OBJECT_NAME (bestnode->fac), bestnode->cost);
-               /* check if we already have a valid best connection to the sink */
-               if (bestnode->cost <= curcost)
-               {
-                       GList *ret;
-                       GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a way to connect via %s\n", GST_OBJECT_NAME ((GstObject *) bestnode->fac));         
-                       /* enter all factories into the return list */
-                       ret = g_list_prepend (NULL, bestnode->fac);
-                       bestnode = bestnode->prev;
-                       while (bestnode != NULL)
-                       {
-                               ret = g_list_prepend (ret, bestnode->fac);
-                               bestnode = bestnode->prev;
-                       }
-                       g_list_free_list_and_elements (factory_nodes);
-                       return ret;
-               }
-               
-               /* iterate over all factories we have
-                * if they have the current cost, calculate if this
-                * factory supplies shorter paths to other elements
-                */
-               while (nodes)
-               {
-                       if (((GstAutoplugNode *) nodes->data)->cost == curcost)
-                       {
-                               /* now check all elements if we got a shorter path */
-                               GList *sinknodes = factory_nodes;
-                               GstAutoplugNode *srcnode = (GstAutoplugNode *) nodes->data;
-                               while (sinknodes)
-                               {
-                                       GstAutoplugNode *sinknode = (GstAutoplugNode *) sinknodes->data;
-                                       GstPadTemplate *templ;
-                                       if ((sinknode->cost > srcnode->cost + gst_autoplug_get_cost (sinknode->fac)) && (templ = gst_autoplug_can_match(srcnode->fac, sinknode->fac)))
-                                       {
-                                               /* we got a shorter path
-                                                * now enter that path to that node */
-                                               sinknode->prev = srcnode;
-                                               sinknode->templ = templ;
-                                               sinknode->cost = srcnode->cost + gst_autoplug_get_cost (sinknode->fac);
-                                               /* make sure to set which cost to view next */
-                                               nextcost = (nextcost > sinknode->cost) ? sinknode->cost : nextcost;
-                                               /* did we get a new best node? */
-                                               if (sinknode->endpoint && (sinknode->cost < bestnode->cost))
-                                               {
-                                                       bestnode = sinknode;
-                                               }                       
-                                       }
-                                       sinknodes = g_list_next (sinknodes);
-                               }
-                               /* FIXME: for speed remove the item we just iterated with from the factory_nodes
-                                * but don't free it yet and don't forget to free it.
-                                */
-                       }
-                 nodes = g_list_next (nodes);
-               }
-               curcost = nextcost;
-       }
-       
-       GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found no path from source caps to sink caps\n");          
-       g_list_free_list_and_elements (factory_nodes);
-       return NULL;    
+  GList *factory_nodes = NULL;
+  guint curcost = GST_AUTOPLUG_MAX_COST; /* below this cost, there is no path */
+  GstAutoplugNode *bestnode = NULL; /* best (unconnected) endpoint currently */
+  
+  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 */
+  while (factories)
+  {
+    GstAutoplugNode *node = g_new0 (GstAutoplugNode, 1);
+    node->prev = NULL;
+    node->fac = (GstElementFactory *) factories->data;
+    node->templ = gst_autoplug_can_connect_src (node->fac, srccaps);
+    node->cost = (node->templ ? gst_autoplug_get_cost (node->fac) : GST_AUTOPLUG_MAX_COST);
+    node->endpoint = gst_autoplug_can_connect_sink (node->fac, sinkcaps);
+    if ((node->endpoint != NULL) && ((bestnode == NULL) || (node->cost < bestnode->cost)))
+    {
+      bestnode = node;
+    }
+    factory_nodes = g_list_prepend (factory_nodes, node);
+    /* make curcost the minimum cost of any plugin */
+    curcost = node->cost < curcost ? node->cost : curcost;
+    factories = g_list_next (factories);
+  }
+  
+  /* check if we even have possible endpoints */
+  if (bestnode == NULL)
+  {
+    GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no factory found that could connect to sink caps\n");
+    g_list_free_list_and_elements (factory_nodes);
+    return NULL;
+  }
+  
+  /* iterate until we found the best path */
+  while (curcost < GST_AUTOPLUG_MAX_COST)
+  {
+    GList *nodes = factory_nodes;
+    guint nextcost = GST_AUTOPLUG_MAX_COST; /* next cost to check */
+    GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "iterating at current cost %d, bestnode %s at %d\n", curcost, GST_OBJECT_NAME (bestnode->fac), bestnode->cost);
+    /* check if we already have a valid best connection to the sink */
+    if (bestnode->cost <= curcost)
+    {
+      GList *ret;
+      GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a way to connect via %s\n", GST_OBJECT_NAME ((GstObject *) bestnode->fac));    
+      /* enter all factories into the return list */
+      ret = g_list_prepend (NULL, bestnode->fac);
+      bestnode = bestnode->prev;
+      while (bestnode != NULL)
+      {
+        ret = g_list_prepend (ret, bestnode->fac);
+        bestnode = bestnode->prev;
+      }
+      g_list_free_list_and_elements (factory_nodes);
+      return ret;
+    }
+    
+    /* iterate over all factories we have
+     * if they have the current cost, calculate if this
+     * factory supplies shorter paths to other elements
+     */
+    while (nodes)
+    {
+      if (((GstAutoplugNode *) nodes->data)->cost == curcost)
+      {
+        /* now check all elements if we got a shorter path */
+        GList *sinknodes = factory_nodes;
+        GstAutoplugNode *srcnode = (GstAutoplugNode *) nodes->data;
+        while (sinknodes)
+        {
+          GstAutoplugNode *sinknode = (GstAutoplugNode *) sinknodes->data;
+          GstPadTemplate *templ;
+          if ((sinknode->cost > srcnode->cost + gst_autoplug_get_cost (sinknode->fac)) && (templ = gst_autoplug_can_match(srcnode->fac, sinknode->fac)))
+          {
+            /* we got a shorter path
+             * now enter that path to that node */
+            sinknode->prev = srcnode;
+            sinknode->templ = templ;
+            sinknode->cost = srcnode->cost + gst_autoplug_get_cost (sinknode->fac);
+            /* make sure to set which cost to view next */
+            nextcost = (nextcost > sinknode->cost) ? sinknode->cost : nextcost;
+            /* did we get a new best node? */
+            if (sinknode->endpoint && (sinknode->cost < bestnode->cost))
+            {
+              bestnode = sinknode;
+            }      
+          }
+          sinknodes = g_list_next (sinknodes);
+        }
+        /* FIXME: for speed remove the item we just iterated with from the factory_nodes
+         * but don't free it yet and don't forget to free it.
+         */
+      }
+      nodes = g_list_next (nodes);
+    }
+    curcost = nextcost;
+  }
+  
+  GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found no path from source caps to sink caps\n");    
+  g_list_free_list_and_elements (factory_nodes);
+  return NULL;  
 }
 
 
 
 
 
-
-
-
-
-
-
index a28d9d5..3b4c811 100644 (file)
@@ -24,7 +24,9 @@
  * TODO:
  * - handle automatic removal of unneeded elements
  * - make the spider handle and send events (esp. new media)
+ * - decide if we plug pads or elements, currently it's a mess
  * - allow disconnecting
+ * - implement proper saving/loading from xml
  * - implement a way to allow merging/splitting (aka tee)
  * - find ways to define which elements to use when plugging
  * - remove pads
@@ -51,7 +53,7 @@ enum {
 
 enum {
   ARG_0,
-  ARG_PLUGTYPE,
+  ARG_FACTORIES,
   /* FILL ME TOO */
 };
 
@@ -70,19 +72,19 @@ GST_PADTEMPLATE_FACTORY (spider_sink_factory,
   NULL      /* no caps */
 );
 /* 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 */
-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);
 
 /* autoplugging functions */
-static GstElement *                gst_spider_find_element_to_plug               (GstElement *src, GstElementFactory *fac, GstPadDirection dir);
-static GstPadConnectReturn         gst_spider_plug_peers                         (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdentity *sink);
-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_peers                       (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad);
+static GstPadConnectReturn         gst_spider_create_and_plug                   (GstSpider *spider, GstElement *src, GstElement *sink, GList *plugpath);
 
 /* random functions */
 static gchar *                    gst_spider_unused_elementname                 (GstBin *bin, const gchar *startwith);
@@ -101,9 +103,10 @@ gst_spider_get_type(void)
 
   if (!spider_type) {
     static const GTypeInfo spider_info = {
-      sizeof(GstSpiderClass),      NULL,
+      sizeof(GstSpiderClass),
       NULL,
-      (GClassInitFunc)gst_spider_class_init,
+      NULL,
+      (GClassInitFunc) gst_spider_class_init,
       NULL,
       NULL,
       sizeof(GstSpider),
@@ -119,7 +122,7 @@ static void
 gst_spider_class_init (GstSpiderClass *klass)
 {
   GObjectClass     *gobject_class;
-  GstElementClass *gstelement_class;
+  GstElementClass  *gstelement_class;
 
   gobject_class = (GObjectClass*) klass;
   gstelement_class = (GstElementClass*) klass;
@@ -127,21 +130,33 @@ gst_spider_class_init (GstSpiderClass *klass)
   parent_class = g_type_class_ref(GST_TYPE_BIN);
 
   /* properties */
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PLUGTYPE,
-  g_param_spec_int ("plugtype", "plug direction", "encoding, decoding or anything",
-                      GST_SPIDER_ANY, GST_SPIDER_PLUGTYPES - 1, 0, G_PARAM_READWRITE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FACTORIES,
+  g_param_spec_pointer ("factories", "allowed factories", "allowed factories for autoplugging", G_PARAM_READWRITE));
 
   gobject_class->set_property = gst_spider_set_property;
   gobject_class->get_property = gst_spider_get_property;
+  gobject_class->dispose = gst_spider_dispose;
 
   gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_spider_request_new_pad);
 }
 static void 
 gst_spider_init (GstSpider *spider) 
 {
-  spider->plugtype = GST_SPIDER_ANY;
+  /* 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 ());
 }
 
+static void
+gst_spider_dispose (GObject *object)
+{
+  GstSpider *spider;
+  
+  spider = GST_SPIDER (object);
+  g_list_free (spider->factories);
+  
+  ((GObjectClass *) parent_class)->dispose (object);
+}
 static GstPad *
 gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name)
 {
@@ -161,10 +176,12 @@ gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gc
     case GST_PAD_SRC:
       padname = gst_spider_unused_elementname ((GstBin *)spider, "src_");
       identity = gst_spider_identity_new_src (padname);
+      returnpad = identity->src;
       break;
     case GST_PAD_SINK:
       padname = gst_spider_unused_elementname ((GstBin *)spider, "sink_");
       identity = gst_spider_identity_new_sink (padname);
+      returnpad = identity->sink;
       break;
     case GST_PAD_UNKNOWN:
     default:
@@ -172,9 +189,6 @@ gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gc
       return NULL;
   }
   
-  /* connect a ghost pad on the right side of the identity and set the requested template */
-  returnpad = gst_spider_identity_request_new_pad  (GST_ELEMENT (identity), templ, NULL);
-
   /* FIXME: use the requested name for the pad */
 
   gst_object_ref (GST_OBJECT (templ));
@@ -192,32 +206,24 @@ static void
 gst_spider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
   GstSpider *spider;
-
+  GList *list;
+  
   /* it's not null if we got it, but it might not be ours */
   g_return_if_fail (GST_IS_SPIDER (object));
 
   spider = GST_SPIDER (object);
 
   switch (prop_id) {
-    case ARG_PLUGTYPE:
-      switch (g_value_get_int (value))
+    case ARG_FACTORIES:
+      list = (GList *) g_value_get_pointer (value);
+      while (list)
       {
-        case GST_SPIDER_ANY:
-          spider->plugtype = GST_SPIDER_ANY;
-          GST_DEBUG (0,"spider: setting plugtype to ANY\n");
-          break;
-        case GST_SPIDER_ENCODE:
-          spider->plugtype = GST_SPIDER_ENCODE;
-          GST_DEBUG (0,"spider: setting plugtype to ENCODE\n");
-          break;
-        case GST_SPIDER_DECODE:
-          spider->plugtype = GST_SPIDER_DECODE;
-          GST_DEBUG (0,"spider: setting plugtype to DECODE\n");
-          break;
-        default:
-          GST_DEBUG (0,"spider: invalid value %d while setting plugtype\n", g_value_get_int (value));
-          break;
+       g_return_if_fail (list->data != NULL);
+       g_return_if_fail (GST_IS_ELEMENTFACTORY (list->data));
+       list = g_list_next (list);
       }
+      g_list_free (spider->factories);
+      spider->factories = (GList *) g_value_get_pointer (value);
       break;
     default:
       break;
@@ -232,8 +238,8 @@ gst_spider_get_property (GObject *object, guint prop_id, GValue *value, GParamSp
   spider = GST_SPIDER(object);
 
   switch (prop_id) {
-    case ARG_PLUGTYPE:
-      g_value_set_int (value, spider->plugtype);
+    case ARG_FACTORIES:
+      g_value_set_pointer (value, spider->factories);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -259,26 +265,43 @@ gst_spider_unused_elementname (GstBin *bin, const gchar *startwith)
 typedef struct {
   GstSpider *spider;
   GstElement *sink;
-  GList *plugpath;
   gulong signal_id;
 } GstSpiderConnectSometimes;
 static void
 gst_spider_connect_sometimes (GstElement *src, GstPad *pad, GstSpiderConnectSometimes *data)
 {
   gboolean restart = FALSE;
+  GstPad *sinkpad;
+  GList *sinkpads = gst_element_get_pad_list (data->sink);
+  
   if (gst_element_get_state ((GstElement *) data->spider) == GST_STATE_PLAYING)
   {
     restart = TRUE;
     gst_element_set_state ((GstElement *) data->spider, GST_STATE_PAUSED);
   }
-  gst_spider_create_and_plug (data->spider, src, data->sink, data->plugpath);
-  g_signal_handler_disconnect (src, data->signal_id);
+  /* 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 (restart)
   {
     gst_element_set_state ((GstElement *) data->spider, GST_STATE_PLAYING);
   }
-  g_free (data);
-  
+  /* do we need this? */
   gst_element_interrupt (src);
 }
 /* connects newsrc to newsink using the elementfactories in plugpath */
@@ -287,6 +310,7 @@ gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink
 {
   GstElement *element;
   
+  /* g_print ("C&P: from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink)); */
   /* get the next element */
   if (plugpath == NULL)
   {
@@ -295,6 +319,7 @@ gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink
     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)); */
   }
   /* insert and connect new element */
   if (!gst_element_connect_elements (src, element))
@@ -314,7 +339,6 @@ gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink
         GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "adding callback to connect element %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (element));
        data->spider = spider;
        data->sink = sink;
-       data->plugpath = plugpath;
        data->signal_id = g_signal_connect (G_OBJECT (src), "new_pad", 
                                            G_CALLBACK (gst_spider_connect_sometimes), data);
  
@@ -322,12 +346,11 @@ gst_spider_create_and_plug (GstSpider *spider, GstElement *src, GstElement *sink
       }
       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 (element));
-    g_list_free (plugpath);
+    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_delete_link (plugpath, plugpath);
+  plugpath = g_list_next (plugpath);
   
   /* recursively connect the rest of the elements */
   if (element != sink) {
@@ -361,7 +384,7 @@ gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPad
 }
 /* plugs a pad into the autoplugger if it isn't plugged yet */
 void
-gst_spider_plug  (GstSpiderIdentity *ident)
+gst_spider_plug (GstSpiderIdentity *ident)
 {
   GstSpider *spider;
   GList *plugto;
@@ -413,9 +436,9 @@ gst_spider_plug  (GstSpiderIdentity *ident)
         /* plug in the right direction */
         if (plugpad == ident->src)
         {
-          gst_spider_plug_peers (spider, peer, ident);
+          gst_spider_plug_peers (spider, peer->src, ident->sink);
         } else {
-          gst_spider_plug_peers (spider, ident, peer);
+          gst_spider_plug_peers (spider, ident->src, peer->sink);
         }
       }
     }
@@ -429,42 +452,36 @@ gst_spider_plug  (GstSpiderIdentity *ident)
  * if no connection was possible
  */
 static GstPadConnectReturn
-gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdentity *sink)
+gst_spider_plug_peers (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad)
 {
-  GstElement *element, *newsrc, *newsink;
-  GstPad *pad, *compat;
+  GstElement *element, *src, *sink, *newsrc, *newsink;
   GList *plugpath;
-  GList *neededfactories;
   GList *templist;
   gboolean result = TRUE;
   
-  GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "trying to plug from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
+  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));
   
-  neededfactories = (GList *) gst_elementfactory_get_list ();
-  /* use only elements which have sources and sinks and where the sinks have caps */
-  neededfactories = gst_autoplug_factories_filters_with_sink_caps (neededfactories);
+  /* get src and sink element */
+  src = (GstElement *) GST_PAD_PARENT (srcpad);
+  sink = (GstElement *) GST_PAD_PARENT (sinkpad);
+
+  /* find a path from src to sink */
+  plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (sinkpad), spider->factories);
   
-  /* use only the elements with exactly 1 sink/src when decoding/encoding */
-  if (spider->plugtype == GST_SPIDER_ENCODE)
-  {
-    templist = neededfactories;
-    neededfactories = gst_autoplug_factories_at_most_templates (neededfactories, GST_PAD_SRC, 1);
-    g_list_free (templist);
-  }
-  if (spider->plugtype == GST_SPIDER_DECODE)
-  {
-    templist = neededfactories;
-    neededfactories = gst_autoplug_factories_at_most_templates (neededfactories, GST_PAD_SINK, 1);
-    g_list_free (templist);
-  }
   
-  /* find a path from src to sink */
-  plugpath = gst_autoplug_sp (gst_pad_get_caps ((GstPad *) GST_RPAD_PEER (src->sink)), gst_pad_get_caps ((GstPad *) GST_RPAD_PEER (sink->src)), neededfactories);
+  /* prints out the path that was found for plugging
+  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) {
     GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "no chance to plug from %s to %s\n", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink));
-    return FALSE;
+    return GST_PAD_CONNECT_REFUSED;
   }
   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, "found a connection that needs %d elements\n", g_list_length (plugpath));
 
@@ -472,16 +489,16 @@ gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdent
    * 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 = (GstElement *) src;
-  while (element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC))
+  newsrc = src;
+  while ((element = gst_spider_find_element_to_plug (newsrc, (GstElementFactory *) plugpath->data, GST_PAD_SRC)))
   {
     newsrc = element;
     plugpath = g_list_delete_link (plugpath, plugpath);
   }
   /* now do the same at the end */
-  newsink = (GstElement *) sink;
+  newsink = sink;
   templist = g_list_last (plugpath);
-  while (element = gst_spider_find_element_to_plug (newsink, (GstElementFactory *) plugpath->data, GST_PAD_SINK))
+  while ((element = gst_spider_find_element_to_plug (newsink, (GstElementFactory *) plugpath->data, GST_PAD_SINK)))
   {
     GList *cur = templist;
     newsink = element;
@@ -494,7 +511,7 @@ gst_spider_plug_peers (GstSpider *spider, GstSpiderIdentity *src, GstSpiderIdent
   result = gst_spider_create_and_plug (spider, newsrc, newsink, plugpath);
 
   /* free no longer needed data */
-  g_list_free (neededfactories);
+  g_list_free (plugpath);
   
   return result;  
 }
index 695f2b2..3632992 100644 (file)
 #include <gst/gst.h>
 #include "gstspideridentity.h"
 
-typedef enum {
-       GST_SPIDER_ANY = 0,
-       GST_SPIDER_ENCODE = 1,
-       GST_SPIDER_DECODE = 2,
-       GST_SPIDER_PLUGTYPES
-} GstSpiderPlugtype;
-
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
@@ -54,9 +47,9 @@ typedef struct _GstSpider GstSpider;
 typedef struct _GstSpiderClass GstSpiderClass;
 
 struct _GstSpider {
-  GstBin                parent;
+  GstBin        parent;
        
-  GstSpiderPlugtype     plugtype; /* direction to plug */              
+  GList *      factories; /* factories to use for plugging */          
 };
        
 struct _GstSpiderClass {
index 3408b8f..6343850 100644 (file)
@@ -39,14 +39,14 @@ GstElementDetails gst_spider_identity_details = {
  * delete me when meging with spider.c
  */
 GST_PADTEMPLATE_FACTORY (spider_src_factory,
-  "src_%02d",
+  "src",
   GST_PAD_SRC,
   GST_PAD_REQUEST,
   NULL      /* no caps */
 );
 
 GST_PADTEMPLATE_FACTORY (spider_sink_factory,
-  "sink_%02d",
+  "sink",
   GST_PAD_SINK,
   GST_PAD_REQUEST,
   NULL      /* no caps */
@@ -140,18 +140,25 @@ gst_spider_identity_get_bufferpool (GstPad *pad)
 }
 
 static void 
-gst_spider_identity_init (GstSpiderIdentity *spider_identity
+gst_spider_identity_init (GstSpiderIdentity *ident
 {
-  /* pads */
-  spider_identity->sink = NULL;
-  spider_identity->src = NULL;
+  /* sink */
+  ident->sink = gst_pad_new_from_template (GST_PADTEMPLATE_GET (spider_sink_factory), "sink");
+  gst_element_add_pad (GST_ELEMENT (ident), ident->sink);
+  gst_pad_set_connect_function (ident->sink, GST_DEBUG_FUNCPTR (gst_spider_identity_connect));
+  gst_pad_set_getcaps_function (ident->sink, GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps));
+  /* src */
+  ident->src = gst_pad_new_from_template (GST_PADTEMPLATE_GET (spider_src_factory), "src");
+  gst_element_add_pad (GST_ELEMENT (ident), ident->src);
+  gst_pad_set_connect_function (ident->src, GST_DEBUG_FUNCPTR (gst_spider_identity_connect));
+  gst_pad_set_getcaps_function (ident->src, GST_DEBUG_FUNCPTR (gst_spider_identity_getcaps));
 
   /* variables */
-  spider_identity->plugged = FALSE;
+  ident->plugged = FALSE;
   
   /* caching */
-  spider_identity->cache_start = NULL;
-  spider_identity->cache_end = NULL;
+  ident->cache_start = NULL;
+  ident->cache_end = NULL;
   
 }
 
@@ -198,6 +205,9 @@ gst_spider_identity_new_sink (gchar *name)
   
   GST_ELEMENT_NAME (ret) = name;
 
+  /* set the right functions */
+  gst_element_set_loop_function (GST_ELEMENT (ret), (GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop));
+
   return ret;
 }
 
@@ -300,7 +310,7 @@ gst_spider_identity_change_state (GstElement *element)
   switch (GST_STATE_TRANSITION (element)) {
     case GST_STATE_PAUSED_TO_PLAYING:
       /* start typefinding or plugging */
-      if ((ident->sink != NULL) && (ident->src == NULL))
+      if ((GST_RPAD_PEER (ident->sink) != NULL) && (GST_RPAD_PEER (ident->src) == NULL))
       {
         if (gst_pad_get_caps ((GstPad *) GST_PAD_PEER (ident->sink)) == NULL)
         {
@@ -311,7 +321,7 @@ gst_spider_identity_change_state (GstElement *element)
         }
       }
       /* autoplug on src */
-      if ((ident->src != NULL) && (ident->sink == NULL))
+      if ((GST_RPAD_PEER (ident->src) != NULL) && (GST_RPAD_PEER (ident->sink) == NULL))
       {
         gst_spider_plug (ident);
       }
@@ -330,7 +340,7 @@ gst_spider_identity_start_typefinding (GstSpiderIdentity *ident)
 {
   GstElement* typefind;
   
-  GST_DEBUG (GST_CAT_AUTOPLUG, "element %s starts typefinding", GST_ELEMENT_NAME(ident));
+  GST_DEBUG (GST_CAT_AUTOPLUG, "element %s starts typefinding\n", GST_ELEMENT_NAME(ident));
   
   /* create and connect typefind object */
   typefind = gst_elementfactory_make ("typefind", g_strdup_printf("%s%s", "typefind", GST_ELEMENT_NAME(ident)));
@@ -362,7 +372,7 @@ callback_typefind_have_type (GstElement *typefind, GstCaps *caps, GstSpiderIdent
 {
   gboolean restart_spider = FALSE;
   
-  GST_INFO (GST_CAT_AUTOPLUG, "element %s has found caps", GST_ELEMENT_NAME(ident));
+  GST_INFO (GST_CAT_AUTOPLUG, "element %s has found caps\n", GST_ELEMENT_NAME(ident));
   /* checks */
   
   /* we have to ref the typefind, because if me remove it the scheduler segfaults 
index 8b97444..4ae09f6 100644 (file)
@@ -1,6 +1,36 @@
 #include <stdlib.h>
 #include <gst/gst.h>
 
+/* returns all factories which have a maximum of maxtemplates GstPadTemplates in direction dir
+ */
+GList *
+gst_factories_at_most_templates(GList *factories, GstPadDirection dir, guint maxtemplates)
+{
+  GList *ret = NULL;
+  
+  while (factories)
+  {
+    guint count = 0;
+    GList *templs = ((GstElementFactory *) factories->data)->padtemplates;
+
+    while (templs)
+    {
+      if (GST_PADTEMPLATE_DIRECTION (templs->data) == dir)
+      {
+        count++;
+      }
+      if (count > maxtemplates)
+        break;
+      templs = g_list_next (templs);
+    }
+    if (count <= maxtemplates)
+      ret = g_list_prepend (ret, factories->data);
+    
+    factories = g_list_next (factories);
+  }
+  return ret;
+}
+
 /* 1:1 copy of gstpropsprivate.h, needed for INFO events */
 
 #define GST_PROPS_ENTRY_IS_VARIABLE(a)  (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID)
@@ -87,8 +117,9 @@ event_func (GstElement *element, GstEvent *event)
 int main(int argc,char *argv[]) 
 {
   GstElement *bin, *filesrc, *decoder, *osssink, *videosink;
+  GList *facs;
   
-  if (argc != 2) {
+  if (argc < 2) {
     g_print("usage: %s <file>\n", argv[0]);
     exit(-1);
   }
@@ -111,7 +142,9 @@ int main(int argc,char *argv[])
   }
   
   /* only use decoding plugins */
-  g_object_set(G_OBJECT(decoder),"plugtype", 2, NULL);
+  g_object_get (decoder, "factories", &facs, NULL);
+  facs = gst_factories_at_most_templates(facs, GST_PAD_SINK, 1);
+  g_object_set (decoder, "factories", facs, NULL);
 
   /* create video and audio sink */
   osssink = gst_elementfactory_make("osssink", "audio");