gstreamer_core/gst/gstplugin.c
branchRCL_3
changeset 7 567bb019e3e3
parent 0 0e761a78d257
child 8 7e817e7e631c
equal deleted inserted replaced
6:9b2c3c7a1a9c 7:567bb019e3e3
    34  * the plugin loader will check the version of the core library the plugin was
    34  * the plugin loader will check the version of the core library the plugin was
    35  * linked against and will create a new #GstPlugin. It will then call the
    35  * linked against and will create a new #GstPlugin. It will then call the
    36  * #GstPluginInitFunc function that was provided in the
    36  * #GstPluginInitFunc function that was provided in the
    37  * <symbol>gst_plugin_desc</symbol>.
    37  * <symbol>gst_plugin_desc</symbol>.
    38  *
    38  *
    39  * Once you have a handle to a #GstPlugin (e.g. from the #GstRegistryPool), you
    39  * Once you have a handle to a #GstPlugin (e.g. from the #GstRegistry), you
    40  * can add any object that subclasses #GstPluginFeature.
    40  * can add any object that subclasses #GstPluginFeature.
    41  *
       
    42  * Use gst_plugin_find_feature() and gst_plugin_get_feature_list() to find
       
    43  * features in a plugin.
       
    44  *
    41  *
    45  * Usually plugins are always automaticlly loaded so you don't need to call
    42  * Usually plugins are always automaticlly loaded so you don't need to call
    46  * gst_plugin_load() explicitly to bring it into memory. There are options to
    43  * gst_plugin_load() explicitly to bring it into memory. There are options to
    47  * statically link plugins to an app or even use GStreamer without a plugin
    44  * statically link plugins to an app or even use GStreamer without a plugin
    48  * repository in which case gst_plugin_load() can be needed to bring the plugin
    45  * repository in which case gst_plugin_load() can be needed to bring the plugin
    78 static GstPluginDesc *_static_plugins;  /* NULL */
    75 static GstPluginDesc *_static_plugins;  /* NULL */
    79 static gboolean _gst_plugin_inited;
    76 static gboolean _gst_plugin_inited;
    80 
    77 
    81 /* static variables for segfault handling of plugin loading */
    78 /* static variables for segfault handling of plugin loading */
    82 static char *_gst_plugin_fault_handler_filename = NULL;
    79 static char *_gst_plugin_fault_handler_filename = NULL;
    83 
       
    84 #ifndef HAVE_WIN32
       
    85 static gboolean _gst_plugin_fault_handler_is_setup = FALSE;
       
    86 #endif
       
    87 
    80 
    88 /* list of valid licenses.
    81 /* list of valid licenses.
    89  * One of these must be specified or the plugin won't be loaded
    82  * One of these must be specified or the plugin won't be loaded
    90  * Contact gstreamer-devel@lists.sourceforge.net if your license should be
    83  * Contact gstreamer-devel@lists.sourceforge.net if your license should be
    91  * added.
    84  * added.
   109   GST_LICENSE_UNKNOWN,          /* some other license */
   102   GST_LICENSE_UNKNOWN,          /* some other license */
   110   NULL
   103   NULL
   111 };
   104 };
   112 
   105 
   113 static GstPlugin *gst_plugin_register_func (GstPlugin * plugin,
   106 static GstPlugin *gst_plugin_register_func (GstPlugin * plugin,
   114     const GstPluginDesc * desc);
   107     const GstPluginDesc * desc, gpointer user_data);
   115 static void gst_plugin_desc_copy (GstPluginDesc * dest,
   108 static void gst_plugin_desc_copy (GstPluginDesc * dest,
   116     const GstPluginDesc * src);
   109     const GstPluginDesc * src);
   117 static void gst_plugin_desc_free (GstPluginDesc * desc);
   110 static void gst_plugin_desc_free (GstPluginDesc * desc);
   118 
   111 
       
   112 static void gst_plugin_ext_dep_free (GstPluginDep * dep);
   119 
   113 
   120 G_DEFINE_TYPE (GstPlugin, gst_plugin, GST_TYPE_OBJECT);
   114 G_DEFINE_TYPE (GstPlugin, gst_plugin, GST_TYPE_OBJECT);
   121 
   115 
   122 static void
   116 static void
   123 gst_plugin_init (GstPlugin * plugin)
   117 gst_plugin_init (GstPlugin * plugin)
   124 {
   118 {
   125   /* do nothing, needed because of G_DEFINE_TYPE */
   119   plugin->priv =
       
   120       G_TYPE_INSTANCE_GET_PRIVATE (plugin, GST_TYPE_PLUGIN, GstPluginPrivate);
   126 }
   121 }
   127 
   122 
   128 static void
   123 static void
   129 gst_plugin_finalize (GObject * object)
   124 gst_plugin_finalize (GObject * object)
   130 {
   125 {
   140   }
   135   }
   141   g_free (plugin->filename);
   136   g_free (plugin->filename);
   142   g_free (plugin->basename);
   137   g_free (plugin->basename);
   143   gst_plugin_desc_free (&plugin->desc);
   138   gst_plugin_desc_free (&plugin->desc);
   144 
   139 
       
   140   g_list_foreach (plugin->priv->deps, (GFunc) gst_plugin_ext_dep_free, NULL);
       
   141   g_list_free (plugin->priv->deps);
       
   142   plugin->priv->deps = NULL;
       
   143 
       
   144   if (plugin->priv->cache_data) {
       
   145     gst_structure_free (plugin->priv->cache_data);
       
   146   }
       
   147 
   145   G_OBJECT_CLASS (gst_plugin_parent_class)->finalize (object);
   148   G_OBJECT_CLASS (gst_plugin_parent_class)->finalize (object);
   146 }
   149 }
   147 
   150 
   148 static void
   151 static void
   149 gst_plugin_class_init (GstPluginClass * klass)
   152 gst_plugin_class_init (GstPluginClass * klass)
   150 {
   153 {
   151   G_OBJECT_CLASS (klass)->finalize = GST_DEBUG_FUNCPTR (gst_plugin_finalize);
   154   G_OBJECT_CLASS (klass)->finalize = GST_DEBUG_FUNCPTR (gst_plugin_finalize);
       
   155 
       
   156   g_type_class_add_private (klass, sizeof (GstPluginPrivate));
   152 }
   157 }
   153 #ifdef __SYMBIAN32__
   158 #ifdef __SYMBIAN32__
   154 EXPORT_C
   159 EXPORT_C
   155 #endif
   160 #endif
   156 
   161 
   272   /* make sure gst_init() has been called */
   277   /* make sure gst_init() has been called */
   273   g_return_val_if_fail (_gst_plugin_inited != FALSE, FALSE);
   278   g_return_val_if_fail (_gst_plugin_inited != FALSE, FALSE);
   274 
   279 
   275   GST_LOG ("attempting to load static plugin \"%s\" now...", name);
   280   GST_LOG ("attempting to load static plugin \"%s\" now...", name);
   276   plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
   281   plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
   277   if (gst_plugin_register_func (plugin, &desc) != NULL) {
   282   if (gst_plugin_register_func (plugin, &desc, NULL) != NULL) {
       
   283     GST_INFO ("registered static plugin \"%s\"", name);
       
   284     res = gst_default_registry_add_plugin (plugin);
       
   285     GST_INFO ("added static plugin \"%s\", result: %d", name, res);
       
   286   }
       
   287   return res;
       
   288 }
       
   289 
       
   290 /**
       
   291  * gst_plugin_register_static_full:
       
   292  * @major_version: the major version number of the GStreamer core that the
       
   293  *     plugin was compiled for, you can just use GST_VERSION_MAJOR here
       
   294  * @minor_version: the minor version number of the GStreamer core that the
       
   295  *     plugin was compiled for, you can just use GST_VERSION_MINOR here
       
   296  * @name: a unique name of the plugin (ideally prefixed with an application- or
       
   297  *     library-specific namespace prefix in order to avoid name conflicts in
       
   298  *     case a similar plugin with the same name ever gets added to GStreamer)
       
   299  * @description: description of the plugin
       
   300  * @init_full_func: pointer to the init function with user data of this plugin.
       
   301  * @version: version string of the plugin
       
   302  * @license: effective license of plugin. Must be one of the approved licenses
       
   303  *     (see #GstPluginDesc above) or the plugin will not be registered.
       
   304  * @source: source module plugin belongs to
       
   305  * @package: shipped package plugin belongs to
       
   306  * @origin: URL to provider of plugin
       
   307  * @user_data: gpointer to user data
       
   308  *
       
   309  * Registers a static plugin, ie. a plugin which is private to an application
       
   310  * or library and contained within the application or library (as opposed to
       
   311  * being shipped as a separate module file) with a #GstPluginInitFullFunc
       
   312  * which allows user data to be passed to the callback function (useful
       
   313  * for bindings).
       
   314  *
       
   315  * You must make sure that GStreamer has been initialised (with gst_init() or
       
   316  * via gst_init_get_option_group()) before calling this function.
       
   317  *
       
   318  * Returns: TRUE if the plugin was registered correctly, otherwise FALSE.
       
   319  *
       
   320  * Since: 0.10.24
       
   321  *
       
   322  */
       
   323 #ifdef __SYMBIAN32__
       
   324 EXPORT_C
       
   325 #endif
       
   326 
       
   327 gboolean
       
   328 gst_plugin_register_static_full (gint major_version, gint minor_version,
       
   329     const gchar * name, gchar * description,
       
   330     GstPluginInitFullFunc init_full_func, const gchar * version,
       
   331     const gchar * license, const gchar * source, const gchar * package,
       
   332     const gchar * origin, gpointer user_data)
       
   333 {
       
   334 #ifdef __SYMBIAN32__
       
   335   GstPluginDesc desc;
       
   336   GstPlugin *plugin;
       
   337   gboolean res = FALSE;
       
   338 
       
   339   desc.major_version = major_version;
       
   340   desc.minor_version = minor_version;
       
   341   desc.name = name;
       
   342   desc.description = description;
       
   343   desc.plugin_init = (GstPluginInitFunc)init_full_func;
       
   344   desc.version = version;
       
   345   desc.license = license;
       
   346   desc.source = source;
       
   347   desc.package = package;
       
   348   desc.origin = origin;
       
   349 #else
       
   350   GstPluginDesc desc = { major_version, minor_version, name, description,
       
   351     (GstPluginInitFunc) init_full_func, version, license, source, package,
       
   352     origin,
       
   353   };
       
   354   GstPlugin *plugin;
       
   355   gboolean res = FALSE;
       
   356 #endif
       
   357   g_return_val_if_fail (name != NULL, FALSE);
       
   358   g_return_val_if_fail (description != NULL, FALSE);
       
   359   g_return_val_if_fail (init_full_func != NULL, FALSE);
       
   360   g_return_val_if_fail (version != NULL, FALSE);
       
   361   g_return_val_if_fail (license != NULL, FALSE);
       
   362   g_return_val_if_fail (source != NULL, FALSE);
       
   363   g_return_val_if_fail (package != NULL, FALSE);
       
   364   g_return_val_if_fail (origin != NULL, FALSE);
       
   365 
       
   366   /* make sure gst_init() has been called */
       
   367   g_return_val_if_fail (_gst_plugin_inited != FALSE, FALSE);
       
   368 
       
   369   GST_LOG ("attempting to load static plugin \"%s\" now...", name);
       
   370   plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
       
   371   if (gst_plugin_register_func (plugin, &desc, user_data) != NULL) {
   278     GST_INFO ("registered static plugin \"%s\"", name);
   372     GST_INFO ("registered static plugin \"%s\"", name);
   279     res = gst_default_registry_add_plugin (plugin);
   373     res = gst_default_registry_add_plugin (plugin);
   280     GST_INFO ("added static plugin \"%s\", result: %d", name, res);
   374     GST_INFO ("added static plugin \"%s\", result: %d", name, res);
   281   }
   375   }
   282   return res;
   376   return res;
   340 
   434 
   341   return TRUE;
   435   return TRUE;
   342 }
   436 }
   343 
   437 
   344 static GstPlugin *
   438 static GstPlugin *
   345 gst_plugin_register_func (GstPlugin * plugin, const GstPluginDesc * desc)
   439 gst_plugin_register_func (GstPlugin * plugin, const GstPluginDesc * desc,
       
   440     gpointer user_data)
   346 {
   441 {
   347   if (!gst_plugin_check_version (desc->major_version, desc->minor_version)) {
   442   if (!gst_plugin_check_version (desc->major_version, desc->minor_version)) {
   348     if (GST_CAT_DEFAULT)
   443     if (GST_CAT_DEFAULT)
   349       GST_WARNING ("plugin \"%s\" has incompatible version, not loading",
   444       GST_WARNING ("plugin \"%s\" has incompatible version, not loading",
   350           plugin->filename);
   445           plugin->filename);
   369   if (GST_CAT_DEFAULT)
   464   if (GST_CAT_DEFAULT)
   370     GST_LOG ("plugin \"%s\" looks good", GST_STR_NULL (plugin->filename));
   465     GST_LOG ("plugin \"%s\" looks good", GST_STR_NULL (plugin->filename));
   371 
   466 
   372   gst_plugin_desc_copy (&plugin->desc, desc);
   467   gst_plugin_desc_copy (&plugin->desc, desc);
   373 
   468 
   374   if (!((desc->plugin_init) (plugin))) {
   469   if (user_data) {
   375     if (GST_CAT_DEFAULT)
   470     if (!(((GstPluginInitFullFunc) (desc->plugin_init)) (plugin, user_data))) {
   376       GST_WARNING ("plugin \"%s\" failed to initialise", plugin->filename);
   471       if (GST_CAT_DEFAULT)
   377     plugin->module = NULL;
   472         GST_WARNING ("plugin \"%s\" failed to initialise", plugin->filename);
   378     return NULL;
   473       plugin->module = NULL;
       
   474       return NULL;
       
   475     }
       
   476   } else {
       
   477     if (!((desc->plugin_init) (plugin))) {
       
   478       if (GST_CAT_DEFAULT)
       
   479         GST_WARNING ("plugin \"%s\" failed to initialise", plugin->filename);
       
   480       plugin->module = NULL;
       
   481       return NULL;
       
   482     }
   379   }
   483   }
   380 
   484 
   381   if (GST_CAT_DEFAULT)
   485   if (GST_CAT_DEFAULT)
   382     GST_LOG ("plugin \"%s\" initialised", GST_STR_NULL (plugin->filename));
   486     GST_LOG ("plugin \"%s\" initialised", GST_STR_NULL (plugin->filename));
   383 
   487 
   384   return plugin;
   488   return plugin;
   385 }
   489 }
   386 
   490 
   387 #ifdef HAVE_SIGACTION
   491 #ifdef HAVE_SIGACTION
   388 static struct sigaction oldaction;
   492 static struct sigaction oldaction;
       
   493 static gboolean _gst_plugin_fault_handler_is_setup = FALSE;
   389 
   494 
   390 /*
   495 /*
   391  * _gst_plugin_fault_handler_restore:
   496  * _gst_plugin_fault_handler_restore:
   392  * segfault handler restorer
   497  * segfault handler restorer
   393  */
   498  */
   449   memset (&action, 0, sizeof (action));
   554   memset (&action, 0, sizeof (action));
   450   action.sa_handler = _gst_plugin_fault_handler_sighandler;
   555   action.sa_handler = _gst_plugin_fault_handler_sighandler;
   451 
   556 
   452   sigaction (SIGSEGV, &action, &oldaction);
   557   sigaction (SIGSEGV, &action, &oldaction);
   453 }
   558 }
   454 #else
   559 #else /* !HAVE_SIGACTION */
   455 static void
   560 static void
   456 _gst_plugin_fault_handler_restore (void)
   561 _gst_plugin_fault_handler_restore (void)
   457 {
   562 {
   458 }
   563 }
   459 
   564 
   460 static void
   565 static void
   461 _gst_plugin_fault_handler_setup (void)
   566 _gst_plugin_fault_handler_setup (void)
   462 {
   567 {
   463 }
   568 }
   464 #endif
   569 #endif /* HAVE_SIGACTION */
   465 
   570 
   466 static void _gst_plugin_fault_handler_setup ();
   571 static void _gst_plugin_fault_handler_setup ();
   467 
   572 
   468 static GStaticMutex gst_plugin_loading_mutex = G_STATIC_MUTEX_INIT;
   573 static GStaticMutex gst_plugin_loading_mutex = G_STATIC_MUTEX_INIT;
       
   574 
       
   575 #define CHECK_PLUGIN_DESC_FIELD(desc,field,fn)                               \
       
   576   if (G_UNLIKELY ((desc)->field == NULL)) {                                  \
       
   577     GST_ERROR ("GstPluginDesc for '%s' has no %s", fn, G_STRINGIFY (field)); \
       
   578   }
   469 
   579 
   470 /**
   580 /**
   471  * gst_plugin_load_file:
   581  * gst_plugin_load_file:
   472  * @filename: the plugin filename to load
   582  * @filename: the plugin filename to load
   473  * @error: pointer to a NULL-valued GError
   583  * @error: pointer to a NULL-valued GError
   488   GModule *module;
   598   GModule *module;
   489   gboolean ret;
   599   gboolean ret;
   490   gpointer ptr;
   600   gpointer ptr;
   491   struct stat file_status;
   601   struct stat file_status;
   492   GstRegistry *registry;
   602   GstRegistry *registry;
       
   603   gboolean new_plugin = TRUE;
   493    #ifdef __SYMBIAN32__
   604    #ifdef __SYMBIAN32__
   494    GstPluginDesc* (*fn)(void)=NULL;
   605    GstPluginDesc* (*fn)(void)=NULL;
   495    void *temp;
   606    void *temp;
   496    
   607    
   497    #endif
   608    #endif
   502   g_static_mutex_lock (&gst_plugin_loading_mutex);
   613   g_static_mutex_lock (&gst_plugin_loading_mutex);
   503 
   614 
   504   plugin = gst_registry_lookup (registry, filename);
   615   plugin = gst_registry_lookup (registry, filename);
   505   if (plugin) {
   616   if (plugin) {
   506     if (plugin->module) {
   617     if (plugin->module) {
       
   618       /* already loaded */
   507       g_static_mutex_unlock (&gst_plugin_loading_mutex);
   619       g_static_mutex_unlock (&gst_plugin_loading_mutex);
   508       return plugin;
   620       return plugin;
   509     } else {
   621     } else {
   510       gst_object_unref (plugin);
   622       /* load plugin and update fields */
   511       plugin = NULL;
   623       new_plugin = FALSE;
   512     }
   624     }
   513   }
   625   }
   514 
   626 
   515   GST_CAT_DEBUG (GST_CAT_PLUGIN_LOADING, "attempt to load plugin \"%s\"",
   627   GST_CAT_DEBUG (GST_CAT_PLUGIN_LOADING, "attempt to load plugin \"%s\"",
   516       filename);
   628       filename);
   544      * message in this case. */
   656      * message in this case. */
   545     g_warning ("Failed to load plugin '%s': %s", filename, g_module_error ());
   657     g_warning ("Failed to load plugin '%s': %s", filename, g_module_error ());
   546     goto return_error;
   658     goto return_error;
   547   }
   659   }
   548 
   660 
   549   plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
   661   if (new_plugin) {
   550 
   662     plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
       
   663     plugin->file_mtime = file_status.st_mtime;
       
   664     plugin->file_size = file_status.st_size;
       
   665     plugin->filename = g_strdup (filename);
       
   666     plugin->basename = g_path_get_basename (filename);
       
   667   }
   551   plugin->module = module;
   668   plugin->module = module;
   552   plugin->filename = g_strdup (filename);
       
   553   plugin->basename = g_path_get_basename (filename);
       
   554   plugin->file_mtime = file_status.st_mtime;
       
   555   plugin->file_size = file_status.st_size;
       
   556 
   669 
   557 #ifdef __SYMBIAN32__
   670 #ifdef __SYMBIAN32__
   558    ret = g_module_symbol (module, "1", &ptr);
   671    ret = g_module_symbol (module, "1", &ptr);
   559 #else   
   672 #else   
   560   ret = g_module_symbol (module, "gst_plugin_desc", &ptr);
   673   ret = g_module_symbol (module, "gst_plugin_desc", &ptr);
   573    temp=fn();
   686    temp=fn();
   574    plugin->orig_desc = (GstPluginDesc *) temp;
   687    plugin->orig_desc = (GstPluginDesc *) temp;
   575    #else
   688    #else
   576   plugin->orig_desc = (GstPluginDesc *) ptr;
   689   plugin->orig_desc = (GstPluginDesc *) ptr;
   577    #endif
   690    #endif
       
   691   if (new_plugin) {
       
   692     /* check plugin description: complain about bad values but accept them, to
       
   693      * maintain backwards compatibility (FIXME: 0.11) */
       
   694     CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, name, filename);
       
   695     CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, description, filename);
       
   696     CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, version, filename);
       
   697     CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, license, filename);
       
   698     CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, source, filename);
       
   699     CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, package, filename);
       
   700     CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, origin, filename);
       
   701   } else {
       
   702     /* this is overwritten by gst_plugin_register_func() */
       
   703     g_free (plugin->desc.description);
       
   704   }
   578 
   705 
   579   GST_LOG ("Plugin %p for file \"%s\" prepared, calling entry function...",
   706   GST_LOG ("Plugin %p for file \"%s\" prepared, calling entry function...",
   580       plugin, filename);
   707       plugin, filename);
   581 
   708 
   582   /* this is where we load the actual .so, so let's trap SIGSEGV */
   709   /* this is where we load the actual .so, so let's trap SIGSEGV */
   584   _gst_plugin_fault_handler_filename = plugin->filename;
   711   _gst_plugin_fault_handler_filename = plugin->filename;
   585 
   712 
   586   GST_LOG ("Plugin %p for file \"%s\" prepared, registering...",
   713   GST_LOG ("Plugin %p for file \"%s\" prepared, registering...",
   587       plugin, filename);
   714       plugin, filename);
   588 
   715 
   589   if (!gst_plugin_register_func (plugin, plugin->orig_desc)) {
   716   if (!gst_plugin_register_func (plugin, plugin->orig_desc, NULL)) {
   590     /* remove signal handler */
   717     /* remove signal handler */
   591     _gst_plugin_fault_handler_restore ();
   718     _gst_plugin_fault_handler_restore ();
   592     GST_DEBUG ("gst_plugin_register_func failed for plugin \"%s\"", filename);
   719     GST_DEBUG ("gst_plugin_register_func failed for plugin \"%s\"", filename);
   593     /* plugin == NULL */
   720     /* plugin == NULL */
   594     g_set_error (error,
   721     g_set_error (error,
   603   /* remove signal handler */
   730   /* remove signal handler */
   604   _gst_plugin_fault_handler_restore ();
   731   _gst_plugin_fault_handler_restore ();
   605   _gst_plugin_fault_handler_filename = NULL;
   732   _gst_plugin_fault_handler_filename = NULL;
   606   GST_INFO ("plugin \"%s\" loaded", plugin->filename);
   733   GST_INFO ("plugin \"%s\" loaded", plugin->filename);
   607 
   734 
   608   gst_object_ref (plugin);
   735   if (new_plugin) {
   609   gst_default_registry_add_plugin (plugin);
   736     gst_object_ref (plugin);
       
   737     gst_default_registry_add_plugin (plugin);
       
   738   }
   610 
   739 
   611   g_static_mutex_unlock (&gst_plugin_loading_mutex);
   740   g_static_mutex_unlock (&gst_plugin_loading_mutex);
   612   return plugin;
   741   return plugin;
   613 
   742 
   614 return_error:
   743 return_error:
   844   g_return_val_if_fail (plugin != NULL, FALSE);
   973   g_return_val_if_fail (plugin != NULL, FALSE);
   845 
   974 
   846   return (plugin->module != NULL || plugin->filename == NULL);
   975   return (plugin->module != NULL || plugin->filename == NULL);
   847 }
   976 }
   848 
   977 
       
   978 /**
       
   979  * gst_plugin_get_cache_data:
       
   980  * @plugin: a plugin
       
   981  *
       
   982  * Gets the plugin specific data cache. If it is %NULL there is no cached data
       
   983  * stored. This is the case when the registry is getting rebuild.
       
   984  *
       
   985  * Returns: The cached data as a #GstStructure or %NULL.
       
   986  *
       
   987  * Since: 0.10.24
       
   988  */
       
   989 #ifdef __SYMBIAN32__
       
   990 EXPORT_C
       
   991 #endif
       
   992 
       
   993 G_CONST_RETURN GstStructure *
       
   994 gst_plugin_get_cache_data (GstPlugin * plugin)
       
   995 {
       
   996   g_return_val_if_fail (GST_IS_PLUGIN (plugin), NULL);
       
   997 
       
   998   return plugin->priv->cache_data;
       
   999 }
       
  1000 
       
  1001 /**
       
  1002  * gst_plugin_set_cache_data:
       
  1003  * @plugin: a plugin
       
  1004  * @cache_data: a structure containing the data to cache
       
  1005  *
       
  1006  * Adds plugin specific data to cache. Passes the ownership of the structure to
       
  1007  * the @plugin.
       
  1008  *
       
  1009  * The cache is flushed every time the registry is rebuild.
       
  1010  *
       
  1011  * Since: 0.10.24
       
  1012  */
       
  1013 #ifdef __SYMBIAN32__
       
  1014 EXPORT_C
       
  1015 #endif
       
  1016 
       
  1017 void
       
  1018 gst_plugin_set_cache_data (GstPlugin * plugin, GstStructure * cache_data)
       
  1019 {
       
  1020   g_return_if_fail (GST_IS_PLUGIN (plugin));
       
  1021   g_return_if_fail (GST_IS_STRUCTURE (cache_data));
       
  1022 
       
  1023   if (plugin->priv->cache_data) {
       
  1024     gst_structure_free (plugin->priv->cache_data);
       
  1025   }
       
  1026   plugin->priv->cache_data = cache_data;
       
  1027 }
       
  1028 
   849 #if 0
  1029 #if 0
   850 /**
  1030 /**
   851  * gst_plugin_feature_list:
  1031  * gst_plugin_feature_list:
   852  * @plugin: plugin to query
  1032  * @plugin: plugin to query
   853  * @filter: the filter to use
  1033  * @filter: the filter to use
  1130   for (g = list; g; g = g->next) {
  1310   for (g = list; g; g = g->next) {
  1131     gst_object_unref (GST_PLUGIN_CAST (g->data));
  1311     gst_object_unref (GST_PLUGIN_CAST (g->data));
  1132   }
  1312   }
  1133   g_list_free (list);
  1313   g_list_free (list);
  1134 }
  1314 }
       
  1315 
       
  1316 /* ===== plugin dependencies ===== */
       
  1317 
       
  1318 /* Scenarios:
       
  1319  * ENV + xyz     where ENV can contain multiple values separated by SEPARATOR
       
  1320  *               xyz may be "" (if ENV contains path to file rather than dir)
       
  1321  * ENV + *xyz   same as above, but xyz acts as suffix filter
       
  1322  * ENV + xyz*   same as above, but xyz acts as prefix filter (is this needed?)
       
  1323  * ENV + *xyz*  same as above, but xyz acts as strstr filter (is this needed?)
       
  1324  * 
       
  1325  * same as above, with additional paths hard-coded at compile-time:
       
  1326  *   - only check paths + ... if ENV is not set or yields not paths
       
  1327  *   - always check paths + ... in addition to ENV
       
  1328  *
       
  1329  * When user specifies set of environment variables, he/she may also use e.g.
       
  1330  * "HOME/.mystuff/plugins", and we'll expand the content of $HOME with the
       
  1331  * remainder 
       
  1332  */
       
  1333 
       
  1334 /* we store in registry:
       
  1335  *  sets of:
       
  1336  *   { 
       
  1337  *     - environment variables (array of strings)
       
  1338  *     - last hash of env variable contents (uint) (so we can avoid doing stats
       
  1339  *       if one of the env vars has changed; premature optimisation galore)
       
  1340  *     - hard-coded paths (array of strings)
       
  1341  *     - xyz filename/suffix/prefix strings (array of strings)
       
  1342  *     - flags (int)
       
  1343  *     - last hash of file/dir stats (int)
       
  1344  *   }
       
  1345  *   (= struct GstPluginDep)
       
  1346  */
       
  1347 
       
  1348 static guint
       
  1349 gst_plugin_ext_dep_get_env_vars_hash (GstPlugin * plugin, GstPluginDep * dep)
       
  1350 {
       
  1351   gchar **e;
       
  1352   guint hash;
       
  1353 
       
  1354   /* there's no deeper logic to what we do here; all we want to know (when
       
  1355    * checking if the plugin needs to be rescanned) is whether the content of
       
  1356    * one of the environment variables in the list is different from when it
       
  1357    * was last scanned */
       
  1358   hash = 0;
       
  1359   for (e = dep->env_vars; e != NULL && *e != NULL; ++e) {
       
  1360     const gchar *val;
       
  1361     gchar env_var[256];
       
  1362 
       
  1363     /* order matters: "val",NULL needs to yield a different hash than
       
  1364      * NULL,"val", so do a shift here whether the var is set or not */
       
  1365     hash = hash << 5;
       
  1366 
       
  1367     /* want environment variable at beginning of string */
       
  1368     if (!g_ascii_isalnum (**e)) {
       
  1369       GST_WARNING_OBJECT (plugin, "string prefix is not a valid environment "
       
  1370           "variable string: %s", *e);
       
  1371       continue;
       
  1372     }
       
  1373 
       
  1374     /* user is allowed to specify e.g. "HOME/.pitivi/plugins" */
       
  1375     g_strlcpy (env_var, *e, sizeof (env_var));
       
  1376     g_strdelimit (env_var, "/\\", '\0');
       
  1377 
       
  1378     if ((val = g_getenv (env_var)))
       
  1379       hash += g_str_hash (val);
       
  1380   }
       
  1381 
       
  1382   return hash;
       
  1383 }
       
  1384 #ifdef __SYMBIAN32__
       
  1385 EXPORT_C
       
  1386 #endif
       
  1387 
       
  1388 
       
  1389 gboolean
       
  1390 _priv_plugin_deps_env_vars_changed (GstPlugin * plugin)
       
  1391 {
       
  1392   GList *l;
       
  1393 
       
  1394   for (l = plugin->priv->deps; l != NULL; l = l->next) {
       
  1395     GstPluginDep *dep = l->data;
       
  1396 
       
  1397     if (dep->env_hash != gst_plugin_ext_dep_get_env_vars_hash (plugin, dep))
       
  1398       return TRUE;
       
  1399   }
       
  1400 
       
  1401   return FALSE;
       
  1402 }
       
  1403 
       
  1404 static GList *
       
  1405 gst_plugin_ext_dep_extract_env_vars_paths (GstPlugin * plugin,
       
  1406     GstPluginDep * dep)
       
  1407 {
       
  1408   gchar **evars;
       
  1409   GList *paths = NULL;
       
  1410 
       
  1411   for (evars = dep->env_vars; evars != NULL && *evars != NULL; ++evars) {
       
  1412     const gchar *e;
       
  1413     gchar **components;
       
  1414 
       
  1415     /* want environment variable at beginning of string */
       
  1416     if (!g_ascii_isalnum (**evars)) {
       
  1417       GST_WARNING_OBJECT (plugin, "string prefix is not a valid environment "
       
  1418           "variable string: %s", *evars);
       
  1419       continue;
       
  1420     }
       
  1421 
       
  1422     /* user is allowed to specify e.g. "HOME/.pitivi/plugins", which we want to
       
  1423      * split into the env_var name component and the path component */
       
  1424     components = g_strsplit_set (*evars, "/\\", 2);
       
  1425     g_assert (components != NULL);
       
  1426 
       
  1427     e = g_getenv (components[0]);
       
  1428     GST_LOG_OBJECT (plugin, "expanding %s = '%s' (path suffix: %s)",
       
  1429         components[0], GST_STR_NULL (e), GST_STR_NULL (components[1]));
       
  1430 
       
  1431     if (components[1] != NULL) {
       
  1432       g_strdelimit (components[1], "/\\", G_DIR_SEPARATOR);
       
  1433     }
       
  1434 
       
  1435     if (e != NULL && *e != '\0') {
       
  1436       gchar **arr;
       
  1437       guint i;
       
  1438 
       
  1439       arr = g_strsplit (e, G_SEARCHPATH_SEPARATOR_S, -1);
       
  1440 
       
  1441       for (i = 0; arr != NULL && arr[i] != NULL; ++i) {
       
  1442         gchar *full_path;
       
  1443 
       
  1444         if (!g_path_is_absolute (arr[i])) {
       
  1445           GST_INFO_OBJECT (plugin, "ignoring environment variable content '%s'"
       
  1446               ": either not an absolute path or not a path at all", arr[i]);
       
  1447           continue;
       
  1448         }
       
  1449 
       
  1450         if (components[1] != NULL) {
       
  1451           full_path = g_build_filename (arr[i], components[1], NULL);
       
  1452         } else {
       
  1453           full_path = g_strdup (arr[i]);
       
  1454         }
       
  1455 
       
  1456         if (!g_list_find_custom (paths, full_path, (GCompareFunc) strcmp)) {
       
  1457           GST_LOG_OBJECT (plugin, "path: '%s'", full_path);
       
  1458           paths = g_list_prepend (paths, full_path);
       
  1459           full_path = NULL;
       
  1460         } else {
       
  1461           GST_LOG_OBJECT (plugin, "path: '%s' (duplicate,ignoring)", full_path);
       
  1462           g_free (full_path);
       
  1463         }
       
  1464       }
       
  1465 
       
  1466       g_strfreev (arr);
       
  1467     }
       
  1468 
       
  1469     g_strfreev (components);
       
  1470   }
       
  1471 
       
  1472   GST_LOG_OBJECT (plugin, "Extracted %d paths from environment",
       
  1473       g_list_length (paths));
       
  1474 
       
  1475   return paths;
       
  1476 }
       
  1477 
       
  1478 static guint
       
  1479 gst_plugin_ext_dep_get_hash_from_stat_entry (struct stat *s)
       
  1480 {
       
  1481   if (!(s->st_mode & (S_IFDIR | S_IFREG)))
       
  1482     return (guint) - 1;
       
  1483 
       
  1484   /* completely random formula */
       
  1485   return ((s->st_size << 3) + (s->st_mtime << 5)) ^ s->st_ctime;
       
  1486 }
       
  1487 
       
  1488 static gboolean
       
  1489 gst_plugin_ext_dep_direntry_matches (GstPlugin * plugin, const gchar * entry,
       
  1490     const gchar ** filenames, GstPluginDependencyFlags flags)
       
  1491 {
       
  1492   /* no filenames specified, match all entries for now (could probably
       
  1493    * optimise by just taking the dir stat hash or so) */
       
  1494   if (filenames == NULL || *filenames == NULL || **filenames == '\0')
       
  1495     return TRUE;
       
  1496 
       
  1497   while (*filenames != NULL) {
       
  1498     /* suffix match? */
       
  1499     if (((flags & GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX)) &&
       
  1500         g_str_has_suffix (entry, *filenames)) {
       
  1501       return TRUE;
       
  1502       /* else it's an exact match that's needed */
       
  1503     } else if (strcmp (entry, *filenames) == 0) {
       
  1504       return TRUE;
       
  1505     }
       
  1506     GST_LOG ("%s does not match %s, flags=0x%04x", entry, *filenames, flags);
       
  1507     ++filenames;
       
  1508   }
       
  1509   return FALSE;
       
  1510 }
       
  1511 
       
  1512 static guint
       
  1513 gst_plugin_ext_dep_scan_dir_and_match_names (GstPlugin * plugin,
       
  1514     const gchar * path, const gchar ** filenames,
       
  1515     GstPluginDependencyFlags flags, int depth)
       
  1516 {
       
  1517   const gchar *entry;
       
  1518   gboolean recurse_dirs;
       
  1519   GError *err = NULL;
       
  1520   GDir *dir;
       
  1521   guint hash = 0;
       
  1522 
       
  1523   recurse_dirs = !!(flags & GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
       
  1524 
       
  1525   dir = g_dir_open (path, 0, &err);
       
  1526   if (dir == NULL) {
       
  1527     GST_DEBUG_OBJECT (plugin, "g_dir_open(%s) failed: %s", path, err->message);
       
  1528     g_error_free (err);
       
  1529     return (guint) - 1;
       
  1530   }
       
  1531 
       
  1532   /* FIXME: we're assuming here that we always get the directory entries in
       
  1533    * the same order, and not in a random order */
       
  1534   while ((entry = g_dir_read_name (dir))) {
       
  1535     gboolean have_match;
       
  1536     struct stat s;
       
  1537     gchar *full_path;
       
  1538     guint fhash;
       
  1539 
       
  1540     have_match =
       
  1541         gst_plugin_ext_dep_direntry_matches (plugin, entry, filenames, flags);
       
  1542 
       
  1543     /* avoid the stat if possible */
       
  1544     if (!have_match && !recurse_dirs)
       
  1545       continue;
       
  1546 
       
  1547     full_path = g_build_filename (path, entry, NULL);
       
  1548     if (g_stat (full_path, &s) < 0) {
       
  1549       fhash = (guint) - 1;
       
  1550       GST_LOG_OBJECT (plugin, "stat: %s (error: %s)", full_path,
       
  1551           g_strerror (errno));
       
  1552     } else if (have_match) {
       
  1553       fhash = gst_plugin_ext_dep_get_hash_from_stat_entry (&s);
       
  1554       GST_LOG_OBJECT (plugin, "stat: %s (result: %u)", full_path, fhash);
       
  1555     } else if ((s.st_mode & (S_IFDIR))) {
       
  1556       fhash = gst_plugin_ext_dep_scan_dir_and_match_names (plugin, full_path,
       
  1557           filenames, flags, depth + 1);
       
  1558     } else {
       
  1559       /* it's not a name match, we want to recurse, but it's not a directory */
       
  1560       g_free (full_path);
       
  1561       continue;
       
  1562     }
       
  1563 
       
  1564     hash = (hash + fhash) << 1;
       
  1565     g_free (full_path);
       
  1566   }
       
  1567 
       
  1568   g_dir_close (dir);
       
  1569   return hash;
       
  1570 }
       
  1571 
       
  1572 static guint
       
  1573 gst_plugin_ext_dep_scan_path_with_filenames (GstPlugin * plugin,
       
  1574     const gchar * path, const gchar ** filenames,
       
  1575     GstPluginDependencyFlags flags)
       
  1576 {
       
  1577   const gchar *empty_filenames[] = { "", NULL };
       
  1578   gboolean recurse_into_dirs, partial_names;
       
  1579   guint i, hash = 0;
       
  1580 
       
  1581   /* to avoid special-casing below (FIXME?) */
       
  1582   if (filenames == NULL || *filenames == NULL)
       
  1583     filenames = empty_filenames;
       
  1584 
       
  1585   recurse_into_dirs = !!(flags & GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
       
  1586   partial_names = !!(flags & GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX);
       
  1587 
       
  1588   /* if we can construct the exact paths to check with the data we have, just
       
  1589    * stat them one by one; this is more efficient than opening the directory
       
  1590    * and going through each entry to see if it matches one of our filenames. */
       
  1591   if (!recurse_into_dirs && !partial_names) {
       
  1592     for (i = 0; filenames[i] != NULL; ++i) {
       
  1593       struct stat s;
       
  1594       gchar *full_path;
       
  1595       guint fhash;
       
  1596 
       
  1597       full_path = g_build_filename (path, filenames[i], NULL);
       
  1598       if (g_stat (full_path, &s) < 0) {
       
  1599         fhash = (guint) - 1;
       
  1600         GST_LOG_OBJECT (plugin, "stat: %s (error: %s)", full_path,
       
  1601             g_strerror (errno));
       
  1602       } else {
       
  1603         fhash = gst_plugin_ext_dep_get_hash_from_stat_entry (&s);
       
  1604         GST_LOG_OBJECT (plugin, "stat: %s (result: %08x)", full_path, fhash);
       
  1605       }
       
  1606       hash = (hash + fhash) << 1;
       
  1607       g_free (full_path);
       
  1608     }
       
  1609   } else {
       
  1610     hash = gst_plugin_ext_dep_scan_dir_and_match_names (plugin, path,
       
  1611         filenames, flags, 0);
       
  1612   }
       
  1613 
       
  1614   return hash;
       
  1615 }
       
  1616 
       
  1617 static guint
       
  1618 gst_plugin_ext_dep_get_stat_hash (GstPlugin * plugin, GstPluginDep * dep)
       
  1619 {
       
  1620   gboolean paths_are_default_only;
       
  1621   GList *scan_paths;
       
  1622   guint scan_hash = 0;
       
  1623 
       
  1624   GST_LOG_OBJECT (plugin, "start");
       
  1625 
       
  1626   paths_are_default_only =
       
  1627       dep->flags & GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY;
       
  1628 
       
  1629   scan_paths = gst_plugin_ext_dep_extract_env_vars_paths (plugin, dep);
       
  1630 
       
  1631   if (scan_paths == NULL || !paths_are_default_only) {
       
  1632     gchar **paths;
       
  1633 
       
  1634     for (paths = dep->paths; paths != NULL && *paths != NULL; ++paths) {
       
  1635       const gchar *path = *paths;
       
  1636 
       
  1637       if (!g_list_find_custom (scan_paths, path, (GCompareFunc) strcmp)) {
       
  1638         GST_LOG_OBJECT (plugin, "path: '%s'", path);
       
  1639         scan_paths = g_list_prepend (scan_paths, g_strdup (path));
       
  1640       } else {
       
  1641         GST_LOG_OBJECT (plugin, "path: '%s' (duplicate, ignoring)", path);
       
  1642       }
       
  1643     }
       
  1644   }
       
  1645 
       
  1646   /* not that the order really matters, but it makes debugging easier */
       
  1647   scan_paths = g_list_reverse (scan_paths);
       
  1648 
       
  1649   while (scan_paths != NULL) {
       
  1650     const gchar *path = scan_paths->data;
       
  1651 
       
  1652     scan_hash += gst_plugin_ext_dep_scan_path_with_filenames (plugin, path,
       
  1653         (const gchar **) dep->names, dep->flags);
       
  1654     scan_hash = scan_hash << 1;
       
  1655 
       
  1656     g_free (scan_paths->data);
       
  1657     scan_paths = g_list_delete_link (scan_paths, scan_paths);
       
  1658   }
       
  1659 
       
  1660   GST_LOG_OBJECT (plugin, "done, scan_hash: %08x", scan_hash);
       
  1661   return scan_hash;
       
  1662 }
       
  1663 #ifdef __SYMBIAN32__
       
  1664 EXPORT_C
       
  1665 #endif
       
  1666 
       
  1667 
       
  1668 gboolean
       
  1669 _priv_plugin_deps_files_changed (GstPlugin * plugin)
       
  1670 {
       
  1671   GList *l;
       
  1672 
       
  1673   for (l = plugin->priv->deps; l != NULL; l = l->next) {
       
  1674     GstPluginDep *dep = l->data;
       
  1675 
       
  1676     if (dep->stat_hash != gst_plugin_ext_dep_get_stat_hash (plugin, dep))
       
  1677       return TRUE;
       
  1678   }
       
  1679 
       
  1680   return FALSE;
       
  1681 }
       
  1682 
       
  1683 static void
       
  1684 gst_plugin_ext_dep_free (GstPluginDep * dep)
       
  1685 {
       
  1686   g_strfreev (dep->env_vars);
       
  1687   g_strfreev (dep->paths);
       
  1688   g_strfreev (dep->names);
       
  1689   g_free (dep);
       
  1690 }
       
  1691 
       
  1692 static gboolean
       
  1693 gst_plugin_ext_dep_strv_equal (gchar ** arr1, gchar ** arr2)
       
  1694 {
       
  1695   if (arr1 == arr2)
       
  1696     return TRUE;
       
  1697   if (arr1 == NULL || arr2 == NULL)
       
  1698     return FALSE;
       
  1699   for (; *arr1 != NULL && *arr2 != NULL; ++arr1, ++arr2) {
       
  1700     if (strcmp (*arr1, *arr2) != 0)
       
  1701       return FALSE;
       
  1702   }
       
  1703   return (*arr1 == *arr2);
       
  1704 }
       
  1705 
       
  1706 static gboolean
       
  1707 gst_plugin_ext_dep_equals (GstPluginDep * dep, const gchar ** env_vars,
       
  1708     const gchar ** paths, const gchar ** names, GstPluginDependencyFlags flags)
       
  1709 {
       
  1710   if (dep->flags != flags)
       
  1711     return FALSE;
       
  1712 
       
  1713   return gst_plugin_ext_dep_strv_equal (dep->env_vars, (gchar **) env_vars) &&
       
  1714       gst_plugin_ext_dep_strv_equal (dep->paths, (gchar **) paths) &&
       
  1715       gst_plugin_ext_dep_strv_equal (dep->names, (gchar **) names);
       
  1716 }
       
  1717 
       
  1718 /**
       
  1719  * gst_plugin_add_dependency:
       
  1720  * @plugin: a #GstPlugin
       
  1721  * @env_vars: NULL-terminated array of environent variables affecting the
       
  1722  *     feature set of the plugin (e.g. an environment variable containing
       
  1723  *     paths where to look for additional modules/plugins of a library),
       
  1724  *     or NULL. Environment variable names may be followed by a path component
       
  1725  *      which will be added to the content of the environment variable, e.g.
       
  1726  *      "HOME/.mystuff/plugins".
       
  1727  * @paths: NULL-terminated array of directories/paths where dependent files
       
  1728  *     may be.
       
  1729  * @names: NULL-terminated array of file names (or file name suffixes,
       
  1730  *     depending on @flags) to be used in combination with the paths from
       
  1731  *     @paths and/or the paths extracted from the environment variables in
       
  1732  *     @env_vars, or NULL.
       
  1733  * @flags: optional flags, or #GST_PLUGIN_DEPENDENCY_FLAG_NONE
       
  1734  *
       
  1735  * Make GStreamer aware of external dependencies which affect the feature
       
  1736  * set of this plugin (ie. the elements or typefinders associated with it).
       
  1737  *
       
  1738  * GStreamer will re-inspect plugins with external dependencies whenever any
       
  1739  * of the external dependencies change. This is useful for plugins which wrap
       
  1740  * other plugin systems, e.g. a plugin which wraps a plugin-based visualisation
       
  1741  * library and makes visualisations available as GStreamer elements, or a
       
  1742  * codec loader which exposes elements and/or caps dependent on what external
       
  1743  * codec libraries are currently installed.
       
  1744  *
       
  1745  * Since: 0.10.22
       
  1746  */
       
  1747 #ifdef __SYMBIAN32__
       
  1748 EXPORT_C
       
  1749 #endif
       
  1750 
       
  1751 void
       
  1752 gst_plugin_add_dependency (GstPlugin * plugin, const gchar ** env_vars,
       
  1753     const gchar ** paths, const gchar ** names, GstPluginDependencyFlags flags)
       
  1754 {
       
  1755   GstPluginDep *dep;
       
  1756   GList *l;
       
  1757 
       
  1758   g_return_if_fail (GST_IS_PLUGIN (plugin));
       
  1759   g_return_if_fail (env_vars != NULL || paths != NULL);
       
  1760 
       
  1761   for (l = plugin->priv->deps; l != NULL; l = l->next) {
       
  1762     if (gst_plugin_ext_dep_equals (l->data, env_vars, paths, names, flags)) {
       
  1763       GST_LOG_OBJECT (plugin, "dependency already registered");
       
  1764       return;
       
  1765     }
       
  1766   }
       
  1767 
       
  1768   dep = g_new0 (GstPluginDep, 1);
       
  1769 
       
  1770   dep->env_vars = g_strdupv ((gchar **) env_vars);
       
  1771   dep->paths = g_strdupv ((gchar **) paths);
       
  1772   dep->names = g_strdupv ((gchar **) names);
       
  1773   dep->flags = flags;
       
  1774 
       
  1775   dep->env_hash = gst_plugin_ext_dep_get_env_vars_hash (plugin, dep);
       
  1776   dep->stat_hash = gst_plugin_ext_dep_get_stat_hash (plugin, dep);
       
  1777 
       
  1778   plugin->priv->deps = g_list_append (plugin->priv->deps, dep);
       
  1779 
       
  1780   GST_DEBUG_OBJECT (plugin, "added dependency:");
       
  1781   for (; env_vars != NULL && *env_vars != NULL; ++env_vars)
       
  1782     GST_DEBUG_OBJECT (plugin, " evar: %s", *env_vars);
       
  1783   for (; paths != NULL && *paths != NULL; ++paths)
       
  1784     GST_DEBUG_OBJECT (plugin, " path: %s", *paths);
       
  1785   for (; names != NULL && *names != NULL; ++names)
       
  1786     GST_DEBUG_OBJECT (plugin, " name: %s", *names);
       
  1787 }
       
  1788 
       
  1789 /**
       
  1790  * gst_plugin_add_dependency_simple:
       
  1791  * @plugin: the #GstPlugin
       
  1792  * @env_vars: one or more environent variables (separated by ':', ';' or ','),
       
  1793  *      or NULL. Environment variable names may be followed by a path component
       
  1794  *      which will be added to the content of the environment variable, e.g.
       
  1795  *      "HOME/.mystuff/plugins:MYSTUFF_PLUGINS_PATH"
       
  1796  * @paths: one ore more directory paths (separated by ':' or ';' or ','),
       
  1797  *      or NULL. Example: "/usr/lib/mystuff/plugins"
       
  1798  * @names: one or more file names or file name suffixes (separated by commas),
       
  1799  *   or NULL
       
  1800  * @flags: optional flags, or #GST_PLUGIN_DEPENDENCY_FLAG_NONE
       
  1801  *
       
  1802  * Make GStreamer aware of external dependencies which affect the feature
       
  1803  * set of this plugin (ie. the elements or typefinders associated with it).
       
  1804  *
       
  1805  * GStreamer will re-inspect plugins with external dependencies whenever any
       
  1806  * of the external dependencies change. This is useful for plugins which wrap
       
  1807  * other plugin systems, e.g. a plugin which wraps a plugin-based visualisation
       
  1808  * library and makes visualisations available as GStreamer elements, or a
       
  1809  * codec loader which exposes elements and/or caps dependent on what external
       
  1810  * codec libraries are currently installed.
       
  1811  *
       
  1812  * Convenience wrapper function for gst_plugin_add_dependency() which
       
  1813  * takes simple strings as arguments instead of string arrays, with multiple
       
  1814  * arguments separated by predefined delimiters (see above).
       
  1815  *
       
  1816  * Since: 0.10.22
       
  1817  */
       
  1818 #ifdef __SYMBIAN32__
       
  1819 EXPORT_C
       
  1820 #endif
       
  1821 
       
  1822 void
       
  1823 gst_plugin_add_dependency_simple (GstPlugin * plugin,
       
  1824     const gchar * env_vars, const gchar * paths, const gchar * names,
       
  1825     GstPluginDependencyFlags flags)
       
  1826 {
       
  1827   gchar **a_evars = NULL;
       
  1828   gchar **a_paths = NULL;
       
  1829   gchar **a_names = NULL;
       
  1830 
       
  1831   if (env_vars)
       
  1832     a_evars = g_strsplit_set (env_vars, ":;,", -1);
       
  1833   if (paths)
       
  1834     a_paths = g_strsplit_set (paths, ":;,", -1);
       
  1835   if (names)
       
  1836     a_names = g_strsplit_set (names, ",", -1);
       
  1837 
       
  1838   gst_plugin_add_dependency (plugin, (const gchar **) a_evars,
       
  1839       (const gchar **) a_paths, (const gchar **) a_names, flags);
       
  1840 
       
  1841   if (a_evars)
       
  1842     g_strfreev (a_evars);
       
  1843   if (a_paths)
       
  1844     g_strfreev (a_paths);
       
  1845   if (a_names)
       
  1846     g_strfreev (a_names);
       
  1847 }