Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / debian / patches / 0024-tag-xmp-Add-struct-xmp-tag-type-support.patch
diff --git a/gst-plugins-base-subtitles0.10/debian/patches/0024-tag-xmp-Add-struct-xmp-tag-type-support.patch b/gst-plugins-base-subtitles0.10/debian/patches/0024-tag-xmp-Add-struct-xmp-tag-type-support.patch
new file mode 100644 (file)
index 0000000..83408f0
--- /dev/null
@@ -0,0 +1,556 @@
+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);
+     }
+   }