Some plugins are adjusted to the new pad template mechanisms.
[platform/upstream/gstreamer.git] / gst / gstplugin.c
1 /* Gnome-Streamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  * 
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <dirent.h>
24 #include <unistd.h>
25 #include <string.h>
26
27 #include <gst/gstplugin.h>
28
29 #include "config.h"
30
31 //#undef PLUGINS_USE_SRCDIR
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 /* list of paths to check for plugins */
40 GList *_gst_plugin_paths;
41
42 GList *_gst_libraries;
43 gint _gst_libraries_seqno;
44
45 /* whether or not to spew library load issues */
46 gboolean _gst_plugin_spew = TRUE;
47
48
49 void _gst_plugin_initialize() {
50   xmlDocPtr doc;
51   _gst_modules = NULL;
52   _gst_modules_seqno = 0;
53   _gst_plugins = NULL;
54   _gst_plugins_seqno = 0;
55   _gst_plugin_paths = NULL;
56   _gst_libraries = NULL;
57   _gst_libraries_seqno = 0;
58
59
60   /* if this is set, we add build-directory paths to the list */
61 #ifdef PLUGINS_USE_SRCDIR
62   /* the catch-all plugins directory */
63   _gst_plugin_paths = g_list_append(_gst_plugin_paths,
64                                      PLUGINS_SRCDIR "/plugins");
65   /* the libreary directory */
66   _gst_plugin_paths = g_list_append(_gst_plugin_paths,
67                                      PLUGINS_SRCDIR "/libs");
68   /* location libgstelements.so */
69   _gst_plugin_paths = g_list_append(_gst_plugin_paths,
70                                      PLUGINS_SRCDIR "/gst/elements");
71   _gst_plugin_paths = g_list_append(_gst_plugin_paths,
72                                      PLUGINS_SRCDIR "/gst/types");
73 #else
74   /* add the main (installed) library path */
75   _gst_plugin_paths = g_list_append(_gst_plugin_paths,PLUGINS_DIR);
76 #endif /* PLUGINS_USE_SRCDIR */
77
78   doc = xmlParseFile("/etc/gstreamer/reg.xml");
79
80   if (!doc || strcmp(doc->root->name, "GST-PluginRegistry")) {
81     g_print("gstplugin: registry needs rebuild\n");
82     gst_plugin_load_all();
83     return;
84   }
85   gst_plugin_load_thyself(doc->root);
86 }
87
88 static gboolean gst_plugin_load_recurse(gchar *directory,gchar *name) {
89   DIR *dir;
90   struct dirent *dirent;
91   gboolean loaded = FALSE;
92
93         //g_print("recursive load of '%s' in '%s'\n", name, directory);
94   dir = opendir(directory);
95   if (dir) {
96     while ((dirent = readdir(dir))) {
97       /* don't want to recurse in place or backwards */
98       if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
99         loaded = gst_plugin_load_recurse(g_strjoin("/",directory,dirent->d_name,
100                                               NULL),name);
101                                 if (loaded && name) return TRUE;
102       }
103     }
104     closedir(dir);
105   } else {
106     if (strstr(directory,".so")) {
107       gchar *temp;
108       if (name) {
109         if ((temp = strstr(directory,name)) && 
110             (!strcmp(temp,name))) {
111           loaded = gst_plugin_load_absolute(directory);
112           return loaded;
113         }
114       } else if ((temp = strstr(directory,".so")) &&
115                  (!strcmp(temp,".so"))) {
116         loaded = gst_plugin_load_absolute(directory);
117         //return loaded;
118       }
119     }
120   }
121   return loaded;
122 }
123
124 /**
125  * gst_plugin_load_all:
126  *
127  * Load all plugins in the path.
128  */
129 void gst_plugin_load_all() {
130   GList *path;
131
132   path = _gst_plugin_paths;
133   while (path != NULL) {
134     gst_plugin_load_recurse(path->data,NULL);
135     path = g_list_next(path);
136   }
137 }
138
139 /**
140  * gst_library_load:
141  * @name: name of library to load
142  *
143  * Load the named library.  Name should be given as
144  * &quot;liblibrary.so&quot;.
145  *
146  * Returns: whether the library was loaded or not
147  */
148 gboolean gst_library_load(gchar *name) {
149   gboolean res;
150   GList *libraries = _gst_libraries;
151
152   while (libraries) {
153     if (!strcmp((gchar *)libraries->data, name)) return TRUE;
154
155     libraries = g_list_next(libraries);
156   }
157   
158   // for now this is the same
159   res = gst_plugin_load(name);
160
161   if (res) {
162     _gst_libraries = g_list_prepend(_gst_libraries, name);
163   }
164
165   return res;
166 }
167
168 static void 
169 gst_plugin_remove(GstPlugin *plugin) 
170 {
171   GList *factories;
172
173   factories = plugin->elements;
174   while (factories) {
175     gst_elementfactory_unregister((GstElementFactory*)(factories->data));
176     factories = g_list_next(factories);
177   }
178   _gst_plugins = g_list_remove(_gst_plugins, plugin);
179   g_free (plugin);
180 }
181
182 /**
183  * gst_plugin_load:
184  * @name: name of plugin to load
185  *
186  * Load the named plugin.  Name should be given as
187  * &quot;libplugin.so&quot;.
188  *
189  * Returns: whether the plugin was loaded or not
190  */
191 gboolean gst_plugin_load(gchar *name) {
192   GList *path;
193   gchar *libspath;
194
195   //g_print("attempting to load plugin '%s'\n",name);
196
197   path = _gst_plugin_paths;
198   while (path != NULL) {
199     if (gst_plugin_load_absolute(g_module_build_path(path->data,name)))
200       return TRUE;
201     libspath = g_strconcat(path->data,"/.libs",NULL);
202     //g_print("trying to load '%s'\n",g_module_build_path(libspath,name));
203     if (gst_plugin_load_absolute(g_module_build_path(libspath,name))) {
204       g_free(libspath);
205       return TRUE;
206     }
207     g_free(libspath);
208     //g_print("trying to load '%s' from '%s'\n",name,path->data);
209     if (gst_plugin_load_recurse(path->data,g_module_build_path("",name))) {
210       return TRUE;
211     }
212     path = g_list_next(path);
213   }
214   return FALSE;
215 }
216
217 /**
218  * gst_plugin_load_absolute:
219  * @name: name of plugin to load
220  *
221  * Returns: whether or not the plugin loaded
222  */
223 gboolean gst_plugin_load_absolute(gchar *name) {
224   GModule *module;
225   GstPluginInitFunc initfunc;
226   GstPlugin *plugin;
227   struct stat file_status;
228
229   if (g_module_supported() == FALSE) {
230     g_print("gstplugin: wow, you built this on a platform without dynamic loading???\n");
231     return FALSE;
232   }
233
234   if (stat(name,&file_status)) {
235 //    g_print("problem opening file %s\n",name);
236     return FALSE;
237   }
238
239   module = g_module_open(name,G_MODULE_BIND_LAZY);
240   if (module != NULL) {
241     if (g_module_symbol(module,"plugin_init",(gpointer *)&initfunc)) {
242       if ((plugin = (initfunc)(module))) {
243         g_print("gstplugin: plugin %s loaded\n", plugin->name);
244         plugin->filename = g_strdup(name);
245         plugin->loaded = TRUE;
246         _gst_modules = g_list_append(_gst_modules,module);
247         _gst_modules_seqno++;
248         _gst_plugins = g_list_prepend(_gst_plugins,plugin);
249         _gst_plugins_seqno++;
250         return TRUE;
251       }
252     }
253     return TRUE;
254   } else if (_gst_plugin_spew) {
255 //    if (strstr(g_module_error(),"No such") == NULL)
256       gst_info("error loading plugin: %s, reason: %s\n", name, g_module_error());
257   }
258
259   return FALSE;
260 }
261
262 /**
263  * gst_plugin_new:
264  * @name: name of new plugin
265  *
266  * Create a new plugin with given name.
267  *
268  * Returns: new plugin
269  */
270 GstPlugin *gst_plugin_new(gchar *name) {
271   GstPlugin *plugin = (GstPlugin *)g_malloc(sizeof(GstPlugin));
272
273   // FIXME need to make sure the plugin hasn't already loaded
274   plugin->name = g_strdup(name);
275   plugin->longname = NULL;
276   plugin->types = NULL;
277   plugin->elements = NULL;
278   plugin->loaded = TRUE;
279
280   return plugin;
281 }
282
283 /**
284  * gst_plugin_set_longname:
285  * @plugin: plugin to set long name of
286  * @longname: new long name
287  *
288  * Sets the long name (should be descriptive) of the plugin.
289  */
290 void gst_plugin_set_longname(GstPlugin *plugin,gchar *longname) {
291   g_return_if_fail(plugin != NULL);
292
293   if (plugin->longname) g_free(plugin->longname);
294   plugin->longname = g_strdup(longname);
295 }
296
297 /**
298  * gst_plugin_find:
299  * @name: name of plugin to find
300  *
301  * Search the list of registered plugins for one of the given name
302  *
303  * Returns: pointer to the #GstPlugin if found, NULL otherwise
304  */
305 GstPlugin *gst_plugin_find(const gchar *name) {
306   GList *plugins = _gst_plugins;
307
308   g_return_val_if_fail(name != NULL, NULL);
309
310   while (plugins) {
311     GstPlugin *plugin = (GstPlugin *)plugins->data;
312 //    g_print("plugin name is '%s'\n",plugin->name);
313     if (plugin->name) {
314       if (!strcmp(plugin->name,name)) {
315         return plugin;
316       }
317     }
318     plugins = g_list_next(plugins);
319   }
320   return NULL;
321 }
322
323 /** 
324  * gst_plugin_find_elementfactory:
325  * @name: name of elementfactory to find
326  *
327  * Find a registered elementfactory by name.
328  *
329  * Returns: @GstElementFactory if found, NULL if not
330  */
331 GstElementFactory *gst_plugin_find_elementfactory(gchar *name) {
332   GList *plugins, *factories;
333   GstElementFactory *factory;
334
335   g_return_val_if_fail(name != NULL, NULL);
336
337   plugins = _gst_plugins;
338   while (plugins) {
339     factories = ((GstPlugin *)(plugins->data))->elements;
340     while (factories) {
341       factory = (GstElementFactory*)(factories->data);
342       if (!strcmp(factory->name, name))
343         return (GstElementFactory*)(factory);
344       factories = g_list_next(factories);
345     }
346     plugins = g_list_next(plugins);
347   }
348
349   return NULL;
350 }
351
352 /** 
353  * gst_plugin_load_elementfactory:
354  * @name: name of elementfactory to load
355  *
356  * Load a registered elementfactory by name.
357  *
358  * Returns: @GstElementFactory if loaded, NULL if not
359  */
360 GstElementFactory *gst_plugin_load_elementfactory(gchar *name) {
361   GList *plugins, *factories;
362   GstElementFactory *factory = NULL;
363   GstPlugin *plugin;
364
365   g_return_val_if_fail(name != NULL, NULL);
366
367   plugins = _gst_plugins;
368   while (plugins) {
369     plugin = (GstPlugin *)plugins->data;
370     factories = plugin->elements;
371     while (factories) {
372       factory = (GstElementFactory*)(factories->data);
373       if (!strcmp(factory->name,name)) {
374         if (!plugin->loaded) {
375           gchar *filename = g_strdup (plugin->filename);
376           g_print("gstplugin: loading element factory %s from plugin %s\n", name, plugin->name);
377           gst_plugin_remove(plugin);
378           if (!gst_plugin_load_absolute(filename)) {
379             g_print("gstplugin: error loading element factory %s from plugin %s\n", name, plugin->name);
380           }
381           g_free (filename);
382           factory = gst_plugin_find_elementfactory(name);
383         }
384         return factory;
385       }
386       factories = g_list_next(factories);
387     }
388     plugins = g_list_next(plugins);
389   }
390
391   return factory;
392 }
393
394 /** 
395  * gst_plugin_load_typefactory:
396  * @mime: name of typefactory to load
397  *
398  * Load a registered typefactory by mime type.
399  */
400 void gst_plugin_load_typefactory(gchar *mime) {
401   GList *plugins, *factories;
402   GstTypeFactory *factory;
403   GstPlugin *plugin;
404
405   g_return_if_fail(mime != NULL);
406
407   plugins = _gst_plugins;
408   while (plugins) {
409     plugin = (GstPlugin *)plugins->data;
410     factories = plugin->types;
411     while (factories) {
412       factory = (GstTypeFactory*)(factories->data);
413       if (!strcmp(factory->mime,mime)) {
414         if (!plugin->loaded) {
415           gchar *filename = g_strdup (plugin->filename);
416           g_print("gstplugin: loading type factory for \"%s\" from plugin %s\n", mime, plugin->name);
417           gst_plugin_remove(plugin);
418           if (!gst_plugin_load_absolute(filename)) {
419             g_print("gstplugin: error loading type factory \"%s\" from plugin %s\n", mime, plugin->name);
420           }
421           g_free (filename);
422         }
423         return;
424       }
425       factories = g_list_next(factories);
426     }
427     plugins = g_list_next(plugins);
428   }
429
430   return;
431 }
432
433 /**
434  * gst_plugin_add_factory:
435  * @plugin: plugin to add factory to
436  * @factory: factory to add
437  *
438  * Add factory to the list of those provided by the plugin.
439  */
440 void gst_plugin_add_factory(GstPlugin *plugin,GstElementFactory *factory) {
441   g_return_if_fail(plugin != NULL);
442   g_return_if_fail(factory != NULL);
443
444 //  g_print("adding factory to plugin\n");
445   plugin->elements = g_list_append(plugin->elements,factory);
446   gst_elementfactory_register (factory);
447 }
448
449 /**
450  * gst_plugin_add_type:
451  * @plugin: plugin to add type to
452  * @factory: the typefactory to add
453  *
454  * Add a typefactory to the list of those provided by the plugin.
455  */
456 void gst_plugin_add_type(GstPlugin *plugin,GstTypeFactory *factory) {
457   g_return_if_fail(plugin != NULL);
458   g_return_if_fail(factory != NULL);
459
460 //  g_print("adding factory to plugin\n");
461   plugin->types = g_list_append(plugin->types,factory);
462 }
463
464 /**
465  * gst_plugin_get_list:
466  *
467  * get the currently loaded plugins
468  *
469  * Returns; a GList of GstPlugin elements
470  */
471 GList *gst_plugin_get_list() {
472   return _gst_plugins;
473 }
474
475 /**
476  * gst_plugin_save_thyself:
477  * @parent: the parent node to save the plugin to
478  *
479  * saves the plugin into an XML representation
480  *
481  * Returns: the new XML node
482  */
483 xmlNodePtr gst_plugin_save_thyself(xmlNodePtr parent) {
484   xmlNodePtr tree, subtree;
485   GList *plugins = NULL, *elements = NULL, *types = NULL;
486
487   plugins = gst_plugin_get_list();
488   while (plugins) {
489     GstPlugin *plugin = (GstPlugin *)plugins->data;
490     tree = xmlNewChild(parent,NULL,"plugin",NULL);
491     xmlNewChild(tree,NULL,"name",plugin->name);
492     xmlNewChild(tree,NULL,"longname",plugin->longname);
493     xmlNewChild(tree,NULL,"filename",plugin->filename);
494     types = plugin->types;
495     while (types) {
496       GstTypeFactory *factory = (GstTypeFactory *)types->data;
497       subtree = xmlNewChild(tree,NULL,"type",NULL);
498
499       gst_typefactory_save_thyself(factory, subtree);
500
501       types = g_list_next(types);
502     }
503     elements = plugin->elements;
504     while (elements) {
505       GstElementFactory *factory = (GstElementFactory *)elements->data;
506       subtree = xmlNewChild(tree,NULL,"element",NULL);
507
508       gst_elementfactory_save_thyself(factory, subtree);
509
510       elements = g_list_next(elements);
511     }
512     plugins = g_list_next(plugins);
513   }
514   return parent;
515 }
516
517 /**
518  * gst_plugin_load_thyself:
519  * @parent: the parent node to load the plugin from
520  *
521  * load the plugin from an XML representation
522  */
523 void gst_plugin_load_thyself(xmlNodePtr parent) {
524   xmlNodePtr kinderen;   
525   gint elementcount = 0;
526   gint typecount = 0;
527   
528   kinderen = parent->childs; // Dutch invasion :-)
529   while (kinderen) {
530     if (!strcmp(kinderen->name, "plugin")) {
531       xmlNodePtr field = kinderen->childs;
532       GstPlugin *plugin = g_new0 (GstPlugin, 1);
533       plugin->elements = NULL;
534       plugin->types = NULL;
535       plugin->loaded = FALSE;
536
537       while (field) {
538         if (!strcmp(field->name, "name")) {
539           if (gst_plugin_find(xmlNodeGetContent(field))) {
540             g_free(plugin);
541             plugin = NULL;
542             break;
543           }
544           else {
545             plugin->name = g_strdup(xmlNodeGetContent(field));
546           }
547         }
548         else if (!strcmp(field->name, "longname")) {
549           plugin->longname = g_strdup(xmlNodeGetContent(field));
550         }
551         else if (!strcmp(field->name, "filename")) {
552           plugin->filename = g_strdup(xmlNodeGetContent(field));
553         }
554         else if (!strcmp(field->name, "element")) {
555           GstElementFactory *factory = gst_elementfactory_load_thyself(field);
556           gst_plugin_add_factory (plugin, factory);
557           elementcount++;
558         }
559         else if (!strcmp(field->name, "type")) {
560           GstTypeFactory *factory = gst_typefactory_load_thyself(field);
561           gst_plugin_add_type (plugin, factory);
562           elementcount++;
563           typecount++;
564         }
565
566         field = field->next;
567       }
568
569       if (plugin) {
570         _gst_plugins = g_list_prepend(_gst_plugins, plugin);
571       }
572     }
573
574     kinderen = kinderen->next;
575   }
576   g_print("gstplugin: added %d registered factories and %d types\n", elementcount, typecount);
577 }
578