GST_DEBUG reorganization containing loads of stuff:
[platform/upstream/gstreamer.git] / gst / autoplug / gstspider.c
1 /* GStreamer
2  * Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
3  *               2002 Wim Taymans <wtay@chello.be>
4  *
5  * gstspider.c: element to automatically link sinks and sources
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22  
23 /*
24  * TODO:
25  * - handle automatic removal of unneeded elements
26  * - make the spider handle and send events (esp. new media)
27  * - decide if we plug pads or elements, currently it's a mess
28  * - allow unlinking
29  * - implement proper saving/loading from xml
30  * - implement a way to allow merging/splitting (aka tee)
31  * - find ways to define which elements to use when plugging
32  * - remove pads
33  * - improve typefinding
34  * - react to errors inside the pipeline
35  * - implement more properties, change the current
36  * - emit signals (most important: "NOT PLUGGABLE")
37  * - implement something for reporting the state of the spider
38  *   to allow easier debugging.
39  *   (could be useful for bins in general)
40  * - fix bugs
41  * ...
42  */
43
44 #ifdef HAVE_CONFIG_H
45 #  include "config.h"
46 #endif
47
48 #include "gstspider.h"
49 #include "gstspideridentity.h"
50 #include "gstsearchfuncs.h"
51
52 GST_DEBUG_CATEGORY (gst_spider_debug);
53 #define GST_CAT_DEFAULT gst_spider_debug
54
55 /* signals and args */
56 enum {
57   /* FILL ME */
58   LAST_SIGNAL
59 };
60
61 enum {
62   ARG_0,
63   ARG_FACTORIES,
64   /* FILL ME TOO */
65 };
66
67 /* generic templates */
68 GST_PAD_TEMPLATE_FACTORY (spider_src_factory,
69   "src_%d",
70   GST_PAD_SRC,
71   GST_PAD_REQUEST,
72   NULL      /* no caps */
73 );
74
75 /* standard GObject stuff */
76 static void                     gst_spider_class_init                   (GstSpiderClass *klass);
77 static void                     gst_spider_init                         (GstSpider *spider);
78 static void                     gst_spider_dispose                      (GObject *object);
79
80 /* element class functions */
81 static GstPad*                  gst_spider_request_new_pad              (GstElement *element, GstPadTemplate *templ, const gchar *name);
82 static void                     gst_spider_set_property                 (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
83 static void                     gst_spider_get_property                 (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
84
85 /* link functions */
86 static GstSpiderConnection *    gst_spider_link_new             (GstSpiderIdentity *src);
87 static void                     gst_spider_link_destroy         (GstSpiderConnection *conn);
88 static void                     gst_spider_link_reset           (GstSpiderConnection *conn, GstElement *to);
89 static void                     gst_spider_link_add             (GstSpiderConnection *conn, GstElement *element);
90 static GstSpiderConnection *    gst_spider_link_find            (GstSpiderIdentity *src);
91 static GstSpiderConnection *    gst_spider_link_get             (GstSpiderIdentity *src);
92
93 /* autoplugging functions */
94 static GstElement *             gst_spider_find_element_to_plug         (GstElement *src, GstElementFactory *fac, GstPadDirection dir);
95 static GstPadLinkReturn         gst_spider_plug                         (GstSpiderConnection *conn);
96 static GstPadLinkReturn         gst_spider_plug_from_srcpad             (GstSpiderConnection *conn, GstPad *srcpad);
97 /*static GstPadLinkReturn      gst_spider_plug_peers                    (GstSpider *spider, GstPad *srcpad, GstPad *sinkpad); */
98 static GstPadLinkReturn         gst_spider_create_and_plug              (GstSpiderConnection *conn, GList *plugpath);
99
100 /* random functions */
101 static gchar *                  gst_spider_unused_elementname           (GstBin *bin, const gchar *startwith);
102
103 /* debugging stuff
104 static void                     print_spider_contents                   (GstSpider *spider);
105 static void                     print_spider_link                       (GstSpiderConnection *conn); */
106
107 /* === variables === */
108 static                          GstElementClass *                       parent_class = NULL;
109
110 /* no signals yet
111 static guint gst_spider_signals[LAST_SIGNAL] = { 0 };*/
112
113 /* GObject and GStreamer init functions */
114 GType
115 gst_spider_get_type(void)
116 {
117   static GType spider_type = 0;
118
119   if (!spider_type) {
120     static const GTypeInfo spider_info = {
121       sizeof(GstSpiderClass),
122       NULL,
123       NULL,
124       (GClassInitFunc) gst_spider_class_init,
125       NULL,
126       NULL,
127       sizeof(GstSpider),
128       0,
129       (GInstanceInitFunc)gst_spider_init,
130     };
131     spider_type = g_type_register_static (GST_TYPE_BIN, "GstSpider", &spider_info, 0);
132   }
133   return spider_type;
134 }
135
136 static void
137 gst_spider_class_init (GstSpiderClass *klass)
138 {
139   GObjectClass     *gobject_class;
140   GstElementClass  *gstelement_class;
141
142   gobject_class = (GObjectClass*) klass;
143   gstelement_class = (GstElementClass*) klass;
144
145   parent_class = g_type_class_ref(GST_TYPE_BIN);
146
147   /* properties */
148   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FACTORIES,
149   g_param_spec_pointer ("factories", "allowed factories", "allowed factories for autoplugging", G_PARAM_READWRITE));
150
151   gobject_class->set_property = gst_spider_set_property;
152   gobject_class->get_property = gst_spider_get_property;
153   gobject_class->dispose = gst_spider_dispose;
154
155   gst_element_class_add_pad_template (gstelement_class, GST_PAD_TEMPLATE_GET (spider_src_factory));
156   
157   gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_spider_request_new_pad);
158 }
159 static void 
160 gst_spider_init (GstSpider *spider) 
161 {
162   /* use only elements which have sources and sinks and where the sinks have caps */
163   /* FIXME: How do we handle factories that are added after the spider was constructed? */
164   spider->factories = gst_autoplug_factories_filters_with_sink_caps ((GList *) 
165                   gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY));
166
167   spider->links = NULL;
168
169   spider->sink_ident = gst_spider_identity_new_sink ("sink_ident");
170   gst_bin_add (GST_BIN (spider), GST_ELEMENT (spider->sink_ident));
171   gst_element_add_ghost_pad (GST_ELEMENT(spider), spider->sink_ident->sink, "sink");
172   
173 }
174
175 static void
176 gst_spider_dispose (GObject *object)
177 {
178   GstSpider *spider;
179   
180   spider = GST_SPIDER (object);
181   g_list_free (spider->factories);
182   
183   ((GObjectClass *) parent_class)->dispose (object);
184 }
185 static GstPad *
186 gst_spider_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name)
187 {
188   GstPad *returnpad;
189   gchar *padname;
190   GstSpiderIdentity *identity;
191   GstSpider *spider;
192   
193   g_return_val_if_fail (templ != NULL, NULL);
194   g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
195   g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC, NULL);
196   
197   spider = GST_SPIDER (element);
198   
199   /* create an identity object, so we have a pad */
200   padname = gst_spider_unused_elementname ((GstBin *)spider, "src_");
201   identity = gst_spider_identity_new_src (padname);
202   returnpad = identity->src;
203   
204   /* FIXME: use the requested name for the pad */
205
206   gst_object_replace ((GstObject **) &returnpad->padtemplate, (GstObject *) templ);
207   
208   gst_bin_add (GST_BIN (element), GST_ELEMENT (identity));
209   
210   returnpad = gst_element_add_ghost_pad (element, returnpad, padname);
211   gst_spider_link_new (identity);
212   GST_DEBUG ("successuflly created requested pad %s:%s", GST_DEBUG_PAD_NAME (returnpad));
213   
214   return returnpad;
215 }
216
217 static void
218 gst_spider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
219 {
220   GstSpider *spider;
221   GList *list;
222   
223   /* it's not null if we got it, but it might not be ours */
224   g_return_if_fail (GST_IS_SPIDER (object));
225
226   spider = GST_SPIDER (object);
227
228   switch (prop_id) {
229     case ARG_FACTORIES:
230       list = (GList *) g_value_get_pointer (value);
231       while (list)
232       {
233         g_return_if_fail (list->data != NULL);
234         g_return_if_fail (GST_IS_ELEMENT_FACTORY (list->data));
235         list = g_list_next (list);
236       }
237       g_list_free (spider->factories);
238       spider->factories = (GList *) g_value_get_pointer (value);
239       break;
240     default:
241       break;
242   }
243 }
244 static void
245 gst_spider_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
246 {
247   GstSpider *spider;
248
249   /* it's not null if we got it, but it might not be ours */
250   spider = GST_SPIDER(object);
251
252   switch (prop_id) {
253     case ARG_FACTORIES:
254       g_value_set_pointer (value, spider->factories);
255       break;
256     default:
257       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
258       break;
259   }
260 }
261 /* get a name for an element that isn't used yet */
262 static gchar *
263 gst_spider_unused_elementname (GstBin *bin, const gchar *startwith)
264 {
265   gchar * name = g_strdup_printf ("%s%d", startwith, 0);
266   guint i;
267   
268   for (i = 0; gst_bin_get_by_name (bin, name) != NULL; )
269   {
270     g_free (name);
271     name = g_strdup_printf ("%s%d", startwith, ++i);
272   }
273   
274   return name;
275 }
276 static void
277 gst_spider_link_sometimes (GstElement *src, GstPad *pad, GstSpiderConnection *conn)
278 {
279   gulong signal_id = conn->signal_id;
280   
281   /* try to autoplug the elements */
282   if (gst_spider_plug_from_srcpad (conn, pad) != GST_PAD_LINK_REFUSED) {
283     GST_DEBUG ("%s:%s was autoplugged to %s:%s, removing callback", 
284                GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (conn->src->sink));
285     g_signal_handler_disconnect (src, signal_id);
286     signal_id = 0;
287   }
288 }
289 /* create a new link from those two elements */
290 static GstSpiderConnection *
291 gst_spider_link_new (GstSpiderIdentity *src)
292 {
293   GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (src));
294   
295   GstSpiderConnection *conn = g_new0 (GstSpiderConnection, 1);
296   conn->src = src;
297   conn->path = NULL;
298   conn->current = (GstElement *) spider->sink_ident;
299   spider->links = g_list_prepend (spider->links, conn);
300   
301   return conn;
302 }
303 static void
304 gst_spider_link_destroy (GstSpiderConnection *conn)
305 {
306   GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (conn->src));
307   /* reset link to unplugged */
308   gst_spider_link_reset (conn, (GstElement *) spider->sink_ident);
309   g_free (conn);
310 }
311 static void
312 gst_spider_link_reset (GstSpiderConnection *conn, GstElement *to)
313 {
314   GstSpider *spider = GST_SPIDER (GST_OBJECT_PARENT (conn->src));
315   GST_DEBUG ("resetting link from %s to %s, currently at %s to %s", GST_ELEMENT_NAME (spider->sink_ident), 
316              GST_ELEMENT_NAME (conn->src), GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (to));
317   while ((conn->path != NULL) && ((GstElement *) conn->path->data != to))
318   {
319     gst_object_unref ((GstObject *) conn->path->data);
320     conn->path = g_list_delete_link (conn->path, conn->path);
321   }
322   if (conn->path == NULL)
323   {
324     conn->current = (GstElement *) spider->sink_ident;
325   } else {
326     conn->current = to;
327   }
328 }
329 /* add an element to the link */
330 static void
331 gst_spider_link_add (GstSpiderConnection *conn, GstElement *element)
332 {
333   gst_object_ref ((GstObject *) element);
334   gst_object_sink ((GstObject *) element);
335   conn->path = g_list_prepend (conn->path, element);
336   conn->current = element;
337 }
338 /* find the link from those two elements */
339 static GstSpiderConnection *
340 gst_spider_link_find (GstSpiderIdentity *src)
341 {
342   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (src);
343   GList *list = spider->links;
344   
345   while (list)
346   {
347     GstSpiderConnection *conn = (GstSpiderConnection *) list->data;
348     if (conn->src == src){
349       return conn;
350     }
351     list = g_list_next(list);
352   }
353   return NULL;
354 }
355 /* get a new link from those two elements
356  * search first; if none is found, create a new one */
357 static GstSpiderConnection *
358 gst_spider_link_get (GstSpiderIdentity *src)
359 {
360   GstSpiderConnection *ret;
361   
362   if ((ret = gst_spider_link_find (src)) != NULL)
363   {
364     return ret;
365   }
366   return gst_spider_link_new (src);
367 }  
368 void                    
369 gst_spider_identity_plug (GstSpiderIdentity *ident)
370 {
371   GstSpider *spider;
372   const GList *padlist;
373   GstPadDirection dir;
374   GstSpiderConnection *conn;
375   
376   /* checks */
377   g_return_if_fail (ident != NULL);
378   g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
379   spider = GST_SPIDER (GST_ELEMENT_PARENT (ident));
380   g_assert (spider != NULL);
381   g_assert (GST_IS_SPIDER (spider));
382   
383   /* return if we're already plugged */
384   if (ident->plugged) return;
385
386   /* get the direction of our ident */
387   if (GST_PAD_PEER (ident->sink))
388   {
389     if (GST_PAD_PEER (ident->src))
390     {
391       /* Hey, the ident is linked on both sides */
392       g_warning ("Trying to autoplug a linked element. Aborting...");
393       return;
394     } else {
395       dir = GST_PAD_SINK;
396     }
397   } else {
398     if (GST_PAD_PEER (ident->src))
399     {
400       dir = GST_PAD_SRC;
401     } else {
402       /* the ident isn't linked on either side */
403       g_warning ("Trying to autoplug an unlinked element. Aborting...");
404       return;
405     }
406   }
407
408   /* now iterate all possible pads and link when needed */
409   padlist = gst_element_get_pad_list (GST_ELEMENT (spider));
410   while (padlist)
411   {
412     GstPad *otherpad;
413     GstSpiderIdentity *peer;
414
415     g_assert (GST_IS_PAD (padlist->data));
416     otherpad = (GstPad *) GST_GPAD_REALPAD (padlist->data);
417     peer = (GstSpiderIdentity *) GST_PAD_PARENT (otherpad);
418     /* we only want to link to the other side */
419     if (dir != GST_PAD_DIRECTION (otherpad))
420     {
421       /* we only link to plugged in elements */
422       if (peer->plugged == TRUE) 
423       {
424         /* plug in the right direction */
425         if (dir == GST_PAD_SINK)
426         {
427           conn = gst_spider_link_get (peer);
428         } else {
429           conn = gst_spider_link_get (ident);
430         }
431         if ((GstElement *) spider->sink_ident == conn->current)
432         {
433           gst_spider_plug (conn);
434         }
435       }
436     }
437     padlist = g_list_next (padlist);
438   }
439   
440   ident->plugged = TRUE; 
441 }
442 void
443 gst_spider_identity_unplug (GstSpiderIdentity *ident)
444 {
445   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (ident);
446   GList *list = spider->links;
447   
448   while (list)
449   {
450     GstSpiderConnection *conn = list->data;
451     GList *cur = list;
452     list = g_list_next (list);
453     if (conn->src == ident)
454     {
455       g_list_delete_link (spider->links, cur);
456       gst_spider_link_destroy (conn);
457     }
458   }
459   ident->plugged = FALSE;
460 }
461 /* links src to sink using the elementfactories in plugpath
462  * plugpath will be removed afterwards */
463 static GstPadLinkReturn
464 gst_spider_create_and_plug (GstSpiderConnection *conn, GList *plugpath)
465 {
466   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src);
467   GList *endelements = NULL, *templist = NULL;
468   GstElement *element;
469   
470   /* exit if plugging is already done */
471   if ((GstElement *) conn->src == conn->current)
472     return GST_PAD_LINK_DONE;
473   
474   /* try to shorten the list at the end and not duplicate link code */
475   if (plugpath != NULL)
476   {
477     templist = g_list_last (plugpath);
478     element = (GstElement *) conn->src;
479     while ((plugpath != NULL) && (element = gst_spider_find_element_to_plug (element, (GstElementFactory *) plugpath->data, GST_PAD_SINK)))
480     {
481       GList *cur = templist;
482       endelements = g_list_prepend (endelements, element);
483       templist = g_list_previous (templist);
484       g_list_delete_link (cur, cur);    
485     }
486   }
487   
488   /* do the linking */
489   while (conn->current != (GstElement *) (endelements == NULL ? conn->src : endelements->data))
490   {
491     /* get sink element to plug, src is conn->current */
492     if (plugpath == NULL)
493     {
494       element = (GstElement *) (endelements == NULL ? conn->src : endelements->data);
495     } else {
496       element = gst_element_factory_create ((GstElementFactory *) plugpath->data, NULL);
497       GST_DEBUG ("Adding element %s of type %s and syncing state with autoplugger", 
498                  GST_ELEMENT_NAME (element), GST_PLUGIN_FEATURE_NAME (plugpath->data));    
499       gst_bin_add (GST_BIN (spider), element);
500     }
501     /* insert and link new element */
502     if (gst_element_link (conn->current, element)) {
503       gst_element_sync_state_with_parent (element);    
504     } else {
505       /* check if the src has SOMETIMES templates. If so, link a callback */
506       GList *templs = gst_element_get_pad_template_list (conn->current);
507          
508       /* remove element that couldn't be linked, if it wasn't the endpoint */
509       if (element != (GstElement *) conn->src)
510         gst_bin_remove (GST_BIN (spider), element);
511     
512       while (templs) {
513         GstPadTemplate *templ = (GstPadTemplate *) templs->data;
514         if ((GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) && (GST_PAD_TEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES))
515         {
516           GST_DEBUG ("adding callback to link element %s to %s", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
517           conn->signal_id = g_signal_connect (G_OBJECT (conn->current), "new_pad", 
518                                               G_CALLBACK (gst_spider_link_sometimes), conn);
519           g_list_free (plugpath);
520           return GST_PAD_LINK_DELAYED;
521         }
522         templs = g_list_next (templs);
523       }
524       GST_DEBUG ("no chance to link element %s to %s", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
525       g_list_free (plugpath);
526       return GST_PAD_LINK_REFUSED;
527     }
528     GST_DEBUG ("added element %s and attached it to element %s", GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (conn->current));
529     gst_spider_link_add (conn, element);
530     if (plugpath != NULL)
531       plugpath = g_list_delete_link (plugpath, plugpath);
532   }
533   
534   /* ref all elements at the end */
535   while (endelements)
536   {
537     gst_spider_link_add (conn, endelements->data);
538     endelements = g_list_delete_link (endelements, endelements);
539   }
540   
541   return GST_PAD_LINK_DONE;
542 }
543 /* checks, if src is already linked to an element from factory fac on direction dir */
544 static GstElement *
545 gst_spider_find_element_to_plug (GstElement *src, GstElementFactory *fac, GstPadDirection dir)
546 {
547   GList *padlist = GST_ELEMENT_PADS (src);
548   
549   while (padlist)
550   {
551     GstPad *pad = (GstPad *) GST_PAD_REALIZE (padlist->data);
552     /* is the pad on the right side and is it linked? */
553     if ((GST_PAD_DIRECTION (pad) == dir) && (pad = (GstPad *) (GST_RPAD_PEER (pad))))
554     {
555       /* is the element the pad is linked to of the right type? */
556       GstElement *element = GST_PAD_PARENT (pad);
557       if (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))->elementfactory == fac) {
558         return element;
559       }
560     }
561     padlist = g_list_next (padlist);
562   }
563   
564   return NULL;
565 }
566 /* try to establish the link */
567 static GstPadLinkReturn
568 gst_spider_plug (GstSpiderConnection *conn)
569 {
570   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src);
571   if ((GstElement *) conn->src == conn->current)
572     return GST_PAD_LINK_DONE;
573   if ((GstElement *) spider->sink_ident == conn->current)
574     return gst_spider_plug_from_srcpad (conn, spider->sink_ident->src);
575   g_warning ("FIXME: autoplugging only possible from GstSpiderIdentity conn->sink yet (yep, that's technical)\n");
576   return GST_PAD_LINK_REFUSED;
577 }
578 /* try to establish the link using this pad */
579 static GstPadLinkReturn
580 gst_spider_plug_from_srcpad (GstSpiderConnection *conn, GstPad *srcpad)
581 {
582   GstElement *element;
583   GList *plugpath;
584   gboolean result = TRUE;
585   GstSpider *spider = (GstSpider *) GST_OBJECT_PARENT (conn->src);
586   GstElement *startelement = conn->current;
587
588   g_assert ((GstElement *) GST_OBJECT_PARENT (srcpad) == conn->current);
589   GST_DEBUG ("trying to plug from %s:%s to %s", 
590              GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (conn->src));
591   
592   /* find a path from src to sink */
593   plugpath = gst_autoplug_sp (gst_pad_get_caps (srcpad), gst_pad_get_caps (conn->src->sink), spider->factories);
594   
595   /* prints out the path that was found for plugging */
596   /* g_print ("found path from %s to %s:\n", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
597   templist = plugpath;
598   while (templist)
599   {
600     g_print("%s\n", GST_OBJECT_NAME (templist->data));
601     templist = g_list_next (templist);
602   }*/
603     
604   /* if there is no way to plug: return */
605   if (plugpath == NULL) {
606     GST_DEBUG ("no chance to plug from %s to %s", GST_ELEMENT_NAME (conn->current), GST_ELEMENT_NAME (conn->src));
607     return GST_PAD_LINK_REFUSED;
608   }
609   GST_DEBUG ("found a link that needs %d elements", g_list_length (plugpath));
610
611   /* now remove non-needed elements from the beginning of the path 
612    * alter src to point to the new element where we need to start 
613    * plugging and alter the plugpath to represent the elements, that must be plugged
614    */
615   element = conn->current;
616   while ((plugpath != NULL) && (element = gst_spider_find_element_to_plug (element, (GstElementFactory *) plugpath->data, GST_PAD_SRC)))
617   {
618     gst_spider_link_add (conn, element);
619     plugpath = g_list_delete_link (plugpath, plugpath);
620   }
621   
622   GST_DEBUG ("%d elements must be inserted to establish the link", g_list_length (plugpath));
623   /* create the elements and plug them */
624   result = gst_spider_create_and_plug (conn, plugpath);
625   
626   /* reset the "current" element */
627   if (result == GST_PAD_LINK_REFUSED)
628   {
629      gst_spider_link_reset (conn, startelement);
630   }
631   
632   return result;  
633 }
634
635 GstElementDetails gst_spider_details = {
636   "Spider",
637   "Generic",
638   "LGPL",
639   "Automatically link sinks and sources",
640   VERSION,
641   "Benjamin Otte <in7y118@public.uni-hamburg.de>",
642   "(C) 2002",
643 };
644
645 static gboolean
646 plugin_init (GModule *module, GstPlugin *plugin)
647 {
648   GstElementFactory *factory;
649
650   GST_DEBUG_CATEGORY_INIT (gst_spider_debug, "spider", 0, "spider autoplugging element");
651   GST_DEBUG_CATEGORY_INIT (gst_spider_identity_debug, "spideridentity", 0, "spider autoplugging proxy element");
652
653   factory = gst_element_factory_new("spider", GST_TYPE_SPIDER,
654                                    &gst_spider_details);
655   gst_plugin_set_longname (plugin, "Spider autoplugging elements");
656   g_return_val_if_fail(factory != NULL, FALSE);
657
658   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (spider_src_factory));
659
660   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
661
662   /* add spideridentity */
663   factory = gst_element_factory_new ("spideridentity", GST_TYPE_SPIDER_IDENTITY,
664                                      &gst_spider_identity_details);
665   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
666
667   return TRUE;
668 }
669
670 GstPluginDesc plugin_desc = {
671   GST_VERSION_MAJOR,
672   GST_VERSION_MINOR,
673   "gstspider",
674   plugin_init
675 };