various style fixes
[platform/upstream/gstreamer.git] / gst / gstregistry.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 David A. Schleef <ds@schleef.org>
5  *
6  * gstregistry.c: handle registry
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:gstregistry
26  * @short_description: Abstract base class for management of #GstPlugin objects
27  * @see_also: #GstPlugin, #GstPluginFeature
28  *
29  * One registry holds the metadata of a set of plugins.
30  * All registries build the #GstRegistryPool.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 #include "gst_private.h"
37 #include <glib.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <errno.h>
44 #include <stdio.h>
45 #include <string.h>
46
47
48 #include "gstinfo.h"
49 #include "gstregistry.h"
50 #include "gstmarshal.h"
51 #include "gstfilter.h"
52
53 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
54
55 /* the one instance of the default registry */
56 static GstRegistry *_gst_registry_default = NULL;
57
58 /*
59  * Design:
60  *
61  * The GstRegistry object is a list of plugins and some functions
62  * for dealing with them.  Plugins are matched 1-1 with a file on
63  * disk, and may or may not be loaded at a given time.  There may
64  * be multiple GstRegistry objects, but the "default registry" is
65  * the only object that has any meaning to the core.
66  *
67  * The registry.xml file in 0.9 is actually a cache of plugin
68  * information.  This is unlike previous versions, where the registry
69  * file was the primary source of plugin information, and was created
70  * by the gst-register command.
71  *
72  * In 0.9, the primary source, at all times, of plugin information
73  * is each plugin file itself.  Thus, if an application wants
74  * information about a particular plugin, or wants to search for
75  * a feature that satisfies given criteria, the primary means of
76  * doing so is to load every plugin and look at the resulting
77  * information that is gathered in the default registry.  Clearly,
78  * this is a time consuming process, so we cache information in
79  * the registry.xml file.
80  *
81  * On startup, plugins are searched for in the plugin search path.
82  * This path can be set directly using the GST_PLUGIN_PATH
83  * environment variable.  The registry file is loaded from
84  * ~/.gstreamer-0.9/registry.xml or the file listed in the
85  * GST_REGISTRY env var.  The only reason to change the registry
86  * location is for testing.
87  *
88  * For each plugin that is found in the plugin search path, there
89  * could be 3 possibilities for cached information:
90  *  - the cache may not contain information about a given file.
91  *  - the cache may have stale information.
92  *  - the cache may have current information.
93  * In the first two cases, the plugin is loaded and the cache
94  * updated.  In addition to these cases, the cache may have entries
95  * for plugins that are not relevant to the current process.  These
96  * are marked as not available to the current process.  If the
97  * cache is updated for whatever reason, it is marked dirty.
98  *
99  * A dirty cache is written out at the end of initialization.  Each
100  * entry is checked to make sure the information is minimally valid.
101  * If not, the entry is simply dropped.
102  *
103  * Implementation notes:
104  *
105  * The "cache" and "default registry" are different concepts and
106  * can represent different sets of plugins.  For various reasons,
107  * at init time, the cache is stored in the default registry, and
108  * plugins not relevant to the current process are marked with the
109  * GST_PLUGIN_FLAG_CACHED bit.  These plugins are removed at the
110  * end of intitialization.
111  *
112  */
113
114 /* Element signals and args */
115 enum
116 {
117   PLUGIN_ADDED,
118   FEATURE_ADDED,
119   LAST_SIGNAL
120 };
121
122 static void gst_registry_class_init (GstRegistryClass * klass);
123 static void gst_registry_init (GstRegistry * registry);
124 static void gst_registry_finalize (GObject * object);
125
126 static guint gst_registry_signals[LAST_SIGNAL] = { 0 };
127
128 static GstPluginFeature *gst_registry_lookup_feature_locked (GstRegistry *
129     registry, const char *name);
130 static GstPlugin *gst_registry_lookup_locked (GstRegistry * registry,
131     const char *filename);
132
133 G_DEFINE_TYPE (GstRegistry, gst_registry, GST_TYPE_OBJECT);
134 static GstObjectClass *parent_class = NULL;
135
136 static void
137 gst_registry_class_init (GstRegistryClass * klass)
138 {
139   GObjectClass *gobject_class;
140
141   gobject_class = (GObjectClass *) klass;
142
143   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
144
145   gst_registry_signals[PLUGIN_ADDED] =
146       g_signal_new ("plugin-added", G_TYPE_FROM_CLASS (klass),
147       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRegistryClass, plugin_added), NULL,
148       NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
149   gst_registry_signals[FEATURE_ADDED] =
150       g_signal_new ("feature-added", G_TYPE_FROM_CLASS (klass),
151       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRegistryClass, feature_added),
152       NULL, NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
153
154   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_registry_finalize);
155 }
156
157 static void
158 gst_registry_init (GstRegistry * registry)
159 {
160 }
161
162 static void
163 gst_registry_finalize (GObject * object)
164 {
165   GstRegistry *registry = GST_REGISTRY (object);
166   GList *plugins, *p;
167   GList *features, *f;
168
169   plugins = registry->plugins;
170   registry->plugins = NULL;
171
172   GST_DEBUG_OBJECT (registry, "registry finalize");
173   p = plugins;
174   while (p) {
175     GstPlugin *plugin = p->data;
176
177     if (plugin) {
178       GST_DEBUG_OBJECT (registry, "removing plugin %s",
179           gst_plugin_get_name (plugin));
180       gst_registry_remove_plugin (registry, plugin);
181     }
182     p = g_list_next (p);
183   }
184   g_list_free (plugins);
185
186   features = registry->features;
187   registry->features = NULL;
188
189   f = features;
190   while (f) {
191     GstPluginFeature *feature = f->data;
192
193     if (feature) {
194       gst_registry_remove_feature (registry, feature);
195     }
196     f = g_list_next (f);
197   }
198   g_list_free (features);
199
200
201   G_OBJECT_CLASS (parent_class)->finalize (object);
202 }
203
204 /**
205  * gst_registry_get_default:
206  *
207  * Retrieves the default registry. The caller does not own a reference on the
208  * registry, as it is alive as long as GStreamer is initialized.
209  */
210 GstRegistry *
211 gst_registry_get_default (void)
212 {
213   if (!_gst_registry_default) {
214     _gst_registry_default = g_object_new (GST_TYPE_REGISTRY, NULL);
215   }
216   return _gst_registry_default;
217 }
218
219 /**
220  * gst_registry_add_path:
221  * @registry: the registry to add the path to
222  * @path: the path to add to the registry
223  *
224  * Add the given path to the registry. The syntax of the
225  * path is specific to the registry. If the path has already been
226  * added, do nothing.
227  */
228 void
229 gst_registry_add_path (GstRegistry * registry, const gchar * path)
230 {
231   g_return_if_fail (GST_IS_REGISTRY (registry));
232   g_return_if_fail (path != NULL);
233
234   if (strlen (path) == 0) {
235     GST_INFO ("Ignoring empty plugin path");
236     return;
237   }
238
239   GST_LOCK (registry);
240   if (g_list_find_custom (registry->paths, path, (GCompareFunc) strcmp)) {
241     g_warning ("path %s already added to registry", path);
242     GST_UNLOCK (registry);
243     return;
244   }
245
246   GST_INFO ("Adding plugin path: \"%s\"", path);
247   registry->paths = g_list_append (registry->paths, g_strdup (path));
248   GST_UNLOCK (registry);
249 }
250
251 /**
252  * gst_registry_get_path_list:
253  * @registry: the registry to get the pathlist of
254  *
255  * Get the list of paths for the given registry.
256  *
257  * Returns: A Glist of paths as strings. g_list_free after use.
258  */
259 GList *
260 gst_registry_get_path_list (GstRegistry * registry)
261 {
262   GList *list;
263
264   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
265
266   GST_LOCK (registry);
267   /* We don't need to copy the strings, because they won't be deleted
268    * as long as the GstRegistry is around */
269   list = g_list_copy (registry->paths);
270   GST_UNLOCK (registry);
271
272   return list;
273 }
274
275
276 /**
277  * gst_registry_add_plugin:
278  * @registry: the registry to add the plugin to
279  * @plugin: the plugin to add
280  *
281  * Add the plugin to the registry. The plugin-added signal will be emitted.
282  *
283  * Returns: TRUE on success.
284  */
285 gboolean
286 gst_registry_add_plugin (GstRegistry * registry, GstPlugin * plugin)
287 {
288   GstPlugin *existing_plugin;
289
290   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
291
292   GST_LOCK (registry);
293   existing_plugin = gst_registry_lookup_locked (registry, plugin->filename);
294   if (existing_plugin) {
295     GST_DEBUG_OBJECT (registry,
296         "Replacing existing plugin %p with new plugin %p for filename \"%s\"",
297         existing_plugin, plugin, GST_STR_NULL (plugin->filename));
298     registry->plugins = g_list_remove (registry->plugins, existing_plugin);
299     gst_object_unref (existing_plugin);
300   }
301
302   GST_DEBUG_OBJECT (registry, "adding plugin %p for filename \"%s\"",
303       plugin, GST_STR_NULL (plugin->filename));
304
305   registry->plugins = g_list_prepend (registry->plugins, plugin);
306
307   gst_object_ref (plugin);
308   gst_object_sink (plugin);
309   GST_UNLOCK (registry);
310
311   GST_DEBUG_OBJECT (registry, "emitting plugin-added for filename \"%s\"",
312       GST_STR_NULL (plugin->filename));
313   g_signal_emit (G_OBJECT (registry), gst_registry_signals[PLUGIN_ADDED], 0,
314       plugin);
315
316   return TRUE;
317 }
318
319 /**
320  * gst_registry_remove_plugin:
321  * @registry: the registry to remove the plugin from
322  * @plugin: the plugin to remove
323  *
324  * Remove the plugin from the registry.
325  */
326 void
327 gst_registry_remove_plugin (GstRegistry * registry, GstPlugin * plugin)
328 {
329   g_return_if_fail (GST_IS_REGISTRY (registry));
330
331   GST_LOCK (registry);
332   registry->plugins = g_list_remove (registry->plugins, plugin);
333   GST_UNLOCK (registry);
334   gst_object_unref (plugin);
335 }
336
337 /**
338  * gst_registry_add_feature:
339  * @registry: the registry to add the plugin to
340  * @feature: the feature to add
341  *
342  * Add the feature to the registry. The feature-added signal will be emitted.
343  *
344  * Returns: TRUE on success.
345  */
346 gboolean
347 gst_registry_add_feature (GstRegistry * registry, GstPluginFeature * feature)
348 {
349   GstPluginFeature *existing_feature;
350
351   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
352   g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), FALSE);
353   g_return_val_if_fail (feature->name != NULL, FALSE);
354   g_return_val_if_fail (feature->plugin_name != NULL, FALSE);
355
356   GST_LOCK (registry);
357   existing_feature = gst_registry_lookup_feature_locked (registry,
358       feature->name);
359   if (existing_feature) {
360     GST_DEBUG_OBJECT (registry, "Replacing existing feature %p (%s)",
361         existing_feature, feature->name);
362     registry->features = g_list_remove (registry->features, existing_feature);
363     gst_object_unref (existing_feature);
364   }
365
366   GST_DEBUG_OBJECT (registry, "adding feature %p (%s)", feature, feature->name);
367
368   registry->features = g_list_prepend (registry->features, feature);
369
370   gst_object_ref (feature);
371   gst_object_sink (feature);
372   GST_UNLOCK (registry);
373
374   GST_DEBUG_OBJECT (registry, "emitting feature-added for %s", feature->name);
375   g_signal_emit (G_OBJECT (registry), gst_registry_signals[FEATURE_ADDED], 0,
376       feature);
377
378   return TRUE;
379 }
380
381 /**
382  * gst_registry_remove_feature:
383  * @registry: the registry to remove the feature from
384  * @feature: the feature to remove
385  *
386  * Remove the feature from the registry.
387  */
388 void
389 gst_registry_remove_feature (GstRegistry * registry, GstPluginFeature * feature)
390 {
391   g_return_if_fail (GST_IS_REGISTRY (registry));
392   GST_DEBUG_OBJECT (registry, "removing feature %p (%s)",
393       feature, gst_plugin_feature_get_name (feature));
394
395   GST_LOCK (registry);
396   registry->features = g_list_remove (registry->features, feature);
397   GST_UNLOCK (registry);
398   gst_object_unref (feature);
399 }
400
401 /**
402  * gst_registry_plugin_filter:
403  * @registry: registry to query
404  * @filter: the filter to use
405  * @first: only return first match
406  * @user_data: user data passed to the filter function
407  *
408  * Runs a filter against all plugins in the registry and returns a GList with
409  * the results. If the first flag is set, only the first match is
410  * returned (as a list with a single object).
411  * Every plugin is reffed; use gst_plugin_list_free() after use, which
412  * will unref again.
413  *
414  * Returns: a #GList of #GstPlugin
415  */
416 GList *
417 gst_registry_plugin_filter (GstRegistry * registry,
418     GstPluginFilter filter, gboolean first, gpointer user_data)
419 {
420   GList *list;
421   GList *g;
422
423   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
424
425   GST_LOCK (registry);
426   list = gst_filter_run (registry->plugins, (GstFilterFunc) filter, first,
427       user_data);
428   for (g = list; g; g = g->next) {
429     gst_object_ref (GST_PLUGIN (g->data));
430   }
431   GST_UNLOCK (registry);
432
433   return list;
434 }
435
436 /**
437  * gst_registry_feature_filter:
438  * @registry: registry to query
439  * @filter: the filter to use
440  * @first: only return first match
441  * @user_data: user data passed to the filter function
442  *
443  * Runs a filter against all features of the plugins in the registry
444  * and returns a GList with the results.
445  * If the first flag is set, only the first match is
446  * returned (as a list with a single object).
447  *
448  * Returns: a GList of plugin features, gst_plugin_feature_list_free after use.
449  */
450 GList *
451 gst_registry_feature_filter (GstRegistry * registry,
452     GstPluginFeatureFilter filter, gboolean first, gpointer user_data)
453 {
454   GList *list;
455   GList *g;
456
457   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
458
459   GST_LOCK (registry);
460   list = gst_filter_run (registry->features, (GstFilterFunc) filter, first,
461       user_data);
462   for (g = list; g; g = g->next) {
463     gst_object_ref (GST_PLUGIN_FEATURE (g->data));
464   }
465   GST_UNLOCK (registry);
466
467   return list;
468 }
469
470 /**
471  * gst_registry_find_plugin:
472  * @registry: the registry to search
473  * @name: the plugin name to find
474  *
475  * Find the plugin with the given name in the registry.
476  * The plugin will be reffed; caller is responsible for unreffing.
477  *
478  * Returns: The plugin with the given name or NULL if the plugin was not found.
479  */
480 GstPlugin *
481 gst_registry_find_plugin (GstRegistry * registry, const gchar * name)
482 {
483   GList *walk;
484   GstPlugin *result = NULL;
485
486   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
487   g_return_val_if_fail (name != NULL, NULL);
488
489   walk = gst_registry_plugin_filter (registry,
490       (GstPluginFilter) gst_plugin_name_filter, TRUE, (gpointer) name);
491   if (walk) {
492     result = GST_PLUGIN (walk->data);
493
494     gst_object_ref (result);
495     gst_plugin_list_free (walk);
496   }
497
498   return result;
499 }
500
501 /**
502  * gst_registry_find_feature:
503  * @registry: the registry to search
504  * @name: the pluginfeature name to find
505  * @type: the pluginfeature type to find
506  *
507  * Find the pluginfeature with the given name and type in the registry.
508  *
509  * Returns: The pluginfeature with the given name and type or NULL
510  * if the plugin was not found.
511  */
512 GstPluginFeature *
513 gst_registry_find_feature (GstRegistry * registry, const gchar * name,
514     GType type)
515 {
516   GstPluginFeature *feature = NULL;
517   GList *walk;
518   GstTypeNameData data;
519
520   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
521   g_return_val_if_fail (name != NULL, NULL);
522
523   data.name = name;
524   data.type = type;
525
526   walk = gst_registry_feature_filter (registry,
527       (GstPluginFeatureFilter) gst_plugin_feature_type_name_filter,
528       TRUE, &data);
529
530   if (walk) {
531     feature = GST_PLUGIN_FEATURE (walk->data);
532
533     gst_object_ref (feature);
534     gst_plugin_feature_list_free (walk);
535   }
536
537   return feature;
538 }
539
540 GList *
541 gst_registry_get_feature_list (GstRegistry * registry, GType type)
542 {
543   GstTypeNameData data;
544
545   data.type = type;
546   data.name = NULL;
547
548   return gst_registry_feature_filter (registry,
549       (GstPluginFeatureFilter) gst_plugin_feature_type_name_filter,
550       FALSE, &data);
551 }
552
553 GList *
554 gst_registry_get_plugin_list (GstRegistry * registry)
555 {
556   GList *list;
557   GList *g;
558
559   GST_LOCK (registry);
560   list = g_list_copy (registry->plugins);
561   for (g = list; g; g = g->next) {
562     gst_object_ref (GST_PLUGIN (g->data));
563   }
564   GST_UNLOCK (registry);
565
566   return list;
567 }
568
569 static GstPluginFeature *
570 gst_registry_lookup_feature_locked (GstRegistry * registry, const char *name)
571 {
572   GList *g;
573   GstPluginFeature *feature;
574
575   if (name == NULL)
576     return NULL;
577
578   for (g = registry->features; g; g = g_list_next (g)) {
579     feature = GST_PLUGIN_FEATURE (g->data);
580     if (feature->name && strcmp (name, feature->name) == 0) {
581       return feature;
582     }
583   }
584
585   return NULL;
586 }
587
588 GstPluginFeature *
589 gst_registry_lookup_feature (GstRegistry * registry, const char *name)
590 {
591   GstPluginFeature *feature;
592
593   GST_LOCK (registry);
594   feature = gst_registry_lookup_feature_locked (registry, name);
595   if (feature)
596     gst_object_ref (feature);
597   GST_UNLOCK (registry);
598
599   return feature;
600 }
601
602 static GstPlugin *
603 gst_registry_lookup_locked (GstRegistry * registry, const char *filename)
604 {
605   GList *g;
606   GstPlugin *plugin;
607   gchar *basename;
608
609   if (filename == NULL)
610     return NULL;
611
612   basename = g_path_get_basename (filename);
613   for (g = registry->plugins; g; g = g_list_next (g)) {
614     plugin = GST_PLUGIN (g->data);
615     if (plugin->basename && strcmp (basename, plugin->basename) == 0) {
616       g_free (basename);
617       return plugin;
618     }
619   }
620
621   g_free (basename);
622   return NULL;
623 }
624
625 /**
626  * gst_registry_lookup:
627  * @registry: the registry to look up in
628  * @filename: the name of the file to look up
629  *
630  * Look up a plugin in the given registry with the given filename.
631  * If found, plugin is reffed.  Caller must unref after use.
632  *
633  * Returns: the #GstPlugin if found, or NULL if not.
634  */
635 GstPlugin *
636 gst_registry_lookup (GstRegistry * registry, const char *filename)
637 {
638   GstPlugin *plugin;
639
640   GST_LOCK (registry);
641   plugin = gst_registry_lookup_locked (registry, filename);
642   if (plugin)
643     gst_object_ref (plugin);
644   GST_UNLOCK (registry);
645
646   return plugin;
647 }
648
649 static void
650 gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
651     int level)
652 {
653   GDir *dir;
654   const gchar *dirent;
655   gchar *filename;
656   GstPlugin *plugin;
657   GstPlugin *newplugin;
658
659   dir = g_dir_open (path, 0, NULL);
660   if (!dir)
661     return;
662
663   while ((dirent = g_dir_read_name (dir))) {
664     filename = g_strjoin ("/", path, dirent, NULL);
665
666     GST_LOG_OBJECT (registry, "examining file: %s", filename);
667
668     if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
669       if (level > 0) {
670         GST_LOG_OBJECT (registry, "found directory, recursing");
671         gst_registry_scan_path_level (registry, filename, level - 1);
672       } else {
673         GST_LOG_OBJECT (registry,
674             "found directory, but recursion level is too deep");
675       }
676       g_free (filename);
677       continue;
678     }
679     if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
680       GST_LOG_OBJECT (registry, "not a regular file, ignoring");
681       g_free (filename);
682       continue;
683     }
684     if (!g_str_has_suffix (filename, ".so") &&
685         !g_str_has_suffix (filename, ".dll") &&
686         !g_str_has_suffix (filename, ".dynlib")) {
687       GST_LOG_OBJECT (registry,
688           "extension is not recognized as module file, ignoring");
689       g_free (filename);
690       continue;
691     }
692
693     /* plug-ins are considered unique by basename; if the given name
694      * was already seen by the registry, we ignore it */
695     plugin = gst_registry_lookup (registry, filename);
696     if (plugin) {
697       struct stat file_status;
698
699       if (stat (filename, &file_status)) {
700         /* FIXME remove from cache */
701         g_free (filename);
702         continue;
703       }
704       if (plugin->registered) {
705         GST_DEBUG_OBJECT (registry,
706             "plugin already registered from path \"%s\"",
707             GST_STR_NULL (plugin->filename));
708         g_free (filename);
709         continue;
710       }
711       plugin->registered = TRUE;
712       if (plugin->file_mtime == file_status.st_mtime &&
713           plugin->file_size == file_status.st_size) {
714         GST_DEBUG_OBJECT (registry, "file %s cached", filename);
715         plugin->flags &= ~GST_PLUGIN_FLAG_CACHED;
716       } else {
717         GST_INFO_OBJECT (registry, "cached info for %s is stale", filename);
718         GST_DEBUG_OBJECT (registry, "mtime %ld != %ld or size %"
719             G_GSIZE_FORMAT " != %"
720             G_GSIZE_FORMAT, plugin->file_mtime, file_status.st_mtime,
721             plugin->file_size, file_status.st_size);
722         gst_registry_remove_plugin (gst_registry_get_default (), plugin);
723         newplugin = gst_plugin_load_file (filename, NULL);
724         if (newplugin)
725           gst_object_unref (newplugin);
726       }
727       gst_object_unref (plugin);
728
729     } else {
730       GST_DEBUG_OBJECT (registry, "file %s not yet in registry", filename);
731       newplugin = gst_plugin_load_file (filename, NULL);
732       if (newplugin) {
733         newplugin->registered = TRUE;
734         gst_object_unref (newplugin);
735       }
736     }
737
738     g_free (filename);
739   }
740
741   g_dir_close (dir);
742 }
743
744 /**
745  * gst_registry_scan_path:
746  * @registry: the registry to add the path to
747  * @path: the path to add to the registry
748  *
749  * Add the given path to the registry. The syntax of the
750  * path is specific to the registry. If the path has already been
751  * added, do nothing.
752  */
753 void
754 gst_registry_scan_path (GstRegistry * registry, const gchar * path)
755 {
756   GST_DEBUG_OBJECT (registry, "scanning path %s", path);
757   gst_registry_scan_path_level (registry, path, 10);
758 }
759
760 void
761 _gst_registry_remove_cache_plugins (GstRegistry * registry)
762 {
763   GList *g;
764   GList *g_next;
765   GstPlugin *plugin;
766
767   GST_DEBUG_OBJECT (registry, "removing cached plugins");
768   g = registry->plugins;
769   while (g) {
770     g_next = g->next;
771     plugin = g->data;
772     if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
773       GST_DEBUG_OBJECT (registry, "removing cached plugin \"%s\"",
774           GST_STR_NULL (plugin->filename));
775       registry->plugins = g_list_remove (registry->plugins, plugin);
776       gst_object_unref (plugin);
777     }
778     g = g_next;
779   }
780 }
781
782
783 static gboolean
784 _gst_plugin_feature_filter_plugin_name (GstPluginFeature * feature,
785     gpointer user_data)
786 {
787   return (strcmp (feature->plugin_name, (gchar *) user_data) == 0);
788 }
789
790 GList *
791 gst_registry_get_feature_list_by_plugin (GstRegistry * registry,
792     const gchar * name)
793 {
794   return gst_registry_feature_filter (registry,
795       _gst_plugin_feature_filter_plugin_name, FALSE, (gpointer) name);
796 }
797
798 void
799 _gst_registry_cleanup ()
800 {
801   if (!_gst_registry_default)
802     return;
803
804   gst_object_unref (_gst_registry_default);
805   _gst_registry_default = NULL;
806 }
807
808 /**
809  * gst_default_registry_check_feature_version:
810  * @feature_name: the name of the feature (e.g. "oggdemux")
811  * @min_major: the minimum major version number
812  * @min_minor: the minimum minor version number
813  * @min_micro: the minimum micro version number
814  *
815  * Checks whether a plugin feature by the given name exists in the
816  * default registry and whether its version is at least the
817  * version required.
818  *
819  * Returns: #TRUE if the feature could be found and the version is
820  * the same as the required version or newer, and #FALSE otherwise.
821  */
822 gboolean
823 gst_default_registry_check_feature_version (const gchar * feature_name,
824     guint min_major, guint min_minor, guint min_micro)
825 {
826   GstPluginFeature *feature;
827   GstRegistry *registry;
828   gboolean ret = FALSE;
829
830   g_return_val_if_fail (feature_name != NULL, FALSE);
831
832   GST_DEBUG ("Looking up plugin feature '%s'", feature_name);
833
834   registry = gst_registry_get_default ();
835   feature = gst_registry_lookup_feature (registry, feature_name);
836   if (feature) {
837     ret = gst_plugin_feature_check_version (feature, min_major, min_minor,
838         min_micro);
839     gst_object_unref (feature);
840   } else {
841     GST_DEBUG ("Could not find plugin feature '%s'", feature_name);
842   }
843
844   return ret;
845 }