gstreamer_core/gst/gstregistry.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
child 29 567bb019e3e3
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     1 /* GStreamer
       
     2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
       
     3  *                    2000 Wim Taymans <wtay@chello.be>
       
     4  *                    2005 David A. Schleef <ds@schleef.org>
       
     5  *
       
     6  * gstregistry.c: handle registry
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Library General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Library General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Library General Public
       
    19  * License along with this library; if not, write to the
       
    20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    21  * Boston, MA 02111-1307, USA.
       
    22  */
       
    23 
       
    24 /**
       
    25  * SECTION:gstregistry
       
    26  * @short_description: Abstract base class for management of #GstPlugin objects
       
    27  * @see_also: #GstPlugin, #GstPluginFeature
       
    28  *
       
    29  * One registry holds the metadata of a set of plugins.
       
    30  * All registries build the #GstRegistryPool.
       
    31  *
       
    32  * <emphasis role="bold">Design:</emphasis>
       
    33  *
       
    34  * The #GstRegistry object is a list of plugins and some functions for dealing
       
    35  * with them. #GstPlugins are matched 1-1 with a file on disk, and may or may
       
    36  * not be loaded at a given time. There may be multiple #GstRegistry objects,
       
    37  * but the "default registry" is the only object that has any meaning to the
       
    38  * core.
       
    39  *
       
    40  * The registry.xml file is actually a cache of plugin information. This is
       
    41  * unlike versions prior to 0.10, where the registry file was the primary source
       
    42  * of plugin information, and was created by the gst-register command.
       
    43  *
       
    44  * The primary source, at all times, of plugin information is each plugin file
       
    45  * itself. Thus, if an application wants information about a particular plugin,
       
    46  * or wants to search for a feature that satisfies given criteria, the primary
       
    47  * means of doing so is to load every plugin and look at the resulting
       
    48  * information that is gathered in the default registry. Clearly, this is a time
       
    49  * consuming process, so we cache information in the registry.xml file.
       
    50  *
       
    51  * On startup, plugins are searched for in the plugin search path. This path can
       
    52  * be set directly using the %GST_PLUGIN_PATH environment variable. The registry
       
    53  * file is loaded from ~/.gstreamer-$GST_MAJORMINOR/registry-$ARCH.xml or the
       
    54  * file listed in the %GST_REGISTRY env var. The only reason to change the
       
    55  * registry location is for testing.
       
    56  *
       
    57  * For each plugin that is found in the plugin search path, there could be 3
       
    58  * possibilities for cached information:
       
    59  * <itemizedlist>
       
    60  *   <listitem>
       
    61  *     <para>the cache may not contain information about a given file.</para>
       
    62  *   </listitem>
       
    63  *   <listitem>
       
    64  *     <para>the cache may have stale information.</para>
       
    65  *   </listitem>
       
    66  *   <listitem>
       
    67  *     <para>the cache may have current information.</para>
       
    68  *   </listitem>
       
    69  * </itemizedlist>
       
    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  * <emphasis role="bold">Implementation notes:</emphasis>
       
    82  *
       
    83  * The "cache" and "default 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 intitialization.
       
    88  */
       
    89 
       
    90 #ifdef HAVE_CONFIG_H
       
    91 #include "config.h"
       
    92 #endif
       
    93 #include "gst_private.h"
       
    94 #include <glib.h>
       
    95 #include <sys/types.h>
       
    96 #include <sys/stat.h>
       
    97 #ifdef HAVE_UNISTD_H
       
    98 #include <unistd.h>
       
    99 #endif
       
   100 #include <errno.h>
       
   101 #include <stdio.h>
       
   102 #include <string.h>
       
   103 
       
   104 
       
   105 #include "gstinfo.h"
       
   106 #include "gstregistry.h"
       
   107 #include "gstmarshal.h"
       
   108 #include "gstfilter.h"
       
   109 
       
   110 #ifdef __SYMBIAN32__
       
   111 #include <glib_global.h>
       
   112 #include "helpfile.h" 
       
   113 #endif
       
   114 
       
   115 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
       
   116 
       
   117 /* the one instance of the default registry and the mutex protecting the
       
   118  * variable. */
       
   119 static GStaticMutex _gst_registry_mutex = G_STATIC_MUTEX_INIT;
       
   120 static GstRegistry *_gst_registry_default = NULL;
       
   121 
       
   122 /* Element signals and args */
       
   123 enum
       
   124 {
       
   125   PLUGIN_ADDED,
       
   126   FEATURE_ADDED,
       
   127   LAST_SIGNAL
       
   128 };
       
   129 
       
   130 static void gst_registry_finalize (GObject * object);
       
   131 
       
   132 static guint gst_registry_signals[LAST_SIGNAL] = { 0 };
       
   133 
       
   134 static GstPluginFeature *gst_registry_lookup_feature_locked (GstRegistry *
       
   135     registry, const char *name);
       
   136 static GstPlugin *gst_registry_lookup_locked (GstRegistry * registry,
       
   137     const char *filename);
       
   138 
       
   139 G_DEFINE_TYPE (GstRegistry, gst_registry, GST_TYPE_OBJECT);
       
   140 static GstObjectClass *parent_class = NULL;
       
   141 
       
   142 static void
       
   143 gst_registry_class_init (GstRegistryClass * klass)
       
   144 {
       
   145   GObjectClass *gobject_class;
       
   146 
       
   147   gobject_class = (GObjectClass *) klass;
       
   148 
       
   149   parent_class = g_type_class_peek_parent (klass);
       
   150 
       
   151   /**
       
   152    * GstRegistry::plugin-added:
       
   153    * @registry: the registry that emitted the signal
       
   154    * @plugin: the plugin that has been added
       
   155    *
       
   156    * Signals that a plugin has been added to the registry (possibly
       
   157    * replacing a previously-added one by the same name)
       
   158    */
       
   159   gst_registry_signals[PLUGIN_ADDED] =
       
   160       g_signal_new ("plugin-added", G_TYPE_FROM_CLASS (klass),
       
   161       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRegistryClass, plugin_added), NULL,
       
   162       NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
       
   163 
       
   164   /**
       
   165    * GstRegistry::feature-added:
       
   166    * @registry: the registry that emitted the signal
       
   167    * @feature: the feature that has been added
       
   168    *
       
   169    * Signals that a feature has been added to the registry (possibly
       
   170    * replacing a previously-added one by the same name)
       
   171    */
       
   172   gst_registry_signals[FEATURE_ADDED] =
       
   173       g_signal_new ("feature-added", G_TYPE_FROM_CLASS (klass),
       
   174       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRegistryClass, feature_added),
       
   175       NULL, NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
       
   176 
       
   177   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_registry_finalize);
       
   178 }
       
   179 
       
   180 static void
       
   181 gst_registry_init (GstRegistry * registry)
       
   182 {
       
   183   registry->feature_hash = g_hash_table_new (g_str_hash, g_str_equal);
       
   184 }
       
   185 
       
   186 static void
       
   187 gst_registry_finalize (GObject * object)
       
   188 {
       
   189   GstRegistry *registry = GST_REGISTRY (object);
       
   190   GList *plugins, *p;
       
   191   GList *features, *f;
       
   192 
       
   193   plugins = registry->plugins;
       
   194   registry->plugins = NULL;
       
   195 
       
   196   GST_DEBUG_OBJECT (registry, "registry finalize");
       
   197   p = plugins;
       
   198   while (p) {
       
   199     GstPlugin *plugin = p->data;
       
   200 
       
   201     if (plugin) {
       
   202       GST_LOG_OBJECT (registry, "removing plugin %s",
       
   203           gst_plugin_get_name (plugin));
       
   204       gst_object_unref (plugin);
       
   205     }
       
   206     p = g_list_next (p);
       
   207   }
       
   208   g_list_free (plugins);
       
   209 
       
   210   features = registry->features;
       
   211   registry->features = NULL;
       
   212 
       
   213   f = features;
       
   214   while (f) {
       
   215     GstPluginFeature *feature = f->data;
       
   216 
       
   217     if (feature) {
       
   218       GST_LOG_OBJECT (registry, "removing feature %p (%s)",
       
   219           feature, gst_plugin_feature_get_name (feature));
       
   220       gst_object_unref (feature);
       
   221     }
       
   222     f = g_list_next (f);
       
   223   }
       
   224   g_list_free (features);
       
   225 
       
   226   g_hash_table_destroy (registry->feature_hash);
       
   227   registry->feature_hash = NULL;
       
   228 
       
   229   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   230 }
       
   231 
       
   232 /**
       
   233  * gst_registry_get_default:
       
   234  *
       
   235  * Retrieves the default registry. The caller does not own a reference on the
       
   236  * registry, as it is alive as long as GStreamer is initialized.
       
   237  *
       
   238  * Returns: The default #GstRegistry.
       
   239  */
       
   240 #ifdef __SYMBIAN32__
       
   241 EXPORT_C
       
   242 #endif
       
   243 
       
   244 GstRegistry *
       
   245 gst_registry_get_default (void)
       
   246 {
       
   247   GstRegistry *registry;
       
   248 
       
   249   g_static_mutex_lock (&_gst_registry_mutex);
       
   250   if (G_UNLIKELY (!_gst_registry_default)) {
       
   251     _gst_registry_default = g_object_new (GST_TYPE_REGISTRY, NULL);
       
   252     gst_object_ref (GST_OBJECT_CAST (_gst_registry_default));
       
   253     gst_object_sink (GST_OBJECT_CAST (_gst_registry_default));
       
   254   }
       
   255   registry = _gst_registry_default;
       
   256   g_static_mutex_unlock (&_gst_registry_mutex);
       
   257 
       
   258   return registry;
       
   259 }
       
   260 
       
   261 /**
       
   262  * gst_registry_add_path:
       
   263  * @registry: the registry to add the path to
       
   264  * @path: the path to add to the registry
       
   265  *
       
   266  * Add the given path to the registry. The syntax of the
       
   267  * path is specific to the registry. If the path has already been
       
   268  * added, do nothing.
       
   269  */
       
   270 #ifdef __SYMBIAN32__
       
   271 EXPORT_C
       
   272 #endif
       
   273 
       
   274 void
       
   275 gst_registry_add_path (GstRegistry * registry, const gchar * path)
       
   276 {
       
   277   g_return_if_fail (GST_IS_REGISTRY (registry));
       
   278   g_return_if_fail (path != NULL);
       
   279 
       
   280   if (strlen (path) == 0)
       
   281     goto empty_path;
       
   282 
       
   283   GST_OBJECT_LOCK (registry);
       
   284   if (g_list_find_custom (registry->paths, path, (GCompareFunc) strcmp))
       
   285     goto was_added;
       
   286 
       
   287   GST_INFO ("Adding plugin path: \"%s\"", path);
       
   288   registry->paths = g_list_append (registry->paths, g_strdup (path));
       
   289   GST_OBJECT_UNLOCK (registry);
       
   290 
       
   291   return;
       
   292 
       
   293 empty_path:
       
   294   {
       
   295     GST_INFO ("Ignoring empty plugin path");
       
   296     return;
       
   297   }
       
   298 was_added:
       
   299   {
       
   300     g_warning ("path %s already added to registry", path);
       
   301     GST_OBJECT_UNLOCK (registry);
       
   302     return;
       
   303   }
       
   304 }
       
   305 
       
   306 /**
       
   307  * gst_registry_get_path_list:
       
   308  * @registry: the registry to get the pathlist of
       
   309  *
       
   310  * Get the list of paths for the given registry.
       
   311  *
       
   312  * Returns: A Glist of paths as strings. g_list_free after use.
       
   313  *
       
   314  * MT safe.
       
   315  */
       
   316 #ifdef __SYMBIAN32__
       
   317 EXPORT_C
       
   318 #endif
       
   319 
       
   320 GList *
       
   321 gst_registry_get_path_list (GstRegistry * registry)
       
   322 {
       
   323   GList *list;
       
   324 
       
   325   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   326 
       
   327   GST_OBJECT_LOCK (registry);
       
   328   /* We don't need to copy the strings, because they won't be deleted
       
   329    * as long as the GstRegistry is around */
       
   330   list = g_list_copy (registry->paths);
       
   331   GST_OBJECT_UNLOCK (registry);
       
   332 
       
   333   return list;
       
   334 }
       
   335 
       
   336 
       
   337 /**
       
   338  * gst_registry_add_plugin:
       
   339  * @registry: the registry to add the plugin to
       
   340  * @plugin: the plugin to add
       
   341  *
       
   342  * Add the plugin to the registry. The plugin-added signal will be emitted.
       
   343  * This function will sink @plugin.
       
   344  *
       
   345  * Returns: TRUE on success.
       
   346  *
       
   347  * MT safe.
       
   348  */
       
   349 #ifdef __SYMBIAN32__
       
   350 EXPORT_C
       
   351 #endif
       
   352 
       
   353 gboolean
       
   354 gst_registry_add_plugin (GstRegistry * registry, GstPlugin * plugin)
       
   355 {
       
   356   GstPlugin *existing_plugin;
       
   357 
       
   358   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
       
   359   g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
       
   360 
       
   361   GST_OBJECT_LOCK (registry);
       
   362   existing_plugin = gst_registry_lookup_locked (registry, plugin->filename);
       
   363   if (G_UNLIKELY (existing_plugin)) {
       
   364     GST_DEBUG_OBJECT (registry,
       
   365         "Replacing existing plugin %p with new plugin %p for filename \"%s\"",
       
   366         existing_plugin, plugin, GST_STR_NULL (plugin->filename));
       
   367     registry->plugins = g_list_remove (registry->plugins, existing_plugin);
       
   368     gst_object_unref (existing_plugin);
       
   369   }
       
   370 
       
   371   GST_DEBUG_OBJECT (registry, "adding plugin %p for filename \"%s\"",
       
   372       plugin, GST_STR_NULL (plugin->filename));
       
   373 
       
   374   registry->plugins = g_list_prepend (registry->plugins, plugin);
       
   375 
       
   376   gst_object_ref (plugin);
       
   377   gst_object_sink (plugin);
       
   378   GST_OBJECT_UNLOCK (registry);
       
   379 
       
   380   GST_LOG_OBJECT (registry, "emitting plugin-added for filename \"%s\"",
       
   381       GST_STR_NULL (plugin->filename));
       
   382   g_signal_emit (G_OBJECT (registry), gst_registry_signals[PLUGIN_ADDED], 0,
       
   383       plugin);
       
   384 
       
   385   return TRUE;
       
   386 }
       
   387 
       
   388 static void
       
   389 gst_registry_remove_features_for_plugin_unlocked (GstRegistry * registry,
       
   390     GstPlugin * plugin)
       
   391 {
       
   392   GList *f;
       
   393 
       
   394   g_return_if_fail (GST_IS_REGISTRY (registry));
       
   395   g_return_if_fail (GST_IS_PLUGIN (plugin));
       
   396 
       
   397   /* Remove all features for this plugin */
       
   398   f = registry->features;
       
   399   while (f != NULL) {
       
   400     GList *next = g_list_next (f);
       
   401     GstPluginFeature *feature = f->data;
       
   402 
       
   403     if (feature && !strcmp (feature->plugin_name, gst_plugin_get_name (plugin))) {
       
   404       GST_DEBUG_OBJECT (registry, "removing feature %p (%s) for plugin %s",
       
   405           feature, gst_plugin_feature_get_name (feature),
       
   406           gst_plugin_get_name (plugin));
       
   407 
       
   408       registry->features = g_list_delete_link (registry->features, f);
       
   409       g_hash_table_remove (registry->feature_hash, feature->name);
       
   410       gst_object_unref (feature);
       
   411     }
       
   412     f = next;
       
   413   }
       
   414 }
       
   415 
       
   416 /**
       
   417  * gst_registry_remove_plugin:
       
   418  * @registry: the registry to remove the plugin from
       
   419  * @plugin: the plugin to remove
       
   420  *
       
   421  * Remove the plugin from the registry.
       
   422  *
       
   423  * MT safe.
       
   424  */
       
   425 #ifdef __SYMBIAN32__
       
   426 EXPORT_C
       
   427 #endif
       
   428 
       
   429 void
       
   430 gst_registry_remove_plugin (GstRegistry * registry, GstPlugin * plugin)
       
   431 {
       
   432   g_return_if_fail (GST_IS_REGISTRY (registry));
       
   433   g_return_if_fail (GST_IS_PLUGIN (plugin));
       
   434 
       
   435   GST_DEBUG_OBJECT (registry, "removing plugin %p (%s)",
       
   436       plugin, gst_plugin_get_name (plugin));
       
   437 
       
   438   GST_OBJECT_LOCK (registry);
       
   439   registry->plugins = g_list_remove (registry->plugins, plugin);
       
   440   gst_registry_remove_features_for_plugin_unlocked (registry, plugin);
       
   441   GST_OBJECT_UNLOCK (registry);
       
   442   gst_object_unref (plugin);
       
   443 }
       
   444 
       
   445 /**
       
   446  * gst_registry_add_feature:
       
   447  * @registry: the registry to add the plugin to
       
   448  * @feature: the feature to add
       
   449  *
       
   450  * Add the feature to the registry. The feature-added signal will be emitted.
       
   451  * This function sinks @feature.
       
   452  *
       
   453  * Returns: TRUE on success.
       
   454  *
       
   455  * MT safe.
       
   456  */
       
   457 #ifdef __SYMBIAN32__
       
   458 EXPORT_C
       
   459 #endif
       
   460 
       
   461 gboolean
       
   462 gst_registry_add_feature (GstRegistry * registry, GstPluginFeature * feature)
       
   463 {
       
   464   GstPluginFeature *existing_feature;
       
   465 
       
   466   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
       
   467   g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), FALSE);
       
   468   g_return_val_if_fail (feature->name != NULL, FALSE);
       
   469   g_return_val_if_fail (feature->plugin_name != NULL, FALSE);
       
   470 
       
   471   GST_OBJECT_LOCK (registry);
       
   472   existing_feature = gst_registry_lookup_feature_locked (registry,
       
   473       feature->name);
       
   474   if (G_UNLIKELY (existing_feature)) {
       
   475     GST_DEBUG_OBJECT (registry, "replacing existing feature %p (%s)",
       
   476         existing_feature, feature->name);
       
   477     /* Remove the existing feature from the list now, before we insert the new
       
   478      * one, but don't unref yet because the hash is still storing a reference to     * it. */
       
   479     registry->features = g_list_remove (registry->features, existing_feature);
       
   480   }
       
   481 
       
   482   GST_DEBUG_OBJECT (registry, "adding feature %p (%s)", feature, feature->name);
       
   483 
       
   484   registry->features = g_list_prepend (registry->features, feature);
       
   485   g_hash_table_replace (registry->feature_hash, feature->name, feature);
       
   486 
       
   487   if (G_UNLIKELY (existing_feature)) {
       
   488     /* We unref now. No need to remove the feature name from the hash table, it      * got replaced by the new feature */
       
   489     gst_object_unref (existing_feature);
       
   490   }
       
   491 
       
   492   gst_object_ref (feature);
       
   493   gst_object_sink (feature);
       
   494   GST_OBJECT_UNLOCK (registry);
       
   495 
       
   496   GST_LOG_OBJECT (registry, "emitting feature-added for %s", feature->name);
       
   497   g_signal_emit (G_OBJECT (registry), gst_registry_signals[FEATURE_ADDED], 0,
       
   498       feature);
       
   499 
       
   500   return TRUE;
       
   501 }
       
   502 
       
   503 /**
       
   504  * gst_registry_remove_feature:
       
   505  * @registry: the registry to remove the feature from
       
   506  * @feature: the feature to remove
       
   507  *
       
   508  * Remove the feature from the registry.
       
   509  *
       
   510  * MT safe.
       
   511  */
       
   512 #ifdef __SYMBIAN32__
       
   513 EXPORT_C
       
   514 #endif
       
   515 
       
   516 void
       
   517 gst_registry_remove_feature (GstRegistry * registry, GstPluginFeature * feature)
       
   518 {
       
   519   g_return_if_fail (GST_IS_REGISTRY (registry));
       
   520   g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
       
   521 
       
   522   GST_DEBUG_OBJECT (registry, "removing feature %p (%s)",
       
   523       feature, gst_plugin_feature_get_name (feature));
       
   524 
       
   525   GST_OBJECT_LOCK (registry);
       
   526   registry->features = g_list_remove (registry->features, feature);
       
   527   g_hash_table_remove (registry->feature_hash, feature->name);
       
   528   GST_OBJECT_UNLOCK (registry);
       
   529   gst_object_unref (feature);
       
   530 }
       
   531 
       
   532 /**
       
   533  * gst_registry_plugin_filter:
       
   534  * @registry: registry to query
       
   535  * @filter: the filter to use
       
   536  * @first: only return first match
       
   537  * @user_data: user data passed to the filter function
       
   538  *
       
   539  * Runs a filter against all plugins in the registry and returns a #GList with
       
   540  * the results. If the first flag is set, only the first match is
       
   541  * returned (as a list with a single object).
       
   542  * Every plugin is reffed; use gst_plugin_list_free() after use, which
       
   543  * will unref again.
       
   544  *
       
   545  * Returns: a #GList of #GstPlugin. Use gst_plugin_list_free() after usage.
       
   546  *
       
   547  * MT safe.
       
   548  */
       
   549 #ifdef __SYMBIAN32__
       
   550 EXPORT_C
       
   551 #endif
       
   552 
       
   553 GList *
       
   554 gst_registry_plugin_filter (GstRegistry * registry,
       
   555     GstPluginFilter filter, gboolean first, gpointer user_data)
       
   556 {
       
   557   GList *list;
       
   558   GList *g;
       
   559 
       
   560   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   561 
       
   562   GST_OBJECT_LOCK (registry);
       
   563   list = gst_filter_run (registry->plugins, (GstFilterFunc) filter, first,
       
   564       user_data);
       
   565   for (g = list; g; g = g->next) {
       
   566     gst_object_ref (GST_PLUGIN_CAST (g->data));
       
   567   }
       
   568   GST_OBJECT_UNLOCK (registry);
       
   569 
       
   570   return list;
       
   571 }
       
   572 
       
   573 /**
       
   574  * gst_registry_feature_filter:
       
   575  * @registry: registry to query
       
   576  * @filter: the filter to use
       
   577  * @first: only return first match
       
   578  * @user_data: user data passed to the filter function
       
   579  *
       
   580  * Runs a filter against all features of the plugins in the registry
       
   581  * and returns a GList with the results.
       
   582  * If the first flag is set, only the first match is
       
   583  * returned (as a list with a single object).
       
   584  *
       
   585  * Returns: a GList of plugin features, gst_plugin_feature_list_free after use.
       
   586  *
       
   587  * MT safe.
       
   588  */
       
   589 #ifdef __SYMBIAN32__
       
   590 EXPORT_C
       
   591 #endif
       
   592 
       
   593 GList *
       
   594 gst_registry_feature_filter (GstRegistry * registry,
       
   595     GstPluginFeatureFilter filter, gboolean first, gpointer user_data)
       
   596 {
       
   597   GList *list;
       
   598   GList *g;
       
   599 
       
   600   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   601 
       
   602   GST_OBJECT_LOCK (registry);
       
   603   list = gst_filter_run (registry->features, (GstFilterFunc) filter, first,
       
   604       user_data);
       
   605   for (g = list; g; g = g->next) {
       
   606     gst_object_ref (GST_PLUGIN_FEATURE_CAST (g->data));
       
   607   }
       
   608   GST_OBJECT_UNLOCK (registry);
       
   609 
       
   610   return list;
       
   611 }
       
   612 
       
   613 /**
       
   614  * gst_registry_find_plugin:
       
   615  * @registry: the registry to search
       
   616  * @name: the plugin name to find
       
   617  *
       
   618  * Find the plugin with the given name in the registry.
       
   619  * The plugin will be reffed; caller is responsible for unreffing.
       
   620  *
       
   621  * Returns: The plugin with the given name or NULL if the plugin was not found.
       
   622  * gst_object_unref() after usage.
       
   623  *
       
   624  * MT safe.
       
   625  */
       
   626 #ifdef __SYMBIAN32__
       
   627 EXPORT_C
       
   628 #endif
       
   629 
       
   630 GstPlugin *
       
   631 gst_registry_find_plugin (GstRegistry * registry, const gchar * name)
       
   632 {
       
   633   GList *walk;
       
   634   GstPlugin *result = NULL;
       
   635 
       
   636   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   637   g_return_val_if_fail (name != NULL, NULL);
       
   638 
       
   639   walk = gst_registry_plugin_filter (registry,
       
   640       (GstPluginFilter) gst_plugin_name_filter, TRUE, (gpointer) name);
       
   641   if (walk) {
       
   642     result = GST_PLUGIN_CAST (walk->data);
       
   643 
       
   644     gst_object_ref (result);
       
   645     gst_plugin_list_free (walk);
       
   646   }
       
   647 
       
   648   return result;
       
   649 }
       
   650 
       
   651 /**
       
   652  * gst_registry_find_feature:
       
   653  * @registry: the registry to search
       
   654  * @name: the pluginfeature name to find
       
   655  * @type: the pluginfeature type to find
       
   656  *
       
   657  * Find the pluginfeature with the given name and type in the registry.
       
   658  *
       
   659  * Returns: The pluginfeature with the given name and type or NULL
       
   660  * if the plugin was not found. gst_object_unref() after usage.
       
   661  *
       
   662  * MT safe.
       
   663  */
       
   664 #ifdef __SYMBIAN32__
       
   665 EXPORT_C
       
   666 #endif
       
   667 
       
   668 GstPluginFeature *
       
   669 gst_registry_find_feature (GstRegistry * registry, const gchar * name,
       
   670     GType type)
       
   671 {
       
   672   GstPluginFeature *feature = NULL;
       
   673   GList *walk;
       
   674   GstTypeNameData data;
       
   675 
       
   676   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   677   g_return_val_if_fail (name != NULL, NULL);
       
   678   g_return_val_if_fail (g_type_is_a (type, GST_TYPE_PLUGIN_FEATURE), NULL);
       
   679 
       
   680   data.name = name;
       
   681   data.type = type;
       
   682 
       
   683   walk = gst_registry_feature_filter (registry,
       
   684       (GstPluginFeatureFilter) gst_plugin_feature_type_name_filter,
       
   685       TRUE, &data);
       
   686 
       
   687   if (walk) {
       
   688     feature = GST_PLUGIN_FEATURE_CAST (walk->data);
       
   689 
       
   690     gst_object_ref (feature);
       
   691     gst_plugin_feature_list_free (walk);
       
   692   }
       
   693 
       
   694   return feature;
       
   695 }
       
   696 
       
   697 /**
       
   698  * gst_registry_get_feature_list:
       
   699  * @registry: a #GstRegistry
       
   700  * @type: a #GType.
       
   701  *
       
   702  * Retrieves a #GList of #GstPluginFeature of @type.
       
   703  *
       
   704  * Returns: a #GList of #GstPluginFeature of @type. gst_plugin_feature_list_free
       
   705  * after usage.
       
   706  *
       
   707  * MT safe.
       
   708  */
       
   709 #ifdef __SYMBIAN32__
       
   710 EXPORT_C
       
   711 #endif
       
   712 
       
   713 GList *
       
   714 gst_registry_get_feature_list (GstRegistry * registry, GType type)
       
   715 {
       
   716   GstTypeNameData data;
       
   717 
       
   718   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   719   g_return_val_if_fail (g_type_is_a (type, GST_TYPE_PLUGIN_FEATURE), NULL);
       
   720 
       
   721   data.type = type;
       
   722   data.name = NULL;
       
   723 
       
   724   return gst_registry_feature_filter (registry,
       
   725       (GstPluginFeatureFilter) gst_plugin_feature_type_name_filter,
       
   726       FALSE, &data);
       
   727 }
       
   728 
       
   729 /**
       
   730  * gst_registry_get_plugin_list:
       
   731  * @registry: the registry to search
       
   732  *
       
   733  * Get a copy of all plugins registered in the given registry. The refcount
       
   734  * of each element in the list in incremented.
       
   735  *
       
   736  * Returns: a #GList of #GstPlugin. gst_plugin_list_free after use.
       
   737  *
       
   738  * MT safe.
       
   739  */
       
   740 #ifdef __SYMBIAN32__
       
   741 EXPORT_C
       
   742 #endif
       
   743 
       
   744 GList *
       
   745 gst_registry_get_plugin_list (GstRegistry * registry)
       
   746 {
       
   747   GList *list;
       
   748   GList *g;
       
   749 
       
   750   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   751 
       
   752   GST_OBJECT_LOCK (registry);
       
   753   list = g_list_copy (registry->plugins);
       
   754   for (g = list; g; g = g->next) {
       
   755     gst_object_ref (GST_PLUGIN_CAST (g->data));
       
   756   }
       
   757   GST_OBJECT_UNLOCK (registry);
       
   758 
       
   759   return list;
       
   760 }
       
   761 
       
   762 static GstPluginFeature *
       
   763 gst_registry_lookup_feature_locked (GstRegistry * registry, const char *name)
       
   764 {
       
   765   if (G_UNLIKELY (name == NULL))
       
   766     return NULL;
       
   767 
       
   768   return g_hash_table_lookup (registry->feature_hash, name);
       
   769 }
       
   770 
       
   771 /**
       
   772  * gst_registry_lookup_feature:
       
   773  * @registry: a #GstRegistry
       
   774  * @name: a #GstPluginFeature name
       
   775  *
       
   776  * Find a #GstPluginFeature with @name in @registry.
       
   777  *
       
   778  * Returns: a #GstPluginFeature with its refcount incremented, use
       
   779  * gst_object_unref() after usage.
       
   780  *
       
   781  * MT safe.
       
   782  */
       
   783 #ifdef __SYMBIAN32__
       
   784 EXPORT_C
       
   785 #endif
       
   786 
       
   787 GstPluginFeature *
       
   788 gst_registry_lookup_feature (GstRegistry * registry, const char *name)
       
   789 {
       
   790   GstPluginFeature *feature;
       
   791 
       
   792   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   793   g_return_val_if_fail (name != NULL, NULL);
       
   794 
       
   795   GST_OBJECT_LOCK (registry);
       
   796   feature = gst_registry_lookup_feature_locked (registry, name);
       
   797   if (feature)
       
   798     gst_object_ref (feature);
       
   799   GST_OBJECT_UNLOCK (registry);
       
   800 
       
   801   return feature;
       
   802 }
       
   803 
       
   804 static GstPlugin *
       
   805 gst_registry_lookup_locked (GstRegistry * registry, const char *filename)
       
   806 {
       
   807   GList *g;
       
   808   GstPlugin *plugin;
       
   809   gchar *basename;
       
   810 
       
   811   if (G_UNLIKELY (filename == NULL))
       
   812     return NULL;
       
   813 
       
   814   basename = g_path_get_basename (filename);
       
   815   /* FIXME: use GTree speed up lookups */
       
   816   for (g = registry->plugins; g; g = g_list_next (g)) {
       
   817     plugin = GST_PLUGIN_CAST (g->data);
       
   818     if (plugin->basename && strcmp (basename, plugin->basename) == 0) {
       
   819       g_free (basename);
       
   820       return plugin;
       
   821     }
       
   822   }
       
   823 
       
   824   g_free (basename);
       
   825   return NULL;
       
   826 }
       
   827 
       
   828 /**
       
   829  * gst_registry_lookup:
       
   830  * @registry: the registry to look up in
       
   831  * @filename: the name of the file to look up
       
   832  *
       
   833  * Look up a plugin in the given registry with the given filename.
       
   834  * If found, plugin is reffed.
       
   835  *
       
   836  * Returns: the #GstPlugin if found, or NULL if not. gst_object_unref()
       
   837  * after usage.
       
   838  */
       
   839 #ifdef __SYMBIAN32__
       
   840 EXPORT_C
       
   841 #endif
       
   842 
       
   843 GstPlugin *
       
   844 gst_registry_lookup (GstRegistry * registry, const char *filename)
       
   845 {
       
   846   GstPlugin *plugin;
       
   847 
       
   848   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
   849   g_return_val_if_fail (filename != NULL, NULL);
       
   850 
       
   851   GST_OBJECT_LOCK (registry);
       
   852   plugin = gst_registry_lookup_locked (registry, filename);
       
   853   if (plugin)
       
   854     gst_object_ref (plugin);
       
   855   GST_OBJECT_UNLOCK (registry);
       
   856 
       
   857   return plugin;
       
   858 }
       
   859 
       
   860 static gboolean
       
   861 gst_registry_scan_path_level (GstRegistry * registry, const gchar * path,
       
   862     int level)
       
   863 {
       
   864   GDir *directory[2];
       
   865   GDir *dir;
       
   866   const gchar *dirent;
       
   867   gchar *filename;
       
   868   GstPlugin *plugin;
       
   869   GstPlugin *newplugin;
       
   870   gboolean changed = FALSE;
       
   871 
       
   872 #ifdef __SYMBIAN32__  
       
   873   GMappedFile *mapped = NULL; 
       
   874   gchar *contents = NULL;  
       
   875   gchar** arglist=NULL;  
       
   876   GError *err = NULL;  
       
   877   char* file;
       
   878   gint i = 2;
       
   879 #endif
       
   880   directory[0] = g_dir_open ( PLUGIN_LIST, 0, NULL );
       
   881   directory[1] = g_dir_open ( PLUGIN_LIST_IN_ROM, 0, NULL );
       
   882   while( i ){
       
   883    --i; 
       
   884     dir = directory[i];
       
   885     if (!dir)
       
   886         continue;
       
   887 
       
   888   while ((dirent = g_dir_read_name (dir))) 
       
   889   {    
       
   890 #ifdef __SYMBIAN32__
       
   891     
       
   892    if( i == 1 )
       
   893         filename = g_strjoin ("\\", PLUGIN_LIST_IN_ROM, dirent, NULL);
       
   894     else
       
   895         filename = g_strjoin ("\\", PLUGIN_LIST, dirent, NULL);
       
   896     mapped = g_mapped_file_new (filename, FALSE, &err);
       
   897     contents = g_mapped_file_get_contents (mapped);
       
   898     arglist = g_strsplit(contents, "\r\n", -1 );
       
   899     
       
   900     g_free (filename);
       
   901      
       
   902     while( *arglist )
       
   903     {
       
   904       filename = *arglist;
       
   905       // trim white spaces from start
       
   906       while(*filename ==' ' )
       
   907           filename++;
       
   908       
       
   909       file = filename;
       
   910       
       
   911       // trim white spaces from last
       
   912       while(*file != ' ' && *file != '\0')
       
   913           file++;
       
   914       *file = '\0';
       
   915       
       
   916       arglist++;
       
   917       /// get the full path of DLL 
       
   918       filename = libgstreamer_get_dll_path( filename );
       
   919 
       
   920 #else
       
   921       
       
   922 	  filename = g_strjoin ("\\", path, dirent, NULL);
       
   923 #endif      
       
   924     GST_LOG_OBJECT (registry, "examining file: %s", filename);
       
   925 
       
   926     if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
       
   927       if (level > 0) {
       
   928         GST_LOG_OBJECT (registry, "found directory, recursing");
       
   929         changed |= gst_registry_scan_path_level (registry, filename, level - 1);
       
   930       } else {
       
   931         GST_LOG_OBJECT (registry,
       
   932             "found directory, but recursion level is too deep");
       
   933       }
       
   934       g_free (filename);
       
   935       continue;
       
   936     }
       
   937       if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
       
   938         GST_LOG_OBJECT (registry, "not a regular file, ignoring");
       
   939         g_free (filename);
       
   940         continue;
       
   941       }
       
   942     if (!g_str_has_suffix (filename, ".so") &&
       
   943         !g_str_has_suffix (filename, ".sl") &&
       
   944         !g_str_has_suffix (filename, ".dll") &&
       
   945         !g_str_has_suffix (filename, ".dynlib")) {
       
   946       GST_LOG_OBJECT (registry,
       
   947           "extension is not recognized as module file, ignoring");
       
   948       g_free (filename);
       
   949       continue;
       
   950     }
       
   951 
       
   952     /* plug-ins are considered unique by basename; if the given name
       
   953      * was already seen by the registry, we ignore it */
       
   954     plugin = gst_registry_lookup (registry, filename);
       
   955     if (plugin) {
       
   956       struct stat file_status;
       
   957 
       
   958       if (stat (filename, &file_status)) {
       
   959         /* Plugin will be removed from cache after the scan completes if it
       
   960          * is still marked 'cached' */
       
   961         g_free (filename);
       
   962         gst_object_unref (plugin);
       
   963         continue;
       
   964       }
       
   965       if (plugin->registered) {
       
   966         GST_DEBUG_OBJECT (registry,
       
   967             "plugin already registered from path \"%s\"",
       
   968             GST_STR_NULL (plugin->filename));
       
   969         g_free (filename);
       
   970         gst_object_unref (plugin);
       
   971         continue;
       
   972       }
       
   973       if (plugin->file_mtime == file_status.st_mtime &&
       
   974           plugin->file_size == file_status.st_size) {
       
   975         GST_LOG_OBJECT (registry, "file %s cached", filename);
       
   976         plugin->flags &= ~GST_PLUGIN_FLAG_CACHED;
       
   977         GST_LOG_OBJECT (registry, "marking plugin %p as registered as %s",
       
   978             plugin, filename);
       
   979         plugin->registered = TRUE;
       
   980         /* Update the file path on which we've seen this cached plugin
       
   981          * to ensure the registry cache will reflect up to date information */
       
   982         if (strcmp (plugin->filename, filename) != 0) {
       
   983           g_free (plugin->filename);
       
   984           plugin->filename = g_strdup (filename);
       
   985           changed = TRUE;
       
   986         }
       
   987       } else {
       
   988         GST_INFO_OBJECT (registry, "cached info for %s is stale", filename);
       
   989         GST_DEBUG_OBJECT (registry, "mtime %ld != %ld or size %"
       
   990             G_GINT64_FORMAT " != %"
       
   991             G_GINT64_FORMAT, plugin->file_mtime, file_status.st_mtime,
       
   992             (gint64) plugin->file_size, (gint64) file_status.st_size);
       
   993         gst_registry_remove_plugin (gst_registry_get_default (), plugin);
       
   994         /* We don't use a GError here because a failure to load some shared
       
   995          * objects as plugins is normal (particularly in the uninstalled case)
       
   996          */
       
   997         newplugin = gst_plugin_load_file (filename, NULL);
       
   998         if (newplugin) {
       
   999           GST_DEBUG_OBJECT (registry, "marking new plugin %p as registered",
       
  1000               newplugin);
       
  1001           newplugin->registered = TRUE;
       
  1002           gst_object_unref (newplugin);
       
  1003         }
       
  1004         changed = TRUE;
       
  1005       }
       
  1006       gst_object_unref (plugin);
       
  1007 
       
  1008     } else {
       
  1009       GST_DEBUG_OBJECT (registry, "file %s not yet in registry", filename);
       
  1010       newplugin = gst_plugin_load_file (filename, NULL);
       
  1011       if (newplugin) {
       
  1012         newplugin->registered = TRUE;
       
  1013         gst_object_unref (newplugin);
       
  1014         changed = TRUE;
       
  1015       }
       
  1016     }
       
  1017 
       
  1018     g_free (filename);
       
  1019   }
       
  1020 #ifdef __SYMBIAN32__          
       
  1021  }  
       
  1022 #endif
       
  1023   g_dir_close (dir);
       
  1024 }
       
  1025   return changed;
       
  1026 }
       
  1027 
       
  1028 /**
       
  1029  * gst_registry_scan_path:
       
  1030  * @registry: the registry to add the path to
       
  1031  * @path: the path to add to the registry
       
  1032  *
       
  1033  * Add the given path to the registry. The syntax of the
       
  1034  * path is specific to the registry. If the path has already been
       
  1035  * added, do nothing.
       
  1036  *
       
  1037  * Returns: %TRUE if registry changed
       
  1038  */
       
  1039 #ifdef __SYMBIAN32__
       
  1040 EXPORT_C
       
  1041 #endif
       
  1042 
       
  1043 gboolean
       
  1044 gst_registry_scan_path (GstRegistry * registry, const gchar * path)
       
  1045 {
       
  1046   gboolean changed;
       
  1047 
       
  1048   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
       
  1049   g_return_val_if_fail (path != NULL, FALSE);
       
  1050 
       
  1051   GST_DEBUG_OBJECT (registry, "scanning path %s", path);
       
  1052   changed = gst_registry_scan_path_level (registry, path, 10);
       
  1053 
       
  1054   GST_DEBUG_OBJECT (registry, "registry changed in path %s: %d", path, changed);
       
  1055 
       
  1056   return changed;
       
  1057 }
       
  1058 
       
  1059 /* Unref all plugins marked 'cached', to clear old plugins that no
       
  1060  * longer exist. Returns TRUE if any plugins were removed */
       
  1061 #ifdef __SYMBIAN32__
       
  1062 EXPORT_C
       
  1063 #endif
       
  1064 
       
  1065 gboolean
       
  1066 _priv_gst_registry_remove_cache_plugins (GstRegistry * registry)
       
  1067 {
       
  1068   GList *g;
       
  1069   GList *g_next;
       
  1070   GstPlugin *plugin;
       
  1071   gboolean changed = FALSE;
       
  1072 
       
  1073   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
       
  1074 
       
  1075   GST_OBJECT_LOCK (registry);
       
  1076 
       
  1077   GST_DEBUG_OBJECT (registry, "removing cached plugins");
       
  1078   g = registry->plugins;
       
  1079   while (g) {
       
  1080     g_next = g->next;
       
  1081     plugin = g->data;
       
  1082     if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
       
  1083       GST_DEBUG_OBJECT (registry, "removing cached plugin \"%s\"",
       
  1084           GST_STR_NULL (plugin->filename));
       
  1085       registry->plugins = g_list_delete_link (registry->plugins, g);
       
  1086       gst_registry_remove_features_for_plugin_unlocked (registry, plugin);
       
  1087       gst_object_unref (plugin);
       
  1088       changed = TRUE;
       
  1089     }
       
  1090     g = g_next;
       
  1091   }
       
  1092 
       
  1093   GST_OBJECT_UNLOCK (registry);
       
  1094 
       
  1095   return changed;
       
  1096 }
       
  1097 
       
  1098 
       
  1099 static gboolean
       
  1100 _gst_plugin_feature_filter_plugin_name (GstPluginFeature * feature,
       
  1101     gpointer user_data)
       
  1102 {
       
  1103   return (strcmp (feature->plugin_name, (gchar *) user_data) == 0);
       
  1104 }
       
  1105 
       
  1106 /**
       
  1107  * gst_registry_get_feature_list_by_plugin:
       
  1108  * @registry: a #GstRegistry.
       
  1109  * @name: a plugin name.
       
  1110  *
       
  1111  * Retrieves a #GList of features of the plugin with name @name.
       
  1112  *
       
  1113  * Returns: a #GList of #GstPluginFeature. gst_plugin_feature_list_free() after usage.
       
  1114  */
       
  1115 #ifdef __SYMBIAN32__
       
  1116 EXPORT_C
       
  1117 #endif
       
  1118 
       
  1119 GList *
       
  1120 gst_registry_get_feature_list_by_plugin (GstRegistry * registry,
       
  1121     const gchar * name)
       
  1122 {
       
  1123   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
       
  1124   g_return_val_if_fail (name != NULL, NULL);
       
  1125 
       
  1126   return gst_registry_feature_filter (registry,
       
  1127       _gst_plugin_feature_filter_plugin_name, FALSE, (gpointer) name);
       
  1128 }
       
  1129 
       
  1130 /* Unref and delete the default registry */
       
  1131 #ifdef __SYMBIAN32__
       
  1132 EXPORT_C
       
  1133 #endif
       
  1134 
       
  1135 void
       
  1136 _priv_gst_registry_cleanup ()
       
  1137 {
       
  1138   GstRegistry *registry;
       
  1139 
       
  1140   g_static_mutex_lock (&_gst_registry_mutex);
       
  1141   if ((registry = _gst_registry_default) != NULL) {
       
  1142     _gst_registry_default = NULL;
       
  1143   }
       
  1144   g_static_mutex_unlock (&_gst_registry_mutex);
       
  1145 
       
  1146   /* unref outside of the lock because we can. */
       
  1147   if (registry)
       
  1148     gst_object_unref (registry);
       
  1149 }
       
  1150 
       
  1151 /**
       
  1152  * gst_default_registry_check_feature_version:
       
  1153  * @feature_name: the name of the feature (e.g. "oggdemux")
       
  1154  * @min_major: the minimum major version number
       
  1155  * @min_minor: the minimum minor version number
       
  1156  * @min_micro: the minimum micro version number
       
  1157  *
       
  1158  * Checks whether a plugin feature by the given name exists in the
       
  1159  * default registry and whether its version is at least the
       
  1160  * version required.
       
  1161  *
       
  1162  * Returns: #TRUE if the feature could be found and the version is
       
  1163  * the same as the required version or newer, and #FALSE otherwise.
       
  1164  */
       
  1165 #ifdef __SYMBIAN32__
       
  1166 EXPORT_C
       
  1167 #endif
       
  1168 
       
  1169 gboolean
       
  1170 gst_default_registry_check_feature_version (const gchar * feature_name,
       
  1171     guint min_major, guint min_minor, guint min_micro)
       
  1172 {
       
  1173   GstPluginFeature *feature;
       
  1174   GstRegistry *registry;
       
  1175   gboolean ret = FALSE;
       
  1176 
       
  1177   g_return_val_if_fail (feature_name != NULL, FALSE);
       
  1178 
       
  1179   GST_DEBUG ("Looking up plugin feature '%s'", feature_name);
       
  1180 
       
  1181   registry = gst_registry_get_default ();
       
  1182   feature = gst_registry_lookup_feature (registry, feature_name);
       
  1183   if (feature) {
       
  1184     ret = gst_plugin_feature_check_version (feature, min_major, min_minor,
       
  1185         min_micro);
       
  1186     gst_object_unref (feature);
       
  1187   } else {
       
  1188     GST_DEBUG ("Could not find plugin feature '%s'", feature_name);
       
  1189   }
       
  1190 
       
  1191   return ret;
       
  1192 }