dashdemux: parse xs:dateTime's timezone indicator
authorJun Xie <jun.xie@samsung.com>
Thu, 14 Dec 2017 07:18:38 +0000 (15:18 +0800)
committerEdward Hervey <bilboed@bilboed.com>
Mon, 18 Dec 2017 13:07:36 +0000 (14:07 +0100)
The lexical form of xs:dateTime is YYYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
timezone indicator (+|-)hh:mm] needs to be parsed.

https://bugzilla.gnome.org/show_bug.cgi?id=791602

ext/dash/gstmpdparser.c
tests/check/elements/dash_mpd.c

index edf553f..c0bbecd 100644 (file)
@@ -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
 
index 8bea598..06cc31f 100644 (file)
@@ -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 =
+      "<?xml version=\"1.0\"?>"
+      "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
+      "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
+      "     schemaLocation=\"TestSchemaLocation\""
+      "     xmlns:xsi=\"TestNamespaceXSI\""
+      "     xmlns:ext=\"TestNamespaceEXT\""
+      "     id=\"testId\""
+      "     type=\"static\""
+      "     availabilityStartTime=\"2015-03-24T1:10:50+08:00\""
+      "     availabilityEndTime=\"2015-03-24T1:10:50.123456-04:30\""
+      "     mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
+      "     minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
+      "     minBufferTime=\"P0Y1M2DT12H10M20.5S\""
+      "     timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
+      "     suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
+      "     maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
+      "     maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\"></MPD>";
+
+  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);