tag: xmp: Add struct xmp tag type support
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Mon, 18 Apr 2011 19:54:54 +0000 (16:54 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Sun, 15 May 2011 16:02:38 +0000 (13:02 -0300)
Adds support for writing the xmp struct tag type, it is a compound tag
that has inner tags.

gst-libs/gst/tag/gstxmptag.c

index b9fee8f..1a6e3c1 100644 (file)
@@ -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);
     }
   }