tpm gstreamer: gstreamer/ gstreamer/docs/gst/ gstreamer/gst/
[email protected] Tue, 6 Jan 2009 09:59:14 -0800 (PST)
| Newsgroups | gmane.comp.video.gstreamer.cvs |
|---|---|
| Message-ID | <[email protected]> |
--===============0458699594665386790==
CVS Root: /cvs/gstreamer
Module: gstreamer
Changes by: tpm
Date: Tue Jan 06 2009 17:59:14 UTC
Log message:
* docs/gst/gstreamer-sections.txt::
* gst/gst_private.h: (GstPluginDep), (_GstPluginPrivate):
* gst/gstplugin.c: (gst_plugin_init), (gst_plugin_finalize),
(gst_plugin_class_init), (gst_plugin_list_free),
(gst_plugin_ext_dep_get_env_vars_hash),
(_priv_plugin_deps_env_vars_changed),
(gst_plugin_ext_dep_extract_env_vars_paths),
(gst_plugin_ext_dep_get_hash_from_stat_entry),
(gst_plugin_ext_dep_direntry_matches),
(gst_plugin_ext_dep_scan_dir_and_match_names),
(gst_plugin_ext_dep_scan_path_with_filenames),
(gst_plugin_ext_dep_get_stat_hash),
(_priv_plugin_deps_files_changed), (gst_plugin_ext_dep_free),
(gst_plugin_ext_dep_strv_equal), (gst_plugin_ext_dep_equals),
(gst_plugin_add_dependency), (gst_plugin_add_dependency_simple):
* gst/gstplugin.h: (GstPluginPrivate), (GstPluginFlags),
(GST_PLUGIN_DEPENDENCY_FLAG_NONE),
(GST_PLUGIN_DEPENDENCY_FLAG_RECURSE),
(GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY),
(GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX),
(GstPluginDependencyFlags), (GstPluginFilter):
* gst/gstregistry.c: (gst_registry_scan_path_level):
* gst/gstregistrybinary.c: (gst_registry_binary_save_feature),
(gst_registry_binary_save_plugin_dep),
(gst_registry_binary_save_plugin),
(gst_registry_binary_load_feature),
(gst_registry_binary_load_plugin_dep_strv),
(gst_registry_binary_load_plugin_dep),
(gst_registry_binary_load_plugin):
* gst/gstregistrybinary.h: (GST_MAGIC_BINARY_VERSION_STR),
(GstBinaryPluginElement), (_GstBinaryDep), (GstBinaryDep):
* gst/gstregistryxml.c: (gst_registry_xml_save_plugin):
Add API for making a GStreamer plugin 'dependent' on external files,
directories or environment variables, so that GStreamer knows when
it needs to re-load GStreamer plugins that wrap other plugin systems.
Fixes bug #350477.
API: add gst_plugin_add_dependency()
API: add gst_plugin_add_dependency_simple()
Modified files:
. : ChangeLog
docs/gst : gstreamer-sections.txt
gst : gst_private.h gstplugin.c gstplugin.h
gstregistry.c gstregistrybinary.c
gstregistrybinary.h gstregistryxml.c
Links:
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.4215&r2=1.4216
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/docs/gst/gstreamer-sections.txt.diff?r1=1.359&r2=1.360
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gst_private.h.diff?r1=1.42&r2=1.43
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstplugin.c.diff?r1=1.186&r2=1.187
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstplugin.h.diff?r1=1.73&r2=1.74
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstregistry.c.diff?r1=1.85&r2=1.86
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstregistrybinary.c.diff?r1=1.43&r2=1.44
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstregistrybinary.h.diff?r1=1.11&r2=1.12
http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstregistryxml.c.diff?r1=1.43&r2=1.44
====Begin Diffs====
Index: ChangeLog
===================================================================
RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v
retrieving revision 1.4215
retrieving revision 1.4216
diff -u -d -r1.4215 -r1.4216
--- ChangeLog 6 Jan 2009 13:00:09 -0000 1.4215
+++ ChangeLog 6 Jan 2009 17:58:56 -0000 1.4216
@@ -1,5 +1,46 @@
2009-01-06 Tim-Philipp Müller <tim.muller at collabora co uk>
+ * docs/gst/gstreamer-sections.txt::
+ * gst/gst_private.h: (GstPluginDep), (_GstPluginPrivate):
+ * gst/gstplugin.c: (gst_plugin_init), (gst_plugin_finalize),
+ (gst_plugin_class_init), (gst_plugin_list_free),
+ (gst_plugin_ext_dep_get_env_vars_hash),
+ (_priv_plugin_deps_env_vars_changed),
+ (gst_plugin_ext_dep_extract_env_vars_paths),
+ (gst_plugin_ext_dep_get_hash_from_stat_entry),
+ (gst_plugin_ext_dep_direntry_matches),
+ (gst_plugin_ext_dep_scan_dir_and_match_names),
+ (gst_plugin_ext_dep_scan_path_with_filenames),
+ (gst_plugin_ext_dep_get_stat_hash),
+ (_priv_plugin_deps_files_changed), (gst_plugin_ext_dep_free),
+ (gst_plugin_ext_dep_strv_equal), (gst_plugin_ext_dep_equals),
+ (gst_plugin_add_dependency), (gst_plugin_add_dependency_simple):
+ * gst/gstplugin.h: (GstPluginPrivate), (GstPluginFlags),
+ (GST_PLUGIN_DEPENDENCY_FLAG_NONE),
+ (GST_PLUGIN_DEPENDENCY_FLAG_RECURSE),
+ (GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY),
+ (GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX),
+ (GstPluginDependencyFlags), (GstPluginFilter):
+ * gst/gstregistry.c: (gst_registry_scan_path_level):
+ * gst/gstregistrybinary.c: (gst_registry_binary_save_feature),
+ (gst_registry_binary_save_plugin_dep),
+ (gst_registry_binary_save_plugin),
+ (gst_registry_binary_load_feature),
+ (gst_registry_binary_load_plugin_dep_strv),
+ (gst_registry_binary_load_plugin_dep),
+ (gst_registry_binary_load_plugin):
+ * gst/gstregistrybinary.h: (GST_MAGIC_BINARY_VERSION_STR),
+ (GstBinaryPluginElement), (_GstBinaryDep), (GstBinaryDep):
+ * gst/gstregistryxml.c: (gst_registry_xml_save_plugin):
+ Add API for making a GStreamer plugin 'dependent' on external files,
+ directories or environment variables, so that GStreamer knows when
+ it needs to re-load GStreamer plugins that wrap other plugin systems.
+ Fixes bug #350477.
+ API: add gst_plugin_add_dependency()
+ API: add gst_plugin_add_dependency_simple()
+
+2009-01-06 Tim-Philipp Müller <tim.muller at collabora co uk>
* docs/faq/gst-uninstalled:
Add libgstapp-0.10 from -base to search path and remove the old
lib from -bad from the search path.
Index: gstreamer-sections.txt
RCS file: /cvs/gstreamer/gstreamer/docs/gst/gstreamer-sections.txt,v
retrieving revision 1.359
retrieving revision 1.360
diff -u -d -r1.359 -r1.360
--- gstreamer-sections.txt 20 Dec 2008 17:33:42 -0000 1.359
+++ gstreamer-sections.txt 6 Jan 2009 17:58:58 -0000 1.360
@@ -1641,6 +1641,10 @@
gst_plugin_load_by_name
gst_plugin_list_free
gst_plugin_register_static
+<SUBSECTION>
+GstPluginDependencyFlags
+gst_plugin_add_dependency
+gst_plugin_add_dependency_simple
<SUBSECTION Standard>
GstPluginClass
GST_PLUGIN
@@ -1653,6 +1657,9 @@
GST_IS_PLUGIN_CLASS
GstPluginFlags
GST_TYPE_PLUGIN_FLAGS
+GST_TYPE_PLUGIN_DEPENDENCY_FLAGS
+GstPluginPrivate
+gst_plugin_dependency_flags_get_type
<SUBSECTION Private>
gst_plugin_get_type
Index: gst_private.h
RCS file: /cvs/gstreamer/gstreamer/gst/gst_private.h,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -d -r1.42 -r1.43
--- gst_private.h 29 Aug 2008 14:12:02 -0000 1.42
+++ gst_private.h 6 Jan 2009 17:58:58 -0000 1.43
@@ -44,6 +44,9 @@
/* we need this in pretty much all files */
#include "gstinfo.h"
+/* for the flags in the GstPluginDep structure below */
+#include "gstplugin.h"
G_BEGIN_DECLS
/* used by gstparse.c and grammar.y */
@@ -51,6 +54,26 @@
GList * missing_elements;
};
+/* used by gstplugin.c and gstregistrybinary.c */
+typedef struct {
+ /* details registered via gst_plugin_add_dependency() */
+ GstPluginDependencyFlags flags;
+ gchar **env_vars;
+ gchar **paths;
+ gchar **names;
+ /* information saved from the last time the plugin was loaded (-1 = unset) */
+ guint env_hash; /* hash of content of environment variables in env_vars */
+ guint stat_hash; /* hash of stat() on all relevant files and directories */
+} GstPluginDep;
+struct _GstPluginPrivate {
+ GList *deps; /* list of GstPluginDep structures */
+};
+gboolean _priv_plugin_deps_env_vars_changed (GstPlugin * plugin);
+gboolean _priv_plugin_deps_files_changed (GstPlugin * plugin);
gboolean _priv_gst_in_valgrind (void);
/* Initialize GStreamer private quark storage */
Index: gstplugin.c
RCS file: /cvs/gstreamer/gstreamer/gst/gstplugin.c,v
retrieving revision 1.186
retrieving revision 1.187
diff -u -d -r1.186 -r1.187
--- gstplugin.c 15 Jul 2008 22:52:59 -0000 1.186
+++ gstplugin.c 6 Jan 2009 17:58:59 -0000 1.187
@@ -109,13 +109,15 @@
const GstPluginDesc * src);
static void gst_plugin_desc_free (GstPluginDesc * desc);
+static void gst_plugin_ext_dep_free (GstPluginDep * dep);
G_DEFINE_TYPE (GstPlugin, gst_plugin, GST_TYPE_OBJECT);
static void
gst_plugin_init (GstPlugin * plugin)
{
- /* do nothing, needed because of G_DEFINE_TYPE */
+ plugin->priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (plugin, GST_TYPE_PLUGIN, GstPluginPrivate);
}
@@ -135,6 +137,10 @@
g_free (plugin->basename);
gst_plugin_desc_free (&plugin->desc);
+ g_list_foreach (plugin->priv->deps, (GFunc) gst_plugin_ext_dep_free, NULL);
+ g_list_free (plugin->priv->deps);
+ plugin->priv->deps = NULL;
G_OBJECT_CLASS (gst_plugin_parent_class)->finalize (object);
@@ -142,6 +148,8 @@
gst_plugin_class_init (GstPluginClass * klass)
G_OBJECT_CLASS (klass)->finalize = GST_DEBUG_FUNCPTR (gst_plugin_finalize);
+ g_type_class_add_private (klass, sizeof (GstPluginPrivate));
GQuark
@@ -1032,3 +1040,520 @@
}
g_list_free (list);
+/* ===== plugin dependencies ===== */
+/* Scenarios:
+ * ENV + xyz where ENV can contain multiple values separated by SEPARATOR
+ * xyz may be "" (if ENV contains path to file rather than dir)
+ * ENV + *xyz same as above, but xyz acts as suffix filter
+ * ENV + xyz* same as above, but xyz acts as prefix filter (is this needed?)
+ * ENV + *xyz* same as above, but xyz acts as strstr filter (is this needed?)
+ *
+ * same as above, with additional paths hard-coded at compile-time:
+ * - only check paths + ... if ENV is not set or yields not paths
+ * - always check paths + ... in addition to ENV
+ *
+ * When user specifies set of environment variables, he/she may also use e.g.
+ * "HOME/.mystuff/plugins", and we'll expand the content of $HOME with the
+ * remainder
+ */
+/* we store in registry:
+ * sets of:
+ * {
+ * - environment variables (array of strings)
+ * - last hash of env variable contents (uint) (so we can avoid doing stats
+ * if one of the env vars has changed; premature optimisation galore)
+ * - hard-coded paths (array of strings)
+ * - xyz filename/suffix/prefix strings (array of strings)
+ * - flags (int)
+ * - last hash of file/dir stats (int)
+ * }
+ * (= struct GstPluginDep)
+static guint
+gst_plugin_ext_dep_get_env_vars_hash (GstPlugin * plugin, GstPluginDep * dep)
+{
+ gchar **e;
+ guint hash;
+ /* there's no deeper logic to what we do here; all we want to know (when
+ * checking if the plugin needs to be rescanned) is whether the content of
+ * one of the environment variables in the list is different from when it
+ * was last scanned */
+ hash = 0;
+ for (e = dep->env_vars; e != NULL && *e != NULL; ++e) {
+ const gchar *val;
+ gchar env_var[256];
+ /* order matters: "val",NULL needs to yield a different hash than
+ * NULL,"val", so do a shift here whether the var is set or not */
+ hash = hash << 5;
+ /* want environment variable at beginning of string */
+ if (!g_ascii_isalnum (**e)) {
+ GST_WARNING_OBJECT (plugin, "string prefix is not a valid environment "
+ "variable string: %s", *e);
+ continue;
+ }
+ /* user is allowed to specify e.g. "HOME/.pitivi/plugins" */
+ g_strlcpy (env_var, *e, sizeof (env_var));
+ g_strdelimit (env_var, "/\\", '\0');
+ if ((val = g_getenv (env_var)))
+ hash += g_str_hash (val);
+ }
+ return hash;
+}
+gboolean
+_priv_plugin_deps_env_vars_changed (GstPlugin * plugin)
+ GList *l;
+ for (l = plugin->priv->deps; l != NULL; l = l->next) {
+ GstPluginDep *dep = l->data;
+ if (dep->env_hash != gst_plugin_ext_dep_get_env_vars_hash (plugin, dep))
+ return TRUE;
+ return FALSE;
+static GList *
+gst_plugin_ext_dep_extract_env_vars_paths (GstPlugin * plugin,
+ GstPluginDep * dep)
+ gchar **evars;
+ GList *paths = NULL;
+ for (evars = dep->env_vars; evars != NULL && *evars != NULL; ++evars) {
+ const gchar *e;
+ gchar **components;
+ if (!g_ascii_isalnum (**evars)) {
+ "variable string: %s", *evars);
+ /* user is allowed to specify e.g. "HOME/.pitivi/plugins", which we want to
+ * split into the env_var name component and the path component */
+ components = g_strsplit_set (*evars, "/\\", 2);
+ g_assert (components != NULL);
+ e = g_getenv (components[0]);
+ GST_LOG_OBJECT (plugin, "expanding %s = '%s' (path suffix: %s)",
+ components[0], GST_STR_NULL (e), GST_STR_NULL (components[1]));
+ if (components[1] != NULL) {
+ g_strdelimit (components[1], "/\\", G_DIR_SEPARATOR);
+ if (e != NULL && *e != '\0') {
+ gchar **arr;
+ guint i;
+ arr = g_strsplit (e, G_SEARCHPATH_SEPARATOR_S, -1);
+ for (i = 0; arr != NULL && arr[i] != NULL; ++i) {
+ gchar *full_path;
+ if (!g_path_is_absolute (arr[i])) {
+ GST_INFO_OBJECT (plugin, "ignoring environment variable content '%s'"
+ ": either not an absolute path or not a path at all", arr[i]);
+ continue;
+ }
+ if (components[1] != NULL) {
+ full_path = g_build_filename (arr[i], components[1], NULL);
+ } else {
+ full_path = g_strdup (arr[i]);
+ if (!g_list_find_custom (paths, full_path, (GCompareFunc) strcmp)) {
+ GST_LOG_OBJECT (plugin, "path: '%s'", full_path);
+ paths = g_list_prepend (paths, full_path);
+ full_path = NULL;
+ GST_LOG_OBJECT (plugin, "path: '%s' (duplicate,ignoring)", full_path);
+ g_free (full_path);
+ }
+ g_strfreev (arr);
+ g_strfreev (components);
+ GST_LOG_OBJECT (plugin, "Extracted %d paths from environment",
+ g_list_length (paths));
+ return paths;
+gst_plugin_ext_dep_get_hash_from_stat_entry (struct stat *s)
+ if (!(s->st_mode & (S_IFDIR | S_IFREG)))
+ return (guint) - 1;
+ /* completely random formula */
+ return ((s->st_size << 3) + (s->st_mtime << 5)) ^ s->st_ctime;
+static gboolean
+gst_plugin_ext_dep_direntry_matches (GstPlugin * plugin, const gchar * entry,
+ const gchar ** filenames, GstPluginDependencyFlags flags)
+ /* no filenames specified, match all entries for now (could probably
+ * optimise by just taking the dir stat hash or so) */
+ if (filenames == NULL || *filenames == NULL || **filenames == '\0')
+ return TRUE;
+ while (*filenames != NULL) {
+ /* suffix match? */
+ if (((flags & GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX)) &&
+ g_str_has_suffix (entry, *filenames)) {
+ /* else it's an exact match that's needed */
+ } else if (strcmp (entry, *filenames) == 0) {
+ GST_LOG ("%s does not match %s, flags=0x%04x", entry, *filenames, flags);
+ ++filenames;
+gst_plugin_ext_dep_scan_dir_and_match_names (GstPlugin * plugin,
+ const gchar * path, const gchar ** filenames,
+ GstPluginDependencyFlags flags, int depth)
+ const gchar *entry;
+ gboolean recurse_dirs;
+ GError *err = NULL;
+ GDir *dir;
+ guint hash = 0;
+ recurse_dirs = !!(flags & GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
+ dir = g_dir_open (path, 0, &err);
+ if (dir == NULL) {
+ GST_DEBUG_OBJECT (plugin, "g_dir_open(%s) failed: %s", path, err->message);
+ g_error_free (err);
+ /* FIXME: we're assuming here that we always get the directory entries in
+ * the same order, and not in a random order */
+ while ((entry = g_dir_read_name (dir))) {
+ gboolean have_match;
+ struct stat s;
+ gchar *full_path;
+ guint fhash;
+ have_match =
+ gst_plugin_ext_dep_direntry_matches (plugin, entry, filenames, flags);
+ /* avoid the stat if possible */
+ if (!have_match && !recurse_dirs)
+ full_path = g_build_filename (path, entry, NULL);
+ if (g_stat (full_path, &s) < 0) {
+ fhash = (guint) - 1;
+ GST_LOG_OBJECT (plugin, "stat: %s (error: %s)", full_path,
+ g_strerror (errno));
+ } else if (have_match) {
+ fhash = gst_plugin_ext_dep_get_hash_from_stat_entry (&s);
+ GST_LOG_OBJECT (plugin, "stat: %s (result: %u)", full_path, fhash);
+ } else if ((s.st_mode & (S_IFDIR))) {
+ fhash = gst_plugin_ext_dep_scan_dir_and_match_names (plugin, full_path,
+ filenames, flags, depth + 1);
+ } else {
+ /* it's not a name match, we want to recurse, but it's not a directory */
+ g_free (full_path);
+ hash = (hash + fhash) << 1;
+ g_free (full_path);
+ g_dir_close (dir);
+gst_plugin_ext_dep_scan_path_with_filenames (GstPlugin * plugin,
+ GstPluginDependencyFlags flags)
+ const gchar *empty_filenames[] = { "", NULL };
+ gboolean recurse_into_dirs, partial_names;
+ guint i, hash = 0;
+ /* to avoid special-casing below (FIXME?) */
+ if (filenames == NULL || *filenames == NULL)
+ filenames = empty_filenames;
+ recurse_into_dirs = !!(flags & GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
+ partial_names = !!(flags & GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX);
+ /* if we can construct the exact paths to check with the data we have, just
+ * stat them one by one; this is more efficient than opening the directory
+ * and going through each entry to see if it matches one of our filenames. */
+ if (!recurse_into_dirs && !partial_names) {
+ for (i = 0; filenames[i] != NULL; ++i) {
+ struct stat s;
+ gchar *full_path;
+ guint fhash;
+ full_path = g_build_filename (path, filenames[i], NULL);
+ if (g_stat (full_path, &s) < 0) {
+ fhash = (guint) - 1;
+ GST_LOG_OBJECT (plugin, "stat: %s (error: %s)", full_path,
+ g_strerror (errno));
+ } else {
+ fhash = gst_plugin_ext_dep_get_hash_from_stat_entry (&s);
+ GST_LOG_OBJECT (plugin, "stat: %s (result: %08x)", full_path, fhash);
+ hash = (hash + fhash) << 1;
+ } else {
+ hash = gst_plugin_ext_dep_scan_dir_and_match_names (plugin, path,
+ filenames, flags, 0);
+gst_plugin_ext_dep_get_stat_hash (GstPlugin * plugin, GstPluginDep * dep)
+ gboolean paths_are_default_only;
+ GList *scan_paths;
+ guint scan_hash = 0;
+ GST_LOG_OBJECT (plugin, "start");
+ paths_are_default_only =
+ dep->flags & GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY;
+ scan_paths = gst_plugin_ext_dep_extract_env_vars_paths (plugin, dep);
+ if (scan_paths == NULL || !paths_are_default_only) {
+ gchar **paths;
+ for (paths = dep->paths; paths != NULL && *paths != NULL; ++paths) {
+ const gchar *path = *paths;
+ if (!g_list_find_custom (scan_paths, path, (GCompareFunc) strcmp)) {
+ GST_LOG_OBJECT (plugin, "path: '%s'", path);
+ scan_paths = g_list_prepend (scan_paths, g_strdup (path));
+ GST_LOG_OBJECT (plugin, "path: '%s' (duplicate, ignoring)", path);
+ /* not that the order really matters, but it makes debugging easier */
+ scan_paths = g_list_reverse (scan_paths);
+ while (scan_paths != NULL) {
+ const gchar *path = scan_paths->data;
+ scan_hash += gst_plugin_ext_dep_scan_path_with_filenames (plugin, path,
+ (const gchar **) dep->names, dep->flags);
+ scan_hash = scan_hash << 1;
+ g_free (scan_paths->data);
+ scan_paths = g_list_delete_link (scan_paths, scan_paths);
+ GST_LOG_OBJECT (plugin, "done, scan_hash: %08x", scan_hash);
+ return scan_hash;
+_priv_plugin_deps_files_changed (GstPlugin * plugin)
+ if (dep->stat_hash != gst_plugin_ext_dep_get_stat_hash (plugin, dep))
+static void
+gst_plugin_ext_dep_free (GstPluginDep * dep)
+ g_strfreev (dep->env_vars);
+ g_strfreev (dep->paths);
+ g_strfreev (dep->names);
+ g_free (dep);
+gst_plugin_ext_dep_strv_equal (gchar ** arr1, gchar ** arr2)
+ if (arr1 == arr2)
+ if (arr1 == NULL || arr2 == NULL)
+ return FALSE;
+ for (; *arr1 != NULL && *arr2 != NULL; ++arr1, ++arr2) {
+ if (strcmp (*arr1, *arr2) != 0)
+ return FALSE;
+ return (*arr1 == *arr2);
+gst_plugin_ext_dep_equals (GstPluginDep * dep, const gchar ** env_vars,
+ const gchar ** paths, const gchar ** names, GstPluginDependencyFlags flags)
+ if (dep->flags != flags)
+ return gst_plugin_ext_dep_strv_equal (dep->env_vars, (gchar **) env_vars) &&
+ gst_plugin_ext_dep_strv_equal (dep->paths, (gchar **) paths) &&
+ gst_plugin_ext_dep_strv_equal (dep->names, (gchar **) names);
+/**
+ * gst_plugin_add_dependency:
+ * @plugin: a #GstPlugin
+ * @env_vars: NULL-terminated array of environent variables affecting the
+ * feature set of the plugin (e.g. an environment variable containing
+ * paths where to look for additional modules/plugins of a library),
+ * or NULL. Environment variable names may be followed by a path component
+ * which will be added to the content of the environment variable, e.g.
+ * "HOME/.mystuff/plugins".
+ * @paths: NULL-terminated array of directories/paths where dependent files
+ * may be.
+ * @names: NULL-terminated array of file names (or file name suffixes,
+ * depending on @flags) to be used in combination with the paths from
+ * @paths and/or the paths extracted from the environment variables in
+ * @env_vars, or NULL.
+ * @flags: optional flags, or #GST_PLUGIN_DEPENDENCY_FLAG_NONE
+ * Make GStreamer aware of external dependencies which affect the feature
+ * set of this plugin (ie. the elements or typefinders associated with it).
+ * GStreamer will re-inspect plugins with external dependencies whenever any
+ * of the external dependencies change. This is useful for plugins which wrap
+ * other plugin systems, e.g. a plugin which wraps a plugin-based visualisation
+ * library and makes visualisations available as GStreamer elements, or a
+ * codec loader which exposes elements and/or caps dependent on what external
+ * codec libraries are currently installed.
+ * Since: 0.10.22
+void
+gst_plugin_add_dependency (GstPlugin * plugin, const gchar ** env_vars,
+ GstPluginDep *dep;
+ g_return_if_fail (GST_IS_PLUGIN (plugin));
+ g_return_if_fail (env_vars != NULL || paths != NULL);
+ if (gst_plugin_ext_dep_equals (l->data, env_vars, paths, names, flags)) {
+ GST_LOG_OBJECT (plugin, "dependency already registered");
+ return;
+ dep = g_new0 (GstPluginDep, 1);
+ dep->env_vars = g_strdupv ((gchar **) env_vars);
+ dep->paths = g_strdupv ((gchar **) paths);
+ dep->names = g_strdupv ((gchar **) names);
+ dep->flags = flags;
+ dep->env_hash = gst_plugin_ext_dep_get_env_vars_hash (plugin, dep);
+ dep->stat_hash = gst_plugin_ext_dep_get_stat_hash (plugin, dep);
+ plugin->priv->deps = g_list_append (plugin->priv->deps, dep);
+ GST_DEBUG_OBJECT (plugin, "added dependency:");
+ for (; env_vars != NULL && *env_vars != NULL; ++env_vars)
+ GST_DEBUG_OBJECT (plugin, " evar: %s", *env_vars);
+ for (; paths != NULL && *paths != NULL; ++paths)
+ GST_DEBUG_OBJECT (plugin, " path: %s", *paths);
+ for (; names != NULL && *names != NULL; ++names)
+ GST_DEBUG_OBJECT (plugin, " name: %s", *names);
+ * gst_plugin_add_dependency_simple:
+ * @plugin: the #GstPlugin
+ * @env_vars: one or more environent variables (separated by ':', ';' or ','),
+ * or NULL. Environment variable names may be followed by a path component
+ * "HOME/.mystuff/plugins:MYSTUFF_PLUGINS_PATH"
+ * @paths: one ore more directory paths (separated by ':' or ';' or ','),
+ * or NULL. Example: "/usr/lib/mystuff/plugins"
+ * @names: one or more file names or file name suffixes (separated by commas),
+ * or NULL
+ * Convenience wrapper function for gst_plugin_add_dependency() which
+ * takes simple strings as arguments instead of string arrays, with multiple
+ * arguments separated by predefined delimiters (see above).
+gst_plugin_add_dependency_simple (GstPlugin * plugin,
+ const gchar * env_vars, const gchar * paths, const gchar * names,
+ gchar **a_evars = NULL;
+ gchar **a_paths = NULL;
+ gchar **a_names = NULL;
+ if (env_vars)
+ a_evars = g_strsplit_set (env_vars, ":;,", -1);
+ if (paths)
+ a_paths = g_strsplit_set (paths, ":;,", -1);
+ if (names)
+ a_names = g_strsplit_set (names, ",", -1);
+ gst_plugin_add_dependency (plugin, (const gchar **) a_evars,
+ (const gchar **) a_paths, (const gchar **) a_names, flags);
+ if (a_evars)
+ g_strfreev (a_evars);
+ if (a_paths)
+ g_strfreev (a_paths);
+ if (a_names)
+ g_strfreev (a_names);
Index: gstplugin.h
RCS file: /cvs/gstreamer/gstreamer/gst/gstplugin.h,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -d -r1.73 -r1.74
--- gstplugin.h 17 Jan 2008 22:22:58 -0000 1.73
+++ gstplugin.h 6 Jan 2009 17:58:59 -0000 1.74
@@ -37,6 +37,7 @@
typedef struct _GstPlugin GstPlugin;
typedef struct _GstPluginClass GstPluginClass;
+typedef struct _GstPluginPrivate GstPluginPrivate;
typedef struct _GstPluginDesc GstPluginDesc;
/**
@@ -76,6 +77,27 @@
} GstPluginFlags;
+ * GstPluginDependencyFlags:
+ * @GST_PLUGIN_DEPENDENCY_FLAG_NONE : no special flags
+ * @GST_PLUGIN_DEPENDENCY_FLAG_RECURSE : recurse into subdirectories
+ * @GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY : use paths
+ * argument only if none of the environment variables is set
+ * @GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX : interpret
+ * filename argument as filter suffix and check all matching files in
+ * the directory
+ * Flags used in connection with gst_plugin_add_dependency().
+typedef enum {
+ GST_PLUGIN_DEPENDENCY_FLAG_NONE = 0,
+ GST_PLUGIN_DEPENDENCY_FLAG_RECURSE = (1 << 0),
+ GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY = (1 << 1),
+ GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX = (1 << 2)
+} GstPluginDependencyFlags;
* GstPluginInitFunc:
* @plugin: The plugin object that can be used to register #GstPluginFeatures for this plugin.
*
@@ -156,7 +178,8 @@
gboolean registered; /* TRUE when the registry has seen a filename
* that matches the plugin's basename */
- gpointer _gst_reserved[GST_PADDING];
+ GstPluginPrivate *priv;
+ gpointer _gst_reserved[GST_PADDING - 1];
struct _GstPluginClass {
@@ -298,6 +321,18 @@
GstPlugin * gst_plugin_load (GstPlugin *plugin);
GstPlugin * gst_plugin_load_by_name (const gchar *name);
+void gst_plugin_add_dependency (GstPlugin * plugin,
+ const gchar ** env_vars,
+ const gchar ** paths,
+ const gchar ** names,
+ GstPluginDependencyFlags flags);
+void gst_plugin_add_dependency_simple (GstPlugin * plugin,
+ const gchar * env_vars,
+ const gchar * paths,
+ const gchar * names,
+ GstPluginDependencyFlags flags);
void gst_plugin_list_free (GList *list);
G_END_DECLS
Index: gstregistry.c
RCS file: /cvs/gstreamer/gstreamer/gst/gstregistry.c,v
retrieving revision 1.85
retrieving revision 1.86
diff -u -d -r1.85 -r1.86
--- gstregistry.c 24 Nov 2008 09:59:07 -0000 1.85
+++ gstregistry.c 6 Jan 2009 17:58:59 -0000 1.86
@@ -863,6 +863,8 @@
* was already seen by the registry, we ignore it */
plugin = gst_registry_lookup (registry, filename);
if (plugin) {
+ gboolean env_vars_changed, deps_changed = FALSE;
if (plugin->registered) {
GST_DEBUG_OBJECT (registry,
"plugin already registered from path \"%s\"",
@@ -871,8 +873,12 @@
gst_object_unref (plugin);
continue;
}
+ env_vars_changed = _priv_plugin_deps_env_vars_changed (plugin);
if (plugin->file_mtime == file_status.st_mtime &&
- plugin->file_size == file_status.st_size) {
+ plugin->file_size == file_status.st_size && !env_vars_changed &&
+ !(deps_changed = _priv_plugin_deps_files_changed (plugin))) {
GST_LOG_OBJECT (registry, "file %s cached", filename);
plugin->flags &= ~GST_PLUGIN_FLAG_CACHED;
GST_LOG_OBJECT (registry, "marking plugin %p as registered as %s",
@@ -888,9 +894,11 @@
} else {
GST_INFO_OBJECT (registry, "cached info for %s is stale", filename);
GST_DEBUG_OBJECT (registry, "mtime %ld != %ld or size %"
- G_GINT64_FORMAT " != %"
- G_GINT64_FORMAT, plugin->file_mtime, file_status.st_mtime,
- (gint64) plugin->file_size, (gint64) file_status.st_size);
+ G_GINT64_FORMAT " != %" G_GINT64_FORMAT " or external dependency "
+ "env_vars changed: %d or external dependencies changed: %d",
+ plugin->file_mtime, file_status.st_mtime,
+ (gint64) plugin->file_size, (gint64) file_status.st_size,
+ env_vars_changed, deps_changed);
gst_registry_remove_plugin (gst_registry_get_default (), plugin);
/* We don't use a GError here because a failure to load some shared
* objects as plugins is normal (particularly in the uninstalled case)
Index: gstregistrybinary.c
RCS file: /cvs/gstreamer/gstreamer/gst/gstregistrybinary.c,v
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- gstregistrybinary.c 27 Dec 2008 16:23:12 -0000 1.43
+++ gstregistrybinary.c 6 Jan 2009 17:58:59 -0000 1.44
@@ -554,6 +554,38 @@
return FALSE;
+gst_registry_binary_save_plugin_dep (GList ** list, GstPluginDep * dep)
+ GstBinaryDep *ed;
+ GstBinaryChunk *chk;
+ gchar **s;
+ ed = g_new0 (GstBinaryDep, 1);
+ chk = gst_registry_binary_make_data (ed, sizeof (GstBinaryDep));
+ ed->flags = dep->flags;
+ ed->n_env_vars = 0;
+ ed->n_paths = 0;
+ ed->n_names = 0;
+ ed->env_hash = dep->env_hash;
+ ed->stat_hash = dep->stat_hash;
+ for (s = dep->env_vars; s != NULL && *s != NULL; ++s, ++ed->n_env_vars)
+ gst_registry_binary_save_string (list, *s);
+ for (s = dep->paths; s != NULL && *s != NULL; ++s, ++ed->n_paths)
+ for (s = dep->names; s != NULL && *s != NULL; ++s, ++ed->n_names)
+ *list = g_list_prepend (*list, chk);
+ GST_LOG ("Saved external plugin dependency");
+ return TRUE;
/*
* gst_registry_binary_save_plugin:
@@ -575,8 +607,18 @@
pe->file_size = plugin->file_size;
pe->file_mtime = plugin->file_mtime;
+ pe->n_deps = 0;
pe->nfeatures = 0;
+ /* pack external deps */
+ for (walk = plugin->priv->deps; walk != NULL; walk = walk->next) {
+ if (!gst_registry_binary_save_plugin_dep (list, walk->data)) {
+ GST_ERROR ("Could not save external plugin dependency, aborting.");
+ goto fail;
+ ++pe->n_deps;
/* pack plugin features */
plugin_features =
gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name);
@@ -954,6 +996,57 @@
+static gchar **
+gst_registry_binary_load_plugin_dep_strv (gchar ** in, guint n)
+ gchar **arr;
+ if (n == 0)
+ return NULL;
+ arr = g_new0 (gchar *, n + 1);
+ while (n > 0) {
+ unpack_string (*in, arr[n - 1]);
+ --n;
+ return arr;
+gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in)
+ GstBinaryDep *d;
+ align (*in);
+ GST_LOG_OBJECT (plugin, "Unpacking GstBinaryDep from %p", *in);
+ unpack_element (*in, d, GstBinaryDep);
+ dep->env_hash = d->env_hash;
+ dep->stat_hash = d->stat_hash;
+ dep->flags = d->flags;
+ dep->names = gst_registry_binary_load_plugin_dep_strv (in, d->n_names);
+ dep->paths = gst_registry_binary_load_plugin_dep_strv (in, d->n_paths);
+ dep->env_vars = gst_registry_binary_load_plugin_dep_strv (in, d->n_env_vars);
+ GST_DEBUG_OBJECT (plugin, "Loaded external plugin dependency from registry: "
+ "env_hash: %08x, stat_hash: %08x", dep->env_hash, dep->stat_hash);
+ for (s = dep->env_vars; s != NULL && *s != NULL; ++s)
+ GST_LOG_OBJECT (plugin, " evar: %s", *s);
+ for (s = dep->paths; s != NULL && *s != NULL; ++s)
+ GST_LOG_OBJECT (plugin, " path: %s", *s);
+ for (s = dep->names; s != NULL && *s != NULL; ++s)
+ GST_LOG_OBJECT (plugin, " name: %s", *s);
* gst_registry_binary_load_plugin:
@@ -1004,6 +1097,8 @@
gst_registry_add_plugin (registry, plugin);
GST_DEBUG ("Added plugin '%s' plugin with %d features from binary registry",
plugin->desc.name, pe->nfeatures);
+ /* Load plugin features */
for (i = 0; i < pe->nfeatures; i++) {
if (!gst_registry_binary_load_feature (registry, in, plugin->desc.name)) {
GST_ERROR ("Error while loading binary feature");
@@ -1011,6 +1106,14 @@
}
+ /* Load external plugin dependencies */
+ for (i = 0; i < pe->n_deps; ++i) {
+ if (!gst_registry_binary_load_plugin_dep (plugin, in)) {
+ GST_ERROR_OBJECT (plugin, "Could not read external plugin dependency");
return TRUE;
/* Errors */
Index: gstregistrybinary.h
RCS file: /cvs/gstreamer/gstreamer/gst/gstregistrybinary.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- gstregistrybinary.h 12 Nov 2008 10:39:25 -0000 1.11
+++ gstregistrybinary.h 6 Jan 2009 17:58:59 -0000 1.12
@@ -57,7 +57,7 @@
* This _must_ be updated whenever the registry format changes,
* we currently use the core version where this change happened.
*/
-#define GST_MAGIC_BINARY_VERSION_STR ("0.10.21.1")
+#define GST_MAGIC_BINARY_VERSION_STR ("0.10.21.2")
* GST_MAGIC_BINARY_VERSION_LEN:
@@ -108,9 +108,23 @@
gulong file_size;
gulong file_mtime;
+ guint n_deps;
guint nfeatures;
} GstBinaryPluginElement;
+/* GstBinaryDep:
+typedef struct _GstBinaryDep
+ guint flags;
+ guint n_env_vars;
+ guint n_paths;
+ guint n_names;
+ guint env_hash;
+ guint stat_hash;
+} GstBinaryDep;
* GstBinaryPluginFeature:
Index: gstregistryxml.c
RCS file: /cvs/gstreamer/gstreamer/gst/gstregistryxml.c,v
--- gstregistryxml.c 30 Oct 2008 14:15:14 -0000 1.43
+++ gstregistryxml.c 6 Jan 2009 17:58:59 -0000 1.44
@@ -785,6 +785,10 @@
GList *walk;
char s[100];
+ if (plugin->priv->deps != NULL) {
+ GST_WARNING ("XML registry does not support external plugin dependencies");
if (!gst_registry_save_escaped (registry, " ", "name", plugin->desc.name))
return FALSE;
if (!gst_registry_save_escaped (registry, " ", "description",
--===============0458699594665386790==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
------------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It is the best place to buy or sell services for
just about anything Open Source.
http://p.sf.net/sfu/Xq1LFB
--===============0458699594665386790==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
gstreamer-cvs-verbose mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gstreamer-cvs-verbose
--===============0458699594665386790==--