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