From 7ebbfbd3a5571c0e7518c5de9e710b9b9915f91e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 22 Mar 2010 15:18:28 -0300 Subject: [PATCH] tag: xmp: Adds mappings for LATITUDE and LONGITUDE Adds the mappings for those tags and tests for tags serialization. Fixes #613690 --- gst-libs/gst/tag/gstxmptag.c | 131 +++++++++++++++++++++++++++++++++++++++++++ tests/check/libs/tag.c | 111 ++++++++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+) diff --git a/gst-libs/gst/tag/gstxmptag.c b/gst-libs/gst/tag/gstxmptag.c index b1d9108..5ede287 100644 --- a/gst-libs/gst/tag/gstxmptag.c +++ b/gst-libs/gst/tag/gstxmptag.c @@ -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); diff --git a/tests/check/libs/tag.c b/tests/check/libs/tag.c index bfe738d..6194876 100644 --- a/tests/check/libs/tag.c +++ b/tests/check/libs/tag.c @@ -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; } -- 2.7.4