From 5e51a77df4d775457f8f1145f2546c333c81b55c Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 23 Jun 2010 12:02:24 -0300 Subject: [PATCH] tag: xmp: Maps GST_TAG_DATE_TIME Adds mapping for GST_TAG_DATE_TIME. Tests included. https://bugzilla.gnome.org/show_bug.cgi?id=594504 --- gst-libs/gst/tag/gstxmptag.c | 128 ++++++++++++++++++++++++++++++++++- tests/check/libs/tag.c | 33 +++++++++ 2 files changed, 159 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/tag/gstxmptag.c b/gst-libs/gst/tag/gstxmptag.c index 51135766b4..e0d05575cf 100644 --- a/gst-libs/gst/tag/gstxmptag.c +++ b/gst-libs/gst/tag/gstxmptag.c @@ -41,6 +41,7 @@ #include #include #include +#include /* * Serializes a GValue into a string. @@ -720,7 +721,7 @@ _init_xmp_tag_map () _xmp_tag_add_simple_mapping (GST_TAG_ARTIST, "dc:creator", NULL, NULL); _xmp_tag_add_simple_mapping (GST_TAG_COPYRIGHT, "dc:rights", NULL, NULL); _xmp_tag_add_simple_mapping (GST_TAG_DATE, "dc:date", NULL, NULL); - _xmp_tag_add_simple_mapping (GST_TAG_DATE, "exif:DateTimeOriginal", NULL, + _xmp_tag_add_simple_mapping (GST_TAG_DATE_TIME, "exif:DateTimeOriginal", NULL, NULL); _xmp_tag_add_simple_mapping (GST_TAG_DESCRIPTION, "dc:description", NULL, NULL); @@ -875,7 +876,104 @@ read_one_tag (GstTagList * list, const gchar * tag, XmpTag * xmptag, break; } default: - if (tag_type == GST_TYPE_DATE) { + if (tag_type == GST_TYPE_DATE_TIME) { + GstDateTime *datetime; + gint year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; + gint usecs = 0; + gint gmt_offset_hour = -1, gmt_offset_min = -1, gmt_offset = -1; + gchar usec_str[16]; + gint ret; + gint len; + + len = strlen (v); + if (len == 0) { + GST_WARNING ("Empty string for datetime parsing"); + return; + } + + GST_DEBUG ("Parsing %s into a datetime", v); + + ret = sscanf (v, "%04d-%02d-%02dT%02d:%02d:%02d.%15s", + &year, &month, &day, &hour, &minute, &second, usec_str); + if (ret < 3) { + /* FIXME theoretically, xmp can express datetimes with only year + * or year and month, but gstdatetime doesn't support it */ + GST_WARNING ("Invalid datetime value: %s", v); + } + + /* parse the usecs */ + if (ret >= 7) { + gint num_digits = 0; + + /* find the number of digits */ + while (isdigit (usec_str[num_digits++]) && num_digits < 6); + + if (num_digits > 0) { + /* fill up to 6 digits with 0 */ + while (num_digits < 6) { + usec_str[num_digits++] = 0; + } + + g_assert (num_digits == 6); + + usec_str[num_digits] = '\0'; + usecs = atoi (usec_str); + } + } + + /* parse the timezone info */ + if (v[len - 1] == 'Z') { + GST_LOG ("UTC timezone"); + + /* Having a Z at the end means UTC */ + datetime = gst_date_time_new (year, month, day, hour, minute, + second, usecs, 0); + } else { + gchar *plus_pos = NULL; + gchar *neg_pos = NULL; + gchar *pos = NULL; + + GST_LOG ("Checking for timezone information"); + + /* check if there is timezone info */ + plus_pos = strrchr (v, '+'); + neg_pos = strrchr (v, '-'); + if (plus_pos) { + pos = plus_pos + 1; + } else if (neg_pos) { + pos = neg_pos + 1; + } + + if (pos) { + gint ret_tz = sscanf (pos, "%d:%d", &gmt_offset_hour, + &gmt_offset_min); + + GST_DEBUG ("Parsing timezone: %s", pos); + + if (ret_tz == 2) { + gmt_offset = gmt_offset_hour * 60 + gmt_offset_min; + if (neg_pos != NULL && neg_pos + 1 == pos) + gmt_offset *= -1; + + GST_LOG ("Timezone offset: %f (%d minutes)", gmt_offset / 60.0, + gmt_offset); + /* no way to know if it is DST or not */ + datetime = gst_date_time_new (year, month, day, hour, minute, + second, usecs, gmt_offset / 60.0f); + } else { + GST_WARNING ("Failed to parse timezone information"); + } + } else { + GST_WARNING ("No timezone signal found"); + } + } + + if (datetime) { + gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, tag, datetime, NULL); + gst_date_time_unref (datetime); + } + + } else if (tag_type == GST_TYPE_DATE) { GDate *date; gint d, m, y; @@ -1201,6 +1299,32 @@ gst_value_serialize_xmp (const GValue * value) return g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date), (gint) g_date_get_month (date), (gint) g_date_get_day (date)); + } else if (G_VALUE_TYPE (value) == GST_TYPE_DATE_TIME) { + gint year, month, day, hour, min, sec, microsec; + gint gmt_offset = 0; + gint gmt_offset_hour, gmt_offset_min; + GstDateTime *datetime = (GstDateTime *) g_value_get_boxed (value); + + year = gst_date_time_get_year (datetime); + month = gst_date_time_get_month (datetime); + day = gst_date_time_get_day (datetime); + hour = gst_date_time_get_hour (datetime); + min = gst_date_time_get_minute (datetime); + sec = gst_date_time_get_second (datetime); + microsec = gst_date_time_get_microsecond (datetime); + gmt_offset = (gint) (60 * gst_date_time_get_time_zone_offset (datetime)); + if (gmt_offset == 0) { + /* UTC */ + return g_strdup_printf ("%04d-%02d-%02dT%02d:%02d:%02d.%06dZ", + year, month, day, hour, min, sec, microsec); + } else { + gmt_offset_hour = ABS (gmt_offset) / 60; + gmt_offset_min = ABS (gmt_offset) % 60; + + return g_strdup_printf ("%04d-%02d-%02dT%02d:%02d:%02d.%06d%c%02d:%02d", + year, month, day, hour, min, sec, microsec, + gmt_offset >= 0 ? '+' : '-', gmt_offset_hour, gmt_offset_min); + } } else { return NULL; } diff --git a/tests/check/libs/tag.c b/tests/check/libs/tag.c index bd57a0aee6..1d1f895948 100644 --- a/tests/check/libs/tag.c +++ b/tests/check/libs/tag.c @@ -870,6 +870,7 @@ tag_list_equals (GstTagList * taglist, GstTagList * taglist2) n_recv = gst_structure_n_fields (taglist2); n_sent = gst_structure_n_fields (taglist); fail_unless (n_recv == n_sent); + fail_unless (n_sent > 0); /* FIXME: compare taglist values */ for (i = 0; i < n_sent; i++) { @@ -935,6 +936,7 @@ GST_START_TEST (test_xmp_tags_serialization_deserialization) { GValue value = { 0 }; GDate *date; + GstDateTime *datetime; g_value_init (&value, G_TYPE_STRING); g_value_set_static_string (&value, "my string"); @@ -1051,6 +1053,37 @@ GST_START_TEST (test_xmp_tags_serialization_deserialization) g_value_set_uint (&value, 22); do_xmp_tag_serialization_deserialization (GST_TAG_USER_RATING, &value); g_value_unset (&value); + + g_value_init (&value, GST_TYPE_DATE_TIME); + datetime = gst_date_time_new (2010, 6, 22, 12, 5, 10, 0, 0); + g_value_set_boxed (&value, datetime); + gst_date_time_unref (datetime); + do_xmp_tag_serialization_deserialization (GST_TAG_DATE_TIME, &value); + datetime = gst_date_time_new (2010, 6, 22, 12, 5, 10, 125, 0); + g_value_set_boxed (&value, datetime); + gst_date_time_unref (datetime); + do_xmp_tag_serialization_deserialization (GST_TAG_DATE_TIME, &value); + datetime = gst_date_time_new (2010, 6, 22, 12, 5, 10, 1, 0); + g_value_set_boxed (&value, datetime); + gst_date_time_unref (datetime); + do_xmp_tag_serialization_deserialization (GST_TAG_DATE_TIME, &value); + datetime = gst_date_time_new (2010, 6, 22, 12, 5, 10, 123456, 0); + g_value_set_boxed (&value, datetime); + gst_date_time_unref (datetime); + do_xmp_tag_serialization_deserialization (GST_TAG_DATE_TIME, &value); + datetime = gst_date_time_new (2010, 6, 22, 12, 5, 10, 123456, -3); + g_value_set_boxed (&value, datetime); + gst_date_time_unref (datetime); + do_xmp_tag_serialization_deserialization (GST_TAG_DATE_TIME, &value); + datetime = gst_date_time_new (2010, 6, 22, 12, 5, 10, 123456, 5); + g_value_set_boxed (&value, datetime); + gst_date_time_unref (datetime); + do_xmp_tag_serialization_deserialization (GST_TAG_DATE_TIME, &value); + datetime = gst_date_time_new_local_time (2010, 12, 2, 12, 5, 10, 43); + g_value_set_boxed (&value, datetime); + gst_date_time_unref (datetime); + do_xmp_tag_serialization_deserialization (GST_TAG_DATE_TIME, &value); + g_value_unset (&value); } GST_END_TEST;