• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer unit test for MPEG-DASH
2  *
3  * Copyright (c) <2015> YouView TV Ltd
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "../../ext/dash/gstmpdparser.c"
22 #include "../../ext/dash/gstxmlhelper.c"
23 #include "../../ext/dash/gstmpdhelper.c"
24 #include "../../ext/dash/gstmpdnode.c"
25 #include "../../ext/dash/gstmpdrepresentationbasenode.c"
26 #include "../../ext/dash/gstmpdmultsegmentbasenode.c"
27 #include "../../ext/dash/gstmpdrootnode.c"
28 #include "../../ext/dash/gstmpdbaseurlnode.c"
29 #include "../../ext/dash/gstmpdutctimingnode.c"
30 #include "../../ext/dash/gstmpdmetricsnode.c"
31 #include "../../ext/dash/gstmpdmetricsrangenode.c"
32 #include "../../ext/dash/gstmpdsnode.c"
33 #include "../../ext/dash/gstmpdsegmenttimelinenode.c"
34 #include "../../ext/dash/gstmpdsegmenttemplatenode.c"
35 #include "../../ext/dash/gstmpdsegmenturlnode.c"
36 #include "../../ext/dash/gstmpdsegmentlistnode.c"
37 #include "../../ext/dash/gstmpdsegmentbasenode.c"
38 #include "../../ext/dash/gstmpdperiodnode.c"
39 #include "../../ext/dash/gstmpdsubrepresentationnode.c"
40 #include "../../ext/dash/gstmpdrepresentationnode.c"
41 #include "../../ext/dash/gstmpdcontentcomponentnode.c"
42 #include "../../ext/dash/gstmpdadaptationsetnode.c"
43 #include "../../ext/dash/gstmpdsubsetnode.c"
44 #include "../../ext/dash/gstmpdprograminformationnode.c"
45 #include "../../ext/dash/gstmpdlocationnode.c"
46 #include "../../ext/dash/gstmpdreportingnode.c"
47 #include "../../ext/dash/gstmpdurltypenode.c"
48 #include "../../ext/dash/gstmpddescriptortypenode.c"
49 #include "../../ext/dash/gstmpdclient.c"
50 #undef GST_CAT_DEFAULT
51 
52 #include <gst/check/gstcheck.h>
53 
54 #include <libxml/parser.h>
55 #include <libxml/tree.h>
56 
57 GST_DEBUG_CATEGORY (gst_dash_demux_debug);
58 
59 /*
60  * compute the number of milliseconds contained in a duration value specified by
61  * year, month, day, hour, minute, second, millisecond
62  *
63  * This function must use the same conversion algorithm implemented in
64  * gst_xml_helper_get_prop_duration from gstmpdparser.c file.
65  */
66 static guint64
duration_to_ms(guint year,guint month,guint day,guint hour,guint minute,guint second,guint millisecond)67 duration_to_ms (guint year, guint month, guint day, guint hour, guint minute,
68     guint second, guint millisecond)
69 {
70   guint64 days = (guint64) year * 365 + (guint64) month * 30 + day;
71   guint64 hours = days * 24 + hour;
72   guint64 minutes = hours * 60 + minute;
73   guint64 seconds = minutes * 60 + second;
74   guint64 ms = seconds * 1000 + millisecond;
75   return ms;
76 }
77 
78 static GstClockTime
duration_to_clocktime(guint year,guint month,guint day,guint hour,guint minute,guint second,guint millisecond)79 duration_to_clocktime (guint year, guint month, guint day, guint hour,
80     guint minute, guint second, guint millisecond)
81 {
82   return (GST_MSECOND * duration_to_ms (year, month, day, hour, minute, second,
83           millisecond));
84 }
85 
86 /*
87  * Test to ensure a simple mpd file successfully parses.
88  *
89  */
GST_START_TEST(dash_mpdparser_validsimplempd)90 GST_START_TEST (dash_mpdparser_validsimplempd)
91 {
92   const gchar *xml =
93       "<?xml version=\"1.0\"?>"
94       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
95       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\"> </MPD>";
96 
97   gboolean ret;
98   GstMPDClient *mpdclient = gst_mpd_client_new ();
99 
100   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
101   assert_equals_int (ret, TRUE);
102 
103   /* check that unset elements with default values are properly configured */
104   assert_equals_int (mpdclient->mpd_root_node->type, GST_MPD_FILE_TYPE_STATIC);
105 
106   gst_mpd_client_free (mpdclient);
107 }
108 
109 GST_END_TEST;
110 
111 /*
112  * Test parsing the MPD attributes.
113  *
114  */
GST_START_TEST(dash_mpdparser_mpd)115 GST_START_TEST (dash_mpdparser_mpd)
116 {
117   GstDateTime *availabilityStartTime;
118   GstDateTime *availabilityEndTime;
119   const gchar *xml =
120       "<?xml version=\"1.0\"?>"
121       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
122       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
123       "     schemaLocation=\"TestSchemaLocation\""
124       "     xmlns:xsi=\"TestNamespaceXSI\""
125       "     xmlns:ext=\"TestNamespaceEXT\""
126       "     id=\"testId\""
127       "     type=\"static\""
128       "     availabilityStartTime=\"2015-03-24T1:10:50\""
129       "     availabilityEndTime=\"2015-03-24T1:10:50.123456\""
130       "     mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
131       "     minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
132       "     minBufferTime=\"P0Y1M2DT12H10M20.5S\""
133       "     timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
134       "     suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
135       "     maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
136       "     maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\"></MPD>";
137 
138   gboolean ret;
139   GstMPDClient *mpdclient = gst_mpd_client_new ();
140 
141   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
142   assert_equals_int (ret, TRUE);
143 
144   assert_equals_string (mpdclient->mpd_root_node->default_namespace,
145       "urn:mpeg:dash:schema:mpd:2011");
146   assert_equals_string (mpdclient->mpd_root_node->namespace_xsi,
147       "TestNamespaceXSI");
148   assert_equals_string (mpdclient->mpd_root_node->namespace_ext,
149       "TestNamespaceEXT");
150   assert_equals_string (mpdclient->mpd_root_node->schemaLocation,
151       "TestSchemaLocation");
152   assert_equals_string (mpdclient->mpd_root_node->id, "testId");
153 
154   assert_equals_int (mpdclient->mpd_root_node->type, GST_MPD_FILE_TYPE_STATIC);
155 
156   availabilityStartTime = mpdclient->mpd_root_node->availabilityStartTime;
157   assert_equals_int (gst_date_time_get_year (availabilityStartTime), 2015);
158   assert_equals_int (gst_date_time_get_month (availabilityStartTime), 3);
159   assert_equals_int (gst_date_time_get_day (availabilityStartTime), 24);
160   assert_equals_int (gst_date_time_get_hour (availabilityStartTime), 1);
161   assert_equals_int (gst_date_time_get_minute (availabilityStartTime), 10);
162   assert_equals_int (gst_date_time_get_second (availabilityStartTime), 50);
163   assert_equals_int (gst_date_time_get_microsecond (availabilityStartTime), 0);
164 
165   availabilityEndTime = mpdclient->mpd_root_node->availabilityEndTime;
166   assert_equals_int (gst_date_time_get_year (availabilityEndTime), 2015);
167   assert_equals_int (gst_date_time_get_month (availabilityEndTime), 3);
168   assert_equals_int (gst_date_time_get_day (availabilityEndTime), 24);
169   assert_equals_int (gst_date_time_get_hour (availabilityEndTime), 1);
170   assert_equals_int (gst_date_time_get_minute (availabilityEndTime), 10);
171   assert_equals_int (gst_date_time_get_second (availabilityEndTime), 50);
172   assert_equals_int (gst_date_time_get_microsecond (availabilityEndTime),
173       123456);
174 
175   assert_equals_uint64 (mpdclient->mpd_root_node->mediaPresentationDuration,
176       duration_to_ms (0, 1, 2, 12, 10, 20, 500));
177 
178   assert_equals_uint64 (mpdclient->mpd_root_node->minimumUpdatePeriod,
179       duration_to_ms (0, 1, 2, 12, 10, 20, 500));
180 
181   assert_equals_uint64 (mpdclient->mpd_root_node->minBufferTime,
182       duration_to_ms (0, 1, 2, 12, 10, 20, 500));
183 
184   assert_equals_uint64 (mpdclient->mpd_root_node->timeShiftBufferDepth,
185       duration_to_ms (0, 1, 2, 12, 10, 20, 500));
186 
187   assert_equals_uint64 (mpdclient->mpd_root_node->suggestedPresentationDelay,
188       duration_to_ms (0, 1, 2, 12, 10, 20, 500));
189 
190   assert_equals_uint64 (mpdclient->mpd_root_node->maxSegmentDuration,
191       duration_to_ms (0, 1, 2, 12, 10, 20, 500));
192 
193   assert_equals_uint64 (mpdclient->mpd_root_node->maxSubsegmentDuration,
194       duration_to_ms (0, 1, 2, 12, 10, 20, 500));
195 
196   gst_mpd_client_free (mpdclient);
197 }
198 
199 GST_END_TEST;
200 
201 /*
202  * Test parsing the ProgramInformation attributes
203  *
204  */
GST_START_TEST(dash_mpdparser_programInformation)205 GST_START_TEST (dash_mpdparser_programInformation)
206 {
207   GstMPDProgramInformationNode *program;
208   const gchar *xml =
209       "<?xml version=\"1.0\"?>"
210       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
211       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
212       "  <ProgramInformation lang=\"en\""
213       "                      moreInformationURL=\"TestMoreInformationUrl\">"
214       "    <Title>TestTitle</Title>"
215       "    <Source>TestSource</Source>"
216       "    <Copyright>TestCopyright</Copyright>"
217       "  </ProgramInformation> </MPD>";
218 
219   gboolean ret;
220   GstMPDClient *mpdclient = gst_mpd_client_new ();
221 
222   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
223   assert_equals_int (ret, TRUE);
224 
225   program =
226       (GstMPDProgramInformationNode *) mpdclient->mpd_root_node->ProgramInfos->
227       data;
228   assert_equals_string (program->lang, "en");
229   assert_equals_string (program->moreInformationURL, "TestMoreInformationUrl");
230   assert_equals_string (program->Title, "TestTitle");
231   assert_equals_string (program->Source, "TestSource");
232   assert_equals_string (program->Copyright, "TestCopyright");
233 
234   gst_mpd_client_free (mpdclient);
235 }
236 
237 GST_END_TEST;
238 
239 /*
240  * Test parsing the BaseURL attributes
241  *
242  */
GST_START_TEST(dash_mpdparser_baseURL)243 GST_START_TEST (dash_mpdparser_baseURL)
244 {
245   GstMPDBaseURLNode *baseURL;
246   const gchar *xml =
247       "<?xml version=\"1.0\"?>"
248       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
249       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
250       "  <BaseURL serviceLocation=\"TestServiceLocation\""
251       "     byteRange=\"TestByteRange\">TestBaseURL</BaseURL></MPD>";
252 
253   gboolean ret;
254   GstMPDClient *mpdclient = gst_mpd_client_new ();
255 
256   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
257   assert_equals_int (ret, TRUE);
258 
259   baseURL = (GstMPDBaseURLNode *) mpdclient->mpd_root_node->BaseURLs->data;
260   assert_equals_string (baseURL->baseURL, "TestBaseURL");
261   assert_equals_string (baseURL->serviceLocation, "TestServiceLocation");
262   assert_equals_string (baseURL->byteRange, "TestByteRange");
263 
264   gst_mpd_client_free (mpdclient);
265 }
266 
267 GST_END_TEST;
268 
269 /*
270  * Test parsing the Location attributes
271  *
272  */
GST_START_TEST(dash_mpdparser_location)273 GST_START_TEST (dash_mpdparser_location)
274 {
275   GstMPDLocationNode *location;
276   const gchar *xml =
277       "<?xml version=\"1.0\"?>"
278       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
279       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
280       "  <Location>TestLocation</Location></MPD>";
281 
282   gboolean ret;
283   GstMPDClient *mpdclient = gst_mpd_client_new ();
284 
285   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
286   assert_equals_int (ret, TRUE);
287 
288   location = (GstMPDLocationNode *) mpdclient->mpd_root_node->Locations->data;
289   assert_equals_string (location->location, "TestLocation");
290 
291   gst_mpd_client_free (mpdclient);
292 }
293 
294 GST_END_TEST;
295 
296 /*
297  * Test parsing Metrics attributes
298  *
299  */
GST_START_TEST(dash_mpdparser_metrics)300 GST_START_TEST (dash_mpdparser_metrics)
301 {
302   GstMPDMetricsNode *metricsNode;
303   const gchar *xml =
304       "<?xml version=\"1.0\"?>"
305       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
306       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
307       "  <Metrics metrics=\"TestMetric\"></Metrics></MPD>";
308 
309   gboolean ret;
310   GstMPDClient *mpdclient = gst_mpd_client_new ();
311 
312   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
313   assert_equals_int (ret, TRUE);
314 
315   metricsNode = (GstMPDMetricsNode *) mpdclient->mpd_root_node->Metrics->data;
316   assert_equals_string (metricsNode->metrics, "TestMetric");
317 
318   gst_mpd_client_free (mpdclient);
319 }
320 
321 GST_END_TEST;
322 
323 /*
324  * Test parsing Metrics Range attributes
325  *
326  */
GST_START_TEST(dash_mpdparser_metrics_range)327 GST_START_TEST (dash_mpdparser_metrics_range)
328 {
329   GstMPDMetricsNode *metricsNode;
330   GstMPDMetricsRangeNode *metricsRangeNode;
331   const gchar *xml =
332       "<?xml version=\"1.0\"?>"
333       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
334       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
335       "  <Metrics>"
336       "    <Range starttime=\"P0Y1M2DT12H10M20.5S\""
337       "           duration=\"P0Y1M2DT12H10M20.1234567S\">"
338       "    </Range></Metrics></MPD>";
339 
340   gboolean ret;
341   GstMPDClient *mpdclient = gst_mpd_client_new ();
342 
343   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
344   assert_equals_int (ret, TRUE);
345 
346   metricsNode = (GstMPDMetricsNode *) mpdclient->mpd_root_node->Metrics->data;
347   assert_equals_pointer (metricsNode->metrics, NULL);
348   metricsRangeNode =
349       (GstMPDMetricsRangeNode *) metricsNode->MetricsRanges->data;
350   assert_equals_uint64 (metricsRangeNode->starttime, duration_to_ms (0, 1, 2,
351           12, 10, 20, 500));
352   assert_equals_uint64 (metricsRangeNode->duration, duration_to_ms (0, 1, 2, 12,
353           10, 20, 123));
354 
355   gst_mpd_client_free (mpdclient);
356 }
357 
358 GST_END_TEST;
359 
360 /*
361  * Test parsing Metrics Reporting attributes
362  *
363  */
GST_START_TEST(dash_mpdparser_metrics_reporting)364 GST_START_TEST (dash_mpdparser_metrics_reporting)
365 {
366   GstMPDMetricsNode *metricsNode;
367   const gchar *xml =
368       "<?xml version=\"1.0\"?>"
369       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
370       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
371       "  <Metrics><Reporting></Reporting></Metrics></MPD>";
372 
373   gboolean ret;
374   GstMPDClient *mpdclient = gst_mpd_client_new ();
375 
376   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
377   assert_equals_int (ret, TRUE);
378 
379   metricsNode = (GstMPDMetricsNode *) mpdclient->mpd_root_node->Metrics->data;
380   assert_equals_pointer (metricsNode->metrics, NULL);
381 
382   gst_mpd_client_free (mpdclient);
383 }
384 
385 GST_END_TEST;
386 
387 /*
388  * Test parsing Period attributes
389  *
390  */
GST_START_TEST(dash_mpdparser_period)391 GST_START_TEST (dash_mpdparser_period)
392 {
393   GstMPDPeriodNode *periodNode;
394   const gchar *xml =
395       "<?xml version=\"1.0\"?>"
396       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
397       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
398       "  <Period id=\"TestId\""
399       "          start=\"P0Y1M2DT12H10M20.1234567S\""
400       "          duration=\"P0Y1M2DT12H10M20.7654321S\""
401       "          bitstreamSwitching=\"true\"></Period></MPD>";
402 
403   gboolean ret;
404   GstMPDClient *mpdclient = gst_mpd_client_new ();
405 
406   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
407   assert_equals_int (ret, TRUE);
408 
409   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
410   assert_equals_string (periodNode->id, "TestId");
411   assert_equals_uint64 (periodNode->start,
412       duration_to_ms (0, 1, 2, 12, 10, 20, 123));
413   assert_equals_uint64 (periodNode->duration,
414       duration_to_ms (0, 1, 2, 12, 10, 20, 765));
415   assert_equals_int (periodNode->bitstreamSwitching, 1);
416 
417   gst_mpd_client_free (mpdclient);
418 }
419 
420 GST_END_TEST;
421 
422 /*
423  * Test parsing Period baseURL attributes
424  *
425  */
GST_START_TEST(dash_mpdparser_period_baseURL)426 GST_START_TEST (dash_mpdparser_period_baseURL)
427 {
428   GstMPDPeriodNode *periodNode;
429   GstMPDBaseURLNode *baseURL;
430   const gchar *xml =
431       "<?xml version=\"1.0\"?>"
432       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
433       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
434       "  <Period>"
435       "    <BaseURL serviceLocation=\"TestServiceLocation\""
436       "             byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
437       "  </Period></MPD>";
438 
439   gboolean ret;
440   GstMPDClient *mpdclient = gst_mpd_client_new ();
441 
442   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
443   assert_equals_int (ret, TRUE);
444 
445   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
446   baseURL = (GstMPDBaseURLNode *) periodNode->BaseURLs->data;
447   assert_equals_string (baseURL->baseURL, "TestBaseURL");
448   assert_equals_string (baseURL->serviceLocation, "TestServiceLocation");
449   assert_equals_string (baseURL->byteRange, "TestByteRange");
450 
451   gst_mpd_client_free (mpdclient);
452 }
453 
454 GST_END_TEST;
455 
456 /*
457  * Test parsing Period SegmentBase attributes
458  *
459  */
GST_START_TEST(dash_mpdparser_period_segmentBase)460 GST_START_TEST (dash_mpdparser_period_segmentBase)
461 {
462   GstMPDPeriodNode *periodNode;
463   GstMPDSegmentBaseNode *segmentBase;
464   const gchar *xml =
465       "<?xml version=\"1.0\"?>"
466       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
467       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
468       "  <Period>"
469       "    <SegmentBase timescale=\"123456\""
470       "                 presentationTimeOffset=\"123456789\""
471       "                 indexRange=\"100-200\""
472       "                 indexRangeExact=\"true\">"
473       "    </SegmentBase></Period></MPD>";
474 
475   gboolean ret;
476   GstMPDClient *mpdclient = gst_mpd_client_new ();
477 
478   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
479   assert_equals_int (ret, TRUE);
480 
481   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
482   segmentBase = periodNode->SegmentBase;
483   assert_equals_uint64 (segmentBase->timescale, 123456);
484   assert_equals_uint64 (segmentBase->presentationTimeOffset, 123456789);
485   assert_equals_uint64 (segmentBase->indexRange->first_byte_pos, 100);
486   assert_equals_uint64 (segmentBase->indexRange->last_byte_pos, 200);
487   assert_equals_int (segmentBase->indexRangeExact, 1);
488 
489   gst_mpd_client_free (mpdclient);
490 }
491 
492 GST_END_TEST;
493 
494 /*
495  * Test parsing Period SegmentBase Initialization attributes
496  *
497  */
GST_START_TEST(dash_mpdparser_period_segmentBase_initialization)498 GST_START_TEST (dash_mpdparser_period_segmentBase_initialization)
499 {
500   GstMPDPeriodNode *periodNode;
501   GstMPDSegmentBaseNode *segmentBase;
502   GstMPDURLTypeNode *initialization;
503   const gchar *xml =
504       "<?xml version=\"1.0\"?>"
505       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
506       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
507       "  <Period>"
508       "    <SegmentBase>"
509       "      <Initialisation sourceURL=\"TestSourceURL\""
510       "                      range=\"100-200\">"
511       "      </Initialisation></SegmentBase></Period></MPD>";
512 
513   gboolean ret;
514   GstMPDClient *mpdclient = gst_mpd_client_new ();
515 
516   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
517   assert_equals_int (ret, TRUE);
518 
519   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
520   segmentBase = periodNode->SegmentBase;
521   initialization = segmentBase->Initialization;
522   assert_equals_string (initialization->sourceURL, "TestSourceURL");
523   assert_equals_uint64 (initialization->range->first_byte_pos, 100);
524   assert_equals_uint64 (initialization->range->last_byte_pos, 200);
525 
526   gst_mpd_client_free (mpdclient);
527 }
528 
529 GST_END_TEST;
530 
531 /*
532  * Test parsing Period SegmentBase RepresentationIndex attributes
533  *
534  */
GST_START_TEST(dash_mpdparser_period_segmentBase_representationIndex)535 GST_START_TEST (dash_mpdparser_period_segmentBase_representationIndex)
536 {
537   GstMPDPeriodNode *periodNode;
538   GstMPDSegmentBaseNode *segmentBase;
539   GstMPDURLTypeNode *representationIndex;
540   const gchar *xml =
541       "<?xml version=\"1.0\"?>"
542       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
543       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
544       "  <Period>"
545       "    <SegmentBase>"
546       "      <RepresentationIndex sourceURL=\"TestSourceURL\""
547       "                           range=\"100-200\">"
548       "      </RepresentationIndex></SegmentBase></Period></MPD>";
549 
550   gboolean ret;
551   GstMPDClient *mpdclient = gst_mpd_client_new ();
552 
553   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
554   assert_equals_int (ret, TRUE);
555 
556   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
557   segmentBase = periodNode->SegmentBase;
558   representationIndex = segmentBase->RepresentationIndex;
559   assert_equals_string (representationIndex->sourceURL, "TestSourceURL");
560   assert_equals_uint64 (representationIndex->range->first_byte_pos, 100);
561   assert_equals_uint64 (representationIndex->range->last_byte_pos, 200);
562 
563   gst_mpd_client_free (mpdclient);
564 }
565 
566 GST_END_TEST;
567 
568 /*
569  * Test parsing Period SegmentList attributes
570  *
571  */
GST_START_TEST(dash_mpdparser_period_segmentList)572 GST_START_TEST (dash_mpdparser_period_segmentList)
573 {
574   GstMPDPeriodNode *periodNode;
575   GstMPDSegmentListNode *segmentList;
576   const gchar *xml =
577       "<?xml version=\"1.0\"?>"
578       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
579       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
580       "  <Period><SegmentList duration=\"1\"></SegmentList></Period></MPD>";
581 
582   gboolean ret;
583   GstMPDClient *mpdclient = gst_mpd_client_new ();
584 
585   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
586   assert_equals_int (ret, TRUE);
587 
588   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
589   segmentList = periodNode->SegmentList;
590   fail_if (segmentList == NULL);
591 
592   gst_mpd_client_free (mpdclient);
593 }
594 
595 GST_END_TEST;
596 
597 /*
598  * Test parsing Period SegmentList MultipleSegmentBaseType attributes
599  *
600  */
GST_START_TEST(dash_mpdparser_period_segmentList_multipleSegmentBaseType)601 GST_START_TEST (dash_mpdparser_period_segmentList_multipleSegmentBaseType)
602 {
603   GstMPDPeriodNode *periodNode;
604   GstMPDSegmentListNode *segmentList;
605 
606   const gchar *xml =
607       "<?xml version=\"1.0\"?>"
608       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
609       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
610       "  <Period>"
611       "    <SegmentList duration=\"10\""
612       "                 startNumber=\"11\">"
613       "    </SegmentList></Period></MPD>";
614 
615   gboolean ret;
616   GstMPDClient *mpdclient = gst_mpd_client_new ();
617 
618   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
619   assert_equals_int (ret, TRUE);
620 
621   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
622   segmentList = periodNode->SegmentList;
623 
624   assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->duration,
625       10);
626   assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
627       (segmentList)->startNumber, 11);
628 
629   gst_mpd_client_free (mpdclient);
630 }
631 
632 GST_END_TEST;
633 
634 /*
635  * Test parsing Period SegmentList MultipleSegmentBaseType SegmentBaseType
636  * attributes
637  */
GST_START_TEST(dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentBaseType)638 GST_START_TEST
639     (dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentBaseType)
640 {
641   GstMPDPeriodNode *periodNode;
642   GstMPDSegmentListNode *segmentList;
643   GstMPDSegmentBaseNode *segmentBase;
644   const gchar *xml =
645       "<?xml version=\"1.0\"?>"
646       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
647       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
648       "  <Period>"
649       "    <SegmentList timescale=\"10\""
650       "                 duration=\"1\""
651       "                 presentationTimeOffset=\"11\""
652       "                 indexRange=\"20-21\""
653       "                 indexRangeExact=\"false\">"
654       "    </SegmentList></Period></MPD>";
655 
656   gboolean ret;
657   GstMPDClient *mpdclient = gst_mpd_client_new ();
658 
659   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
660   assert_equals_int (ret, TRUE);
661 
662   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
663   segmentList = periodNode->SegmentList;
664   segmentBase = GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->SegmentBase;
665   assert_equals_uint64 (segmentBase->timescale, 10);
666   assert_equals_uint64 (segmentBase->presentationTimeOffset, 11);
667   assert_equals_uint64 (segmentBase->indexRange->first_byte_pos, 20);
668   assert_equals_uint64 (segmentBase->indexRange->last_byte_pos, 21);
669   assert_equals_int (segmentBase->indexRangeExact, FALSE);
670 
671   gst_mpd_client_free (mpdclient);
672 }
673 
674 GST_END_TEST;
675 
676 /*
677  * Test parsing Period SegmentList MultipleSegmentBaseType SegmentTimeline
678  * attributes
679  */
GST_START_TEST(dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline)680 GST_START_TEST
681     (dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline)
682 {
683   GstMPDPeriodNode *periodNode;
684   GstMPDSegmentListNode *segmentList;
685   GstMPDSegmentTimelineNode *segmentTimeline;
686   const gchar *xml =
687       "<?xml version=\"1.0\"?>"
688       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
689       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
690       "  <Period>"
691       "    <SegmentList>"
692       "      <SegmentTimeline>"
693       "      </SegmentTimeline></SegmentList></Period></MPD>";
694 
695   gboolean ret;
696   GstMPDClient *mpdclient = gst_mpd_client_new ();
697 
698   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
699   assert_equals_int (ret, TRUE);
700 
701   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
702   segmentList = periodNode->SegmentList;
703   segmentTimeline =
704       GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->SegmentTimeline;
705   fail_if (segmentTimeline == NULL);
706 
707   gst_mpd_client_free (mpdclient);
708 }
709 
710 GST_END_TEST;
711 
712 /*
713  * Test parsing Period SegmentList MultipleSegmentBaseType SegmentTimeline S
714  * attributes
715  */
GST_START_TEST(dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline_s)716 GST_START_TEST
717     (dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline_s)
718 {
719   GstMPDPeriodNode *periodNode;
720   GstMPDSegmentListNode *segmentList;
721   GstMPDSegmentTimelineNode *segmentTimeline;
722   GstMPDSNode *sNode;
723   const gchar *xml =
724       "<?xml version=\"1.0\"?>"
725       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
726       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
727       "  <Period>"
728       "    <SegmentList>"
729       "      <SegmentTimeline>"
730       "        <S t=\"1\" d=\"2\" r=\"3\">"
731       "        </S></SegmentTimeline></SegmentList></Period></MPD>";
732 
733   gboolean ret;
734   GstMPDClient *mpdclient = gst_mpd_client_new ();
735 
736   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
737   assert_equals_int (ret, TRUE);
738 
739   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
740   segmentList = periodNode->SegmentList;
741   segmentTimeline =
742       GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->SegmentTimeline;
743   sNode = (GstMPDSNode *) g_queue_peek_head (&segmentTimeline->S);
744   assert_equals_uint64 (sNode->t, 1);
745   assert_equals_uint64 (sNode->d, 2);
746   assert_equals_uint64 (sNode->r, 3);
747 
748   gst_mpd_client_free (mpdclient);
749 }
750 
751 GST_END_TEST;
752 
753 /*
754  * Test parsing Period SegmentList MultipleSegmentBaseType BitstreamSwitching
755  * attributes
756  */
GST_START_TEST(dash_mpdparser_period_segmentList_multipleSegmentBaseType_bitstreamSwitching)757 GST_START_TEST
758     (dash_mpdparser_period_segmentList_multipleSegmentBaseType_bitstreamSwitching)
759 {
760   GstMPDPeriodNode *periodNode;
761   GstMPDSegmentListNode *segmentList;
762   GstMPDURLTypeNode *bitstreamSwitching;
763   const gchar *xml =
764       "<?xml version=\"1.0\"?>"
765       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
766       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
767       "  <Period>"
768       "    <SegmentList duration=\"0\">"
769       "      <BitstreamSwitching sourceURL=\"TestSourceURL\""
770       "                          range=\"100-200\">"
771       "      </BitstreamSwitching></SegmentList></Period></MPD>";
772 
773   gboolean ret;
774   GstMPDClient *mpdclient = gst_mpd_client_new ();
775 
776   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
777   assert_equals_int (ret, TRUE);
778 
779   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
780   segmentList = periodNode->SegmentList;
781 
782   bitstreamSwitching =
783       GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->BitstreamSwitching;
784   assert_equals_string (bitstreamSwitching->sourceURL, "TestSourceURL");
785   assert_equals_uint64 (bitstreamSwitching->range->first_byte_pos, 100);
786   assert_equals_uint64 (bitstreamSwitching->range->last_byte_pos, 200);
787 
788   gst_mpd_client_free (mpdclient);
789 }
790 
791 GST_END_TEST;
792 
793 /*
794  * Test parsing Period SegmentList SegmentURL attributes
795  *
796  */
GST_START_TEST(dash_mpdparser_period_segmentList_segmentURL)797 GST_START_TEST (dash_mpdparser_period_segmentList_segmentURL)
798 {
799   GstMPDPeriodNode *periodNode;
800   GstMPDSegmentListNode *segmentList;
801   GstMPDSegmentURLNode *segmentURL;
802   const gchar *xml =
803       "<?xml version=\"1.0\"?>"
804       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
805       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
806       "  <Period>"
807       "    <SegmentList duration=\"1\">"
808       "      <SegmentURL media=\"TestMedia\""
809       "                  mediaRange=\"100-200\""
810       "                  index=\"TestIndex\""
811       "                  indexRange=\"300-400\">"
812       "      </SegmentURL></SegmentList></Period></MPD>";
813 
814   gboolean ret;
815   GstMPDClient *mpdclient = gst_mpd_client_new ();
816 
817   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
818   assert_equals_int (ret, TRUE);
819 
820   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
821   segmentList = periodNode->SegmentList;
822   segmentURL = (GstMPDSegmentURLNode *) segmentList->SegmentURL->data;
823   assert_equals_string (segmentURL->media, "TestMedia");
824   assert_equals_uint64 (segmentURL->mediaRange->first_byte_pos, 100);
825   assert_equals_uint64 (segmentURL->mediaRange->last_byte_pos, 200);
826   assert_equals_string (segmentURL->index, "TestIndex");
827   assert_equals_uint64 (segmentURL->indexRange->first_byte_pos, 300);
828   assert_equals_uint64 (segmentURL->indexRange->last_byte_pos, 400);
829 
830   gst_mpd_client_free (mpdclient);
831 }
832 
833 GST_END_TEST;
834 
835 /*
836  * Test parsing Period SegmentTemplate attributes
837  *
838  */
GST_START_TEST(dash_mpdparser_period_segmentTemplate)839 GST_START_TEST (dash_mpdparser_period_segmentTemplate)
840 {
841   GstMPDPeriodNode *periodNode;
842   GstMPDSegmentTemplateNode *segmentTemplate;
843   const gchar *xml =
844       "<?xml version=\"1.0\"?>"
845       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
846       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
847       "  <Period>"
848       "    <SegmentTemplate media=\"TestMedia\""
849       "                     duration=\"0\""
850       "                     index=\"TestIndex\""
851       "                     initialization=\"TestInitialization\""
852       "                     bitstreamSwitching=\"TestBitstreamSwitching\">"
853       "    </SegmentTemplate></Period></MPD>";
854 
855   gboolean ret;
856   GstMPDClient *mpdclient = gst_mpd_client_new ();
857 
858   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
859   assert_equals_int (ret, TRUE);
860 
861   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
862   segmentTemplate = periodNode->SegmentTemplate;
863   assert_equals_string (segmentTemplate->media, "TestMedia");
864   assert_equals_string (segmentTemplate->index, "TestIndex");
865   assert_equals_string (segmentTemplate->initialization, "TestInitialization");
866   assert_equals_string (segmentTemplate->bitstreamSwitching,
867       "TestBitstreamSwitching");
868 
869   gst_mpd_client_free (mpdclient);
870 }
871 
872 GST_END_TEST;
873 
874 /*
875  * Test parsing Period SegmentTemplate attributes where a
876  * presentationTimeOffset attribute has been specified
877  *
878  */
GST_START_TEST(dash_mpdparser_period_segmentTemplateWithPresentationTimeOffset)879 GST_START_TEST (dash_mpdparser_period_segmentTemplateWithPresentationTimeOffset)
880 {
881   const gchar *xml =
882       "<?xml version=\"1.0\"?>"
883       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
884       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
885       "  <Period start=\"PT1M\" duration=\"PT40S\">"
886       "    <AdaptationSet"
887       "      bitstreamSwitching=\"false\""
888       "      mimeType=\"video/mp4\""
889       "      contentType=\"video\">"
890       "      <SegmentTemplate media=\"$RepresentationID$/TestMedia-$Time$.mp4\""
891       "                     index=\"$RepresentationID$/TestIndex.mp4\""
892       "                     timescale=\"100\""
893       "                     presentationTimeOffset=\"6000\""
894       "                     initialization=\"$RepresentationID$/TestInitialization\""
895       "                     bitstreamSwitching=\"true\">"
896       "        <SegmentTimeline>"
897       "          <S d=\"400\" r=\"9\" t=\"100\"/>"
898       "        </SegmentTimeline></SegmentTemplate>"
899       "      <Representation bandwidth=\"95866\" frameRate=\"90000/3600\""
900       "        id=\"vrep\" /></AdaptationSet></Period></MPD>";
901 
902   gboolean ret;
903   GList *adaptationSets;
904   GstMPDAdaptationSetNode *adapt_set;
905   GstActiveStream *activeStream;
906   GstMediaFragmentInfo fragment;
907   GstClockTime expectedDuration;
908   GstClockTime expectedTimestamp;
909   GstMPDClient *mpdclient;
910   GstMPDPeriodNode *periodNode;
911   GstMPDSegmentTemplateNode *segmentTemplate;
912 
913   mpdclient = gst_mpd_client_new ();
914   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
915   assert_equals_int (ret, TRUE);
916 
917   ret =
918       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
919       -1, NULL);
920   assert_equals_int (ret, TRUE);
921 
922   periodNode =
923       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
924       0);
925   fail_if (periodNode == NULL);
926 
927   /* get the list of adaptation sets of the first period */
928   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
929   fail_if (adaptationSets == NULL);
930 
931   /* setup streaming from the first adaptation set */
932   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
933   fail_if (adapt_set == NULL);
934   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
935   assert_equals_int (ret, TRUE);
936   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
937   fail_if (activeStream == NULL);
938 
939   segmentTemplate = adapt_set->SegmentTemplate;
940   fail_if (segmentTemplate == NULL);
941   assert_equals_string (segmentTemplate->media,
942       "$RepresentationID$/TestMedia-$Time$.mp4");
943   assert_equals_string (segmentTemplate->index,
944       "$RepresentationID$/TestIndex.mp4");
945   assert_equals_string (segmentTemplate->initialization,
946       "$RepresentationID$/TestInitialization");
947   assert_equals_string (segmentTemplate->bitstreamSwitching, "true");
948 
949   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
950   assert_equals_int (ret, TRUE);
951   expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 4, 0);
952   /* start = Period@start + S@t - presentationTimeOffset */
953   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 1, 0);
954   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
955   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
956   /* the $Time$ expansion uses the @t value, without including
957      Period@start or presentationTimeOffset */
958   assert_equals_string (fragment.uri, "/vrep/TestMedia-100.mp4");
959   gst_mpdparser_media_fragment_info_clear (&fragment);
960 
961   gst_mpd_client_free (mpdclient);
962 }
963 
964 GST_END_TEST;
965 
966 /*
967  * Test parsing Period SegmentTemplate MultipleSegmentBaseType attributes
968  *
969  */
GST_START_TEST(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType)970 GST_START_TEST (dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType)
971 {
972   GstMPDPeriodNode *periodNode;
973   GstMPDSegmentTemplateNode *segmentTemplate;
974   const gchar *xml =
975       "<?xml version=\"1.0\"?>"
976       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
977       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
978       "  <Period>"
979       "    <SegmentTemplate duration=\"10\""
980       "                     startNumber=\"11\">"
981       "    </SegmentTemplate></Period></MPD>";
982 
983   gboolean ret;
984   GstMPDClient *mpdclient = gst_mpd_client_new ();
985 
986   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
987   assert_equals_int (ret, TRUE);
988 
989   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
990   segmentTemplate = periodNode->SegmentTemplate;
991 
992   assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
993       (segmentTemplate)->duration, 10);
994   assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
995       (segmentTemplate)->startNumber, 11);
996 
997   gst_mpd_client_free (mpdclient);
998 }
999 
1000 GST_END_TEST;
1001 
1002 /*
1003  * Test parsing Period SegmentTemplate MultipleSegmentBaseType SegmentBaseType
1004  * attributes
1005  */
GST_START_TEST(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentBaseType)1006 GST_START_TEST
1007     (dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentBaseType)
1008 {
1009   GstMPDPeriodNode *periodNode;
1010   GstMPDSegmentTemplateNode *segmentTemplate;
1011   GstMPDSegmentBaseNode *segmentBase;
1012   const gchar *xml =
1013       "<?xml version=\"1.0\"?>"
1014       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1015       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1016       "  <Period>"
1017       "    <SegmentTemplate timescale=\"123456\""
1018       "                     duration=\"1\""
1019       "                     presentationTimeOffset=\"123456789\""
1020       "                     indexRange=\"100-200\""
1021       "                     indexRangeExact=\"true\">"
1022       "    </SegmentTemplate></Period></MPD>";
1023 
1024   gboolean ret;
1025   GstMPDClient *mpdclient = gst_mpd_client_new ();
1026 
1027   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1028   assert_equals_int (ret, TRUE);
1029 
1030   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1031   segmentTemplate = periodNode->SegmentTemplate;
1032   segmentBase = GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->SegmentBase;
1033   assert_equals_uint64 (segmentBase->timescale, 123456);
1034   assert_equals_uint64 (segmentBase->presentationTimeOffset, 123456789);
1035   assert_equals_uint64 (segmentBase->indexRange->first_byte_pos, 100);
1036   assert_equals_uint64 (segmentBase->indexRange->last_byte_pos, 200);
1037   assert_equals_int (segmentBase->indexRangeExact, TRUE);
1038 
1039   gst_mpd_client_free (mpdclient);
1040 }
1041 
1042 GST_END_TEST;
1043 
1044 /*
1045  * Test parsing Period SegmentTemplate MultipleSegmentBaseType SegmentTimeline
1046  * attributes
1047  */
GST_START_TEST(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline)1048 GST_START_TEST
1049     (dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline)
1050 {
1051   GstMPDPeriodNode *periodNode;
1052   GstMPDSegmentTemplateNode *segmentTemplate;
1053   GstMPDSegmentTimelineNode *segmentTimeline;
1054   const gchar *xml =
1055       "<?xml version=\"1.0\"?>"
1056       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1057       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1058       "  <Period>"
1059       "    <SegmentTemplate>"
1060       "      <SegmentTimeline>"
1061       "      </SegmentTimeline></SegmentTemplate></Period></MPD>";
1062 
1063   gboolean ret;
1064   GstMPDClient *mpdclient = gst_mpd_client_new ();
1065 
1066   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1067   assert_equals_int (ret, TRUE);
1068 
1069   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1070   segmentTemplate = periodNode->SegmentTemplate;
1071 
1072   segmentTimeline = (GstMPDSegmentTimelineNode *)
1073       GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->SegmentTimeline;
1074   fail_if (segmentTimeline == NULL);
1075 
1076   gst_mpd_client_free (mpdclient);
1077 }
1078 
1079 GST_END_TEST;
1080 
1081 /*
1082  * Test parsing Period SegmentTemplate MultipleSegmentBaseType SegmentTimeline
1083  * S attributes
1084  */
GST_START_TEST(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline_s)1085 GST_START_TEST
1086     (dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline_s)
1087 {
1088   GstMPDPeriodNode *periodNode;
1089   GstMPDSegmentTemplateNode *segmentTemplate;
1090   GstMPDSegmentTimelineNode *segmentTimeline;
1091   GstMPDSNode *sNode;
1092   const gchar *xml =
1093       "<?xml version=\"1.0\"?>"
1094       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1095       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1096       "  <Period>"
1097       "    <SegmentTemplate>"
1098       "      <SegmentTimeline>"
1099       "        <S t=\"1\" d=\"2\" r=\"3\">"
1100       "        </S></SegmentTimeline></SegmentTemplate></Period></MPD>";
1101 
1102   gboolean ret;
1103   GstMPDClient *mpdclient = gst_mpd_client_new ();
1104 
1105   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1106   assert_equals_int (ret, TRUE);
1107 
1108   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1109   segmentTemplate = periodNode->SegmentTemplate;
1110   segmentTimeline = (GstMPDSegmentTimelineNode *)
1111       GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->SegmentTimeline;
1112   sNode = (GstMPDSNode *) g_queue_peek_head (&segmentTimeline->S);
1113   assert_equals_uint64 (sNode->t, 1);
1114   assert_equals_uint64 (sNode->d, 2);
1115   assert_equals_uint64 (sNode->r, 3);
1116 
1117   gst_mpd_client_free (mpdclient);
1118 }
1119 
1120 GST_END_TEST;
1121 
1122 /*
1123  * Test parsing Period SegmentTemplate MultipleSegmentBaseType
1124  * BitstreamSwitching attributes
1125  */
GST_START_TEST(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_bitstreamSwitching)1126 GST_START_TEST
1127     (dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_bitstreamSwitching)
1128 {
1129   GstMPDPeriodNode *periodNode;
1130   GstMPDSegmentTemplateNode *segmentTemplate;
1131   GstMPDURLTypeNode *bitstreamSwitching;
1132   const gchar *xml =
1133       "<?xml version=\"1.0\"?>"
1134       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1135       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1136       "  <Period>"
1137       "    <SegmentTemplate duration=\"1\">"
1138       "      <BitstreamSwitching sourceURL=\"TestSourceURL\""
1139       "                          range=\"100-200\">"
1140       "      </BitstreamSwitching></SegmentTemplate></Period></MPD>";
1141 
1142   gboolean ret;
1143   GstMPDClient *mpdclient = gst_mpd_client_new ();
1144 
1145   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1146   assert_equals_int (ret, TRUE);
1147 
1148   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1149   segmentTemplate = periodNode->SegmentTemplate;
1150   bitstreamSwitching =
1151       GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->BitstreamSwitching;
1152   assert_equals_string (bitstreamSwitching->sourceURL, "TestSourceURL");
1153   assert_equals_uint64 (bitstreamSwitching->range->first_byte_pos, 100);
1154   assert_equals_uint64 (bitstreamSwitching->range->last_byte_pos, 200);
1155 
1156   gst_mpd_client_free (mpdclient);
1157 }
1158 
1159 GST_END_TEST;
1160 
1161 /*
1162  * Test parsing Period AdaptationSet attributes
1163  *
1164  */
GST_START_TEST(dash_mpdparser_period_adaptationSet)1165 GST_START_TEST (dash_mpdparser_period_adaptationSet)
1166 {
1167   GstMPDPeriodNode *periodNode;
1168   GstMPDAdaptationSetNode *adaptationSet;
1169   const gchar *xml =
1170       "<?xml version=\"1.0\"?>"
1171       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1172       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1173       "  <Period>"
1174       "    <AdaptationSet id=\"7\""
1175       "                   group=\"8\""
1176       "                   lang=\"en\""
1177       "                   contentType=\"TestContentType\""
1178       "                   par=\"4:3\""
1179       "                   minBandwidth=\"100\""
1180       "                   maxBandwidth=\"200\""
1181       "                   minWidth=\"1000\""
1182       "                   maxWidth=\"2000\""
1183       "                   minHeight=\"1100\""
1184       "                   maxHeight=\"2100\""
1185       "                   minFrameRate=\"25/123\""
1186       "                   maxFrameRate=\"26\""
1187       "                   segmentAlignment=\"2\""
1188       "                   subsegmentAlignment=\"false\""
1189       "                   subsegmentStartsWithSAP=\"6\""
1190       "                   bitstreamSwitching=\"false\">"
1191       "    </AdaptationSet></Period></MPD>";
1192 
1193   gboolean ret;
1194   GstMPDClient *mpdclient = gst_mpd_client_new ();
1195 
1196   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1197   assert_equals_int (ret, TRUE);
1198 
1199   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1200   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1201   assert_equals_uint64 (adaptationSet->id, 7);
1202   assert_equals_uint64 (adaptationSet->group, 8);
1203   assert_equals_string (adaptationSet->lang, "en");
1204   assert_equals_string (adaptationSet->contentType, "TestContentType");
1205   assert_equals_uint64 (adaptationSet->par->num, 4);
1206   assert_equals_uint64 (adaptationSet->par->den, 3);
1207   assert_equals_uint64 (adaptationSet->minBandwidth, 100);
1208   assert_equals_uint64 (adaptationSet->maxBandwidth, 200);
1209   assert_equals_uint64 (adaptationSet->minWidth, 1000);
1210   assert_equals_uint64 (adaptationSet->maxWidth, 2000);
1211   assert_equals_uint64 (adaptationSet->minHeight, 1100);
1212   assert_equals_uint64 (adaptationSet->maxHeight, 2100);
1213   assert_equals_uint64 (GST_MPD_REPRESENTATION_BASE_NODE
1214       (adaptationSet)->minFrameRate->num, 25);
1215   assert_equals_uint64 (GST_MPD_REPRESENTATION_BASE_NODE
1216       (adaptationSet)->minFrameRate->den, 123);
1217   assert_equals_uint64 (GST_MPD_REPRESENTATION_BASE_NODE
1218       (adaptationSet)->maxFrameRate->num, 26);
1219   assert_equals_uint64 (GST_MPD_REPRESENTATION_BASE_NODE
1220       (adaptationSet)->maxFrameRate->den, 1);
1221   assert_equals_int (adaptationSet->segmentAlignment->flag, 1);
1222   assert_equals_uint64 (adaptationSet->segmentAlignment->value, 2);
1223   assert_equals_int (adaptationSet->subsegmentAlignment->flag, 0);
1224   assert_equals_uint64 (adaptationSet->subsegmentAlignment->value, 0);
1225   assert_equals_int (adaptationSet->subsegmentStartsWithSAP, 6);
1226   assert_equals_int (adaptationSet->bitstreamSwitching, 0);
1227 
1228   gst_mpd_client_free (mpdclient);
1229 }
1230 
1231 GST_END_TEST;
1232 
1233 /*
1234  * Test parsing Period AdaptationSet RepresentationBase attributes
1235  *
1236  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representationBase)1237 GST_START_TEST (dash_mpdparser_period_adaptationSet_representationBase)
1238 {
1239   GstMPDPeriodNode *periodNode;
1240   GstMPDAdaptationSetNode *adaptationSet;
1241   GstMPDRepresentationBaseNode *representationBase;
1242   const gchar *xml =
1243       "<?xml version=\"1.0\"?>"
1244       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1245       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1246       "  <Period>"
1247       "    <AdaptationSet profiles=\"TestProfiles\""
1248       "                   width=\"100\""
1249       "                   height=\"200\""
1250       "                   sar=\"10:20\""
1251       "                   frameRate=\"30/40\""
1252       "                   audioSamplingRate=\"TestAudioSamplingRate\""
1253       "                   mimeType=\"TestMimeType\""
1254       "                   segmentProfiles=\"TestSegmentProfiles\""
1255       "                   codecs=\"TestCodecs\""
1256       "                   maximumSAPPeriod=\"3.4\""
1257       "                   startWithSAP=\"0\""
1258       "                   maxPlayoutRate=\"1.2\""
1259       "                   codingDependency=\"false\""
1260       "                   scanType=\"progressive\">"
1261       "    </AdaptationSet></Period></MPD>";
1262 
1263   gboolean ret;
1264   GstMPDClient *mpdclient = gst_mpd_client_new ();
1265 
1266   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1267   assert_equals_int (ret, TRUE);
1268 
1269   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1270   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1271   representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
1272   assert_equals_string (representationBase->profiles, "TestProfiles");
1273   assert_equals_uint64 (representationBase->width, 100);
1274   assert_equals_uint64 (representationBase->height, 200);
1275   assert_equals_uint64 (representationBase->sar->num, 10);
1276   assert_equals_uint64 (representationBase->sar->den, 20);
1277   assert_equals_uint64 (representationBase->frameRate->num, 30);
1278   assert_equals_uint64 (representationBase->frameRate->den, 40);
1279   assert_equals_string (representationBase->audioSamplingRate,
1280       "TestAudioSamplingRate");
1281   assert_equals_string (representationBase->mimeType, "TestMimeType");
1282   assert_equals_string (representationBase->segmentProfiles,
1283       "TestSegmentProfiles");
1284   assert_equals_string (representationBase->codecs, "TestCodecs");
1285   assert_equals_float (representationBase->maximumSAPPeriod, 3.4);
1286   assert_equals_int (representationBase->startWithSAP, GST_SAP_TYPE_0);
1287   assert_equals_float (representationBase->maxPlayoutRate, 1.2);
1288   assert_equals_float (representationBase->codingDependency, 0);
1289   assert_equals_string (representationBase->scanType, "progressive");
1290 
1291   gst_mpd_client_free (mpdclient);
1292 }
1293 
1294 GST_END_TEST;
1295 
1296 /*
1297  * Test parsing Period AdaptationSet RepresentationBase FramePacking attributes
1298  *
1299  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representationBase_framePacking)1300 GST_START_TEST
1301     (dash_mpdparser_period_adaptationSet_representationBase_framePacking) {
1302   GstMPDPeriodNode *periodNode;
1303   GstMPDAdaptationSetNode *adaptationSet;
1304   GstMPDRepresentationBaseNode *representationBase;
1305   GstMPDDescriptorTypeNode *framePacking;
1306   const gchar *xml =
1307       "<?xml version=\"1.0\"?>"
1308       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1309       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1310       "  <Period>"
1311       "    <AdaptationSet>"
1312       "      <FramePacking schemeIdUri=\"TestSchemeIdUri\""
1313       "                    value=\"TestValue\">"
1314       "      </FramePacking></AdaptationSet></Period></MPD>";
1315 
1316   gboolean ret;
1317   GstMPDClient *mpdclient = gst_mpd_client_new ();
1318 
1319   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1320   assert_equals_int (ret, TRUE);
1321 
1322   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1323   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1324   representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
1325   framePacking =
1326       (GstMPDDescriptorTypeNode *) representationBase->FramePacking->data;
1327   assert_equals_string (framePacking->schemeIdUri, "TestSchemeIdUri");
1328   assert_equals_string (framePacking->value, "TestValue");
1329 
1330   gst_mpd_client_free (mpdclient);
1331 }
1332 
1333 GST_END_TEST;
1334 
1335 /*
1336  * Test parsing Period AdaptationSet RepresentationBase
1337  * AudioChannelConfiguration attributes
1338  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representationBase_audioChannelConfiguration)1339 GST_START_TEST
1340     (dash_mpdparser_period_adaptationSet_representationBase_audioChannelConfiguration)
1341 {
1342   GstMPDPeriodNode *periodNode;
1343   GstMPDAdaptationSetNode *adaptationSet;
1344   GstMPDRepresentationBaseNode *representationBase;
1345   GstMPDDescriptorTypeNode *audioChannelConfiguration;
1346   const gchar *xml =
1347       "<?xml version=\"1.0\"?>"
1348       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1349       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1350       "  <Period>"
1351       "    <AdaptationSet>"
1352       "      <AudioChannelConfiguration schemeIdUri=\"TestSchemeIdUri\""
1353       "                                 value=\"TestValue\">"
1354       "      </AudioChannelConfiguration></AdaptationSet></Period></MPD>";
1355 
1356   gboolean ret;
1357   GstMPDClient *mpdclient = gst_mpd_client_new ();
1358 
1359   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1360   assert_equals_int (ret, TRUE);
1361 
1362   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1363   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1364   representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
1365   audioChannelConfiguration = (GstMPDDescriptorTypeNode *)
1366       representationBase->AudioChannelConfiguration->data;
1367   assert_equals_string (audioChannelConfiguration->schemeIdUri,
1368       "TestSchemeIdUri");
1369   assert_equals_string (audioChannelConfiguration->value, "TestValue");
1370 
1371   gst_mpd_client_free (mpdclient);
1372 }
1373 
1374 GST_END_TEST;
1375 
1376 /*
1377  * Test parsing Period AdaptationSet RepresentationBase ContentProtection
1378  * attributes
1379  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representationBase_contentProtection)1380 GST_START_TEST
1381     (dash_mpdparser_period_adaptationSet_representationBase_contentProtection) {
1382   GstMPDPeriodNode *periodNode;
1383   GstMPDAdaptationSetNode *adaptationSet;
1384   GstMPDRepresentationBaseNode *representationBase;
1385   GstMPDDescriptorTypeNode *contentProtection;
1386   const gchar *xml =
1387       "<?xml version=\"1.0\"?>"
1388       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1389       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1390       "  <Period>"
1391       "    <AdaptationSet>"
1392       "      <ContentProtection schemeIdUri=\"TestSchemeIdUri\""
1393       "                         value=\"TestValue\">"
1394       "      </ContentProtection></AdaptationSet></Period></MPD>";
1395 
1396   gboolean ret;
1397   GstMPDClient *mpdclient = gst_mpd_client_new ();
1398   gchar *str;
1399 
1400   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1401   assert_equals_int (ret, TRUE);
1402 
1403   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1404   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1405   representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
1406   contentProtection =
1407       (GstMPDDescriptorTypeNode *) representationBase->ContentProtection->data;
1408   assert_equals_string (contentProtection->schemeIdUri, "TestSchemeIdUri");
1409 
1410   /* We can't do a simple compare of value (which should be an XML dump
1411      of the ContentProtection element), because the whitespace
1412      formatting from xmlDump might differ between versions of libxml */
1413   str = strstr (contentProtection->value, "<ContentProtection");
1414   fail_if (str == NULL);
1415   str = strstr (contentProtection->value, "value=\"TestValue\"");
1416   fail_if (str == NULL);
1417   str = strstr (contentProtection->value, "</ContentProtection>");
1418   fail_if (str == NULL);
1419 
1420   gst_mpd_client_free (mpdclient);
1421 }
1422 
1423 GST_END_TEST;
1424 
1425 /*
1426  * Test parsing Period AdaptationSet RepresentationBase ContentProtection
1427  * with custom ContentProtection content.
1428  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representationBase_contentProtection_with_content)1429 GST_START_TEST
1430     (dash_mpdparser_period_adaptationSet_representationBase_contentProtection_with_content)
1431 {
1432   GstMPDPeriodNode *periodNode;
1433   GstMPDAdaptationSetNode *adaptationSet;
1434   GstMPDRepresentationBaseNode *representationBase;
1435   GstMPDDescriptorTypeNode *contentProtection;
1436   const gchar *xml =
1437       "<?xml version=\"1.0\"?>"
1438       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1439       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1440       "     xmlns:customns=\"foo\""
1441       "  <Period>"
1442       "    <AdaptationSet>"
1443       "      <ContentProtection schemeIdUri=\"TestSchemeIdUri\">"
1444       "        <customns:bar>Hello world</customns:bar>"
1445       "      </ContentProtection></AdaptationSet></Period></MPD>";
1446 
1447   gboolean ret;
1448   GstMPDClient *mpdclient = gst_mpd_client_new ();
1449   gchar *str;
1450 
1451   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1452   assert_equals_int (ret, TRUE);
1453 
1454   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1455   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1456   representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
1457   contentProtection =
1458       (GstMPDDescriptorTypeNode *) representationBase->ContentProtection->data;
1459   assert_equals_string (contentProtection->schemeIdUri, "TestSchemeIdUri");
1460 
1461   /* We can't do a simple compare of value (which should be an XML dump
1462      of the ContentProtection element), because the whitespace
1463      formatting from xmlDump might differ between versions of libxml */
1464   str = strstr (contentProtection->value, "<ContentProtection");
1465   fail_if (str == NULL);
1466   str =
1467       strstr (contentProtection->value,
1468       "<customns:bar>Hello world</customns:bar>");
1469   fail_if (str == NULL);
1470   str = strstr (contentProtection->value, "</ContentProtection>");
1471   fail_if (str == NULL);
1472 
1473   gst_mpd_client_free (mpdclient);
1474 }
1475 
1476 GST_END_TEST;
1477 
1478 
1479 /*
1480  * Test parsing ContentProtection element that has no value attribute
1481  */
GST_START_TEST(dash_mpdparser_contentProtection_no_value)1482 GST_START_TEST (dash_mpdparser_contentProtection_no_value)
1483 {
1484   GstMPDPeriodNode *periodNode;
1485   GstMPDAdaptationSetNode *adaptationSet;
1486   GstMPDRepresentationBaseNode *representationBase;
1487   GstMPDDescriptorTypeNode *contentProtection;
1488   const gchar *xml =
1489       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
1490       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1491       "     xmlns:mspr=\"urn:microsoft:playready\""
1492       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1493       "  <Period>"
1494       "    <AdaptationSet>"
1495       "      <ContentProtection schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\" value=\"cenc\"/>"
1496       "      <ContentProtection xmlns:mas=\"urn:marlin:mas:1-0:services:schemas:mpd\" schemeIdUri=\"urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4\">"
1497       "	      <mas:MarlinContentIds>"
1498       "	        <mas:MarlinContentId>urn:marlin:kid:02020202020202020202020202020202</mas:MarlinContentId>"
1499       "       </mas:MarlinContentIds>"
1500       "      </ContentProtection>"
1501       "      <ContentProtection schemeIdUri=\"urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95\" value=\"MSPR 2.0\">"
1502       "        <mspr:pro>dGVzdA==</mspr:pro>"
1503       "     </ContentProtection>" "</AdaptationSet></Period></MPD>";
1504 
1505   gboolean ret;
1506   GstMPDClient *mpdclient = gst_mpd_client_new ();
1507   gchar *str;
1508 
1509   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1510   assert_equals_int (ret, TRUE);
1511 
1512   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1513   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1514   representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
1515   assert_equals_int (g_list_length (representationBase->ContentProtection), 3);
1516   contentProtection = (GstMPDDescriptorTypeNode *)
1517       g_list_nth (representationBase->ContentProtection, 1)->data;
1518   assert_equals_string (contentProtection->schemeIdUri,
1519       "urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4");
1520   fail_if (contentProtection->value == NULL);
1521   /* We can't do a simple compare of value (which should be an XML dump
1522      of the ContentProtection element), because the whitespace
1523      formatting from xmlDump might differ between versions of libxml */
1524   str = strstr (contentProtection->value, "<ContentProtection");
1525   fail_if (str == NULL);
1526   str = strstr (contentProtection->value, "<mas:MarlinContentIds>");
1527   fail_if (str == NULL);
1528   str = strstr (contentProtection->value, "<mas:MarlinContentId>");
1529   fail_if (str == NULL);
1530   str =
1531       strstr (contentProtection->value,
1532       "urn:marlin:kid:02020202020202020202020202020202");
1533   fail_if (str == NULL);
1534   str = strstr (contentProtection->value, "</ContentProtection>");
1535   fail_if (str == NULL);
1536   gst_mpd_client_free (mpdclient);
1537 }
1538 
1539 GST_END_TEST;
1540 
1541 /*
1542  * Test parsing ContentProtection element that has no value attribute
1543  * nor an XML encoding
1544  */
GST_START_TEST(dash_mpdparser_contentProtection_no_value_no_encoding)1545 GST_START_TEST (dash_mpdparser_contentProtection_no_value_no_encoding)
1546 {
1547   GstMPDPeriodNode *periodNode;
1548   GstMPDAdaptationSetNode *adaptationSet;
1549   GstMPDRepresentationBaseNode *representationBase;
1550   GstMPDDescriptorTypeNode *contentProtection;
1551   const gchar *xml =
1552       "<?xml version=\"1.0\"?>"
1553       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1554       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1555       "  <Period>"
1556       "    <AdaptationSet>"
1557       "      <ContentProtection schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\" value=\"cenc\"/>"
1558       "      <ContentProtection xmlns:mas=\"urn:marlin:mas:1-0:services:schemas:mpd\" schemeIdUri=\"urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4\">"
1559       "	      <mas:MarlinContentIds>"
1560       "	        <mas:MarlinContentId>urn:marlin:kid:02020202020202020202020202020202</mas:MarlinContentId>"
1561       "       </mas:MarlinContentIds>"
1562       "     </ContentProtection>" "</AdaptationSet></Period></MPD>";
1563 
1564   gboolean ret;
1565   GstMPDClient *mpdclient = gst_mpd_client_new ();
1566 
1567   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1568   assert_equals_int (ret, TRUE);
1569 
1570   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1571   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1572   representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
1573   assert_equals_int (g_list_length (representationBase->ContentProtection), 2);
1574   contentProtection = (GstMPDDescriptorTypeNode *)
1575       g_list_nth (representationBase->ContentProtection, 1)->data;
1576   assert_equals_string (contentProtection->schemeIdUri,
1577       "urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4");
1578   fail_if (contentProtection->value == NULL);
1579   gst_mpd_client_free (mpdclient);
1580 }
1581 
1582 GST_END_TEST;
1583 
1584 /*
1585  * Test parsing Period AdaptationSet RepresentationBase ContentProtection
1586  * attributes
1587  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representationBase_contentProtection_xml_namespaces)1588 GST_START_TEST
1589     (dash_mpdparser_period_adaptationSet_representationBase_contentProtection_xml_namespaces)
1590 {
1591   const gchar *xml =
1592       "<?xml version=\"1.0\"?>"
1593       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" minBufferTime=\"PT1.500S\""
1594       "  type=\"static\" mediaPresentationDuration=\"PT0H24M28.000S\""
1595       "  maxSegmentDuration=\"PT0H0M4.000S\""
1596       "  profiles=\"urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash264\""
1597       "  xmlns:cenc=\"urn:mpeg:cenc:2013\" xmlns:clearkey=\"http://dashif.org/guidelines/clearKey\">"
1598       "  <Period>" "    <AdaptationSet>"
1599       "      <ContentProtection schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\""
1600       "        value=\"cenc\" cenc:default_KID=\"33969335-53A5-4E78-BA99-9054CD1B2871\">"
1601       "      </ContentProtection>"
1602       "      <ContentProtection value=\"ClearKey1.0\""
1603       "        schemeIdUri=\"urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e\">"
1604       "        <clearkey:Laurl Lic_type=\"EME-1.0\">https://drm.test.example/AcquireLicense</clearkey:Laurl>"
1605       "      </ContentProtection></AdaptationSet></Period></MPD>";
1606   GstMPDPeriodNode *periodNode;
1607   GstMPDAdaptationSetNode *adaptationSet;
1608   GstMPDRepresentationBaseNode *representationBase;
1609   GstMPDDescriptorTypeNode *contentProtection;
1610   gboolean ret;
1611   GstMPDClient *mpdclient = gst_mpd_client_new ();
1612   xmlDocPtr doc;
1613   xmlNode *root_element = NULL, *node;
1614   xmlChar *property = NULL;
1615 
1616   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1617   assert_equals_int (ret, TRUE);
1618 
1619   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1620   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1621   representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
1622   assert_equals_int (g_list_length (representationBase->ContentProtection), 2);
1623   contentProtection = (GstMPDDescriptorTypeNode *)
1624       g_list_nth_data (representationBase->ContentProtection, 0);
1625   assert_equals_string (contentProtection->schemeIdUri,
1626       "urn:mpeg:dash:mp4protection:2011");
1627 
1628   contentProtection = (GstMPDDescriptorTypeNode *)
1629       g_list_nth_data (representationBase->ContentProtection, 1);
1630   assert_equals_string (contentProtection->schemeIdUri,
1631       "urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e");
1632 
1633   /* We can't do a simple string compare of value, because the whitespace
1634      formatting from xmlDump might differ between versions of libxml */
1635   LIBXML_TEST_VERSION;
1636   doc =
1637       xmlReadMemory (contentProtection->value,
1638       strlen (contentProtection->value), "ContentProtection.xml", NULL,
1639       XML_PARSE_NONET);
1640   fail_if (!doc);
1641   root_element = xmlDocGetRootElement (doc);
1642   fail_if (root_element->type != XML_ELEMENT_NODE);
1643   fail_if (xmlStrcmp (root_element->name,
1644           (xmlChar *) "ContentProtection") != 0);
1645   fail_if ((property =
1646           xmlGetNoNsProp (root_element, (const xmlChar *) "value")) == NULL);
1647   fail_if (xmlStrcmp (property, (xmlChar *) "ClearKey1.0") != 0);
1648   xmlFree (property);
1649   fail_if ((property =
1650           xmlGetNoNsProp (root_element,
1651               (const xmlChar *) "schemeIdUri")) == NULL);
1652   assert_equals_string ((const gchar *) property,
1653       "urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e");
1654   xmlFree (property);
1655 
1656   for (node = root_element->children; node; node = node->next) {
1657     if (node->type == XML_ELEMENT_NODE)
1658       break;
1659   }
1660   assert_equals_string ((const gchar *) node->name, "Laurl");
1661   assert_equals_string ((const gchar *) node->children->content,
1662       "https://drm.test.example/AcquireLicense");
1663 
1664   xmlFreeDoc (doc);
1665 
1666   gst_mpd_client_free (mpdclient);
1667 }
1668 
1669 GST_END_TEST;
1670 
1671 /*
1672  * Test parsing Period AdaptationSet Accessibility attributes
1673  *
1674  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_accessibility)1675 GST_START_TEST (dash_mpdparser_period_adaptationSet_accessibility)
1676 {
1677   GstMPDPeriodNode *periodNode;
1678   GstMPDAdaptationSetNode *adaptationSet;
1679   GstMPDDescriptorTypeNode *accessibility;
1680   const gchar *xml =
1681       "<?xml version=\"1.0\"?>"
1682       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1683       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1684       "  <Period>"
1685       "    <AdaptationSet>"
1686       "      <Accessibility schemeIdUri=\"TestSchemeIdUri\""
1687       "                     value=\"TestValue\">"
1688       "      </Accessibility></AdaptationSet></Period></MPD>";
1689 
1690   gboolean ret;
1691   GstMPDClient *mpdclient = gst_mpd_client_new ();
1692 
1693   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1694   assert_equals_int (ret, TRUE);
1695 
1696   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1697   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1698   accessibility =
1699       (GstMPDDescriptorTypeNode *) adaptationSet->Accessibility->data;
1700   assert_equals_string (accessibility->schemeIdUri, "TestSchemeIdUri");
1701   assert_equals_string (accessibility->value, "TestValue");
1702 
1703   gst_mpd_client_free (mpdclient);
1704 }
1705 
1706 GST_END_TEST;
1707 
1708 /*
1709  * Test parsing Period AdaptationSet Role attributes
1710  *
1711  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_role)1712 GST_START_TEST (dash_mpdparser_period_adaptationSet_role)
1713 {
1714   GstMPDPeriodNode *periodNode;
1715   GstMPDAdaptationSetNode *adaptationSet;
1716   GstMPDDescriptorTypeNode *role;
1717   const gchar *xml =
1718       "<?xml version=\"1.0\"?>"
1719       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1720       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1721       "  <Period>"
1722       "    <AdaptationSet>"
1723       "      <Role schemeIdUri=\"TestSchemeIdUri\""
1724       "            value=\"TestValue\">"
1725       "      </Role></AdaptationSet></Period></MPD>";
1726 
1727   gboolean ret;
1728   GstMPDClient *mpdclient = gst_mpd_client_new ();
1729 
1730   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1731   assert_equals_int (ret, TRUE);
1732 
1733   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1734   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1735   role = (GstMPDDescriptorTypeNode *) adaptationSet->Role->data;
1736   assert_equals_string (role->schemeIdUri, "TestSchemeIdUri");
1737   assert_equals_string (role->value, "TestValue");
1738 
1739   gst_mpd_client_free (mpdclient);
1740 }
1741 
1742 GST_END_TEST;
1743 
1744 /*
1745  * Test parsing Period AdaptationSet Rating attributes
1746  *
1747  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_rating)1748 GST_START_TEST (dash_mpdparser_period_adaptationSet_rating)
1749 {
1750   GstMPDPeriodNode *periodNode;
1751   GstMPDAdaptationSetNode *adaptationSet;
1752   GstMPDDescriptorTypeNode *rating;
1753   const gchar *xml =
1754       "<?xml version=\"1.0\"?>"
1755       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1756       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1757       "  <Period>"
1758       "    <AdaptationSet>"
1759       "      <Rating schemeIdUri=\"TestSchemeIdUri\""
1760       "              value=\"TestValue\">"
1761       "      </Rating></AdaptationSet></Period></MPD>";
1762 
1763   gboolean ret;
1764   GstMPDClient *mpdclient = gst_mpd_client_new ();
1765 
1766   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1767   assert_equals_int (ret, TRUE);
1768 
1769   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1770   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1771   rating = (GstMPDDescriptorTypeNode *) adaptationSet->Rating->data;
1772   assert_equals_string (rating->schemeIdUri, "TestSchemeIdUri");
1773   assert_equals_string (rating->value, "TestValue");
1774 
1775   gst_mpd_client_free (mpdclient);
1776 }
1777 
1778 GST_END_TEST;
1779 
1780 /*
1781  * Test parsing Period AdaptationSet Viewpoint attributes
1782  *
1783  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_viewpoint)1784 GST_START_TEST (dash_mpdparser_period_adaptationSet_viewpoint)
1785 {
1786   GstMPDPeriodNode *periodNode;
1787   GstMPDAdaptationSetNode *adaptationSet;
1788   GstMPDDescriptorTypeNode *viewpoint;
1789   const gchar *xml =
1790       "<?xml version=\"1.0\"?>"
1791       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1792       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1793       "  <Period>"
1794       "    <AdaptationSet>"
1795       "      <Viewpoint schemeIdUri=\"TestSchemeIdUri\""
1796       "                 value=\"TestValue\">"
1797       "      </Viewpoint></AdaptationSet></Period></MPD>";
1798 
1799   gboolean ret;
1800   GstMPDClient *mpdclient = gst_mpd_client_new ();
1801 
1802   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1803   assert_equals_int (ret, TRUE);
1804 
1805   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1806   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1807   viewpoint = (GstMPDDescriptorTypeNode *) adaptationSet->Viewpoint->data;
1808   assert_equals_string (viewpoint->schemeIdUri, "TestSchemeIdUri");
1809   assert_equals_string (viewpoint->value, "TestValue");
1810 
1811   gst_mpd_client_free (mpdclient);
1812 }
1813 
1814 GST_END_TEST;
1815 
1816 /*
1817  * Test parsing Period AdaptationSet ContentComponent attributes
1818  *
1819  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_contentComponent)1820 GST_START_TEST (dash_mpdparser_period_adaptationSet_contentComponent)
1821 {
1822   GstMPDPeriodNode *periodNode;
1823   GstMPDAdaptationSetNode *adaptationSet;
1824   GstMPDContentComponentNode *contentComponent;
1825   const gchar *xml =
1826       "<?xml version=\"1.0\"?>"
1827       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1828       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1829       "  <Period>"
1830       "    <AdaptationSet>"
1831       "      <ContentComponent id=\"1\""
1832       "                        lang=\"en\""
1833       "                        contentType=\"TestContentType\""
1834       "                        par=\"10:20\">"
1835       "      </ContentComponent></AdaptationSet></Period></MPD>";
1836 
1837   gboolean ret;
1838   GstMPDClient *mpdclient = gst_mpd_client_new ();
1839 
1840   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1841   assert_equals_int (ret, TRUE);
1842 
1843   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1844   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1845   contentComponent = (GstMPDContentComponentNode *)
1846       adaptationSet->ContentComponents->data;
1847   assert_equals_uint64 (contentComponent->id, 1);
1848   assert_equals_string (contentComponent->lang, "en");
1849   assert_equals_string (contentComponent->contentType, "TestContentType");
1850   assert_equals_uint64 (contentComponent->par->num, 10);
1851   assert_equals_uint64 (contentComponent->par->den, 20);
1852 
1853   gst_mpd_client_free (mpdclient);
1854 }
1855 
1856 GST_END_TEST;
1857 
1858 /*
1859  * Test parsing Period AdaptationSet ContentComponent Accessibility attributes
1860  *
1861  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_contentComponent_accessibility)1862 GST_START_TEST
1863     (dash_mpdparser_period_adaptationSet_contentComponent_accessibility) {
1864   GstMPDPeriodNode *periodNode;
1865   GstMPDAdaptationSetNode *adaptationSet;
1866   GstMPDContentComponentNode *contentComponent;
1867   GstMPDDescriptorTypeNode *accessibility;
1868   const gchar *xml =
1869       "<?xml version=\"1.0\"?>"
1870       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1871       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1872       "  <Period>"
1873       "    <AdaptationSet>"
1874       "      <ContentComponent>"
1875       "        <Accessibility schemeIdUri=\"TestSchemeIdUri\""
1876       "                       value=\"TestValue\">"
1877       "        </Accessibility>"
1878       "      </ContentComponent></AdaptationSet></Period></MPD>";
1879 
1880   gboolean ret;
1881   GstMPDClient *mpdclient = gst_mpd_client_new ();
1882 
1883   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1884   assert_equals_int (ret, TRUE);
1885 
1886   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1887   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1888   contentComponent = (GstMPDContentComponentNode *)
1889       adaptationSet->ContentComponents->data;
1890   accessibility =
1891       (GstMPDDescriptorTypeNode *) contentComponent->Accessibility->data;
1892   assert_equals_string (accessibility->schemeIdUri, "TestSchemeIdUri");
1893   assert_equals_string (accessibility->value, "TestValue");
1894 
1895   gst_mpd_client_free (mpdclient);
1896 }
1897 
1898 GST_END_TEST;
1899 
1900 /*
1901  * Test parsing Period AdaptationSet ContentComponent Role attributes
1902  *
1903  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_contentComponent_role)1904 GST_START_TEST (dash_mpdparser_period_adaptationSet_contentComponent_role)
1905 {
1906   GstMPDPeriodNode *periodNode;
1907   GstMPDAdaptationSetNode *adaptationSet;
1908   GstMPDContentComponentNode *contentComponent;
1909   GstMPDDescriptorTypeNode *role;
1910   const gchar *xml =
1911       "<?xml version=\"1.0\"?>"
1912       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1913       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1914       "  <Period>"
1915       "    <AdaptationSet>"
1916       "      <ContentComponent>"
1917       "        <Role schemeIdUri=\"TestSchemeIdUri\""
1918       "              value=\"TestValue\">"
1919       "        </Role></ContentComponent></AdaptationSet></Period></MPD>";
1920 
1921   gboolean ret;
1922   GstMPDClient *mpdclient = gst_mpd_client_new ();
1923 
1924   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1925   assert_equals_int (ret, TRUE);
1926 
1927   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1928   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1929   contentComponent = (GstMPDContentComponentNode *)
1930       adaptationSet->ContentComponents->data;
1931   role = (GstMPDDescriptorTypeNode *) contentComponent->Role->data;
1932   assert_equals_string (role->schemeIdUri, "TestSchemeIdUri");
1933   assert_equals_string (role->value, "TestValue");
1934 
1935   gst_mpd_client_free (mpdclient);
1936 }
1937 
1938 GST_END_TEST;
1939 
1940 /*
1941  * Test parsing Period AdaptationSet ContentComponent Rating attributes
1942  *
1943  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_contentComponent_rating)1944 GST_START_TEST (dash_mpdparser_period_adaptationSet_contentComponent_rating)
1945 {
1946   GstMPDPeriodNode *periodNode;
1947   GstMPDAdaptationSetNode *adaptationSet;
1948   GstMPDContentComponentNode *contentComponent;
1949   GstMPDDescriptorTypeNode *rating;
1950   const gchar *xml =
1951       "<?xml version=\"1.0\"?>"
1952       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1953       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1954       "  <Period>"
1955       "    <AdaptationSet>"
1956       "      <ContentComponent>"
1957       "        <Rating schemeIdUri=\"TestSchemeIdUri\""
1958       "                value=\"TestValue\">"
1959       "        </Rating>"
1960       "      </ContentComponent></AdaptationSet></Period></MPD>";
1961 
1962   gboolean ret;
1963   GstMPDClient *mpdclient = gst_mpd_client_new ();
1964 
1965   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
1966   assert_equals_int (ret, TRUE);
1967 
1968   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
1969   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
1970   contentComponent = (GstMPDContentComponentNode *)
1971       adaptationSet->ContentComponents->data;
1972   rating = (GstMPDDescriptorTypeNode *) contentComponent->Rating->data;
1973   assert_equals_string (rating->schemeIdUri, "TestSchemeIdUri");
1974   assert_equals_string (rating->value, "TestValue");
1975 
1976   gst_mpd_client_free (mpdclient);
1977 }
1978 
1979 GST_END_TEST;
1980 
1981 /*
1982  * Test parsing Period AdaptationSet ContentComponent Viewpoint attributes
1983  *
1984  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_contentComponent_viewpoint)1985 GST_START_TEST (dash_mpdparser_period_adaptationSet_contentComponent_viewpoint)
1986 {
1987   GstMPDPeriodNode *periodNode;
1988   GstMPDAdaptationSetNode *adaptationSet;
1989   GstMPDContentComponentNode *contentComponent;
1990   GstMPDDescriptorTypeNode *viewpoint;
1991   const gchar *xml =
1992       "<?xml version=\"1.0\"?>"
1993       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
1994       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
1995       "  <Period>"
1996       "    <AdaptationSet>"
1997       "      <ContentComponent>"
1998       "        <Viewpoint schemeIdUri=\"TestSchemeIdUri\""
1999       "                   value=\"TestValue\">"
2000       "        </Viewpoint>"
2001       "      </ContentComponent></AdaptationSet></Period></MPD>";
2002 
2003   gboolean ret;
2004   GstMPDClient *mpdclient = gst_mpd_client_new ();
2005 
2006   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2007   assert_equals_int (ret, TRUE);
2008 
2009   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2010   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2011   contentComponent = (GstMPDContentComponentNode *)
2012       adaptationSet->ContentComponents->data;
2013   viewpoint = (GstMPDDescriptorTypeNode *) contentComponent->Viewpoint->data;
2014   assert_equals_string (viewpoint->schemeIdUri, "TestSchemeIdUri");
2015   assert_equals_string (viewpoint->value, "TestValue");
2016 
2017   gst_mpd_client_free (mpdclient);
2018 }
2019 
2020 GST_END_TEST;
2021 
2022 /*
2023  * Test parsing Period AdaptationSet BaseURL attributes
2024  *
2025  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_baseURL)2026 GST_START_TEST (dash_mpdparser_period_adaptationSet_baseURL)
2027 {
2028   GstMPDPeriodNode *periodNode;
2029   GstMPDAdaptationSetNode *adaptationSet;
2030   GstMPDBaseURLNode *baseURL;
2031   const gchar *xml =
2032       "<?xml version=\"1.0\"?>"
2033       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2034       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2035       "  <Period>"
2036       "    <AdaptationSet>"
2037       "      <BaseURL serviceLocation=\"TestServiceLocation\""
2038       "               byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
2039       "    </AdaptationSet></Period></MPD>";
2040 
2041   gboolean ret;
2042   GstMPDClient *mpdclient = gst_mpd_client_new ();
2043 
2044   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2045   assert_equals_int (ret, TRUE);
2046 
2047   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2048   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2049   baseURL = (GstMPDBaseURLNode *) adaptationSet->BaseURLs->data;
2050   assert_equals_string (baseURL->baseURL, "TestBaseURL");
2051   assert_equals_string (baseURL->serviceLocation, "TestServiceLocation");
2052   assert_equals_string (baseURL->byteRange, "TestByteRange");
2053 
2054   gst_mpd_client_free (mpdclient);
2055 }
2056 
2057 GST_END_TEST;
2058 
2059 /*
2060  * Test parsing Period AdaptationSet SegmentBase attributes
2061  *
2062  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_segmentBase)2063 GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentBase)
2064 {
2065   GstMPDPeriodNode *periodNode;
2066   GstMPDAdaptationSetNode *adaptationSet;
2067   GstMPDSegmentBaseNode *segmentBase;
2068   const gchar *xml =
2069       "<?xml version=\"1.0\"?>"
2070       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2071       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2072       "  <Period>"
2073       "    <AdaptationSet>"
2074       "      <SegmentBase timescale=\"123456\""
2075       "                   presentationTimeOffset=\"123456789\""
2076       "                   indexRange=\"100-200\""
2077       "                   indexRangeExact=\"true\">"
2078       "      </SegmentBase></AdaptationSet></Period></MPD>";
2079 
2080   gboolean ret;
2081   GstMPDClient *mpdclient = gst_mpd_client_new ();
2082 
2083   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2084   assert_equals_int (ret, TRUE);
2085 
2086   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2087   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2088   segmentBase = adaptationSet->SegmentBase;
2089   assert_equals_uint64 (segmentBase->timescale, 123456);
2090   assert_equals_uint64 (segmentBase->presentationTimeOffset, 123456789);
2091   assert_equals_uint64 (segmentBase->indexRange->first_byte_pos, 100);
2092   assert_equals_uint64 (segmentBase->indexRange->last_byte_pos, 200);
2093   assert_equals_int (segmentBase->indexRangeExact, TRUE);
2094 
2095   gst_mpd_client_free (mpdclient);
2096 }
2097 
2098 GST_END_TEST;
2099 
2100 /*
2101  * Test parsing Period AdaptationSet SegmentBase Initialization attributes
2102  *
2103  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_segmentBase_initialization)2104 GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentBase_initialization)
2105 {
2106   GstMPDPeriodNode *periodNode;
2107   GstMPDAdaptationSetNode *adaptationSet;
2108   GstMPDSegmentBaseNode *segmentBase;
2109   GstMPDURLTypeNode *initialization;
2110   const gchar *xml =
2111       "<?xml version=\"1.0\"?>"
2112       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2113       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2114       "  <Period>"
2115       "    <AdaptationSet>"
2116       "      <SegmentBase>"
2117       "        <Initialisation sourceURL=\"TestSourceURL\""
2118       "                        range=\"100-200\">"
2119       "        </Initialisation></SegmentBase></AdaptationSet></Period></MPD>";
2120 
2121   gboolean ret;
2122   GstMPDClient *mpdclient = gst_mpd_client_new ();
2123 
2124   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2125   assert_equals_int (ret, TRUE);
2126 
2127   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2128   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2129   segmentBase = adaptationSet->SegmentBase;
2130   initialization = segmentBase->Initialization;
2131   assert_equals_string (initialization->sourceURL, "TestSourceURL");
2132   assert_equals_uint64 (initialization->range->first_byte_pos, 100);
2133   assert_equals_uint64 (initialization->range->last_byte_pos, 200);
2134 
2135   gst_mpd_client_free (mpdclient);
2136 }
2137 
2138 GST_END_TEST;
2139 
2140 /*
2141  * Test parsing Period AdaptationSet SegmentBase RepresentationIndex attributes
2142  *
2143  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_segmentBase_representationIndex)2144 GST_START_TEST
2145     (dash_mpdparser_period_adaptationSet_segmentBase_representationIndex) {
2146   GstMPDPeriodNode *periodNode;
2147   GstMPDAdaptationSetNode *adaptationSet;
2148   GstMPDSegmentBaseNode *segmentBase;
2149   GstMPDURLTypeNode *representationIndex;
2150   const gchar *xml =
2151       "<?xml version=\"1.0\"?>"
2152       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2153       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2154       "  <Period>"
2155       "    <AdaptationSet>"
2156       "      <SegmentBase>"
2157       "        <RepresentationIndex sourceURL=\"TestSourceURL\""
2158       "                             range=\"100-200\">"
2159       "        </RepresentationIndex>"
2160       "      </SegmentBase></AdaptationSet></Period></MPD>";
2161 
2162   gboolean ret;
2163   GstMPDClient *mpdclient = gst_mpd_client_new ();
2164 
2165   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2166   assert_equals_int (ret, TRUE);
2167 
2168   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2169   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2170   segmentBase = adaptationSet->SegmentBase;
2171   representationIndex = segmentBase->RepresentationIndex;
2172   assert_equals_string (representationIndex->sourceURL, "TestSourceURL");
2173   assert_equals_uint64 (representationIndex->range->first_byte_pos, 100);
2174   assert_equals_uint64 (representationIndex->range->last_byte_pos, 200);
2175 
2176   gst_mpd_client_free (mpdclient);
2177 }
2178 
2179 GST_END_TEST;
2180 
2181 /*
2182  * Test parsing Period AdaptationSet SegmentList attributes
2183  *
2184  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_segmentList)2185 GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentList)
2186 {
2187   GstMPDPeriodNode *periodNode;
2188   GstMPDAdaptationSetNode *adaptationSet;
2189   GstMPDSegmentListNode *segmentList;
2190   const gchar *xml =
2191       "<?xml version=\"1.0\"?>"
2192       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2193       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2194       "  <Period>"
2195       "    <AdaptationSet>"
2196       "      <SegmentList duration=\"1\"></SegmentList></AdaptationSet></Period></MPD>";
2197 
2198   gboolean ret;
2199   GstMPDClient *mpdclient = gst_mpd_client_new ();
2200 
2201   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2202   assert_equals_int (ret, TRUE);
2203 
2204   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2205   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2206   segmentList = adaptationSet->SegmentList;
2207   fail_if (segmentList == NULL);
2208 
2209   gst_mpd_client_free (mpdclient);
2210 }
2211 
2212 GST_END_TEST;
2213 
2214 /*
2215  * Test parsing Period AdaptationSet SegmentTemplate attributes
2216  *
2217  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_segmentTemplate)2218 GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentTemplate)
2219 {
2220   GstMPDPeriodNode *periodNode;
2221   GstMPDAdaptationSetNode *adaptationSet;
2222   GstMPDSegmentTemplateNode *segmentTemplate;
2223   const gchar *xml =
2224       "<?xml version=\"1.0\"?>"
2225       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2226       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2227       "  <Period>"
2228       "    <AdaptationSet>"
2229       "      <SegmentTemplate media=\"TestMedia\""
2230       "                       duration=\"1\""
2231       "                       index=\"TestIndex\""
2232       "                       initialization=\"TestInitialization\""
2233       "                       bitstreamSwitching=\"TestBitstreamSwitching\">"
2234       "      </SegmentTemplate></AdaptationSet></Period></MPD>";
2235 
2236   gboolean ret;
2237   GstMPDClient *mpdclient = gst_mpd_client_new ();
2238 
2239   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2240   assert_equals_int (ret, TRUE);
2241 
2242   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2243   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2244   segmentTemplate = adaptationSet->SegmentTemplate;
2245   assert_equals_string (segmentTemplate->media, "TestMedia");
2246   assert_equals_string (segmentTemplate->index, "TestIndex");
2247   assert_equals_string (segmentTemplate->initialization, "TestInitialization");
2248   assert_equals_string (segmentTemplate->bitstreamSwitching,
2249       "TestBitstreamSwitching");
2250 
2251   gst_mpd_client_free (mpdclient);
2252 }
2253 
2254 GST_END_TEST;
2255 
2256 
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_segmentTemplate_inherit)2257 GST_START_TEST
2258     (dash_mpdparser_period_adaptationSet_representation_segmentTemplate_inherit)
2259 {
2260   GstMPDPeriodNode *periodNode;
2261   GstMPDAdaptationSetNode *adaptationSet;
2262   GstMPDRepresentationNode *representation;
2263   GstMPDSegmentTemplateNode *segmentTemplate;
2264   const gchar *xml =
2265       "<?xml version=\"1.0\"?>"
2266       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2267       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2268       "  <Period>"
2269       "    <SegmentTemplate media=\"ParentMedia\" duration=\"1\" "
2270       "                     initialization=\"ParentInitialization\">"
2271       "    </SegmentTemplate>"
2272       "    <AdaptationSet>"
2273       "      <Representation id=\"1\" bandwidth=\"5000\">"
2274       "      <SegmentTemplate media=\"TestMedia\""
2275       "                       index=\"TestIndex\""
2276       "                       bitstreamSwitching=\"TestBitstreamSwitching\">"
2277       "      </SegmentTemplate></Representation></AdaptationSet></Period></MPD>";
2278 
2279   gboolean ret;
2280   GstMPDClient *mpdclient = gst_mpd_client_new ();
2281 
2282   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2283   assert_equals_int (ret, TRUE);
2284 
2285   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2286   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2287   representation =
2288       (GstMPDRepresentationNode *) adaptationSet->Representations->data;
2289   segmentTemplate = representation->SegmentTemplate;
2290   assert_equals_string (segmentTemplate->media, "TestMedia");
2291   assert_equals_string (segmentTemplate->index, "TestIndex");
2292   assert_equals_string (segmentTemplate->initialization,
2293       "ParentInitialization");
2294   assert_equals_string (segmentTemplate->bitstreamSwitching,
2295       "TestBitstreamSwitching");
2296 
2297   gst_mpd_client_free (mpdclient);
2298 }
2299 
2300 GST_END_TEST;
2301 
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_segmentBase_inherit)2302 GST_START_TEST
2303     (dash_mpdparser_period_adaptationSet_representation_segmentBase_inherit) {
2304   GstMPDPeriodNode *periodNode;
2305   GstMPDAdaptationSetNode *adaptationSet;
2306   GstMPDRepresentationNode *representation;
2307   GstMPDSegmentBaseNode *segmentBase;
2308   const gchar *xml =
2309       "<?xml version=\"1.0\"?>"
2310       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2311       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2312       "  <Period>"
2313       "    <SegmentBase timescale=\"123456\""
2314       "                 presentationTimeOffset=\"123456789\""
2315       "                 indexRange=\"100-200\""
2316       "                 indexRangeExact=\"true\">"
2317       "      <Initialisation sourceURL=\"TestSourceURL\""
2318       "                      range=\"100-200\" />"
2319       "    </SegmentBase>"
2320       "    <AdaptationSet>"
2321       "      <Representation id=\"1\" bandwidth=\"5000\">"
2322       "      <SegmentBase>"
2323       "      </SegmentBase></Representation></AdaptationSet></Period></MPD>";
2324 
2325   gboolean ret;
2326   GstMPDClient *mpdclient = gst_mpd_client_new ();
2327 
2328   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2329   assert_equals_int (ret, TRUE);
2330 
2331   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2332   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2333   representation =
2334       (GstMPDRepresentationNode *) adaptationSet->Representations->data;
2335   segmentBase = representation->SegmentBase;
2336   assert_equals_int (segmentBase->timescale, 123456);
2337 
2338   gst_mpd_client_free (mpdclient);
2339 }
2340 
2341 GST_END_TEST;
2342 
2343 /*
2344  * Test parsing Period AdaptationSet SegmentTemplate attributes with
2345  * inheritance
2346  */
GST_START_TEST(dash_mpdparser_adapt_repr_segmentTemplate_inherit)2347 GST_START_TEST (dash_mpdparser_adapt_repr_segmentTemplate_inherit)
2348 {
2349   GstMPDPeriodNode *periodNode;
2350   GstMPDAdaptationSetNode *adaptationSet;
2351   GstMPDSegmentTemplateNode *segmentTemplate;
2352   GstMPDRepresentationNode *representation;
2353   GstMPDSegmentBaseNode *segmentBase;
2354   const gchar *xml =
2355       "<?xml version=\"1.0\"?>"
2356       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2357       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2358       "  <Period duration=\"PT0H5M0.000S\">"
2359       "    <AdaptationSet maxWidth=\"1280\" maxHeight=\"720\" maxFrameRate=\"50\">"
2360       "      <SegmentTemplate initialization=\"set1_init.mp4\"/>"
2361       "      <Representation id=\"1\" mimeType=\"video/mp4\" codecs=\"avc1.640020\" "
2362       "          width=\"1280\" height=\"720\" frameRate=\"50\" bandwidth=\"30000\">"
2363       "        <SegmentTemplate timescale=\"12800\" media=\"track1_$Number$.m4s\" startNumber=\"1\" duration=\"25600\"/>"
2364       "  </Representation></AdaptationSet></Period></MPD>";
2365 
2366   gboolean ret;
2367   GstMPDClient *mpdclient = gst_mpd_client_new ();
2368 
2369   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2370   assert_equals_int (ret, TRUE);
2371 
2372   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2373   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2374   representation = (GstMPDRepresentationNode *)
2375       adaptationSet->Representations->data;
2376   segmentTemplate = representation->SegmentTemplate;
2377   fail_if (segmentTemplate == NULL);
2378   segmentBase = GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->SegmentBase;
2379 
2380   assert_equals_uint64 (segmentBase->timescale, 12800);
2381   assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
2382       (segmentTemplate)->duration, 25600);
2383   assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
2384       (segmentTemplate)->startNumber, 1);
2385   assert_equals_string (segmentTemplate->media, "track1_$Number$.m4s");
2386   assert_equals_string (segmentTemplate->initialization, "set1_init.mp4");
2387 
2388   gst_mpd_client_free (mpdclient);
2389 }
2390 
2391 GST_END_TEST;
2392 /*
2393  * Test parsing Period AdaptationSet SegmentTemplate attributes with
2394  * inheritance
2395  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_segmentTemplate_inherit)2396 GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentTemplate_inherit)
2397 {
2398   GstMPDPeriodNode *periodNode;
2399   GstMPDAdaptationSetNode *adaptationSet;
2400   GstMPDSegmentTemplateNode *segmentTemplate;
2401   const gchar *xml =
2402       "<?xml version=\"1.0\"?>"
2403       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2404       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2405       "  <Period>"
2406       "    <SegmentTemplate media=\"ParentMedia\" duration=\"1\" "
2407       "                     initialization=\"ParentInitialization\">"
2408       "    </SegmentTemplate>"
2409       "    <AdaptationSet>"
2410       "      <SegmentTemplate media=\"TestMedia\""
2411       "                       duration=\"1\""
2412       "                       index=\"TestIndex\""
2413       "                       bitstreamSwitching=\"TestBitstreamSwitching\">"
2414       "      </SegmentTemplate></AdaptationSet></Period></MPD>";
2415 
2416   gboolean ret;
2417   GstMPDClient *mpdclient = gst_mpd_client_new ();
2418 
2419   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2420   assert_equals_int (ret, TRUE);
2421 
2422   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2423   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2424   segmentTemplate = adaptationSet->SegmentTemplate;
2425   assert_equals_string (segmentTemplate->media, "TestMedia");
2426   assert_equals_string (segmentTemplate->index, "TestIndex");
2427   assert_equals_string (segmentTemplate->initialization,
2428       "ParentInitialization");
2429   assert_equals_string (segmentTemplate->bitstreamSwitching,
2430       "TestBitstreamSwitching");
2431 
2432   gst_mpd_client_free (mpdclient);
2433 }
2434 
2435 GST_END_TEST;
2436 
2437 /*
2438  * Test parsing Period AdaptationSet Representation attributes
2439  *
2440  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation)2441 GST_START_TEST (dash_mpdparser_period_adaptationSet_representation)
2442 {
2443   GstMPDPeriodNode *periodNode;
2444   GstMPDAdaptationSetNode *adaptationSet;
2445   GstMPDRepresentationNode *representation;
2446   const gchar *xml =
2447       "<?xml version=\"1.0\"?>"
2448       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2449       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2450       "  <Period>"
2451       "    <AdaptationSet>"
2452       "      <Representation id=\"Test_Id\""
2453       "                      bandwidth=\"100\""
2454       "                      qualityRanking=\"200\""
2455       "                      dependencyId=\"one two three\""
2456       "                      mediaStreamStructureId=\"\">"
2457       "      </Representation></AdaptationSet></Period></MPD>";
2458 
2459   gboolean ret;
2460   GstMPDClient *mpdclient = gst_mpd_client_new ();
2461 
2462   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2463   assert_equals_int (ret, TRUE);
2464 
2465   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2466   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2467   representation = (GstMPDRepresentationNode *)
2468       adaptationSet->Representations->data;
2469   assert_equals_string (representation->id, "Test_Id");
2470   assert_equals_uint64 (representation->bandwidth, 100);
2471   assert_equals_uint64 (representation->qualityRanking, 200);
2472   assert_equals_string (representation->dependencyId[0], "one");
2473   assert_equals_string (representation->dependencyId[1], "two");
2474   assert_equals_string (representation->dependencyId[2], "three");
2475   assert_equals_pointer (representation->dependencyId[3], NULL);
2476   assert_equals_pointer (representation->mediaStreamStructureId[0], NULL);
2477 
2478   gst_mpd_client_free (mpdclient);
2479 }
2480 
2481 GST_END_TEST;
2482 
2483 /*
2484  * Test parsing Period AdaptationSet Representation RepresentationBaseType attributes
2485  *
2486  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_representationBase)2487 GST_START_TEST
2488     (dash_mpdparser_period_adaptationSet_representation_representationBase) {
2489   GstMPDPeriodNode *periodNode;
2490   GstMPDAdaptationSetNode *adaptationSet;
2491   GstMPDRepresentationNode *representation;
2492 
2493   const gchar *xml =
2494       "<?xml version=\"1.0\"?>"
2495       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2496       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2497       "  <Period>"
2498       "    <AdaptationSet>"
2499       "      <Representation id=\"1\" bandwidth=\"250000\">"
2500       "      </Representation></AdaptationSet></Period></MPD>";
2501 
2502   gboolean ret;
2503   GstMPDClient *mpdclient = gst_mpd_client_new ();
2504 
2505   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2506   assert_equals_int (ret, TRUE);
2507 
2508   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2509   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2510   representation = (GstMPDRepresentationNode *)
2511       adaptationSet->Representations->data;
2512 
2513   fail_if (representation == NULL);
2514 
2515   gst_mpd_client_free (mpdclient);
2516 }
2517 
2518 GST_END_TEST;
2519 
2520 /*
2521  * Test parsing Period AdaptationSet Representation BaseURL attributes
2522  *
2523  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_baseURL)2524 GST_START_TEST (dash_mpdparser_period_adaptationSet_representation_baseURL)
2525 {
2526   GstMPDPeriodNode *periodNode;
2527   GstMPDAdaptationSetNode *adaptationSet;
2528   GstMPDRepresentationNode *representation;
2529   GstMPDBaseURLNode *baseURL;
2530   const gchar *xml =
2531       "<?xml version=\"1.0\"?>"
2532       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2533       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2534       "  <Period>"
2535       "    <AdaptationSet>"
2536       "      <Representation id=\"1\" bandwidth=\"250000\">"
2537       "        <BaseURL serviceLocation=\"TestServiceLocation\""
2538       "                 byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
2539       "      </Representation></AdaptationSet></Period></MPD>";
2540 
2541   gboolean ret;
2542   GstMPDClient *mpdclient = gst_mpd_client_new ();
2543 
2544   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2545   assert_equals_int (ret, TRUE);
2546 
2547   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2548   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2549   representation = (GstMPDRepresentationNode *)
2550       adaptationSet->Representations->data;
2551   baseURL = (GstMPDBaseURLNode *) representation->BaseURLs->data;
2552   assert_equals_string (baseURL->baseURL, "TestBaseURL");
2553   assert_equals_string (baseURL->serviceLocation, "TestServiceLocation");
2554   assert_equals_string (baseURL->byteRange, "TestByteRange");
2555 
2556   gst_mpd_client_free (mpdclient);
2557 }
2558 
2559 GST_END_TEST;
2560 
2561 /*
2562  * Test parsing Period AdaptationSet Representation SubRepresentation attributes
2563  *
2564  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_subRepresentation)2565 GST_START_TEST
2566     (dash_mpdparser_period_adaptationSet_representation_subRepresentation) {
2567   GstMPDPeriodNode *periodNode;
2568   GstMPDAdaptationSetNode *adaptationSet;
2569   GstMPDRepresentationNode *representation;
2570   GstMPDSubRepresentationNode *subRepresentation;
2571   const gchar *xml =
2572       "<?xml version=\"1.0\"?>"
2573       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2574       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2575       "  <Period>"
2576       "    <AdaptationSet>"
2577       "      <Representation id=\"1\" bandwidth=\"250000\">"
2578       "        <SubRepresentation level=\"100\""
2579       "                           dependencyLevel=\"1 2 3\""
2580       "                           bandwidth=\"200\""
2581       "                           contentComponent=\"content1 content2\">"
2582       "        </SubRepresentation>"
2583       "      </Representation></AdaptationSet></Period></MPD>";
2584 
2585   gboolean ret;
2586   GstMPDClient *mpdclient = gst_mpd_client_new ();
2587 
2588   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2589   assert_equals_int (ret, TRUE);
2590 
2591   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2592   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2593   representation = (GstMPDRepresentationNode *)
2594       adaptationSet->Representations->data;
2595   subRepresentation = (GstMPDSubRepresentationNode *)
2596       representation->SubRepresentations->data;
2597   assert_equals_uint64 (subRepresentation->level, 100);
2598   assert_equals_uint64 (subRepresentation->dependencyLevel_size, 3);
2599   assert_equals_uint64 (subRepresentation->dependencyLevel[0], 1);
2600   assert_equals_uint64 (subRepresentation->dependencyLevel[1], 2);
2601   assert_equals_uint64 (subRepresentation->dependencyLevel[2], 3);
2602   assert_equals_uint64 (subRepresentation->bandwidth, 200);
2603   assert_equals_string (subRepresentation->contentComponent[0], "content1");
2604   assert_equals_string (subRepresentation->contentComponent[1], "content2");
2605   assert_equals_pointer (subRepresentation->contentComponent[2], NULL);
2606 
2607   gst_mpd_client_free (mpdclient);
2608 }
2609 
2610 GST_END_TEST;
2611 
2612 /*
2613  * Test parsing Period AdaptationSet Representation SubRepresentation
2614  * RepresentationBase attributes
2615  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_subRepresentation_representationBase)2616 GST_START_TEST
2617     (dash_mpdparser_period_adaptationSet_representation_subRepresentation_representationBase)
2618 {
2619   GstMPDPeriodNode *periodNode;
2620   GstMPDAdaptationSetNode *adaptationSet;
2621   GstMPDRepresentationNode *representation;
2622   GstMPDSubRepresentationNode *subRepresentation;
2623 
2624   const gchar *xml =
2625       "<?xml version=\"1.0\"?>"
2626       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2627       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2628       "  <Period>"
2629       "    <AdaptationSet>"
2630       "      <Representation id=\"1\" bandwidth=\"250000\">"
2631       "        <SubRepresentation>"
2632       "        </SubRepresentation>"
2633       "      </Representation></AdaptationSet></Period></MPD>";
2634 
2635   gboolean ret;
2636   GstMPDClient *mpdclient = gst_mpd_client_new ();
2637 
2638   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2639   assert_equals_int (ret, TRUE);
2640 
2641   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2642   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2643   representation = (GstMPDRepresentationNode *)
2644       adaptationSet->Representations->data;
2645   subRepresentation = (GstMPDSubRepresentationNode *)
2646       representation->SubRepresentations->data;
2647 
2648   fail_if (subRepresentation == NULL);
2649 
2650   gst_mpd_client_free (mpdclient);
2651 }
2652 
2653 GST_END_TEST;
2654 
2655 /*
2656  * Test parsing Period AdaptationSet Representation SegmentBase attributes
2657  *
2658  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_segmentBase)2659 GST_START_TEST (dash_mpdparser_period_adaptationSet_representation_segmentBase)
2660 {
2661   GstMPDPeriodNode *periodNode;
2662   GstMPDAdaptationSetNode *adaptationSet;
2663   GstMPDRepresentationNode *representation;
2664   GstMPDSegmentBaseNode *segmentBase;
2665   const gchar *xml =
2666       "<?xml version=\"1.0\"?>"
2667       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2668       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2669       "  <Period>"
2670       "    <AdaptationSet>"
2671       "      <Representation id=\"1\" bandwidth=\"250000\">"
2672       "        <SegmentBase>"
2673       "        </SegmentBase>"
2674       "      </Representation></AdaptationSet></Period></MPD>";
2675 
2676   gboolean ret;
2677   GstMPDClient *mpdclient = gst_mpd_client_new ();
2678 
2679   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2680   assert_equals_int (ret, TRUE);
2681 
2682   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2683   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2684   representation = (GstMPDRepresentationNode *)
2685       adaptationSet->Representations->data;
2686   segmentBase = representation->SegmentBase;
2687   fail_if (segmentBase == NULL);
2688 
2689   gst_mpd_client_free (mpdclient);
2690 }
2691 
2692 GST_END_TEST;
2693 
2694 /*
2695  * Test parsing Period AdaptationSet Representation SegmentList attributes
2696  *
2697  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_segmentList)2698 GST_START_TEST (dash_mpdparser_period_adaptationSet_representation_segmentList)
2699 {
2700   GstMPDPeriodNode *periodNode;
2701   GstMPDAdaptationSetNode *adaptationSet;
2702   GstMPDRepresentationNode *representation;
2703   GstMPDSegmentListNode *segmentList;
2704   const gchar *xml =
2705       "<?xml version=\"1.0\"?>"
2706       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2707       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2708       "  <Period>"
2709       "    <AdaptationSet>"
2710       "      <Representation id=\"1\" bandwidth=\"250000\">"
2711       "        <SegmentList duration=\"1\">"
2712       "        </SegmentList>"
2713       "      </Representation></AdaptationSet></Period></MPD>";
2714 
2715   gboolean ret;
2716   GstMPDClient *mpdclient = gst_mpd_client_new ();
2717 
2718   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2719   assert_equals_int (ret, TRUE);
2720 
2721   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2722   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2723   representation = (GstMPDRepresentationNode *)
2724       adaptationSet->Representations->data;
2725   segmentList = representation->SegmentList;
2726   fail_if (segmentList == NULL);
2727 
2728   gst_mpd_client_free (mpdclient);
2729 }
2730 
2731 GST_END_TEST;
2732 
2733 /*
2734  * Test parsing Period AdaptationSet Representation SegmentTemplate attributes
2735  *
2736  */
GST_START_TEST(dash_mpdparser_period_adaptationSet_representation_segmentTemplate)2737 GST_START_TEST
2738     (dash_mpdparser_period_adaptationSet_representation_segmentTemplate) {
2739   GstMPDPeriodNode *periodNode;
2740   GstMPDAdaptationSetNode *adaptationSet;
2741   GstMPDRepresentationNode *representation;
2742   GstMPDSegmentTemplateNode *segmentTemplate;
2743   const gchar *xml =
2744       "<?xml version=\"1.0\"?>"
2745       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2746       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2747       "  <Period>"
2748       "    <AdaptationSet>"
2749       "      <Representation id=\"1\" bandwidth=\"250000\">"
2750       "        <SegmentTemplate duration=\"1\">"
2751       "        </SegmentTemplate>"
2752       "      </Representation></AdaptationSet></Period></MPD>";
2753 
2754   gboolean ret;
2755   GstMPDClient *mpdclient = gst_mpd_client_new ();
2756 
2757   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2758   assert_equals_int (ret, TRUE);
2759 
2760   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2761   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
2762   representation = (GstMPDRepresentationNode *)
2763       adaptationSet->Representations->data;
2764   segmentTemplate = representation->SegmentTemplate;
2765   fail_if (segmentTemplate == NULL);
2766 
2767   gst_mpd_client_free (mpdclient);
2768 }
2769 
2770 GST_END_TEST;
2771 
2772 /*
2773  * Test parsing Period Subset attributes
2774  *
2775  */
GST_START_TEST(dash_mpdparser_period_subset)2776 GST_START_TEST (dash_mpdparser_period_subset)
2777 {
2778   GstMPDPeriodNode *periodNode;
2779   GstMPDSubsetNode *subset;
2780   const gchar *xml =
2781       "<?xml version=\"1.0\"?>"
2782       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2783       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2784       "  <Period><Subset contains=\"1 2 3\"></Subset></Period></MPD>";
2785 
2786   gboolean ret;
2787   GstMPDClient *mpdclient = gst_mpd_client_new ();
2788 
2789   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2790   assert_equals_int (ret, TRUE);
2791 
2792   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
2793   subset = (GstMPDSubsetNode *) periodNode->Subsets->data;
2794   assert_equals_uint64 (subset->contains_size, 3);
2795   assert_equals_uint64 (subset->contains[0], 1);
2796   assert_equals_uint64 (subset->contains[1], 2);
2797   assert_equals_uint64 (subset->contains[2], 3);
2798 
2799   gst_mpd_client_free (mpdclient);
2800 }
2801 
2802 GST_END_TEST;
2803 
2804 /*
2805  * Test parsing UTCTiming elements
2806  *
2807  */
GST_START_TEST(dash_mpdparser_utctiming)2808 GST_START_TEST (dash_mpdparser_utctiming)
2809 {
2810   const gchar *xml =
2811       "<?xml version=\"1.0\"?>"
2812       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2813       " profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2814       "<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:http-xsdate:2014\" value=\"http://time.akamai.com/?iso http://example.time/xsdate\"/>"
2815       "<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:direct:2014\" value=\"2002-05-30T09:30:10Z \"/>"
2816       "<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:ntp:2014\" value=\"0.europe.pool.ntp.org 1.europe.pool.ntp.org 2.europe.pool.ntp.org 3.europe.pool.ntp.org\"/>"
2817       "</MPD>";
2818   gboolean ret;
2819   GstMPDClient *mpdclient = gst_mpd_client_new ();
2820   GstMPDUTCTimingType selected_method;
2821   gchar **urls;
2822 
2823   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2824 
2825   assert_equals_int (ret, TRUE);
2826   fail_if (mpdclient->mpd_root_node == NULL);
2827   fail_if (mpdclient->mpd_root_node->UTCTimings == NULL);
2828   assert_equals_int (g_list_length (mpdclient->mpd_root_node->UTCTimings), 3);
2829   urls =
2830       gst_mpd_client_get_utc_timing_sources (mpdclient,
2831       GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE, &selected_method);
2832   fail_if (urls == NULL);
2833   assert_equals_int (selected_method, GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE);
2834   assert_equals_int (g_strv_length (urls), 2);
2835   assert_equals_string (urls[0], "http://time.akamai.com/?iso");
2836   assert_equals_string (urls[1], "http://example.time/xsdate");
2837   urls =
2838       gst_mpd_client_get_utc_timing_sources (mpdclient,
2839       GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE | GST_MPD_UTCTIMING_TYPE_HTTP_ISO,
2840       &selected_method);
2841   fail_if (urls == NULL);
2842   assert_equals_int (selected_method, GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE);
2843   urls =
2844       gst_mpd_client_get_utc_timing_sources (mpdclient,
2845       GST_MPD_UTCTIMING_TYPE_DIRECT, NULL);
2846   fail_if (urls == NULL);
2847   assert_equals_int (g_strv_length (urls), 1);
2848   assert_equals_string (urls[0], "2002-05-30T09:30:10Z ");
2849   urls =
2850       gst_mpd_client_get_utc_timing_sources (mpdclient,
2851       GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE | GST_MPD_UTCTIMING_TYPE_DIRECT,
2852       &selected_method);
2853   fail_if (urls == NULL);
2854   assert_equals_int (selected_method, GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE);
2855   urls =
2856       gst_mpd_client_get_utc_timing_sources (mpdclient,
2857       GST_MPD_UTCTIMING_TYPE_NTP, &selected_method);
2858   fail_if (urls == NULL);
2859   assert_equals_int (selected_method, GST_MPD_UTCTIMING_TYPE_NTP);
2860   assert_equals_int (g_strv_length (urls), 4);
2861   assert_equals_string (urls[0], "0.europe.pool.ntp.org");
2862   assert_equals_string (urls[1], "1.europe.pool.ntp.org");
2863   assert_equals_string (urls[2], "2.europe.pool.ntp.org");
2864   assert_equals_string (urls[3], "3.europe.pool.ntp.org");
2865   gst_mpd_client_free (mpdclient);
2866 }
2867 
2868 GST_END_TEST;
2869 
2870 /*
2871  * Test parsing invalid UTCTiming values:
2872  * - elements with no schemeIdUri property should be rejected
2873  * - elements with no value property should be rejected
2874  * - elements with unrecognised UTCTiming scheme should be rejected
2875  * - elements with empty values should be rejected
2876  *
2877  */
GST_START_TEST(dash_mpdparser_utctiming_invalid_value)2878 GST_START_TEST (dash_mpdparser_utctiming_invalid_value)
2879 {
2880   const gchar *xml =
2881       "<?xml version=\"1.0\"?>"
2882       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2883       " profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
2884       "<UTCTiming invalid_schemeIdUri=\"dummy.uri.scheme\" value=\"dummy value\"/>"
2885       "<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:ntp:2014\" invalid_value=\"dummy value\"/>"
2886       "<UTCTiming schemeIdUri=\"dummy.uri.scheme\" value=\"dummy value\"/>"
2887       "<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:ntp:2014\" value=\"\"/>"
2888       "</MPD>";
2889   gboolean ret;
2890   GstMPDClient *mpdclient = gst_mpd_client_new ();
2891 
2892   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2893 
2894   assert_equals_int (ret, TRUE);
2895   fail_if (mpdclient->mpd_root_node == NULL);
2896   fail_if (mpdclient->mpd_root_node->UTCTimings != NULL);
2897   gst_mpd_client_free (mpdclient);
2898 }
2899 
2900 GST_END_TEST;
2901 
2902 /*
2903  * Test parsing the type property: value "dynamic"
2904  *
2905  */
GST_START_TEST(dash_mpdparser_type_dynamic)2906 GST_START_TEST (dash_mpdparser_type_dynamic)
2907 {
2908   gboolean isLive;
2909 
2910   const gchar *xml =
2911       "<?xml version=\"1.0\"?>"
2912       "<MPD type=\"dynamic\" xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
2913       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\"> </MPD>";
2914 
2915   gboolean ret;
2916   GstMPDClient *mpdclient = gst_mpd_client_new ();
2917 
2918   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
2919   assert_equals_int (ret, TRUE);
2920 
2921   isLive = gst_mpd_client_is_live (mpdclient);
2922   assert_equals_int (isLive, 1);
2923 
2924   gst_mpd_client_free (mpdclient);
2925 }
2926 
2927 GST_END_TEST;
2928 
2929 /*
2930  * Validate gst_mpdparser_build_URL_from_template function
2931  *
2932  */
GST_START_TEST(dash_mpdparser_template_parsing)2933 GST_START_TEST (dash_mpdparser_template_parsing)
2934 {
2935   const gchar *id = "TestId";
2936   guint number = 7;
2937   guint bandwidth = 2500;
2938   guint64 time = 100;
2939   gchar *result;
2940 
2941   struct TestUrl
2942   {
2943     const gchar *urlTemplate;
2944     const gchar *expectedResponse;
2945   };
2946 
2947   /* various test scenarios to attempt */
2948   struct TestUrl testUrl[] = {
2949     {"", NULL},                 /* empty string for template */
2950     {"$$", "$"},                /* escaped $ */
2951     {"Number", "Number"},       /* string similar with an identifier, but without $ */
2952     {"Number$Number$", "Number7"},      /* Number identifier */
2953     {"Number$Number$$$", "Number7$"},   /* Number identifier followed by $$ */
2954     {"Number$Number$Number$Number$", "Number7Number7"}, /* series of "Number" string and Number identifier */
2955     {"Representation$RepresentationID$", "RepresentationTestId"},       /* RepresentationID identifier */
2956     {"TestMedia$Bandwidth$$$test", "TestMedia2500$test"},       /* Bandwidth identifier */
2957     {"TestMedia$Time$", "TestMedia100"},        /* Time identifier */
2958     {"TestMedia$Time", NULL},   /* Identifier not finished with $ */
2959     {"Time$Time%d$", NULL},     /* usage of %d (no width) */
2960     {"Time$Time%0d$", "Time100"},       /* usage of format smaller than number of digits */
2961     {"Time$Time%01d$", "Time100"},      /* usage of format smaller than number of digits */
2962     {"Time$Time%05d$", "Time00100"},    /* usage of format bigger than number of digits */
2963     {"Time$Time%05dtest$", "Time00100test"},    /* usage extra text in format */
2964     {"Time$Time%3d$", NULL},    /* incorrect format: width does not start with 0 */
2965     {"Time$Time%0-4d$", NULL},  /* incorrect format: width is not a number */
2966     {"Time$Time%0$", NULL},     /* incorrect format: no d, x or u */
2967     {"Time$Time1%01d$", NULL},  /* incorrect format: does not start with % after identifier */
2968     {"$Bandwidth%/init.mp4v", NULL},    /* incorrect identifier: not finished with $ */
2969     {"$Number%/$Time$.mp4v", NULL},     /* incorrect number of $ separators */
2970     {"$RepresentationID1$", NULL},      /* incorrect identifier */
2971     {"$Bandwidth1$", NULL},     /* incorrect identifier */
2972     {"$Number1$", NULL},        /* incorrect identifier */
2973     {"$RepresentationID%01d$", NULL},   /* incorrect format: RepresentationID does not support formatting */
2974     {"Time$Time%05u$", NULL},   /* %u format */
2975     {"Time$Time%05x$", NULL},   /* %x format */
2976     {"Time$Time%05utest$", NULL},       /* %u format followed by text */
2977     {"Time$Time%05xtest$", NULL},       /* %x format followed by text */
2978     {"Time$Time%05xtest%$", NULL},      /* second % character in format */
2979   };
2980 
2981   guint count = sizeof (testUrl) / sizeof (testUrl[0]);
2982   gint i;
2983 
2984   for (i = 0; i < count; i++) {
2985     result =
2986         gst_mpdparser_build_URL_from_template (testUrl[i].urlTemplate, id,
2987         number, bandwidth, time);
2988     assert_equals_string (result, testUrl[i].expectedResponse);
2989     g_free (result);
2990   }
2991 }
2992 
2993 GST_END_TEST;
2994 
2995 /*
2996  * Test handling isoff ondemand profile
2997  *
2998  */
GST_START_TEST(dash_mpdparser_isoff_ondemand_profile)2999 GST_START_TEST (dash_mpdparser_isoff_ondemand_profile)
3000 {
3001   gboolean hasOnDemandProfile;
3002 
3003   const gchar *xml =
3004       "<?xml version=\"1.0\"?>"
3005       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3006       "     profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\"></MPD>";
3007 
3008   gboolean ret;
3009   GstMPDClient *mpdclient = gst_mpd_client_new ();
3010 
3011   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3012   assert_equals_int (ret, TRUE);
3013 
3014   hasOnDemandProfile = gst_mpd_client_has_isoff_ondemand_profile (mpdclient);
3015   assert_equals_int (hasOnDemandProfile, 1);
3016 
3017   gst_mpd_client_free (mpdclient);
3018 }
3019 
3020 GST_END_TEST;
3021 
3022 /*
3023  * Test handling GstDateTime
3024  *
3025  */
GST_START_TEST(dash_mpdparser_GstDateTime)3026 GST_START_TEST (dash_mpdparser_GstDateTime)
3027 {
3028   gint64 delta;
3029   GstDateTime *time1;
3030   GstDateTime *time2;
3031   GstDateTime *time3;
3032   GDateTime *g_time2;
3033   GDateTime *g_time3;
3034 
3035   time1 = gst_date_time_new_from_iso8601_string ("2012-06-23T23:30:59Z");
3036   time2 = gst_date_time_new_from_iso8601_string ("2012-06-23T23:31:00Z");
3037 
3038   delta = gst_mpd_client_calculate_time_difference (time1, time2);
3039   assert_equals_int64 (delta, 1 * GST_SECOND);
3040 
3041   time3 =
3042       gst_mpd_client_add_time_difference (time1, GST_TIME_AS_USECONDS (delta));
3043 
3044   /* convert to GDateTime in order to compare time2 and time 3 */
3045   g_time2 = gst_date_time_to_g_date_time (time2);
3046   g_time3 = gst_date_time_to_g_date_time (time3);
3047   fail_if (g_date_time_compare (g_time2, g_time3) != 0);
3048 
3049   gst_date_time_unref (time1);
3050   gst_date_time_unref (time2);
3051   gst_date_time_unref (time3);
3052   g_date_time_unref (g_time2);
3053   g_date_time_unref (g_time3);
3054 }
3055 
3056 GST_END_TEST;
3057 
3058 /*
3059  * Test bitstreamSwitching inheritance from Period to AdaptationSet
3060  *
3061  * Description of bistreamSwitching attribute in Period:
3062  * "When set to ‘true’, this is equivalent as if the
3063  * AdaptationSet@bitstreamSwitching for each Adaptation Set contained in this
3064  * Period is set to 'true'. In this case, the AdaptationSet@bitstreamSwitching
3065  * attribute shall not be set to 'false' for any Adaptation Set in this Period"
3066  *
3067  */
GST_START_TEST(dash_mpdparser_bitstreamSwitching_inheritance)3068 GST_START_TEST (dash_mpdparser_bitstreamSwitching_inheritance)
3069 {
3070   GList *adaptationSets;
3071   GstMPDAdaptationSetNode *adapt_set;
3072   guint activeStreams;
3073   GstActiveStream *activeStream;
3074   GstCaps *caps;
3075   GstStructure *s;
3076   gboolean bitstreamSwitchingFlag;
3077 
3078   const gchar *xml =
3079       "<?xml version=\"1.0\"?>"
3080       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3081       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3082       "  <Period id=\"Period0\""
3083       "          duration=\"P0Y0M1DT1H1M1S\""
3084       "          bitstreamSwitching=\"true\">"
3085       "    <AdaptationSet id=\"1\""
3086       "                   mimeType=\"video/mp4\">"
3087       "      <Representation id=\"1\" bandwidth=\"250000\">"
3088       "      </Representation>"
3089       "    </AdaptationSet>"
3090       "    <AdaptationSet id=\"2\""
3091       "                   mimeType=\"audio\""
3092       "                   bitstreamSwitching=\"false\">"
3093       "      <Representation id=\"2\" bandwidth=\"250000\">"
3094       "      </Representation></AdaptationSet></Period></MPD>";
3095 
3096   gboolean ret;
3097   GstMPDClient *mpdclient = gst_mpd_client_new ();
3098 
3099   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3100   assert_equals_int (ret, TRUE);
3101 
3102   /* process the xml data */
3103   ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3104       -1, NULL);
3105   assert_equals_int (ret, TRUE);
3106 
3107   /* get the list of adaptation sets of the first period */
3108   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
3109   fail_if (adaptationSets == NULL);
3110 
3111   /* setup streaming from the first adaptation set */
3112   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
3113   fail_if (adapt_set == NULL);
3114   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3115   assert_equals_int (ret, TRUE);
3116 
3117   /* setup streaming from the second adaptation set */
3118   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 1);
3119   fail_if (adapt_set == NULL);
3120   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3121   assert_equals_int (ret, TRUE);
3122 
3123   /* 2 active streams */
3124   activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
3125   assert_equals_int (activeStreams, 2);
3126 
3127   /* get details of the first active stream */
3128   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
3129   fail_if (activeStream == NULL);
3130 
3131   assert_equals_int (activeStream->mimeType, GST_STREAM_VIDEO);
3132   caps = gst_mpd_client_get_stream_caps (activeStream);
3133   fail_unless (caps != NULL);
3134   s = gst_caps_get_structure (caps, 0);
3135   assert_equals_string (gst_structure_get_name (s), "video/quicktime");
3136   gst_caps_unref (caps);
3137 
3138   /* inherited from Period's bitstreamSwitching */
3139   bitstreamSwitchingFlag =
3140       gst_mpd_client_get_bitstream_switching_flag (activeStream);
3141   assert_equals_int (bitstreamSwitchingFlag, TRUE);
3142 
3143   /* get details of the second active stream */
3144   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 1);
3145   fail_if (activeStream == NULL);
3146 
3147   assert_equals_int (activeStream->mimeType, GST_STREAM_AUDIO);
3148   caps = gst_mpd_client_get_stream_caps (activeStream);
3149   fail_unless (caps != NULL);
3150   s = gst_caps_get_structure (caps, 0);
3151   assert_equals_string (gst_structure_get_name (s), "audio");
3152   gst_caps_unref (caps);
3153 
3154   /* set to FALSE in our example, but overwritten to TRUE by Period's
3155    * bitstreamSwitching
3156    */
3157   bitstreamSwitchingFlag =
3158       gst_mpd_client_get_bitstream_switching_flag (activeStream);
3159   assert_equals_int (bitstreamSwitchingFlag, TRUE);
3160 
3161   gst_mpd_client_free (mpdclient);
3162 }
3163 
3164 GST_END_TEST;
3165 
3166 /*
3167  * Test various duration formats
3168  */
GST_START_TEST(dash_mpdparser_various_duration_formats)3169 GST_START_TEST (dash_mpdparser_various_duration_formats)
3170 {
3171   GstMPDPeriodNode *periodNode;
3172   const gchar *xml =
3173       "<?xml version=\"1.0\"?>"
3174       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3175       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
3176       "     availabilityStartTime=\"2015-03-24T0:0:0\""
3177       "     mediaPresentationDuration=\"P100Y\">"
3178       "  <Period id=\"Period0\" start=\"PT1S\"></Period>"
3179       "  <Period id=\"Period1\" start=\"PT1.5S\"></Period>"
3180       "  <Period id=\"Period2\" start=\"PT1,7S\"></Period>"
3181       "  <Period id=\"Period3\" start=\"PT1M\"></Period>"
3182       "  <Period id=\"Period4\" start=\"PT1H\"></Period>"
3183       "  <Period id=\"Period5\" start=\"P1D\"></Period>"
3184       "  <Period id=\"Period6\" start=\"P1M\"></Period>"
3185       "  <Period id=\"Period7\" start=\"P1Y\"></Period></MPD>";
3186 
3187   gboolean ret;
3188   GstMPDClient *mpdclient = gst_mpd_client_new ();
3189 
3190   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3191   assert_equals_int (ret, TRUE);
3192 
3193   ret =
3194       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3195       -1, NULL);
3196   assert_equals_int (ret, TRUE);
3197 
3198   periodNode =
3199       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3200       0);
3201   assert_equals_string (periodNode->id, "Period0");
3202   assert_equals_uint64 (periodNode->start,
3203       duration_to_ms (0, 0, 0, 0, 0, 1, 0));
3204 
3205   periodNode =
3206       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3207       1);
3208   assert_equals_string (periodNode->id, "Period1");
3209   assert_equals_uint64 (periodNode->start,
3210       duration_to_ms (0, 0, 0, 0, 0, 1, 500));
3211 
3212   periodNode =
3213       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3214       2);
3215   assert_equals_string (periodNode->id, "Period2");
3216   assert_equals_uint64 (periodNode->start,
3217       duration_to_ms (0, 0, 0, 0, 0, 1, 700));
3218 
3219   periodNode =
3220       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3221       3);
3222   assert_equals_string (periodNode->id, "Period3");
3223   assert_equals_uint64 (periodNode->start,
3224       duration_to_ms (0, 0, 0, 0, 1, 0, 0));
3225 
3226   periodNode =
3227       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3228       4);
3229   assert_equals_string (periodNode->id, "Period4");
3230   assert_equals_uint64 (periodNode->start,
3231       duration_to_ms (0, 0, 0, 1, 0, 0, 0));
3232 
3233   periodNode =
3234       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3235       5);
3236   assert_equals_string (periodNode->id, "Period5");
3237   assert_equals_uint64 (periodNode->start,
3238       duration_to_ms (0, 0, 1, 0, 0, 0, 0));
3239 
3240   periodNode =
3241       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3242       6);
3243   assert_equals_string (periodNode->id, "Period6");
3244   assert_equals_uint64 (periodNode->start,
3245       duration_to_ms (0, 1, 0, 0, 0, 0, 0));
3246 
3247   periodNode =
3248       (GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3249       7);
3250   assert_equals_string (periodNode->id, "Period7");
3251   assert_equals_uint64 (periodNode->start,
3252       duration_to_ms (1, 0, 0, 0, 0, 0, 0));
3253 
3254   gst_mpd_client_free (mpdclient);
3255 }
3256 
3257 GST_END_TEST;
3258 
3259 /*
3260  * Test media presentation setup
3261  *
3262  */
GST_START_TEST(dash_mpdparser_setup_media_presentation)3263 GST_START_TEST (dash_mpdparser_setup_media_presentation)
3264 {
3265   const gchar *xml =
3266       "<?xml version=\"1.0\"?>"
3267       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3268       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3269       "  <Period id=\"Period0\""
3270       "          duration=\"P0Y0M1DT1H1M1S\"></Period></MPD>";
3271 
3272   gboolean ret;
3273   GstMPDClient *mpdclient = gst_mpd_client_new ();
3274 
3275   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3276   assert_equals_int (ret, TRUE);
3277 
3278   /* process the xml data */
3279   ret =
3280       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3281       -1, NULL);
3282   assert_equals_int (ret, TRUE);
3283 
3284   gst_mpd_client_free (mpdclient);
3285 }
3286 
3287 GST_END_TEST;
3288 
3289 /*
3290  * Test setting a stream
3291  *
3292  */
GST_START_TEST(dash_mpdparser_setup_streaming)3293 GST_START_TEST (dash_mpdparser_setup_streaming)
3294 {
3295   GList *adaptationSets;
3296   GstMPDAdaptationSetNode *adapt_set;
3297 
3298   const gchar *xml =
3299       "<?xml version=\"1.0\"?>"
3300       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3301       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3302       "  <Period id=\"Period0\""
3303       "          duration=\"P0Y0M1DT1H1M1S\">"
3304       "    <AdaptationSet id=\"1\""
3305       "                   mimeType=\"video/mp4\">"
3306       "      <Representation id=\"1\" bandwidth=\"250000\">"
3307       "      </Representation></AdaptationSet></Period></MPD>";
3308 
3309   gboolean ret;
3310   GstMPDClient *mpdclient = gst_mpd_client_new ();
3311 
3312   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3313   assert_equals_int (ret, TRUE);
3314 
3315   /* process the xml data */
3316   ret =
3317       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3318       -1, NULL);
3319   assert_equals_int (ret, TRUE);
3320 
3321   /* get the first adaptation set of the first period */
3322   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
3323   fail_if (adaptationSets == NULL);
3324   adapt_set = (GstMPDAdaptationSetNode *) adaptationSets->data;
3325   fail_if (adapt_set == NULL);
3326 
3327   /* setup streaming from the adaptation set */
3328   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3329   assert_equals_int (ret, TRUE);
3330 
3331   gst_mpd_client_free (mpdclient);
3332 }
3333 
3334 GST_END_TEST;
3335 
3336 /*
3337  * Test handling Period selection
3338  *
3339  */
GST_START_TEST(dash_mpdparser_period_selection)3340 GST_START_TEST (dash_mpdparser_period_selection)
3341 {
3342   const gchar *periodName;
3343   guint periodIndex;
3344 
3345   const gchar *xml =
3346       "<?xml version=\"1.0\"?>"
3347       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3348       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
3349       "     mediaPresentationDuration=\"P0Y0M1DT1H4M3S\">"
3350       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\"></Period>"
3351       "  <Period id=\"Period1\"></Period>"
3352       "  <Period id=\"Period2\" start=\"P0Y0M1DT1H3M3S\"></Period></MPD>";
3353 
3354   gboolean ret;
3355   GstMPDClient *mpdclient = gst_mpd_client_new ();
3356 
3357   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3358   assert_equals_int (ret, TRUE);
3359 
3360   /* period_idx should be 0 and we should have no active periods */
3361   assert_equals_uint64 (mpdclient->period_idx, 0);
3362   fail_unless (mpdclient->periods == NULL);
3363 
3364   /* process the xml data */
3365   ret =
3366       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3367       -1, NULL);
3368   assert_equals_int (ret, TRUE);
3369 
3370   /* check the periods */
3371   fail_unless (mpdclient->periods != NULL);
3372   periodName = gst_mpd_client_get_period_id (mpdclient);
3373   assert_equals_string (periodName, "Period0");
3374 
3375   ret = gst_mpd_client_set_period_index (mpdclient, 1);
3376   assert_equals_int (ret, TRUE);
3377   periodName = gst_mpd_client_get_period_id (mpdclient);
3378   assert_equals_string (periodName, "Period1");
3379 
3380   ret = gst_mpd_client_set_period_index (mpdclient, 2);
3381   assert_equals_int (ret, TRUE);
3382   periodName = gst_mpd_client_get_period_id (mpdclient);
3383   assert_equals_string (periodName, "Period2");
3384 
3385   ret = gst_mpd_client_has_next_period (mpdclient);
3386   assert_equals_int (ret, FALSE);
3387   ret = gst_mpd_client_has_previous_period (mpdclient);
3388   assert_equals_int (ret, TRUE);
3389 
3390   ret = gst_mpd_client_set_period_index (mpdclient, 0);
3391   assert_equals_int (ret, TRUE);
3392   ret = gst_mpd_client_has_next_period (mpdclient);
3393   assert_equals_int (ret, TRUE);
3394   ret = gst_mpd_client_has_previous_period (mpdclient);
3395   assert_equals_int (ret, FALSE);
3396 
3397   ret = gst_mpd_client_set_period_id (mpdclient, "Period1");
3398   assert_equals_int (ret, TRUE);
3399   periodIndex = gst_mpd_client_get_period_index (mpdclient);
3400   assert_equals_uint64 (periodIndex, 1);
3401 
3402   gst_mpd_client_free (mpdclient);
3403 }
3404 
3405 GST_END_TEST;
3406 
3407 /*
3408  * Test handling Period selection based on time
3409  *
3410  */
GST_START_TEST(dash_mpdparser_get_period_at_time)3411 GST_START_TEST (dash_mpdparser_get_period_at_time)
3412 {
3413   guint periodIndex;
3414   GstDateTime *time;
3415 
3416   const gchar *xml =
3417       "<?xml version=\"1.0\"?>"
3418       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3419       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
3420       "     availabilityStartTime=\"2015-03-24T0:0:0\""
3421       "     mediaPresentationDuration=\"P0Y0M1DT1H4M3S\">"
3422       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\"></Period>"
3423       "  <Period id=\"Period1\"></Period>"
3424       "  <Period id=\"Period2\" start=\"P0Y0M1DT1H3M3S\"></Period></MPD>";
3425 
3426   gboolean ret;
3427   GstMPDClient *mpdclient = gst_mpd_client_new ();
3428 
3429   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3430   assert_equals_int (ret, TRUE);
3431 
3432   /* process the xml data */
3433   ret =
3434       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3435       -1, NULL);
3436   assert_equals_int (ret, TRUE);
3437 
3438   /* request period for a time before availabilityStartTime, expect period index 0 */
3439   time = gst_date_time_new_from_iso8601_string ("2015-03-23T23:30:59Z");
3440   periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
3441   gst_date_time_unref (time);
3442   assert_equals_int (periodIndex, 0);
3443 
3444   /* request period for a time from period 0 */
3445   time = gst_date_time_new_from_iso8601_string ("2015-03-24T23:30:59Z");
3446   periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
3447   gst_date_time_unref (time);
3448   assert_equals_int (periodIndex, 0);
3449 
3450   /* request period for a time from period 1 */
3451   time = gst_date_time_new_from_iso8601_string ("2015-03-25T1:1:1Z");
3452   periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
3453   gst_date_time_unref (time);
3454   assert_equals_int (periodIndex, 1);
3455 
3456   /* request period for a time from period 2 */
3457   time = gst_date_time_new_from_iso8601_string ("2015-03-25T1:3:3Z");
3458   periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
3459   gst_date_time_unref (time);
3460   assert_equals_int (periodIndex, 2);
3461 
3462   /* request period for a time after mediaPresentationDuration, expect period index G_MAXUINT */
3463   time = gst_date_time_new_from_iso8601_string ("2015-03-25T1:4:3Z");
3464   periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
3465   gst_date_time_unref (time);
3466   assert_equals_int (periodIndex, G_MAXUINT);
3467 
3468   gst_mpd_client_free (mpdclient);
3469 }
3470 
3471 GST_END_TEST;
3472 
3473 /*
3474  * Test handling Adaptation sets
3475  *
3476  */
GST_START_TEST(dash_mpdparser_adaptationSet_handling)3477 GST_START_TEST (dash_mpdparser_adaptationSet_handling)
3478 {
3479   const gchar *periodName;
3480   guint adaptation_sets_count;
3481   GList *adaptationSets, *it;
3482   guint count = 0;
3483 
3484   const gchar *xml =
3485       "<?xml version=\"1.0\"?>"
3486       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3487       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3488       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
3489       "    <AdaptationSet id=\"1\"></AdaptationSet>"
3490       "  </Period>"
3491       "  <Period id=\"Period1\" duration=\"P0Y0M1DT1H1M1S\">"
3492       "    <AdaptationSet id=\"10\"></AdaptationSet>"
3493       "    <AdaptationSet id=\"11\"></AdaptationSet></Period></MPD>";
3494 
3495   gboolean ret;
3496   GstMPDClient *mpdclient = gst_mpd_client_new ();
3497 
3498   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3499   assert_equals_int (ret, TRUE);
3500 
3501   /* process the xml data */
3502   ret =
3503       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3504       -1, NULL);
3505   assert_equals_int (ret, TRUE);
3506 
3507   /* period0 has 1 adaptation set */
3508   fail_unless (mpdclient->periods != NULL);
3509   periodName = gst_mpd_client_get_period_id (mpdclient);
3510   assert_equals_string (periodName, "Period0");
3511   adaptation_sets_count = gst_mpd_client_get_nb_adaptationSet (mpdclient);
3512   assert_equals_int (adaptation_sets_count, 1);
3513 
3514   /* period1 has 2 adaptation set */
3515   ret = gst_mpd_client_set_period_id (mpdclient, "Period1");
3516   assert_equals_int (ret, TRUE);
3517   adaptation_sets_count = gst_mpd_client_get_nb_adaptationSet (mpdclient);
3518   assert_equals_int (adaptation_sets_count, 2);
3519 
3520   /* check the id for the 2 adaptation sets from period 1 */
3521   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
3522   fail_if (adaptationSets == NULL);
3523 
3524   for (it = adaptationSets; it; it = g_list_next (it)) {
3525     GstMPDAdaptationSetNode *adapt_set;
3526     adapt_set = (GstMPDAdaptationSetNode *) it->data;
3527     fail_if (adapt_set == NULL);
3528 
3529     assert_equals_int (adapt_set->id, 10 + count);
3530     count++;
3531   }
3532 
3533   gst_mpd_client_free (mpdclient);
3534 }
3535 
3536 GST_END_TEST;
3537 
3538 /*
3539  * Test handling Representation selection
3540  *
3541  */
GST_START_TEST(dash_mpdparser_representation_selection)3542 GST_START_TEST (dash_mpdparser_representation_selection)
3543 {
3544   GList *adaptationSets;
3545   GstMPDAdaptationSetNode *adaptationSetNode;
3546   GList *representations;
3547   gint represendationIndex;
3548 
3549   const gchar *xml =
3550       "<?xml version=\"1.0\"?>"
3551       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3552       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3553       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
3554       "    <AdaptationSet id=\"1\" mimeType=\"video/mp4\">"
3555       "      <Representation id=\"v0\" bandwidth=\"500000\"></Representation>"
3556       "      <Representation id=\"v1\" bandwidth=\"250000\"></Representation>"
3557       "    </AdaptationSet></Period></MPD>";
3558 
3559   gboolean ret;
3560   GstMPDClient *mpdclient = gst_mpd_client_new ();
3561 
3562   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3563   assert_equals_int (ret, TRUE);
3564 
3565   /* process the xml data */
3566   ret =
3567       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3568       -1, NULL);
3569   assert_equals_int (ret, TRUE);
3570 
3571   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
3572   fail_if (adaptationSets == NULL);
3573 
3574   adaptationSetNode = adaptationSets->data;
3575   fail_if (adaptationSetNode == NULL);
3576   assert_equals_int (adaptationSetNode->id, 1);
3577 
3578   representations = adaptationSetNode->Representations;
3579   fail_if (representations == NULL);
3580 
3581   represendationIndex =
3582       gst_mpd_client_get_rep_idx_with_min_bandwidth (representations);
3583   assert_equals_int (represendationIndex, 1);
3584 
3585   represendationIndex =
3586       gst_mpd_client_get_rep_idx_with_max_bandwidth (representations, 0, 0, 0,
3587       0, 1);
3588   assert_equals_int (represendationIndex, 1);
3589 
3590   represendationIndex =
3591       gst_mpd_client_get_rep_idx_with_max_bandwidth (representations, 100000, 0,
3592       0, 0, 1);
3593   assert_equals_int (represendationIndex, -1);
3594 
3595   represendationIndex =
3596       gst_mpd_client_get_rep_idx_with_max_bandwidth (representations, 300000, 0,
3597       0, 0, 1);
3598   assert_equals_int (represendationIndex, 1);
3599 
3600   represendationIndex =
3601       gst_mpd_client_get_rep_idx_with_max_bandwidth (representations, 500000, 0,
3602       0, 0, 1);
3603   assert_equals_int (represendationIndex, 0);
3604 
3605   gst_mpd_client_free (mpdclient);
3606 }
3607 
3608 GST_END_TEST;
3609 
3610 /*
3611  * Test handling Active stream selection
3612  *
3613  */
GST_START_TEST(dash_mpdparser_activeStream_selection)3614 GST_START_TEST (dash_mpdparser_activeStream_selection)
3615 {
3616   GList *adaptationSets;
3617   GstMPDAdaptationSetNode *adapt_set;
3618   guint activeStreams;
3619   GstActiveStream *activeStream;
3620 
3621   const gchar *xml =
3622       "<?xml version=\"1.0\"?>"
3623       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3624       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3625       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
3626       "    <AdaptationSet id=\"1\" mimeType=\"video/mp4\">"
3627       "      <Representation id=\"1\" bandwidth=\"250000\">"
3628       "      </Representation>"
3629       "    </AdaptationSet>"
3630       "    <AdaptationSet id=\"2\" mimeType=\"audio\">"
3631       "      <Representation id=\"2\" bandwidth=\"250000\">"
3632       "      </Representation>"
3633       "    </AdaptationSet>"
3634       "    <AdaptationSet id=\"3\" mimeType=\"application\">"
3635       "      <Representation id=\"3\" bandwidth=\"250000\">"
3636       "      </Representation></AdaptationSet></Period></MPD>";
3637 
3638   gboolean ret;
3639   GstMPDClient *mpdclient = gst_mpd_client_new ();
3640 
3641   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3642   assert_equals_int (ret, TRUE);
3643 
3644   /* process the xml data */
3645   ret =
3646       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3647       -1, NULL);
3648   assert_equals_int (ret, TRUE);
3649 
3650   /* get the list of adaptation sets of the first period */
3651   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
3652   fail_if (adaptationSets == NULL);
3653 
3654   /* no active streams yet */
3655   activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
3656   assert_equals_int (activeStreams, 0);
3657 
3658   /* setup streaming from the first adaptation set */
3659   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
3660   fail_if (adapt_set == NULL);
3661   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3662   assert_equals_int (ret, TRUE);
3663 
3664   /* 1 active streams */
3665   activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
3666   assert_equals_int (activeStreams, 1);
3667 
3668   /* setup streaming from the second adaptation set */
3669   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 1);
3670   fail_if (adapt_set == NULL);
3671   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3672   assert_equals_int (ret, TRUE);
3673 
3674   /* 2 active streams */
3675   activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
3676   assert_equals_int (activeStreams, 2);
3677 
3678   /* setup streaming from the third adaptation set */
3679   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 2);
3680   fail_if (adapt_set == NULL);
3681   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3682   assert_equals_int (ret, TRUE);
3683 
3684   /* 3 active streams */
3685   activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
3686   assert_equals_int (activeStreams, 3);
3687 
3688   /* get details of the first active stream */
3689   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
3690   fail_if (activeStream == NULL);
3691   assert_equals_int (activeStream->mimeType, GST_STREAM_VIDEO);
3692 
3693   /* get details of the second active stream */
3694   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 1);
3695   fail_if (activeStream == NULL);
3696   assert_equals_int (activeStream->mimeType, GST_STREAM_AUDIO);
3697 
3698   /* get details of the third active stream */
3699   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 2);
3700   fail_if (activeStream == NULL);
3701   assert_equals_int (activeStream->mimeType, GST_STREAM_APPLICATION);
3702 
3703   gst_mpd_client_free (mpdclient);
3704 }
3705 
3706 GST_END_TEST;
3707 
3708 /*
3709  * Test getting Active stream parameters
3710  *
3711  */
GST_START_TEST(dash_mpdparser_activeStream_parameters)3712 GST_START_TEST (dash_mpdparser_activeStream_parameters)
3713 {
3714   GList *adaptationSets;
3715   GstMPDAdaptationSetNode *adapt_set;
3716   guint activeStreams;
3717   GstActiveStream *activeStream;
3718   GstCaps *caps;
3719   GstStructure *s;
3720   gboolean bitstreamSwitchingFlag;
3721   guint videoStreamWidth;
3722   guint videoStreamHeight;
3723   guint audioStreamRate;
3724   guint audioChannelsCount;
3725 
3726   const gchar *xml =
3727       "<?xml version=\"1.0\"?>"
3728       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3729       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3730       "  <Period id=\"Period0\""
3731       "          duration=\"P0Y0M1DT1H1M1S\">"
3732       "    <AdaptationSet id=\"1\""
3733       "                   mimeType=\"video/mp4\""
3734       "                   width=\"320\""
3735       "                   height=\"240\""
3736       "                   bitstreamSwitching=\"true\""
3737       "                   audioSamplingRate=\"48000\">"
3738       "      <Representation id=\"1\" bandwidth=\"250000\">"
3739       "      </Representation></AdaptationSet></Period></MPD>";
3740 
3741   gboolean ret;
3742   GstMPDClient *mpdclient = gst_mpd_client_new ();
3743 
3744   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3745   assert_equals_int (ret, TRUE);
3746 
3747   /* process the xml data */
3748   ret =
3749       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3750       -1, NULL);
3751   assert_equals_int (ret, TRUE);
3752 
3753   /* get the list of adaptation sets of the first period */
3754   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
3755   fail_if (adaptationSets == NULL);
3756 
3757   /* setup streaming from the first adaptation set */
3758   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
3759   fail_if (adapt_set == NULL);
3760   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3761   assert_equals_int (ret, TRUE);
3762 
3763   /* 1 active streams */
3764   activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
3765   assert_equals_int (activeStreams, 1);
3766 
3767   /* get details of the first active stream */
3768   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
3769   fail_if (activeStream == NULL);
3770 
3771   assert_equals_int (activeStream->mimeType, GST_STREAM_VIDEO);
3772   caps = gst_mpd_client_get_stream_caps (activeStream);
3773   fail_unless (caps != NULL);
3774   s = gst_caps_get_structure (caps, 0);
3775   assert_equals_string (gst_structure_get_name (s), "video/quicktime");
3776   gst_caps_unref (caps);
3777 
3778   bitstreamSwitchingFlag =
3779       gst_mpd_client_get_bitstream_switching_flag (activeStream);
3780   assert_equals_int (bitstreamSwitchingFlag, 1);
3781 
3782   videoStreamWidth = gst_mpd_client_get_video_stream_width (activeStream);
3783   assert_equals_int (videoStreamWidth, 320);
3784 
3785   videoStreamHeight = gst_mpd_client_get_video_stream_height (activeStream);
3786   assert_equals_int (videoStreamHeight, 240);
3787 
3788   audioStreamRate = gst_mpd_client_get_audio_stream_rate (activeStream);
3789   assert_equals_int (audioStreamRate, 48000);
3790 
3791   audioChannelsCount =
3792       gst_mpd_client_get_audio_stream_num_channels (activeStream);
3793   assert_equals_int (audioChannelsCount, 0);
3794 
3795   gst_mpd_client_free (mpdclient);
3796 }
3797 
3798 GST_END_TEST;
3799 
3800 /*
3801  * Test getting number and list of audio languages
3802  *
3803  */
GST_START_TEST(dash_mpdparser_get_audio_languages)3804 GST_START_TEST (dash_mpdparser_get_audio_languages)
3805 {
3806   GList *adaptationSets;
3807   GstMPDAdaptationSetNode *adapt_set;
3808   guint activeStreams;
3809   guint adaptationSetsCount;
3810   GList *languages = NULL;
3811   guint languagesCount;
3812 
3813   const gchar *xml =
3814       "<?xml version=\"1.0\"?>"
3815       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3816       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3817       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
3818       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
3819       "      <Representation id=\"1\" bandwidth=\"250000\">"
3820       "      </Representation>"
3821       "    </AdaptationSet>"
3822       "    <AdaptationSet id=\"2\" mimeType=\"video/mp4\">"
3823       "      <Representation id=\"2\" bandwidth=\"250000\">"
3824       "      </Representation>"
3825       "    </AdaptationSet>"
3826       "    <AdaptationSet id=\"3\" mimeType=\"audio\" lang=\"fr\">"
3827       "      <Representation id=\"3\" bandwidth=\"250000\">"
3828       "      </Representation></AdaptationSet></Period></MPD>";
3829 
3830   gboolean ret;
3831   GstMPDClient *mpdclient = gst_mpd_client_new ();
3832   gint i;
3833 
3834   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3835   assert_equals_int (ret, TRUE);
3836 
3837   /* process the xml data */
3838   ret =
3839       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3840       -1, NULL);
3841   assert_equals_int (ret, TRUE);
3842 
3843   /* get the list of adaptation sets of the first period */
3844   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
3845   fail_if (adaptationSets == NULL);
3846 
3847   /* setup streaming from all adaptation sets */
3848   adaptationSetsCount = gst_mpd_client_get_nb_adaptationSet (mpdclient);
3849   for (i = 0; i < adaptationSetsCount; i++) {
3850     adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, i);
3851     fail_if (adapt_set == NULL);
3852     ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3853     assert_equals_int (ret, TRUE);
3854   }
3855   activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
3856   assert_equals_int (activeStreams, adaptationSetsCount);
3857 
3858   languagesCount =
3859       gst_mpd_client_get_list_and_nb_of_audio_language (mpdclient, &languages);
3860   assert_equals_int (languagesCount, 2);
3861   assert_equals_string ((gchar *) g_list_nth_data (languages, 0), "en");
3862   assert_equals_string ((gchar *) g_list_nth_data (languages, 1), "fr");
3863 
3864   g_list_free (languages);
3865 
3866   gst_mpd_client_free (mpdclient);
3867 }
3868 
3869 GST_END_TEST;
3870 
3871 /*
3872  * Tests getting the base URL
3873  *
3874  */
3875 static GstMPDClient *
setup_mpd_client(const gchar * xml)3876 setup_mpd_client (const gchar * xml)
3877 {
3878   GList *adaptationSets;
3879   GstMPDAdaptationSetNode *adapt_set;
3880   guint activeStreams;
3881   guint adaptationSetsCount;
3882   gboolean ret;
3883   GstMPDClient *mpdclient = gst_mpd_client_new ();
3884   gint i;
3885 
3886   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
3887   assert_equals_int (ret, TRUE);
3888 
3889   /* process the xml data */
3890   ret =
3891       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
3892       -1, NULL);
3893   assert_equals_int (ret, TRUE);
3894 
3895   /* get the list of adaptation sets of the first period */
3896   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
3897   fail_if (adaptationSets == NULL);
3898 
3899   /* setup streaming from all adaptation sets */
3900   adaptationSetsCount = gst_mpd_client_get_nb_adaptationSet (mpdclient);
3901   for (i = 0; i < adaptationSetsCount; i++) {
3902     adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, i);
3903     fail_if (adapt_set == NULL);
3904     ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
3905     assert_equals_int (ret, TRUE);
3906   }
3907   activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
3908   assert_equals_int (activeStreams, adaptationSetsCount);
3909 
3910   return mpdclient;
3911 }
3912 
GST_START_TEST(dash_mpdparser_get_baseURL1)3913 GST_START_TEST (dash_mpdparser_get_baseURL1)
3914 {
3915   const gchar *baseURL;
3916   const gchar *xml =
3917       "<?xml version=\"1.0\"?>"
3918       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3919       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3920       "  <BaseURL>http://example.com/</BaseURL>"
3921       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
3922       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
3923       "      <Representation id=\"1\" bandwidth=\"250000\">"
3924       "      </Representation></AdaptationSet></Period></MPD>";
3925 
3926   GstMPDClient *mpdclient = setup_mpd_client (xml);
3927 
3928   baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
3929   fail_if (baseURL == NULL);
3930   assert_equals_string (baseURL, "http://example.com/");
3931 
3932   gst_mpd_client_free (mpdclient);
3933 }
3934 
3935 GST_END_TEST;
3936 
3937 
GST_START_TEST(dash_mpdparser_get_baseURL2)3938 GST_START_TEST (dash_mpdparser_get_baseURL2)
3939 {
3940   const gchar *baseURL;
3941   const gchar *xml =
3942       "<?xml version=\"1.0\"?>"
3943       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3944       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3945       "  <BaseURL>mpd_base_url/</BaseURL>"
3946       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
3947       "    <BaseURL> /period_base_url/</BaseURL>"
3948       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
3949       "      <BaseURL>adaptation_base_url</BaseURL>"
3950       "      <Representation id=\"1\" bandwidth=\"250000\">"
3951       "        <BaseURL>representation_base_url</BaseURL>"
3952       "      </Representation></AdaptationSet></Period></MPD>";
3953 
3954   GstMPDClient *mpdclient = setup_mpd_client (xml);
3955 
3956   /* test baseURL. Its value should be computed like this:
3957    *  - start with xml url (null)
3958    *  - set it to the value from MPD's BaseURL element: "mpd_base_url/"
3959    *  - update the value with BaseURL element from Period. Because Period's
3960    * baseURL is absolute (starts with /) it will overwrite the current value
3961    * for baseURL. So, baseURL becomes "/period_base_url/"
3962    *  - update the value with BaseURL element from AdaptationSet. Because this
3963    * is a relative url, it will update the current value. baseURL becomes
3964    * "/period_base_url/adaptation_base_url"
3965    *  - update the value with BaseURL element from Representation. Because this
3966    * is a relative url, it will update the current value. Because the current
3967    * value does not end in /, everything after the last / will be overwritten.
3968    * baseURL becomes "/period_base_url/representation_base_url"
3969    */
3970   baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
3971   fail_if (baseURL == NULL);
3972   assert_equals_string (baseURL, "/period_base_url/representation_base_url");
3973 
3974   gst_mpd_client_free (mpdclient);
3975 }
3976 
3977 GST_END_TEST;
3978 
3979 
GST_START_TEST(dash_mpdparser_get_baseURL3)3980 GST_START_TEST (dash_mpdparser_get_baseURL3)
3981 {
3982   const gchar *baseURL;
3983   const gchar *xml =
3984       "<?xml version=\"1.0\"?>"
3985       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
3986       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
3987       "  <BaseURL>mpd_base_url/</BaseURL>"
3988       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
3989       "    <BaseURL> /period_base_url/</BaseURL>"
3990       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
3991       "      <BaseURL>adaptation_base_url</BaseURL>"
3992       "      <Representation id=\"1\" bandwidth=\"250000\">"
3993       "        <BaseURL>/representation_base_url</BaseURL>"
3994       "      </Representation></AdaptationSet></Period></MPD>";
3995 
3996   GstMPDClient *mpdclient = setup_mpd_client (xml);
3997 
3998   /* test baseURL. Its value should be computed like this:
3999    *  - start with xml url (null)
4000    *  - set it to the value from MPD's BaseURL element: "mpd_base_url/"
4001    *  - update the value with BaseURL element from Period. Because Period's
4002    * baseURL is absolute (starts with /) it will overwrite the current value
4003    * for baseURL. So, baseURL becomes "/period_base_url/"
4004    *  - update the value with BaseURL element from AdaptationSet. Because this
4005    * is a relative url, it will update the current value. baseURL becomes
4006    * "/period_base_url/adaptation_base_url"
4007    *  - update the value with BaseURL element from Representation. Because this
4008    * is an absolute url, it will replace everything again"
4009    */
4010   baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
4011   fail_if (baseURL == NULL);
4012   assert_equals_string (baseURL, "/representation_base_url");
4013 
4014   gst_mpd_client_free (mpdclient);
4015 }
4016 
4017 GST_END_TEST;
4018 
4019 
GST_START_TEST(dash_mpdparser_get_baseURL4)4020 GST_START_TEST (dash_mpdparser_get_baseURL4)
4021 {
4022   const gchar *baseURL;
4023   const gchar *xml =
4024       "<?xml version=\"1.0\"?>"
4025       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4026       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
4027       "  <BaseURL>mpd_base_url/</BaseURL>"
4028       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
4029       "    <BaseURL> /period_base_url/</BaseURL>"
4030       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
4031       "      <BaseURL>adaptation_base_url/</BaseURL>"
4032       "      <Representation id=\"1\" bandwidth=\"250000\">"
4033       "        <BaseURL>representation_base_url/</BaseURL>"
4034       "      </Representation></AdaptationSet></Period></MPD>";
4035 
4036   GstMPDClient *mpdclient = setup_mpd_client (xml);
4037 
4038   /* test baseURL. Its value should be computed like this:
4039    *  - start with xml url (null)
4040    *  - set it to the value from MPD's BaseURL element: "mpd_base_url/"
4041    *  - update the value with BaseURL element from Period. Because Period's
4042    * baseURL is absolute (starts with /) it will overwrite the current value
4043    * for baseURL. So, baseURL becomes "/period_base_url/"
4044    *  - update the value with BaseURL element from AdaptationSet. Because this
4045    * is a relative url, it will update the current value. baseURL becomes
4046    * "/period_base_url/adaptation_base_url/"
4047    *  - update the value with BaseURL element from Representation. Because this
4048    * is an relative url, it will update the current value."
4049    */
4050   baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
4051   fail_if (baseURL == NULL);
4052   assert_equals_string (baseURL,
4053       "/period_base_url/adaptation_base_url/representation_base_url/");
4054 
4055   gst_mpd_client_free (mpdclient);
4056 }
4057 
4058 GST_END_TEST;
4059 
4060 /* test multiple BaseUrl entries per section */
GST_START_TEST(dash_mpdparser_get_baseURL5)4061 GST_START_TEST (dash_mpdparser_get_baseURL5)
4062 {
4063   GstMPDPeriodNode *periodNode;
4064   GstMPDAdaptationSetNode *adaptationSet;
4065   GstMPDRepresentationNode *representation;
4066   const gchar *baseURL;
4067   GstMPDBaseURLNode *gstBaseURL;
4068 
4069   const gchar *xml =
4070       "<?xml version=\"1.0\"?>"
4071       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4072       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
4073       "  <BaseURL>/mpd_base_url1/</BaseURL>"
4074       "  <BaseURL>/mpd_base_url2/</BaseURL>"
4075       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
4076       "    <BaseURL> period_base_url1/</BaseURL>"
4077       "    <BaseURL> period_base_url2/</BaseURL>"
4078       "    <BaseURL> period_base_url3/</BaseURL>"
4079       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
4080       "      <BaseURL>adaptation_base_url1/</BaseURL>"
4081       "      <BaseURL>adaptation_base_url2/</BaseURL>"
4082       "      <BaseURL>adaptation_base_url3/</BaseURL>"
4083       "      <BaseURL>adaptation_base_url4/</BaseURL>"
4084       "      <Representation id=\"1\" bandwidth=\"250000\">"
4085       "        <BaseURL>representation_base_url1/</BaseURL>"
4086       "        <BaseURL>representation_base_url2/</BaseURL>"
4087       "        <BaseURL>representation_base_url3/</BaseURL>"
4088       "        <BaseURL>representation_base_url4/</BaseURL>"
4089       "        <BaseURL>representation_base_url5/</BaseURL>"
4090       "      </Representation></AdaptationSet></Period></MPD>";
4091 
4092   GstMPDClient *mpdclient = setup_mpd_client (xml);
4093 
4094   assert_equals_int (g_list_length (mpdclient->mpd_root_node->BaseURLs), 2);
4095   gstBaseURL = g_list_nth_data (mpdclient->mpd_root_node->BaseURLs, 0);
4096   assert_equals_string (gstBaseURL->baseURL, "/mpd_base_url1/");
4097   gstBaseURL = g_list_nth_data (mpdclient->mpd_root_node->BaseURLs, 1);
4098   assert_equals_string (gstBaseURL->baseURL, "/mpd_base_url2/");
4099 
4100   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
4101   assert_equals_int (g_list_length (periodNode->BaseURLs), 3);
4102   gstBaseURL = g_list_nth_data (periodNode->BaseURLs, 0);
4103   assert_equals_string (gstBaseURL->baseURL, " period_base_url1/");
4104   gstBaseURL = g_list_nth_data (periodNode->BaseURLs, 1);
4105   assert_equals_string (gstBaseURL->baseURL, " period_base_url2/");
4106   gstBaseURL = g_list_nth_data (periodNode->BaseURLs, 2);
4107   assert_equals_string (gstBaseURL->baseURL, " period_base_url3/");
4108 
4109   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
4110   assert_equals_int (g_list_length (adaptationSet->BaseURLs), 4);
4111   gstBaseURL = g_list_nth_data (adaptationSet->BaseURLs, 0);
4112   assert_equals_string (gstBaseURL->baseURL, "adaptation_base_url1/");
4113   gstBaseURL = g_list_nth_data (adaptationSet->BaseURLs, 1);
4114   assert_equals_string (gstBaseURL->baseURL, "adaptation_base_url2/");
4115   gstBaseURL = g_list_nth_data (adaptationSet->BaseURLs, 2);
4116   assert_equals_string (gstBaseURL->baseURL, "adaptation_base_url3/");
4117   gstBaseURL = g_list_nth_data (adaptationSet->BaseURLs, 3);
4118   assert_equals_string (gstBaseURL->baseURL, "adaptation_base_url4/");
4119 
4120   representation = (GstMPDRepresentationNode *)
4121       adaptationSet->Representations->data;
4122   assert_equals_int (g_list_length (representation->BaseURLs), 5);
4123   gstBaseURL = g_list_nth_data (representation->BaseURLs, 0);
4124   assert_equals_string (gstBaseURL->baseURL, "representation_base_url1/");
4125   gstBaseURL = g_list_nth_data (representation->BaseURLs, 1);
4126   assert_equals_string (gstBaseURL->baseURL, "representation_base_url2/");
4127   gstBaseURL = g_list_nth_data (representation->BaseURLs, 2);
4128   assert_equals_string (gstBaseURL->baseURL, "representation_base_url3/");
4129   gstBaseURL = g_list_nth_data (representation->BaseURLs, 3);
4130   assert_equals_string (gstBaseURL->baseURL, "representation_base_url4/");
4131   gstBaseURL = g_list_nth_data (representation->BaseURLs, 4);
4132   assert_equals_string (gstBaseURL->baseURL, "representation_base_url5/");
4133 
4134   /* test baseURL. Its value should be computed like this:
4135    *  - start with xml url (null)
4136    *  - set it to the value from MPD's BaseURL element: "/mpd_base_url1/"
4137    *  - update the value with BaseURL element from Period. Because this
4138    * is a relative url, it will update the current value. baseURL becomes
4139    * "/mpd_base_url1/period_base_url1/"
4140    *  - update the value with BaseURL element from AdaptationSet. Because this
4141    * is a relative url, it will update the current value. baseURL becomes
4142    * "/mpd_base_url1/period_base_url1/adaptation_base_url1/"
4143    *  - update the value with BaseURL element from Representation. Because this
4144    * is an relative url, it will update the current value."
4145    */
4146   baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
4147   fail_if (baseURL == NULL);
4148   assert_equals_string (baseURL,
4149       "/mpd_base_url1/period_base_url1/adaptation_base_url1/representation_base_url1/");
4150 
4151   gst_mpd_client_free (mpdclient);
4152 }
4153 
4154 GST_END_TEST;
4155 
4156 /* test no BaseURL */
GST_START_TEST(dash_mpdparser_get_baseURL6)4157 GST_START_TEST (dash_mpdparser_get_baseURL6)
4158 {
4159   const gchar *baseURL;
4160   const gchar *xml =
4161       "<?xml version=\"1.0\"?>"
4162       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4163       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
4164       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
4165       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
4166       "      <Representation id=\"1\" bandwidth=\"250000\">"
4167       "      </Representation></AdaptationSet></Period></MPD>";
4168 
4169   GstMPDClient *mpdclient = setup_mpd_client (xml);
4170 
4171   baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
4172   fail_if (baseURL == NULL);
4173   assert_equals_string (baseURL, "");
4174 
4175   gst_mpd_client_free (mpdclient);
4176 }
4177 
4178 GST_END_TEST;
4179 
4180 /* BaseURL: test that the path is made absolute (a / is prepended if needed */
GST_START_TEST(dash_mpdparser_get_baseURL7)4181 GST_START_TEST (dash_mpdparser_get_baseURL7)
4182 {
4183   const gchar *baseURL;
4184   const gchar *xml =
4185       "<?xml version=\"1.0\"?>"
4186       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4187       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
4188       "  <BaseURL>x/example.com/</BaseURL>"
4189       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
4190       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
4191       "      <Representation id=\"1\" bandwidth=\"250000\">"
4192       "      </Representation></AdaptationSet></Period></MPD>";
4193 
4194   GstMPDClient *mpdclient;
4195 
4196   mpdclient = setup_mpd_client (xml);
4197 
4198   baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
4199   fail_if (baseURL == NULL);
4200   assert_equals_string (baseURL, "/x/example.com/");
4201 
4202   gst_mpd_client_free (mpdclient);
4203 }
4204 
4205 GST_END_TEST;
4206 
4207 /* BaseURL: test that a / is not prepended if the string contains ':'
4208  * This tests uris with schema present */
GST_START_TEST(dash_mpdparser_get_baseURL8)4209 GST_START_TEST (dash_mpdparser_get_baseURL8)
4210 {
4211   const gchar *baseURL;
4212   const gchar *xml =
4213       "<?xml version=\"1.0\"?>"
4214       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4215       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
4216       "  <BaseURL>x:y/example.com/</BaseURL>"
4217       "  <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
4218       "    <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
4219       "      <Representation id=\"1\" bandwidth=\"250000\">"
4220       "      </Representation></AdaptationSet></Period></MPD>";
4221 
4222   GstMPDClient *mpdclient = setup_mpd_client (xml);
4223 
4224   baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
4225   fail_if (baseURL == NULL);
4226   assert_equals_string (baseURL, "x:y/example.com/");
4227 
4228   gst_mpd_client_free (mpdclient);
4229 }
4230 
4231 GST_END_TEST;
4232 
4233 /*
4234  * Test getting mediaPresentationDuration
4235  *
4236  */
GST_START_TEST(dash_mpdparser_get_mediaPresentationDuration)4237 GST_START_TEST (dash_mpdparser_get_mediaPresentationDuration)
4238 {
4239   GstClockTime mediaPresentationDuration;
4240 
4241   const gchar *xml =
4242       "<?xml version=\"1.0\"?>"
4243       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4244       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4245       "     mediaPresentationDuration=\"P0Y0M0DT0H0M3S\"></MPD>";
4246 
4247   gboolean ret;
4248   GstMPDClient *mpdclient = gst_mpd_client_new ();
4249 
4250   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4251   assert_equals_int (ret, TRUE);
4252 
4253   mediaPresentationDuration =
4254       gst_mpd_client_get_media_presentation_duration (mpdclient);
4255   assert_equals_uint64 (mediaPresentationDuration, 3000000000);
4256 
4257   gst_mpd_client_free (mpdclient);
4258 }
4259 
4260 GST_END_TEST;
4261 
4262 /*
4263  * Test getting streamPresentationOffset
4264  *
4265  */
GST_START_TEST(dash_mpdparser_get_streamPresentationOffset)4266 GST_START_TEST (dash_mpdparser_get_streamPresentationOffset)
4267 {
4268   GList *adaptationSets;
4269   GstMPDAdaptationSetNode *adapt_set;
4270   GstClockTime offset;
4271   const gchar *xml =
4272       "<?xml version=\"1.0\"?>"
4273       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4274       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4275       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
4276       "  <Period>"
4277       "    <AdaptationSet mimeType=\"video/mp4\">"
4278       "      <SegmentBase timescale=\"1000\" presentationTimeOffset=\"3000\">"
4279       "      </SegmentBase>"
4280       "      <Representation id=\"1\" bandwidth=\"250000\">"
4281       "      </Representation></AdaptationSet></Period></MPD>";
4282 
4283   gboolean ret;
4284   GstMPDClient *mpdclient = gst_mpd_client_new ();
4285 
4286   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4287   assert_equals_int (ret, TRUE);
4288 
4289   /* process the xml data */
4290   ret =
4291       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
4292       -1, NULL);
4293   assert_equals_int (ret, TRUE);
4294 
4295   /* get the list of adaptation sets of the first period */
4296   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
4297   fail_if (adaptationSets == NULL);
4298 
4299   /* setup streaming from the first adaptation set */
4300   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
4301   fail_if (adapt_set == NULL);
4302   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
4303   assert_equals_int (ret, TRUE);
4304 
4305   /* test the stream presentation time offset */
4306   offset = gst_mpd_client_get_stream_presentation_offset (mpdclient, 0);
4307   /* seems to be set only for template segments, so here it is 0 */
4308   assert_equals_int (offset, 0);
4309 
4310   gst_mpd_client_free (mpdclient);
4311 }
4312 
4313 GST_END_TEST;
4314 
4315 /*
4316  * Test handling segments
4317  *
4318  */
GST_START_TEST(dash_mpdparser_segments)4319 GST_START_TEST (dash_mpdparser_segments)
4320 {
4321   GList *adaptationSets;
4322   GstMPDAdaptationSetNode *adapt_set;
4323   gboolean hasNextSegment;
4324   GstActiveStream *activeStream;
4325   GstFlowReturn flow;
4326   GstDateTime *segmentAvailability;
4327   GstDateTime *gst_time;
4328   GDateTime *g_time;
4329 
4330   const gchar *xml =
4331       "<?xml version=\"1.0\"?>"
4332       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4333       "     type=\"dynamic\""
4334       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4335       "     availabilityStartTime=\"2015-03-24T0:0:0\""
4336       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
4337       "  <Period id=\"Period0\" start=\"P0Y0M0DT0H0M10S\">"
4338       "    <AdaptationSet mimeType=\"video/mp4\">"
4339       "      <Representation id=\"1\" bandwidth=\"250000\">"
4340       "        <SegmentList duration=\"45\">"
4341       "          <SegmentURL media=\"TestMedia1\""
4342       "                      mediaRange=\"10-20\""
4343       "                      index=\"TestIndex1\""
4344       "                      indexRange=\"30-40\">"
4345       "          </SegmentURL>"
4346       "          <SegmentURL media=\"TestMedia2\""
4347       "                      mediaRange=\"20-30\""
4348       "                      index=\"TestIndex2\""
4349       "                      indexRange=\"40-50\">"
4350       "          </SegmentURL>"
4351       "        </SegmentList>"
4352       "      </Representation></AdaptationSet></Period></MPD>";
4353 
4354   gboolean ret;
4355   GstMPDClient *mpdclient = gst_mpd_client_new ();
4356 
4357   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4358   assert_equals_int (ret, TRUE);
4359 
4360   /* process the xml data */
4361   ret =
4362       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
4363       -1, NULL);
4364   assert_equals_int (ret, TRUE);
4365 
4366   /* get the list of adaptation sets of the first period */
4367   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
4368   fail_if (adaptationSets == NULL);
4369 
4370   /* setup streaming from the first adaptation set */
4371   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
4372   fail_if (adapt_set == NULL);
4373   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
4374   assert_equals_int (ret, TRUE);
4375 
4376   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
4377   fail_if (activeStream == NULL);
4378 
4379   /* segment_index 0, segment_count 2.
4380    * Has next segment and can advance to next segment
4381    */
4382   hasNextSegment =
4383       gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
4384   assert_equals_int (hasNextSegment, 1);
4385   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
4386   assert_equals_int (flow, GST_FLOW_OK);
4387 
4388   /* segment_index 1, segment_count 2.
4389    * Does not have next segment and can not advance to next segment
4390    */
4391   hasNextSegment =
4392       gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
4393   assert_equals_int (hasNextSegment, 0);
4394   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
4395   assert_equals_int (flow, GST_FLOW_EOS);
4396 
4397   /* go to first segment */
4398   gst_mpd_client_seek_to_first_segment (mpdclient);
4399 
4400   /* segment_index 0, segment_count 2.
4401    * Has next segment and can advance to next segment
4402    */
4403   hasNextSegment =
4404       gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
4405   assert_equals_int (hasNextSegment, 1);
4406   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
4407   assert_equals_int (flow, GST_FLOW_OK);
4408 
4409   /* segment_index 1, segment_count 2
4410    * Does not have next segment
4411    */
4412   hasNextSegment =
4413       gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
4414   assert_equals_int (hasNextSegment, 0);
4415 
4416   /* segment index is still 1 */
4417   hasNextSegment =
4418       gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
4419   assert_equals_int (hasNextSegment, 0);
4420 
4421   /* each segment has a duration of 0 hours, 0 min 45 seconds
4422    * segment index is 1.
4423    * Start time is at the beginning of segment 1, so 1 * segment_duration = 1 * 45s
4424    * Availability start time is at the end of the segment, so we add duration (45s)
4425    * We also add period start time (10s)
4426    * So, availability start time for segment 1 is: 10 (period start) +
4427    * 45 (segment start) + 45 (duration) = 1'40s
4428    */
4429   segmentAvailability =
4430       gst_mpd_client_get_next_segment_availability_start_time (mpdclient,
4431       activeStream);
4432   assert_equals_int (gst_date_time_get_year (segmentAvailability), 2015);
4433   assert_equals_int (gst_date_time_get_month (segmentAvailability), 3);
4434   assert_equals_int (gst_date_time_get_day (segmentAvailability), 24);
4435   assert_equals_int (gst_date_time_get_hour (segmentAvailability), 0);
4436   assert_equals_int (gst_date_time_get_minute (segmentAvailability), 1);
4437   assert_equals_int (gst_date_time_get_second (segmentAvailability), 40);
4438   gst_date_time_unref (segmentAvailability);
4439 
4440   /* seek to time */
4441   gst_time = gst_date_time_new_from_iso8601_string ("2015-03-24T0:0:20Z");
4442   g_time = gst_date_time_to_g_date_time (gst_time);
4443   ret = gst_mpd_client_seek_to_time (mpdclient, g_time);
4444   assert_equals_int (ret, 1);
4445   gst_date_time_unref (gst_time);
4446   g_date_time_unref (g_time);
4447 
4448   /* segment index is now 0 */
4449   hasNextSegment =
4450       gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
4451   assert_equals_int (hasNextSegment, 1);
4452 
4453   gst_mpd_client_free (mpdclient);
4454 }
4455 
4456 GST_END_TEST;
4457 
4458 /*
4459  * Test handling headers
4460  *
4461  */
GST_START_TEST(dash_mpdparser_headers)4462 GST_START_TEST (dash_mpdparser_headers)
4463 {
4464   GList *adaptationSets;
4465   GstMPDAdaptationSetNode *adapt_set;
4466   gchar *uri;
4467   gint64 range_start;
4468   gint64 range_end;
4469 
4470   const gchar *xml =
4471       "<?xml version=\"1.0\"?>"
4472       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4473       "     type=\"dynamic\""
4474       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4475       "     availabilityStartTime=\"2015-03-24T0:0:0\""
4476       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
4477       "  <Period id=\"Period0\">"
4478       "    <AdaptationSet mimeType=\"video/mp4\">"
4479       "      <Representation id=\"1\" bandwidth=\"250000\">"
4480       "        <SegmentBase indexRange=\"10-20\">"
4481       "          <Initialization sourceURL=\"TestSourceUrl\""
4482       "                          range=\"100-200\">"
4483       "          </Initialization>"
4484       "          <RepresentationIndex sourceURL=\"TestSourceIndex\">"
4485       "          </RepresentationIndex>"
4486       "        </SegmentBase>"
4487       "      </Representation></AdaptationSet></Period></MPD>";
4488 
4489   gboolean ret;
4490   GstMPDClient *mpdclient = gst_mpd_client_new ();
4491 
4492   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4493   assert_equals_int (ret, TRUE);
4494 
4495   /* process the xml data */
4496   ret =
4497       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
4498       -1, NULL);
4499   assert_equals_int (ret, TRUE);
4500 
4501   /* get the list of adaptation sets of the first period */
4502   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
4503   fail_if (adaptationSets == NULL);
4504 
4505   /* setup streaming from the first adaptation set */
4506   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
4507   fail_if (adapt_set == NULL);
4508   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
4509   assert_equals_int (ret, TRUE);
4510 
4511   /* get segment url and range from segment Initialization */
4512   ret =
4513       gst_mpd_client_get_next_header (mpdclient, &uri, 0, &range_start,
4514       &range_end);
4515   assert_equals_int (ret, TRUE);
4516   assert_equals_string (uri, "TestSourceUrl");
4517   assert_equals_int64 (range_start, 100);
4518   assert_equals_int64 (range_end, 200);
4519   g_free (uri);
4520 
4521   /* get segment url and range from segment indexRange */
4522   ret =
4523       gst_mpd_client_get_next_header_index (mpdclient, &uri, 0, &range_start,
4524       &range_end);
4525   assert_equals_int (ret, TRUE);
4526   assert_equals_string (uri, "TestSourceIndex");
4527   assert_equals_int64 (range_start, 10);
4528   assert_equals_int64 (range_end, 20);
4529   g_free (uri);
4530 
4531   gst_mpd_client_free (mpdclient);
4532 }
4533 
4534 GST_END_TEST;
4535 
4536 /*
4537  * Test handling fragments
4538  *
4539  */
GST_START_TEST(dash_mpdparser_fragments)4540 GST_START_TEST (dash_mpdparser_fragments)
4541 {
4542   GList *adaptationSets;
4543   GstMPDAdaptationSetNode *adapt_set;
4544   GstMediaFragmentInfo fragment;
4545   GstActiveStream *activeStream;
4546   GstClockTime nextFragmentDuration;
4547   GstClockTime nextFragmentTimestamp;
4548   GstClockTime nextFragmentTimestampEnd;
4549   GstClockTime periodStartTime;
4550   GstClockTime expectedDuration;
4551   GstClockTime expectedTimestamp;
4552   GstClockTime expectedTimestampEnd;
4553 
4554   const gchar *xml =
4555       "<?xml version=\"1.0\"?>"
4556       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4557       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4558       "     availabilityStartTime=\"2015-03-24T0:0:0\""
4559       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
4560       "  <Period id=\"Period0\" start=\"P0Y0M0DT0H0M10S\">"
4561       "    <AdaptationSet mimeType=\"video/mp4\">"
4562       "      <Representation id=\"1\" bandwidth=\"250000\">"
4563       "      </Representation></AdaptationSet></Period></MPD>";
4564 
4565   gboolean ret;
4566   GstMPDClient *mpdclient = gst_mpd_client_new ();
4567 
4568   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4569   assert_equals_int (ret, TRUE);
4570 
4571   /* process the xml data */
4572   ret =
4573       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
4574       -1, NULL);
4575   assert_equals_int (ret, TRUE);
4576 
4577   /* get the list of adaptation sets of the first period */
4578   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
4579   fail_if (adaptationSets == NULL);
4580 
4581   /* setup streaming from the first adaptation set */
4582   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
4583   fail_if (adapt_set == NULL);
4584   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
4585   assert_equals_int (ret, TRUE);
4586   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
4587   fail_if (activeStream == NULL);
4588 
4589   /* expected duration of the next fragment */
4590   expectedDuration = duration_to_ms (0, 0, 0, 3, 3, 20, 0);
4591   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 0, 0);
4592   expectedTimestampEnd = duration_to_ms (0, 0, 0, 3, 3, 20, 0);
4593 
4594   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
4595   assert_equals_int (ret, TRUE);
4596   assert_equals_string (fragment.uri, "");
4597   assert_equals_int64 (fragment.range_start, 0);
4598   assert_equals_int64 (fragment.range_end, -1);
4599   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
4600   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
4601   gst_mpdparser_media_fragment_info_clear (&fragment);
4602 
4603   periodStartTime = gst_mpd_client_get_period_start_time (mpdclient);
4604   assert_equals_uint64 (periodStartTime, 10 * GST_SECOND);
4605 
4606   nextFragmentDuration =
4607       gst_mpd_client_get_next_fragment_duration (mpdclient, activeStream);
4608   assert_equals_uint64 (nextFragmentDuration, expectedDuration * GST_MSECOND);
4609 
4610   ret =
4611       gst_mpd_client_get_next_fragment_timestamp (mpdclient, 0,
4612       &nextFragmentTimestamp);
4613   assert_equals_int (ret, TRUE);
4614   assert_equals_uint64 (nextFragmentTimestamp, expectedTimestamp * GST_MSECOND);
4615 
4616   ret =
4617       gst_mpd_client_get_last_fragment_timestamp_end (mpdclient, 0,
4618       &nextFragmentTimestampEnd);
4619   assert_equals_int (ret, TRUE);
4620   assert_equals_uint64 (nextFragmentTimestampEnd,
4621       expectedTimestampEnd * GST_MSECOND);
4622 
4623   gst_mpd_client_free (mpdclient);
4624 }
4625 
4626 GST_END_TEST;
4627 
4628 /*
4629  * Test inheriting segmentBase from parent
4630  *
4631  */
GST_START_TEST(dash_mpdparser_inherited_segmentBase)4632 GST_START_TEST (dash_mpdparser_inherited_segmentBase)
4633 {
4634   GstMPDPeriodNode *periodNode;
4635   GstMPDSegmentBaseNode *segmentBase;
4636   GstMPDAdaptationSetNode *adaptationSet;
4637   GstMPDRepresentationNode *representation;
4638   const gchar *xml =
4639       "<?xml version=\"1.0\"?>"
4640       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4641       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
4642       "  <Period>"
4643       "    <AdaptationSet>"
4644       "      <SegmentBase timescale=\"100\">"
4645       "      </SegmentBase>"
4646       "      <Representation id=\"1\" bandwidth=\"250000\">"
4647       "        <SegmentBase timescale=\"200\">"
4648       "        </SegmentBase>"
4649       "      </Representation></AdaptationSet></Period></MPD>";
4650 
4651   gboolean ret;
4652   GstMPDClient *mpdclient = gst_mpd_client_new ();
4653 
4654   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4655   assert_equals_int (ret, TRUE);
4656 
4657   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
4658   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
4659   representation = (GstMPDRepresentationNode *)
4660       adaptationSet->Representations->data;
4661 
4662   /* test segment base from adaptation set */
4663   segmentBase = adaptationSet->SegmentBase;
4664   assert_equals_uint64 (segmentBase->timescale, 100);
4665 
4666   /* test segment base from representation */
4667   segmentBase = representation->SegmentBase;
4668   assert_equals_uint64 (segmentBase->timescale, 200);
4669 
4670   gst_mpd_client_free (mpdclient);
4671 }
4672 
4673 GST_END_TEST;
4674 
4675 /*
4676  * Test inheriting segmentURL from parent
4677  *
4678  */
GST_START_TEST(dash_mpdparser_inherited_segmentURL)4679 GST_START_TEST (dash_mpdparser_inherited_segmentURL)
4680 {
4681   GList *adaptationSets;
4682   GstMPDAdaptationSetNode *adapt_set;
4683   GstActiveStream *activeStream;
4684   GstMediaFragmentInfo fragment;
4685   GstClockTime expectedDuration;
4686   GstClockTime expectedTimestamp;
4687   GstFlowReturn flow;
4688 
4689   const gchar *xml =
4690       "<?xml version=\"1.0\"?>"
4691       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4692       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4693       "     availabilityStartTime=\"2015-03-24T0:0:0\""
4694       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
4695       "  <Period>"
4696       "    <AdaptationSet mimeType=\"video/mp4\">"
4697       "      <SegmentList duration=\"100\">"
4698       "        <SegmentURL media=\"TestMediaAdaptation\""
4699       "                    mediaRange=\"10-20\""
4700       "                    index=\"TestIndexAdaptation\""
4701       "                    indexRange=\"30-40\">"
4702       "        </SegmentURL>"
4703       "      </SegmentList>"
4704       "      <Representation id=\"1\" bandwidth=\"250000\">"
4705       "        <SegmentList duration=\"110\">"
4706       "          <SegmentURL media=\"TestMediaRep\""
4707       "                      mediaRange=\"100-200\""
4708       "                      index=\"TestIndexRep\""
4709       "                      indexRange=\"300-400\">"
4710       "          </SegmentURL>"
4711       "        </SegmentList>"
4712       "      </Representation></AdaptationSet></Period></MPD>";
4713 
4714   gboolean ret;
4715   GstMPDClient *mpdclient = gst_mpd_client_new ();
4716 
4717   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4718   assert_equals_int (ret, TRUE);
4719 
4720   /* process the xml data */
4721   ret =
4722       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
4723       -1, NULL);
4724   assert_equals_int (ret, TRUE);
4725 
4726   /* get the list of adaptation sets of the first period */
4727   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
4728   fail_if (adaptationSets == NULL);
4729 
4730   /* setup streaming from the first adaptation set */
4731   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
4732   fail_if (adapt_set == NULL);
4733   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
4734   assert_equals_int (ret, TRUE);
4735 
4736   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
4737   fail_if (activeStream == NULL);
4738 
4739   /* expected duration of the next fragment
4740    * Segment duration was set to 100 in AdaptationSet and to 110 in Representation
4741    * We expect duration to be 110
4742    */
4743   expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 110, 0);
4744   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 0, 0);
4745 
4746   /* the representation contains 1 segment (the one from Representation) */
4747 
4748   /* check first segment */
4749   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
4750   assert_equals_int (ret, TRUE);
4751   assert_equals_string (fragment.uri, "/TestMediaRep");
4752   assert_equals_int64 (fragment.range_start, 100);
4753   assert_equals_int64 (fragment.range_end, 200);
4754   assert_equals_string (fragment.index_uri, "/TestIndexRep");
4755   assert_equals_int64 (fragment.index_range_start, 300);
4756   assert_equals_int64 (fragment.index_range_end, 400);
4757   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
4758   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
4759   gst_mpdparser_media_fragment_info_clear (&fragment);
4760 
4761   /* try to advance to next segment. Should fail */
4762   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
4763   assert_equals_int (flow, GST_FLOW_EOS);
4764 
4765   gst_mpd_client_free (mpdclient);
4766 }
4767 
4768 GST_END_TEST;
4769 
4770 /*
4771  * Test segment list
4772  *
4773  */
GST_START_TEST(dash_mpdparser_segment_list)4774 GST_START_TEST (dash_mpdparser_segment_list)
4775 {
4776   GList *adaptationSets;
4777   GstMPDAdaptationSetNode *adapt_set;
4778   GstActiveStream *activeStream;
4779   GstMediaFragmentInfo fragment;
4780   GstClockTime expectedDuration;
4781   GstClockTime expectedTimestamp;
4782   const gchar *xml =
4783       "<?xml version=\"1.0\"?>"
4784       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4785       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4786       "     availabilityStartTime=\"2015-03-24T0:0:0\""
4787       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
4788       "  <Period start=\"P0Y0M0DT0H0M10S\">"
4789       "    <AdaptationSet mimeType=\"video/mp4\">"
4790       "      <Representation id=\"1\" bandwidth=\"250000\">"
4791       "        <SegmentList duration=\"12000\">"
4792       "          <SegmentURL media=\"TestMedia\""
4793       "                      mediaRange=\"100-200\""
4794       "                      index=\"TestIndex\""
4795       "                      indexRange=\"300-400\">"
4796       "          </SegmentURL>"
4797       "        </SegmentList>"
4798       "      </Representation></AdaptationSet></Period></MPD>";
4799 
4800   gboolean ret;
4801   GstMPDClient *mpdclient = gst_mpd_client_new ();
4802 
4803   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4804   assert_equals_int (ret, TRUE);
4805 
4806   /* process the xml data */
4807   ret =
4808       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
4809       -1, NULL);
4810   assert_equals_int (ret, TRUE);
4811 
4812   /* get the list of adaptation sets of the first period */
4813   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
4814   fail_if (adaptationSets == NULL);
4815 
4816   /* setup streaming from the first adaptation set */
4817   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
4818   fail_if (adapt_set == NULL);
4819   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
4820   assert_equals_int (ret, TRUE);
4821 
4822   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
4823   fail_if (activeStream == NULL);
4824 
4825   /* expected duration of the next fragment
4826    * Segment duration was set larger than period duration (12000 vs 11000).
4827    * We expect it to be limited to period duration.
4828    */
4829   expectedDuration = duration_to_ms (0, 0, 0, 3, 3, 20, 0);
4830   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 10, 0);
4831 
4832   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
4833   assert_equals_int (ret, TRUE);
4834   assert_equals_string (fragment.uri, "/TestMedia");
4835   assert_equals_int64 (fragment.range_start, 100);
4836   assert_equals_int64 (fragment.range_end, 200);
4837   assert_equals_string (fragment.index_uri, "/TestIndex");
4838   assert_equals_int64 (fragment.index_range_start, 300);
4839   assert_equals_int64 (fragment.index_range_end, 400);
4840   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
4841   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
4842 
4843   gst_mpdparser_media_fragment_info_clear (&fragment);
4844 
4845   gst_mpd_client_free (mpdclient);
4846 }
4847 
4848 GST_END_TEST;
4849 
4850 /*
4851  * Test segment template
4852  *
4853  */
GST_START_TEST(dash_mpdparser_segment_template)4854 GST_START_TEST (dash_mpdparser_segment_template)
4855 {
4856   GList *adaptationSets;
4857   GstMPDAdaptationSetNode *adapt_set;
4858   GstActiveStream *activeStream;
4859   GstMediaFragmentInfo fragment;
4860   GstClockTime expectedDuration;
4861   GstClockTime expectedTimestamp;
4862   GstClockTime periodStartTime;
4863   GstClockTime offset;
4864   GstClockTime lastFragmentTimestampEnd;
4865   const gchar *xml =
4866       "<?xml version=\"1.0\"?>"
4867       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4868       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4869       "     availabilityStartTime=\"2015-03-24T0:0:0\""
4870       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
4871       "  <Period start=\"P0Y0M0DT0H0M10S\">"
4872       "    <AdaptationSet mimeType=\"video/mp4\">"
4873       "      <Representation id=\"repId\" bandwidth=\"250000\">"
4874       "        <SegmentTemplate duration=\"12000\""
4875       "                         presentationTimeOffset=\"15\""
4876       "                         media=\"TestMedia_rep=$RepresentationID$number=$Number$bandwidth=$Bandwidth$time=$Time$\""
4877       "                         index=\"TestIndex\">"
4878       "        </SegmentTemplate>"
4879       "      </Representation></AdaptationSet></Period></MPD>";
4880 
4881   gboolean ret;
4882   GstMPDClient *mpdclient = gst_mpd_client_new ();
4883 
4884   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
4885   assert_equals_int (ret, TRUE);
4886 
4887   /* process the xml data */
4888   ret =
4889       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
4890       -1, NULL);
4891   assert_equals_int (ret, TRUE);
4892 
4893   /* get the list of adaptation sets of the first period */
4894   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
4895   fail_if (adaptationSets == NULL);
4896 
4897   /* setup streaming from the first adaptation set */
4898   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
4899   fail_if (adapt_set == NULL);
4900   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
4901   assert_equals_int (ret, TRUE);
4902 
4903   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
4904   fail_if (activeStream == NULL);
4905 
4906   /* expected duration of the next fragment
4907    * Segment duration was set larger than period duration (12000 vs 11000).
4908    * We expect it to not be limited to period duration.
4909    */
4910   expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 12000, 0);
4911 
4912   /* while the period starts at 10ms, the fragment timestamp is supposed to be
4913    * 0ms. timestamps are starting from 0 at every period, and only the overall
4914    * composition of periods should consider the period start timestamp. In
4915    * dashdemux this is done by mapping the 0 fragment timestamp to a stream
4916    * time equal to the period start time.
4917    */
4918   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 0, 0);
4919 
4920   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
4921   assert_equals_int (ret, TRUE);
4922   assert_equals_string (fragment.uri,
4923       "/TestMedia_rep=repIdnumber=1bandwidth=250000time=0");
4924   assert_equals_int64 (fragment.range_start, 0);
4925   assert_equals_int64 (fragment.range_end, -1);
4926   assert_equals_string (fragment.index_uri, "/TestIndex");
4927   assert_equals_int64 (fragment.index_range_start, 0);
4928   assert_equals_int64 (fragment.index_range_end, -1);
4929   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
4930   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
4931 
4932   periodStartTime = gst_mpd_client_get_period_start_time (mpdclient);
4933   assert_equals_uint64 (periodStartTime, 10 * GST_SECOND);
4934 
4935   offset = gst_mpd_client_get_stream_presentation_offset (mpdclient, 0);
4936   assert_equals_uint64 (offset, 15 * GST_SECOND);
4937 
4938   gst_mpdparser_media_fragment_info_clear (&fragment);
4939 
4940   /*
4941    * Period starts at 10s.
4942    * MPD has a duration of 3h3m30s, so period duration is 3h3m20s.
4943    * We expect the last fragment to end at period start + period duration: 3h3m30s
4944    */
4945   expectedTimestamp = duration_to_ms (0, 0, 0, 3, 3, 30, 0);
4946   gst_mpd_client_get_last_fragment_timestamp_end (mpdclient, 0,
4947       &lastFragmentTimestampEnd);
4948   assert_equals_uint64 (lastFragmentTimestampEnd,
4949       expectedTimestamp * GST_MSECOND);
4950 
4951   gst_mpd_client_free (mpdclient);
4952 }
4953 
4954 GST_END_TEST;
4955 
4956 /*
4957  * Test segment timeline
4958  *
4959  */
GST_START_TEST(dash_mpdparser_segment_timeline)4960 GST_START_TEST (dash_mpdparser_segment_timeline)
4961 {
4962   GList *adaptationSets;
4963   GstMPDAdaptationSetNode *adapt_set;
4964   GstActiveStream *activeStream;
4965   GstMediaFragmentInfo fragment;
4966   GstClockTime expectedDuration;
4967   GstClockTime expectedTimestamp;
4968   GstFlowReturn flow;
4969   GstDateTime *segmentAvailability;
4970 
4971   const gchar *xml =
4972       "<?xml version=\"1.0\"?>"
4973       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
4974       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
4975       "     availabilityStartTime=\"2015-03-24T0:0:0\""
4976       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
4977       "  <Period start=\"P0Y0M0DT0H0M10S\">"
4978       "    <AdaptationSet mimeType=\"video/mp4\">"
4979       "      <SegmentList>"
4980       "        <SegmentTimeline>"
4981       "          <S t=\"10\"  d=\"20\" r=\"30\"></S>"
4982       "        </SegmentTimeline>"
4983       "      </SegmentList>"
4984       "      <Representation id=\"1\" bandwidth=\"250000\">"
4985       "        <SegmentList>"
4986       "          <SegmentTimeline>"
4987       "            <S t=\"3\"  d=\"2\" r=\"1\"></S>"
4988       "            <S t=\"10\" d=\"3\" r=\"0\"></S>"
4989       "          </SegmentTimeline>"
4990       "          <SegmentURL media=\"TestMedia0\""
4991       "                      index=\"TestIndex0\">"
4992       "          </SegmentURL>"
4993       "          <SegmentURL media=\"TestMedia1\""
4994       "                      index=\"TestIndex1\">"
4995       "          </SegmentURL>"
4996       "        </SegmentList>"
4997       "      </Representation></AdaptationSet></Period></MPD>";
4998 
4999   gboolean ret;
5000   GstMPDClient *mpdclient = gst_mpd_client_new ();
5001 
5002   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5003   assert_equals_int (ret, TRUE);
5004 
5005   /* process the xml data */
5006   ret =
5007       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5008       -1, NULL);
5009   assert_equals_int (ret, TRUE);
5010 
5011   /* get the list of adaptation sets of the first period */
5012   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
5013   fail_if (adaptationSets == NULL);
5014 
5015   /* setup streaming from the first adaptation set */
5016   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
5017   fail_if (adapt_set == NULL);
5018   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
5019   assert_equals_int (ret, TRUE);
5020 
5021   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
5022   fail_if (activeStream == NULL);
5023 
5024   /* expected duration of the next fragment */
5025   expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 2, 0);
5026   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 13, 0);
5027 
5028   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
5029   assert_equals_int (ret, TRUE);
5030   assert_equals_string (fragment.uri, "/TestMedia0");
5031   assert_equals_string (fragment.index_uri, "/TestIndex0");
5032   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
5033   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
5034   gst_mpdparser_media_fragment_info_clear (&fragment);
5035 
5036   /* first segment starts at 3s and has a duration of 2s.
5037    * We also add period start time (10s) so we expect a segment availability
5038    * start time of 15s
5039    */
5040   segmentAvailability =
5041       gst_mpd_client_get_next_segment_availability_start_time (mpdclient,
5042       activeStream);
5043   fail_unless (segmentAvailability != NULL);
5044   assert_equals_int (gst_date_time_get_year (segmentAvailability), 2015);
5045   assert_equals_int (gst_date_time_get_month (segmentAvailability), 3);
5046   assert_equals_int (gst_date_time_get_day (segmentAvailability), 24);
5047   assert_equals_int (gst_date_time_get_hour (segmentAvailability), 0);
5048   assert_equals_int (gst_date_time_get_minute (segmentAvailability), 0);
5049   assert_equals_int (gst_date_time_get_second (segmentAvailability), 15);
5050   gst_date_time_unref (segmentAvailability);
5051 
5052   /* advance to next segment */
5053   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
5054   assert_equals_int (flow, GST_FLOW_OK);
5055 
5056   /* second segment starts after first ends */
5057   expectedTimestamp = expectedTimestamp + expectedDuration;
5058 
5059   /* check second segment.
5060    * It is a repeat of first segmentURL, because "r" in SegmentTimeline is 1
5061    */
5062   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
5063   assert_equals_int (ret, TRUE);
5064   assert_equals_string (fragment.uri, "/TestMedia0");
5065   assert_equals_string (fragment.index_uri, "/TestIndex0");
5066   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
5067   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
5068   gst_mpdparser_media_fragment_info_clear (&fragment);
5069 
5070   /* first segment starts at 3s and has a duration of 2s.
5071    * Second segment starts when the first ends (5s) and has a duration of 2s,
5072    * so it ends at 7s.
5073    * We also add period start time (10s) so we expect a segment availability
5074    * start time of 17s
5075    */
5076   segmentAvailability =
5077       gst_mpd_client_get_next_segment_availability_start_time (mpdclient,
5078       activeStream);
5079   fail_unless (segmentAvailability != NULL);
5080   assert_equals_int (gst_date_time_get_year (segmentAvailability), 2015);
5081   assert_equals_int (gst_date_time_get_month (segmentAvailability), 3);
5082   assert_equals_int (gst_date_time_get_day (segmentAvailability), 24);
5083   assert_equals_int (gst_date_time_get_hour (segmentAvailability), 0);
5084   assert_equals_int (gst_date_time_get_minute (segmentAvailability), 0);
5085   assert_equals_int (gst_date_time_get_second (segmentAvailability), 17);
5086   gst_date_time_unref (segmentAvailability);
5087 
5088   /* advance to next segment */
5089   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
5090   assert_equals_int (flow, GST_FLOW_OK);
5091 
5092   /* third segment has a small gap after the second ends  (t=10) */
5093   expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 3, 0);
5094   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 20, 0);
5095 
5096   /* check third segment */
5097   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
5098   assert_equals_int (ret, TRUE);
5099   assert_equals_string (fragment.uri, "/TestMedia1");
5100   assert_equals_string (fragment.index_uri, "/TestIndex1");
5101   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
5102   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
5103   gst_mpdparser_media_fragment_info_clear (&fragment);
5104 
5105   /* Third segment starts at 10s and has a duration of 3s so it ends at 13s.
5106    * We also add period start time (10s) so we expect a segment availability
5107    * start time of 23s
5108    */
5109   segmentAvailability =
5110       gst_mpd_client_get_next_segment_availability_start_time (mpdclient,
5111       activeStream);
5112   fail_unless (segmentAvailability != NULL);
5113   assert_equals_int (gst_date_time_get_year (segmentAvailability), 2015);
5114   assert_equals_int (gst_date_time_get_month (segmentAvailability), 3);
5115   assert_equals_int (gst_date_time_get_day (segmentAvailability), 24);
5116   assert_equals_int (gst_date_time_get_hour (segmentAvailability), 0);
5117   assert_equals_int (gst_date_time_get_minute (segmentAvailability), 0);
5118   assert_equals_int (gst_date_time_get_second (segmentAvailability), 23);
5119   gst_date_time_unref (segmentAvailability);
5120 
5121   gst_mpd_client_free (mpdclient);
5122 }
5123 
5124 GST_END_TEST;
5125 
5126 /*
5127  * Test SegmentList with multiple inherited segmentURLs
5128  *
5129  */
GST_START_TEST(dash_mpdparser_multiple_inherited_segmentURL)5130 GST_START_TEST (dash_mpdparser_multiple_inherited_segmentURL)
5131 {
5132   GList *adaptationSets;
5133   GstMPDAdaptationSetNode *adapt_set;
5134   GstActiveStream *activeStream;
5135   GstMediaFragmentInfo fragment;
5136   GstClockTime expectedDuration;
5137   GstClockTime expectedTimestamp;
5138   GstFlowReturn flow;
5139 
5140   /*
5141    * Period duration is 30 seconds
5142    * Period start is 10 seconds. Thus, period duration is 20 seconds.
5143    *
5144    * There are 2 segments in the AdaptationSet segment list and 2 in the
5145    * Representation's segment list.
5146    * Segment duration is 5s for the Adaptation segments and 8s for
5147    * Representation segments.
5148    * Separately, each segment list (duration 2*5=10 or 2*8=16) fits comfortably
5149    * in the Period's 20s duration.
5150    *
5151    * We expect the Representation segments to overwrite the AdaptationSet segments.
5152    */
5153   const gchar *xml =
5154       "<?xml version=\"1.0\"?>"
5155       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5156       " profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5157       " availabilityStartTime=\"2015-03-24T0:0:0\""
5158       " mediaPresentationDuration=\"P0Y0M0DT0H0M30S\">"
5159       "<Period>"
5160       "  <AdaptationSet mimeType=\"video/mp4\">"
5161       "    <SegmentList duration=\"5\">"
5162       "      <SegmentURL"
5163       "         media=\"TestMedia0\" mediaRange=\"10-20\""
5164       "         index=\"TestIndex0\" indexRange=\"100-200\""
5165       "      ></SegmentURL>"
5166       "      <SegmentURL"
5167       "         media=\"TestMedia1\" mediaRange=\"20-30\""
5168       "         index=\"TestIndex1\" indexRange=\"200-300\""
5169       "      ></SegmentURL>"
5170       "    </SegmentList>"
5171       "    <Representation id=\"1\" bandwidth=\"250000\">"
5172       "      <SegmentList duration=\"8\">"
5173       "        <SegmentURL"
5174       "           media=\"TestMedia2\" mediaRange=\"30-40\""
5175       "           index=\"TestIndex2\" indexRange=\"300-400\""
5176       "        ></SegmentURL>"
5177       "        <SegmentURL"
5178       "           media=\"TestMedia3\" mediaRange=\"40-50\""
5179       "           index=\"TestIndex3\" indexRange=\"400-500\""
5180       "        ></SegmentURL>"
5181       "      </SegmentList>"
5182       "    </Representation></AdaptationSet></Period></MPD>";
5183 
5184   gboolean ret;
5185   GstMPDClient *mpdclient = gst_mpd_client_new ();
5186 
5187   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5188   assert_equals_int (ret, TRUE);
5189 
5190   /* process the xml data */
5191   ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5192       -1, NULL);
5193   assert_equals_int (ret, TRUE);
5194 
5195   /* get the list of adaptation sets of the first period */
5196   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
5197   fail_if (adaptationSets == NULL);
5198 
5199   /* setup streaming from the first adaptation set */
5200   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
5201   fail_if (adapt_set == NULL);
5202   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
5203   assert_equals_int (ret, TRUE);
5204 
5205   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
5206   fail_if (activeStream == NULL);
5207 
5208   expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 8, 0);
5209   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 0, 0);
5210 
5211   /* the representation contains 2 segments defined in the Representation
5212    *
5213    * Both will have the duration specified in the Representation (8)
5214    */
5215 
5216   /* check first segment */
5217   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
5218   assert_equals_int (ret, TRUE);
5219   assert_equals_string (fragment.uri, "/TestMedia2");
5220   assert_equals_int64 (fragment.range_start, 30);
5221   assert_equals_int64 (fragment.range_end, 40);
5222   assert_equals_string (fragment.index_uri, "/TestIndex2");
5223   assert_equals_int64 (fragment.index_range_start, 300);
5224   assert_equals_int64 (fragment.index_range_end, 400);
5225   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
5226   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
5227   gst_mpdparser_media_fragment_info_clear (&fragment);
5228 
5229   /* advance to next segment */
5230   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
5231   assert_equals_int (flow, GST_FLOW_OK);
5232 
5233   /* second segment starts after previous ends */
5234   expectedTimestamp = expectedTimestamp + expectedDuration;
5235 
5236   /* check second segment */
5237   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
5238   assert_equals_int (ret, TRUE);
5239   assert_equals_string (fragment.uri, "/TestMedia3");
5240   assert_equals_int64 (fragment.range_start, 40);
5241   assert_equals_int64 (fragment.range_end, 50);
5242   assert_equals_string (fragment.index_uri, "/TestIndex3");
5243   assert_equals_int64 (fragment.index_range_start, 400);
5244   assert_equals_int64 (fragment.index_range_end, 500);
5245   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
5246   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
5247   gst_mpdparser_media_fragment_info_clear (&fragment);
5248 
5249   /* try to advance to the next segment. There isn't any, so it should fail */
5250   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
5251   assert_equals_int (flow, GST_FLOW_EOS);
5252 
5253   gst_mpd_client_free (mpdclient);
5254 }
5255 
5256 GST_END_TEST;
5257 
5258 /*
5259  * Test SegmentList with multiple segmentURL
5260  *
5261  */
GST_START_TEST(dash_mpdparser_multipleSegmentURL)5262 GST_START_TEST (dash_mpdparser_multipleSegmentURL)
5263 {
5264   GList *adaptationSets;
5265   GstMPDAdaptationSetNode *adapt_set;
5266   GstActiveStream *activeStream;
5267   GstMediaFragmentInfo fragment;
5268   GstClockTime expectedDuration;
5269   GstClockTime expectedTimestamp;
5270   GstFlowReturn flow;
5271 
5272   /*
5273    * Period duration is 30 seconds
5274    * Period start is 10 seconds. Thus, period duration is 20 seconds.
5275    *
5276    * Segment duration is 25 seconds. There are 2 segments in the list.
5277    * We expect first segment to have a duration of 20 seconds (limited by the period)
5278    * and the second segment to not exist.
5279    */
5280   const gchar *xml =
5281       "<?xml version=\"1.0\"?>"
5282       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5283       " profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5284       " availabilityStartTime=\"2015-03-24T0:0:0\""
5285       " mediaPresentationDuration=\"P0Y0M0DT0H0M30S\">"
5286       "<Period start=\"P0Y0M0DT0H0M10S\">"
5287       "  <AdaptationSet mimeType=\"video/mp4\">"
5288       "    <Representation id=\"1\" bandwidth=\"250000\">"
5289       "      <SegmentList duration=\"25\">"
5290       "        <SegmentURL"
5291       "           media=\"TestMedia0\" mediaRange=\"10-20\""
5292       "           index=\"TestIndex0\" indexRange=\"100-200\""
5293       "        ></SegmentURL>"
5294       "        <SegmentURL"
5295       "           media=\"TestMedia1\" mediaRange=\"20-30\""
5296       "           index=\"TestIndex1\" indexRange=\"200-300\""
5297       "        ></SegmentURL>"
5298       "      </SegmentList>"
5299       "    </Representation></AdaptationSet></Period></MPD>";
5300 
5301   gboolean ret;
5302   GstMPDClient *mpdclient = gst_mpd_client_new ();
5303 
5304   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5305   assert_equals_int (ret, TRUE);
5306 
5307   /* process the xml data */
5308   ret =
5309       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5310       -1, NULL);
5311   assert_equals_int (ret, TRUE);
5312 
5313   /* get the list of adaptation sets of the first period */
5314   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
5315   fail_if (adaptationSets == NULL);
5316 
5317   /* setup streaming from the first adaptation set */
5318   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
5319   fail_if (adapt_set == NULL);
5320   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
5321   assert_equals_int (ret, TRUE);
5322 
5323   activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
5324   fail_if (activeStream == NULL);
5325 
5326   expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 20, 0);
5327   expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 10, 0);
5328 
5329   /* the representation contains 2 segments. The first is partially
5330    * clipped, and the second entirely (and thus discarded).
5331    */
5332 
5333   /* check first segment */
5334   ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
5335   assert_equals_int (ret, TRUE);
5336   assert_equals_string (fragment.uri, "/TestMedia0");
5337   assert_equals_int64 (fragment.range_start, 10);
5338   assert_equals_int64 (fragment.range_end, 20);
5339   assert_equals_string (fragment.index_uri, "/TestIndex0");
5340   assert_equals_int64 (fragment.index_range_start, 100);
5341   assert_equals_int64 (fragment.index_range_end, 200);
5342   assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
5343   assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
5344   gst_mpdparser_media_fragment_info_clear (&fragment);
5345 
5346   /* advance to next segment */
5347   flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
5348   assert_equals_int (flow, GST_FLOW_EOS);
5349 
5350   gst_mpd_client_free (mpdclient);
5351 }
5352 
5353 GST_END_TEST;
5354 
5355 /*
5356  * Test parsing empty xml string
5357  *
5358  */
GST_START_TEST(dash_mpdparser_missing_xml)5359 GST_START_TEST (dash_mpdparser_missing_xml)
5360 {
5361   const gchar *xml = "";
5362 
5363   gboolean ret;
5364   GstMPDClient *mpdclient = gst_mpd_client_new ();
5365 
5366   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5367   assert_equals_int (ret, FALSE);
5368 
5369   gst_mpd_client_free (mpdclient);
5370 }
5371 
5372 GST_END_TEST;
5373 
5374 /*
5375  * Test parsing an xml with no mpd tag
5376  *
5377  */
GST_START_TEST(dash_mpdparser_missing_mpd)5378 GST_START_TEST (dash_mpdparser_missing_mpd)
5379 {
5380   const gchar *xml = "<?xml version=\"1.0\"?>";
5381 
5382   gboolean ret;
5383   GstMPDClient *mpdclient = gst_mpd_client_new ();
5384 
5385   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5386   assert_equals_int (ret, FALSE);
5387 
5388   gst_mpd_client_free (mpdclient);
5389 }
5390 
5391 GST_END_TEST;
5392 
5393 /*
5394  * Test parsing an MPD with a wrong end tag
5395  */
GST_START_TEST(dash_mpdparser_no_end_tag)5396 GST_START_TEST (dash_mpdparser_no_end_tag)
5397 {
5398   const gchar *xml =
5399       "<?xml version=\"1.0\"?>"
5400       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5401       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\"> </NPD>";
5402 
5403   gboolean ret;
5404   GstMPDClient *mpdclient = gst_mpd_client_new ();
5405 
5406   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5407   assert_equals_int (ret, FALSE);
5408 
5409   gst_mpd_client_free (mpdclient);
5410 }
5411 
5412 GST_END_TEST;
5413 
5414 /*
5415  * Test parsing an MPD with no default namespace
5416  */
GST_START_TEST(dash_mpdparser_no_default_namespace)5417 GST_START_TEST (dash_mpdparser_no_default_namespace)
5418 {
5419   const gchar *xml =
5420       "<?xml version=\"1.0\"?>"
5421       "<MPD profiles=\"urn:mpeg:dash:profile:isoff-main:2011\"></MPD>";
5422 
5423   gboolean ret;
5424   GstMPDClient *mpdclient = gst_mpd_client_new ();
5425 
5426   ret = gst_mpd_client_parse (mpdclient, xml, strlen (xml));
5427   assert_equals_int (ret, TRUE);
5428 
5429   gst_mpd_client_free (mpdclient);
5430 }
5431 
5432 GST_END_TEST;
5433 
5434 /*
5435  * Test handling wrong period duration during attempts to
5436  * infer a period duration from the start time of the next period
5437  */
GST_START_TEST(dash_mpdparser_wrong_period_duration_inferred_from_next_period)5438 GST_START_TEST (dash_mpdparser_wrong_period_duration_inferred_from_next_period)
5439 {
5440   const gchar *periodName;
5441 
5442   const gchar *xml =
5443       "<?xml version=\"1.0\"?>"
5444       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5445       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5446       "     availabilityStartTime=\"2015-03-24T0:0:0\""
5447       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
5448       "  <Period id=\"Period0\" duration=\"P0Y0M0DT1H1M0S\"></Period>"
5449       "  <Period id=\"Period1\"></Period>"
5450       "  <Period id=\"Period2\" start=\"P0Y0M0DT0H0M10S\"></Period></MPD>";
5451 
5452   gboolean ret;
5453   GstMPDClient *mpdclient = gst_mpd_client_new ();
5454 
5455   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5456   assert_equals_int (ret, TRUE);
5457 
5458   /* period_idx should be 0 and we should have no active periods */
5459   assert_equals_uint64 (mpdclient->period_idx, 0);
5460   fail_unless (mpdclient->periods == NULL);
5461 
5462   /* process the xml data */
5463   ret =
5464       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5465       -1, NULL);
5466   assert_equals_int (ret, TRUE);
5467 
5468   /* Period0 should be present */
5469   fail_unless (mpdclient->periods != NULL);
5470   periodName = gst_mpd_client_get_period_id (mpdclient);
5471   assert_equals_string (periodName, "Period0");
5472 
5473   /* Period1 should not be present due to wrong duration */
5474   ret = gst_mpd_client_set_period_index (mpdclient, 1);
5475   assert_equals_int (ret, FALSE);
5476 
5477   gst_mpd_client_free (mpdclient);
5478 }
5479 
5480 GST_END_TEST;
5481 
5482 /*
5483  * Test handling wrong period duration during attempts to
5484  * infer a period duration from the mediaPresentationDuration
5485  */
GST_START_TEST(dash_mpdparser_wrong_period_duration_inferred_from_next_mediaPresentationDuration)5486 GST_START_TEST
5487     (dash_mpdparser_wrong_period_duration_inferred_from_next_mediaPresentationDuration)
5488 {
5489   const gchar *xml =
5490       "<?xml version=\"1.0\"?>"
5491       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5492       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5493       "     availabilityStartTime=\"2015-03-24T0:0:0\""
5494       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
5495       "  <Period id=\"Period0\" start=\"P0Y0M0DT4H0M0S\"></Period></MPD>";
5496 
5497   gboolean ret;
5498   GstMPDClient *mpdclient = gst_mpd_client_new ();
5499 
5500   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5501   assert_equals_int (ret, TRUE);
5502 
5503   /* period_idx should be 0 and we should have no active periods */
5504   assert_equals_uint64 (mpdclient->period_idx, 0);
5505   fail_unless (mpdclient->periods == NULL);
5506 
5507   /* process the xml data
5508    * should fail due to wrong duration in Period0 (start > mediaPresentationDuration)
5509    */
5510   ret =
5511       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5512       -1, NULL);
5513   assert_equals_int (ret, FALSE);
5514 
5515   gst_mpd_client_free (mpdclient);
5516 }
5517 
5518 GST_END_TEST;
5519 
GST_START_TEST(dash_mpdparser_whitespace_strings)5520 GST_START_TEST (dash_mpdparser_whitespace_strings)
5521 {
5522   fail_unless (_mpd_helper_validate_no_whitespace ("") == TRUE);
5523   fail_unless (_mpd_helper_validate_no_whitespace ("/") == TRUE);
5524   fail_unless (_mpd_helper_validate_no_whitespace (" ") == FALSE);
5525   fail_unless (_mpd_helper_validate_no_whitespace ("aaaaaaaa ") == FALSE);
5526   fail_unless (_mpd_helper_validate_no_whitespace ("a\ta") == FALSE);
5527   fail_unless (_mpd_helper_validate_no_whitespace ("a\ra") == FALSE);
5528   fail_unless (_mpd_helper_validate_no_whitespace ("a\na") == FALSE);
5529 }
5530 
5531 GST_END_TEST;
5532 
GST_START_TEST(dash_mpdparser_rfc1738_strings)5533 GST_START_TEST (dash_mpdparser_rfc1738_strings)
5534 {
5535   fail_unless (gst_mpdparser_validate_rfc1738_url ("/") == TRUE);
5536   fail_unless (gst_mpdparser_validate_rfc1738_url (" ") == FALSE);
5537   fail_unless (gst_mpdparser_validate_rfc1738_url ("aaaaaaaa ") == FALSE);
5538 
5539   fail_unless (gst_mpdparser_validate_rfc1738_url ("") == TRUE);
5540   fail_unless (gst_mpdparser_validate_rfc1738_url ("a") == TRUE);
5541   fail_unless (gst_mpdparser_validate_rfc1738_url
5542       (";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),%AA")
5543       == TRUE);
5544   fail_unless (gst_mpdparser_validate_rfc1738_url
5545       (";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),/%AA")
5546       == TRUE);
5547   fail_unless (gst_mpdparser_validate_rfc1738_url
5548       (";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),% ")
5549       == FALSE);
5550   fail_unless (gst_mpdparser_validate_rfc1738_url ("%AA") == TRUE);
5551   fail_unless (gst_mpdparser_validate_rfc1738_url ("%A") == FALSE);
5552   fail_unless (gst_mpdparser_validate_rfc1738_url ("%") == FALSE);
5553   fail_unless (gst_mpdparser_validate_rfc1738_url ("%XA") == FALSE);
5554   fail_unless (gst_mpdparser_validate_rfc1738_url ("%AX") == FALSE);
5555   fail_unless (gst_mpdparser_validate_rfc1738_url ("%XX") == FALSE);
5556   fail_unless (gst_mpdparser_validate_rfc1738_url ("\001") == FALSE);
5557 }
5558 
5559 GST_END_TEST;
5560 
5561 /*
5562  * Test negative period duration
5563  */
GST_START_TEST(dash_mpdparser_negative_period_duration)5564 GST_START_TEST (dash_mpdparser_negative_period_duration)
5565 {
5566   const gchar *xml =
5567       "<?xml version=\"1.0\"?>"
5568       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5569       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5570       "     availabilityStartTime=\"2015-03-24T0:0:0\""
5571       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
5572       "  <Period id=\"Period0\""
5573       "          start=\"P0Y0M0DT1H0M0S\""
5574       "          duration=\"-PT10S\">"
5575       "  </Period><Period id=\"Period1\"></Period></MPD>";
5576 
5577   gboolean ret;
5578   GstMPDClient *mpdclient = gst_mpd_client_new ();
5579 
5580   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5581   assert_equals_int (ret, TRUE);
5582 
5583   /* process the xml data
5584    * should fail due to negative duration of Period0
5585    */
5586   ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5587       -1, NULL);
5588   assert_equals_int (ret, FALSE);
5589 
5590   gst_mpd_client_free (mpdclient);
5591 }
5592 
5593 GST_END_TEST;
5594 
5595 /*
5596  * Test parsing negative values from attributes that should be unsigned
5597  *
5598  */
GST_START_TEST(dash_mpdparser_read_unsigned_from_negative_values)5599 GST_START_TEST (dash_mpdparser_read_unsigned_from_negative_values)
5600 {
5601   GstMPDPeriodNode *periodNode;
5602   GstMPDSegmentBaseNode *segmentBase;
5603   GstMPDAdaptationSetNode *adaptationSet;
5604   GstMPDRepresentationNode *representation;
5605   GstMPDSubRepresentationNode *subRepresentation;
5606 
5607   const gchar *xml =
5608       "<?xml version=\"1.0\"?>"
5609       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5610       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5611       "     availabilityStartTime=\"2015--1-13T12:25:37\">"
5612       "  <Period start=\"-P-2015Y\" duration=\"-P-5M\">"
5613       "    <SegmentBase presentationTimeOffset=\"-10\""
5614       "                 timescale=\"-5\""
5615       "                 indexRange=\"1--10\">"
5616       "    </SegmentBase>"
5617       "    <AdaptationSet par=\"-1:7\""
5618       "                   minFrameRate=\" -1\""
5619       "                   segmentAlignment=\"-4\">"
5620       "      <Representation id=\"1\" bandwidth=\"250000\">"
5621       "        <SubRepresentation dependencyLevel=\"1 -2 3\">"
5622       "        </SubRepresentation>"
5623       "      </Representation></AdaptationSet></Period></MPD>";
5624 
5625   gboolean ret;
5626   GstMPDClient *mpdclient = gst_mpd_client_new ();
5627 
5628   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5629   assert_equals_int (ret, TRUE);
5630 
5631   periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
5632   segmentBase = periodNode->SegmentBase;
5633   adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
5634   representation = (GstMPDRepresentationNode *)
5635       adaptationSet->Representations->data;
5636   subRepresentation = (GstMPDSubRepresentationNode *)
5637       representation->SubRepresentations->data;
5638 
5639   /* availabilityStartTime parsing should fail */
5640   fail_if (mpdclient->mpd_root_node->availabilityStartTime != NULL);
5641 
5642   /* Period start parsing should fail */
5643   assert_equals_int64 (periodNode->start, -1);
5644 
5645   /* Period duration parsing should fail */
5646   assert_equals_int64 (periodNode->duration, -1);
5647 
5648   /* expect negative value to be rejected and presentationTimeOffset to be 0 */
5649   assert_equals_uint64 (segmentBase->presentationTimeOffset, 0);
5650   assert_equals_uint64 (segmentBase->timescale, 1);
5651   fail_if (segmentBase->indexRange != NULL);
5652 
5653   /* par ratio parsing should fail */
5654   fail_if (adaptationSet->par != NULL);
5655 
5656   /* minFrameRate parsing should fail */
5657   fail_if (GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet)->minFrameRate !=
5658       NULL);
5659 
5660   /* segmentAlignment parsing should fail */
5661   fail_if (adaptationSet->segmentAlignment != NULL);
5662 
5663   /* dependency level parsing should fail */
5664   fail_if (subRepresentation->dependencyLevel != NULL);
5665 
5666   gst_mpd_client_free (mpdclient);
5667 }
5668 
5669 GST_END_TEST;
5670 
5671 /*
5672  * Test negative mediaPresentationDuration duration
5673  */
GST_START_TEST(dash_mpdparser_negative_mediaPresentationDuration)5674 GST_START_TEST (dash_mpdparser_negative_mediaPresentationDuration)
5675 {
5676   const gchar *xml =
5677       "<?xml version=\"1.0\"?>"
5678       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5679       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5680       "     availabilityStartTime=\"2015-03-24T0:0:0\""
5681       "     mediaPresentationDuration=\"-P0Y0M0DT3H3M30S\">"
5682       "  <Period id=\"Period0\" start=\"P0Y0M0DT1H0M0S\"></Period></MPD>";
5683 
5684   gboolean ret;
5685   GstMPDClient *mpdclient = gst_mpd_client_new ();
5686 
5687   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5688   assert_equals_int (ret, TRUE);
5689 
5690   /* process the xml data
5691    * should fail due to negative duration of mediaPresentationDuration
5692    */
5693   ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5694       -1, NULL);
5695   assert_equals_int (ret, FALSE);
5696 
5697   gst_mpd_client_free (mpdclient);
5698 }
5699 
5700 GST_END_TEST;
5701 
5702 /*
5703  * Test parsing an MPD with no profiles
5704  */
GST_START_TEST(dash_mpdparser_no_profiles)5705 GST_START_TEST (dash_mpdparser_no_profiles)
5706 {
5707   const gchar *xml =
5708       "<?xml version=\"1.0\"?>"
5709       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\"></MPD>";
5710 
5711   gboolean ret;
5712   GstMPDClient *mpdclient = gst_mpd_client_new ();
5713 
5714   ret = gst_mpd_client_parse (mpdclient, xml, strlen (xml));
5715 
5716   assert_equals_int (ret, TRUE);
5717 
5718   gst_mpd_client_free (mpdclient);
5719 }
5720 
5721 GST_END_TEST;
5722 
5723 /*
5724  * Test S node list greater than SegmentURL list
5725  *
5726  */
GST_START_TEST(dash_mpdparser_unmatched_segmentTimeline_segmentURL)5727 GST_START_TEST (dash_mpdparser_unmatched_segmentTimeline_segmentURL)
5728 {
5729   GList *adaptationSets;
5730   GstMPDAdaptationSetNode *adapt_set;
5731 
5732   const gchar *xml =
5733       "<?xml version=\"1.0\"?>"
5734       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5735       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5736       "     availabilityStartTime=\"2015-03-24T0:0:0\""
5737       "     mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
5738       "  <Period start=\"P0Y0M0DT0H0M10S\">"
5739       "    <AdaptationSet mimeType=\"video/mp4\">"
5740       "      <Representation id=\"1\" bandwidth=\"250000\">"
5741       "        <SegmentList>"
5742       "          <SegmentTimeline>"
5743       "            <S t=\"3\"  d=\"2\" r=\"1\"></S>"
5744       "            <S t=\"10\" d=\"3\" r=\"0\"></S>"
5745       "          </SegmentTimeline>"
5746       "          <SegmentURL media=\"TestMedia0\""
5747       "                      index=\"TestIndex0\">"
5748       "          </SegmentURL>"
5749       "        </SegmentList>"
5750       "      </Representation></AdaptationSet></Period></MPD>";
5751 
5752   gboolean ret;
5753   GstMPDClient *mpdclient = gst_mpd_client_new ();
5754 
5755   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5756   assert_equals_int (ret, TRUE);
5757 
5758   /* process the xml data */
5759   ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5760       -1, NULL);
5761   assert_equals_int (ret, TRUE);
5762 
5763   /* get the list of adaptation sets of the first period */
5764   adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
5765   fail_if (adaptationSets == NULL);
5766 
5767   adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
5768   fail_if (adapt_set == NULL);
5769 
5770   /* setup streaming from the first adaptation set.
5771    * Should fail because the second S node does not have a  matching
5772    * SegmentURL node
5773    */
5774   ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
5775   assert_equals_int (ret, FALSE);
5776 
5777   gst_mpd_client_free (mpdclient);
5778 }
5779 
5780 GST_END_TEST;
5781 
5782 /*
5783  * Test parsing of the default presentation delay property
5784  */
GST_START_TEST(dash_mpdparser_default_presentation_delay)5785 GST_START_TEST (dash_mpdparser_default_presentation_delay)
5786 {
5787   const gchar *xml =
5788       "<?xml version=\"1.0\"?>"
5789       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5790       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5791       "     maxSegmentDuration=\"PT2S\">"
5792       "  <Period id=\"Period0\" start=\"P0S\"></Period></MPD>";
5793 
5794   gboolean ret;
5795   GstMPDClient *mpdclient = gst_mpd_client_new ();
5796   gint64 value;
5797 
5798   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5799   assert_equals_int (ret, TRUE);
5800   value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "5s");
5801   assert_equals_int64 (value, 5000);
5802   value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "5S");
5803   assert_equals_int64 (value, 5000);
5804   value =
5805       gst_mpd_client_parse_default_presentation_delay (mpdclient, "5 seconds");
5806   assert_equals_int64 (value, 5000);
5807   value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "2500ms");
5808   assert_equals_int64 (value, 2500);
5809   value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "3f");
5810   assert_equals_int64 (value, 6000);
5811   value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "3F");
5812   assert_equals_int64 (value, 6000);
5813   value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "");
5814   assert_equals_int64 (value, 0);
5815   value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "10");
5816   assert_equals_int64 (value, 0);
5817   value =
5818       gst_mpd_client_parse_default_presentation_delay (mpdclient,
5819       "not a number");
5820   assert_equals_int64 (value, 0);
5821 
5822   gst_mpd_client_free (mpdclient);
5823 }
5824 
5825 GST_END_TEST;
5826 
GST_START_TEST(dash_mpdparser_duration)5827 GST_START_TEST (dash_mpdparser_duration)
5828 {
5829   guint64 v;
5830 
5831   fail_unless (_mpd_helper_parse_duration ("", &v) == FALSE);
5832   fail_unless (_mpd_helper_parse_duration (" ", &v) == FALSE);
5833   fail_unless (_mpd_helper_parse_duration ("0", &v) == FALSE);
5834   fail_unless (_mpd_helper_parse_duration ("D-1", &v) == FALSE);
5835   fail_unless (_mpd_helper_parse_duration ("T", &v) == FALSE);
5836 
5837   fail_unless (_mpd_helper_parse_duration ("P", &v) == TRUE);
5838   fail_unless (_mpd_helper_parse_duration ("PT", &v) == TRUE);
5839   fail_unless (_mpd_helper_parse_duration ("PX", &v) == FALSE);
5840   fail_unless (_mpd_helper_parse_duration ("PPT", &v) == FALSE);
5841   fail_unless (_mpd_helper_parse_duration ("PTT", &v) == FALSE);
5842 
5843   fail_unless (_mpd_helper_parse_duration ("P1D", &v) == TRUE);
5844   fail_unless (_mpd_helper_parse_duration ("P1D1D", &v) == FALSE);
5845   fail_unless (_mpd_helper_parse_duration ("P1D1M", &v) == FALSE);
5846   fail_unless (_mpd_helper_parse_duration ("P1M1D", &v) == TRUE);
5847   fail_unless (_mpd_helper_parse_duration ("P1M1D1M", &v) == FALSE);
5848   fail_unless (_mpd_helper_parse_duration ("P1M1D1D", &v) == FALSE);
5849 
5850   fail_unless (_mpd_helper_parse_duration ("P0M0D", &v) == TRUE);
5851   fail_unless (_mpd_helper_parse_duration ("P-1M", &v) == FALSE);
5852   fail_unless (_mpd_helper_parse_duration ("P15M", &v) == FALSE);
5853   fail_unless (_mpd_helper_parse_duration ("P-1D", &v) == FALSE);
5854   fail_unless (_mpd_helper_parse_duration ("P35D", &v) == FALSE);
5855   fail_unless (_mpd_helper_parse_duration ("P-1Y", &v) == FALSE);
5856   fail_unless (_mpd_helper_parse_duration ("PT-1H", &v) == FALSE);
5857   fail_unless (_mpd_helper_parse_duration ("PT25H", &v) == FALSE);
5858   fail_unless (_mpd_helper_parse_duration ("PT-1M", &v) == FALSE);
5859   fail_unless (_mpd_helper_parse_duration ("PT65M", &v) == FALSE);
5860   fail_unless (_mpd_helper_parse_duration ("PT-1S", &v) == FALSE);
5861   /* seconds are allowed to be larger than 60 */
5862   fail_unless (_mpd_helper_parse_duration ("PT65S", &v) == TRUE);
5863 
5864   fail_unless (_mpd_helper_parse_duration ("PT1.1H", &v) == FALSE);
5865   fail_unless (_mpd_helper_parse_duration ("PT1-1H", &v) == FALSE);
5866   fail_unless (_mpd_helper_parse_duration ("PT1-H", &v) == FALSE);
5867   fail_unless (_mpd_helper_parse_duration ("PT-H", &v) == FALSE);
5868   fail_unless (_mpd_helper_parse_duration ("PTH", &v) == FALSE);
5869   fail_unless (_mpd_helper_parse_duration ("PT0", &v) == FALSE);
5870   fail_unless (_mpd_helper_parse_duration ("PT1.1S", &v) == TRUE);
5871   fail_unless (_mpd_helper_parse_duration ("PT1.1.1S", &v) == FALSE);
5872 
5873   fail_unless (_mpd_helper_parse_duration ("P585Y", &v) == FALSE);
5874   fail_unless (_mpd_helper_parse_duration ("P584Y", &v) == TRUE);
5875 
5876   fail_unless (_mpd_helper_parse_duration (" P10DT8H", &v) == TRUE);
5877   fail_unless (_mpd_helper_parse_duration ("P10D T8H", &v) == FALSE);
5878   fail_unless (_mpd_helper_parse_duration ("P10DT8H ", &v) == TRUE);
5879 }
5880 
5881 GST_END_TEST;
5882 
5883 /*
5884  * Test that the maximum_segment_duration correctly implements the
5885  * rules in the DASH specification
5886  */
GST_START_TEST(dash_mpdparser_maximum_segment_duration)5887 GST_START_TEST (dash_mpdparser_maximum_segment_duration)
5888 {
5889   const gchar *xml_template =
5890       "<?xml version=\"1.0\"?>"
5891       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5892       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
5893       "     availabilityStartTime=\"2015-03-24T0:0:0\""
5894       "     %s "
5895       "     mediaPresentationDuration=\"P100Y\">"
5896       "  <Period id=\"Period0\" start=\"PT0S\">"
5897       "    <AdaptationSet mimeType=\"video/mp4\" >"
5898       "      <SegmentTemplate timescale=\"90000\" initialization=\"$RepresentationID$/Header.m4s\" media=\"$RepresentationID$/$Number$.m4s\" duration=\"360000\" />"
5899       "      <Representation id=\"video1\" width=\"576\" height=\"324\" frameRate=\"25\" sar=\"1:1\" bandwidth=\"900000\" codecs=\"avc1.4D401E\"/>"
5900       "    </AdaptationSet>"
5901       "      <AdaptationSet mimeType=\"audio/mp4\" >"
5902       "        <SegmentTemplate timescale=\"90000\" initialization=\"$RepresentationID$/Header.m4s\" media=\"$RepresentationID$/$Number$.m4s\" duration=\"340000\" />"
5903       "        <Representation id=\"audio1\" audioSamplingRate=\"22050\" bandwidth=\"29600\" codecs=\"mp4a.40.2\">"
5904       "        <AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"2\"/>"
5905       "      </Representation>" "    </AdaptationSet>" "  </Period></MPD>";
5906   gboolean ret;
5907   GstMPDClient *mpdclient;
5908   gchar *xml;
5909   GstClockTime dur;
5910   GList *adapt_sets, *iter;
5911 
5912   xml = g_strdup_printf (xml_template, "maxSegmentDuration=\"PT4.5S\"");
5913   mpdclient = gst_mpd_client_new ();
5914   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5915   g_free (xml);
5916   assert_equals_int (ret, TRUE);
5917 
5918   assert_equals_uint64 (mpdclient->mpd_root_node->maxSegmentDuration,
5919       duration_to_ms (0, 0, 0, 0, 0, 4, 500));
5920   dur = gst_mpd_client_get_maximum_segment_duration (mpdclient);
5921   assert_equals_uint64 (dur, duration_to_clocktime (0, 0, 0, 0, 0, 4, 500));
5922   gst_mpd_client_free (mpdclient);
5923 
5924   /* now parse without the maxSegmentDuration attribute, to check that
5925      gst_mpd_client_get_maximum_segment_duration uses the maximum
5926      duration of any segment
5927    */
5928   xml = g_strdup_printf (xml_template, "");
5929   mpdclient = gst_mpd_client_new ();
5930   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
5931   g_free (xml);
5932   assert_equals_int (ret, TRUE);
5933   ret =
5934       gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
5935       -1, NULL);
5936   assert_equals_int (ret, TRUE);
5937   adapt_sets = gst_mpd_client_get_adaptation_sets (mpdclient);
5938   for (iter = adapt_sets; iter; iter = g_list_next (iter)) {
5939     GstMPDAdaptationSetNode *adapt_set_node = iter->data;
5940 
5941     ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set_node);
5942     assert_equals_int (ret, TRUE);
5943   }
5944   dur = gst_mpd_client_get_maximum_segment_duration (mpdclient);
5945   assert_equals_uint64 (dur, duration_to_clocktime (0, 0, 0, 0, 0, 4, 0));
5946   gst_mpd_client_free (mpdclient);
5947 }
5948 
5949 GST_END_TEST;
5950 
5951 /*
5952  * Test parsing of Perioud using @xlink:href attribute
5953  */
5954 
5955 #define STRINGIFY_(x) #x
5956 #define STRINGIFY(x) STRINGIFY_ (x)
5957 #define REMOTEDIR STRINGIFY (DASH_MPD_DATADIR)
5958 #define XLINK_SINGLE_PERIOD_FILENAME REMOTEDIR "/xlink_single_period.period"
5959 #define XLINK_DOUBLE_PERIOD_FILENAME REMOTEDIR "/xlink_double_period.period"
5960 
GST_START_TEST(dash_mpdparser_xlink_period)5961 GST_START_TEST (dash_mpdparser_xlink_period)
5962 {
5963   GstMPDPeriodNode *periodNode;
5964   GstUriDownloader *downloader;
5965   GstMPDClient *mpdclient;
5966   GList *period_list, *iter;
5967   gboolean ret;
5968   gchar *xml_joined, *file_uri_single_period, *file_uri_double_period;
5969   const gchar *xml_frag_start =
5970       "<?xml version=\"1.0\"?>"
5971       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
5972       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
5973       "  <Period id=\"Period0\" duration=\"PT5S\"></Period>";
5974 
5975   const gchar *xml_uri_front = "  <Period xlink:href=\"";
5976 
5977   const gchar *xml_uri_rear =
5978       "\""
5979       "          xlink:actuate=\"onRequest\""
5980       "          xmlns:xlink=\"http://www.w3.org/1999/xlink\"></Period>";
5981 
5982   const gchar *xml_frag_end = "</MPD>";
5983 
5984   /* XLINK_ONE_PERIOD_FILENAME
5985    *
5986    * <Period id="xlink-single-period-Period1" duration="PT10S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>
5987    */
5988 
5989   /* XLINK_TWO_PERIODS_FILENAME
5990    *
5991    * <Period id="xlink-double-period-Period1" duration="PT10S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>
5992    * <Period id="xlink-double-period-Period2" duration="PT20S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>
5993    */
5994 
5995 
5996   mpdclient = gst_mpd_client_new ();
5997   downloader = gst_uri_downloader_new ();
5998 
5999   gst_mpd_client_set_uri_downloader (mpdclient, downloader);
6000 
6001   file_uri_single_period =
6002       gst_filename_to_uri (XLINK_SINGLE_PERIOD_FILENAME, NULL);
6003   file_uri_double_period =
6004       gst_filename_to_uri (XLINK_DOUBLE_PERIOD_FILENAME, NULL);
6005 
6006   /* constructs initial mpd using external xml uri */
6007   /* For invalid URI, mpdparser should be ignore it */
6008   xml_joined = g_strjoin ("", xml_frag_start,
6009       xml_uri_front, "http://404.invalid/ERROR/XML.period", xml_uri_rear,
6010       xml_uri_front, (const char *) file_uri_single_period, xml_uri_rear,
6011       xml_uri_front, (const char *) file_uri_double_period, xml_uri_rear,
6012       xml_frag_end, NULL);
6013 
6014   ret =
6015       gst_mpd_client_parse (mpdclient, xml_joined, (gint) strlen (xml_joined));
6016   assert_equals_int (ret, TRUE);
6017 
6018   period_list = mpdclient->mpd_root_node->Periods;
6019   /* only count periods on initial mpd (external xml does not parsed yet) */
6020   assert_equals_int (g_list_length (period_list), 4);
6021 
6022   /* process the xml data */
6023   ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
6024       -1, NULL);
6025   assert_equals_int (ret, TRUE);
6026 
6027   period_list = mpdclient->mpd_root_node->Periods;
6028   assert_equals_int (g_list_length (period_list), 4);
6029 
6030   iter = period_list;
6031   periodNode = (GstMPDPeriodNode *) iter->data;
6032   assert_equals_string (periodNode->id, "Period0");
6033 
6034   iter = iter->next;
6035   periodNode = (GstMPDPeriodNode *) iter->data;
6036   assert_equals_string (periodNode->id, "xlink-single-period-Period1");
6037 
6038   iter = iter->next;
6039   periodNode = (GstMPDPeriodNode *) iter->data;
6040   assert_equals_string (periodNode->id, "xlink-double-period-Period1");
6041 
6042   iter = iter->next;
6043   periodNode = (GstMPDPeriodNode *) iter->data;
6044   assert_equals_string (periodNode->id, "xlink-double-period-Period2");
6045 
6046   gst_mpd_client_free (mpdclient);
6047   g_object_unref (downloader);
6048   g_free (file_uri_single_period);
6049   g_free (file_uri_double_period);
6050   g_free (xml_joined);
6051 }
6052 
6053 GST_END_TEST;
6054 
6055 
6056 /*
6057  * Test parsing xsd:datetime with timezoneoffset.
6058  *
6059  */
GST_START_TEST(dash_mpdparser_datetime_with_tz_offset)6060 GST_START_TEST (dash_mpdparser_datetime_with_tz_offset)
6061 {
6062   GstDateTime *availabilityStartTime;
6063   GstDateTime *availabilityEndTime;
6064   const gchar *xml =
6065       "<?xml version=\"1.0\"?>"
6066       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
6067       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
6068       "     schemaLocation=\"TestSchemaLocation\""
6069       "     xmlns:xsi=\"TestNamespaceXSI\""
6070       "     xmlns:ext=\"TestNamespaceEXT\""
6071       "     id=\"testId\""
6072       "     type=\"static\""
6073       "     availabilityStartTime=\"2015-03-24T1:10:50+08:00\""
6074       "     availabilityEndTime=\"2015-03-24T1:10:50.123456-04:30\""
6075       "     mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
6076       "     minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
6077       "     minBufferTime=\"P0Y1M2DT12H10M20.5S\""
6078       "     timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
6079       "     suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
6080       "     maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
6081       "     maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\"></MPD>";
6082 
6083   gboolean ret;
6084   GstMPDClient *mpdclient = gst_mpd_client_new ();
6085 
6086   ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
6087   assert_equals_int (ret, TRUE);
6088 
6089   availabilityStartTime = mpdclient->mpd_root_node->availabilityStartTime;
6090   assert_equals_int (gst_date_time_get_year (availabilityStartTime), 2015);
6091   assert_equals_int (gst_date_time_get_month (availabilityStartTime), 3);
6092   assert_equals_int (gst_date_time_get_day (availabilityStartTime), 24);
6093   assert_equals_int (gst_date_time_get_hour (availabilityStartTime), 1);
6094   assert_equals_int (gst_date_time_get_minute (availabilityStartTime), 10);
6095   assert_equals_int (gst_date_time_get_second (availabilityStartTime), 50);
6096   assert_equals_int (gst_date_time_get_microsecond (availabilityStartTime), 0);
6097   assert_equals_float (gst_date_time_get_time_zone_offset
6098       (availabilityStartTime), 8.0);
6099 
6100   availabilityEndTime = mpdclient->mpd_root_node->availabilityEndTime;
6101   assert_equals_int (gst_date_time_get_year (availabilityEndTime), 2015);
6102   assert_equals_int (gst_date_time_get_month (availabilityEndTime), 3);
6103   assert_equals_int (gst_date_time_get_day (availabilityEndTime), 24);
6104   assert_equals_int (gst_date_time_get_hour (availabilityEndTime), 1);
6105   assert_equals_int (gst_date_time_get_minute (availabilityEndTime), 10);
6106   assert_equals_int (gst_date_time_get_second (availabilityEndTime), 50);
6107   assert_equals_int (gst_date_time_get_microsecond (availabilityEndTime),
6108       123456);
6109   assert_equals_float (gst_date_time_get_time_zone_offset (availabilityEndTime),
6110       -4.5);
6111 
6112   gst_mpd_client_free (mpdclient);
6113 }
6114 
6115 GST_END_TEST;
6116 
6117 /*
6118  * Test generate xml content.
6119  *
6120  */
GST_START_TEST(dash_mpdparser_check_mpd_xml_generator)6121 GST_START_TEST (dash_mpdparser_check_mpd_xml_generator)
6122 {
6123   const gchar *xml =
6124       "<?xml version=\"1.0\"?>"
6125       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
6126       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
6127       "     schemaLocation=\"TestSchemaLocation\""
6128       "     xmlns:xsi=\"TestNamespaceXSI\""
6129       "     xmlns:ext=\"TestNamespaceEXT\""
6130       "     id=\"testId\""
6131       "     type=\"static\""
6132       "     availabilityStartTime=\"2015-03-24T1:10:50+08:00\""
6133       "     availabilityEndTime=\"2015-03-24T1:10:50.123456-04:30\""
6134       "     mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
6135       "     minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
6136       "     minBufferTime=\"P0Y1M2DT12H10M20.5S\""
6137       "     timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
6138       "     suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
6139       "     maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
6140       "     maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\">"
6141       "     <BaseURL serviceLocation=\"TestServiceLocation\""
6142       "     byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
6143       "     <Location>TestLocation</Location>"
6144       "     <ProgramInformation lang=\"en\""
6145       "     moreInformationURL=\"TestMoreInformationUrl\">"
6146       "     <Title>TestTitle</Title>"
6147       "     <Source>TestSource</Source>"
6148       "     <Copyright>TestCopyright</Copyright>"
6149       "     </ProgramInformation>"
6150       "     <Metrics metrics=\"TestMetric\"><Range starttime=\"P0Y1M2DT12H10M20.5S\""
6151       "           duration=\"P0Y1M2DT12H10M20.1234567S\">"
6152       "    </Range></Metrics>"
6153       "  <Period>"
6154       "    <AdaptationSet>"
6155       "      <Representation id=\"1\" bandwidth=\"250000\">"
6156       "        <SegmentTemplate duration=\"1\">"
6157       "        </SegmentTemplate>"
6158       "      </Representation></AdaptationSet></Period>" "     </MPD>";
6159 
6160   gboolean ret;
6161   gchar *new_xml;
6162   gint new_xml_size;
6163   GstMPDClient *first_mpdclient = NULL;
6164   GstMPDClient *second_mpdclient = NULL;
6165   GstMPDBaseURLNode *first_baseURL, *second_baseURL;
6166   GstMPDLocationNode *first_location, *second_location;
6167   GstMPDProgramInformationNode *first_prog_info, *second_prog_info;
6168   GstMPDMetricsNode *first_metrics, *second_metrics;
6169   GstMPDMetricsRangeNode *first_metrics_range, *second_metrics_range;
6170 
6171   first_mpdclient = gst_mpd_client_new ();
6172 
6173   ret = gst_mpd_client_parse (first_mpdclient, xml, (gint) strlen (xml));
6174   assert_equals_int (ret, TRUE);
6175 
6176   gst_mpd_client_get_xml_content (first_mpdclient, &new_xml, &new_xml_size);
6177 
6178   second_mpdclient = gst_mpd_client_new ();
6179 
6180   ret = gst_mpd_client_parse (second_mpdclient, new_xml, new_xml_size);
6181   assert_equals_int (ret, TRUE);
6182   g_free (new_xml);
6183 
6184   /* assert that parameters are equal */
6185   assert_equals_string (first_mpdclient->mpd_root_node->default_namespace,
6186       second_mpdclient->mpd_root_node->default_namespace);
6187   assert_equals_string (first_mpdclient->mpd_root_node->namespace_xsi,
6188       second_mpdclient->mpd_root_node->namespace_xsi);
6189   assert_equals_string (first_mpdclient->mpd_root_node->namespace_ext,
6190       second_mpdclient->mpd_root_node->namespace_ext);
6191   assert_equals_string (first_mpdclient->mpd_root_node->schemaLocation,
6192       second_mpdclient->mpd_root_node->schemaLocation);
6193   assert_equals_string (first_mpdclient->mpd_root_node->id,
6194       second_mpdclient->mpd_root_node->id);
6195   assert_equals_string (first_mpdclient->mpd_root_node->profiles,
6196       second_mpdclient->mpd_root_node->profiles);
6197   assert_equals_uint64 (first_mpdclient->
6198       mpd_root_node->mediaPresentationDuration,
6199       second_mpdclient->mpd_root_node->mediaPresentationDuration);
6200   assert_equals_uint64 (first_mpdclient->mpd_root_node->minimumUpdatePeriod,
6201       second_mpdclient->mpd_root_node->minimumUpdatePeriod);
6202   assert_equals_uint64 (first_mpdclient->mpd_root_node->minBufferTime,
6203       second_mpdclient->mpd_root_node->minBufferTime);
6204   assert_equals_uint64 (first_mpdclient->mpd_root_node->timeShiftBufferDepth,
6205       second_mpdclient->mpd_root_node->timeShiftBufferDepth);
6206   assert_equals_uint64 (first_mpdclient->
6207       mpd_root_node->suggestedPresentationDelay,
6208       second_mpdclient->mpd_root_node->suggestedPresentationDelay);
6209   assert_equals_uint64 (first_mpdclient->mpd_root_node->maxSegmentDuration,
6210       second_mpdclient->mpd_root_node->maxSegmentDuration);
6211   assert_equals_uint64 (first_mpdclient->mpd_root_node->maxSubsegmentDuration,
6212       second_mpdclient->mpd_root_node->maxSubsegmentDuration);
6213 
6214   /* baseURLs */
6215   first_baseURL =
6216       (GstMPDBaseURLNode *) first_mpdclient->mpd_root_node->BaseURLs->data;
6217   second_baseURL =
6218       (GstMPDBaseURLNode *) second_mpdclient->mpd_root_node->BaseURLs->data;
6219   assert_equals_string (first_baseURL->baseURL, second_baseURL->baseURL);
6220   assert_equals_string (first_baseURL->serviceLocation,
6221       second_baseURL->serviceLocation);
6222   assert_equals_string (first_baseURL->byteRange, second_baseURL->byteRange);
6223 
6224   /* locations */
6225   first_location =
6226       (GstMPDLocationNode *) first_mpdclient->mpd_root_node->Locations->data;
6227   second_location =
6228       (GstMPDLocationNode *) second_mpdclient->mpd_root_node->Locations->data;
6229   assert_equals_string (first_location->location, second_location->location);
6230 
6231   /* ProgramInformation */
6232   first_prog_info =
6233       (GstMPDProgramInformationNode *) first_mpdclient->mpd_root_node->
6234       ProgramInfos->data;
6235   second_prog_info =
6236       (GstMPDProgramInformationNode *) second_mpdclient->mpd_root_node->
6237       ProgramInfos->data;
6238   assert_equals_string (first_prog_info->lang, second_prog_info->lang);
6239   assert_equals_string (first_prog_info->moreInformationURL,
6240       second_prog_info->moreInformationURL);
6241   assert_equals_string (first_prog_info->Title, second_prog_info->Title);
6242   assert_equals_string (first_prog_info->Source, second_prog_info->Source);
6243   assert_equals_string (first_prog_info->Copyright,
6244       second_prog_info->Copyright);
6245 
6246   /* Metrics */
6247   first_metrics =
6248       (GstMPDMetricsNode *) first_mpdclient->mpd_root_node->Metrics->data;
6249   second_metrics =
6250       (GstMPDMetricsNode *) second_mpdclient->mpd_root_node->Metrics->data;
6251   assert_equals_string (first_metrics->metrics, second_metrics->metrics);
6252 
6253   /* Metrics Range */
6254   first_metrics_range =
6255       (GstMPDMetricsRangeNode *) first_metrics->MetricsRanges->data;
6256   second_metrics_range =
6257       (GstMPDMetricsRangeNode *) second_metrics->MetricsRanges->data;
6258   assert_equals_uint64 (first_metrics_range->starttime,
6259       second_metrics_range->starttime);
6260   assert_equals_uint64 (first_metrics_range->duration,
6261       second_metrics_range->duration);
6262 
6263   gst_mpd_client_free (first_mpdclient);
6264   gst_mpd_client_free (second_mpdclient);
6265 }
6266 
6267 GST_END_TEST;
6268 
6269 /*
6270  * Test add mpd content with mpd_client set methods
6271  *
6272  */
GST_START_TEST(dash_mpdparser_check_mpd_client_set_methods)6273 GST_START_TEST (dash_mpdparser_check_mpd_client_set_methods)
6274 {
6275   const gchar *xml =
6276       "<?xml version=\"1.0\"?>"
6277       "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
6278       "     profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
6279       "     schemaLocation=\"TestSchemaLocation\""
6280       "     xmlns:xsi=\"TestNamespaceXSI\""
6281       "     xmlns:ext=\"TestNamespaceEXT\""
6282       "     id=\"testId\""
6283       "     type=\"static\""
6284       "     availabilityStartTime=\"2015-03-24T1:10:50+08:00\""
6285       "     availabilityEndTime=\"2015-03-24T1:10:50.123456-04:30\""
6286       "     mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
6287       "     minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
6288       "     minBufferTime=\"P0Y1M2DT12H10M20.5S\""
6289       "     timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
6290       "     suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
6291       "     maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
6292       "     maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\">"
6293       "     <BaseURL serviceLocation=\"TestServiceLocation\""
6294       "     byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
6295       "     <Location>TestLocation</Location>"
6296       "     <ProgramInformation lang=\"en\""
6297       "     moreInformationURL=\"TestMoreInformationUrl\">"
6298       "     <Title>TestTitle</Title>"
6299       "     <Source>TestSource</Source>"
6300       "     <Copyright>TestCopyright</Copyright>"
6301       "     </ProgramInformation>"
6302       "     <Metrics metrics=\"TestMetric\"><Range starttime=\"P0Y1M2DT12H10M20.5S\""
6303       "           duration=\"P0Y1M2DT12H10M20.1234567S\">"
6304       "    </Range></Metrics>"
6305       "  <Period id=\"TestId\" start=\"PT1M\" duration=\"PT40S\""
6306       "          bitstreamSwitching=\"true\">"
6307       "    <AdaptationSet id=\"9\" contentType=\"video\" mimeType=\"video\">"
6308       "      <Representation id=\"audio_1\" "
6309       "                      bandwidth=\"100\""
6310       "                      qualityRanking=\"200\""
6311       "                      width=\"640\""
6312       "                      height=\"480\""
6313       "                      codecs=\"avc1\""
6314       "                      audioSamplingRate=\"44100\""
6315       "                      mimeType=\"audio/mp4\">"
6316       "        <SegmentList duration=\"15\" startNumber=\"11\">"
6317       "          <SegmentURL media=\"segment001.ts\"></SegmentURL>"
6318       "          <SegmentURL media=\"segment002.ts\"></SegmentURL>"
6319       "        </SegmentList>"
6320       "      </Representation></AdaptationSet></Period>" "     </MPD>";
6321   gboolean ret;
6322   gchar *period_id;
6323   guint adaptation_set_id;
6324   gchar *representation_id;
6325   GstMPDClient *first_mpdclient = NULL;
6326   GstMPDClient *second_mpdclient = NULL;
6327   GstMPDBaseURLNode *first_baseURL, *second_baseURL;
6328   GstMPDPeriodNode *first_period, *second_period;
6329   GstMPDAdaptationSetNode *first_adap_set, *second_adap_set;
6330   GstMPDRepresentationNode *first_rep, *second_rep;
6331   GstMPDSegmentListNode *first_seg_list, *second_seg_list;
6332   GstMPDSegmentURLNode *first_seg_url, *second_seg_url;
6333 
6334   first_mpdclient = gst_mpd_client_new ();
6335 
6336   ret = gst_mpd_client_parse (first_mpdclient, xml, (gint) strlen (xml));
6337   assert_equals_int (ret, TRUE);
6338 
6339   second_mpdclient = gst_mpd_client_new ();
6340   gst_mpd_client_set_root_node (second_mpdclient,
6341       "default-namespace", "urn:mpeg:dash:schema:mpd:2011",
6342       "profiles", "urn:mpeg:dash:profile:isoff-main:2011",
6343       "schema-location", "TestSchemaLocation",
6344       "namespace-xsi", "TestNamespaceXSI",
6345       "namespace-ext", "TestNamespaceEXT", "id", "testId", NULL);
6346   gst_mpd_client_add_baseurl_node (second_mpdclient,
6347       "url", "TestBaseURL",
6348       "service-location", "TestServiceLocation",
6349       "byte-range", "TestByteRange", NULL);
6350   period_id = gst_mpd_client_set_period_node (second_mpdclient, (gchar *) "TestId", "start", (guint64) 60000,   // ms
6351       "duration", (guint64) 40000, "bitstream-switching", 1, NULL);
6352   adaptation_set_id =
6353       gst_mpd_client_set_adaptation_set_node (second_mpdclient, period_id, 9,
6354       "content-type", "video", "mime-type", "video", NULL);
6355 
6356   representation_id =
6357       gst_mpd_client_set_representation_node (second_mpdclient, period_id,
6358       adaptation_set_id, (gchar *) "audio_1", "bandwidth", 100,
6359       "quality-ranking", 200, "mime-type", "audio/mp4", "width", 640, "height",
6360       480, "codecs", "avc1", "audio-sampling-rate", 44100, NULL);
6361 
6362   gst_mpd_client_set_segment_list (second_mpdclient, period_id,
6363       adaptation_set_id, representation_id, "duration", 15, "start-number", 11,
6364       NULL);
6365   gst_mpd_client_add_segment_url (second_mpdclient, period_id,
6366       adaptation_set_id, representation_id, "media", "segment001.ts", NULL);
6367   gst_mpd_client_add_segment_url (second_mpdclient, period_id,
6368       adaptation_set_id, representation_id, "media", "segment002.ts", NULL);
6369 
6370   /* assert that parameters are equal */
6371   assert_equals_string (first_mpdclient->mpd_root_node->default_namespace,
6372       second_mpdclient->mpd_root_node->default_namespace);
6373   assert_equals_string (first_mpdclient->mpd_root_node->namespace_xsi,
6374       second_mpdclient->mpd_root_node->namespace_xsi);
6375   assert_equals_string (first_mpdclient->mpd_root_node->namespace_ext,
6376       second_mpdclient->mpd_root_node->namespace_ext);
6377   assert_equals_string (first_mpdclient->mpd_root_node->schemaLocation,
6378       second_mpdclient->mpd_root_node->schemaLocation);
6379   assert_equals_string (first_mpdclient->mpd_root_node->id,
6380       second_mpdclient->mpd_root_node->id);
6381   assert_equals_string (first_mpdclient->mpd_root_node->profiles,
6382       second_mpdclient->mpd_root_node->profiles);
6383 
6384 
6385   /* baseURLs */
6386   first_baseURL =
6387       (GstMPDBaseURLNode *) first_mpdclient->mpd_root_node->BaseURLs->data;
6388   second_baseURL =
6389       (GstMPDBaseURLNode *) second_mpdclient->mpd_root_node->BaseURLs->data;
6390   assert_equals_string (first_baseURL->baseURL, second_baseURL->baseURL);
6391   assert_equals_string (first_baseURL->serviceLocation,
6392       second_baseURL->serviceLocation);
6393   assert_equals_string (first_baseURL->byteRange, second_baseURL->byteRange);
6394 
6395   /* Period */
6396   first_period =
6397       (GstMPDPeriodNode *) first_mpdclient->mpd_root_node->Periods->data;
6398   second_period =
6399       (GstMPDPeriodNode *) second_mpdclient->mpd_root_node->Periods->data;
6400 
6401   assert_equals_string (first_period->id, second_period->id);
6402   assert_equals_int64 (first_period->start, second_period->start);
6403   assert_equals_int64 (first_period->duration, second_period->duration);
6404   assert_equals_int (first_period->bitstreamSwitching,
6405       second_period->bitstreamSwitching);
6406 
6407   /* Adaptation set */
6408   first_adap_set =
6409       (GstMPDAdaptationSetNode *) first_period->AdaptationSets->data;
6410   second_adap_set =
6411       (GstMPDAdaptationSetNode *) second_period->AdaptationSets->data;
6412 
6413   assert_equals_int (first_adap_set->id, second_adap_set->id);
6414   assert_equals_string (first_adap_set->contentType,
6415       second_adap_set->contentType);
6416   assert_equals_string (GST_MPD_REPRESENTATION_BASE_NODE
6417       (first_adap_set)->mimeType,
6418       GST_MPD_REPRESENTATION_BASE_NODE (second_adap_set)->mimeType);
6419 
6420   /* Representation */
6421   first_rep =
6422       (GstMPDRepresentationNode *) first_adap_set->Representations->data;
6423   second_rep =
6424       (GstMPDRepresentationNode *) second_adap_set->Representations->data;
6425   assert_equals_string (first_rep->id, second_rep->id);
6426   assert_equals_int (first_rep->bandwidth, second_rep->bandwidth);
6427   assert_equals_int (first_rep->qualityRanking, second_rep->qualityRanking);
6428   assert_equals_string (GST_MPD_REPRESENTATION_BASE_NODE (first_rep)->mimeType,
6429       GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->mimeType);
6430 
6431   assert_equals_int (GST_MPD_REPRESENTATION_BASE_NODE (first_rep)->width,
6432       GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->width);
6433 
6434   assert_equals_int (GST_MPD_REPRESENTATION_BASE_NODE (first_rep)->height,
6435       GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->height);
6436 
6437   assert_equals_string (GST_MPD_REPRESENTATION_BASE_NODE (first_rep)->codecs,
6438       GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->codecs);
6439 
6440   assert_equals_string (GST_MPD_REPRESENTATION_BASE_NODE
6441       (first_rep)->audioSamplingRate,
6442       GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->audioSamplingRate);
6443 
6444   /*SegmentList */
6445   first_seg_list = (GstMPDSegmentListNode *) first_rep->SegmentList;
6446   second_seg_list = (GstMPDSegmentListNode *) second_rep->SegmentList;
6447   assert_equals_int (GST_MPD_MULT_SEGMENT_BASE_NODE (first_seg_list)->duration,
6448       GST_MPD_MULT_SEGMENT_BASE_NODE (second_seg_list)->duration);
6449   assert_equals_int (GST_MPD_MULT_SEGMENT_BASE_NODE
6450       (first_seg_list)->startNumber,
6451       GST_MPD_MULT_SEGMENT_BASE_NODE (second_seg_list)->startNumber);
6452 
6453   first_seg_url = (GstMPDSegmentURLNode *) first_seg_list->SegmentURL->data;
6454   second_seg_url = (GstMPDSegmentURLNode *) second_seg_list->SegmentURL->data;
6455 
6456   assert_equals_string (first_seg_url->media, second_seg_url->media);
6457 
6458 
6459   gst_mpd_client_free (first_mpdclient);
6460   gst_mpd_client_free (second_mpdclient);
6461 }
6462 
6463 GST_END_TEST;
6464 
6465 /*
6466  * create a test suite containing all dash testcases
6467  */
6468 static Suite *
dash_suite(void)6469 dash_suite (void)
6470 {
6471   Suite *s = suite_create ("dash");
6472   TCase *tc_simpleMPD = tcase_create ("simpleMPD");
6473   TCase *tc_complexMPD = tcase_create ("complexMPD");
6474   TCase *tc_negativeTests = tcase_create ("negativeTests");
6475   TCase *tc_stringTests = tcase_create ("stringTests");
6476   TCase *tc_duration = tcase_create ("duration");
6477 
6478   GST_DEBUG_CATEGORY_INIT (gst_dash_demux_debug, "gst_dash_demux_debug", 0,
6479       "mpeg dash tests");
6480 
6481   /* test parsing the simplest possible mpd */
6482   tcase_add_test (tc_simpleMPD, dash_mpdparser_validsimplempd);
6483 
6484   /* test parsing the simplest possible mpd */
6485   tcase_add_test (tc_simpleMPD, dash_mpdparser_check_mpd_xml_generator);
6486 
6487   /* test mpd client set methods */
6488   tcase_add_test (tc_simpleMPD, dash_mpdparser_check_mpd_client_set_methods);
6489 
6490   /* tests parsing attributes from each element type */
6491   tcase_add_test (tc_simpleMPD, dash_mpdparser_mpd);
6492   tcase_add_test (tc_simpleMPD, dash_mpdparser_datetime_with_tz_offset);
6493   tcase_add_test (tc_simpleMPD, dash_mpdparser_programInformation);
6494   tcase_add_test (tc_simpleMPD, dash_mpdparser_baseURL);
6495   tcase_add_test (tc_simpleMPD, dash_mpdparser_location);
6496   tcase_add_test (tc_simpleMPD, dash_mpdparser_metrics);
6497   tcase_add_test (tc_simpleMPD, dash_mpdparser_metrics_range);
6498   tcase_add_test (tc_simpleMPD, dash_mpdparser_metrics_reporting);
6499   tcase_add_test (tc_simpleMPD, dash_mpdparser_period);
6500   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_baseURL);
6501   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentBase);
6502   tcase_add_test (tc_simpleMPD,
6503       dash_mpdparser_period_segmentBase_initialization);
6504   tcase_add_test (tc_simpleMPD,
6505       dash_mpdparser_period_segmentBase_representationIndex);
6506   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentList);
6507   tcase_add_test (tc_simpleMPD,
6508       dash_mpdparser_period_segmentList_multipleSegmentBaseType);
6509   tcase_add_test (tc_simpleMPD,
6510       dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentBaseType);
6511   tcase_add_test (tc_simpleMPD,
6512       dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline);
6513   tcase_add_test (tc_simpleMPD,
6514       dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline_s);
6515   tcase_add_test (tc_simpleMPD,
6516       dash_mpdparser_period_segmentList_multipleSegmentBaseType_bitstreamSwitching);
6517   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentList_segmentURL);
6518   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentTemplate);
6519   tcase_add_test (tc_simpleMPD,
6520       dash_mpdparser_period_segmentTemplateWithPresentationTimeOffset);
6521   tcase_add_test (tc_simpleMPD,
6522       dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType);
6523   tcase_add_test (tc_simpleMPD,
6524       dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentBaseType);
6525   tcase_add_test (tc_simpleMPD,
6526       dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline);
6527   tcase_add_test (tc_simpleMPD,
6528       dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline_s);
6529   tcase_add_test (tc_simpleMPD,
6530       dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_bitstreamSwitching);
6531   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet);
6532   tcase_add_test (tc_simpleMPD,
6533       dash_mpdparser_period_adaptationSet_representationBase);
6534   tcase_add_test (tc_simpleMPD,
6535       dash_mpdparser_period_adaptationSet_representationBase_framePacking);
6536   tcase_add_test (tc_simpleMPD,
6537       dash_mpdparser_adapt_repr_segmentTemplate_inherit);
6538   tcase_add_test (tc_simpleMPD,
6539       dash_mpdparser_period_adaptationSet_representationBase_audioChannelConfiguration);
6540   tcase_add_test (tc_simpleMPD,
6541       dash_mpdparser_period_adaptationSet_representationBase_contentProtection);
6542   tcase_add_test (tc_simpleMPD, dash_mpdparser_contentProtection_no_value);
6543   tcase_add_test (tc_simpleMPD,
6544       dash_mpdparser_contentProtection_no_value_no_encoding);
6545   tcase_add_test (tc_simpleMPD,
6546       dash_mpdparser_period_adaptationSet_representationBase_contentProtection_with_content);
6547   tcase_add_test (tc_simpleMPD,
6548       dash_mpdparser_period_adaptationSet_representationBase_contentProtection_xml_namespaces);
6549   tcase_add_test (tc_simpleMPD,
6550       dash_mpdparser_period_adaptationSet_accessibility);
6551   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet_role);
6552   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet_rating);
6553   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet_viewpoint);
6554   tcase_add_test (tc_simpleMPD,
6555       dash_mpdparser_period_adaptationSet_contentComponent);
6556   tcase_add_test (tc_simpleMPD,
6557       dash_mpdparser_period_adaptationSet_contentComponent_accessibility);
6558   tcase_add_test (tc_simpleMPD,
6559       dash_mpdparser_period_adaptationSet_contentComponent_role);
6560   tcase_add_test (tc_simpleMPD,
6561       dash_mpdparser_period_adaptationSet_contentComponent_rating);
6562   tcase_add_test (tc_simpleMPD,
6563       dash_mpdparser_period_adaptationSet_contentComponent_viewpoint);
6564   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet_baseURL);
6565   tcase_add_test (tc_simpleMPD,
6566       dash_mpdparser_period_adaptationSet_segmentBase);
6567   tcase_add_test (tc_simpleMPD,
6568       dash_mpdparser_period_adaptationSet_segmentBase_initialization);
6569   tcase_add_test (tc_simpleMPD,
6570       dash_mpdparser_period_adaptationSet_segmentBase_representationIndex);
6571   tcase_add_test (tc_simpleMPD,
6572       dash_mpdparser_period_adaptationSet_segmentList);
6573   tcase_add_test (tc_simpleMPD,
6574       dash_mpdparser_period_adaptationSet_segmentTemplate);
6575   tcase_add_test (tc_simpleMPD,
6576       dash_mpdparser_period_adaptationSet_segmentTemplate_inherit);
6577   tcase_add_test (tc_simpleMPD,
6578       dash_mpdparser_period_adaptationSet_representation);
6579   tcase_add_test (tc_simpleMPD,
6580       dash_mpdparser_period_adaptationSet_representation_representationBase);
6581   tcase_add_test (tc_simpleMPD,
6582       dash_mpdparser_period_adaptationSet_representation_baseURL);
6583   tcase_add_test (tc_simpleMPD,
6584       dash_mpdparser_period_adaptationSet_representation_subRepresentation);
6585   tcase_add_test (tc_simpleMPD,
6586       dash_mpdparser_period_adaptationSet_representation_subRepresentation_representationBase);
6587   tcase_add_test (tc_simpleMPD,
6588       dash_mpdparser_period_adaptationSet_representation_segmentBase);
6589   tcase_add_test (tc_simpleMPD,
6590       dash_mpdparser_period_adaptationSet_representation_segmentList);
6591   tcase_add_test (tc_simpleMPD,
6592       dash_mpdparser_period_adaptationSet_representation_segmentTemplate);
6593   tcase_add_test (tc_simpleMPD,
6594       dash_mpdparser_period_adaptationSet_representation_segmentTemplate_inherit);
6595   tcase_add_test (tc_simpleMPD,
6596       dash_mpdparser_period_adaptationSet_representation_segmentBase_inherit);
6597   tcase_add_test (tc_simpleMPD, dash_mpdparser_period_subset);
6598   tcase_add_test (tc_simpleMPD, dash_mpdparser_utctiming);
6599   tcase_add_test (tc_simpleMPD, dash_mpdparser_utctiming_invalid_value);
6600 
6601   /* tests checking other possible values for attributes */
6602   tcase_add_test (tc_simpleMPD, dash_mpdparser_type_dynamic);
6603   tcase_add_test (tc_simpleMPD, dash_mpdparser_template_parsing);
6604   tcase_add_test (tc_simpleMPD, dash_mpdparser_isoff_ondemand_profile);
6605   tcase_add_test (tc_simpleMPD, dash_mpdparser_GstDateTime);
6606   tcase_add_test (tc_simpleMPD, dash_mpdparser_bitstreamSwitching_inheritance);
6607   tcase_add_test (tc_simpleMPD, dash_mpdparser_various_duration_formats);
6608   tcase_add_test (tc_simpleMPD, dash_mpdparser_default_presentation_delay);
6609 
6610   /* tests checking xlink attributes */
6611   tcase_add_test (tc_simpleMPD, dash_mpdparser_xlink_period);
6612 
6613   /* tests checking the MPD management
6614    * (eg. setting active streams, obtaining attributes values)
6615    */
6616   tcase_add_test (tc_complexMPD, dash_mpdparser_setup_media_presentation);
6617   tcase_add_test (tc_complexMPD, dash_mpdparser_setup_streaming);
6618   tcase_add_test (tc_complexMPD, dash_mpdparser_period_selection);
6619   tcase_add_test (tc_complexMPD, dash_mpdparser_get_period_at_time);
6620   tcase_add_test (tc_complexMPD, dash_mpdparser_adaptationSet_handling);
6621   tcase_add_test (tc_complexMPD, dash_mpdparser_representation_selection);
6622   tcase_add_test (tc_complexMPD, dash_mpdparser_multipleSegmentURL);
6623   tcase_add_test (tc_complexMPD, dash_mpdparser_activeStream_selection);
6624   tcase_add_test (tc_complexMPD, dash_mpdparser_activeStream_parameters);
6625   tcase_add_test (tc_complexMPD, dash_mpdparser_get_audio_languages);
6626   tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL1);
6627   tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL2);
6628   tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL3);
6629   tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL4);
6630   tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL5);
6631   tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL6);
6632   tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL7);
6633   tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL8);
6634   tcase_add_test (tc_complexMPD, dash_mpdparser_get_mediaPresentationDuration);
6635   tcase_add_test (tc_complexMPD, dash_mpdparser_get_streamPresentationOffset);
6636   tcase_add_test (tc_complexMPD, dash_mpdparser_segments);
6637   tcase_add_test (tc_complexMPD, dash_mpdparser_headers);
6638   tcase_add_test (tc_complexMPD, dash_mpdparser_fragments);
6639   tcase_add_test (tc_complexMPD, dash_mpdparser_inherited_segmentBase);
6640   tcase_add_test (tc_complexMPD, dash_mpdparser_inherited_segmentURL);
6641   tcase_add_test (tc_complexMPD, dash_mpdparser_segment_list);
6642   tcase_add_test (tc_complexMPD, dash_mpdparser_segment_template);
6643   tcase_add_test (tc_complexMPD, dash_mpdparser_segment_timeline);
6644   tcase_add_test (tc_complexMPD, dash_mpdparser_multiple_inherited_segmentURL);
6645 
6646   /* tests checking the parsing of missing/incomplete attributes of xml */
6647   tcase_add_test (tc_negativeTests, dash_mpdparser_missing_xml);
6648   tcase_add_test (tc_negativeTests, dash_mpdparser_missing_mpd);
6649   tcase_add_test (tc_negativeTests, dash_mpdparser_no_end_tag);
6650   tcase_add_test (tc_negativeTests, dash_mpdparser_no_profiles);
6651   tcase_add_test (tc_negativeTests, dash_mpdparser_no_default_namespace);
6652   tcase_add_test (tc_negativeTests,
6653       dash_mpdparser_wrong_period_duration_inferred_from_next_period);
6654   tcase_add_test (tc_negativeTests,
6655       dash_mpdparser_wrong_period_duration_inferred_from_next_mediaPresentationDuration);
6656   tcase_add_test (tc_negativeTests, dash_mpdparser_negative_period_duration);
6657   tcase_add_test (tc_negativeTests,
6658       dash_mpdparser_read_unsigned_from_negative_values);
6659   tcase_add_test (tc_negativeTests,
6660       dash_mpdparser_negative_mediaPresentationDuration);
6661   tcase_add_test (tc_negativeTests,
6662       dash_mpdparser_unmatched_segmentTimeline_segmentURL);
6663 
6664   tcase_add_test (tc_stringTests, dash_mpdparser_whitespace_strings);
6665   tcase_add_test (tc_stringTests, dash_mpdparser_rfc1738_strings);
6666 
6667   tcase_add_test (tc_duration, dash_mpdparser_duration);
6668   tcase_add_test (tc_duration, dash_mpdparser_maximum_segment_duration);
6669 
6670   suite_add_tcase (s, tc_simpleMPD);
6671   suite_add_tcase (s, tc_complexMPD);
6672   suite_add_tcase (s, tc_negativeTests);
6673   suite_add_tcase (s, tc_stringTests);
6674   suite_add_tcase (s, tc_duration);
6675 
6676   return s;
6677 }
6678 
6679 GST_CHECK_MAIN (dash);
6680