tag: xmp: Adds mappings for LATITUDE and LONGITUDE
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Mon, 22 Mar 2010 18:18:28 +0000 (15:18 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Wed, 24 Mar 2010 18:33:16 +0000 (15:33 -0300)
Adds the mappings for those tags and tests
for tags serialization.

Fixes #613690

gst-libs/gst/tag/gstxmptag.c
tests/check/libs/tag.c

index b1d9108..5ede287 100644 (file)
@@ -157,6 +157,130 @@ _xmp_tag_get_mapping_reverse (const gchar * xmp_tag, XmpTag ** _xmp_tag)
   return ret;
 }
 
+/* (de)serialize functions */
+static gchar *
+serialize_exif_gps_coordinate (const GValue * value, gchar pos, gchar neg)
+{
+  gdouble num;
+  gchar c;
+  gint integer;
+  gchar fraction[G_ASCII_DTOSTR_BUF_SIZE];
+
+  g_return_val_if_fail (G_VALUE_TYPE (value) == G_TYPE_DOUBLE, NULL);
+
+  num = g_value_get_double (value);
+  if (num < 0) {
+    c = neg;
+    num *= -1;
+  } else {
+    c = pos;
+  }
+  integer = (gint) num;
+
+  g_ascii_dtostr (fraction, sizeof (fraction), (num - integer) * 60);
+
+  /* FIXME review GPSCoordinate serialization spec for the .mm or ,ss
+   * decision. Couldn't understand it clearly */
+  return g_strdup_printf ("%d,%s%c", integer, fraction, c);
+}
+
+static gchar *
+serialize_exif_latitude (const GValue * value)
+{
+  return serialize_exif_gps_coordinate (value, 'N', 'S');
+}
+
+static gchar *
+serialize_exif_longitude (const GValue * value)
+{
+  return serialize_exif_gps_coordinate (value, 'E', 'W');
+}
+
+static void
+deserialize_exif_gps_coordinate (GstTagList * taglist, const gchar * gst_tag,
+    const gchar * str, gchar pos, gchar neg)
+{
+  gdouble value = 0;
+  gint d = 0, m = 0, s = 0;
+  gdouble m2 = 0;
+  gchar c;
+  const gchar *current;
+
+  /* get the degrees */
+  if (sscanf (str, "%d", &d) != 1)
+    goto error;
+
+  /* find the beginning of the minutes */
+  current = strchr (str, ',');
+  if (current == NULL)
+    goto end;
+  current += 1;
+
+  /* check if it uses ,SS or .mm */
+  if (strchr (current, ',') != NULL) {
+    sscanf (current, "%d,%d%c", &m, &s, &c);
+  } else {
+    gchar *copy = g_strdup (current);
+    gint len = strlen (copy);
+    gint i;
+
+    /* check the last letter */
+    for (i = len - 1; len >= 0; len--) {
+      if (g_ascii_isspace (copy[i]))
+        continue;
+
+      if (g_ascii_isalpha (copy[i])) {
+        /* found it */
+        c = copy[i];
+        copy[i] = '\0';
+        break;
+
+      } else {
+        /* something is wrong */
+        g_free (copy);
+        goto error;
+      }
+    }
+
+    /* use a copy so we can change the last letter as E can cause
+     * problems here */
+    m2 = g_ascii_strtod (copy, NULL);
+    g_free (copy);
+  }
+
+end:
+  /* we can add them all as those that aren't parsed are 0 */
+  value = d + (m / 60.0) + (s / (60.0 * 60.0)) + (m2 / 60.0);
+
+  if (c == pos) {
+    //NOP
+  } else if (c == neg) {
+    value *= -1;
+  } else {
+    goto error;
+  }
+
+  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, gst_tag, value, NULL);
+  return;
+
+error:
+  GST_WARNING ("Failed to deserialize gps coordinate: %s", str);
+}
+
+static void
+deserialize_exif_latitude (GstTagList * taglist, const gchar * gst_tag,
+    const gchar * str)
+{
+  deserialize_exif_gps_coordinate (taglist, gst_tag, str, 'N', 'S');
+}
+
+static void
+deserialize_exif_longitude (GstTagList * taglist, const gchar * gst_tag,
+    const gchar * str)
+{
+  deserialize_exif_gps_coordinate (taglist, gst_tag, str, 'E', 'W');
+}
+
 /* look at this page for addtional schemas
  * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/XMP.html
  */
@@ -182,6 +306,13 @@ _init_xmp_tag_map ()
   /* FIXME: we probably want GST_TAG_{,AUDIO_,VIDEO_}MIME_TYPE */
   _xmp_tag_add_simple_mapping (GST_TAG_VIDEO_CODEC, "dc:format", NULL, NULL);
 
