Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst / gstregistry.c
index 5b6df92..3e843c8 100644 (file)
@@ -46,7 +46,7 @@
  * means of doing so is to load every plugin and look at the resulting
  * information that is gathered in the default registry. Clearly, this is a time
  * consuming process, so we cache information in the registry file. The format
- * and location of the cache file is internal to gstreamer. 
+ * and location of the cache file is internal to gstreamer.
  *
  * On startup, plugins are searched for in the plugin search path. The following
  * locations are checked in this order:
  * different sets of plugins. For various reasons, at init time, the cache is
  * stored in the default registry, and plugins not relevant to the current
  * process are marked with the %GST_PLUGIN_FLAG_CACHED bit. These plugins are
- * removed at the end of intitialization.
+ * removed at the end of initialization.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "gsterror.h"
 #include "gstregistry.h"
 #include "gstmarshal.h"
-#include "gstfilter.h"
 
 #include "gstpluginloader.h"
 
@@ -175,6 +174,8 @@ extern GList *_priv_gst_plugin_paths;
 
 /* Set to TRUE when the registry cache should be disabled */
 gboolean _gst_disable_registry_cache = FALSE;
+
+static gboolean __registry_reuse_plugin_scanner = TRUE;
 #endif
 
 /* Element signals and args */
@@ -194,8 +195,8 @@ static GstPluginFeature *gst_registry_lookup_feature_locked (GstRegistry *
 static GstPlugin *gst_registry_lookup_bn_locked (GstRegistry * registry,
     const char *basename);
 
+#define gst_registry_parent_class parent_class
 G_DEFINE_TYPE (GstRegistry, gst_registry, GST_TYPE_OBJECT);
-static GstObjectClass *parent_class = NULL;
 
 static void
 gst_registry_class_init (GstRegistryClass * klass)
@@ -204,7 +205,6 @@ gst_registry_class_init (GstRegistryClass * klass)
 
   gobject_class = (GObjectClass *) klass;
 
-  parent_class = g_type_class_peek_parent (klass);
   g_type_class_add_private (klass, sizeof (GstRegistryPrivate));
 
   /**
@@ -278,9 +278,9 @@ gst_registry_finalize (GObject * object)
     GstPluginFeature *feature = f->data;
 
     if (feature) {
-      GST_LOG_OBJECT (registry, "removing feature %p (%s)",
-          feature, gst_plugin_feature_get_name (feature));
-      gst_object_unref (feature);
+      GST_LOG_OBJECT (registry, "removing feature %p (%s)", feature,
+          GST_OBJECT_NAME (feature));
+      gst_object_unparent (GST_OBJECT_CAST (feature));
     }
     f = g_list_next (f);
   }
@@ -484,8 +484,8 @@ gst_registry_remove_features_for_plugin_unlocked (GstRegistry * registry,
           plugin->desc.name);
 
       registry->features = g_list_delete_link (registry->features, f);
-      g_hash_table_remove (registry->feature_hash, feature->name);
-      gst_object_unref (feature);
+      g_hash_table_remove (registry->feature_hash, GST_OBJECT_NAME (feature));
+      gst_object_unparent (GST_OBJECT_CAST (feature));
     }
     f = next;
   }
@@ -538,38 +538,41 @@ gst_registry_add_feature (GstRegistry * registry, GstPluginFeature * feature)
 
   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
   g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), FALSE);
-  g_return_val_if_fail (feature->name != NULL, FALSE);
+  g_return_val_if_fail (GST_OBJECT_NAME (feature) != NULL, FALSE);
   g_return_val_if_fail (feature->plugin_name != NULL, FALSE);
 
   GST_OBJECT_LOCK (registry);
   existing_feature = gst_registry_lookup_feature_locked (registry,
-      feature->name);
+      GST_OBJECT_NAME (feature));
   if (G_UNLIKELY (existing_feature)) {
     GST_DEBUG_OBJECT (registry, "replacing existing feature %p (%s)",
-        existing_feature, feature->name);
+        existing_feature, GST_OBJECT_NAME (feature));
     /* Remove the existing feature from the list now, before we insert the new
      * one, but don't unref yet because the hash is still storing a reference to
      * it. */
     registry->features = g_list_remove (registry->features, existing_feature);
   }
 
-  GST_DEBUG_OBJECT (registry, "adding feature %p (%s)", feature, feature->name);
+  GST_DEBUG_OBJECT (registry, "adding feature %p (%s)", feature,
+      GST_OBJECT_NAME (feature));
 
   registry->features = g_list_prepend (registry->features, feature);
-  g_hash_table_replace (registry->feature_hash, feature->name, feature);
+  g_hash_table_replace (registry->feature_hash, GST_OBJECT_NAME (feature),
+      feature);
 
   if (G_UNLIKELY (existing_feature)) {
     /* We unref now. No need to remove the feature name from the hash table, it
      * got replaced by the new feature */
-    gst_object_unref (existing_feature);
+    gst_object_unparent (GST_OBJECT_CAST (existing_feature));
   }
 
