2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstplugin.c: Plugin subsystem for loading elements, types, and libs
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.
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.
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.
23 #include <sys/types.h>
28 #include "gst_private.h"
29 #include "gstplugin.h"
33 /* list of loaded modules and its sequence number */
35 gint _gst_modules_seqno;
36 /* global list of plugins and its sequence number */
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;
44 GList *_gst_libraries;
45 gint _gst_libraries_seqno;
47 /* whether or not to spew library load issues */
48 gboolean _gst_plugin_spew = FALSE;
50 static gboolean plugin_times_older_than(time_t regtime);
51 static time_t get_time(const char * path);
54 _gst_plugin_initialize (void)
58 _gst_modules_seqno = 0;
60 _gst_plugins_seqno = 0;
61 _gst_plugin_paths = NULL;
62 _gst_libraries = NULL;
63 _gst_libraries_seqno = 0;
66 /* if this is set, we add build-directory paths to the list */
67 #ifdef PLUGINS_USE_SRCDIR
68 /* the catch-all plugins directory */
69 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
70 PLUGINS_SRCDIR "/plugins");
71 /* the libreary directory */
72 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
73 PLUGINS_SRCDIR "/libs");
74 /* location libgstelements.so */
75 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
76 PLUGINS_SRCDIR "/gst/elements");
77 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
78 PLUGINS_SRCDIR "/gst/types");
79 #else /* PLUGINS_USE_SRCDIR */
80 /* add the main (installed) library path */
81 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths, PLUGINS_DIR);
82 #endif /* PLUGINS_USE_SRCDIR */
84 doc = xmlParseFile (GST_CONFIG_DIR"/reg.xml");
86 if (!doc || strcmp (doc->root->name, "GST-PluginRegistry") ||
87 !plugin_times_older_than(get_time(GST_CONFIG_DIR"/reg.xml"))) {
88 g_warning ("gstplugin: registry needs rebuild\n");
89 gst_plugin_load_all ();
92 gst_plugin_load_thyself (doc->root);
98 get_time(const char * path)
101 if (stat(path, &statbuf)) return 0;
102 if (statbuf.st_mtime > statbuf.st_ctime) return statbuf.st_mtime;
103 return statbuf.st_ctime;
107 plugin_times_older_than_recurse(gchar *path, time_t regtime)
110 struct dirent *dirent;
112 time_t pathtime = get_time(path);
114 if (pathtime > regtime) {
115 GST_INFO (GST_CAT_PLUGIN_LOADING,
116 "time for %s was %ld; more recent than registry time of %ld\n",
117 path, (long)pathtime, (long)regtime);
123 while ((dirent = readdir(dir))) {
124 /* don't want to recurse in place or backwards */
125 if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
126 if (!plugin_times_older_than_recurse(
127 g_strjoin("/",path,dirent->d_name,NULL), regtime))
137 plugin_times_older_than(time_t regtime)
139 // return true iff regtime is more recent than the times of all the files
140 // in the plugin dirs.
142 path = _gst_plugin_paths;
143 while (path != NULL) {
144 GST_DEBUG (GST_CAT_PLUGIN_LOADING,
145 "comparing plugin times from %s with %ld\n",
146 (gchar *)path->data, (long) regtime);
147 if(!plugin_times_older_than_recurse(path->data, regtime))
149 path = g_list_next(path);
155 gst_plugin_load_recurse (gchar *directory, gchar *name)
158 struct dirent *dirent;
159 gboolean loaded = FALSE;
162 //g_print("recursive load of '%s' in '%s'\n", name, directory);
163 dir = opendir(directory);
165 while ((dirent = readdir(dir))) {
166 /* don't want to recurse in place or backwards */
167 if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
168 dirname = g_strjoin("/",directory,dirent->d_name,NULL);
169 loaded = gst_plugin_load_recurse(dirname,name);
171 if (loaded && name) {
179 if (strstr(directory,".so")) {
182 if ((temp = strstr(directory,name)) &&
183 (!strcmp(temp,name))) {
184 loaded = gst_plugin_load_absolute(directory);
186 } else if ((temp = strstr(directory,".so")) &&
187 (!strcmp(temp,".so"))) {
188 loaded = gst_plugin_load_absolute(directory);
196 * gst_plugin_load_all:
198 * Load all plugins in the path.
201 gst_plugin_load_all(void)
205 path = _gst_plugin_paths;
206 while (path != NULL) {
207 GST_DEBUG (GST_CAT_PLUGIN_LOADING,"loading plugins from %s\n",(gchar *)path->data);
208 gst_plugin_load_recurse(path->data,NULL);
209 path = g_list_next(path);
211 GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded %d plugins with %d elements and %d types",
212 _gst_plugins_seqno,_gst_plugin_elementfactories,_gst_plugin_types);
217 * @name: name of library to load
219 * Load the named library. Name should be given as
220 * "liblibrary.so".
222 * Returns: whether the library was loaded or not
225 gst_library_load (const gchar *name)
228 GList *libraries = _gst_libraries;
231 if (!strcmp((gchar *)libraries->data, name)) return TRUE;
233 libraries = g_list_next(libraries);
236 // for now this is the same
237 res = gst_plugin_load(name);
240 _gst_libraries = g_list_prepend(_gst_libraries, g_strdup (name));
247 gst_plugin_remove (GstPlugin *plugin)
251 factories = plugin->elements;
253 gst_elementfactory_destroy ((GstElementFactory*)(factories->data));
254 factories = g_list_next(factories);
257 _gst_plugins = g_list_remove(_gst_plugins, plugin);
259 // don't free the stuct because someone can have a handle to it
264 * @name: name of plugin to load
266 * Load the named plugin. Name should be given as
267 * "libplugin.so".
269 * Returns: whether the plugin was loaded or not
272 gst_plugin_load (const gchar *name)
279 //g_print("attempting to load plugin '%s'\n",name);
281 plugin = gst_plugin_find (name);
283 if (plugin && plugin->loaded) return TRUE;
285 path = _gst_plugin_paths;
286 while (path != NULL) {
287 pluginname = g_module_build_path(path->data,name);
288 if (gst_plugin_load_absolute(pluginname)) {
293 libspath = g_strconcat(path->data,"/.libs",NULL);
294 //g_print("trying to load '%s'\n",g_module_build_path(libspath,name));
295 pluginname = g_module_build_path(libspath,name);
297 if (gst_plugin_load_absolute(pluginname)) {
302 //g_print("trying to load '%s' from '%s'\n",name,path->data);
303 pluginname = g_module_build_path("",name);
304 if (gst_plugin_load_recurse(path->data,pluginname)) {
309 path = g_list_next(path);
315 * gst_plugin_load_absolute:
316 * @name: name of plugin to load
318 * Returns: whether or not the plugin loaded
321 gst_plugin_load_absolute (const gchar *name)
324 GstPluginInitFunc initfunc;
326 struct stat file_status;
328 if (g_module_supported() == FALSE) {
329 g_warning("gstplugin: wow, you built this on a platform without dynamic loading???\n");
333 if (stat(name,&file_status)) {
334 // g_print("problem opening file %s\n",name);
338 module = g_module_open(name,G_MODULE_BIND_LAZY);
339 if (module != NULL) {
340 if (g_module_symbol(module,"plugin_init",(gpointer *)&initfunc)) {
341 if ((plugin = (initfunc)(module))) {
342 GST_INFO (GST_CAT_PLUGIN_LOADING,"plugin \"%s\" loaded: %d elements, %d types",
343 plugin->name,plugin->numelements,plugin->numtypes);
344 plugin->filename = g_strdup(name);
345 plugin->loaded = TRUE;
346 _gst_modules = g_list_prepend(_gst_modules,module);
347 _gst_modules_seqno++;
348 _gst_plugins = g_list_prepend(_gst_plugins,plugin);
349 _gst_plugins_seqno++;
350 _gst_plugin_elementfactories += plugin->numelements;
351 _gst_plugin_types += plugin->numtypes;
356 } else if (_gst_plugin_spew) {
357 gst_info("error loading plugin: %s, reason: %s\n", name, g_module_error());
365 * @name: name of new plugin
367 * Create a new plugin with given name.
369 * Returns: new plugin
372 gst_plugin_new (const gchar *name)
376 // return NULL if the plugin is allready loaded
377 plugin = gst_plugin_find (name);
378 if (plugin) return NULL;
380 plugin = (GstPlugin *)g_malloc(sizeof(GstPlugin));
382 plugin->name = g_strdup(name);
383 plugin->longname = NULL;
384 plugin->elements = NULL;
385 plugin->numelements = 0;
386 plugin->types = NULL;
387 plugin->numtypes = 0;
388 plugin->loaded = TRUE;
394 * gst_plugin_get_name:
395 * @plugin: plugin to get the name of
397 * Get the short name of the plugin
399 * Returns: the name of the plugin
402 gst_plugin_get_name (GstPlugin *plugin)
404 g_return_val_if_fail (plugin != NULL, NULL);
410 * gst_plugin_set_name:
411 * @plugin: plugin to set name of
414 * Sets the name (should be short) of the plugin.
417 gst_plugin_set_name (GstPlugin *plugin, const gchar *name)
419 g_return_if_fail (plugin != NULL);
422 g_free (plugin->name);
424 plugin->name = g_strdup (name);
428 * gst_plugin_set_longname:
429 * @plugin: plugin to set long name of
430 * @longname: new long name
432 * Sets the long name (should be descriptive) of the plugin.
435 gst_plugin_set_longname (GstPlugin *plugin, const gchar *longname)
437 g_return_if_fail(plugin != NULL);
439 if (plugin->longname)
440 g_free(plugin->longname);
442 plugin->longname = g_strdup(longname);
446 * gst_plugin_get_longname:
447 * @plugin: plugin to get long name of
449 * Get the long descriptive name of the plugin
451 * Returns: the long name of the plugin
454 gst_plugin_get_longname (GstPlugin *plugin)
456 g_return_val_if_fail (plugin != NULL, NULL);
458 return plugin->longname;
462 * gst_plugin_get_filename:
463 * @plugin: plugin to get the filename of
465 * get the filename of the plugin
467 * Returns: the filename of the plugin
470 gst_plugin_get_filename (GstPlugin *plugin)
472 g_return_val_if_fail (plugin != NULL, NULL);
474 return plugin->filename;
478 * gst_plugin_is_loaded:
479 * @plugin: plugin to query
481 * queries if the plugin is loaded into memory
483 * Returns: TRUE is loaded, FALSE otherwise
486 gst_plugin_is_loaded (GstPlugin *plugin)
488 g_return_val_if_fail (plugin != NULL, FALSE);
490 return plugin->loaded;
496 * @name: name of plugin to find
498 * Search the list of registered plugins for one of the given name
500 * Returns: pointer to the #GstPlugin if found, NULL otherwise
503 gst_plugin_find (const gchar *name)
505 GList *plugins = _gst_plugins;
507 g_return_val_if_fail(name != NULL, NULL);
510 GstPlugin *plugin = (GstPlugin *)plugins->data;
511 // g_print("plugin name is '%s'\n",plugin->name);
513 if (!strcmp(plugin->name,name)) {
517 plugins = g_list_next(plugins);
523 * gst_plugin_find_elementfactory:
524 * @name: name of elementfactory to find
526 * Find a registered elementfactory by name.
528 * Returns: @GstElementFactory if found, NULL if not
531 gst_plugin_find_elementfactory (const gchar *name)
533 GList *plugins, *factories;
534 GstElementFactory *factory;
536 g_return_val_if_fail(name != NULL, NULL);
538 plugins = _gst_plugins;
540 factories = ((GstPlugin *)(plugins->data))->elements;
542 factory = (GstElementFactory*)(factories->data);
543 if (!strcmp(factory->name, name))
544 return (GstElementFactory*)(factory);
545 factories = g_list_next(factories);
547 plugins = g_list_next(plugins);
554 * gst_plugin_load_elementfactory:
555 * @name: name of elementfactory to load
557 * Load a registered elementfactory by name.
559 * Returns: @GstElementFactory if loaded, NULL if not
562 gst_plugin_load_elementfactory (const gchar *name)
564 GList *plugins, *factories;
565 GstElementFactory *factory = NULL;
568 g_return_val_if_fail(name != NULL, NULL);
570 plugins = _gst_plugins;
572 plugin = (GstPlugin *)plugins->data;
573 factories = plugin->elements;
576 factory = (GstElementFactory*)(factories->data);
578 if (!strcmp(factory->name,name)) {
579 if (!plugin->loaded) {
580 gchar *filename = g_strdup (plugin->filename);
581 gchar *pluginname = g_strdup (plugin->name);
583 GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded elementfactory %s from plugin %s",name,plugin->name);
584 gst_plugin_remove(plugin);
585 if (!gst_plugin_load_absolute(filename)) {
586 GST_DEBUG (0,"gstplugin: error loading element factory %s from plugin %s\n", name, pluginname);
591 factory = gst_plugin_find_elementfactory(name);
594 factories = g_list_next(factories);
596 plugins = g_list_next(plugins);
603 * gst_plugin_load_typefactory:
604 * @mime: name of typefactory to load
606 * Load a registered typefactory by mime type.
609 gst_plugin_load_typefactory (const gchar *mime)
611 GList *plugins, *factories;
612 GstTypeFactory *factory;
615 g_return_if_fail (mime != NULL);
617 plugins = g_list_copy (_gst_plugins);
619 plugin = (GstPlugin *)plugins->data;
620 factories = g_list_copy (plugin->types);
623 factory = (GstTypeFactory*)(factories->data);
625 if (!strcmp(factory->mime,mime)) {
626 if (!plugin->loaded) {
627 gchar *filename = g_strdup (plugin->filename);
628 gchar *pluginname = g_strdup (plugin->name);
630 GST_INFO (GST_CAT_PLUGIN_LOADING,"loading type factory for \"%s\" from plugin %s",mime,plugin->name);
631 plugin->loaded = TRUE;
632 gst_plugin_remove(plugin);
633 if (!gst_plugin_load_absolute(filename)) {
634 GST_DEBUG (0,"gstplugin: error loading type factory \"%s\" from plugin %s\n", mime, pluginname);
641 factories = g_list_next(factories);
644 g_list_free (factories);
645 plugins = g_list_next(plugins);
647 g_list_free (plugins);
653 * gst_plugin_add_factory:
654 * @plugin: plugin to add factory to
655 * @factory: factory to add
657 * Add factory to the list of those provided by the plugin.
660 gst_plugin_add_factory (GstPlugin *plugin, GstElementFactory *factory)
662 g_return_if_fail (plugin != NULL);
663 g_return_if_fail (factory != NULL);
665 // g_print("adding factory to plugin\n");
666 plugin->elements = g_list_prepend (plugin->elements, factory);
667 plugin->numelements++;
671 * gst_plugin_add_type:
672 * @plugin: plugin to add type to
673 * @factory: the typefactory to add
675 * Add a typefactory to the list of those provided by the plugin.
678 gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory)
680 g_return_if_fail (plugin != NULL);
681 g_return_if_fail (factory != NULL);
683 // g_print("adding factory to plugin\n");
684 plugin->types = g_list_prepend (plugin->types, factory);
686 gst_type_register (factory);
690 * gst_plugin_get_list:
692 * get the currently loaded plugins
694 * Returns; a GList of GstPlugin elements
697 gst_plugin_get_list(void)
703 * gst_plugin_save_thyself:
704 * @parent: the parent node to save the plugin to
706 * saves the plugin into an XML representation
708 * Returns: the new XML node
711 gst_plugin_save_thyself (xmlNodePtr parent)
713 xmlNodePtr tree, subtree;
714 GList *plugins = NULL, *elements = NULL, *types = NULL;
716 plugins = gst_plugin_get_list();
718 GstPlugin *plugin = (GstPlugin *)plugins->data;
719 tree = xmlNewChild(parent,NULL,"plugin",NULL);
720 xmlNewChild(tree,NULL,"name",plugin->name);
721 xmlNewChild(tree,NULL,"longname",plugin->longname);
722 xmlNewChild(tree,NULL,"filename",plugin->filename);
723 types = plugin->types;
725 GstTypeFactory *factory = (GstTypeFactory *)types->data;
726 subtree = xmlNewChild(tree,NULL,"type",NULL);
728 gst_typefactory_save_thyself(factory, subtree);
730 types = g_list_next(types);
732 elements = plugin->elements;
734 GstElementFactory *factory = (GstElementFactory *)elements->data;
735 subtree = xmlNewChild(tree,NULL,"element",NULL);
737 gst_elementfactory_save_thyself(factory, subtree);
739 elements = g_list_next(elements);
741 plugins = g_list_next(plugins);
747 * gst_plugin_load_thyself:
748 * @parent: the parent node to load the plugin from
750 * load the plugin from an XML representation
753 gst_plugin_load_thyself (xmlNodePtr parent)
756 gint elementcount = 0;
760 kinderen = parent->childs; // Dutch invasion :-)
762 if (!strcmp(kinderen->name, "plugin")) {
763 xmlNodePtr field = kinderen->childs;
764 GstPlugin *plugin = g_new0 (GstPlugin, 1);
765 plugin->elements = NULL;
766 plugin->types = NULL;
767 plugin->loaded = FALSE;
770 if (!strcmp(field->name, "name")) {
771 pluginname = xmlNodeGetContent(field);
772 if (gst_plugin_find(pluginname)) {
778 plugin->name = pluginname;
781 else if (!strcmp(field->name, "longname")) {
782 plugin->longname = xmlNodeGetContent(field);
784 else if (!strcmp(field->name, "filename")) {
785 plugin->filename = xmlNodeGetContent(field);
787 else if (!strcmp(field->name, "element")) {
788 GstElementFactory *factory = gst_elementfactory_load_thyself(field);
789 gst_plugin_add_factory (plugin, factory);
792 else if (!strcmp(field->name, "type")) {
793 GstTypeFactory *factory = gst_typefactory_load_thyself(field);
794 gst_plugin_add_type (plugin, factory);
803 _gst_plugins = g_list_prepend(_gst_plugins, plugin);
807 kinderen = kinderen->next;
809 GST_INFO (GST_CAT_PLUGIN_LOADING,"added %d registered factories and %d types",elementcount,typecount);
814 * gst_plugin_get_factory_list:
815 * @plugin: the plugin to get the factories from
817 * get a list of all the factories that this plugin provides
819 * Returns: a GList of factories
822 gst_plugin_get_factory_list (GstPlugin *plugin)
824 g_return_val_if_fail (plugin != NULL, NULL);
826 return plugin->elements;
830 * gst_plugin_get_type_list:
831 * @plugin: the plugin to get the typefactories from
833 * get a list of all the typefactories that this plugin provides
835 * Returns: a GList of factories
838 gst_plugin_get_type_list (GstPlugin *plugin)
840 g_return_val_if_fail (plugin != NULL, NULL);
842 return plugin->types;