+  /* exif schema */
+  _xmp_tag_add_simple_mapping (GST_TAG_GEO_LOCATION_LATITUDE,
+      "exif:GPSLatitude", serialize_exif_latitude, deserialize_exif_latitude);
+  _xmp_tag_add_simple_mapping (GST_TAG_GEO_LOCATION_LONGITUDE,
+      "exif:GPSLongitude", serialize_exif_longitude,
+      deserialize_exif_longitude);
+
   /* photoshop schema */
   _xmp_tag_add_simple_mapping (GST_TAG_GEO_LOCATION_COUNTRY,
       "photoshop:Country", NULL, NULL);
index bfe738d..6194876 100644 (file)
@@ -852,6 +852,116 @@ GST_START_TEST (test_xmp_parsing)
 
 GST_END_TEST;
 
+static void
+do_xmp_tag_serialization_deserialization (const gchar * gsttag, GValue * value)
+{
+  GstTagList *taglist = gst_tag_list_new ();
+  GstTagList *taglist2;
+  GstBuffer *buf;
+  const gchar *name_sent, *name_recv;
+  const GValue *value_sent, *value_recv;
+  gboolean found;
+  gint comparison;
+  gint n_recv;
+  gint n_sent;
+  gint i, j;
+
+  fail_if (FALSE);
+
+  gst_tag_list_add_value (taglist, GST_TAG_MERGE_REPLACE, gsttag, value);
+
+  buf = gst_tag_list_to_xmp_buffer (taglist, TRUE);
+  taglist2 = gst_tag_list_from_xmp_buffer (buf);
+
+  /* verify tags */
+  fail_unless (taglist2 != NULL);
+  n_recv = gst_structure_n_fields (taglist2);
+  n_sent = gst_structure_n_fields (taglist);
+  fail_unless (n_recv == n_sent);
+
+  /* FIXME: compare taglist values */
+  for (i = 0; i < n_sent; i++) {
+    name_sent = gst_structure_nth_field_name (taglist, i);
+    value_sent = gst_structure_get_value (taglist, name_sent);
+    found = FALSE;
+    for (j = 0; j < n_recv; j++) {
+      name_recv = gst_structure_nth_field_name (taglist2, j);
+      if (!strcmp (name_sent, name_recv)) {
+        value_recv = gst_structure_get_value (taglist2, name_recv);
+        comparison = gst_value_compare (value_sent, value_recv);
+        if (comparison != GST_VALUE_EQUAL) {
+          gchar *vs = g_strdup_value_contents (value_sent);
+          gchar *vr = g_strdup_value_contents (value_recv);
+          GST_DEBUG ("sent = %s:'%s', recv = %s:'%s'",
+              G_VALUE_TYPE_NAME (value_sent), vs,
+              G_VALUE_TYPE_NAME (value_recv), vr);
+          g_free (vs);
+          g_free (vr);
+        }
+        fail_unless (comparison == GST_VALUE_EQUAL,
+            "tag item %s has been received with different type or value",
+            name_sent);
+        found = TRUE;
+        break;
+      }
+    }
+    fail_unless (found, "tag item %s is lost", name_sent);
+  }
+
+  gst_buffer_unref (buf);
+  gst_tag_list_free (taglist);
+  gst_tag_list_free (taglist2);
+}
+
+GST_START_TEST (test_xmp_tags_serialization_deserialization)
+{
+  GValue value = { 0 };
+  GDate *date;
+
+  g_value_init (&value, G_TYPE_STRING);
+  g_value_set_static_string (&value, "my string");
+  do_xmp_tag_serialization_deserialization (GST_TAG_ARTIST, &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_COPYRIGHT, &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_DESCRIPTION, &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_KEYWORDS, &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_TITLE, &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_VIDEO_CODEC, &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_COUNTRY,
+      &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_CITY, &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_SUBLOCATION,
+      &value);
+
+  g_value_unset (&value);
+  g_value_init (&value, G_TYPE_DOUBLE);
+
+  g_value_set_double (&value, 0.0);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_LATITUDE,
+      &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_LONGITUDE,
+      &value);
+  g_value_set_double (&value, 10.5);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_LATITUDE,
+      &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_LONGITUDE,
+      &value);
+  g_value_set_double (&value, -32.375);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_LATITUDE,
+      &value);
+  do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_LONGITUDE,
+      &value);
+  g_value_unset (&value);
+
+  g_value_init (&value, GST_TYPE_DATE);
+  date = g_date_new_dmy (22, 3, 2010);
+  gst_value_set_date (&value, date);
+  g_date_free (date);
+  do_xmp_tag_serialization_deserialization (GST_TAG_DATE, &value);
+  g_value_unset (&value);
+}
+
+GST_END_TEST;
+
 
 static Suite *
 tag_suite (void)
@@ -868,6 +978,7 @@ tag_suite (void)
   tcase_add_test (tc_chain, test_language_utils);
   tcase_add_test (tc_chain, test_xmp_formatting);
   tcase_add_test (tc_chain, test_xmp_parsing);
+  tcase_add_test (tc_chain, test_xmp_tags_serialization_deserialization);
   return s;
 }