-  gst_object_ref_sink (feature);
+  gst_object_set_parent (GST_OBJECT_CAST (feature), GST_OBJECT_CAST (registry));
 
   registry->priv->cookie++;
   GST_OBJECT_UNLOCK (registry);
 
-  GST_LOG_OBJECT (registry, "emitting feature-added for %s", feature->name);
+  GST_LOG_OBJECT (registry, "emitting feature-added for %s",
+      GST_OBJECT_NAME (feature));
   g_signal_emit (registry, gst_registry_signals[FEATURE_ADDED], 0, feature);
 
   return TRUE;
@@ -595,10 +598,11 @@ gst_registry_remove_feature (GstRegistry * registry, GstPluginFeature * feature)
 
   GST_OBJECT_LOCK (registry);
   registry->features = g_list_remove (registry->features, feature);
-  g_hash_table_remove (registry->feature_hash, feature->name);
+  g_hash_table_remove (registry->feature_hash, GST_OBJECT_NAME (feature));
   registry->priv->cookie++;
   GST_OBJECT_UNLOCK (registry);
-  gst_object_unref (feature);
+
+  gst_object_unparent ((GstObject *) feature);
 }
 
 /**
@@ -623,22 +627,46 @@ GList *
 gst_registry_plugin_filter (GstRegistry * registry,
     GstPluginFilter filter, gboolean first, gpointer user_data)
 {
-  GList *list;
-  GList *g;
+  GList *list = NULL;
 
   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
 
   GST_OBJECT_LOCK (registry);
-  list = gst_filter_run (registry->plugins, (GstFilterFunc) filter, first,
-      user_data);
-  for (g = list; g; g = g->next) {
-    gst_object_ref (GST_PLUGIN_CAST (g->data));
+  {
+    const GList *walk;
+
+    for (walk = registry->plugins; walk != NULL; walk = walk->next) {
+      GstPlugin *plugin = walk->data;
+
+      if (filter == NULL || filter (plugin, user_data)) {
+        list = g_list_prepend (list, gst_object_ref (plugin));
+
+        if (first)
+          break;
+      }
+    }
   }
   GST_OBJECT_UNLOCK (registry);
 
   return list;
 }
 
+typedef struct
+{
+  const gchar *name;
+  GType type;
+} GstTypeNameData;
+
+static gboolean
+gst_plugin_feature_type_name_filter (GstPluginFeature * feature,
+    GstTypeNameData * data)
+{
+  g_assert (GST_IS_PLUGIN_FEATURE (feature));
+
+  return ((data->type == 0 || data->type == G_OBJECT_TYPE (feature)) &&
+      (data->name == NULL || !strcmp (data->name, GST_OBJECT_NAME (feature))));
+}
+
 /* returns TRUE if the list was changed
  *
  * Must be called with the object lock taken */
