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;
70 /* if this is set, we add build-directory paths to the list */
71 #ifdef PLUGINS_USE_SRCDIR
72 /* the catch-all plugins directory */
73 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
74 PLUGINS_SRCDIR "/plugins");
75 /* the libreary directory */
76 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
77 PLUGINS_SRCDIR "/libs");
78 /* location libgstelements.so */
79 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
80 PLUGINS_SRCDIR "/gst/elements");
81 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
82 PLUGINS_SRCDIR "/gst/types");
83 #endif /* PLUGINS_USE_SRCDIR */
85 /* add the main (installed) library path */
86 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths, PLUGINS_DIR);
88 doc = xmlParseFile (GST_CONFIG_DIR"/reg.xml");
90 if (!doc || strcmp (doc->xmlRootNode->name, "GST-PluginRegistry") ||
91 !plugin_times_older_than(get_time(GST_CONFIG_DIR"/reg.xml"))) {
92 if (_gst_warn_old_registry)
93 g_warning ("gstplugin: registry needs rebuild\n");
94 gst_plugin_load_all ();
97 gst_plugin_load_thyself (doc->xmlRootNode);
103 * gst_plugin_add_path:
104 * @path: the directory to add to the search path
106 * Add a directory to the path searched for plugins.
109 gst_plugin_add_path (const gchar *path)
111 _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,g_strdup(path));
115 get_time(const char * path)
118 if (stat(path, &statbuf)) return 0;
119 if (statbuf.st_mtime > statbuf.st_ctime) return statbuf.st_mtime;
120 return statbuf.st_ctime;
124 plugin_times_older_than_recurse(gchar *path, time_t regtime)
127 struct dirent *dirent;
130 time_t pathtime = get_time(path);
132 if (pathtime > regtime) {
133 GST_INFO (GST_CAT_PLUGIN_LOADING,
134 "time for %s was %ld; more recent than registry time of %ld\n",
135 path, (long)pathtime, (long)regtime);
141 while ((dirent = readdir(dir))) {
142 /* don't want to recurse in place or backwards */
143 if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
144 pluginname = g_strjoin("/",path,dirent->d_name,NULL);
145 if (!plugin_times_older_than_recurse(pluginname , regtime)) {
159 plugin_times_older_than(time_t regtime)
161 // return true iff regtime is more recent than the times of all the files
162 // in the plugin dirs.
164 path = _gst_plugin_paths;
165 while (path != NULL) {
166 GST_DEBUG (GST_CAT_PLUGIN_LOADING,
167 "comparing plugin times from %s with %ld\n",
168 (gchar *)path->data, (long) regtime);
169 if(!plugin_times_older_than_recurse(path->data, regtime))
171 path = g_list_next(path);
177 gst_plugin_load_recurse (gchar *directory, gchar *name)
180 struct dirent *dirent;
181 gboolean loaded = FALSE;
184 //g_print("recursive load of '%s' in '%s'\n", name, directory);
185 dir = opendir(directory);
187 while ((dirent = readdir(dir))) {
188 /* don't want to recurse in place or backwards */
189 if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
190 dirname = g_strjoin("/",directory,dirent->d_name,NULL);
191 loaded = gst_plugin_load_recurse(dirname,name);
193 if (loaded && name) {
201 if (strstr(directory,".so")) {
204 if ((temp = strstr(directory,name)) &&
205 (!strcmp(temp,name))) {
206 loaded = gst_plugin_load_absolute(directory);
208 } else if ((temp = strstr(directory,".so")) &&
209 (!strcmp(temp,".so"))) {
210 loaded = gst_plugin_load_absolute(directory);
218 * gst_plugin_load_all:
220 * Load all plugins in the path.
223 gst_plugin_load_all(void)
227 path = _gst_plugin_paths;
228 while (path != NULL) {
229 GST_INFO (GST_CAT_PLUGIN_LOADING,"loading plugins from %s\n",(gchar *)path->data);
230 gst_plugin_load_recurse(path->data,NULL);
231 path = g_list_next(path);
233 GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded %d plugins with %d elements and %d types",
234 _gst_plugins_seqno,_gst_plugin_elementfactories,_gst_plugin_types);
239 * @name: name of library to load
241 * Load the named library. Name should be given as
242 * "liblibrary.so".
244 * Returns: whether the library was loaded or not
247 gst_library_load (const gchar *name)
250 GList *libraries = _gst_libraries;
253 if (!strcmp((gchar *)libraries->data, name)) return TRUE;
255 libraries = g_list_next(libraries);
258 // for now this is the same
259 res = gst_plugin_load(name);
262 _gst_libraries = g_list_prepend(_gst_libraries, g_strdup (name));
269 gst_plugin_remove (GstPlugin *plugin)
273 factories = plugin->elements;
275 gst_elementfactory_destroy ((GstElementFactory*)(factories->data));
276 factories = g_list_next(factories);
279 _gst_plugins = g_list_remove(_gst_plugins, plugin);
281 // don't free the stuct because someone can have a handle to it
286 * @name: name of plugin to load
288 * Load the named plugin. Name should be given as
289 * "libplugin.so".
291 * Returns: whether the plugin was loaded or not
294 gst_plugin_load (const gchar *name)
301 //g_print("attempting to load plugin '%s'\n",name);
303 plugin = gst_plugin_find (name);
305 if (plugin && plugin->loaded) return TRUE;
307 path = _gst_plugin_paths;
308 while (path != NULL) {
309 pluginname = g_module_build_path(path->data,name);
310 if (gst_plugin_load_absolute(pluginname)) {
315 libspath = g_strconcat(path->data,"/.libs",NULL);
316 //g_print("trying to load '%s'\n",g_module_build_path(libspath,name));
317 pluginname = g_module_build_path(libspath,name);
319 if (gst_plugin_load_absolute(pluginname)) {
324 //g_print("trying to load '%s' from '%s'\n",name,path->data);
325 pluginname = g_module_build_path("",name);
326 if (gst_plugin_load_recurse(path->data,pluginname)) {
331 path = g_list_next(path);
337 * gst_plugin_load_absolute:
338 * @name: name of plugin to load
340 * Returns: whether or not the plugin loaded
343 gst_plugin_load_absolute (const gchar *name)
346 GstPluginInitFunc initfunc;
348 struct stat file_status;
350 if (g_module_supported() == FALSE) {
351 g_warning("gstplugin: wow, you built this on a platform without dynamic loading???\n");
355 if (stat(name,&file_status)) {
356 // g_print("problem opening file %s\n",name);
360 module = g_module_open(name,G_MODULE_BIND_LAZY);
361 if (module != NULL) {
362 if (g_module_symbol(module,"plugin_init",(gpointer *)&initfunc)) {
363 if ((plugin = (initfunc)(module))) {
364 GST_INFO (GST_CAT_PLUGIN_LOADING,"plugin \"%s\" loaded: %d elements, %d types",
365 plugin->name,plugin->numelements,plugin->numtypes);
366 plugin->filename = g_strdup(name);
367 plugin->loaded = TRUE;
368 _gst_modules = g_list_prepend(_gst_modules,module);
369 _gst_modules_seqno++;
370 _gst_plugins = g_list_prepend(_gst_plugins,plugin);
371 _gst_plugins_seqno++;
372 _gst_plugin_elementfactories += plugin->numelements;
373 _gst_plugin_types += plugin->numtypes;
378 } else if (_gst_plugin_spew) {
379 // FIXME this should be some standard gst mechanism!!!
380 g_printerr ("error loading plugin %s, reason: %s\n", name, g_module_error());
388 * @name: name of new plugin
390 * Create a new plugin with given name.
392 * Returns: new plugin
395 gst_plugin_new (const gchar *name)
399 // return NULL if the plugin is allready loaded
400 plugin = gst_plugin_find (name);
401 if (plugin) return NULL;
403 plugin = (GstPlugin *)g_malloc(sizeof(GstPlugin));
405 plugin->name = g_strdup(name);
406 plugin->longname = NULL;
407 plugin->elements = NULL;
408 plugin->numelements = 0;
409 plugin->types = NULL;
410 plugin->numtypes = 0;
411 plugin->loaded = TRUE;
417 * gst_plugin_get_name:
418 * @plugin: plugin to get the name of
420 * Get the short name of the plugin
422 * Returns: the name of the plugin
425 gst_plugin_get_name (GstPlugin *plugin)
427 g_return_val_if_fail (plugin != NULL, NULL);
433 * gst_plugin_set_name:
434 * @plugin: plugin to set name of
437 * Sets the name (should be short) of the plugin.
440 gst_plugin_set_name (GstPlugin *plugin, const gchar *name)
442 g_return_if_fail (plugin != NULL);
445 g_free (plugin->name);
447 plugin->name = g_strdup (name);
451 * gst_plugin_set_longname:
452 * @plugin: plugin to set long name of
453 * @longname: new long name
455 * Sets the long name (should be descriptive) of the plugin.
458 gst_plugin_set_longname (GstPlugin *plugin, const gchar *longname)
460 g_return_if_fail(plugin != NULL);
462 if (plugin->longname)
463 g_free(plugin->longname);
465 plugin->longname = g_strdup(longname);
469 * gst_plugin_get_longname:
470 * @plugin: plugin to get long name of
472 * Get the long descriptive name of the plugin
474 * Returns: the long name of the plugin
477 gst_plugin_get_longname (GstPlugin *plugin)
479 g_return_val_if_fail (plugin != NULL, NULL);
481 return plugin->longname;
485 * gst_plugin_get_filename:
486 * @plugin: plugin to get the filename of
488 * get the filename of the plugin
490 * Returns: the filename of the plugin
493 gst_plugin_get_filename (GstPlugin *plugin)
495 g_return_val_if_fail (plugin != NULL, NULL);
497 return plugin->filename;
501 * gst_plugin_is_loaded:
502 * @plugin: plugin to query
504 * queries if the plugin is loaded into memory
506 * Returns: TRUE is loaded, FALSE otherwise
509 gst_plugin_is_loaded (GstPlugin *plugin)
511 g_return_val_if_fail (plugin != NULL, FALSE);
513 return plugin->loaded;
519 * @name: name of plugin to find
521 * Search the list of registered plugins for one of the given name
523 * Returns: pointer to the #GstPlugin if found, NULL otherwise
526 gst_plugin_find (const gchar *name)
528 GList *plugins = _gst_plugins;
530 g_return_val_if_fail(name != NULL, NULL);
533 GstPlugin *plugin = (GstPlugin *)plugins->data;
534 // g_print("plugin name is '%s'\n",plugin->name);
536 if (!strcmp(plugin->name,name)) {
540 plugins = g_list_next(plugins);
546 * gst_plugin_find_elementfactory:
547 * @name: name of elementfactory to find
549 * Find a registered elementfactory by name.
551 * Returns: @GstElementFactory if found, NULL if not
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);
626 * gst_plugin_load_typefactory:
627 * @mime: name of typefactory to load
629 * Load a registered typefactory by mime type.
632 gst_plugin_load_typefactory (const gchar *mime)
634 GList *plugins, *factories;
635 GstTypeFactory *factory;
638 g_return_if_fail (mime != NULL);
640 plugins = g_list_copy (_gst_plugins);
642 plugin = (GstPlugin *)plugins->data;
643 factories = g_list_copy (plugin->types);
646 factory = (GstTypeFactory*)(factories->data);
648 if (!strcmp(factory->mime,mime)) {
649 if (!plugin->loaded) {
650 gchar *filename = g_strdup (plugin->filename);
651 gchar *pluginname = g_strdup (plugin->name);
653 GST_INFO (GST_CAT_PLUGIN_LOADING,"loading type factory for \"%s\" from plugin %s",mime,plugin->name);
654 plugin->loaded = TRUE;
655 gst_plugin_remove(plugin);
656 if (!gst_plugin_load_absolute(filename)) {
657 GST_DEBUG (0,"gstplugin: error loading type factory \"%s\" from plugin %s\n", mime, pluginname);
664 factories = g_list_next(factories);
667 g_list_free (factories);
668 plugins = g_list_next(plugins);
670 g_list_free (plugins);
676 * gst_plugin_add_factory:
677 * @plugin: plugin to add factory to
678 * @factory: factory to add
680 * Add factory to the list of those provided by the plugin.
683 gst_plugin_add_factory (GstPlugin *plugin, GstElementFactory *factory)
685 g_return_if_fail (plugin != NULL);
686 g_return_if_fail (factory != NULL);
688 // g_print("adding factory to plugin\n");
689 plugin->elements = g_list_prepend (plugin->elements, factory);
690 plugin->numelements++;
694 * gst_plugin_add_type:
695 * @plugin: plugin to add type to
696 * @factory: the typefactory to add
698 * Add a typefactory to the list of those provided by the plugin.
701 gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory)
703 g_return_if_fail (plugin != NULL);
704 g_return_if_fail (factory != NULL);
706 // g_print("adding factory to plugin\n");
707 plugin->types = g_list_prepend (plugin->types, factory);
709 gst_type_register (factory);
713 * gst_plugin_get_list:
715 * get the currently loaded plugins
717 * Returns; a GList of GstPlugin elements
720 gst_plugin_get_list(void)
726 * gst_plugin_save_thyself:
727 * @parent: the parent node to save the plugin to
729 * saves the plugin into an XML representation
731 * Returns: the new XML node
734 gst_plugin_save_thyself (xmlNodePtr parent)
736 xmlNodePtr tree, subtree;
737 GList *plugins = NULL, *elements = NULL, *types = NULL;
739 plugins = gst_plugin_get_list();
741 GstPlugin *plugin = (GstPlugin *)plugins->data;
742 tree = xmlNewChild(parent,NULL,"plugin",NULL);
743 xmlNewChild(tree,NULL,"name",plugin->name);
744 xmlNewChild(tree,NULL,"longname",plugin->longname);
745 xmlNewChild(tree,NULL,"filename",plugin->filename);
746 types = plugin->types;
748 GstTypeFactory *factory = (GstTypeFactory *)types->data;
749 subtree = xmlNewChild(tree,NULL,"typefactory",NULL);
751 gst_typefactory_save_thyself(factory, subtree);
753 types = g_list_next(types);
755 elements = plugin->elements;
757 GstElementFactory *factory = (GstElementFactory *)elements->data;
758 subtree = xmlNewChild(tree,NULL,"elementfactory",NULL);
760 gst_elementfactory_save_thyself(factory, subtree);
762 elements = g_list_next(elements);
764 plugins = g_list_next(plugins);
770 * gst_plugin_load_thyself:
771 * @parent: the parent node to load the plugin from
773 * load the plugin from an XML representation
776 gst_plugin_load_thyself (xmlNodePtr parent)
779 gint elementcount = 0;
783 kinderen = parent->xmlChildrenNode; // Dutch invasion :-)
785 if (!strcmp(kinderen->name, "plugin")) {
786 xmlNodePtr field = kinderen->xmlChildrenNode;
787 GstPlugin *plugin = g_new0 (GstPlugin, 1);
788 plugin->elements = NULL;
789 plugin->types = NULL;
790 plugin->loaded = FALSE;
793 if (!strcmp(field->name, "name")) {
794 pluginname = xmlNodeGetContent(field);
795 if (gst_plugin_find(pluginname)) {
801 plugin->name = pluginname;
804 else if (!strcmp(field->name, "longname")) {
805 plugin->longname = xmlNodeGetContent(field);
807 else if (!strcmp(field->name, "filename")) {
808 plugin->filename = xmlNodeGetContent(field);
810 else if (!strcmp(field->name, "elementfactory")) {
811 GstElementFactory *factory = gst_elementfactory_load_thyself(field);
812 gst_plugin_add_factory (plugin, factory);
815 else if (!strcmp(field->name, "typefactory")) {
816 GstTypeFactory *factory = gst_typefactory_load_thyself(field);
817 gst_plugin_add_type (plugin, factory);
826 _gst_plugins = g_list_prepend(_gst_plugins, plugin);
830 kinderen = kinderen->next;
832 GST_INFO (GST_CAT_PLUGIN_LOADING,"added %d registered factories and %d types",elementcount,typecount);
837 * gst_plugin_get_factory_list:
838 * @plugin: the plugin to get the factories from
840 * get a list of all the factories that this plugin provides
842 * Returns: a GList of factories
845 gst_plugin_get_factory_list (GstPlugin *plugin)
847 g_return_val_if_fail (plugin != NULL, NULL);
849 return plugin->elements;
853 * gst_plugin_get_type_list:
854 * @plugin: the plugin to get the typefactories from
856 * get a list of all the typefactories that this plugin provides
858 * Returns: a GList of factories
861 gst_plugin_get_type_list (GstPlugin *plugin)
863 g_return_val_if_fail (plugin != NULL, NULL);
865 return plugin->types;