--- /dev/null
+From 2c10edefb47f82a72a27fb54fb181c4e3ea440cf Mon Sep 17 00:00:00 2001
+From: Thiago Santos <thiago.sousa.santos@collabora.co.uk>
+Date: Mon, 18 Apr 2011 16:54:54 -0300
+Subject: [PATCH] tag: xmp: Add struct xmp tag type support
+
+Adds support for writing the xmp struct tag type, it is a compound tag
+that has inner tags.
+---
+ gst-libs/gst/tag/gstxmptag.c | 357 +++++++++++++++++++++++-------------------
+ 1 files changed, 195 insertions(+), 162 deletions(-)
+
+diff --git a/gst-libs/gst/tag/gstxmptag.c b/gst-libs/gst/tag/gstxmptag.c
+index b9fee8f..1a6e3c1 100644
+--- a/gst-libs/gst/tag/gstxmptag.c
++++ b/gst-libs/gst/tag/gstxmptag.c
+@@ -112,14 +112,31 @@ xmp_serialization_data_use_schema (XmpSerializationData * serdata,
+ return FALSE;
+ }
+
++typedef enum
++{
++ GstXmpTagTypeSimple = 0,
++ GstXmpTagTypeBag,
++ GstXmpTagTypeSeq,
++ GstXmpTagTypeStruct,
++
++ /* Not really a xmp type, this is a tag that in gst is represented with
++ * a single value and on xmp it needs 2 (or more) simple values
++ *
++ * e.g. GST_TAG_GEO_LOCATION_ELEVATION needs to be mapped into 2 complementary
++ * tags in the exif's schema. One of them stores the absolute elevation,
++ * and the other one stores if it is above of below sea level.
++ */
++ GstXmpTagTypeCompound
++} GstXmpTagType;
+
+-#define GST_XMP_TAG_TYPE_SIMPLE 0
+-#define GST_XMP_TAG_TYPE_BAG 1
+-#define GST_XMP_TAG_TYPE_SEQ 2
+ struct _XmpTag
+ {
++ const gchar *gst_tag;
+ const gchar *tag_name;
+- gint type;
++ GstXmpTagType type;
++
++ /* Used for struct and compound types */
++ GSList *children;
+
+ XmpSerializationFunc serialize;
+ XmpDeserializationFunc deserialize;
+@@ -129,10 +146,10 @@ static GstTagMergeMode
+ xmp_tag_get_merge_mode (XmpTag * xmptag)
+ {
+ switch (xmptag->type) {
+- case GST_XMP_TAG_TYPE_BAG:
+- case GST_XMP_TAG_TYPE_SEQ:
++ case GstXmpTagTypeBag:
++ case GstXmpTagTypeSeq:
+ return GST_TAG_MERGE_APPEND;
+- case GST_XMP_TAG_TYPE_SIMPLE:
++ case GstXmpTagTypeSimple:
+ default:
+ return GST_TAG_MERGE_KEEP;
+ }
+@@ -142,11 +159,11 @@ static const gchar *
+ xmp_tag_get_type_name (XmpTag * xmptag)
+ {
+ switch (xmptag->type) {
+- case GST_XMP_TAG_TYPE_SEQ:
++ case GstXmpTagTypeSeq:
+ return "rdf:Seq";
+ default:
+ g_assert_not_reached ();
+- case GST_XMP_TAG_TYPE_BAG:
++ case GstXmpTagTypeBag:
+ return "rdf:Bag";
+ }
+ }
+@@ -159,14 +176,9 @@ struct _PendingXmpTag
+ };
+ typedef struct _PendingXmpTag PendingXmpTag;
+
+-
+ /*
+ * A schema is a mapping of strings (the tag name in gstreamer) to a list of
+- * tags in xmp (XmpTag). We need a list because some tags are split into 2
+- * when serialized into xmp.
+- * e.g. GST_TAG_GEO_LOCATION_ELEVATION needs to be mapped into 2 complementary
+- * tags in the exif's schema. One of them stores the absolute elevation,
+- * and the other one stores if it is above of below sea level.
++ * tags in xmp (XmpTag).
+ */
+ typedef GHashTable GstXmpSchema;
+ #define gst_xmp_schema_lookup g_hash_table_lookup
+@@ -214,40 +226,70 @@ _gst_xmp_add_schema (const gchar * name, GstXmpSchema * schema)
+ }
+
+ static void
+-_gst_xmp_schema_add_mapping (GstXmpSchema * schema, const gchar * gst_tag,
+- GPtrArray * array)
++_gst_xmp_schema_add_mapping (GstXmpSchema * schema, XmpTag * tag)
+ {
+ GQuark key;
+
+- key = g_quark_from_string (gst_tag);
++ key = g_quark_from_string (tag->gst_tag);
+
+ if (gst_xmp_schema_lookup (schema, GUINT_TO_POINTER (key))) {
+- GST_WARNING ("Tag %s already present for the schema", gst_tag);
++ GST_WARNING ("Tag %s already present for the schema", tag->gst_tag);
+ g_assert_not_reached ();
+ return;
+ }
+- gst_xmp_schema_insert (schema, GUINT_TO_POINTER (key), array);
++ gst_xmp_schema_insert (schema, GUINT_TO_POINTER (key), tag);
+ }
+
+-static void
+-_gst_xmp_schema_add_simple_mapping (GstXmpSchema * schema,
+- const gchar * gst_tag, const gchar * xmp_tag, gint xmp_type,
+- XmpSerializationFunc serialization_func,
++static XmpTag *
++gst_xmp_tag_create (const gchar * gst_tag, const gchar * xmp_tag,
++ gint xmp_type, XmpSerializationFunc serialization_func,
+ XmpDeserializationFunc deserialization_func)
+ {
+ XmpTag *xmpinfo;
+- GPtrArray *array;
+
+ xmpinfo = g_slice_new (XmpTag);
++ xmpinfo->gst_tag = gst_tag;
+ xmpinfo->tag_name = xmp_tag;
+ xmpinfo->type = xmp_type;
+ xmpinfo->serialize = serialization_func;
+ xmpinfo->deserialize = deserialization_func;
++ xmpinfo->children = NULL;
+
+- array = g_ptr_array_sized_new (1);
+- g_ptr_array_add (array, xmpinfo);
++ return xmpinfo;
++}
+
+- _gst_xmp_schema_add_mapping (schema, gst_tag, array);
++static XmpTag *
++gst_xmp_tag_create_compound (const gchar * gst_tag, const gchar * xmp_tag_a,
++ const gchar * xmp_tag_b, XmpSerializationFunc serialization_func_a,
++ XmpSerializationFunc serialization_func_b,
++ XmpDeserializationFunc deserialization_func)
++{
++ XmpTag *xmptag;
++ XmpTag *xmptag_a =
++ gst_xmp_tag_create (gst_tag, xmp_tag_a, GstXmpTagTypeSimple,
++ serialization_func_a, deserialization_func);
++ XmpTag *xmptag_b =
++ gst_xmp_tag_create (gst_tag, xmp_tag_b, GstXmpTagTypeSimple,
++ serialization_func_b, deserialization_func);
++
++ xmptag =
++ gst_xmp_tag_create (gst_tag, NULL, GstXmpTagTypeCompound, NULL, NULL);
++
++ xmptag->children = g_slist_prepend (xmptag->children, xmptag_b);
++ xmptag->children = g_slist_prepend (xmptag->children, xmptag_a);
++
++ return xmptag;
++}
++
++static void
++_gst_xmp_schema_add_simple_mapping (GstXmpSchema * schema,
++ const gchar * gst_tag, const gchar * xmp_tag, gint xmp_type,
++ XmpSerializationFunc serialization_func,
++ XmpDeserializationFunc deserialization_func)
++{
++ _gst_xmp_schema_add_mapping (schema,
++ gst_xmp_tag_create (gst_tag, xmp_tag, xmp_type, serialization_func,
++ deserialization_func));
+ }
+
+ /*
+@@ -286,22 +328,30 @@ _gst_xmp_schema_get_mapping_reverse (GstXmpSchema * schema,
+ GHashTableIter iter;
+ gpointer key, value;
+ const gchar *ret = NULL;
+- gint index;
+
+ /* Iterate over the hashtable */
+ g_hash_table_iter_init (&iter, schema);
+ while (!ret && g_hash_table_iter_next (&iter, &key, &value)) {
+- GPtrArray *array = (GPtrArray *) value;
+-
+- /* each mapping might contain complementary tags */
+- for (index = 0; index < array->len; index++) {
+- XmpTag *xmpinfo = (XmpTag *) g_ptr_array_index (array, index);
++ XmpTag *xmpinfo = (XmpTag *) value;
+
++ if (xmpinfo->tag_name) {
+ if (strcmp (xmpinfo->tag_name, xmp_tag) == 0) {
+ *_xmp_tag = xmpinfo;
+ ret = g_quark_to_string (GPOINTER_TO_UINT (key));
+ goto out;
+ }
++ } else if (xmpinfo->children) {
++ GSList *iter;
++ for (iter = xmpinfo->children; iter; iter = g_slist_next (iter)) {
++ XmpTag *child = iter->data;
++ if (strcmp (child->tag_name, xmp_tag) == 0) {
++ *_xmp_tag = child;
++ ret = g_quark_to_string (GPOINTER_TO_UINT (key));
++ goto out;
++ }
++ }
++ } else {
++ g_assert_not_reached ();
+ }
+ }
+
+@@ -856,7 +906,6 @@ deserialize_tiff_orientation (XmpTag * xmptag, GstTagList * taglist,
+ static gpointer
+ _init_xmp_tag_map (gpointer user_data)
+ {
+- GPtrArray *array;
+ XmpTag *xmpinfo;
+ GstXmpSchema *schema;
+
+@@ -868,136 +917,95 @@ _init_xmp_tag_map (gpointer user_data)
+ */
+ schema = gst_xmp_schema_new ();
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_ARTIST,
+- "dc:creator", GST_XMP_TAG_TYPE_SEQ, NULL, NULL);
++ "dc:creator", GstXmpTagTypeSeq, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_COPYRIGHT,
+- "dc:rights", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ "dc:rights", GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_DATE, "dc:date",
+- GST_XMP_TAG_TYPE_SEQ, NULL, NULL);
++ GstXmpTagTypeSeq, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_DESCRIPTION,
+- "dc:description", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ "dc:description", GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_KEYWORDS,
+- "dc:subject", GST_XMP_TAG_TYPE_BAG, NULL, NULL);
++ "dc:subject", GstXmpTagTypeBag, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_TITLE, "dc:title",
+- GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ GstXmpTagTypeSimple, NULL, NULL);
+ /* FIXME: we probably want GST_TAG_{,AUDIO_,VIDEO_}MIME_TYPE */
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_VIDEO_CODEC,
+- "dc:format", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ "dc:format", GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_add_schema ("dc", schema);
+
+ /* xap (xmp) schema */
+ schema = gst_xmp_schema_new ();
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_USER_RATING,
+- "xmp:Rating", GST_XMP_TAG_TYPE_SIMPLE, NULL, deserialize_xmp_rating);
++ "xmp:Rating", GstXmpTagTypeSimple, NULL, deserialize_xmp_rating);
+ _gst_xmp_add_schema ("xap", schema);
+
+ /* tiff */
+ schema = gst_xmp_schema_new ();
+ _gst_xmp_schema_add_simple_mapping (schema,
+- GST_TAG_DEVICE_MANUFACTURER, "tiff:Make", GST_XMP_TAG_TYPE_SIMPLE, NULL,
++ GST_TAG_DEVICE_MANUFACTURER, "tiff:Make", GstXmpTagTypeSimple, NULL,
+ NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_DEVICE_MODEL,
+- "tiff:Model", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ "tiff:Model", GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_APPLICATION_NAME,
+- "tiff:Software", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ "tiff:Software", GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_IMAGE_ORIENTATION,
+- "tiff:Orientation", GST_XMP_TAG_TYPE_SIMPLE, serialize_tiff_orientation,
++ "tiff:Orientation", GstXmpTagTypeSimple, serialize_tiff_orientation,
+ deserialize_tiff_orientation);
+ _gst_xmp_add_schema ("tiff", schema);
+
+ /* exif schema */
+ schema = gst_xmp_schema_new ();
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_DATE_TIME,
+- "exif:DateTimeOriginal", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ "exif:DateTimeOriginal", GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema,
+ GST_TAG_GEO_LOCATION_LATITUDE, "exif:GPSLatitude",
+- GST_XMP_TAG_TYPE_SIMPLE, serialize_exif_latitude,
+- deserialize_exif_latitude);
++ GstXmpTagTypeSimple, serialize_exif_latitude, deserialize_exif_latitude);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_GEO_LOCATION_LONGITUDE,
+- "exif:GPSLongitude", GST_XMP_TAG_TYPE_SIMPLE, serialize_exif_longitude,
++ "exif:GPSLongitude", GstXmpTagTypeSimple, serialize_exif_longitude,
+ deserialize_exif_longitude);
+ _gst_xmp_schema_add_simple_mapping (schema,
+ GST_TAG_CAPTURING_EXPOSURE_COMPENSATION, "exif:ExposureBiasValue",
+- GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ GstXmpTagTypeSimple, NULL, NULL);
+
+ /* compound exif tags */
+- array = g_ptr_array_sized_new (2);
+- xmpinfo = g_slice_new (XmpTag);
+- xmpinfo->tag_name = "exif:GPSAltitude";
+- xmpinfo->serialize = serialize_exif_altitude;
+- xmpinfo->deserialize = deserialize_exif_altitude;
+- xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
+- g_ptr_array_add (array, xmpinfo);
+- xmpinfo = g_slice_new (XmpTag);
+- xmpinfo->tag_name = "exif:GPSAltitudeRef";
+- xmpinfo->serialize = serialize_exif_altituderef;
+- xmpinfo->deserialize = deserialize_exif_altitude;
+- xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
+- g_ptr_array_add (array, xmpinfo);
+- _gst_xmp_schema_add_mapping (schema, GST_TAG_GEO_LOCATION_ELEVATION, array);
+-
+- array = g_ptr_array_sized_new (2);
+- xmpinfo = g_slice_new (XmpTag);
+- xmpinfo->tag_name = "exif:GPSSpeed";
+- xmpinfo->serialize = serialize_exif_gps_speed;
+- xmpinfo->deserialize = deserialize_exif_gps_speed;
+- xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
+- g_ptr_array_add (array, xmpinfo);
+- xmpinfo = g_slice_new (XmpTag);
+- xmpinfo->tag_name = "exif:GPSSpeedRef";
+- xmpinfo->serialize = serialize_exif_gps_speedref;
+- xmpinfo->deserialize = deserialize_exif_gps_speed;
+- xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
+- g_ptr_array_add (array, xmpinfo);
+- _gst_xmp_schema_add_mapping (schema,
+- GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, array);
+-
+- array = g_ptr_array_sized_new (2);
+- xmpinfo = g_slice_new (XmpTag);
+- xmpinfo->tag_name = "exif:GPSTrack";
+- xmpinfo->serialize = serialize_exif_gps_direction;
+- xmpinfo->deserialize = deserialize_exif_gps_track;
+- xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
+- g_ptr_array_add (array, xmpinfo);
+- xmpinfo = g_slice_new (XmpTag);
+- xmpinfo->tag_name = "exif:GPSTrackRef";
+- xmpinfo->serialize = serialize_exif_gps_directionref;
+- xmpinfo->deserialize = deserialize_exif_gps_track;
+- xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
+- g_ptr_array_add (array, xmpinfo);
+- _gst_xmp_schema_add_mapping (schema,
+- GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION, array);
++ xmpinfo = gst_xmp_tag_create_compound (GST_TAG_GEO_LOCATION_ELEVATION,
++ "exif:GPSAltitude", "exif:GPSAltitudeRef", serialize_exif_altitude,
++ serialize_exif_altituderef, deserialize_exif_altitude);
++ _gst_xmp_schema_add_mapping (schema, xmpinfo);
++
++ xmpinfo = gst_xmp_tag_create_compound (GST_TAG_GEO_LOCATION_MOVEMENT_SPEED,
++ "exif:GPSSpeed", "exif:GPSSpeedRef", serialize_exif_gps_speed,
++ serialize_exif_gps_speedref, deserialize_exif_gps_speed);
++ _gst_xmp_schema_add_mapping (schema, xmpinfo);
++
++ xmpinfo =
++ gst_xmp_tag_create_compound (GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION,
++ "exif:GPSTrack", "exif:GPSTrackRef", serialize_exif_gps_direction,
++ serialize_exif_gps_directionref, deserialize_exif_gps_track);
++ _gst_xmp_schema_add_mapping (schema, xmpinfo);
++
++ xmpinfo = gst_xmp_tag_create_compound (GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION,
++ "exif:GPSImgDirection", "exif:GPSImgDirectionRef",
++ serialize_exif_gps_direction, serialize_exif_gps_directionref,
++ deserialize_exif_gps_img_direction);
++ _gst_xmp_schema_add_mapping (schema, xmpinfo);
+
+- array = g_ptr_array_sized_new (2);
+- xmpinfo = g_slice_new (XmpTag);
+- xmpinfo->tag_name = "exif:GPSImgDirection";
+- xmpinfo->serialize = serialize_exif_gps_direction;
+- xmpinfo->deserialize = deserialize_exif_gps_img_direction;
+- xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
+- g_ptr_array_add (array, xmpinfo);
+- xmpinfo = g_slice_new (XmpTag);
+- xmpinfo->tag_name = "exif:GPSImgDirectionRef";
+- xmpinfo->serialize = serialize_exif_gps_directionref;
+- xmpinfo->deserialize = deserialize_exif_gps_img_direction;
+- xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
+- g_ptr_array_add (array, xmpinfo);
+- _gst_xmp_schema_add_mapping (schema,
+- GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION, array);
+ _gst_xmp_add_schema ("exif", schema);
+
+ /* photoshop schema */
+ schema = gst_xmp_schema_new ();
+ _gst_xmp_schema_add_simple_mapping (schema,
+ GST_TAG_GEO_LOCATION_COUNTRY, "photoshop:Country",
+- GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_schema_add_simple_mapping (schema, GST_TAG_GEO_LOCATION_CITY,
+- "photoshop:City", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ "photoshop:City", GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_add_schema ("photoshop", schema);
+
+ /* iptc4xmpcore schema */
+ schema = gst_xmp_schema_new ();
+ _gst_xmp_schema_add_simple_mapping (schema,
+ GST_TAG_GEO_LOCATION_SUBLOCATION, "Iptc4xmpCore:Location",
+- GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
++ GstXmpTagTypeSimple, NULL, NULL);
+ _gst_xmp_add_schema ("Iptc4xmpCore", schema);
+
+ return NULL;
+@@ -1540,62 +1548,93 @@ gst_value_serialize_xmp (const GValue * value)
+ }
+
+ static void
+-write_one_tag (const GstTagList * list, const gchar * tag,
+- GPtrArray * xmp_tag_array, gpointer user_data)
++write_one_tag (const GstTagList * list, XmpTag * xmp_tag, gpointer user_data)
+ {
+- guint i = 0, ct = gst_tag_list_get_tag_size (list, tag), tag_index;
++ guint i = 0, ct;
+ XmpSerializationData *serialization_data = user_data;
+ GString *data = serialization_data->data;
+ char *s;
+
+- for (tag_index = 0; tag_index < xmp_tag_array->len; tag_index++) {
+- XmpTag *xmp_tag;
++ /* struct type handled differently */
++ if (xmp_tag->type == GstXmpTagTypeStruct ||
++ xmp_tag->type == GstXmpTagTypeCompound) {
++ GSList *iter;
++ gboolean use_it = FALSE;
++
++ /* check if any of the inner tags are present on the taglist */
++ for (iter = xmp_tag->children; iter && !use_it; iter = g_slist_next (iter)) {
++ XmpTag *child_tag = iter->data;
+
+- xmp_tag = g_ptr_array_index (xmp_tag_array, tag_index);
+- string_open_tag (data, xmp_tag->tag_name);
++ if (gst_tag_list_get_value_index (list, child_tag->gst_tag, 0) != NULL) {
++ use_it = TRUE;
++ break;
++ }
++ }
+
+- /* fast path for single valued tag */
+- if (ct == 1 || xmp_tag->type == GST_XMP_TAG_TYPE_SIMPLE) {
++ if (use_it) {
++ if (xmp_tag->tag_name)
++ string_open_tag (data, xmp_tag->tag_name);
++ /* now write it */
++ for (iter = xmp_tag->children; iter; iter = g_slist_next (iter)) {
++ write_one_tag (list, iter->data, user_data);
++ }
++ if (xmp_tag->tag_name)
++ string_close_tag (data, xmp_tag->tag_name);
++ }
++ return;
++ }
++
++ /* at this point we must have a gst_tag */
++ g_assert (xmp_tag->gst_tag);
++ if (gst_tag_list_get_value_index (list, xmp_tag->gst_tag, 0) == NULL)
++ return;
++
++ ct = gst_tag_list_get_tag_size (list, xmp_tag->gst_tag);
++ string_open_tag (data, xmp_tag->tag_name);
++
++ /* fast path for single valued tag */
++ if (ct == 1 || xmp_tag->type == GstXmpTagTypeSimple) {
++ if (xmp_tag->serialize) {
++ s = xmp_tag->serialize (gst_tag_list_get_value_index (list,
++ xmp_tag->gst_tag, 0));
++ } else {
++ s = gst_value_serialize_xmp (gst_tag_list_get_value_index (list,
++ xmp_tag->gst_tag, 0));
++ }
++ if (s) {
++ g_string_append (data, s);
++ g_free (s);
++ } else {
++ GST_WARNING ("unhandled type for %s to xmp", xmp_tag->gst_tag);
++ }
++ } else {
++ const gchar *typename;
++
++ typename = xmp_tag_get_type_name (xmp_tag);
++
++ string_open_tag (data, typename);
++ for (i = 0; i < ct; i++) {
++ GST_DEBUG ("mapping %s[%u/%u] to xmp", xmp_tag->gst_tag, i, ct);
+ if (xmp_tag->serialize) {
+- s = xmp_tag->serialize (gst_tag_list_get_value_index (list, tag, 0));
++ s = xmp_tag->serialize (gst_tag_list_get_value_index (list,
++ xmp_tag->gst_tag, i));
+ } else {
+- s = gst_value_serialize_xmp (gst_tag_list_get_value_index (list, tag,
+- 0));
++ s = gst_value_serialize_xmp (gst_tag_list_get_value_index (list,
++ xmp_tag->gst_tag, i));
+ }
+ if (s) {
++ string_open_tag (data, "rdf:li");
+ g_string_append (data, s);
++ string_close_tag (data, "rdf:li");
+ g_free (s);
+ } else {
+- GST_WARNING ("unhandled type for %s to xmp", tag);
+- }
+- } else {
+- const gchar *typename;
+-
+- typename = xmp_tag_get_type_name (xmp_tag);
+-
+- string_open_tag (data, typename);
+- for (i = 0; i < ct; i++) {
+- GST_DEBUG ("mapping %s[%u/%u] to xmp", tag, i, ct);
+- if (xmp_tag->serialize) {
+- s = xmp_tag->serialize (gst_tag_list_get_value_index (list, tag, i));
+- } else {
+- s = gst_value_serialize_xmp (gst_tag_list_get_value_index (list, tag,
+- i));
+- }
+- if (s) {
+- string_open_tag (data, "rdf:li");
+- g_string_append (data, s);
+- string_close_tag (data, "rdf:li");
+- g_free (s);
+- } else {
+- GST_WARNING ("unhandled type for %s to xmp", tag);
+- }
++ GST_WARNING ("unhandled type for %s to xmp", xmp_tag->gst_tag);
+ }
+- string_close_tag (data, typename);
+ }
+-
+- string_close_tag (data, xmp_tag->tag_name);
++ string_close_tag (data, typename);
+ }
++
++ string_close_tag (data, xmp_tag->tag_name);
+ }
+
+ /**
+@@ -1652,7 +1691,6 @@ gst_tag_list_to_xmp_buffer_full (const GstTagList * list, gboolean read_only,
+ /* use all schemas */
+ schemas = gst_tag_xmp_list_schemas ();
+ }
+- i = 0;
+ for (i = 0; schemas[i] != NULL; i++) {
+ GstXmpSchema *schema = _gst_xmp_get_schema (schemas[i]);
+ GHashTableIter iter;
+@@ -1664,12 +1702,7 @@ gst_tag_list_to_xmp_buffer_full (const GstTagList * list, gboolean read_only,
+ /* Iterate over the hashtable */
+ g_hash_table_iter_init (&iter, schema);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+- const gchar *tag = g_quark_to_string (GPOINTER_TO_UINT (key));
+-
+- if (gst_tag_list_get_value_index (list, tag, 0) != NULL) {
+- write_one_tag (list, tag, value, (gpointer) & serialization_data);
+- }
+-
++ write_one_tag (list, value, (gpointer) & serialization_data);
+ }
+ }
+