diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c index edf553f228..c0bbecdc1f 100644 --- a/ext/dash/gstmpdparser.c +++ b/ext/dash/gstmpdparser.c @@ -831,7 +831,7 @@ error: The dateTime data type is used to specify a date and a time. - The dateTime is specified in the following form "YYYY-MM-DDThh:mm:ss" where: + The lexical form of xs:dateTime is YYYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] * YYYY indicates the year * MM indicates the month @@ -841,7 +841,7 @@ error: * mm indicates the minute * ss indicates the second - Note: All components are required! + The time zone may be specified as Z (UTC) or (+|-)hh:mm */ static gboolean gst_mpdparser_get_xml_prop_dateTime (xmlNode * a_node, @@ -853,6 +853,8 @@ gst_mpdparser_get_xml_prop_dateTime (xmlNode * a_node, gint year, month, day, hour, minute; gdouble second; gboolean exists = FALSE; + gfloat tzoffset = 0.0; + gint gmt_offset_hour = -99, gmt_offset_min = -99; prop_string = xmlGetProp (a_node, (const xmlChar *) property_name); if (prop_string) { @@ -902,9 +904,50 @@ gst_mpdparser_get_xml_prop_dateTime (xmlNode * a_node, GST_LOG (" - %s: %4d/%02d/%02d %02d:%02d:%09.6lf", property_name, year, month, day, hour, minute, second); + if (strrchr (str, '+') || strrchr (str, '-')){ + /* reuse some code from gst-plugins-base/gst-libs/gst/tag/gstxmptag.c */ + gint gmt_offset = -1; + 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 (str, '+'); + neg_pos = strrchr (str, '-'); + if (plus_pos) + pos = plus_pos + 1; + else if (neg_pos) + pos = neg_pos + 1; + + if (pos && strlen (pos) >= 3) { + gint ret_tz; + if (pos[2] == ':') + ret_tz = sscanf (pos, "%d:%d", &gmt_offset_hour, &gmt_offset_min); + else + ret_tz = sscanf (pos, "%02d%02d", &gmt_offset_hour, &gmt_offset_min); + + GST_DEBUG ("Parsing timezone: %s", pos); + + if (ret_tz == 2) { + if (neg_pos != NULL && neg_pos + 1 == pos) { + gmt_offset_hour *= -1; + gmt_offset_min *= -1; + } + gmt_offset = gmt_offset_hour * 60 + gmt_offset_min; + + tzoffset = gmt_offset / 60.0; + + GST_LOG ("Timezone offset: %f (%d minutes)", tzoffset, gmt_offset); + } else + GST_WARNING ("Failed to parse timezone information"); + } + } + exists = TRUE; *property_value = - gst_date_time_new (0, year, month, day, hour, minute, second); + gst_date_time_new (tzoffset, year, month, day, hour, minute, second); xmlFree (prop_string); } @@ -917,6 +960,7 @@ error: return FALSE; } + /* Duration Data Type diff --git a/tests/check/elements/dash_mpd.c b/tests/check/elements/dash_mpd.c index 8bea598c5d..06cc31f966 100644 --- a/tests/check/elements/dash_mpd.c +++ b/tests/check/elements/dash_mpd.c @@ -5770,6 +5770,68 @@ GST_START_TEST (dash_mpdparser_xlink_period) GST_END_TEST; + +/* + * Test parsing xsd:datetime with timezoneoffset. + * + */ +GST_START_TEST (dash_mpdparser_datetime_with_tz_offset) +{ + GstDateTime *availabilityStartTime; + GstDateTime *availabilityEndTime; + const gchar *xml = + "" + ""; + + gboolean ret; + GstMpdClient *mpdclient = gst_mpd_client_new (); + + ret = gst_mpd_parse (mpdclient, xml, (gint) strlen (xml)); + assert_equals_int (ret, TRUE); + + availabilityStartTime = mpdclient->mpd_node->availabilityStartTime; + assert_equals_int (gst_date_time_get_year (availabilityStartTime), 2015); + assert_equals_int (gst_date_time_get_month (availabilityStartTime), 3); + assert_equals_int (gst_date_time_get_day (availabilityStartTime), 24); + assert_equals_int (gst_date_time_get_hour (availabilityStartTime), 1); + assert_equals_int (gst_date_time_get_minute (availabilityStartTime), 10); + assert_equals_int (gst_date_time_get_second (availabilityStartTime), 50); + assert_equals_int (gst_date_time_get_microsecond (availabilityStartTime), 0); + assert_equals_float (gst_date_time_get_time_zone_offset (availabilityStartTime), 8.0); + + availabilityEndTime = mpdclient->mpd_node->availabilityEndTime; + assert_equals_int (gst_date_time_get_year (availabilityEndTime), 2015); + assert_equals_int (gst_date_time_get_month (availabilityEndTime), 3); + assert_equals_int (gst_date_time_get_day (availabilityEndTime), 24); + assert_equals_int (gst_date_time_get_hour (availabilityEndTime), 1); + assert_equals_int (gst_date_time_get_minute (availabilityEndTime), 10); + assert_equals_int (gst_date_time_get_second (availabilityEndTime), 50); + assert_equals_int (gst_date_time_get_microsecond (availabilityEndTime), + 123456); + assert_equals_float (gst_date_time_get_time_zone_offset (availabilityEndTime), -4.5); + + gst_mpd_client_free (mpdclient); +} + +GST_END_TEST; + + + /* * create a test suite containing all dash testcases */ @@ -5791,6 +5853,7 @@ dash_suite (void) /* tests parsing attributes from each element type */ tcase_add_test (tc_simpleMPD, dash_mpdparser_mpd); + tcase_add_test (tc_simpleMPD, dash_mpdparser_datetime_with_tz_offset); tcase_add_test (tc_simpleMPD, dash_mpdparser_programInformation); tcase_add_test (tc_simpleMPD, dash_mpdparser_baseURL); tcase_add_test (tc_simpleMPD, dash_mpdparser_location);