@@ -651,16 +679,24 @@ gst_registry_get_feature_list_or_create (GstRegistry * registry,
 
   if (G_UNLIKELY (!*previous || priv->cookie != *cookie)) {
     GstTypeNameData data;
+    const GList *walk;
 
-    if (*previous)
+    if (*previous) {
       gst_plugin_feature_list_free (*previous);
+      *previous = NULL;
+    }
 
     data.type = type;
     data.name = NULL;
-    *previous =
-        gst_filter_run (registry->features,
-        (GstFilterFunc) gst_plugin_feature_type_name_filter, FALSE, &data);
-    g_list_foreach (*previous, (GFunc) gst_object_ref, NULL);
+
+    for (walk = registry->features; walk != NULL; walk = walk->next) {
+      GstPluginFeature *feature = walk->data;
+
+      if (gst_plugin_feature_type_name_filter (feature, &data)) {
+        *previous = g_list_prepend (*previous, gst_object_ref (feature));
+      }
+    }
+
     *cookie = priv->cookie;
     res = TRUE;
   }
@@ -677,7 +713,7 @@ type_find_factory_rank_cmp (const GstPluginFeature * fac1,
 
   /* to make the order in which things happen more deterministic,
    * sort by name when the ranks are the same. */
-  return strcmp (fac1->name, fac2->name);
+  return strcmp (GST_OBJECT_NAME (fac1), GST_OBJECT_NAME (fac2));
 }
 
 static GList *
@@ -742,16 +778,24 @@ GList *
 gst_registry_feature_filter (GstRegistry * registry,
     GstPluginFeatureFilter filter, gboolean first, gpointer user_data)
 {
-  GList *list;
-  GList *g;
+  GList *list = NULL;
 
   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
 
   GST_OBJECT_LOCK (registry);
-  list = gst_filter_run (registry->features, (GstFilterFunc) filter, first,
-      user_data);
-  for (g = list; g; g = g->next) {
-    gst_object_ref (GST_PLUGIN_FEATURE_CAST (g->data));
+  {
+    const GList *walk;
+
+    for (walk = registry->features; walk != NULL; walk = walk->next) {
+      GstPluginFeature *feature = walk->data;
+
+      if (filter == NULL || filter (feature, user_data)) {
+        list = g_list_prepend (list, gst_object_ref (feature));
+
+        if (first)
+          break;
+      }
+    }
   }
   GST_OBJECT_UNLOCK (registry);
 
@@ -1083,6 +1127,11 @@ gst_registry_scan_plugin_file (GstRegistryScanContext * context,
     changed = TRUE;
   }
 
+  if (!__registry_reuse_plugin_scanner) {
+    clear_scan_context (context);
+    context->helper_state = REGISTRY_SCAN_HELPER_NOT_STARTED;
+  }
+
   return changed;
 }
 
@@ -1215,11 +1264,11 @@ gst_registry_scan_path_level (GstRegistryScanContext * context,
       } else {
         GST_INFO_OBJECT (context->registry, "cached info for %s is stale",
             filename);
-        GST_DEBUG_OBJECT (context->registry, "mtime %ld != %ld or size %"
-            G_GINT64_FORMAT " != %" G_GINT64_FORMAT " or external dependency "
-            "env_vars changed: %d or external dependencies changed: %d"
-            " or old path %s != new path %s",
-            plugin->file_mtime, file_status.st_mtime,
+        GST_DEBUG_OBJECT (context->registry, "mtime %" G_GINT64_FORMAT " != %"
+            G_GINT64_FORMAT " or size %" G_GINT64_FORMAT " != %"
+            G_GINT64_FORMAT " or external dependency env_vars changed: %d or"
+            " external dependencies changed: %d or old path %s != new path %s",
+            (gint64) plugin->file_mtime, (gint64) file_status.st_mtime,
             (gint64) plugin->file_size, (gint64) file_status.st_size,
             env_vars_changed, deps_changed, plugin->filename, filename);
         gst_registry_remove_plugin (context->registry, plugin);
@@ -1509,8 +1558,9 @@ scan_and_update_registry (GstRegistry * default_registry,
 
     /* plugins in the user's home directory take precedence over
      * system-installed ones */
-    home_plugins = g_build_filename (g_get_home_dir (),
-        ".gstreamer-" GST_MAJORMINOR, "plugins", NULL);
+    home_plugins = g_build_filename (g_get_user_data_dir (),
+        "gstreamer-" GST_MAJORMINOR, "plugins", NULL);
+
     GST_DEBUG ("scanning home plugins %s", home_plugins);
     changed |= gst_registry_scan_path_internal (&context, home_plugins);
     g_free (home_plugins);
@@ -1566,7 +1616,7 @@ scan_and_update_registry (GstRegistry * default_registry,
   }
 
   GST_INFO ("Registry cache changed. Writing new registry cache");
-  if (!gst_registry_binary_write_cache (default_registry, registry_file)) {
+  if (!priv_gst_registry_binary_write_cache (default_registry, registry_file)) {
     g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
         _("Error writing registry cache to %s: %s"),
         registry_file, g_strerror (errno));
@@ -1589,13 +1639,13 @@ ensure_current_registry (GError ** error)
   default_registry = gst_registry_get_default ();
   registry_file = g_strdup (g_getenv ("GST_REGISTRY"));
   if (registry_file == NULL) {
-    registry_file = g_build_filename (g_get_home_dir (),
-        ".gstreamer-" GST_MAJORMINOR, "registry." HOST_CPU ".bin", NULL);
+    registry_file = g_build_filename (g_get_user_cache_dir (),
+        "gstreamer-" GST_MAJORMINOR, "registry." HOST_CPU ".bin", NULL);
   }
 
   if (!_gst_disable_registry_cache) {
     GST_INFO ("reading registry cache: %s", registry_file);
-    have_cache = gst_registry_binary_read_cache (default_registry,
+    have_cache = priv_gst_registry_binary_read_cache (default_registry,
         registry_file);
     /* Only ever read the registry cache once, then disable it for
      * subsequent updates during the program lifetime */
@@ -1615,6 +1665,12 @@ ensure_current_registry (GError ** error)
   }
 
   if (do_update) {
+    const gchar *reuse_env;
+
+    if ((reuse_env = g_getenv ("GST_REGISTRY_REUSE_PLUGIN_SCANNER"))) {
+      /* do reuse for any value different from "no" */
+      __registry_reuse_plugin_scanner = (strcmp (reuse_env, "no") != 0);
+    }
     /* now check registry */
     GST_DEBUG ("Updating registry cache");
     scan_and_update_registry (default_registry, registry_file, TRUE, error);