gst: Handle floating references consistently
[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., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 /**
25  * SECTION:gstregistry
26  * @title: GstRegistry
27  * @short_description: Abstract base class for management of #GstPlugin objects
28  * @see_also: #GstPlugin, #GstPluginFeature
29  *
30  * One registry holds the metadata of a set of plugins.
31  *
32  * <emphasis role="bold">Design:</emphasis>
33  *
34  * The #GstRegistry object is a list of plugins and some functions for dealing
35  * with them. Each #GstPlugin is matched 1-1 with a file on disk, and may or may
36  * not be loaded at a given time.
37  *
38  * The primary source, at all times, of plugin information is each plugin file
39  * itself. Thus, if an application wants information about a particular plugin,
40  * or wants to search for a feature that satisfies given criteria, the primary
41  * means of doing so is to load every plugin and look at the resulting
42  * information that is gathered in the default registry. Clearly, this is a time
43  * consuming process, so we cache information in the registry file. The format
44  * and location of the cache file is internal to gstreamer.
45  *
46  * On startup, plugins are searched for in the plugin search path. The following
47  * locations are checked in this order:
48  *
49  * * location from --gst-plugin-path commandline option.
50  * * the GST_PLUGIN_PATH environment variable.
51  * * the GST_PLUGIN_SYSTEM_PATH environment variable.
52  * * default locations (if GST_PLUGIN_SYSTEM_PATH is not set).
53  *   Those default locations are:
54  *   `$XDG_DATA_HOME/gstreamer-$GST_API_VERSION/plugins/`
55  *   and `$prefix/libs/gstreamer-$GST_API_VERSION/`.
56  *   [$XDG_DATA_HOME](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) defaults to
57  *   `$HOME/.local/share`.
58  *
59  * The registry cache file is loaded from
60  * `$XDG_CACHE_HOME/gstreamer-$GST_API_VERSION/registry-$ARCH.bin`
61  * (where $XDG_CACHE_HOME defaults to `$HOME/.cache`) or the file listed in the `GST_REGISTRY`
62  * env var. One reason to change the registry location is for testing.
63  *
64  * For each plugin that is found in the plugin search path, there could be 3
65  * possibilities for cached information:
66  *
67  *   * the cache may not contain information about a given file.
68  *   * the cache may have stale information.
69  *   * the cache may have current information.
70  *
71  * In the first two cases, the plugin is loaded and the cache updated. In
72  * addition to these cases, the cache may have entries for plugins that are not
73  * relevant to the current process. These are marked as not available to the
74  * current process. If the cache is updated for whatever reason, it is marked
75  * dirty.
76  *
77  * A dirty cache is written out at the end of initialization. Each entry is
78  * checked to make sure the information is minimally valid. If not, the entry is
79  * simply dropped.
80  *
81  * ## Implementation notes:
82  *
83  * The "cache" and "registry" are different concepts and can represent
84  * different sets of plugins. For various reasons, at init time, the cache is
85  * stored in the default registry, and plugins not relevant to the current
86  * process are marked with the %GST_PLUGIN_FLAG_CACHED bit. These plugins are
87  * removed at the end of initialization.
88  */
89
90 #ifdef HAVE_CONFIG_H
91 #include "config.h"
92 #endif
93 #include "gstconfig.h"
94 #include "gst_private.h"
95 #include <glib.h>
96 #include <sys/types.h>
97 #include <sys/stat.h>
98 #ifdef HAVE_UNISTD_H
99 #include <unistd.h>
100 #endif
101 #include <errno.h>
102 #include <stdio.h>
103 #include <string.h>
104
105 /* For g_stat () */
106 #include <glib/gstdio.h>
107
108 #include "gstinfo.h"
109 #include "gsterror.h"
110 #include "gstregistry.h"
111 #include "gstdeviceproviderfactory.h"
112
113 #include "gstpluginloader.h"
114
115 #include "gst-i18n-lib.h"
116
117 #include "gst.h"
118 #include "glib-compat-private.h"
119
120 #ifdef G_OS_WIN32
121 #include <windows.h>
122 extern HMODULE _priv_gst_dll_handle;
123 #endif
124
125 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
126
127 struct _GstRegistryPrivate
128 {
129   GList *plugins;
130   GList *features;
131
132   guint n_plugins;
133 #if 0
134   GList *paths;
135 #endif
136
137   int cache_file;
138
139   /* hash to speedup _lookup_feature_locked() */
140   GHashTable *feature_hash;
141   /* hash to speedup _lookup */
142   GHashTable *basename_hash;
143
144   /* updated whenever the feature list changes */
145   guint32 cookie;
146   /* speedup for searching features */
147   GList *element_factory_list;
148   guint32 efl_cookie;
149   GList *typefind_factory_list;
150   guint32 tfl_cookie;
151   GList *device_provider_factory_list;
152   guint32 dmfl_cookie;
153 };
154
155 /* the one instance of the default registry and the mutex protecting the
156  * variable. */
157 static GMutex _gst_registry_mutex;
158 static GstRegistry *_gst_registry_default = NULL;
159
160 /* defaults */
161 #define DEFAULT_FORK TRUE
162
163 /* control the behaviour of registry rebuild */
164 static gboolean _gst_enable_registry_fork = DEFAULT_FORK;
165 /* List of plugins that need preloading/reloading after scanning registry */
166 extern GSList *_priv_gst_preload_plugins;
167
168 #ifndef GST_DISABLE_REGISTRY
169 /* Set to TRUE to disable registry, behaves similar to GST_DISABLE_REGISTRY */
170 gboolean _priv_gst_disable_registry = FALSE;
171 /*set to TRUE when registry needn't to be updated */
172 gboolean _priv_gst_disable_registry_update = FALSE;
173 extern GList *_priv_gst_plugin_paths;
174
175 /* Set to TRUE when the registry cache should be disabled */
176 gboolean _gst_disable_registry_cache = FALSE;
177
178 static gboolean __registry_reuse_plugin_scanner = TRUE;
179 #endif
180
181 /* Element signals and args */
182 enum
183 {
184   PLUGIN_ADDED,
185   FEATURE_ADDED,
186   LAST_SIGNAL
187 };
188
189 static void gst_registry_finalize (GObject * object);
190
191 static guint gst_registry_signals[LAST_SIGNAL] = { 0 };
192
193 static GstPluginFeature *gst_registry_lookup_feature_locked (GstRegistry *
194     registry, const char *name);
195 static GstPlugin *gst_registry_lookup_bn_locked (GstRegistry * registry,
196     const char *basename);
197
198 #define gst_registry_parent_class parent_class
199 G_DEFINE_TYPE (GstRegistry, gst_registry, GST_TYPE_OBJECT);
200
201 static void
202 gst_registry_class_init (GstRegistryClass * klass)
203 {
204   GObjectClass *gobject_class;
205
206   gobject_class = (GObjectClass *) klass;
207
208   g_type_class_add_private (klass, sizeof (GstRegistryPrivate));
209
210   /**
211    * GstRegistry::plugin-added:
212    * @registry: the registry that emitted the signal
213    * @plugin: the plugin that has been added
214    *
215    * Signals that a plugin has been added to the registry (possibly
216    * replacing a previously-added one by the same name)
217    */
218   gst_registry_signals[PLUGIN_ADDED] =
219       g_signal_new ("plugin-added", G_TYPE_FROM_CLASS (klass),
220       G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
221       G_TYPE_NONE, 1, GST_TYPE_PLUGIN);
222
223   /**
224    * GstRegistry::feature-added:
225    * @registry: the registry that emitted the signal
226    * @feature: the feature that has been added
227    *
228    * Signals that a feature has been added to the registry (possibly
229    * replacing a previously-added one by the same name)
230    */
231   gst_registry_signals[FEATURE_ADDED] =
232       g_signal_new ("feature-added", G_TYPE_FROM_CLASS (klass),
233       G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
234       G_TYPE_NONE, 1, GST_TYPE_PLUGIN_FEATURE);
235
236   gobject_class->finalize = gst_registry_finalize;
237 }
238
239 static void
240 gst_registry_init (GstRegistry * registry)
241 {
242   registry->priv =
243       G_TYPE_INSTANCE_GET_PRIVATE (registry, GST_TYPE_REGISTRY,
244       GstRegistryPrivate);
245   registry->priv->feature_hash = g_hash_table_new (g_str_hash, g_str_equal);
246   registry->priv->basename_hash = g_hash_table_new (g_str_hash, g_str_equal);
247 }
248
249 static void
250 gst_registry_finalize (GObject * object)
251 {
252   GstRegistry *registry = GST_REGISTRY (object);
253   GList *plugins, *p;
254   GList *features, *f;
255
256   plugins = registry->priv->plugins;
257   registry->priv->plugins = NULL;
258   registry->priv->n_plugins = 0;
259
260   GST_DEBUG_OBJECT (registry, "registry finalize");
261   p = plugins;
262   while (p) {
263     GstPlugin *plugin = p->data;
264
265     if (plugin) {
266       GST_LOG_OBJECT (registry, "removing plugin %s",
267           gst_plugin_get_name (plugin));
268       gst_object_unref (plugin);
269     }
270     p = g_list_next (p);
271   }
272   g_list_free (plugins);
273
274   features = registry->priv->features;
275   registry->priv->features = NULL;
276
277   f = features;
278   while (f) {
279     GstPluginFeature *feature = f->data;
280
281     if (feature) {
282       GST_LOG_OBJECT (registry, "removing feature %p (%s)", feature,
283           GST_OBJECT_NAME (feature));
284       gst_object_unparent (GST_OBJECT_CAST (feature));
285     }
286     f = g_list_next (f);
287   }
288   g_list_free (features);
289
290   g_hash_table_destroy (registry->priv->feature_hash);
291   registry->priv->feature_hash = NULL;
292   g_hash_table_destroy (registry->priv->basename_hash);
293   registry->priv->basename_hash = NULL;
294
295   if (registry->priv->element_factory_list) {
296     GST_DEBUG_OBJECT (registry, "Cleaning up cached element factory list");
297     gst_plugin_feature_list_free (registry->priv->element_factory_list);
298   }
299
300   if (registry->priv->typefind_factory_list) {
301     GST_DEBUG_OBJECT (registry, "Cleaning up cached typefind factory list");
302     gst_plugin_feature_list_free (registry->priv->typefind_factory_list);
303   }
304
305   if (registry->priv->device_provider_factory_list) {
306     GST_DEBUG_OBJECT (registry,
307         "Cleaning up cached device provider factory list");
308     gst_plugin_feature_list_free (registry->priv->device_provider_factory_list);
309   }
310
311   G_OBJECT_CLASS (parent_class)->finalize (object);
312 }
313
314 /**
315  * gst_registry_get:
316  *
317  * Retrieves the singleton plugin registry. The caller does not own a
318  * reference on the registry, as it is alive as long as GStreamer is
319  * initialized.
320  *
321  * Returns: (transfer none): the #GstRegistry.
322  */
323 GstRegistry *
324 gst_registry_get (void)
325 {
326   GstRegistry *registry;
327
328   g_mutex_lock (&_gst_registry_mutex);
329   if (G_UNLIKELY (!_gst_registry_default)) {
330     _gst_registry_default = g_object_new (GST_TYPE_REGISTRY, NULL);
331     gst_object_ref_sink (GST_OBJECT_CAST (_gst_registry_default));
332   }
333   registry = _gst_registry_default;
334   g_mutex_unlock (&_gst_registry_mutex);
335
336   return registry;
337 }
338
339 #if 0
340 /**
341  * gst_registry_add_path:
342  * @registry: the registry to add the path to
343  * @path: the path to add to the registry
344  *
345  * Add the given path to the registry. The syntax of the
346  * path is specific to the registry. If the path has already been
347  * added, do nothing.
348  */
349 void
350 gst_registry_add_path (GstRegistry * registry, const gchar * path)
351 {
352   g_return_if_fail (GST_IS_REGISTRY (registry));
353   g_return_if_fail (path != NULL);
354
355   if (strlen (path) == 0)
356     goto empty_path;
357
358   GST_OBJECT_LOCK (registry);
359   if (g_list_find_custom (registry->priv->paths, path, (GCompareFunc) strcmp))
360     goto was_added;
361
362   GST_INFO ("Adding plugin path: \"%s\"", path);
363   registry->priv->paths =
364       g_list_append (registry->priv->paths, g_strdup (path));
365   GST_OBJECT_UNLOCK (registry);
366
367   return;
368
369 empty_path:
370   {
371     GST_INFO ("Ignoring empty plugin path");
372     return;
373   }
374 was_added:
375   {
376     g_warning ("path %s already added to registry", path);
377     GST_OBJECT_UNLOCK (registry);
378     return;
379   }
380 }
381
382 /**
383  * gst_registry_get_path_list:
384  * @registry: the registry to get the pathlist of
385  *
386  * Get the list of paths for the given registry.
387  *
388  * Returns: (transfer container) (element-type char*): A #GList of paths as
389  *     strings. g_list_free after use.
390  *
391  * MT safe.
392  */
393 GList *
394 gst_registry_get_path_list (GstRegistry * registry)
395 {
396   GList *list;
397
398   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
399
400   GST_OBJECT_LOCK (registry);
401   /* We don't need to copy the strings, because they won't be deleted
402    * as long as the GstRegistry is around */
403   list = g_list_copy (registry->priv->paths);
404   GST_OBJECT_UNLOCK (registry);
405
406   return list;
407 }
408 #endif
409
410 /**
411  * gst_registry_add_plugin:
412  * @registry: the registry to add the plugin to
413  * @plugin: (transfer full): the plugin to add
414  *
415  * Add the plugin to the registry. The plugin-added signal will be emitted.
416  * This function will sink @plugin.
417  *
418  * Returns: %TRUE on success.
419  *
420  * MT safe.
421  */
422 gboolean
423 gst_registry_add_plugin (GstRegistry * registry, GstPlugin * plugin)
424 {
425   GstPlugin *existing_plugin;
426
427   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
428   g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
429
430   GST_OBJECT_LOCK (registry);
431   if (G_LIKELY (plugin->basename)) {
432     /* we have a basename, see if we find the plugin */
433     existing_plugin =
434         gst_registry_lookup_bn_locked (registry, plugin->basename);
435     if (existing_plugin) {
436       GST_DEBUG_OBJECT (registry,
437           "Replacing existing plugin \"%s\" %p with new plugin %p for filename \"%s\"",
438           GST_STR_NULL (existing_plugin->filename), existing_plugin, plugin,
439           GST_STR_NULL (plugin->filename));
440       /* If the new plugin is blacklisted and the existing one isn't cached, do not
441        * accept if it's from a different location than the existing one */
442       if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED) &&
443           strcmp (plugin->filename, existing_plugin->filename)) {
444         GST_WARNING_OBJECT (registry,
445             "Not replacing plugin because new one (%s) is blacklisted but for a different location than existing one (%s)",
446             plugin->filename, existing_plugin->filename);
447         /* Keep reference counting consistent */
448         gst_object_ref_sink (plugin);
449         gst_object_unref (plugin);
450         GST_OBJECT_UNLOCK (registry);
451         return FALSE;
452       }
453       registry->priv->plugins =
454           g_list_remove (registry->priv->plugins, existing_plugin);
455       --registry->priv->n_plugins;
456       if (G_LIKELY (existing_plugin->basename))
457         g_hash_table_remove (registry->priv->basename_hash,
458             existing_plugin->basename);
459       gst_object_unref (existing_plugin);
460     }
461   }
462
463   GST_DEBUG_OBJECT (registry, "adding plugin %p for filename \"%s\"",
464       plugin, GST_STR_NULL (plugin->filename));
465
466   registry->priv->plugins = g_list_prepend (registry->priv->plugins, plugin);
467   ++registry->priv->n_plugins;
468
469   if (G_LIKELY (plugin->basename))
470     g_hash_table_replace (registry->priv->basename_hash, plugin->basename,
471         plugin);
472
473   gst_object_ref_sink (plugin);
474   GST_OBJECT_UNLOCK (registry);
475
476   GST_LOG_OBJECT (registry, "emitting plugin-added for filename \"%s\"",
477       GST_STR_NULL (plugin->filename));
478   g_signal_emit (registry, gst_registry_signals[PLUGIN_ADDED], 0, plugin);
479
480   return TRUE;
481 }
482
483 static void
484 gst_registry_remove_features_for_plugin_unlocked (GstRegistry * registry,
485     GstPlugin * plugin)
486 {
487   GList *f;
488
489   g_return_if_fail (GST_IS_REGISTRY (registry));
490   g_return_if_fail (GST_IS_PLUGIN (plugin));
491
492   /* Remove all features for this plugin */
493   f = registry->priv->features;
494   while (f != NULL) {
495     GList *next = g_list_next (f);
496     GstPluginFeature *feature = f->data;
497
498     if (G_UNLIKELY (feature && feature->plugin == plugin)) {
499       GST_DEBUG_OBJECT (registry, "removing feature %p (%s) for plugin %p (%s)",
500           feature, gst_plugin_feature_get_name (feature), plugin,
501           plugin->desc.name);
502
503       registry->priv->features =
504           g_list_delete_link (registry->priv->features, f);
505       g_hash_table_remove (registry->priv->feature_hash,
506           GST_OBJECT_NAME (feature));
507       gst_object_unparent (GST_OBJECT_CAST (feature));
508     }
509     f = next;
510   }
511   registry->priv->cookie++;
512 }
513
514 /**
515  * gst_registry_remove_plugin:
516  * @registry: the registry to remove the plugin from
517  * @plugin: (transfer none): the plugin to remove
518  *
519  * Remove the plugin from the registry.
520  *
521  * MT safe.
522  */
523 void
524 gst_registry_remove_plugin (GstRegistry * registry, GstPlugin * plugin)
525 {
526   g_return_if_fail (GST_IS_REGISTRY (registry));
527   g_return_if_fail (GST_IS_PLUGIN (plugin));
528
529   GST_DEBUG_OBJECT (registry, "removing plugin %p (%s)",
530       plugin, gst_plugin_get_name (plugin));
531
532   GST_OBJECT_LOCK (registry);
533   registry->priv->plugins = g_list_remove (registry->priv->plugins, plugin);
534   --registry->priv->n_plugins;
535   if (G_LIKELY (plugin->basename))
536     g_hash_table_remove (registry->priv->basename_hash, plugin->basename);
537   gst_registry_remove_features_for_plugin_unlocked (registry, plugin);
538   GST_OBJECT_UNLOCK (registry);
539   gst_object_unref (plugin);
540 }
541
542 /**
543  * gst_registry_add_feature:
544  * @registry: the registry to add the plugin to
545  * @feature: (transfer full): the feature to add
546  *
547  * Add the feature to the registry. The feature-added signal will be emitted.
548  * This function sinks @feature.
549  *
550  * Returns: %TRUE on success.
551  *
552  * MT safe.
553  */
554 gboolean
555 gst_registry_add_feature (GstRegistry * registry, GstPluginFeature * feature)
556 {
557   GstPluginFeature *existing_feature;
558
559   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
560   g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), FALSE);
561   g_return_val_if_fail (GST_OBJECT_NAME (feature) != NULL, FALSE);
562   g_return_val_if_fail (feature->plugin_name != NULL, FALSE);
563
564   GST_OBJECT_LOCK (registry);
565   existing_feature = gst_registry_lookup_feature_locked (registry,
566       GST_OBJECT_NAME (feature));
567   if (G_UNLIKELY (existing_feature)) {
568     GST_DEBUG_OBJECT (registry, "replacing existing feature %p (%s)",
569         existing_feature, GST_OBJECT_NAME (feature));
570     /* Remove the existing feature from the list now, before we insert the new
571      * one, but don't unref yet because the hash is still storing a reference to
572      * it. */
573     registry->priv->features =
574         g_list_remove (registry->priv->features, existing_feature);
575   }
576
577   GST_DEBUG_OBJECT (registry, "adding feature %p (%s)", feature,
578       GST_OBJECT_NAME (feature));
579
580   registry->priv->features = g_list_prepend (registry->priv->features, feature);
581   g_hash_table_replace (registry->priv->feature_hash, GST_OBJECT_NAME (feature),
582       feature);
583
584   if (G_UNLIKELY (existing_feature)) {
585     /* We unref now. No need to remove the feature name from the hash table, it
586      * got replaced by the new feature */
587     gst_object_unparent (GST_OBJECT_CAST (existing_feature));
588   }
589
590   gst_object_set_parent (GST_OBJECT_CAST (feature), GST_OBJECT_CAST (registry));
591
592   registry->priv->cookie++;
593   GST_OBJECT_UNLOCK (registry);
594
595   GST_LOG_OBJECT (registry, "emitting feature-added for %s",
596       GST_OBJECT_NAME (feature));
597   g_signal_emit (registry, gst_registry_signals[FEATURE_ADDED], 0, feature);
598
599   return TRUE;
600 }
601
602 /**
603  * gst_registry_remove_feature:
604  * @registry: the registry to remove the feature from
605  * @feature: (transfer none): the feature to remove
606  *
607  * Remove the feature from the registry.
608  *
609  * MT safe.
610  */
611 void
612 gst_registry_remove_feature (GstRegistry * registry, GstPluginFeature * feature)
613 {
614   g_return_if_fail (GST_IS_REGISTRY (registry));
615   g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
616
617   GST_DEBUG_OBJECT (registry, "removing feature %p (%s)",
618       feature, gst_plugin_feature_get_name (feature));
619
620   GST_OBJECT_LOCK (registry);
621   registry->priv->features = g_list_remove (registry->priv->features, feature);
622   g_hash_table_remove (registry->priv->feature_hash, GST_OBJECT_NAME (feature));
623   registry->priv->cookie++;
624   GST_OBJECT_UNLOCK (registry);
625
626   gst_object_unparent ((GstObject *) feature);
627 }
628
629 /**
630  * gst_registry_plugin_filter:
631  * @registry: registry to query
632  * @filter: (scope call): the filter to use
633  * @first: only return first match
634  * @user_data: (closure): user data passed to the filter function
635  *
636  * Runs a filter against all plugins in the registry and returns a #GList with
637  * the results. If the first flag is set, only the first match is
638  * returned (as a list with a single object).
639  * Every plugin is reffed; use gst_plugin_list_free() after use, which
640  * will unref again.
641  *
642  * Returns: (transfer full) (element-type Gst.Plugin): a #GList of #GstPlugin.
643  *     Use gst_plugin_list_free() after usage.
644  *
645  * MT safe.
646  */
647 GList *
648 gst_registry_plugin_filter (GstRegistry * registry,
649     GstPluginFilter filter, gboolean first, gpointer user_data)
650 {
651   GstPlugin **plugins;
652   GList *walk, *list = NULL;
653   guint n_plugins, i;
654
655   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
656
657   GST_OBJECT_LOCK (registry);
658   n_plugins = registry->priv->n_plugins;
659   plugins = g_newa (GstPlugin *, n_plugins + 1);
660   for (walk = registry->priv->plugins, i = 0; walk != NULL; walk = walk->next)
661     plugins[i++] = gst_object_ref (walk->data);
662   GST_OBJECT_UNLOCK (registry);
663
664   for (i = 0; i < n_plugins; ++i) {
665     if (filter == NULL || filter (plugins[i], user_data)) {
666       list = g_list_prepend (list, gst_object_ref (plugins[i]));
667
668       if (first)
669         break;
670     }
671   }
672
673   for (i = 0; i < n_plugins; ++i)
674     gst_object_unref (plugins[i]);
675
676   return list;
677 }
678
679 typedef struct
680 {
681   const gchar *name;
682   GType type;
683 } GstTypeNameData;
684
685 static gboolean
686 gst_plugin_feature_type_name_filter (GstPluginFeature * feature,
687     GstTypeNameData * data)
688 {
689   g_assert (GST_IS_PLUGIN_FEATURE (feature));
690
691   return ((data->type == 0 || data->type == G_OBJECT_TYPE (feature)) &&
692       (data->name == NULL || !strcmp (data->name, GST_OBJECT_NAME (feature))));
693 }
694
695 /* returns TRUE if the list was changed
696  *
697  * Must be called with the object lock taken */
698 static gboolean
699 gst_registry_get_feature_list_or_create (GstRegistry * registry,
700     GList ** previous, guint32 * cookie, GType type)
701 {
702   gboolean res = FALSE;
703   GstRegistryPrivate *priv = registry->priv;
704
705   if (G_UNLIKELY (!*previous || priv->cookie != *cookie)) {
706     GstTypeNameData data;
707     const GList *walk;
708
709     if (*previous) {
710       gst_plugin_feature_list_free (*previous);
711       *previous = NULL;
712     }
713
714     data.type = type;
715     data.name = NULL;
716
717     for (walk = registry->priv->features; walk != NULL; walk = walk->next) {
718       GstPluginFeature *feature = walk->data;
719
720       if (gst_plugin_feature_type_name_filter (feature, &data)) {
721         *previous = g_list_prepend (*previous, gst_object_ref (feature));
722       }
723     }
724
725     *cookie = priv->cookie;
726     res = TRUE;
727   }
728
729   return res;
730 }
731
732 static gint
733 type_find_factory_rank_cmp (const GstPluginFeature * fac1,
734     const GstPluginFeature * fac2)
735 {
736   if (G_LIKELY (fac1->rank != fac2->rank))
737     return fac2->rank - fac1->rank;
738
739   /* to make the order in which things happen more deterministic,
740    * sort by name when the ranks are the same. */
741   return strcmp (GST_OBJECT_NAME (fac1), GST_OBJECT_NAME (fac2));
742 }
743
744 static GList *
745 gst_registry_get_element_factory_list (GstRegistry * registry)
746 {
747   GList *list;
748
749   GST_OBJECT_LOCK (registry);
750
751   gst_registry_get_feature_list_or_create (registry,
752       &registry->priv->element_factory_list, &registry->priv->efl_cookie,
753       GST_TYPE_ELEMENT_FACTORY);
754
755   /* Return reffed copy */
756   list = gst_plugin_feature_list_copy (registry->priv->element_factory_list);
757
758   GST_OBJECT_UNLOCK (registry);
759
760   return list;
761 }
762
763 static GList *
764 gst_registry_get_typefind_factory_list (GstRegistry * registry)
765 {
766   GList *list;
767
768   GST_OBJECT_LOCK (registry);
769
770   if (G_UNLIKELY (gst_registry_get_feature_list_or_create (registry,
771               &registry->priv->typefind_factory_list,
772               &registry->priv->tfl_cookie, GST_TYPE_TYPE_FIND_FACTORY)))
773     registry->priv->typefind_factory_list =
774         g_list_sort (registry->priv->typefind_factory_list,
775         (GCompareFunc) type_find_factory_rank_cmp);
776
777   /* Return reffed copy */
778   list = gst_plugin_feature_list_copy (registry->priv->typefind_factory_list);
779
780   GST_OBJECT_UNLOCK (registry);
781
782   return list;
783 }
784
785
786 static GList *
787 gst_registry_get_device_provider_factory_list (GstRegistry * registry)
788 {
789   GList *list;
790
791   GST_OBJECT_LOCK (registry);
792
793   gst_registry_get_feature_list_or_create (registry,
794       &registry->priv->device_provider_factory_list,
795       &registry->priv->dmfl_cookie, GST_TYPE_DEVICE_PROVIDER_FACTORY);
796
797   /* Return reffed copy */
798   list =
799       gst_plugin_feature_list_copy (registry->
800       priv->device_provider_factory_list);
801
802   GST_OBJECT_UNLOCK (registry);
803
804   return list;
805 }
806
807 /**
808  * gst_registry_feature_filter:
809  * @registry: registry to query
810  * @filter: (scope call): the filter to use
811  * @first: only return first match
812  * @user_data: (closure): user data passed to the filter function
813  *
814  * Runs a filter against all features of the plugins in the registry
815  * and returns a GList with the results.
816  * If the first flag is set, only the first match is
817  * returned (as a list with a single object).
818  *
819  * Returns: (transfer full) (element-type Gst.PluginFeature): a #GList of
820  *     #GstPluginFeature. Use gst_plugin_feature_list_free() after usage.
821  *
822  * MT safe.
823  */
824 GList *
825 gst_registry_feature_filter (GstRegistry * registry,
826     GstPluginFeatureFilter filter, gboolean first, gpointer user_data)
827 {
828   GstPluginFeature **features;
829   GList *walk, *list = NULL;
830   guint n_features, i;
831
832   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
833
834   GST_OBJECT_LOCK (registry);
835   n_features = g_hash_table_size (registry->priv->feature_hash);
836   features = g_newa (GstPluginFeature *, n_features + 1);
837   for (walk = registry->priv->features, i = 0; walk != NULL; walk = walk->next)
838     features[i++] = gst_object_ref (walk->data);
839   GST_OBJECT_UNLOCK (registry);
840
841   for (i = 0; i < n_features; ++i) {
842     if (filter == NULL || filter (features[i], user_data)) {
843       list = g_list_prepend (list, gst_object_ref (features[i]));
844
845       if (first)
846         break;
847     }
848   }
849
850   for (i = 0; i < n_features; ++i)
851     gst_object_unref (features[i]);
852
853   return list;
854 }
855
856 static gboolean
857 gst_registry_plugin_name_filter (GstPlugin * plugin, const gchar * name)
858 {
859   return (plugin->desc.name && !strcmp (plugin->desc.name, name));
860 }
861
862 /**
863  * gst_registry_find_plugin:
864  * @registry: the registry to search
865  * @name: the plugin name to find
866  *
867  * Find the plugin with the given name in the registry.
868  * The plugin will be reffed; caller is responsible for unreffing.
869  *
870  * Returns: (transfer full) (nullable): the plugin with the given name
871  *     or %NULL if the plugin was not found. gst_object_unref() after
872  *     usage.
873  *
874  * MT safe.
875  */
876 GstPlugin *
877 gst_registry_find_plugin (GstRegistry * registry, const gchar * name)
878 {
879   GList *walk;
880   GstPlugin *result = NULL;
881
882   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
883   g_return_val_if_fail (name != NULL, NULL);
884
885   walk = gst_registry_plugin_filter (registry,
886       (GstPluginFilter) gst_registry_plugin_name_filter, TRUE, (gpointer) name);
887   if (walk) {
888     result = GST_PLUGIN_CAST (walk->data);
889
890     gst_object_ref (result);
891     gst_plugin_list_free (walk);
892   }
893
894   return result;
895 }
896
897 /**
898  * gst_registry_find_feature:
899  * @registry: the registry to search
900  * @name: the pluginfeature name to find
901  * @type: the pluginfeature type to find
902  *
903  * Find the pluginfeature with the given name and type in the registry.
904  *
905  * Returns: (transfer full) (nullable): the pluginfeature with the
906  *     given name and type or %NULL if the plugin was not
907  *     found. gst_object_unref() after usage.
908  *
909  * MT safe.
910  */
911 GstPluginFeature *
912 gst_registry_find_feature (GstRegistry * registry, const gchar * name,
913     GType type)
914 {
915   GstPluginFeature *feature = NULL;
916
917   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
918   g_return_val_if_fail (name != NULL, NULL);
919   g_return_val_if_fail (g_type_is_a (type, GST_TYPE_PLUGIN_FEATURE), NULL);
920
921   feature = gst_registry_lookup_feature (registry, name);
922   if (feature && !g_type_is_a (G_TYPE_FROM_INSTANCE (feature), type)) {
923     gst_object_unref (feature);
924     feature = NULL;
925   }
926
927   return feature;
928 }
929
930 /**
931  * gst_registry_get_feature_list:
932  * @registry: a #GstRegistry
933  * @type: a #GType.
934  *
935  * Retrieves a #GList of #GstPluginFeature of @type.
936  *
937  * Returns: (transfer full) (element-type Gst.PluginFeature): a #GList of
938  *     #GstPluginFeature of @type. Use gst_plugin_feature_list_free() after use
939  *
940  * MT safe.
941  */
942 GList *
943 gst_registry_get_feature_list (GstRegistry * registry, GType type)
944 {
945   GstTypeNameData data;
946
947   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
948   g_return_val_if_fail (g_type_is_a (type, GST_TYPE_PLUGIN_FEATURE), NULL);
949
950   /* Speed up */
951   if (type == GST_TYPE_ELEMENT_FACTORY)
952     return gst_registry_get_element_factory_list (registry);
953   else if (type == GST_TYPE_TYPE_FIND_FACTORY)
954     return gst_registry_get_typefind_factory_list (registry);
955   else if (type == GST_TYPE_DEVICE_PROVIDER_FACTORY)
956     return gst_registry_get_device_provider_factory_list (registry);
957
958   data.type = type;
959   data.name = NULL;
960
961   return gst_registry_feature_filter (registry,
962       (GstPluginFeatureFilter) gst_plugin_feature_type_name_filter,
963       FALSE, &data);
964 }
965
966 /**
967  * gst_registry_get_plugin_list:
968  * @registry: the registry to search
969  *
970  * Get a copy of all plugins registered in the given registry. The refcount
971  * of each element in the list in incremented.
972  *
973  * Returns: (transfer full) (element-type Gst.Plugin): a #GList of #GstPlugin.
974  *     Use gst_plugin_list_free() after usage.
975  *
976  * MT safe.
977  */
978 GList *
979 gst_registry_get_plugin_list (GstRegistry * registry)
980 {
981   GList *list;
982   GList *g;
983
984   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
985
986   GST_OBJECT_LOCK (registry);
987   list = g_list_copy (registry->priv->plugins);
988   for (g = list; g; g = g->next) {
989     gst_object_ref (GST_PLUGIN_CAST (g->data));
990   }
991   GST_OBJECT_UNLOCK (registry);
992
993   return list;
994 }
995
996 static GstPluginFeature *
997 gst_registry_lookup_feature_locked (GstRegistry * registry, const char *name)
998 {
999   return g_hash_table_lookup (registry->priv->feature_hash, name);
1000 }
1001
1002 /**
1003  * gst_registry_lookup_feature:
1004  * @registry: a #GstRegistry
1005  * @name: a #GstPluginFeature name
1006  *
1007  * Find a #GstPluginFeature with @name in @registry.
1008  *
1009  * Returns: (transfer full): a #GstPluginFeature with its refcount incremented,
1010  *     use gst_object_unref() after usage.
1011  *
1012  * MT safe.
1013  */
1014 GstPluginFeature *
1015 gst_registry_lookup_feature (GstRegistry * registry, const char *name)
1016 {
1017   GstPluginFeature *feature;
1018
1019   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
1020   g_return_val_if_fail (name != NULL, NULL);
1021
1022   GST_OBJECT_LOCK (registry);
1023   feature = gst_registry_lookup_feature_locked (registry, name);
1024   if (feature)
1025     gst_object_ref (feature);
1026   GST_OBJECT_UNLOCK (registry);
1027
1028   return feature;
1029 }
1030
1031 static GstPlugin *
1032 gst_registry_lookup_bn_locked (GstRegistry * registry, const char *basename)
1033 {
1034   return g_hash_table_lookup (registry->priv->basename_hash, basename);
1035 }
1036
1037 static GstPlugin *
1038 gst_registry_lookup_bn (GstRegistry * registry, const char *basename)
1039 {
1040   GstPlugin *plugin;
1041
1042   GST_OBJECT_LOCK (registry);
1043   plugin = gst_registry_lookup_bn_locked (registry, basename);
1044   if (plugin)
1045     gst_object_ref (plugin);
1046   GST_OBJECT_UNLOCK (registry);
1047
1048   return plugin;
1049 }
1050
1051 /**
1052  * gst_registry_lookup:
1053  * @registry: the registry to look up in
1054  * @filename: the name of the file to look up
1055  *
1056  * Look up a plugin in the given registry with the given filename.
1057  * If found, plugin is reffed.
1058  *
1059  * Returns: (transfer full) (nullable): the #GstPlugin if found, or
1060  *     %NULL if not.  gst_object_unref() after usage.
1061  */
1062 GstPlugin *
1063 gst_registry_lookup (GstRegistry * registry, const char *filename)
1064 {
1065   GstPlugin *plugin;
1066   gchar *basename;
1067
1068   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
1069   g_return_val_if_fail (filename != NULL, NULL);
1070
1071   basename = g_path_get_basename (filename);
1072   if (G_UNLIKELY (basename == NULL))
1073     return NULL;
1074
1075   plugin = gst_registry_lookup_bn (registry, basename);
1076
1077   g_free (basename);
1078
1079   return plugin;
1080 }
1081
1082 typedef enum
1083 {
1084   REGISTRY_SCAN_HELPER_NOT_STARTED = 0,
1085   REGISTRY_SCAN_HELPER_DISABLED,
1086   REGISTRY_SCAN_HELPER_RUNNING
1087 } GstRegistryScanHelperState;
1088
1089 typedef struct
1090 {
1091   GstRegistry *registry;
1092   GstRegistryScanHelperState helper_state;
1093   GstPluginLoader *helper;
1094   gboolean changed;
1095 } GstRegistryScanContext;
1096
1097 static void
1098 init_scan_context (GstRegistryScanContext * context, GstRegistry * registry)
1099 {
1100   gboolean do_fork;
1101
1102   context->registry = registry;
1103
1104   /* see if forking is enabled and set up the scan helper state accordingly */
1105   do_fork = _gst_enable_registry_fork;
1106   if (do_fork) {
1107     const gchar *fork_env;
1108
1109     /* forking enabled, see if it is disabled with an env var */
1110     if ((fork_env = g_getenv ("GST_REGISTRY_FORK"))) {
1111       /* fork enabled for any value different from "no" */
1112       do_fork = strcmp (fork_env, "no") != 0;
1113     }
1114   }
1115
1116   if (do_fork)
1117     context->helper_state = REGISTRY_SCAN_HELPER_NOT_STARTED;
1118   else
1119     context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
1120
1121   context->helper = NULL;
1122   context->changed = FALSE;
1123 }
1124
1125 static void
1126 clear_scan_context (GstRegistryScanContext * context)
1127 {
1128   if (context->helper) {
1129     context->changed |= _priv_gst_plugin_loader_funcs.destroy (context->helper);
1130     context->helper = NULL;
1131   }
1132 }
1133
1134 static gboolean
1135 gst_registry_scan_plugin_file (GstRegistryScanContext * context,
1136     const gchar * filename, off_t file_size, time_t file_mtime)
1137 {
1138   gboolean changed = FALSE;
1139   GstPlugin *newplugin = NULL;
1140
1141 #ifdef G_OS_WIN32
1142   /* Disable external plugin loader on Windows until it is ported properly. */
1143   context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
1144 #endif
1145
1146
1147   /* Have a plugin to load - see if the scan-helper needs starting */
1148   if (context->helper_state == REGISTRY_SCAN_HELPER_NOT_STARTED) {
1149     GST_DEBUG ("Starting plugin scanner for file %s", filename);
1150     context->helper = _priv_gst_plugin_loader_funcs.create (context->registry);
1151     if (context->helper != NULL)
1152       context->helper_state = REGISTRY_SCAN_HELPER_RUNNING;
1153     else {
1154       GST_WARNING ("Failed starting plugin scanner. Scanning in-process");
1155       context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
1156     }
1157   }
1158
1159   if (context->helper_state == REGISTRY_SCAN_HELPER_RUNNING) {
1160     GST_DEBUG ("Using scan-helper to load plugin %s", filename);
1161     if (!_priv_gst_plugin_loader_funcs.load (context->helper,
1162             filename, file_size, file_mtime)) {
1163       g_warning ("External plugin loader failed. This most likely means that "
1164           "the plugin loader helper binary was not found or could not be run. "
1165           "You might need to set the GST_PLUGIN_SCANNER environment variable "
1166           "if your setup is unusual. This should normally not be required "
1167           "though.");
1168       context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
1169     }
1170   }
1171
1172   /* Check if the helper is disabled (or just got disabled above) */
1173   if (context->helper_state == REGISTRY_SCAN_HELPER_DISABLED) {
1174     /* Load plugin the old fashioned way... */
1175
1176     /* We don't use a GError here because a failure to load some shared
1177      * objects as plugins is normal (particularly in the uninstalled case)
1178      */
1179     newplugin = _priv_gst_plugin_load_file_for_registry (filename,
1180         context->registry, NULL);
1181   }
1182
1183   if (newplugin) {
1184     GST_DEBUG_OBJECT (context->registry, "marking new plugin %p as registered",
1185         newplugin);
1186     newplugin->registered = TRUE;
1187     gst_object_unref (newplugin);
1188     changed = TRUE;
1189   }
1190 #ifndef GST_DISABLE_REGISTRY
1191   if (!__registry_reuse_plugin_scanner) {
1192     clear_scan_context (context);
1193     context->helper_state = REGISTRY_SCAN_HELPER_NOT_STARTED;
1194   }
1195 #endif
1196
1197   return changed;
1198 }
1199
1200 static gboolean
1201 is_blacklisted_hidden_directory (const gchar * dirent)
1202 {
1203   if (G_LIKELY (dirent[0] != '.'))
1204     return FALSE;
1205
1206   /* skip the .debug directory, these contain elf files that are not
1207    * useful or worse, can crash dlopen () */
1208   if (strcmp (dirent, ".debug") == 0)
1209     return TRUE;
1210
1211   /* can also skip .git and .deps dirs, those won't contain useful files.
1212    * This speeds up scanning a bit in uninstalled setups. */
1213   if (strcmp (dirent, ".git") == 0 || strcmp (dirent, ".deps") == 0)
1214     return TRUE;
1215
1216   return FALSE;
1217 }
1218
1219 static gboolean
1220 gst_registry_scan_path_level (GstRegistryScanContext * context,
1221     const gchar * path, int level)
1222 {
1223   GDir *dir;
1224   const gchar *dirent;
1225   gchar *filename;
1226   GstPlugin *plugin;
1227   gboolean changed = FALSE;
1228
1229   dir = g_dir_open (path, 0, NULL);
1230   if (!dir)
1231     return FALSE;
1232
1233   while ((dirent = g_dir_read_name (dir))) {
1234     GStatBuf file_status;
1235
1236     filename = g_build_filename (path, dirent, NULL);
1237     if (g_stat (filename, &file_status) < 0) {
1238       /* Plugin will be removed from cache after the scan completes if it
1239        * is still marked 'cached' */
1240       g_free (filename);
1241       continue;
1242     }
1243
1244     if (file_status.st_mode & S_IFDIR) {
1245       if (G_UNLIKELY (is_blacklisted_hidden_directory (dirent))) {
1246         GST_TRACE_OBJECT (context->registry, "ignoring %s directory", dirent);
1247         g_free (filename);
1248         continue;
1249       }
1250       /* FIXME 2.0: Don't recurse into directories, this behaviour
1251        * is inconsistent with other PATH environment variables
1252        */
1253       if (level > 0) {
1254         GST_LOG_OBJECT (context->registry, "recursing into directory %s",
1255             filename);
1256         changed |= gst_registry_scan_path_level (context, filename, level - 1);
1257       } else {
1258         GST_LOG_OBJECT (context->registry, "not recursing into directory %s, "
1259             "recursion level too deep", filename);
1260       }
1261       g_free (filename);
1262       continue;
1263     }
1264     if (!(file_status.st_mode & S_IFREG)) {
1265       GST_TRACE_OBJECT (context->registry, "%s is not a regular file, ignoring",
1266           filename);
1267       g_free (filename);
1268       continue;
1269     }
1270     if (!g_str_has_suffix (dirent, "." G_MODULE_SUFFIX)
1271 #ifdef GST_EXTRA_MODULE_SUFFIX
1272         && !g_str_has_suffix (dirent, GST_EXTRA_MODULE_SUFFIX)
1273 #endif
1274         ) {
1275       GST_TRACE_OBJECT (context->registry,
1276           "extension is not recognized as module file, ignoring file %s",
1277           filename);
1278       g_free (filename);
1279       continue;
1280     }
1281
1282     GST_LOG_OBJECT (context->registry, "file %s looks like a possible module",
1283         filename);
1284
1285     /* try to avoid unnecessary plugin-move pain */
1286     if (g_str_has_prefix (dirent, "libgstvalve") ||
1287         g_str_has_prefix (dirent, "libgstselector")) {
1288       GST_WARNING_OBJECT (context->registry, "ignoring old plugin %s which "
1289           "has been merged into the corelements plugin", filename);
1290       /* Plugin will be removed from cache after the scan completes if it
1291        * is still marked 'cached' */
1292       g_free (filename);
1293       continue;
1294     }
1295
1296     /* plug-ins are considered unique by basename; if the given name
1297      * was already seen by the registry, we ignore it */
1298     plugin = gst_registry_lookup_bn (context->registry, dirent);
1299     if (plugin) {
1300       gboolean env_vars_changed, deps_changed = FALSE;
1301
1302       if (plugin->registered) {
1303         GST_DEBUG_OBJECT (context->registry,
1304             "plugin already registered from path \"%s\"",
1305             GST_STR_NULL (plugin->filename));
1306         g_free (filename);
1307         gst_object_unref (plugin);
1308         continue;
1309       }
1310
1311       env_vars_changed = _priv_plugin_deps_env_vars_changed (plugin);
1312
1313       /* If a file with a certain basename is seen on a different path,
1314        * update the plugin to ensure the registry cache will reflect up
1315        * to date information */
1316
1317       if (plugin->file_mtime == file_status.st_mtime &&
1318           plugin->file_size == file_status.st_size && !env_vars_changed &&
1319           !(deps_changed = _priv_plugin_deps_files_changed (plugin)) &&
1320           !strcmp (plugin->filename, filename)) {
1321         GST_LOG_OBJECT (context->registry, "file %s cached", filename);
1322         GST_OBJECT_FLAG_UNSET (plugin, GST_PLUGIN_FLAG_CACHED);
1323         GST_LOG_OBJECT (context->registry,
1324             "marking plugin %p as registered as %s", plugin, filename);
1325         plugin->registered = TRUE;
1326       } else {
1327         GST_INFO_OBJECT (context->registry, "cached info for %s is stale",
1328             filename);
1329         GST_DEBUG_OBJECT (context->registry, "mtime %" G_GINT64_FORMAT " != %"
1330             G_GINT64_FORMAT " or size %" G_GINT64_FORMAT " != %"
1331             G_GINT64_FORMAT " or external dependency env_vars changed: %d or"
1332             " external dependencies changed: %d or old path %s != new path %s",
1333             (gint64) plugin->file_mtime, (gint64) file_status.st_mtime,
1334             (gint64) plugin->file_size, (gint64) file_status.st_size,
1335             env_vars_changed, deps_changed, plugin->filename, filename);
1336         gst_registry_remove_plugin (context->registry, plugin);
1337         changed |= gst_registry_scan_plugin_file (context, filename,
1338             file_status.st_size, file_status.st_mtime);
1339       }
1340       gst_object_unref (plugin);
1341
1342     } else {
1343       GST_DEBUG_OBJECT (context->registry, "file %s not yet in registry",
1344           filename);
1345       changed |= gst_registry_scan_plugin_file (context, filename,
1346           file_status.st_size, file_status.st_mtime);
1347     }
1348
1349     g_free (filename);
1350   }
1351
1352   g_dir_close (dir);
1353
1354   return changed;
1355 }
1356
1357 static gboolean
1358 gst_registry_scan_path_internal (GstRegistryScanContext * context,
1359     const gchar * path)
1360 {
1361   gboolean changed;
1362
1363   GST_DEBUG_OBJECT (context->registry, "scanning path %s", path);
1364   changed = gst_registry_scan_path_level (context, path, 10);
1365
1366   GST_DEBUG_OBJECT (context->registry, "registry changed in path %s: %d", path,
1367       changed);
1368   return changed;
1369 }
1370
1371 /**
1372  * gst_registry_scan_path:
1373  * @registry: the registry to add found plugins to
1374  * @path: the path to scan
1375  *
1376  * Scan the given path for plugins to add to the registry. The syntax of the
1377  * path is specific to the registry.
1378  *
1379  * Returns: %TRUE if registry changed
1380  */
1381 gboolean
1382 gst_registry_scan_path (GstRegistry * registry, const gchar * path)
1383 {
1384   GstRegistryScanContext context;
1385   gboolean result;
1386
1387   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
1388   g_return_val_if_fail (path != NULL, FALSE);
1389
1390   init_scan_context (&context, registry);
1391
1392   result = gst_registry_scan_path_internal (&context, path);
1393
1394   clear_scan_context (&context);
1395   result |= context.changed;
1396
1397   return result;
1398 }
1399
1400 static gboolean
1401 _gst_plugin_feature_filter_plugin_name (GstPluginFeature * feature,
1402     gpointer user_data)
1403 {
1404   return (strcmp (feature->plugin_name, (gchar *) user_data) == 0);
1405 }
1406
1407 /**
1408  * gst_registry_get_feature_list_by_plugin:
1409  * @registry: a #GstRegistry.
1410  * @name: a plugin name.
1411  *
1412  * Retrieves a #GList of features of the plugin with name @name.
1413  *
1414  * Returns: (transfer full) (element-type Gst.PluginFeature): a #GList of
1415  *     #GstPluginFeature. Use gst_plugin_feature_list_free() after usage.
1416  */
1417 GList *
1418 gst_registry_get_feature_list_by_plugin (GstRegistry * registry,
1419     const gchar * name)
1420 {
1421   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
1422   g_return_val_if_fail (name != NULL, NULL);
1423
1424   return gst_registry_feature_filter (registry,
1425       _gst_plugin_feature_filter_plugin_name, FALSE, (gpointer) name);
1426 }
1427
1428 /* Unref and delete the default registry */
1429 void
1430 _priv_gst_registry_cleanup (void)
1431 {
1432   GstRegistry *registry;
1433
1434   g_mutex_lock (&_gst_registry_mutex);
1435   if ((registry = _gst_registry_default) != NULL) {
1436     _gst_registry_default = NULL;
1437   }
1438   g_mutex_unlock (&_gst_registry_mutex);
1439
1440   /* unref outside of the lock because we can. */
1441   if (registry)
1442     gst_object_unref (registry);
1443 }
1444
1445 /**
1446  * gst_registry_check_feature_version:
1447  * @registry: a #GstRegistry
1448  * @feature_name: the name of the feature (e.g. "oggdemux")
1449  * @min_major: the minimum major version number
1450  * @min_minor: the minimum minor version number
1451  * @min_micro: the minimum micro version number
1452  *
1453  * Checks whether a plugin feature by the given name exists in
1454  * @registry and whether its version is at least the
1455  * version required.
1456  *
1457  * Returns: %TRUE if the feature could be found and the version is
1458  * the same as the required version or newer, and %FALSE otherwise.
1459  */
1460 gboolean
1461 gst_registry_check_feature_version (GstRegistry * registry,
1462     const gchar * feature_name, guint min_major, guint min_minor,
1463     guint min_micro)
1464 {
1465   GstPluginFeature *feature;
1466   gboolean ret = FALSE;
1467
1468   g_return_val_if_fail (feature_name != NULL, FALSE);
1469
1470   GST_DEBUG ("Looking up plugin feature '%s'", feature_name);
1471
1472   feature = gst_registry_lookup_feature (registry, feature_name);
1473   if (feature) {
1474     ret = gst_plugin_feature_check_version (feature, min_major, min_minor,
1475         min_micro);
1476     gst_object_unref (feature);
1477   } else {
1478     GST_DEBUG ("Could not find plugin feature '%s'", feature_name);
1479   }
1480
1481   return ret;
1482 }
1483
1484 static void
1485 load_plugin_func (gpointer data, gpointer user_data)
1486 {
1487   GstPlugin *plugin;
1488   const gchar *filename;
1489   GError *err = NULL;
1490
1491   filename = (const gchar *) data;
1492   GST_DEBUG ("Pre-loading plugin %s", filename);
1493
1494   plugin = gst_plugin_load_file (filename, &err);
1495
1496   if (plugin) {
1497     GST_INFO ("Loaded plugin: \"%s\"", filename);
1498
1499     gst_registry_add_plugin (gst_registry_get (), plugin);
1500   } else {
1501     if (err) {
1502       /* Report error to user, and free error */
1503       GST_ERROR ("Failed to load plugin: %s", err->message);
1504       g_error_free (err);
1505     } else {
1506       GST_WARNING ("Failed to load plugin: \"%s\"", filename);
1507     }
1508   }
1509 }
1510
1511 #ifndef GST_DISABLE_REGISTRY
1512 /* Unref all plugins marked 'cached', to clear old plugins that no
1513  * longer exist. Returns %TRUE if any plugins were removed */
1514 static gboolean
1515 gst_registry_remove_cache_plugins (GstRegistry * registry)
1516 {
1517   GList *g;
1518   GList *g_next;
1519   GstPlugin *plugin;
1520   gboolean changed = FALSE;
1521
1522   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
1523
1524   GST_OBJECT_LOCK (registry);
1525
1526   GST_DEBUG_OBJECT (registry, "removing cached plugins");
1527   g = registry->priv->plugins;
1528   while (g) {
1529     g_next = g->next;
1530     plugin = g->data;
1531     if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_CACHED)) {
1532       GST_DEBUG_OBJECT (registry, "removing cached plugin \"%s\"",
1533           GST_STR_NULL (plugin->filename));
1534       registry->priv->plugins = g_list_delete_link (registry->priv->plugins, g);
1535       --registry->priv->n_plugins;
1536       if (G_LIKELY (plugin->basename))
1537         g_hash_table_remove (registry->priv->basename_hash, plugin->basename);
1538       gst_registry_remove_features_for_plugin_unlocked (registry, plugin);
1539       gst_object_unref (plugin);
1540       changed = TRUE;
1541     }
1542     g = g_next;
1543   }
1544
1545   GST_OBJECT_UNLOCK (registry);
1546
1547   return changed;
1548 }
1549
1550 typedef enum
1551 {
1552   REGISTRY_SCAN_AND_UPDATE_FAILURE = 0,
1553   REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED,
1554   REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED
1555 } GstRegistryScanAndUpdateResult;
1556
1557 /*
1558  * scan_and_update_registry:
1559  * @default_registry: the #GstRegistry
1560  * @registry_file: registry filename
1561  * @write_changes: write registry if it has changed?
1562  *
1563  * Scans for registry changes and eventually updates the registry cache.
1564  *
1565  * Return: %REGISTRY_SCAN_AND_UPDATE_FAILURE if the registry could not scanned
1566  *         or updated, %REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED if the
1567  *         registry is clean and %REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED if
1568  *         it has been updated and the cache needs to be re-read.
1569  */
1570 static GstRegistryScanAndUpdateResult
1571 scan_and_update_registry (GstRegistry * default_registry,
1572     const gchar * registry_file, gboolean write_changes, GError ** error)
1573 {
1574   const gchar *plugin_path;
1575   gboolean changed = FALSE;
1576   GList *l;
1577   GstRegistryScanContext context;
1578
1579   GST_INFO ("Validating plugins from registry cache: %s", registry_file);
1580
1581   init_scan_context (&context, default_registry);
1582
1583   /* It sounds tempting to just compare the mtime of directories with the mtime
1584    * of the registry cache, but it does not work. It would not catch updated
1585    * plugins, which might bring more or less features.
1586    */
1587
1588   /* scan paths specified via --gst-plugin-path */
1589   GST_DEBUG ("scanning paths added via --gst-plugin-path");
1590   for (l = _priv_gst_plugin_paths; l != NULL; l = l->next) {
1591     GST_INFO ("Scanning plugin path: \"%s\"", (gchar *) l->data);
1592     changed |= gst_registry_scan_path_internal (&context, (gchar *) l->data);
1593   }
1594   /* keep plugin_paths around in case a re-scan is forced later on */
1595
1596   /* GST_PLUGIN_PATH specifies a list of directories to scan for
1597    * additional plugins.  These take precedence over the system plugins */
1598   plugin_path = g_getenv ("GST_PLUGIN_PATH_1_0");
1599   if (plugin_path == NULL)
1600     plugin_path = g_getenv ("GST_PLUGIN_PATH");
1601   if (plugin_path) {
1602     char **list;
1603     int i;
1604
1605     GST_DEBUG ("GST_PLUGIN_PATH set to %s", plugin_path);
1606     list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
1607     for (i = 0; list[i]; i++) {
1608       changed |= gst_registry_scan_path_internal (&context, list[i]);
1609     }
1610     g_strfreev (list);
1611   } else {
1612     GST_DEBUG ("GST_PLUGIN_PATH not set");
1613   }
1614
1615   /* GST_PLUGIN_SYSTEM_PATH specifies a list of plugins that are always
1616    * loaded by default.  If not set, this defaults to the system-installed
1617    * path, and the plugins installed in the user's home directory */
1618   plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH_1_0");
1619   if (plugin_path == NULL)
1620     plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH");
1621   if (plugin_path == NULL) {
1622     char *home_plugins;
1623
1624     GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH not set");
1625
1626     /* plugins in the user's home directory take precedence over
1627      * system-installed ones */
1628     home_plugins = g_build_filename (g_get_user_data_dir (),
1629         "gstreamer-" GST_API_VERSION, "plugins", NULL);
1630
1631     GST_DEBUG ("scanning home plugins %s", home_plugins);
1632     changed |= gst_registry_scan_path_internal (&context, home_plugins);
1633     g_free (home_plugins);
1634
1635     /* add the main (installed) library path */
1636
1637 #ifdef G_OS_WIN32
1638     {
1639       char *base_dir;
1640       char *dir;
1641
1642       base_dir =
1643           g_win32_get_package_installation_directory_of_module
1644           (_priv_gst_dll_handle);
1645
1646       dir = g_build_filename (base_dir,
1647 #ifdef _DEBUG
1648           "debug"
1649 #endif
1650           "lib", "gstreamer-" GST_API_VERSION, NULL);
1651       GST_DEBUG ("scanning DLL dir %s", dir);
1652
1653       changed |= gst_registry_scan_path_internal (&context, dir);
1654
1655       g_free (dir);
1656       g_free (base_dir);
1657     }
1658 #else
1659     GST_DEBUG ("scanning main plugins %s", PLUGINDIR);
1660     changed |= gst_registry_scan_path_internal (&context, PLUGINDIR);
1661 #endif
1662   } else {
1663     gchar **list;
1664     gint i;
1665
1666     GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH set to %s", plugin_path);
1667     list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
1668     for (i = 0; list[i]; i++) {
1669       changed |= gst_registry_scan_path_internal (&context, list[i]);
1670     }
1671     g_strfreev (list);
1672   }
1673
1674   clear_scan_context (&context);
1675   changed |= context.changed;
1676
1677   /* Remove cached plugins so stale info is cleared. */
1678   changed |= gst_registry_remove_cache_plugins (default_registry);
1679
1680   if (!changed) {
1681     GST_INFO ("Registry cache has not changed");
1682     return REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED;
1683   }
1684
1685   if (!write_changes) {
1686     GST_INFO ("Registry cache changed, but writing is disabled. Not writing.");
1687     return REGISTRY_SCAN_AND_UPDATE_FAILURE;
1688   }
1689
1690   GST_INFO ("Registry cache changed. Writing new registry cache");
1691   if (!priv_gst_registry_binary_write_cache (default_registry,
1692           default_registry->priv->plugins, registry_file)) {
1693     g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
1694         _("Error writing registry cache to %s: %s"),
1695         registry_file, g_strerror (errno));
1696     return REGISTRY_SCAN_AND_UPDATE_FAILURE;
1697   }
1698
1699   GST_INFO ("Registry cache written successfully");
1700   return REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED;
1701 }
1702
1703 static gboolean
1704 ensure_current_registry (GError ** error)
1705 {
1706   gchar *registry_file;
1707   GstRegistry *default_registry;
1708   gboolean ret = TRUE;
1709   gboolean do_update = TRUE;
1710   gboolean have_cache = TRUE;
1711
1712   default_registry = gst_registry_get ();
1713
1714   registry_file = g_strdup (g_getenv ("GST_REGISTRY_1_0"));
1715   if (registry_file == NULL)
1716     registry_file = g_strdup (g_getenv ("GST_REGISTRY"));
1717   if (registry_file == NULL) {
1718     registry_file = g_build_filename (g_get_user_cache_dir (),
1719         "gstreamer-" GST_API_VERSION, "registry." TARGET_CPU ".bin", NULL);
1720   }
1721
1722   if (!_gst_disable_registry_cache) {
1723     GST_INFO ("reading registry cache: %s", registry_file);
1724     have_cache = priv_gst_registry_binary_read_cache (default_registry,
1725         registry_file);
1726     /* Only ever read the registry cache once, then disable it for
1727      * subsequent updates during the program lifetime */
1728     _gst_disable_registry_cache = TRUE;
1729   }
1730
1731   if (have_cache) {
1732     do_update = !_priv_gst_disable_registry_update;
1733     if (do_update) {
1734       const gchar *update_env;
1735
1736       if ((update_env = g_getenv ("GST_REGISTRY_UPDATE"))) {
1737         /* do update for any value different from "no" */
1738         do_update = (strcmp (update_env, "no") != 0);
1739       }
1740     }
1741   }
1742
1743   if (do_update) {
1744     const gchar *reuse_env;
1745
1746     if ((reuse_env = g_getenv ("GST_REGISTRY_REUSE_PLUGIN_SCANNER"))) {
1747       /* do reuse for any value different from "no" */
1748       __registry_reuse_plugin_scanner = (strcmp (reuse_env, "no") != 0);
1749     }
1750     /* now check registry */
1751     GST_DEBUG ("Updating registry cache");
1752     scan_and_update_registry (default_registry, registry_file, TRUE, error);
1753   } else {
1754     GST_DEBUG ("Not updating registry cache (disabled)");
1755   }
1756
1757   g_free (registry_file);
1758   GST_INFO ("registry reading and updating done, result = %d", ret);
1759
1760   return ret;
1761 }
1762 #endif /* GST_DISABLE_REGISTRY */
1763
1764 /**
1765  * gst_registry_fork_is_enabled:
1766  *
1767  * By default GStreamer will perform scanning and rebuilding of the
1768  * registry file using a helper child process.
1769  *
1770  * Applications might want to disable this behaviour with the
1771  * gst_registry_fork_set_enabled() function, in which case new plugins
1772  * are scanned (and loaded) into the application process.
1773  *
1774  * Returns: %TRUE if GStreamer will use the child helper process when
1775  * rebuilding the registry.
1776  */
1777 gboolean
1778 gst_registry_fork_is_enabled (void)
1779 {
1780   return _gst_enable_registry_fork;
1781 }
1782
1783 /**
1784  * gst_registry_fork_set_enabled:
1785  * @enabled: whether rebuilding the registry can use a temporary child helper process.
1786  *
1787  * Applications might want to disable/enable spawning of a child helper process
1788  * when rebuilding the registry. See gst_registry_fork_is_enabled() for more
1789  * information.
1790  */
1791 void
1792 gst_registry_fork_set_enabled (gboolean enabled)
1793 {
1794   _gst_enable_registry_fork = enabled;
1795 }
1796
1797 /**
1798  * gst_update_registry:
1799  *
1800  * Forces GStreamer to re-scan its plugin paths and update the default
1801  * plugin registry.
1802  *
1803  * Applications will almost never need to call this function, it is only
1804  * useful if the application knows new plugins have been installed (or old
1805  * ones removed) since the start of the application (or, to be precise, the
1806  * first call to gst_init()) and the application wants to make use of any
1807  * newly-installed plugins without restarting the application.
1808  *
1809  * Applications should assume that the registry update is neither atomic nor
1810  * thread-safe and should therefore not have any dynamic pipelines running
1811  * (including the playbin and decodebin elements) and should also not create
1812  * any elements or access the GStreamer registry while the update is in
1813  * progress.
1814  *
1815  * Note that this function may block for a significant amount of time.
1816  *
1817  * Returns: %TRUE if the registry has been updated successfully (does not
1818  *          imply that there were changes), otherwise %FALSE.
1819  */
1820 gboolean
1821 gst_update_registry (void)
1822 {
1823   gboolean res;
1824
1825 #ifndef GST_DISABLE_REGISTRY
1826   if (!_priv_gst_disable_registry) {
1827     GError *err = NULL;
1828
1829     res = ensure_current_registry (&err);
1830     if (err) {
1831       GST_WARNING ("registry update failed: %s", err->message);
1832       g_error_free (err);
1833     } else {
1834       GST_LOG ("registry update succeeded");
1835     }
1836   } else {
1837     GST_INFO ("registry update disabled by environment");
1838     res = TRUE;
1839   }
1840
1841 #else
1842   GST_WARNING ("registry update failed: %s", "registry disabled");
1843   res = TRUE;
1844 #endif /* GST_DISABLE_REGISTRY */
1845
1846   if (_priv_gst_preload_plugins) {
1847     GST_DEBUG ("Preloading indicated plugins...");
1848     g_slist_foreach (_priv_gst_preload_plugins, load_plugin_func, NULL);
1849   }
1850
1851   return res;
1852 }
1853
1854 /**
1855  * gst_registry_get_feature_list_cookie:
1856  * @registry: the registry
1857  *
1858  * Returns the registry's feature list cookie. This changes
1859  * every time a feature is added or removed from the registry.
1860  *
1861  * Returns: the feature list cookie.
1862  */
1863 guint32
1864 gst_registry_get_feature_list_cookie (GstRegistry * registry)
1865 {
1866   g_return_val_if_fail (GST_IS_REGISTRY (registry), 0);
1867
1868   return registry->priv->cookie;
1869 }