A rather large patch:
[platform/upstream/gstreamer.git] / gst / gstplugin.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstplugin.c: Plugin subsystem for loading elements, types, and libs
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 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <dirent.h>
26 #include <unistd.h>
27
28 #include "gst_private.h"
29 #include "gstplugin.h"
30 #include "config.h"
31
32
33 /* list of loaded modules and its sequence number */
34 GList *_gst_modules;
35 gint _gst_modules_seqno;
36 /* global list of plugins and its sequence number */
37 GList *_gst_plugins;
38 gint _gst_plugins_seqno;
39 gint _gst_plugin_elementfactories = 0;
40 gint _gst_plugin_types = 0;
41 /* list of paths to check for plugins */
42 GList *_gst_plugin_paths;
43
44 GList *_gst_libraries;
45 gint _gst_libraries_seqno;
46
47 /* whether or not to spew library load issues */
48 gboolean _gst_plugin_spew = FALSE;
49
50 /* whether or not to warn if registry needs rebuild (gstreamer-register sets
51  * this to false.) */
52 gboolean _gst_warn_old_registry = TRUE;
53
54 static gboolean plugin_times_older_than(time_t regtime);
55 static time_t get_time(const char * path);
56
57 void
58 _gst_plugin_initialize (void)
59 {
60   xmlDocPtr doc;
61   _gst_modules = NULL;
62   _gst_modules_seqno = 0;
63   _gst_plugins = NULL;
64   _gst_plugins_seqno = 0;
65   _gst_plugin_paths = NULL;
66   _gst_libraries = NULL;
67   _gst_libraries_seqno = 0;
68
69   /* add the main (installed) library path */
70   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths, PLUGINS_DIR);
71
72   /* if this is set, we add build-directory paths to the list */
73 #ifdef PLUGINS_USE_SRCDIR
74   /* the catch-all plugins directory */
75   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
76                                       PLUGINS_SRCDIR "/plugins");
77   /* the libreary directory */
78   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
79                                       PLUGINS_SRCDIR "/libs");
80   /* location libgstelements.so */
81   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
82                                       PLUGINS_SRCDIR "/gst/elements");
83   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
84                                       PLUGINS_SRCDIR "/gst/types");
85   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
86                                       PLUGINS_SRCDIR "/gst/autoplug");
87 #endif /* PLUGINS_USE_SRCDIR */
88
89   doc = xmlParseFile (GST_CONFIG_DIR"/reg.xml");
90
91   if (!doc || 
92       !doc->xmlRootNode ||
93       doc->xmlRootNode->name == 0 ||
94       strcmp (doc->xmlRootNode->name, "GST-PluginRegistry") ||
95       !plugin_times_older_than(get_time(GST_CONFIG_DIR"/reg.xml"))) {
96     if (_gst_warn_old_registry)
97         g_warning ("gstplugin: registry needs rebuild: run gstreamer-register\n");
98     gst_plugin_load_all ();
99     return;
100   }
101   gst_plugin_load_thyself (doc->xmlRootNode);
102
103   xmlFreeDoc (doc);
104 }
105
106 /**
107  * gst_plugin_add_path:
108  * @path: the directory to add to the search path
109  *
110  * Add a directory to the path searched for plugins.
111  */
112 void
113 gst_plugin_add_path (const gchar *path)
114 {
115   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,g_strdup(path));
116 }
117
118 static time_t
119 get_time(const char * path)
120 {
121   struct stat statbuf;
122   if (stat(path, &statbuf)) return 0;
123   if (statbuf.st_mtime > statbuf.st_ctime) return statbuf.st_mtime;
124   return statbuf.st_ctime;
125 }
126
127 static gboolean
128 plugin_times_older_than_recurse(gchar *path, time_t regtime)
129 {
130   DIR *dir;
131   struct dirent *dirent;
132   gchar *pluginname;
133
134   time_t pathtime = get_time(path);
135
136   if (pathtime > regtime) {
137     GST_INFO (GST_CAT_PLUGIN_LOADING,
138                "time for %s was %ld; more recent than registry time of %ld\n",
139                path, (long)pathtime, (long)regtime);
140     return FALSE;
141   }
142
143   dir = opendir(path);
144   if (dir) {
145     while ((dirent = readdir(dir))) {
146       /* don't want to recurse in place or backwards */
147       if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
148         pluginname = g_strjoin("/",path,dirent->d_name,NULL);
149         if (!plugin_times_older_than_recurse(pluginname , regtime)) {
150           g_free (pluginname);
151           closedir(dir);
152           return FALSE;
153         }
154         g_free (pluginname);
155       }
156     }
157     closedir(dir);
158   }
159   return TRUE;
160 }
161
162 static gboolean
163 plugin_times_older_than(time_t regtime)
164 {
165   // return true iff regtime is more recent than the times of all the files
166   // in the plugin dirs.
167   GList *path;
168   path = _gst_plugin_paths;
169   while (path != NULL) {
170     GST_DEBUG (GST_CAT_PLUGIN_LOADING,
171                "comparing plugin times from %s with %ld\n",
172                (gchar *)path->data, (long) regtime);
173     if(!plugin_times_older_than_recurse(path->data, regtime))
174         return FALSE;
175     path = g_list_next(path);
176   }
177   return TRUE;
178 }
179
180 static gboolean
181 gst_plugin_load_recurse (gchar *directory, gchar *name)
182 {
183   DIR *dir;
184   struct dirent *dirent;
185   gboolean loaded = FALSE;
186   gchar *dirname;
187
188   //g_print("recursive load of '%s' in '%s'\n", name, directory);
189   dir = opendir(directory);
190   if (dir) {
191     while ((dirent = readdir(dir))) {
192       /* don't want to recurse in place or backwards */
193       if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
194         dirname = g_strjoin("/",directory,dirent->d_name,NULL);
195         loaded = gst_plugin_load_recurse(dirname,name);
196         g_free(dirname);
197         if (loaded && name) {
198           closedir(dir);
199           return TRUE;
200         }
201       }
202     }
203     closedir(dir);
204   } else {
205     if (strstr(directory,".so")) {
206       gchar *temp;
207       if (name) {
208         if ((temp = strstr(directory,name)) &&
209             (!strcmp(temp,name))) {
210           loaded = gst_plugin_load_absolute(directory);
211         }
212       } else if ((temp = strstr(directory,".so")) &&
213                  (!strcmp(temp,".so"))) {
214         loaded = gst_plugin_load_absolute(directory);
215       }
216     }
217   }
218   return loaded;
219 }
220
221 /**
222  * gst_plugin_load_all:
223  *
224  * Load all plugins in the path.
225  */
226 void
227 gst_plugin_load_all(void)
228 {
229   GList *path;
230
231   path = _gst_plugin_paths;
232   while (path != NULL) {
233     GST_INFO (GST_CAT_PLUGIN_LOADING,"loading plugins from %s",(gchar *)path->data);
234     gst_plugin_load_recurse(path->data,NULL);
235     path = g_list_next(path);
236   }
237   GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded %d plugins with %d elements and %d types",
238        _gst_plugins_seqno,_gst_plugin_elementfactories,_gst_plugin_types);
239 }
240
241 /**
242  * gst_library_load:
243  * @name: name of library to load
244  *
245  * Load the named library.  Name should be given as
246  * &quot;liblibrary.so&quot;.
247  *
248  * Returns: whether the library was loaded or not
249  */
250 gboolean
251 gst_library_load (const gchar *name)
252 {
253   gboolean res;
254   GList *libraries = _gst_libraries;
255
256   while (libraries) {
257     if (!strcmp((gchar *)libraries->data, name)) return TRUE;
258
259     libraries = g_list_next(libraries);
260   }
261
262   // for now this is the same
263   res = gst_plugin_load(name);
264
265   if (res) {
266     _gst_libraries = g_list_prepend(_gst_libraries, g_strdup (name));
267   }
268
269   return res;
270 }
271
272 static void
273 gst_plugin_remove (GstPlugin *plugin)
274 {
275   GList *factories;
276
277   factories = plugin->elements;
278   while (factories) {
279     gst_elementfactory_destroy ((GstElementFactory*)(factories->data));
280     factories = g_list_next(factories);
281   }
282
283   _gst_plugins = g_list_remove(_gst_plugins, plugin);
284
285   // don't free the stuct because someone can have a handle to it
286 }
287
288 /**
289  * gst_plugin_load:
290  * @name: name of plugin to load
291  *
292  * Load the named plugin.  Name should be given as
293  * &quot;libplugin.so&quot;.
294  *
295  * Returns: whether the plugin was loaded or not
296  */
297 gboolean
298 gst_plugin_load (const gchar *name)
299 {
300   GList *path;
301   gchar *libspath;
302   GstPlugin *plugin;
303   gchar *pluginname;
304
305   //g_print("attempting to load plugin '%s'\n",name);
306
307   plugin = gst_plugin_find (name);
308
309   if (plugin && plugin->loaded) return TRUE;
310
311   path = _gst_plugin_paths;
312   while (path != NULL) {
313     pluginname = g_module_build_path(path->data,name);
314     if (gst_plugin_load_absolute(pluginname)) {
315       g_free(pluginname);
316       return TRUE;
317     }
318     g_free(pluginname);
319     libspath = g_strconcat(path->data,"/.libs",NULL);
320     //g_print("trying to load '%s'\n",g_module_build_path(libspath,name));
321     pluginname = g_module_build_path(libspath,name);
322     g_free(libspath);
323     if (gst_plugin_load_absolute(pluginname)) {
324       g_free(pluginname);
325       return TRUE;
326     }
327     g_free(pluginname);
328     //g_print("trying to load '%s' from '%s'\n",name,path->data);
329     pluginname = g_module_build_path("",name);
330     if (gst_plugin_load_recurse(path->data,pluginname)) {
331       g_free(pluginname);
332       return TRUE;
333     }
334     g_free(pluginname);
335     path = g_list_next(path);
336   }
337   return FALSE;
338 }
339
340 /**
341  * gst_plugin_load_absolute:
342  * @name: name of plugin to load
343  *
344  * Returns: whether or not the plugin loaded
345  */
346 gboolean
347 gst_plugin_load_absolute (const gchar *name)
348 {
349   GModule *module;
350   GstPluginInitFunc initfunc;
351   GstPlugin *plugin;
352   struct stat file_status;
353
354   if (g_module_supported() == FALSE) {
355     g_warning("gstplugin: wow, you built this on a platform without dynamic loading???\n");
356     return FALSE;
357   }
358
359   if (stat(name,&file_status)) {
360 //    g_print("problem opening file %s\n",name);
361     return FALSE;
362   }
363
364   module = g_module_open(name,G_MODULE_BIND_LAZY);
365   if (module != NULL) {
366     if (g_module_symbol(module,"plugin_init",(gpointer *)&initfunc)) {
367       GST_INFO (GST_CAT_PLUGIN_LOADING,"loading plugin \"%s\"...",
368            name);
369       if ((plugin = (initfunc)(module))) {
370         GST_INFO (GST_CAT_PLUGIN_LOADING,"plugin \"%s\" loaded: %d elements, %d types",
371              plugin->name,plugin->numelements,plugin->numtypes);
372         plugin->filename = g_strdup(name);
373         plugin->loaded = TRUE;
374         _gst_modules = g_list_prepend(_gst_modules,module);
375         _gst_modules_seqno++;
376         _gst_plugins = g_list_prepend(_gst_plugins,plugin);
377         _gst_plugins_seqno++;
378         _gst_plugin_elementfactories += plugin->numelements;
379         _gst_plugin_types += plugin->numtypes;
380         return TRUE;
381       }
382     }
383     return TRUE;
384   } else if (_gst_plugin_spew) {
385     // FIXME this should be some standard gst mechanism!!!
386     g_printerr ("error loading plugin %s, reason: %s\n", name, g_module_error());
387   }
388
389   return FALSE;
390 }
391
392 /**
393  * gst_plugin_new:
394  * @name: name of new plugin
395  *
396  * Create a new plugin with given name.
397  *
398  * Returns: new plugin
399  */
400 GstPlugin*
401 gst_plugin_new (const gchar *name)
402 {
403   GstPlugin *plugin;
404
405   // return NULL if the plugin is allready loaded
406   plugin = gst_plugin_find (name);
407   if (plugin) return NULL;
408
409   plugin = (GstPlugin *)g_malloc(sizeof(GstPlugin));
410
411   plugin->name = g_strdup(name);
412   plugin->longname = NULL;
413   plugin->elements = NULL;
414   plugin->numelements = 0;
415   plugin->types = NULL;
416   plugin->numtypes = 0;
417   plugin->autopluggers = NULL;
418   plugin->numautopluggers = 0;
419   plugin->loaded = TRUE;
420
421   return plugin;
422 }
423
424 /**
425  * gst_plugin_get_name:
426  * @plugin: plugin to get the name of
427  *
428  * Get the short name of the plugin
429  *
430  * Returns: the name of the plugin
431  */
432 const gchar*
433 gst_plugin_get_name (GstPlugin *plugin)
434 {
435   g_return_val_if_fail (plugin != NULL, NULL);
436
437   return plugin->name;
438 }
439
440 /**
441  * gst_plugin_set_name:
442  * @plugin: plugin to set name of
443  * @name: new name
444  *
445  * Sets the name (should be short) of the plugin.
446  */
447 void
448 gst_plugin_set_name (GstPlugin *plugin, const gchar *name)
449 {
450   g_return_if_fail (plugin != NULL);
451
452   if (plugin->name)
453     g_free (plugin->name);
454
455   plugin->name = g_strdup (name);
456 }
457
458 /**
459  * gst_plugin_set_longname:
460  * @plugin: plugin to set long name of
461  * @longname: new long name
462  *
463  * Sets the long name (should be descriptive) of the plugin.
464  */
465 void
466 gst_plugin_set_longname (GstPlugin *plugin, const gchar *longname)
467 {
468   g_return_if_fail(plugin != NULL);
469
470   if (plugin->longname)
471     g_free(plugin->longname);
472
473   plugin->longname = g_strdup(longname);
474 }
475
476 /**
477  * gst_plugin_get_longname:
478  * @plugin: plugin to get long name of
479  *
480  * Get the long descriptive name of the plugin
481  *
482  * Returns: the long name of the plugin
483  */
484 const gchar*
485 gst_plugin_get_longname (GstPlugin *plugin)
486 {
487   g_return_val_if_fail (plugin != NULL, NULL);
488
489   return plugin->longname;
490 }
491
492 /**
493  * gst_plugin_get_filename:
494  * @plugin: plugin to get the filename of
495  *
496  * get the filename of the plugin
497  *
498  * Returns: the filename of the plugin
499  */
500 const gchar*
501 gst_plugin_get_filename (GstPlugin *plugin)
502 {
503   g_return_val_if_fail (plugin != NULL, NULL);
504
505   return plugin->filename;
506 }
507
508 /**
509  * gst_plugin_is_loaded:
510  * @plugin: plugin to query
511  *
512  * queries if the plugin is loaded into memory
513  *
514  * Returns: TRUE is loaded, FALSE otherwise
515  */
516 gboolean
517 gst_plugin_is_loaded (GstPlugin *plugin)
518 {
519   g_return_val_if_fail (plugin != NULL, FALSE);
520
521   return plugin->loaded;
522 }
523
524
525 /**
526  * gst_plugin_find:
527  * @name: name of plugin to find
528  *
529  * Search the list of registered plugins for one of the given name
530  *
531  * Returns: pointer to the #GstPlugin if found, NULL otherwise
532  */
533 GstPlugin*
534 gst_plugin_find (const gchar *name)
535 {
536   GList *plugins = _gst_plugins;
537
538   g_return_val_if_fail(name != NULL, NULL);
539
540   while (plugins) {
541     GstPlugin *plugin = (GstPlugin *)plugins->data;
542 //    g_print("plugin name is '%s'\n",plugin->name);
543     if (plugin->name) {
544       if (!strcmp(plugin->name,name)) {
545         return plugin;
546       }
547     }
548     plugins = g_list_next(plugins);
549   }
550   return NULL;
551 }
552
553 static GstElementFactory*
554 gst_plugin_find_elementfactory (const gchar *name)
555 {
556   GList *plugins, *factories;
557   GstElementFactory *factory;
558
559   g_return_val_if_fail(name != NULL, NULL);
560
561   plugins = _gst_plugins;
562   while (plugins) {
563     factories = ((GstPlugin *)(plugins->data))->elements;
564     while (factories) {
565       factory = (GstElementFactory*)(factories->data);
566       if (!strcmp(factory->name, name))
567         return (GstElementFactory*)(factory);
568       factories = g_list_next(factories);
569     }
570     plugins = g_list_next(plugins);
571   }
572
573   return NULL;
574 }
575
576 /**
577  * gst_plugin_load_elementfactory:
578  * @name: name of elementfactory to load
579  *
580  * Load a registered elementfactory by name.
581  *
582  * Returns: @GstElementFactory if loaded, NULL if not
583  */
584 GstElementFactory*
585 gst_plugin_load_elementfactory (const gchar *name)
586 {
587   GList *plugins, *factories;
588   GstElementFactory *factory = NULL;
589   GstPlugin *plugin;
590
591   g_return_val_if_fail(name != NULL, NULL);
592
593   plugins = _gst_plugins;
594   while (plugins) {
595     plugin = (GstPlugin *)plugins->data;
596     factories = plugin->elements;
597
598     while (factories) {
599       factory = (GstElementFactory*)(factories->data);
600
601       if (!strcmp(factory->name,name)) {
602         if (!plugin->loaded) {
603           gchar *filename = g_strdup (plugin->filename);
604           gchar *pluginname = g_strdup (plugin->name);
605
606           GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded elementfactory %s from plugin %s",name,plugin->name);
607           gst_plugin_remove(plugin);
608           if (!gst_plugin_load_absolute(filename)) {
609             GST_DEBUG (0,"gstplugin: error loading element factory %s from plugin %s\n", name, pluginname);
610           }
611           g_free (pluginname);
612           g_free (filename);
613         }
614         factory = gst_plugin_find_elementfactory(name);
615         return factory;
616       }
617       factories = g_list_next(factories);
618     }
619     plugins = g_list_next(plugins);
620   }
621
622   return factory;
623 }
624
625 static GstAutoplugFactory*
626 gst_plugin_find_autoplugfactory (const gchar *name)
627 {
628   GList *plugins, *factories;
629   GstAutoplugFactory *factory;
630
631   g_return_val_if_fail(name != NULL, NULL);
632
633   plugins = _gst_plugins;
634   while (plugins) {
635     factories = ((GstPlugin *)(plugins->data))->autopluggers;
636     while (factories) {
637       factory = (GstAutoplugFactory*)(factories->data);
638       if (!strcmp(factory->name, name))
639         return (GstAutoplugFactory*)(factory);
640       factories = g_list_next(factories);
641     }
642     plugins = g_list_next(plugins);
643   }
644
645   return NULL;
646 }
647 /**
648  * gst_plugin_load_autoplugfactory:
649  * @name: name of autoplugfactory to load
650  *
651  * Load a registered autoplugfactory by name.
652  *
653  * Returns: @GstAutoplugFactory if loaded, NULL if not
654  */
655 GstAutoplugFactory*
656 gst_plugin_load_autoplugfactory (const gchar *name)
657 {
658   GList *plugins, *factories;
659   GstAutoplugFactory *factory = NULL;
660   GstPlugin *plugin;
661
662   g_return_val_if_fail(name != NULL, NULL);
663
664   plugins = _gst_plugins;
665   while (plugins) {
666     plugin = (GstPlugin *)plugins->data;
667     factories = plugin->autopluggers;
668
669     while (factories) {
670       factory = (GstAutoplugFactory*)(factories->data);
671
672       if (!strcmp(factory->name,name)) {
673         if (!plugin->loaded) {
674           gchar *filename = g_strdup (plugin->filename);
675           gchar *pluginname = g_strdup (plugin->name);
676
677           GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded autoplugfactory %s from plugin %s",name,plugin->name);
678           gst_plugin_remove(plugin);
679           if (!gst_plugin_load_absolute(filename)) {
680             GST_DEBUG (0,"gstplugin: error loading autoplug factory %s from plugin %s\n", name, pluginname);
681           }
682           g_free (pluginname);
683           g_free (filename);
684         }
685         factory = gst_plugin_find_autoplugfactory(name);
686         return factory;
687       }
688       factories = g_list_next(factories);
689     }
690     plugins = g_list_next(plugins);
691   }
692
693   return factory;
694 }
695
696 /**
697  * gst_plugin_load_typefactory:
698  * @mime: name of typefactory to load
699  *
700  * Load a registered typefactory by mime type.
701  */
702 void
703 gst_plugin_load_typefactory (const gchar *mime)
704 {
705   GList *plugins, *factories;
706   GstTypeFactory *factory;
707   GstPlugin *plugin;
708
709   g_return_if_fail (mime != NULL);
710
711   plugins = g_list_copy (_gst_plugins);
712   while (plugins) {
713     plugin = (GstPlugin *)plugins->data;
714     factories = g_list_copy (plugin->types);
715
716     while (factories) {
717       factory = (GstTypeFactory*)(factories->data);
718
719       if (!strcmp(factory->mime,mime)) {
720         if (!plugin->loaded) {
721           gchar *filename = g_strdup (plugin->filename);
722           gchar *pluginname = g_strdup (plugin->name);
723
724           GST_INFO (GST_CAT_PLUGIN_LOADING,"loading type factory for \"%s\" from plugin %s",mime,plugin->name);
725           plugin->loaded = TRUE;
726           gst_plugin_remove(plugin);
727           if (!gst_plugin_load_absolute(filename)) {
728             GST_DEBUG (0,"gstplugin: error loading type factory \"%s\" from plugin %s\n", mime, pluginname);
729           }
730           g_free (filename);
731           g_free (pluginname);
732         }
733         //return;
734       }
735       factories = g_list_next(factories);
736     }
737
738     g_list_free (factories);
739     plugins = g_list_next(plugins);
740   }
741   g_list_free (plugins);
742
743   return;
744 }
745
746 /**
747  * gst_plugin_add_factory:
748  * @plugin: plugin to add factory to
749  * @factory: factory to add
750  *
751  * Add factory to the list of those provided by the plugin.
752  */
753 void
754 gst_plugin_add_factory (GstPlugin *plugin, GstElementFactory *factory)
755 {
756   g_return_if_fail (plugin != NULL);
757   g_return_if_fail (factory != NULL);
758
759 //  g_print("adding factory to plugin\n");
760   plugin->elements = g_list_prepend (plugin->elements, factory);
761   plugin->numelements++;
762 }
763
764 /**
765  * gst_plugin_add_type:
766  * @plugin: plugin to add type to
767  * @factory: the typefactory to add
768  *
769  * Add a typefactory to the list of those provided by the plugin.
770  */
771 void
772 gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory)
773 {
774   g_return_if_fail (plugin != NULL);
775   g_return_if_fail (factory != NULL);
776
777 //  g_print("adding factory to plugin\n");
778   plugin->types = g_list_prepend (plugin->types, factory);
779   plugin->numtypes++;
780   gst_type_register (factory);
781 }
782
783 /**
784  * gst_plugin_add_autoplugger:
785  * @plugin: plugin to add the autoplugger to
786  * @factory: the autoplugfactory to add
787  *
788  * Add an autoplugfactory to the list of those provided by the plugin.
789  */
790 void
791 gst_plugin_add_autoplugger (GstPlugin *plugin, GstAutoplugFactory *factory)
792 {
793   g_return_if_fail (plugin != NULL);
794   g_return_if_fail (factory != NULL);
795
796 //  g_print("adding factory to plugin\n");
797   plugin->autopluggers = g_list_prepend (plugin->autopluggers, factory);
798   plugin->numautopluggers++;
799 }
800
801 /**
802  * gst_plugin_get_list:
803  *
804  * get the currently loaded plugins
805  *
806  * Returns; a GList of GstPlugin elements
807  */
808 GList*
809 gst_plugin_get_list (void)
810 {
811   return _gst_plugins;
812 }
813
814 /**
815  * gst_plugin_save_thyself:
816  * @parent: the parent node to save the plugin to
817  *
818  * saves the plugin into an XML representation
819  *
820  * Returns: the new XML node
821  */
822 xmlNodePtr
823 gst_plugin_save_thyself (xmlNodePtr parent)
824 {
825   xmlNodePtr tree, subtree;
826   GList *plugins = NULL, *elements = NULL, *types = NULL, *autopluggers = NULL;
827
828   plugins = gst_plugin_get_list ();
829   while (plugins) {
830     GstPlugin *plugin = (GstPlugin *)plugins->data;
831
832     tree = xmlNewChild (parent, NULL, "plugin", NULL);
833     xmlNewChild (tree, NULL, "name", plugin->name);
834     xmlNewChild (tree, NULL, "longname", plugin->longname);
835     xmlNewChild (tree, NULL, "filename", plugin->filename);
836
837     types = plugin->types;
838     while (types) {
839       GstTypeFactory *factory = (GstTypeFactory *)types->data;
840       subtree = xmlNewChild(tree, NULL, "typefactory", NULL);
841
842       gst_typefactory_save_thyself (factory, subtree);
843
844       types = g_list_next (types);
845     }
846     elements = plugin->elements;
847     while (elements) {
848       GstElementFactory *factory = (GstElementFactory *)elements->data;
849       subtree = xmlNewChild (tree, NULL, "elementfactory", NULL);
850
851       gst_elementfactory_save_thyself (factory, subtree);
852
853       elements = g_list_next (elements);
854     }
855     autopluggers = plugin->autopluggers;
856     while (autopluggers) {
857       GstAutoplugFactory *factory = (GstAutoplugFactory *)autopluggers->data;
858       subtree = xmlNewChild (tree, NULL, "autoplugfactory", NULL);
859
860       gst_autoplugfactory_save_thyself (factory, subtree);
861
862       autopluggers = g_list_next (autopluggers);
863     }
864     plugins = g_list_next (plugins);
865   }
866   return parent;
867 }
868
869 /**
870  * gst_plugin_load_thyself:
871  * @parent: the parent node to load the plugin from
872  *
873  * load the plugin from an XML representation
874  */
875 void
876 gst_plugin_load_thyself (xmlNodePtr parent)
877 {
878   xmlNodePtr kinderen;
879   gint elementcount = 0;
880   gint autoplugcount = 0;
881   gint typecount = 0;
882   gchar *pluginname;
883
884   kinderen = parent->xmlChildrenNode; // Dutch invasion :-)
885   while (kinderen) {
886     if (!strcmp (kinderen->name, "plugin")) {
887       xmlNodePtr field = kinderen->xmlChildrenNode;
888       GstPlugin *plugin = g_new0 (GstPlugin, 1);
889
890       plugin->elements = NULL;
891       plugin->types = NULL;
892       plugin->loaded = FALSE;
893
894       while (field) {
895         if (!strcmp (field->name, "name")) {
896           pluginname = xmlNodeGetContent (field);
897           if (gst_plugin_find (pluginname)) {
898             g_free (pluginname);
899             g_free (plugin);
900             plugin = NULL;
901             break;
902           } else {
903             plugin->name = pluginname;
904           }
905         }
906         else if (!strcmp (field->name, "longname")) {
907           plugin->longname = xmlNodeGetContent (field);
908         }
909         else if (!strcmp (field->name, "filename")) {
910           plugin->filename = xmlNodeGetContent (field);
911         }
912         else if (!strcmp (field->name, "elementfactory")) {
913           GstElementFactory *factory = gst_elementfactory_load_thyself (field);
914           gst_plugin_add_factory (plugin, factory);
915           elementcount++;
916         }
917         else if (!strcmp (field->name, "autoplugfactory")) {
918           GstAutoplugFactory *factory = gst_autoplugfactory_load_thyself (field);
919           gst_plugin_add_autoplugger (plugin, factory);
920           autoplugcount++;
921         }
922         else if (!strcmp (field->name, "typefactory")) {
923           GstTypeFactory *factory = gst_typefactory_load_thyself (field);
924           gst_plugin_add_type (plugin, factory);
925           elementcount++;
926           typecount++;
927         }
928
929         field = field->next;
930       }
931
932       if (plugin) {
933         _gst_plugins = g_list_prepend (_gst_plugins, plugin);
934       }
935     }
936
937     kinderen = kinderen->next;
938   }
939   GST_INFO (GST_CAT_PLUGIN_LOADING, "added %d registered factories, %d autopluggers and %d types",
940                   elementcount, autoplugcount, typecount);
941 }
942
943
944 /**
945  * gst_plugin_get_factory_list:
946  * @plugin: the plugin to get the factories from
947  *
948  * get a list of all the factories that this plugin provides
949  *
950  * Returns: a GList of factories
951  */
952 GList*
953 gst_plugin_get_factory_list (GstPlugin *plugin)
954 {
955   g_return_val_if_fail (plugin != NULL, NULL);
956
957   return plugin->elements;
958 }
959
960 /**
961  * gst_plugin_get_type_list:
962  * @plugin: the plugin to get the typefactories from
963  *
964  * get a list of all the typefactories that this plugin provides
965  *
966  * Returns: a GList of factories
967  */
968 GList*
969 gst_plugin_get_type_list (GstPlugin *plugin)
970 {
971   g_return_val_if_fail (plugin != NULL, NULL);
972
973   return plugin->types;
974 }
975
976 /**
977  * gst_plugin_get_autoplug_list:
978  * @plugin: the plugin to get the autoplugfactories from
979  *
980  * get a list of all the autoplugfactories that this plugin provides
981  *
982  * Returns: a GList of factories
983  */
984 GList*
985 gst_plugin_get_autoplug_list (GstPlugin *plugin)
986 {
987   g_return_val_if_fail (plugin != NULL, NULL);
988
989   return plugin->autopluggers;
990 }