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 */
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 */
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>
48 #include "gstinfo.h"
49 #include "gstregistry.h"
50 #include "gstmarshal.h"
51 #include "gstfilter.h"
53 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
55 /* the one instance of the default registry */
56 static GstRegistry *_gst_registry_default = NULL;
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 */
114 /* Element signals and args */
115 enum
116 {
117 PLUGIN_ADDED,
118 FEATURE_ADDED,
119 LAST_SIGNAL
120 };
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);
126 static guint gst_registry_signals[LAST_SIGNAL] = { 0 };
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);
133 G_DEFINE_TYPE (GstRegistry, gst_registry, GST_TYPE_OBJECT);
134 static GstObjectClass *parent_class = NULL;
136 static void
137 gst_registry_class_init (GstRegistryClass * klass)
138 {
139 GObjectClass *gobject_class;
141 gobject_class = (GObjectClass *) klass;
143 parent_class = g_type_class_ref (GST_TYPE_OBJECT);
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);
154 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_registry_finalize);
155 }
157 static void
158 gst_registry_init (GstRegistry * registry)
159 {
160 }
162 static void
163 gst_registry_finalize (GObject * object)
164 {
165 GstRegistry *registry = GST_REGISTRY (object);
166 GList *plugins, *p;
167 GList *features, *f;
169 plugins = registry->plugins;
170 registry->plugins = NULL;
172 GST_DEBUG_OBJECT (registry, "registry finalize");
173 p = plugins;
174 while (p) {
175 GstPlugin *plugin = p->data;
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);
186 features = registry->features;
187 registry->features = NULL;
189 f = features;
190 while (f) {
191 GstPluginFeature *feature = f->data;
193 if (feature) {
194 gst_registry_remove_feature (registry, feature);
195 }
196 f = g_list_next (f);
197 }
198 g_list_free (features);
201 G_OBJECT_CLASS (parent_class)->finalize (object);
202 }
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 }
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);
234 if (strlen (path) == 0) {
235 GST_INFO ("Ignoring empty plugin path");
236 return;
237 }
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 }
246 GST_INFO ("Adding plugin path: \"%s\"", path);
247 registry->paths = g_list_append (registry->paths, g_strdup (path));
248 GST_UNLOCK (registry);
249 }
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;
264 g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
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);
272 return list;
273 }
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;
290 g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
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 }
302 GST_DEBUG_OBJECT (registry, "adding plugin %p for filename \"%s\"",
303 plugin, GST_STR_NULL (plugin->filename));
305 registry->plugins = g_list_prepend (registry->plugins, plugin);
307 gst_object_ref (plugin);
308 gst_object_sink (plugin);
309 GST_UNLOCK (registry);
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);
316 return TRUE;
317 }
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));
331 GST_LOCK (registry);
332 registry->plugins = g_list_remove (registry->plugins, plugin);
333 GST_UNLOCK (registry);
334 gst_object_unref (plugin);
335 }
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;
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);
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 }
366 GST_DEBUG_OBJECT (registry, "adding feature %p (%s)", feature, feature->name);
368 registry->features = g_list_prepend (registry->features, feature);
370 gst_object_ref (feature);
371 gst_object_sink (feature);
372 GST_UNLOCK (registry);
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);
378 return TRUE;
379 }
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));
395 GST_LOCK (registry);
396 registry->features = g_list_remove (registry->features, feature);
397 GST_UNLOCK (registry);
398 gst_object_unref (feature);
399 }
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;
423 g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
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);
433 return list;
434 }
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;
457 g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
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);
467 return list;
468 }
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;
486 g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
487 g_return_val_if_fail (name != NULL, NULL);
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);
494 gst_object_ref (result);
495 gst_plugin_list_free (walk);
496 }
498 return result;
499 }
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;
520 g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
521 g_return_val_if_fail (name != NULL, NULL);
523 data.name = name;
524 data.type = type;
526 walk = gst_registry_feature_filter (registry,
527 (GstPluginFeatureFilter) gst_plugin_feature_type_name_filter,
528 TRUE, &data);
530 if (walk) {
531 feature = GST_PLUGIN_FEATURE (walk->data);
533 gst_object_ref (feature);
534 gst_plugin_feature_list_free (walk);
535 }
537 return feature;
538 }
540 GList *
541 gst_registry_get_feature_list (GstRegistry * registry, GType type)
542 {
543 GstTypeNameData data;
545 data.type = type;
546 data.name = NULL;
548 return gst_registry_feature_filter (registry,
549 (GstPluginFeatureFilter) gst_plugin_feature_type_name_filter,
550 FALSE, &data);
551 }
553 GList *
554 gst_registry_get_plugin_list (GstRegistry * registry)
555 {
556 GList *list;
557 GList *g;
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);
566 return list;
567 }
569 static GstPluginFeature *
570 gst_registry_lookup_feature_locked (GstRegistry * registry, const char *name)
571 {
572 GList *g;
573 GstPluginFeature *feature;
575 if (name == NULL)
576 return NULL;
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 }
585 return NULL;
586 }
588 GstPluginFeature *
589 gst_registry_lookup_feature (GstRegistry * registry, const char *name)
590 {
591 GstPluginFeature *feature;
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);
599 return feature;
600 }
602 static GstPlugin *
603 gst_registry_lookup_locked (GstRegistry * registry, const char *filename)
604 {
605 GList *g;
606 GstPlugin *plugin;
607 gchar *basename;
609 if (filename == NULL)
610 return NULL;
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 }
621 g_free (basename);
622 return NULL;
623 }
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;
640 GST_LOCK (registry);
641 plugin = gst_registry_lookup_locked (registry, filename);
642 if (plugin)
643 gst_object_ref (plugin);
644 GST_UNLOCK (registry);
646 return plugin;
647 }
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;
659 dir = g_dir_open (path, 0, NULL);
660 if (!dir)
661 return;
663 while ((dirent = g_dir_read_name (dir))) {
664 filename = g_strjoin ("/", path, dirent, NULL);
666 GST_LOG_OBJECT (registry, "examining file: %s", filename);
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 }
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;
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 gst_object_unref (plugin);
710 continue;
711 }
712 plugin->registered = TRUE;
713 if (plugin->file_mtime == file_status.st_mtime &&
714 plugin->file_size == file_status.st_size) {
715 GST_DEBUG_OBJECT (registry, "file %s cached", filename);
716 plugin->flags &= ~GST_PLUGIN_FLAG_CACHED;
717 } else {
718 GST_INFO_OBJECT (registry, "cached info for %s is stale", filename);
719 GST_DEBUG_OBJECT (registry, "mtime %ld != %ld or size %"
720 G_GSIZE_FORMAT " != %"
721 G_GSIZE_FORMAT, plugin->file_mtime, file_status.st_mtime,
722 plugin->file_size, file_status.st_size);
723 gst_registry_remove_plugin (gst_registry_get_default (), plugin);
724 newplugin = gst_plugin_load_file (filename, NULL);
725 if (newplugin)
726 gst_object_unref (newplugin);
727 }
728 gst_object_unref (plugin);
730 } else {
731 GST_DEBUG_OBJECT (registry, "file %s not yet in registry", filename);
732 newplugin = gst_plugin_load_file (filename, NULL);
733 if (newplugin) {
734 newplugin->registered = TRUE;
735 gst_object_unref (newplugin);
736 }
737 }
739 g_free (filename);
740 }
742 g_dir_close (dir);
743 }
745 /**
746 * gst_registry_scan_path:
747 * @registry: the registry to add the path to
748 * @path: the path to add to the registry
749 *
750 * Add the given path to the registry. The syntax of the
751 * path is specific to the registry. If the path has already been
752 * added, do nothing.
753 */
754 void
755 gst_registry_scan_path (GstRegistry * registry, const gchar * path)
756 {
757 GST_DEBUG_OBJECT (registry, "scanning path %s", path);
758 gst_registry_scan_path_level (registry, path, 10);
759 }
761 void
762 _gst_registry_remove_cache_plugins (GstRegistry * registry)
763 {
764 GList *g;
765 GList *g_next;
766 GstPlugin *plugin;
768 GST_DEBUG_OBJECT (registry, "removing cached plugins");
769 g = registry->plugins;
770 while (g) {
771 g_next = g->next;
772 plugin = g->data;
773 if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
774 GST_DEBUG_OBJECT (registry, "removing cached plugin \"%s\"",
775 GST_STR_NULL (plugin->filename));
776 registry->plugins = g_list_remove (registry->plugins, plugin);
777 gst_object_unref (plugin);
778 }
779 g = g_next;
780 }
781 }
784 static gboolean
785 _gst_plugin_feature_filter_plugin_name (GstPluginFeature * feature,
786 gpointer user_data)
787 {
788 return (strcmp (feature->plugin_name, (gchar *) user_data) == 0);
789 }
791 GList *
792 gst_registry_get_feature_list_by_plugin (GstRegistry * registry,
793 const gchar * name)
794 {
795 return gst_registry_feature_filter (registry,
796 _gst_plugin_feature_filter_plugin_name, FALSE, (gpointer) name);
797 }
799 void
800 _gst_registry_cleanup ()
801 {
802 if (!_gst_registry_default)
803 return;
805 gst_object_unref (_gst_registry_default);
806 _gst_registry_default = NULL;
807 }
809 /**
810 * gst_default_registry_check_feature_version:
811 * @feature_name: the name of the feature (e.g. "oggdemux")
812 * @min_major: the minimum major version number
813 * @min_minor: the minimum minor version number
814 * @min_micro: the minimum micro version number
815 *
816 * Checks whether a plugin feature by the given name exists in the
817 * default registry and whether its version is at least the
818 * version required.
819 *
820 * Returns: #TRUE if the feature could be found and the version is
821 * the same as the required version or newer, and #FALSE otherwise.
822 */
823 gboolean
824 gst_default_registry_check_feature_version (const gchar * feature_name,
825 guint min_major, guint min_minor, guint min_micro)
826 {
827 GstPluginFeature *feature;
828 GstRegistry *registry;
829 gboolean ret = FALSE;
831 g_return_val_if_fail (feature_name != NULL, FALSE);
833 GST_DEBUG ("Looking up plugin feature '%s'", feature_name);
835 registry = gst_registry_get_default ();
836 feature = gst_registry_lookup_feature (registry, feature_name);
837 if (feature) {
838 ret = gst_plugin_feature_check_version (feature, min_major, min_minor,
839 min_micro);
840 gst_object_unref (feature);
841 } else {
842 GST_DEBUG ("Could not find plugin feature '%s'", feature_name);
843 }
845 return ret;
846 }