From: Stefan Kost Date: Thu, 11 Jan 2007 13:45:51 +0000 (+0000) Subject: commit binary registry (disabled by default, see #359653) X-Git-Tag: RELEASE-0_10_12~100 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ebf0c9d353bd4a5e81bb93b575359c89d4b9afe1;p=platform%2Fupstream%2Fgstreamer.git commit binary registry (disabled by default, see #359653) Original commit message from CVS: * configure.ac: * docs/gst/gstreamer-sections.txt: * gst/Makefile.am: * gst/gstregistry.c: (gst_registry_lookup_feature_locked), (gst_registry_lookup_locked): * gst/gstregistry.h: * gst/gstregistrybinary.c: (gst_registry_binary_write), (gst_registry_binary_initialize_magic), (gst_registry_binary_save_string), (gst_registry_binary_save_pad_template), (gst_registry_binary_save_feature), (gst_registry_binary_save_plugin), (gst_registry_binary_write_cache), (gst_registry_binary_check_magic), (gst_registry_binary_load_pad_template), (gst_registry_binary_load_feature), (gst_registry_binary_load_plugin), (gst_registry_binary_read_cache): * gst/gstregistrybinary.h: * gst/gstregistryxml.c: (load_feature), (gst_registry_xml_read_cache): commit binary registry (disabled by default, see #359653) --- diff --git a/ChangeLog b/ChangeLog index e5b005d..a1472fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2007-01-11 Stefan Kost + + * configure.ac: + * docs/gst/gstreamer-sections.txt: + * gst/Makefile.am: + * gst/gstregistry.c: (gst_registry_lookup_feature_locked), + (gst_registry_lookup_locked): + * gst/gstregistry.h: + * gst/gstregistrybinary.c: (gst_registry_binary_write), + (gst_registry_binary_initialize_magic), + (gst_registry_binary_save_string), + (gst_registry_binary_save_pad_template), + (gst_registry_binary_save_feature), + (gst_registry_binary_save_plugin), + (gst_registry_binary_write_cache), + (gst_registry_binary_check_magic), + (gst_registry_binary_load_pad_template), + (gst_registry_binary_load_feature), + (gst_registry_binary_load_plugin), + (gst_registry_binary_read_cache): + * gst/gstregistrybinary.h: + * gst/gstregistryxml.c: (load_feature), + (gst_registry_xml_read_cache): + commit binary registry (disabled by default, see #359653) + 2007-01-11 Tim-Philipp Müller * tests/check/gst/gstpad.c: (test_get_allowed_caps): diff --git a/configure.ac b/configure.ac index f257831..f89def9 100644 --- a/configure.ac +++ b/configure.ac @@ -191,6 +191,23 @@ if test "x$USE_POISONING" = xyes; then [Define if we should poison deallocated memory]) fi +dnl Use binary registry +AC_ARG_ENABLE(binary-registry, + AC_HELP_STRING([--enable-binary-registry], + [enable experimental binary registry]), + [ + case "${enableval}" in + yes) USE_BINARY_REGISTRY=yes ;; + no) USE_BINARY_REGISTRY=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-binary-registry) ;; + esac + ], + [USE_BINARY_REGISTRY=no]) dnl Default value +if test "x$USE_BINARY_REGISTRY" = xyes; then + AC_DEFINE(USE_BINARY_REGISTRY, 1, + [Define if we should use binary registry instead xml registry]) +fi + dnl *** checks for platform *** dnl * hardware/architecture * diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 94e3f82..defbdfa 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -1649,6 +1649,8 @@ gst_registry_find_plugin gst_registry_find_feature gst_registry_lookup_feature gst_registry_scan_path +gst_registry_binary_read_cache +gst_registry_binary_write_cache gst_registry_xml_read_cache gst_registry_xml_write_cache gst_registry_lookup @@ -1672,6 +1674,9 @@ GST_IS_REGISTRY_CLASS GST_REGISTRY_GET_CLASS GST_TYPE_REGISTRY +GST_MAGIC_BINARY_REGISTRY_LEN +GST_MAGIC_BINARY_REGISTRY_STR +GST_MAGIC_BINARY_VERSION_LEN gst_registry_get_type diff --git a/gst/Makefile.am b/gst/Makefile.am index f3e4f49..aabd9657 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -9,7 +9,7 @@ endif if GST_DISABLE_REGISTRY GST_REGISTRY_SRC = else -GST_REGISTRY_SRC = gstregistryxml.c +GST_REGISTRY_SRC = gstregistryxml.c gstregistrybinary.c endif if GST_DISABLE_PARSE @@ -210,6 +210,7 @@ noinst_HEADERS = \ gst-i18n-lib.h \ gst-i18n-app.h \ gstquark.h \ + gstregistrybinary.h \ gst_private.h gstmarshal.h: gstmarshal.list diff --git a/gst/gstregistry.c b/gst/gstregistry.c index 4aa0bdb..df240e3 100644 --- a/gst/gstregistry.c +++ b/gst/gstregistry.c @@ -684,6 +684,7 @@ gst_registry_lookup_feature_locked (GstRegistry * registry, const char *name) if (G_UNLIKELY (name == NULL)) return NULL; + /* FIXME: use GTree speed up lookups */ for (g = registry->features; g; g = g_list_next (g)) { feature = GST_PLUGIN_FEATURE_CAST (g->data); if (feature->name && strcmp (name, feature->name) == 0) { @@ -734,6 +735,7 @@ gst_registry_lookup_locked (GstRegistry * registry, const char *filename) return NULL; basename = g_path_get_basename (filename); + /* FIXME: use GTree speed up lookups */ for (g = registry->plugins; g; g = g_list_next (g)) { plugin = GST_PLUGIN_CAST (g->data); if (plugin->basename && strcmp (basename, plugin->basename) == 0) { diff --git a/gst/gstregistry.h b/gst/gstregistry.h index 743e058..7c6d872 100644 --- a/gst/gstregistry.h +++ b/gst/gstregistry.h @@ -50,7 +50,10 @@ struct _GstRegistry { GstObject object; /*< private >*/ - GList *plugins; + /* FIXME: shouldn't we use GTree for these to speedup + * gst_registry_lookup_feature_locked(), gst_registry_lookup_locked() + */ + GList *plugins; GList *features; GList *paths; @@ -106,8 +109,13 @@ GstPluginFeature* gst_registry_find_feature (GstRegistry *registry, const gchar GstPlugin * gst_registry_lookup (GstRegistry *registry, const char *filename); GstPluginFeature * gst_registry_lookup_feature (GstRegistry *registry, const char *name); +#ifdef USE_BINARY_REGISTRY +gboolean gst_registry_binary_read_cache (GstRegistry * registry, const char *location); +gboolean gst_registry_binary_write_cache (GstRegistry * registry, const char *location); +#else gboolean gst_registry_xml_read_cache (GstRegistry * registry, const char *location); gboolean gst_registry_xml_write_cache (GstRegistry * registry, const char *location); +#endif /* convinience defines for the default registry */ diff --git a/gst/gstregistrybinary.c b/gst/gstregistrybinary.c new file mode 100644 index 0000000..824f9a6 --- /dev/null +++ b/gst/gstregistrybinary.c @@ -0,0 +1,741 @@ +/* GStreamer + * Copyright (C) 2006 Josep Torra + * 2006 Mathieu Garcia + * 2006 Stefan Kost + * + * gstregistrybinary.c: GstRegistryBinary object, support routines + * + * This library is free software; you can redistribute it and/or + * modify it ulnder the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* FIXME: + * - Add random key to libgstreamer during build and only accept registry, + * if key matches + * - handle cases where we can't mmap + * - keep registry binary blob and reference strings + * (need const flags in GstPlugin, etc.) + * - why do we collect a list of binary chunks and not write immediately + * - need more robustness + * - don't parse beyond mem-block size + * - include md5-sum ? + */ + +#include + +#define GST_CAT_DEFAULT GST_CAT_REGISTRY + +/* macros */ + +#define unpack_element(_inptr, _outptr, _element) \ + _outptr = (_element *)_inptr; \ + _inptr += sizeof (_element) + +#define unpack_string(_inptr, _outptr) \ + _outptr = g_strdup ((gchar *)_inptr); \ + _inptr += strlen(_outptr) + 1 + +#if !GST_HAVE_UNALIGNED_ACCESS +# define alignment32(_address) (size_t)_address%4 +# define align32(_ptr) _ptr += (( alignment32(_ptr) == 0) ? 0 : 4-alignment32(_ptr)) +#else +# define alignment32(_address) 0 +# define align32(_ptr) do {} while(0) +#endif + +/* Registry saving */ + +/* + * gst_registry_binary_write: + * + * Write from a memory location to the registry cache file + * + * Returns: %TRUE for success + */ +inline static gboolean +gst_registry_binary_write (GstRegistry * registry, const void *mem, + const ssize_t size, unsigned long *file_position, gboolean align) +{ +#if !GST_HAVE_UNALIGNED_ACCESS + gchar padder[] = { 0, 0, 0, 0 }; + int padsize = 0; + + /* Padding to insert the struct that requiere word alignment */ + if ((align) && (alignment32 (*file_position) != 0)) { + padsize = 4 - alignment32 (*file_position); + if (write (registry->cache_file, padder, padsize) != padsize) { + GST_ERROR ("Failed to write binary registry padder"); + return FALSE; + } + *file_position = *file_position + padsize; + } +#endif + + if (write (registry->cache_file, mem, size) != size) { + GST_ERROR ("Failed to write binary registry element"); + return FALSE; + } + *file_position = *file_position + size; + return TRUE; +} + +/* + * gst_registry_binary_initialize_magic: + * + * Initialize the GstBinaryRegistryMagic, setting both our magic number and + * gstreamer major/minor version + */ +inline static gboolean +gst_registry_binary_initialize_magic (GstBinaryRegistryMagic * m) +{ + if (!strncpy (m->magic, GST_MAGIC_BINARY_REGISTRY_STR, + GST_MAGIC_BINARY_REGISTRY_LEN) + || !strncpy (m->version, GST_MAJORMINOR, GST_MAGIC_BINARY_VERSION_LEN)) { + GST_ERROR ("Failed to write magic to the registry magic structure"); + return FALSE; + } + return TRUE; +} + +/* + * gst_registry_binary_save_string: + * + * Store a string in a binary chunk. + * + * Returns: %TRUE for success + */ +inline static gboolean +gst_registry_binary_save_string (GList ** list, gchar * str) +{ + GstBinaryChunk *chunk; + + chunk = g_malloc (sizeof (GstBinaryChunk)); + chunk->data = str; + chunk->size = strlen ((gchar *) chunk->data) + 1; + chunk->flags = GST_BINARY_REGISTRY_FLAG_CONST; + chunk->align = FALSE; + *list = g_list_prepend (*list, chunk); + return TRUE; +} + +/* + * gst_registry_binary_save_pad_template: + * + * Store pad_templates in binary chunks. + * + * Returns: %TRUE for success + */ +static gboolean +gst_registry_binary_save_pad_template (GList ** list, + GstStaticPadTemplate * template) +{ + GstBinaryPadTemplate *pt; + GstBinaryChunk *chk; + + pt = g_malloc (sizeof (GstBinaryPadTemplate)); + chk = g_malloc (sizeof (GstBinaryChunk)); + + chk->data = pt; + chk->size = sizeof (GstBinaryPadTemplate); + chk->flags = GST_BINARY_REGISTRY_FLAG_NONE; + chk->align = TRUE; + + pt->presence = template->presence; + pt->direction = template->direction; + + /* pack pad template strings */ + gst_registry_binary_save_string (list, + (gchar *) (template->static_caps.string)); + gst_registry_binary_save_string (list, template->name_template); + + *list = g_list_prepend (*list, chk); + + return TRUE; +} + +/* + * gst_registry_binary_save_feature: + * + * Store features in binary chunks. + * + * Returns: %TRUE for success + */ +static gboolean +gst_registry_binary_save_feature (GList ** list, GstPluginFeature * feature) +{ + const gchar *type_name = g_type_name (G_OBJECT_TYPE (feature)); + GstBinaryPluginFeature *pf; + GstBinaryChunk *chk; + GList *walk; + + if (!type_name) { + GST_ERROR ("NULL feature type_name, aborting."); + return FALSE; + } + + pf = g_malloc (sizeof (GstBinaryPluginFeature)); + chk = g_malloc (sizeof (GstBinaryChunk)); + + chk->data = pf; + chk->size = sizeof (GstBinaryPluginFeature); + chk->flags = GST_BINARY_REGISTRY_FLAG_NONE; + chk->align = TRUE; + + pf->rank = feature->rank; + pf->npadtemplates = pf->ninterfaces = pf->nuritypes = 0; + + if (GST_IS_ELEMENT_FACTORY (feature)) { + GstElementFactory *factory = GST_ELEMENT_FACTORY (feature); + + /* save pad-templates */ + for (walk = factory->staticpadtemplates; walk; + walk = g_list_next (walk), pf->npadtemplates++) { + GstStaticPadTemplate *template = walk->data; + + if (!gst_registry_binary_save_pad_template (list, template)) { + GST_ERROR ("Can't fill pad template, aborting."); + goto fail; + } + } + + /* pack element factory strings */ + gst_registry_binary_save_string (list, factory->details.author); + gst_registry_binary_save_string (list, factory->details.description); + gst_registry_binary_save_string (list, factory->details.klass); + gst_registry_binary_save_string (list, factory->details.longname); + } + + /* pack plugin feature strings */ + gst_registry_binary_save_string (list, feature->name); + gst_registry_binary_save_string (list, (gchar *) type_name); + + *list = g_list_prepend (*list, chk); + + /* FIXME: save interfaces and uritypes */ + return TRUE; + + /* Errors */ +fail: + g_free (chk); + g_free (pf); + return FALSE; +} + +/* + * gst_registry_binary_save_plugin: + * + * Adapt a GstPlugin to our GstBinaryPluginElement structure, and write it to + * the registry file. + */ +static gboolean +gst_registry_binary_save_plugin (GList ** list, GstRegistry * registry, + GstPlugin * plugin) +{ + GstBinaryPluginElement *pe; + GstBinaryChunk *chk; + GList *plugin_features = NULL; + GList *walk; + + pe = g_malloc (sizeof (GstBinaryPluginElement)); + chk = g_malloc (sizeof (GstBinaryChunk)); + + chk->data = pe; + chk->size = sizeof (GstBinaryPluginElement); + chk->flags = GST_BINARY_REGISTRY_FLAG_NONE; + chk->align = TRUE; + + pe->file_size = plugin->file_size; + pe->file_mtime = plugin->file_mtime; + pe->nfeatures = 0; + + /* pack plugin features */ + plugin_features = + gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name); + for (walk = plugin_features; walk; walk = g_list_next (walk), pe->nfeatures++) { + GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data); + + if (!gst_registry_binary_save_feature (list, feature)) { + GST_ERROR ("Can't fill plugin feature, aborting."); + goto fail; + } + } + GST_DEBUG ("Save plugin '%s' with %d features", plugin->desc.name, + pe->nfeatures); + + gst_plugin_feature_list_free (plugin_features); + + /* pack plugin element strings */ + gst_registry_binary_save_string (list, plugin->desc.origin); + gst_registry_binary_save_string (list, plugin->desc.package); + gst_registry_binary_save_string (list, plugin->desc.source); + gst_registry_binary_save_string (list, plugin->desc.license); + gst_registry_binary_save_string (list, plugin->desc.version); + gst_registry_binary_save_string (list, plugin->filename); + gst_registry_binary_save_string (list, plugin->desc.description); + gst_registry_binary_save_string (list, plugin->desc.name); + + *list = g_list_prepend (*list, chk); + + GST_DEBUG ("Found %d features in plugin \"%s\"", pe->nfeatures, + plugin->desc.name); + return TRUE; + + /* Errors */ +fail: + gst_plugin_feature_list_free (plugin_features); + g_free (chk); + g_free (pe); + return FALSE; +} + +/** + * gst_registry_binary_write_cache: + * + * Write the cache to file. Part of the code was taken from gstregistryxml.c + */ +gboolean +gst_registry_binary_write_cache (GstRegistry * registry, const char *location) +{ + GList *walk; + char *tmp_location; + GstBinaryRegistryMagic *magic; + GstBinaryChunk *magic_chunk; + GList *to_write = NULL; + unsigned long file_position = 0; + + GST_INFO ("Building binary registry cache image"); + + g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE); + tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL); + registry->cache_file = g_mkstemp (tmp_location); + if (registry->cache_file == -1) { + char *dir; + + /* oops, I bet the directory doesn't exist */ + dir = g_path_get_dirname (location); + g_mkdir_with_parents (dir, 0777); + g_free (dir); + + /* the previous g_mkstemp call overwrote the XXXXXX placeholder ... */ + g_free (tmp_location); + tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL); + registry->cache_file = g_mkstemp (tmp_location); + + if (registry->cache_file == -1) { + GST_DEBUG ("g_mkstemp() failed: %s", g_strerror (errno)); + g_free (tmp_location); + return FALSE; + } + } + + magic = g_malloc (sizeof (GstBinaryRegistryMagic)); + if (!gst_registry_binary_initialize_magic (magic)) + goto fail; + + magic_chunk = g_malloc (sizeof (GstBinaryChunk)); + magic_chunk->data = magic; + magic_chunk->size = sizeof (GstBinaryRegistryMagic); + magic_chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE; + magic_chunk->align = TRUE; + + /* iterate trough the list of plugins and fit them into binary structures */ + for (walk = registry->plugins; walk; walk = g_list_next (walk)) { + GstPlugin *plugin = GST_PLUGIN (walk->data); + + if (!plugin->filename) + continue; + + if (plugin->flags & GST_PLUGIN_FLAG_CACHED) { + int ret; + struct stat statbuf; + + ret = g_stat (plugin->filename, &statbuf); + if ((ret = g_stat (plugin->filename, &statbuf)) < 0 || + plugin->file_mtime != statbuf.st_mtime || + plugin->file_size != statbuf.st_size) + continue; + } + + if (!gst_registry_binary_save_plugin (&to_write, registry, plugin)) { + GST_ERROR ("Can't write binary plugin information for \"%s\"", + plugin->filename); + } + } + to_write = g_list_prepend (to_write, magic_chunk); + + GST_INFO ("Writing binary registry cache"); + + /* write out data chunks */ + for (walk = to_write; walk; walk = g_list_next (walk)) { + GstBinaryChunk *cur = walk->data; + + if (!gst_registry_binary_write (registry, cur->data, cur->size, + &file_position, cur->align)) { + if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST)) + g_free (cur->data); + g_free (cur); + g_list_free (to_write); + goto fail; + } + if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST)) + g_free (cur->data); + g_free (cur); + } + g_list_free (to_write); + + if (close (registry->cache_file) < 0) { + GST_DEBUG ("Can't close registry file : %s", strerror (errno)); + goto fail; + } + + if (g_file_test (tmp_location, G_FILE_TEST_EXISTS)) { +#ifdef WIN32 + remove (location); +#endif + rename (tmp_location, location); + } + + g_free (tmp_location); + GST_INFO ("Wrote binary registry cache"); + return TRUE; + + /* Errors */ +fail: + g_free (tmp_location); + return FALSE; +} + +/* Registry loading */ + +/* + * gst_registry_binary_check_magic: + * + * Check GstBinaryRegistryMagic validity. + * Return FALSE if something is wrong + */ +static gboolean +gst_registry_binary_check_magic (gchar ** in) +{ + GstBinaryRegistryMagic *m; + + align32 (*in); + GST_DEBUG ("Reading/casting for GstBinaryRegistryMagic at address %p", *in); + unpack_element (*in, m, GstBinaryRegistryMagic); + + if (m == NULL || m->magic == NULL || m->version == NULL) { + GST_ERROR ("Binary registry magic structure is broken"); + return FALSE; + } + if (strncmp (m->magic, GST_MAGIC_BINARY_REGISTRY_STR, + GST_MAGIC_BINARY_REGISTRY_LEN) != 0) { + GST_ERROR + ("Binary registry magic is different : %02x%02x%02x%02x != %02x%02x%02x%02x", + GST_MAGIC_BINARY_REGISTRY_STR[0] & 0xff, + GST_MAGIC_BINARY_REGISTRY_STR[1] & 0xff, + GST_MAGIC_BINARY_REGISTRY_STR[2] & 0xff, + GST_MAGIC_BINARY_REGISTRY_STR[3] & 0xff, m->magic[0] & 0xff, + m->magic[1] & 0xff, m->magic[2] & 0xff, m->magic[3] & 0xff); + return FALSE; + } + if (strncmp (m->version, GST_MAJORMINOR, GST_MAGIC_BINARY_VERSION_LEN)) { + GST_ERROR ("Binary registry magic version is different : %s != %s", + GST_MAJORMINOR, m->version); + return FALSE; + } + return TRUE; +} + +/* + * gst_registry_binary_load_pad_template: + * + * Make a new GstStaticPadTemplate from current GstBinaryPadTemplate structure + * + * Returns: new GstStaticPadTemplate + */ +static gboolean +gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in) +{ + GstBinaryPadTemplate *pt; + GstStaticPadTemplate *template; + + align32 (*in); + GST_DEBUG ("Reading/casting for GstBinaryPadTemplate at address %p", *in); + unpack_element (*in, pt, GstBinaryPadTemplate); + + + template = g_new0 (GstStaticPadTemplate, 1); + template->presence = pt->presence; + template->direction = pt->direction; + + /* unpack pad template strings */ + unpack_string (*in, template->name_template); + unpack_string (*in, template->static_caps.string); + + __gst_element_factory_add_static_pad_template (factory, template); + GST_DEBUG ("Added pad_template %s", template->name_template); + + return TRUE; +} + +/* + * gst_registry_binary_load_feature: + * + * Make a new GstPluginFeature from current GstBinaryPluginFeature structure + * + * Returns: new GstPluginFeature + */ +static gboolean +gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in, + gchar * plugin_name) +{ + GstBinaryPluginFeature *pf; + GstPluginFeature *feature; + gchar *type_name; + GType type; + guint i; + + align32 (*in); + GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in); + unpack_element (*in, pf, GstBinaryPluginFeature); + + /* unpack plugin feature strings */ + unpack_string (*in, type_name); + + if (!type_name || !*(type_name)) + return FALSE; + + GST_DEBUG ("Plugin '%s' feature typename : '%s'", plugin_name, type_name); + + if (!(type = g_type_from_name (type_name))) { + GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name, + plugin_name); + return FALSE; + } + if ((feature = g_object_new (type, NULL)) == NULL) { + GST_ERROR ("Can't create feature from type"); + return FALSE; + } + + if (!GST_IS_PLUGIN_FEATURE (feature)) { + GST_ERROR ("typename : '%s' is not a plgin feature", type_name); + goto fail; + } + + feature->rank = pf->rank; + feature->plugin_name = plugin_name; + + /* unpack more plugin feature strings */ + unpack_string (*in, feature->name); + + if (GST_IS_ELEMENT_FACTORY (feature)) { + GstElementFactory *factory = GST_ELEMENT_FACTORY (feature); + + /* unpack element factory strings */ + unpack_string (*in, factory->details.longname); + unpack_string (*in, factory->details.klass); + unpack_string (*in, factory->details.description); + unpack_string (*in, factory->details.author); + GST_DEBUG ("Element factory : '%s' with npadtemplates=%d", + factory->details.longname, pf->npadtemplates); + + /* load pad templates */ + for (i = 0; i < pf->npadtemplates; i++) { + if (!gst_registry_binary_load_pad_template (factory, in)) { + GST_ERROR ("Error while loading binary pad template"); + goto fail; + } + } + } + + gst_registry_add_feature (registry, feature); + GST_DEBUG ("Added feature %s", feature->name); + + /* FIXME: handle interfaces and uritypes */ +#if 0 + for (i = 0; i < pf->ninterfaces; i++) { + // read string + __gst_element_factory_add_interface (factory, s); + } + for (i = 0; i < pf->nuritypes; i++) { + // read string + add_to_char_array (&factory->uri_protocols, s); + } +#endif + return TRUE; + + /* Errors */ +fail: + if (GST_IS_OBJECT (feature)) + gst_object_unref (feature); + else + g_object_unref (feature); + return FALSE; +} + +/* + * gst_registry_binary_load_plugin: + * + * Make a new GstPlugin from current GstBinaryPluginElement structure + * and save it to the GstRegistry. Return an offset to the next + * GstBinaryPluginElement structure. + */ +static gboolean +gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in) +{ + GstBinaryPluginElement *pe; + GstPlugin *plugin = NULL; + guint i; + + align32 (*in); + GST_DEBUG ("Reading/casting for GstBinaryPluginElement at address %p", *in); + unpack_element (*in, pe, GstBinaryPluginElement); + + if (pe->nfeatures < 0) { + GST_ERROR ("The number of feature structure is not valid !"); + return FALSE; + } + + if (pe->file_mtime < 0 || pe->file_size < 0) { + GST_ERROR ("Plugin time or file size is not valid !"); + return FALSE; + } + + GST_DEBUG ("Adding plugin with %d features from binary registry", + pe->nfeatures); + + plugin = g_object_new (GST_TYPE_PLUGIN, NULL); + + plugin->flags |= GST_PLUGIN_FLAG_CACHED; + plugin->file_mtime = pe->file_mtime; + plugin->file_size = pe->file_size; + + /* unpack plugin element strings */ + unpack_string (*in, plugin->desc.name); + unpack_string (*in, plugin->desc.description); + unpack_string (*in, plugin->filename); + unpack_string (*in, plugin->desc.version); + unpack_string (*in, plugin->desc.license); + unpack_string (*in, plugin->desc.source); + unpack_string (*in, plugin->desc.package); + unpack_string (*in, plugin->desc.origin); + GST_DEBUG ("read strings for '%s'", plugin->desc.name); + + plugin->basename = g_path_get_basename (plugin->filename); + gst_registry_add_plugin (registry, plugin); + GST_DEBUG ("Added plugin '%s' from binary registry", plugin->desc.name); + GST_DEBUG ("Number of features %d", pe->nfeatures); + for (i = 0; i < pe->nfeatures; i++) { + if (!gst_registry_binary_load_feature (registry, in, + g_strdup (plugin->desc.name))) { + GST_ERROR ("Error while loading binary feature"); + goto fail; + } + } + + return TRUE; + + /* Errors */ +fail: + gst_object_unref (plugin); + return FALSE; +} + + +/** + * gst_registry_binary_read_cache: + * @registry: a #GstRegistry + * @location: a filename + * + * Read the contents of the binary cache file at @location into @registry. + * + * Returns: %TRUE on success. + */ +gboolean +gst_registry_binary_read_cache (GstRegistry * registry, const char *location) +{ + GMappedFile *mapped = NULL; + GTimer *timer = NULL; + gchar *contents = NULL; + gchar *in = NULL; + gdouble seconds; + gsize size; + GError *err = NULL; + + /* make sure these types exist */ + GST_TYPE_ELEMENT_FACTORY; + GST_TYPE_TYPE_FIND_FACTORY; +#ifndef GST_DISABLE_INDEX + GST_TYPE_INDEX_FACTORY; +#endif + + timer = g_timer_new (); + + mapped = g_mapped_file_new (location, FALSE, &err); + if (err != NULL) { + GST_INFO ("Unable to mmap file: %s\n", err->message); + g_error_free (err); + return FALSE; + } + + if ((contents = g_mapped_file_get_contents (mapped)) == NULL) { + GST_ERROR ("Can't load file %s : %s", location, strerror (errno)); + g_mapped_file_free (mapped); + return FALSE; + } + /* in is a cursor pointer, we initialize it with the begin of registry and is updated on each read */ + in = contents; + GST_DEBUG ("File mapped at address %p", in); + /* check length for header */ + size = g_mapped_file_get_length (mapped); + if (size < sizeof (GstBinaryRegistryMagic)) { + GST_INFO ("No or broken registry header"); + return FALSE; + } + /* check if header is valid */ + if (!gst_registry_binary_check_magic (&in)) { + GST_ERROR ("Binary registry type not recognized (invalid magic)"); + g_mapped_file_free (mapped); + return FALSE; + } + + /* check if there are plugins in the file */ + + if (!(((size_t) in + sizeof (GstBinaryPluginElement)) < + (size_t) contents + size)) { + GST_INFO ("No binary plugins structure to read"); + return TRUE; /* empty file, this is not an error */ + } + + + for (; + ((size_t) in + sizeof (GstBinaryPluginElement)) < + (size_t) contents + size;) { + GST_INFO ("reading binary registry %ld(%x)/%ld", + (size_t) in - (size_t) contents, (size_t) in - (size_t) contents, size); + if (!gst_registry_binary_load_plugin (registry, &in)) { + GST_ERROR ("Problem while reading binary registry"); + return FALSE; + } + } + + g_timer_stop (timer); + seconds = g_timer_elapsed (timer, NULL); + g_timer_destroy (timer); + + GST_INFO ("loaded %s in %lf seconds", location, seconds); + + g_mapped_file_free (mapped); + return TRUE; +} diff --git a/gst/gstregistrybinary.h b/gst/gstregistrybinary.h new file mode 100644 index 0000000..d71cc60 --- /dev/null +++ b/gst/gstregistrybinary.h @@ -0,0 +1,173 @@ +/* GStreamer + * Copyright (C) 2006 Josep Torra + * 2006 Mathieu Garcia + * 2006 Stefan Kost + * + * gstregistrybinary.h: Header for registry handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* SUGGESTIONS AND TODO : +** ==================== +** - Use a compressed registry, but would induce performance loss +** - Encrypt the registry, for security purpose, but would also reduce performances +** - Also have a non-mmap based cache reading (work with file descriptors) +*/ + +#ifndef __GST_REGISTRYBINARY_H__ +#define __GST_REGISTRYBINARY_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "glib-compat-private.h" +#include + +/* + * GST_MAGIC_BINARY_REGISTRY_STR: + * + * A tag, written at the beginning of the file + */ +#define GST_MAGIC_BINARY_REGISTRY_STR "\xc0\xde\xf0\x0d" +/* + * GST_MAGIC_BINARY_REGISTRY_LEN: + * + * length of the header tag. + */ +#define GST_MAGIC_BINARY_REGISTRY_LEN (4) +/* + * GST_MAGIC_BINARY_VERSION_LEN: + * + * length of the version string. + */ +#define GST_MAGIC_BINARY_VERSION_LEN (64) + +typedef struct _GstBinaryRegistryMagic +{ + char magic[GST_MAGIC_BINARY_REGISTRY_LEN]; + char version[GST_MAGIC_BINARY_VERSION_LEN]; +} GstBinaryRegistryMagic; + +/* + * we reference strings directly from the plugins and in this case set CONST to + * avoid freeing them + */ +enum { + GST_BINARY_REGISTRY_FLAG_NONE = 0, + GST_BINARY_REGISTRY_FLAG_CONST = 1 +}; + +/* GstBinaryChunk: + * + * Header for binary blobs + */ +typedef struct _GstBinaryChunk +{ + void *data; + unsigned int size; + unsigned int flags; + gboolean align; +} GstBinaryChunk; + +/* A structure containing (staticely) every information needed for a plugin +** +** Notes : +** "nfeatures" is used to say how many GstBinaryPluginFeature structures we will have +** right after the structure itself. +*/ + +typedef struct _GstBinaryPluginElement +{ + unsigned long file_size; + unsigned long file_mtime; + + unsigned int nfeatures; +} GstBinaryPluginElement; + + +/* A structure containing the plugin features +** +** Note : +** "npadtemplates" is used to store the number of GstBinaryPadTemplate structures following the structure itself. +** "ninterfaces" is used to store the number of GstBinaryInterface structures following the structure itself. +** "nuritypes" is used to store the number of GstBinaryUriType structures following the structure itself. +*/ +typedef struct _GstBinaryPluginFeature +{ + unsigned long rank; + + unsigned int npadtemplates; + unsigned int ninterfaces; + unsigned int nuritypes; +} GstBinaryPluginFeature; + + +/* +** A structure containing the static pad templates of a plugin feature +*/ +typedef struct _GstBinaryPadTemplate +{ + int direction; /* Either 0:"sink" or 1:"src" */ + GstPadPresence presence; +} GstBinaryPadTemplate; + +/* +** A very simple structure defining the plugin feature interface string +*/ +//#define GST_BINARY_REGISTRY_INTERFACE_INTERFACE_LEN (512) +typedef struct _GstBinaryInterface +{ + //char interface[GST_BINARY_REGISTRY_INTERFACE_INTERFACE_LEN]; + unsigned long size; +} GstBinaryInterface; + +/* Uri Type */ +typedef struct _GstBinaryUriType +{ + GstURIType type; /* GST_URI_SINK / GST_URI_SRC */ + unsigned long nuriprotocols; +} GstBinaryUriType; + +/* Function prototypes */ +gboolean gst_registry_binary_write_cache(GstRegistry *registry, const char *location); +gboolean gst_registry_binary_read_cache(GstRegistry *registry, const char *location); + +#endif /* !__GST_REGISTRYBINARY_H__ */ + diff --git a/gst/gstregistryxml.c b/gst/gstregistryxml.c index 8f8e766..ad7f6cd 100644 --- a/gst/gstregistryxml.c +++ b/gst/gstregistryxml.c @@ -249,7 +249,7 @@ load_feature (xmlTextReaderPtr reader) feature_name = (gchar *) xmlTextReaderGetAttribute (reader, BAD_CAST "typename"); - GST_DEBUG ("loading feature"); + GST_LOG ("loading feature"); if (!feature_name) return NULL; @@ -480,10 +480,9 @@ load_plugin (xmlTextReaderPtr reader, GList ** feature_list) * @registry: a #GstRegistry * @location: a filename * - * Read the contents of the XML cache file at location - * @location into @registry. + * Read the contents of the XML cache file at @location into @registry. * - * Returns: TRUE on success. + * Returns: %TRUE on success. */ gboolean gst_registry_xml_read_cache (GstRegistry * registry, const char *location) @@ -573,7 +572,7 @@ gst_registry_xml_read_cache (GstRegistry * registry, const char *location) seconds = g_timer_elapsed (timer, NULL); g_timer_destroy (timer); - GST_INFO ("loaded %s in %f seconds", location, seconds); + GST_INFO ("loaded %s in %lf seconds", location, seconds); if (mapped) g_mapped_file_free (mapped);