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 /* whether or not to warn if registry needs rebuild (gstreamer-register sets
52 gboolean _gst_warn_old_registry = TRUE;
54 static gboolean plugin_times_older_than(time_t regtime);
55 static time_t get_time(const char * path);
58 _gst_plugin_initialize (void)
62 _gst_modules_seqno = 0;
64 _gst_plugins_seqno = 0;
65 _gst_plugin_paths = NULL;
66 _gst_libraries = NULL;
67 _gst_libraries_seqno = 0;
69 /* add the main (installed) library path */
70 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths, PLUGINS_DIR);
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 */
89 doc = xmlParseFile (GST_CONFIG_DIR"/reg.xml");
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 ();
101 gst_plugin_load_thyself (doc->xmlRootNode);
107 * gst_plugin_add_path:
108 * @path: the directory to add to the search path
110 * Add a directory to the path searched for plugins.
113 gst_plugin_add_path (const gchar *path)
115 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,g_strdup(path));
119 get_time(const char * path)
122 if (stat(path, &statbuf)) return 0;
123 if (statbuf.st_mtime > statbuf.st_ctime) return statbuf.st_mtime;
124 return statbuf.st_ctime;
128 plugin_times_older_than_recurse(gchar *path, time_t regtime)
131 struct dirent *dirent;
134 time_t pathtime = get_time(path);
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);
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)) {
163 plugin_times_older_than(time_t regtime)
165 // return true iff regtime is more recent than the times of all the files
166 // in the plugin dirs.
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))
175 path = g_list_next(path);
181 gst_plugin_load_recurse (gchar *directory, gchar *name)
184 struct dirent *dirent;
185 gboolean loaded = FALSE;
188 //g_print("recursive load of '%s' in '%s'\n", name, directory);
189 dir = opendir(directory);
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);
197 if (loaded && name) {
205 if (strstr(directory,".so")) {
208 if ((temp = strstr(directory,name)) &&
209 (!strcmp(temp,name))) {
210 loaded = gst_plugin_load_absolute(directory);
212 } else if ((temp = strstr(directory,".so")) &&
213 (!strcmp(temp,".so"))) {
214 loaded = gst_plugin_load_absolute(directory);
222 * gst_plugin_load_all:
224 * Load all plugins in the path.
227 gst_plugin_load_all(void)
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);
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);
243 * @name: name of library to load
245 * Load the named library. Name should be given as
246 * "liblibrary.so".
248 * Returns: whether the library was loaded or not
251 gst_library_load (const gchar *name)
254 GList *libraries = _gst_libraries;
257 if (!strcmp((gchar *)libraries->data, name)) return TRUE;
259 libraries = g_list_next(libraries);
262 // for now this is the same
263 res = gst_plugin_load(name);
266 _gst_libraries = g_list_prepend(_gst_libraries, g_strdup (name));
273 gst_plugin_remove (GstPlugin *plugin)
277 factories = plugin->elements;
279 gst_elementfactory_destroy ((GstElementFactory*)(factories->data));
280 factories = g_list_next(factories);
283 _gst_plugins = g_list_remove(_gst_plugins, plugin);
285 // don't free the stuct because someone can have a handle to it
290 * @name: name of plugin to load
292 * Load the named plugin. Name should be given as
293 * "libplugin.so".
295 * Returns: whether the plugin was loaded or not
298 gst_plugin_load (const gchar *name)
305 //g_print("attempting to load plugin '%s'\n",name);
307 plugin = gst_plugin_find (name);
309 if (plugin && plugin->loaded) return TRUE;
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)) {
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);
323 if (gst_plugin_load_absolute(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)) {
335 path = g_list_next(path);
341 * gst_plugin_load_absolute:
342 * @name: name of plugin to load
344 * Returns: whether or not the plugin loaded
347 gst_plugin_load_absolute (const gchar *name)
350 GstPluginInitFunc initfunc;
352 struct stat file_status;
354 if (g_module_supported() == FALSE) {
355 g_warning("gstplugin: wow, you built this on a platform without dynamic loading???\n");
359 if (stat(name,&file_status)) {
360 // g_print("problem opening file %s\n",name);
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\"...",
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;
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());
394 * @name: name of new plugin
396 * Create a new plugin with given name.
398 * Returns: new plugin
401 gst_plugin_new (const gchar *name)
405 // return NULL if the plugin is allready loaded
406 plugin = gst_plugin_find (name);
407 if (plugin) return NULL;
409 plugin = (GstPlugin *)g_malloc(sizeof(GstPlugin));
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;
425 * gst_plugin_get_name:
426 * @plugin: plugin to get the name of
428 * Get the short name of the plugin
430 * Returns: the name of the plugin
433 gst_plugin_get_name (GstPlugin *plugin)
435 g_return_val_if_fail (plugin != NULL, NULL);
441 * gst_plugin_set_name:
442 * @plugin: plugin to set name of
445 * Sets the name (should be short) of the plugin.
448 gst_plugin_set_name (GstPlugin *plugin, const gchar *name)
450 g_return_if_fail (plugin != NULL);
453 g_free (plugin->name);
455 plugin->name = g_strdup (name);
459 * gst_plugin_set_longname:
460 * @plugin: plugin to set long name of
461 * @longname: new long name
463 * Sets the long name (should be descriptive) of the plugin.
466 gst_plugin_set_longname (GstPlugin *plugin, const gchar *longname)
468 g_return_if_fail(plugin != NULL);
470 if (plugin->longname)
471 g_free(plugin->longname);
473 plugin->longname = g_strdup(longname);
477 * gst_plugin_get_longname:
478 * @plugin: plugin to get long name of
480 * Get the long descriptive name of the plugin
482 * Returns: the long name of the plugin
485 gst_plugin_get_longname (GstPlugin *plugin)
487 g_return_val_if_fail (plugin != NULL, NULL);
489 return plugin->longname;
493 * gst_plugin_get_filename:
494 * @plugin: plugin to get the filename of
496 * get the filename of the plugin
498 * Returns: the filename of the plugin
501 gst_plugin_get_filename (GstPlugin *plugin)
503 g_return_val_if_fail (plugin != NULL, NULL);
505 return plugin->filename;
509 * gst_plugin_is_loaded:
510 * @plugin: plugin to query
512 * queries if the plugin is loaded into memory
514 * Returns: TRUE is loaded, FALSE otherwise
517 gst_plugin_is_loaded (GstPlugin *plugin)
519 g_return_val_if_fail (plugin != NULL, FALSE);
521 return plugin->loaded;
527 * @name: name of plugin to find
529 * Search the list of registered plugins for one of the given name
531 * Returns: pointer to the #GstPlugin if found, NULL otherwise
534 gst_plugin_find (const gchar *name)
536 GList *plugins = _gst_plugins;
538 g_return_val_if_fail(name != NULL, NULL);
541 GstPlugin *plugin = (GstPlugin *)plugins->data;
542 // g_print("plugin name is '%s'\n",plugin->name);
544 if (!strcmp(plugin->name,name)) {
548 plugins = g_list_next(plugins);
553 static GstElementFactory*
554 gst_plugin_find_elementfactory (const gchar *name)
556 GList *plugins, *factories;
557 GstElementFactory *factory;
559 g_return_val_if_fail(name != NULL, NULL);
561 plugins = _gst_plugins;
563 factories = ((GstPlugin *)(plugins->data))->elements;
565 factory = (GstElementFactory*)(factories->data);
566 if (!strcmp(factory->name, name))
567 return (GstElementFactory*)(factory);
568 factories = g_list_next(factories);
570 plugins = g_list_next(plugins);
577 * gst_plugin_load_elementfactory:
578 * @name: name of elementfactory to load
580 * Load a registered elementfactory by name.
582 * Returns: @GstElementFactory if loaded, NULL if not
585 gst_plugin_load_elementfactory (const gchar *name)
587 GList *plugins, *factories;
588 GstElementFactory *factory = NULL;
591 g_return_val_if_fail(name != NULL, NULL);
593 plugins = _gst_plugins;
595 plugin = (GstPlugin *)plugins->data;
596 factories = plugin->elements;
599 factory = (GstElementFactory*)(factories->data);
601 if (!strcmp(factory->name,name)) {
602 if (!plugin->loaded) {
603 gchar *filename = g_strdup (plugin->filename);
604 gchar *pluginname = g_strdup (plugin->name);
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);
614 factory = gst_plugin_find_elementfactory(name);
617 factories = g_list_next(factories);
619 plugins = g_list_next(plugins);
625 static GstAutoplugFactory*
626 gst_plugin_find_autoplugfactory (const gchar *name)
628 GList *plugins, *factories;
629 GstAutoplugFactory *factory;
631 g_return_val_if_fail(name != NULL, NULL);
633 plugins = _gst_plugins;
635 factories = ((GstPlugin *)(plugins->data))->autopluggers;
637 factory = (GstAutoplugFactory*)(factories->data);
638 if (!strcmp(factory->name, name))
639 return (GstAutoplugFactory*)(factory);
640 factories = g_list_next(factories);
642 plugins = g_list_next(plugins);
648 * gst_plugin_load_autoplugfactory:
649 * @name: name of autoplugfactory to load
651 * Load a registered autoplugfactory by name.
653 * Returns: @GstAutoplugFactory if loaded, NULL if not
656 gst_plugin_load_autoplugfactory (const gchar *name)
658 GList *plugins, *factories;
659 GstAutoplugFactory *factory = NULL;
662 g_return_val_if_fail(name != NULL, NULL);
664 plugins = _gst_plugins;
666 plugin = (GstPlugin *)plugins->data;
667 factories = plugin->autopluggers;
670 factory = (GstAutoplugFactory*)(factories->data);
672 if (!strcmp(factory->name,name)) {
673 if (!plugin->loaded) {
674 gchar *filename = g_strdup (plugin->filename);
675 gchar *pluginname = g_strdup (plugin->name);
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);
685 factory = gst_plugin_find_autoplugfactory(name);
688 factories = g_list_next(factories);
690 plugins = g_list_next(plugins);
697 * gst_plugin_load_typefactory:
698 * @mime: name of typefactory to load
700 * Load a registered typefactory by mime type.
703 gst_plugin_load_typefactory (const gchar *mime)
705 GList *plugins, *factories;
706 GstTypeFactory *factory;
709 g_return_if_fail (mime != NULL);
711 plugins = g_list_copy (_gst_plugins);
713 plugin = (GstPlugin *)plugins->data;
714 factories = g_list_copy (plugin->types);
717 factory = (GstTypeFactory*)(factories->data);
719 if (!strcmp(factory->mime,mime)) {
720 if (!plugin->loaded) {
721 gchar *filename = g_strdup (plugin->filename);
722 gchar *pluginname = g_strdup (plugin->name);
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);
735 factories = g_list_next(factories);
738 g_list_free (factories);
739 plugins = g_list_next(plugins);
741 g_list_free (plugins);
747 * gst_plugin_add_factory:
748 * @plugin: plugin to add factory to
749 * @factory: factory to add
751 * Add factory to the list of those provided by the plugin.
754 gst_plugin_add_factory (GstPlugin *plugin, GstElementFactory *factory)
756 g_return_if_fail (plugin != NULL);
757 g_return_if_fail (factory != NULL);
759 // g_print("adding factory to plugin\n");
760 plugin->elements = g_list_prepend (plugin->elements, factory);
761 plugin->numelements++;
765 * gst_plugin_add_type:
766 * @plugin: plugin to add type to
767 * @factory: the typefactory to add
769 * Add a typefactory to the list of those provided by the plugin.
772 gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory)
774 g_return_if_fail (plugin != NULL);
775 g_return_if_fail (factory != NULL);
777 // g_print("adding factory to plugin\n");
778 plugin->types = g_list_prepend (plugin->types, factory);
780 gst_type_register (factory);
784 * gst_plugin_add_autoplugger:
785 * @plugin: plugin to add the autoplugger to
786 * @factory: the autoplugfactory to add
788 * Add an autoplugfactory to the list of those provided by the plugin.
791 gst_plugin_add_autoplugger (GstPlugin *plugin, GstAutoplugFactory *factory)
793 g_return_if_fail (plugin != NULL);
794 g_return_if_fail (factory != NULL);
796 // g_print("adding factory to plugin\n");
797 plugin->autopluggers = g_list_prepend (plugin->autopluggers, factory);
798 plugin->numautopluggers++;
802 * gst_plugin_get_list:
804 * get the currently loaded plugins
806 * Returns; a GList of GstPlugin elements
809 gst_plugin_get_list (void)
815 * gst_plugin_save_thyself:
816 * @parent: the parent node to save the plugin to
818 * saves the plugin into an XML representation
820 * Returns: the new XML node
823 gst_plugin_save_thyself (xmlNodePtr parent)
825 xmlNodePtr tree, subtree;
826 GList *plugins = NULL, *elements = NULL, *types = NULL, *autopluggers = NULL;
828 plugins = gst_plugin_get_list ();
830 GstPlugin *plugin = (GstPlugin *)plugins->data;
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);
837 types = plugin->types;
839 GstTypeFactory *factory = (GstTypeFactory *)types->data;
840 subtree = xmlNewChild(tree, NULL, "typefactory", NULL);
842 gst_typefactory_save_thyself (factory, subtree);
844 types = g_list_next (types);
846 elements = plugin->elements;
848 GstElementFactory *factory = (GstElementFactory *)elements->data;
849 subtree = xmlNewChild (tree, NULL, "elementfactory", NULL);
851 gst_elementfactory_save_thyself (factory, subtree);
853 elements = g_list_next (elements);
855 autopluggers = plugin->autopluggers;
856 while (autopluggers) {
857 GstAutoplugFactory *factory = (GstAutoplugFactory *)autopluggers->data;
858 subtree = xmlNewChild (tree, NULL, "autoplugfactory", NULL);
860 gst_autoplugfactory_save_thyself (factory, subtree);
862 autopluggers = g_list_next (autopluggers);
864 plugins = g_list_next (plugins);
870 * gst_plugin_load_thyself:
871 * @parent: the parent node to load the plugin from
873 * load the plugin from an XML representation
876 gst_plugin_load_thyself (xmlNodePtr parent)
879 gint elementcount = 0;
880 gint autoplugcount = 0;
884 kinderen = parent->xmlChildrenNode; // Dutch invasion :-)
886 if (!strcmp (kinderen->name, "plugin")) {
887 xmlNodePtr field = kinderen->xmlChildrenNode;
888 GstPlugin *plugin = g_new0 (GstPlugin, 1);
890 plugin->elements = NULL;
891 plugin->types = NULL;
892 plugin->loaded = FALSE;
895 if (!strcmp (field->name, "name")) {
896 pluginname = xmlNodeGetContent (field);
897 if (gst_plugin_find (pluginname)) {
903 plugin->name = pluginname;
906 else if (!strcmp (field->name, "longname")) {
907 plugin->longname = xmlNodeGetContent (field);
909 else if (!strcmp (field->name, "filename")) {
910 plugin->filename = xmlNodeGetContent (field);
912 else if (!strcmp (field->name, "elementfactory")) {
913 GstElementFactory *factory = gst_elementfactory_load_thyself (field);
914 gst_plugin_add_factory (plugin, factory);
917 else if (!strcmp (field->name, "autoplugfactory")) {
918 GstAutoplugFactory *factory = gst_autoplugfactory_load_thyself (field);
919 gst_plugin_add_autoplugger (plugin, factory);
922 else if (!strcmp (field->name, "typefactory")) {
923 GstTypeFactory *factory = gst_typefactory_load_thyself (field);
924 gst_plugin_add_type (plugin, factory);
933 _gst_plugins = g_list_prepend (_gst_plugins, plugin);
937 kinderen = kinderen->next;
939 GST_INFO (GST_CAT_PLUGIN_LOADING, "added %d registered factories, %d autopluggers and %d types",
940 elementcount, autoplugcount, typecount);
945 * gst_plugin_get_factory_list:
946 * @plugin: the plugin to get the factories from
948 * get a list of all the factories that this plugin provides
950 * Returns: a GList of factories
953 gst_plugin_get_factory_list (GstPlugin *plugin)
955 g_return_val_if_fail (plugin != NULL, NULL);
957 return plugin->elements;
961 * gst_plugin_get_type_list:
962 * @plugin: the plugin to get the typefactories from
964 * get a list of all the typefactories that this plugin provides
966 * Returns: a GList of factories
969 gst_plugin_get_type_list (GstPlugin *plugin)
971 g_return_val_if_fail (plugin != NULL, NULL);
973 return plugin->types;
977 * gst_plugin_get_autoplug_list:
978 * @plugin: the plugin to get the autoplugfactories from
980 * get a list of all the autoplugfactories that this plugin provides
982 * Returns: a GList of factories
985 gst_plugin_get_autoplug_list (GstPlugin *plugin)
987 g_return_val_if_fail (plugin != NULL, NULL);
989 return plugin->autopluggers;