2 * Copyright (C) 2006 Josep Torra <josep@fluendo.com>
3 * 2006 Mathieu Garcia <matthieu@fluendo.com>
4 * 2006,2007 Stefan Kost <ensonic@users.sf.net>
5 * 2008 Sebastian Dröge <slomo@circular-chaos.org>
7 * gstregistrybinary.c: GstRegistryBinary object, support routines
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * - keep registry binary blob and reference strings
27 * - don't free/unmmap contents when leaving gst_registry_binary_read_cache()
28 * - free at gst_deinit() / _priv_gst_registry_cleanup() ?
30 * - GST_PLUGIN_FLAG_CONST
31 * - GstPluginFeature, GstIndexFactory, GstElementFactory
32 * - needs Flags (GST_PLUGIN_FEATURE_FLAG_CONST)
33 * - can we turn loaded into flag?
34 * - why do we collect a list of binary chunks and not write immediately
35 * - because we need to process subchunks, before we can set e.g. nr_of_items
50 #if defined (_MSC_VER) && _MSC_VER >= 1400
54 #include <gst/gst_private.h>
55 #include <gst/gstconfig.h>
56 #include <gst/gstelement.h>
57 #include <gst/gsttypefind.h>
58 #include <gst/gsttypefindfactory.h>
59 #include <gst/gsturi.h>
60 #include <gst/gstinfo.h>
61 #include <gst/gstenumtypes.h>
62 #include <gst/gstpadtemplate.h>
64 #include <gst/gstregistrybinary.h>
66 #include <glib/gstdio.h> /* for g_stat(), g_mapped_file(), ... */
68 #include "glib-compat-private.h"
71 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
73 /* count string length, but return -1 if we hit the eof */
75 _strnlen (const gchar * str, gint maxlen)
82 while (*str++ != '\0') {
92 #define unpack_element(inptr, outptr, element, endptr, error_label) G_STMT_START{ \
93 if (inptr + sizeof(element) >= endptr) \
95 outptr = (element *) inptr; \
96 inptr += sizeof (element); \
99 #define unpack_const_string(inptr, outptr, endptr, error_label) G_STMT_START{\
100 gint _len = _strnlen (inptr, (endptr-inptr)) + 1; \
103 outptr = g_intern_string ((const gchar *)inptr); \
107 #define unpack_string(inptr, outptr, endptr, error_label) G_STMT_START{\
108 gint _len = _strnlen (inptr, (endptr-inptr)) + 1; \
111 outptr = g_memdup ((gconstpointer)inptr, _len); \
115 #define ALIGNMENT (sizeof (void *))
116 #define alignment(_address) (gsize)_address%ALIGNMENT
117 #define align(_ptr) _ptr += (( alignment(_ptr) == 0) ? 0 : ALIGNMENT-alignment(_ptr))
119 /* Registry saving */
122 /* On win32, we can't use g_mkstmp(), because of cross-DLL file I/O problems.
123 * So, we just create the entire binary registry in memory, then write it out
124 * with g_file_set_contents(), which creates a temporary file internally
127 typedef struct BinaryRegistryCache
129 const char *location;
132 } BinaryRegistryCache;
134 static BinaryRegistryCache *
135 gst_registry_binary_cache_init (GstRegistry * registry, const char *location)
137 BinaryRegistryCache *cache = g_new0 (BinaryRegistryCache, 1);
138 cache->location = location;
143 gst_registry_binary_cache_write (GstRegistry * registry,
144 BinaryRegistryCache * cache, unsigned long offset,
145 const void *data, int length)
147 cache->len = MAX (offset + length, cache->len);
148 cache->mem = g_realloc (cache->mem, cache->len);
150 memcpy (cache->mem + offset, data, length);
156 gst_registry_binary_cache_finish (GstRegistry * registry,
157 BinaryRegistryCache * cache, gboolean success)
160 GError *error = NULL;
161 if (!g_file_set_contents (cache->location, (const gchar *) cache->mem,
162 cache->len, &error)) {
163 /* Probably the directory didn't exist; create it */
165 dir = g_path_get_dirname (cache->location);
166 g_mkdir_with_parents (dir, 0777);
169 g_error_free (error);
172 if (!g_file_set_contents (cache->location, (const gchar *) cache->mem,
173 cache->len, &error)) {
174 GST_ERROR ("Failed to write to cache file: %s", error->message);
175 g_error_free (error);
186 typedef struct BinaryRegistryCache
188 const char *location;
190 unsigned long currentoffset;
191 } BinaryRegistryCache;
193 static BinaryRegistryCache *
194 gst_registry_binary_cache_init (GstRegistry * registry, const char *location)
196 BinaryRegistryCache *cache = g_new0 (BinaryRegistryCache, 1);
198 cache->location = location;
199 cache->tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
200 registry->cache_file = g_mkstemp (cache->tmp_location);
201 if (registry->cache_file == -1) {
204 /* oops, I bet the directory doesn't exist */
205 dir = g_path_get_dirname (location);
206 g_mkdir_with_parents (dir, 0777);
209 /* the previous g_mkstemp call overwrote the XXXXXX placeholder ... */
210 g_free (cache->tmp_location);
211 cache->tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
212 registry->cache_file = g_mkstemp (cache->tmp_location);
214 if (registry->cache_file == -1) {
215 GST_DEBUG ("g_mkstemp() failed: %s", g_strerror (errno));
216 g_free (cache->tmp_location);
226 gst_registry_binary_cache_write (GstRegistry * registry,
227 BinaryRegistryCache * cache, unsigned long offset,
228 const void *data, int length)
231 if (offset != cache->currentoffset) {
232 if (lseek (registry->cache_file, offset, SEEK_SET) != 0) {
233 GST_ERROR ("Seeking to new offset failed");
236 cache->currentoffset = offset;
239 written = write (registry->cache_file, data, length);
240 if (written != length) {
241 GST_ERROR ("Failed to write to cache file");
243 cache->currentoffset += written;
249 gst_registry_binary_cache_finish (GstRegistry * registry,
250 BinaryRegistryCache * cache, gboolean success)
252 /* only fsync if we're actually going to use and rename the file below */
253 if (success && fsync (registry->cache_file) < 0)
256 if (close (registry->cache_file) < 0)
260 /* Only do the rename if we wrote the entire file successfully */
261 if (g_rename (cache->tmp_location, cache->location) < 0)
265 g_free (cache->tmp_location);
267 GST_INFO ("Wrote binary registry cache");
273 g_unlink (cache->tmp_location);
274 g_free (cache->tmp_location);
280 GST_ERROR ("fsync() failed: %s", g_strerror (errno));
281 goto fail_after_close;
285 GST_ERROR ("close() failed: %s", g_strerror (errno));
286 goto fail_after_close;
290 GST_ERROR ("g_rename() failed: %s", g_strerror (errno));
291 goto fail_after_close;
297 * gst_registry_binary_write_chunk:
299 * Write from a memory location to the registry cache file
301 * Returns: %TRUE for success
303 inline static gboolean
304 gst_registry_binary_write_chunk (GstRegistry * registry,
305 BinaryRegistryCache * cache, const void *mem,
306 const gssize size, unsigned long *file_position, gboolean align)
308 gchar padder[ALIGNMENT] = { 0, };
311 /* Padding to insert the struct that requiere word alignment */
312 if ((align) && (alignment (*file_position) != 0)) {
313 padsize = ALIGNMENT - alignment (*file_position);
314 if (gst_registry_binary_cache_write (registry, cache, *file_position,
315 padder, padsize) != padsize) {
316 GST_ERROR ("Failed to write binary registry padder");
319 *file_position += padsize;
322 if (gst_registry_binary_cache_write (registry, cache, *file_position,
323 mem, size) != size) {
324 GST_ERROR ("Failed to write binary registry element");
328 *file_position += size;
335 * gst_registry_binary_initialize_magic:
337 * Initialize the GstBinaryRegistryMagic, setting both our magic number and
338 * gstreamer major/minor version
340 inline static gboolean
341 gst_registry_binary_initialize_magic (GstBinaryRegistryMagic * m)
343 memset (m, 0, sizeof (GstBinaryRegistryMagic));
345 if (!strncpy (m->magic, GST_MAGIC_BINARY_REGISTRY_STR,
346 GST_MAGIC_BINARY_REGISTRY_LEN)
347 || !strncpy (m->version, GST_MAGIC_BINARY_VERSION_STR,
348 GST_MAGIC_BINARY_VERSION_LEN)) {
349 GST_ERROR ("Failed to write magic to the registry magic structure");
358 * gst_registry_binary_save_const_string:
360 * Store a const string in a binary chunk.
362 * Returns: %TRUE for success
364 inline static gboolean
365 gst_registry_binary_save_const_string (GList ** list, const gchar * str)
367 GstBinaryChunk *chunk;
369 if (G_UNLIKELY (str == NULL)) {
370 GST_ERROR ("unexpected NULL string in plugin or plugin feature data");
374 chunk = g_malloc (sizeof (GstBinaryChunk));
375 chunk->data = (gpointer) str;
376 chunk->size = strlen ((gchar *) chunk->data) + 1;
377 chunk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
378 chunk->align = FALSE;
379 *list = g_list_prepend (*list, chunk);
384 * gst_registry_binary_save_string:
386 * Store a string in a binary chunk.
388 * Returns: %TRUE for success
390 inline static gboolean
391 gst_registry_binary_save_string (GList ** list, gchar * str)
393 GstBinaryChunk *chunk;
395 chunk = g_malloc (sizeof (GstBinaryChunk));
397 chunk->size = strlen ((gchar *) chunk->data) + 1;
398 chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
399 chunk->align = FALSE;
400 *list = g_list_prepend (*list, chunk);
406 * gst_registry_binary_save_data:
408 * Store some data in a binary chunk.
410 * Returns: the initialized chunk
412 inline static GstBinaryChunk *
413 gst_registry_binary_make_data (gpointer data, gulong size)
415 GstBinaryChunk *chunk;
417 chunk = g_malloc (sizeof (GstBinaryChunk));
420 chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
427 * gst_registry_binary_save_pad_template:
429 * Store pad_templates in binary chunks.
431 * Returns: %TRUE for success
434 gst_registry_binary_save_pad_template (GList ** list,
435 GstStaticPadTemplate * template)
437 GstBinaryPadTemplate *pt;
440 pt = g_malloc0 (sizeof (GstBinaryPadTemplate));
441 chk = gst_registry_binary_make_data (pt, sizeof (GstBinaryPadTemplate));
443 pt->presence = template->presence;
444 pt->direction = template->direction;
446 /* pack pad template strings */
447 gst_registry_binary_save_const_string (list,
448 (gchar *) (template->static_caps.string));
449 gst_registry_binary_save_const_string (list, template->name_template);
451 *list = g_list_prepend (*list, chk);
458 * gst_registry_binary_save_feature:
460 * Store features in binary chunks.
462 * Returns: %TRUE for success
465 gst_registry_binary_save_feature (GList ** list, GstPluginFeature * feature)
467 const gchar *type_name = g_type_name (G_OBJECT_TYPE (feature));
468 GstBinaryPluginFeature *pf = NULL;
469 GstBinaryChunk *chk = NULL;
473 GST_ERROR ("NULL feature type_name, aborting.");
477 if (GST_IS_ELEMENT_FACTORY (feature)) {
478 GstBinaryElementFactory *ef;
479 GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
481 ef = g_malloc0 (sizeof (GstBinaryElementFactory));
482 chk = gst_registry_binary_make_data (ef, sizeof (GstBinaryElementFactory));
483 ef->npadtemplates = ef->ninterfaces = ef->nuriprotocols = 0;
484 pf = (GstBinaryPluginFeature *) ef;
486 /* save interfaces */
487 for (walk = factory->interfaces; walk;
488 walk = g_list_next (walk), ef->ninterfaces++) {
489 gst_registry_binary_save_const_string (list, (gchar *) walk->data);
491 GST_DEBUG ("Saved %d Interfaces", ef->ninterfaces);
493 if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
494 if (factory->uri_protocols && *factory->uri_protocols) {
495 GstBinaryChunk *subchk;
499 gst_registry_binary_make_data (&factory->uri_type,
500 sizeof (factory->uri_type));
501 subchk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
503 protocol = factory->uri_protocols;
505 gst_registry_binary_save_const_string (list, *protocol++);
508 *list = g_list_prepend (*list, subchk);
509 GST_DEBUG ("Saved %d UriTypes", ef->nuriprotocols);
511 g_warning ("GStreamer feature '%s' is URI handler but does not provide"
512 " any protocols it can handle", feature->name);
516 /* save pad-templates */
517 for (walk = factory->staticpadtemplates; walk;
518 walk = g_list_next (walk), ef->npadtemplates++) {
519 GstStaticPadTemplate *template = walk->data;
521 if (!gst_registry_binary_save_pad_template (list, template)) {
522 GST_ERROR ("Can't fill pad template, aborting.");
527 /* pack element factory strings */
528 gst_registry_binary_save_const_string (list, factory->details.author);
529 gst_registry_binary_save_const_string (list, factory->details.description);
530 gst_registry_binary_save_const_string (list, factory->details.klass);
531 gst_registry_binary_save_const_string (list, factory->details.longname);
532 } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
533 GstBinaryTypeFindFactory *tff;
534 GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
536 tff = g_malloc0 (sizeof (GstBinaryTypeFindFactory));
538 gst_registry_binary_make_data (tff, sizeof (GstBinaryTypeFindFactory));
539 tff->nextensions = 0;
540 pf = (GstBinaryPluginFeature *) tff;
542 /* save extensions */
543 if (factory->extensions) {
544 while (factory->extensions[tff->nextensions]) {
545 gst_registry_binary_save_const_string (list,
546 factory->extensions[tff->nextensions++]);
551 GstCaps *copy = gst_caps_copy (factory->caps);
554 /* we copy the caps here so we can simplify them
555 * before saving. This is a lot faster when loading
557 gst_caps_do_simplify (copy);
558 str = gst_caps_to_string (copy);
559 gst_caps_unref (copy);
560 gst_registry_binary_save_string (list, str);
562 gst_registry_binary_save_const_string (list, "");
565 } else if (GST_IS_INDEX_FACTORY (feature)) {
566 GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
568 pf = g_malloc0 (sizeof (GstBinaryPluginFeature));
569 chk = gst_registry_binary_make_data (pf, sizeof (GstBinaryPluginFeature));
570 pf->rank = feature->rank;
572 /* pack element factory strings */
573 gst_registry_binary_save_const_string (list, factory->longdesc);
575 GST_WARNING ("unhandled feature type '%s'", type_name);
579 pf->rank = feature->rank;
580 *list = g_list_prepend (*list, chk);
582 /* pack plugin feature strings */
583 gst_registry_binary_save_const_string (list, feature->name);
584 gst_registry_binary_save_const_string (list, (gchar *) type_name);
597 gst_registry_binary_save_plugin_dep (GList ** list, GstPluginDep * dep)
603 ed = g_new0 (GstBinaryDep, 1);
604 chk = gst_registry_binary_make_data (ed, sizeof (GstBinaryDep));
606 ed->flags = dep->flags;
611 ed->env_hash = dep->env_hash;
612 ed->stat_hash = dep->stat_hash;
614 for (s = dep->env_vars; s != NULL && *s != NULL; ++s, ++ed->n_env_vars)
615 gst_registry_binary_save_string (list, g_strdup (*s));
617 for (s = dep->paths; s != NULL && *s != NULL; ++s, ++ed->n_paths)
618 gst_registry_binary_save_string (list, g_strdup (*s));
620 for (s = dep->names; s != NULL && *s != NULL; ++s, ++ed->n_names)
621 gst_registry_binary_save_string (list, g_strdup (*s));
623 *list = g_list_prepend (*list, chk);
625 GST_LOG ("Saved external plugin dependency");
630 * gst_registry_binary_save_plugin:
632 * Adapt a GstPlugin to our GstBinaryPluginElement structure, and write it to
636 gst_registry_binary_save_plugin (GList ** list, GstRegistry * registry,
639 GstBinaryPluginElement *pe;
641 GList *plugin_features = NULL;
644 pe = g_malloc0 (sizeof (GstBinaryPluginElement));
645 chk = gst_registry_binary_make_data (pe, sizeof (GstBinaryPluginElement));
647 pe->file_size = plugin->file_size;
648 pe->file_mtime = plugin->file_mtime;
652 /* pack external deps */
653 for (walk = plugin->priv->deps; walk != NULL; walk = walk->next) {
654 if (!gst_registry_binary_save_plugin_dep (list, walk->data)) {
655 GST_ERROR ("Could not save external plugin dependency, aborting.");
661 /* pack plugin features */
663 gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name);
664 for (walk = plugin_features; walk; walk = g_list_next (walk), pe->nfeatures++) {
665 GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data);
667 if (!gst_registry_binary_save_feature (list, feature)) {
668 GST_ERROR ("Can't fill plugin feature, aborting.");
672 GST_DEBUG ("Save plugin '%s' with %d feature(s)", plugin->desc.name,
675 gst_plugin_feature_list_free (plugin_features);
677 /* pack plugin element strings */
678 gst_registry_binary_save_const_string (list, plugin->desc.origin);
679 gst_registry_binary_save_const_string (list, plugin->desc.package);
680 gst_registry_binary_save_const_string (list, plugin->desc.source);
681 gst_registry_binary_save_const_string (list, plugin->desc.license);
682 gst_registry_binary_save_const_string (list, plugin->desc.version);
683 gst_registry_binary_save_const_string (list, plugin->filename);
684 gst_registry_binary_save_const_string (list, plugin->desc.description);
685 gst_registry_binary_save_const_string (list, plugin->desc.name);
687 *list = g_list_prepend (*list, chk);
689 GST_DEBUG ("Found %d features in plugin \"%s\"", pe->nfeatures,
695 gst_plugin_feature_list_free (plugin_features);
702 * gst_registry_binary_write_cache:
703 * @registry: a #GstRegistry
704 * @location: a filename
706 * Write the @registry to a cache to file at given @location.
708 * Returns: %TRUE on success.
711 gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
714 GstBinaryRegistryMagic magic;
715 GList *to_write = NULL;
716 unsigned long file_position = 0;
717 BinaryRegistryCache *cache;
719 GST_INFO ("Building binary registry cache image");
721 g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
723 if (!gst_registry_binary_initialize_magic (&magic))
726 /* iterate trough the list of plugins and fit them into binary structures */
727 for (walk = registry->plugins; walk; walk = g_list_next (walk)) {
728 GstPlugin *plugin = GST_PLUGIN (walk->data);
730 if (!plugin->filename)
733 if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
736 if (g_stat (plugin->filename, &statbuf) < 0 ||
737 plugin->file_mtime != statbuf.st_mtime ||
738 plugin->file_size != statbuf.st_size)
742 if (!gst_registry_binary_save_plugin (&to_write, registry, plugin)) {
743 GST_ERROR ("Can't write binary plugin information for \"%s\"",
748 GST_INFO ("Writing binary registry cache");
750 cache = gst_registry_binary_cache_init (registry, location);
755 if (gst_registry_binary_cache_write (registry, cache, file_position,
756 &magic, sizeof (GstBinaryRegistryMagic)) !=
757 sizeof (GstBinaryRegistryMagic)) {
758 GST_ERROR ("Failed to write binary registry magic");
761 file_position += sizeof (GstBinaryRegistryMagic);
763 /* write out data chunks */
764 for (walk = to_write; walk; walk = g_list_next (walk)) {
765 GstBinaryChunk *cur = walk->data;
767 if (!gst_registry_binary_write_chunk (registry, cache, cur->data, cur->size,
768 &file_position, cur->align)) {
769 if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
775 if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
780 g_list_free (to_write);
782 if (!gst_registry_binary_cache_finish (registry, cache, TRUE))
790 for (walk = to_write; walk; walk = g_list_next (walk)) {
791 GstBinaryChunk *cur = walk->data;
793 if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
797 g_list_free (to_write);
800 (void) gst_registry_binary_cache_finish (registry, cache, FALSE);
810 /* Registry loading */
813 * gst_registry_binary_check_magic:
815 * Check GstBinaryRegistryMagic validity.
816 * Return < 0 if something is wrong, -2 means
817 * that just the version of the registry is out of
818 * date, -1 is a general failure.
821 gst_registry_binary_check_magic (gchar ** in, gsize size)
823 GstBinaryRegistryMagic *m;
826 GST_DEBUG ("Reading/casting for GstBinaryRegistryMagic at address %p", *in);
827 unpack_element (*in, m, GstBinaryRegistryMagic, (*in + size), fail);
829 if (strncmp (m->magic, GST_MAGIC_BINARY_REGISTRY_STR,
830 GST_MAGIC_BINARY_REGISTRY_LEN) != 0) {
832 ("Binary registry magic is different : %02x%02x%02x%02x != %02x%02x%02x%02x",
833 GST_MAGIC_BINARY_REGISTRY_STR[0] & 0xff,
834 GST_MAGIC_BINARY_REGISTRY_STR[1] & 0xff,
835 GST_MAGIC_BINARY_REGISTRY_STR[2] & 0xff,
836 GST_MAGIC_BINARY_REGISTRY_STR[3] & 0xff, m->magic[0] & 0xff,
837 m->magic[1] & 0xff, m->magic[2] & 0xff, m->magic[3] & 0xff);
840 if (strncmp (m->version, GST_MAGIC_BINARY_VERSION_STR,
841 GST_MAGIC_BINARY_VERSION_LEN)) {
842 GST_WARNING ("Binary registry magic version is different : %s != %s",
843 GST_MAGIC_BINARY_VERSION_STR, m->version);
850 GST_WARNING ("Not enough data for binary registry magic structure");
856 * gst_registry_binary_load_pad_template:
858 * Make a new GstStaticPadTemplate from current GstBinaryPadTemplate structure
860 * Returns: new GstStaticPadTemplate
863 gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in,
866 GstBinaryPadTemplate *pt;
867 GstStaticPadTemplate *template;
870 GST_DEBUG ("Reading/casting for GstBinaryPadTemplate at address %p", *in);
871 unpack_element (*in, pt, GstBinaryPadTemplate, end, fail);
873 template = g_new0 (GstStaticPadTemplate, 1);
874 template->presence = pt->presence;
875 template->direction = pt->direction;
877 /* unpack pad template strings */
878 unpack_const_string (*in, template->name_template, end, fail);
879 unpack_string (*in, template->static_caps.string, end, fail);
881 __gst_element_factory_add_static_pad_template (factory, template);
882 GST_DEBUG ("Added pad_template %s", template->name_template);
887 GST_INFO ("Reading pad template failed");
893 * gst_registry_binary_load_feature:
895 * Make a new GstPluginFeature from current binary plugin feature structure
897 * Returns: new GstPluginFeature
900 gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
901 gchar * end, const gchar * plugin_name)
903 GstBinaryPluginFeature *pf = NULL;
904 GstPluginFeature *feature = NULL;
905 gchar *type_name = NULL, *str;
909 /* unpack plugin feature strings */
910 unpack_string (*in, type_name, end, fail);
913 GST_ERROR ("No feature type name");
917 GST_DEBUG ("Plugin '%s' feature typename : '%s'", plugin_name, type_name);
919 if (!(type = g_type_from_name (type_name))) {
920 GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name,
925 if ((feature = g_object_new (type, NULL)) == NULL) {
926 GST_ERROR ("Can't create feature from type");
931 if (!GST_IS_PLUGIN_FEATURE (feature)) {
932 GST_ERROR ("typename : '%s' is not a plugin feature", type_name);
936 /* unpack more plugin feature strings */
937 unpack_string (*in, feature->name, end, fail);
939 if (GST_IS_ELEMENT_FACTORY (feature)) {
940 GstBinaryElementFactory *ef;
941 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (feature);
944 GST_LOG ("Reading/casting for GstBinaryElementFactory at address %p", *in);
945 unpack_element (*in, ef, GstBinaryElementFactory, end, fail);
946 pf = (GstBinaryPluginFeature *) ef;
948 /* unpack element factory strings */
949 unpack_string (*in, factory->details.longname, end, fail);
950 unpack_string (*in, factory->details.klass, end, fail);
951 unpack_string (*in, factory->details.description, end, fail);
952 unpack_string (*in, factory->details.author, end, fail);
953 GST_DEBUG ("Element factory : '%s' with npadtemplates=%d",
954 factory->details.longname, ef->npadtemplates);
956 /* load pad templates */
957 for (i = 0; i < ef->npadtemplates; i++) {
958 if (!gst_registry_binary_load_pad_template (factory, in, end)) {
959 GST_ERROR ("Error while loading binary pad template");
965 if (ef->nuriprotocols) {
966 GST_DEBUG ("Reading %d UriTypes at address %p", ef->nuriprotocols, *in);
969 factory->uri_type = *((guint *) * in);
970 *in += sizeof (factory->uri_type);
971 /*unpack_element(*in, &factory->uri_type, factory->uri_type, end, fail); */
973 factory->uri_protocols = g_new0 (gchar *, ef->nuriprotocols + 1);
974 for (i = 0; i < ef->nuriprotocols; i++) {
975 unpack_string (*in, str, end, fail);
976 factory->uri_protocols[i] = str;
979 /* load interfaces */
980 GST_DEBUG ("Reading %d Interfaces at address %p", ef->ninterfaces, *in);
981 for (i = 0; i < ef->ninterfaces; i++) {
982 unpack_string (*in, str, end, fail);
983 __gst_element_factory_add_interface (factory, str);
986 } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
987 GstBinaryTypeFindFactory *tff;
988 GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
991 GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
992 unpack_element (*in, tff, GstBinaryTypeFindFactory, end, fail);
993 pf = (GstBinaryPluginFeature *) tff;
996 unpack_string (*in, str, end, fail);
997 factory->caps = (str && *str) ? gst_caps_from_string (str) : NULL;
999 /* load extensions */
1000 if (tff->nextensions) {
1001 GST_DEBUG ("Reading %d Typefind extensions at address %p",
1002 tff->nextensions, *in);
1003 factory->extensions = g_new0 (gchar *, tff->nextensions + 1);
1004 for (i = 0; i < tff->nextensions; i++) {
1005 unpack_string (*in, str, end, fail);
1006 factory->extensions[i] = str;
1009 } else if (GST_IS_INDEX_FACTORY (feature)) {
1010 GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
1013 GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
1014 unpack_element (*in, pf, GstBinaryPluginFeature, end, fail);
1016 /* unpack index factory strings */
1017 unpack_string (*in, factory->longdesc, end, fail);
1019 GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
1023 feature->rank = pf->rank;
1025 /* should already be the interned string, but better make sure */
1026 feature->plugin_name = g_intern_string (plugin_name);
1028 gst_registry_add_feature (registry, feature);
1029 GST_DEBUG ("Added feature %s", feature->name);
1036 GST_INFO ("Reading plugin feature failed");
1038 if (GST_IS_OBJECT (feature))
1039 gst_object_unref (feature);
1041 g_object_unref (feature);
1046 gst_registry_binary_load_plugin_dep_strv (gchar ** in, gchar * end, guint n)
1053 arr = g_new0 (gchar *, n + 1);
1055 unpack_string (*in, arr[n - 1], end, fail);
1060 GST_INFO ("Reading plugin dependency strings failed");
1065 gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in,
1073 GST_LOG_OBJECT (plugin, "Unpacking GstBinaryDep from %p", *in);
1074 unpack_element (*in, d, GstBinaryDep, end, fail);
1076 dep = g_new0 (GstPluginDep, 1);
1078 dep->env_hash = d->env_hash;
1079 dep->stat_hash = d->stat_hash;
1081 dep->flags = d->flags;
1083 dep->names = gst_registry_binary_load_plugin_dep_strv (in, end, d->n_names);
1084 dep->paths = gst_registry_binary_load_plugin_dep_strv (in, end, d->n_paths);
1086 gst_registry_binary_load_plugin_dep_strv (in, end, d->n_env_vars);
1088 plugin->priv->deps = g_list_append (plugin->priv->deps, dep);
1090 GST_DEBUG_OBJECT (plugin, "Loaded external plugin dependency from registry: "
1091 "env_hash: %08x, stat_hash: %08x", dep->env_hash, dep->stat_hash);
1092 for (s = dep->env_vars; s != NULL && *s != NULL; ++s)
1093 GST_LOG_OBJECT (plugin, " evar: %s", *s);
1094 for (s = dep->paths; s != NULL && *s != NULL; ++s)
1095 GST_LOG_OBJECT (plugin, " path: %s", *s);
1096 for (s = dep->names; s != NULL && *s != NULL; ++s)
1097 GST_LOG_OBJECT (plugin, " name: %s", *s);
1101 GST_INFO ("Reading plugin dependency failed");
1106 * gst_registry_binary_load_plugin:
1108 * Make a new GstPlugin from current GstBinaryPluginElement structure
1109 * and save it to the GstRegistry. Return an offset to the next
1110 * GstBinaryPluginElement structure.
1113 gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in,
1116 GstBinaryPluginElement *pe;
1117 GstPlugin *plugin = NULL;
1121 GST_LOG ("Reading/casting for GstBinaryPluginElement at address %p", *in);
1122 unpack_element (*in, pe, GstBinaryPluginElement, end, fail);
1124 plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
1126 /* TODO: also set GST_PLUGIN_FLAG_CONST */
1127 plugin->flags |= GST_PLUGIN_FLAG_CACHED;
1128 plugin->file_mtime = pe->file_mtime;
1129 plugin->file_size = pe->file_size;
1131 /* unpack plugin element strings */
1132 unpack_const_string (*in, plugin->desc.name, end, fail);
1133 unpack_string (*in, plugin->desc.description, end, fail);
1134 unpack_string (*in, plugin->filename, end, fail);
1135 unpack_const_string (*in, plugin->desc.version, end, fail);
1136 unpack_const_string (*in, plugin->desc.license, end, fail);
1137 unpack_const_string (*in, plugin->desc.source, end, fail);
1138 unpack_const_string (*in, plugin->desc.package, end, fail);
1139 unpack_const_string (*in, plugin->desc.origin, end, fail);
1140 GST_LOG ("read strings for name='%s'", plugin->desc.name);
1141 GST_LOG (" desc.description='%s'", plugin->desc.description);
1142 GST_LOG (" filename='%s'", plugin->filename);
1143 GST_LOG (" desc.version='%s'", plugin->desc.version);
1144 GST_LOG (" desc.license='%s'", plugin->desc.license);
1145 GST_LOG (" desc.source='%s'", plugin->desc.source);
1146 GST_LOG (" desc.package='%s'", plugin->desc.package);
1147 GST_LOG (" desc.origin='%s'", plugin->desc.origin);
1149 plugin->basename = g_path_get_basename (plugin->filename);
1151 /* Takes ownership of plugin */
1152 gst_registry_add_plugin (registry, plugin);
1153 GST_DEBUG ("Added plugin '%s' plugin with %d features from binary registry",
1154 plugin->desc.name, pe->nfeatures);
1156 /* Load plugin features */
1157 for (i = 0; i < pe->nfeatures; i++) {
1158 if (!gst_registry_binary_load_feature (registry, in, end,
1159 plugin->desc.name)) {
1160 GST_ERROR ("Error while loading binary feature");
1161 gst_registry_remove_plugin (registry, plugin);
1166 /* Load external plugin dependencies */
1167 for (i = 0; i < pe->n_deps; ++i) {
1168 if (!gst_registry_binary_load_plugin_dep (plugin, in, end)) {
1169 GST_ERROR_OBJECT (plugin, "Could not read external plugin dependency");
1170 gst_registry_remove_plugin (registry, plugin);
1179 GST_INFO ("Reading plugin failed");
1185 * gst_registry_binary_read_cache:
1186 * @registry: a #GstRegistry
1187 * @location: a filename
1189 * Read the contents of the binary cache file at @location into @registry.
1191 * Returns: %TRUE on success.
1194 gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
1196 GMappedFile *mapped = NULL;
1197 gchar *contents = NULL;
1201 gboolean res = FALSE;
1202 gint check_magic_result;
1203 #ifndef GST_DISABLE_GST_DEBUG
1204 GTimer *timer = NULL;
1208 /* make sure these types exist */
1209 GST_TYPE_ELEMENT_FACTORY;
1210 GST_TYPE_TYPE_FIND_FACTORY;
1211 GST_TYPE_INDEX_FACTORY;
1213 #ifndef GST_DISABLE_GST_DEBUG
1214 timer = g_timer_new ();
1217 mapped = g_mapped_file_new (location, FALSE, &err);
1219 GST_INFO ("Unable to mmap file %s : %s", location, err->message);
1223 g_file_get_contents (location, &contents, &size, &err);
1225 GST_INFO ("Unable to read file %s : %s", location, err->message);
1226 #ifndef GST_DISABLE_GST_DEBUG
1227 g_timer_destroy (timer);
1233 if ((contents = g_mapped_file_get_contents (mapped)) == NULL) {
1234 GST_ERROR ("Can't load file %s : %s", location, g_strerror (errno));
1237 /* check length for header */
1238 size = g_mapped_file_get_length (mapped);
1241 /* in is a cursor pointer, we initialize it with the begin of registry and is updated on each read */
1243 GST_DEBUG ("File data at address %p", in);
1244 if (size < sizeof (GstBinaryRegistryMagic)) {
1245 GST_ERROR ("No or broken registry header");
1249 /* check if header is valid */
1250 if ((check_magic_result = gst_registry_binary_check_magic (&in, size)) < 0) {
1252 if (check_magic_result == -1)
1254 ("Binary registry type not recognized (invalid magic) for file at %s",
1259 /* check if there are plugins in the file */
1260 if (!(((gsize) in + sizeof (GstBinaryPluginElement)) <
1261 (gsize) contents + size)) {
1262 GST_INFO ("No binary plugins structure to read");
1263 /* empty file, this is not an error */
1265 gchar *end = contents + size;
1266 /* read as long as we still have space for a GstBinaryPluginElement */
1268 ((gsize) in + sizeof (GstBinaryPluginElement)) <
1269 (gsize) contents + size;) {
1270 GST_DEBUG ("reading binary registry %" G_GSIZE_FORMAT "(%x)/%"
1271 G_GSIZE_FORMAT, (gsize) in - (gsize) contents,
1272 (guint) ((gsize) in - (gsize) contents), size);
1273 if (!gst_registry_binary_load_plugin (registry, &in, end)) {
1274 GST_ERROR ("Problem while reading binary registry %s", location);
1280 #ifndef GST_DISABLE_GST_DEBUG
1281 g_timer_stop (timer);
1282 seconds = g_timer_elapsed (timer, NULL);
1285 GST_INFO ("loaded %s in %lf seconds", location, seconds);
1288 /* TODO: once we re-use the pointers to registry contents, return here */
1291 #ifndef GST_DISABLE_GST_DEBUG
1292 g_timer_destroy (timer);
1295 g_mapped_file_free (mapped);
1303 /* FIXME 0.11: these are here for backwards compatibility */
1306 gst_registry_xml_read_cache (GstRegistry * registry, const char *location)
1312 gst_registry_xml_write_cache (GstRegistry * registry, const char *location)