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