Initialize Tizen 2.3
[framework/multimedia/gst-plugins-ext0.10.git] / wearable / dashdemux / src / gstmpdparser.c
1 /*
2  * DASH MPD parsing library
3  *
4  * gstmpdparser.c
5  *
6  * Copyright (C) 2012 STMicroelectronics
7  *
8  * Authors:
9  *   Gianluca Gennari <gennarone@gmail.com>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public
22  * License along with this library (COPYING); if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  */
26
27 #include <string.h>
28 #include <libxml/tree.h>
29 #include "gstfragmented.h"
30 #include "gstmpdparser.h"
31
32 #define GST_CAT_DEFAULT fragmented_debug
33
34 /* Property parsing */
35 static gchar *gst_mpdparser_get_xml_prop_string (xmlNode * a_node,
36     const gchar * property);
37 static gchar **gst_mpdparser_get_xml_prop_string_vector_type (xmlNode * a_node,
38     const gchar * property);
39 static guint gst_mpdparser_get_xml_prop_unsigned_integer (xmlNode * a_node,
40     const gchar * property, guint default_val);
41 static guint *gst_mpdparser_get_xml_prop_uint_vector_type (xmlNode * a_node,
42     const gchar * property, guint * size);
43 static gdouble gst_mpdparser_get_xml_prop_double (xmlNode * a_node,
44     const gchar * property);
45 static gboolean gst_mpdparser_get_xml_prop_boolean (xmlNode * a_node,
46     const gchar * property);
47 static GstMPDFileType gst_mpdparser_get_xml_prop_type (xmlNode * a_node,
48     const gchar * property);
49 static GstSAPType gst_mpdparser_get_xml_prop_SAP_type (xmlNode * a_node,
50     const gchar * property);
51 static GstRange *gst_mpdparser_get_xml_prop_range (xmlNode * a_node,
52     const gchar * property);
53 static GstRatio *gst_mpdparser_get_xml_prop_ratio (xmlNode * a_node,
54     const gchar * property);
55 static GstFrameRate *gst_mpdparser_get_xml_prop_framerate (xmlNode * a_node,
56     const gchar * property);
57 static GstConditionalUintType *gst_mpdparser_get_xml_prop_cond_uint (xmlNode *
58     a_node, const gchar * property);
59 static GstDateTime *gst_mpdparser_get_xml_prop_dateTime (xmlNode * a_node,
60     const gchar * property);
61 static gint64 gst_mpdparser_get_xml_prop_duration (xmlNode * a_node,
62     const gchar * property);
63 static gchar *gst_mpdparser_get_xml_node_content (xmlNode * a_node);
64 static gchar *gst_mpdparser_get_xml_node_namespace (xmlNode * a_node,
65     const gchar * prefix);
66
67 /* XML node parsing */
68 static void gst_mpdparser_parse_baseURL_node (GList ** list, xmlNode * a_node);
69 static void gst_mpdparser_parse_descriptor_type_node (GList ** list,
70     xmlNode * a_node);
71 static void gst_mpdparser_parse_content_component_node (GList ** list,
72     xmlNode * a_node);
73 static void gst_mpdparser_parse_location_node (GList ** list, xmlNode * a_node);
74 static void gst_mpdparser_parse_subrepresentation_node (GList ** list,
75     xmlNode * a_node);
76 static void gst_mpdparser_parse_segment_url_node (GList ** list,
77     xmlNode * a_node);
78 static void gst_mpdparser_parse_url_type_node (GstURLType ** pointer,
79     xmlNode * a_node);
80 static void gst_mpdparser_parse_seg_base_type_ext (GstSegmentBaseType **
81     pointer, xmlNode * a_node);
82 static void gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node);
83 static void gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode **
84     pointer, xmlNode * a_node);
85 static void gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType
86     ** pointer, xmlNode * a_node);
87 static void gst_mpdparser_parse_segment_list_node (GstSegmentListNode **
88     pointer, xmlNode * a_node);
89 static void
90 gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType **
91     pointer, xmlNode * a_node);
92 static void gst_mpdparser_parse_representation_node (GList ** list,
93     xmlNode * a_node);
94 static void gst_mpdparser_parse_adaptation_set_node (GList ** list,
95     xmlNode * a_node);
96 static void gst_mpdparser_parse_subset_node (GList ** list, xmlNode * a_node);
97 static void gst_mpdparser_parse_segment_template_node (GstSegmentTemplateNode **
98     pointer, xmlNode * a_node);
99 static void gst_mpdparser_parse_period_node (GList ** list, xmlNode * a_node);
100 static void gst_mpdparser_parse_program_info_node (GList ** list,
101     xmlNode * a_node);
102 static void gst_mpdparser_parse_metrics_range_node (GList ** list,
103     xmlNode * a_node);
104 static void gst_mpdparser_parse_metrics_node (GList ** list, xmlNode * a_node);
105 static void gst_mpdparser_parse_root_node (GstMPDNode ** pointer,
106     xmlNode * a_node);
107
108 /* Helper functions */
109 static gint convert_to_millisecs (gint decimals, gint pos);
110 static int strncmp_ext (const char *s1, const char *s2);
111 static GstStreamPeriod *gst_mpdparser_get_stream_period (GstMpdClient * client);
112 static gchar *gst_mpdparser_parse_baseURL (GstMpdClient * client);
113 static gchar *gst_mpdparser_get_segmentURL_for_range (gchar * url,
114     GstRange * range);
115 static gchar *gst_mpdparser_get_mediaURL (GstMpdClient * client,
116     GstSegmentURLNode * segmentURL);
117 static gchar *gst_mpdparser_get_initializationURL (GstURLType *
118     InitializationURL);
119 static gchar *gst_mpdparser_build_URL_from_template (const gchar * url_template,
120     const gchar * id, guint number, guint bandwidth, guint time);
121 static gboolean gst_mpd_client_add_media_segment (GstActiveStream * stream,
122     GstSegmentURLNode * url_node, guint number, guint start,
123     GstClockTime start_time, GstClockTime duration);
124 static const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType);
125 static GstClockTime gst_mpd_client_get_segment_duration (GstMpdClient * client);
126 static void gst_mpd_client_set_segment_index (GstActiveStream * stream,
127     guint segment_idx);
128
129 /* Adaptation Set */
130 static GstAdaptationSetNode
131     *gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets,
132     const gchar * mimeType);
133 static GstAdaptationSetNode
134     *gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
135     const gchar * mimeType, gint idx);
136 static GstAdaptationSetNode
137     *gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *
138     AdaptationSets, const gchar * mimeType, const gchar * lang);
139
140 /* Representation */
141 static GstRepresentationNode *gst_mpdparser_get_lowest_representation (GList *
142     Representations);
143 #if 0
144 static GstRepresentationNode *gst_mpdparser_get_highest_representation (GList *
145     Representations);
146 static GstRepresentationNode
147     *gst_mpdparser_get_representation_with_max_bandwidth (GList *
148     Representations, gint max_bandwidth);
149 #endif
150 static GstSegmentBaseType *gst_mpdparser_get_segment_base (GstPeriodNode *
151     Period, GstAdaptationSetNode * AdaptationSet,
152     GstRepresentationNode * Representation);
153 static GstSegmentListNode *gst_mpdparser_get_segment_list (GstPeriodNode *
154     Period, GstAdaptationSetNode * AdaptationSet,
155     GstRepresentationNode * Representation);
156
157 /* Memory management */
158 static void gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node);
159 static void gst_mpdparser_free_prog_info_node (GstProgramInformationNode *
160     prog_info_node);
161 static void gst_mpdparser_free_metrics_node (GstMetricsNode * metrics_node);
162 static void gst_mpdparser_free_metrics_range_node (GstMetricsRangeNode *
163     metrics_range_node);
164 static void gst_mpdparser_free_period_node (GstPeriodNode * period_node);
165 static void gst_mpdparser_free_subset_node (GstSubsetNode * subset_node);
166 static void gst_mpdparser_free_segment_template_node (GstSegmentTemplateNode *
167     segment_template_node);
168 static void
169 gst_mpdparser_free_representation_base_type (GstRepresentationBaseType *
170     representation_base);
171 static void gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode *
172     adaptation_set_node);
173 static void gst_mpdparser_free_representation_node (GstRepresentationNode *
174     representation_node);
175 static void gst_mpdparser_free_subrepresentation_node (GstSubRepresentationNode
176     * subrep_node);
177 static void gst_mpdparser_free_s_node (GstSNode * s_node);
178 static void gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode *
179     seg_timeline);
180 static void gst_mpdparser_free_url_type_node (GstURLType * url_type_node);
181 static void gst_mpdparser_free_seg_base_type_ext (GstSegmentBaseType *
182     seg_base_type);
183 static void gst_mpdparser_free_mult_seg_base_type_ext (GstMultSegmentBaseType *
184     mult_seg_base_type);
185 static void gst_mpdparser_free_segment_list_node (GstSegmentListNode *
186     segment_list_node);
187 static void gst_mpdparser_free_segment_url_node (GstSegmentURLNode *
188     segment_url);
189 static void gst_mpdparser_free_base_url_node (GstBaseURL * base_url_node);
190 static void gst_mpdparser_free_descriptor_type_node (GstDescriptorType *
191     descriptor_type);
192 static void gst_mpdparser_free_content_component_node (GstContentComponentNode *
193     content_component_node);
194 static void gst_mpdparser_free_stream_period (GstStreamPeriod * stream_period);
195 static void gst_mpdparser_free_media_segment (GstMediaSegment * media_segment);
196 static void gst_mpdparser_free_active_stream (GstActiveStream * active_stream);
197
198 /* functions to parse node namespaces, content and properties */
199 static gchar *
200 gst_mpdparser_get_xml_prop_string (xmlNode * a_node, const gchar * property)
201 {
202   xmlChar *prop_string;
203
204   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
205   if (prop_string) {
206     GST_LOG (" - %s: %s", property, prop_string);
207   }
208
209   return (gchar *) prop_string;
210 }
211
212 static gchar **
213 gst_mpdparser_get_xml_prop_string_vector_type (xmlNode * a_node,
214     const gchar * property)
215 {
216   xmlChar *prop_string;
217   gchar **prop_string_vector = NULL;
218   guint i = 0;
219
220   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
221   if (prop_string) {
222     prop_string_vector = g_strsplit ((gchar *) prop_string, " ", -1);
223     if (!prop_string_vector) {
224       GST_WARNING ("Scan of string vector property failed!");
225       return NULL;
226     }
227     GST_LOG (" - %s:", property);
228     while (prop_string_vector[i]) {
229       GST_LOG ("    %s", prop_string_vector[i]);
230       i++;
231     }
232     xmlFree (prop_string);
233   }
234
235   return prop_string_vector;
236 }
237
238 static guint
239 gst_mpdparser_get_xml_prop_unsigned_integer (xmlNode * a_node,
240     const gchar * property, guint default_val)
241 {
242   xmlChar *prop_string;
243   guint prop_unsigned_integer = default_val;
244
245   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
246   if (prop_string) {
247     if (sscanf ((gchar *) prop_string, "%u", &prop_unsigned_integer)) {
248       GST_LOG (" - %s: %u", property, prop_unsigned_integer);
249     } else {
250       GST_WARNING
251           ("failed to parse unsigned integer property %s from xml string %s",
252           property, prop_string);
253     }
254     xmlFree (prop_string);
255   }
256
257   return prop_unsigned_integer;
258 }
259
260 static guint *
261 gst_mpdparser_get_xml_prop_uint_vector_type (xmlNode * a_node,
262     const gchar * property, guint * size)
263 {
264   xmlChar *prop_string;
265   gchar **str_vector;
266   guint *prop_uint_vector = NULL, i;
267
268   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
269   if (prop_string) {
270     str_vector = g_strsplit ((gchar *) prop_string, " ", -1);
271     if (!str_vector) {
272       GST_WARNING ("Scan of uint vector property failed!");
273       return NULL;
274     }
275     *size = g_strv_length (str_vector);
276     prop_uint_vector = g_malloc (*size * sizeof (guint));
277     if (!prop_uint_vector) {
278       GST_WARNING ("Array allocation failed!");
279     } else {
280       GST_LOG (" - %s:", property);
281       for (i = 0; i < *size; i++) {
282         if (sscanf ((gchar *) str_vector[i], "%u", &prop_uint_vector[i])) {
283           GST_LOG ("    %u", prop_uint_vector[i]);
284         } else {
285           GST_WARNING
286               ("failed to parse uint vector type property %s from xml string %s",
287               property, str_vector[i]);
288         }
289       }
290     }
291     xmlFree (prop_string);
292     g_strfreev (str_vector);
293   }
294
295   return prop_uint_vector;
296 }
297
298 static gdouble
299 gst_mpdparser_get_xml_prop_double (xmlNode * a_node, const gchar * property)
300 {
301   xmlChar *prop_string;
302   gdouble prop_double = 0;
303
304   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
305   if (prop_string) {
306     if (sscanf ((gchar *) prop_string, "%lf", &prop_double)) {
307       GST_LOG (" - %s: %lf", property, prop_double);
308     } else {
309       GST_WARNING ("failed to parse double property %s from xml string %s",
310           property, prop_string);
311     }
312     xmlFree (prop_string);
313   }
314
315   return prop_double;
316 }
317
318 static gboolean
319 gst_mpdparser_get_xml_prop_boolean (xmlNode * a_node, const gchar * property)
320 {
321   xmlChar *prop_string;
322   gboolean prop_bool = FALSE;
323
324   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
325   if (prop_string) {
326     if (xmlStrcmp (prop_string, (xmlChar *) "false") == 0) {
327       GST_LOG (" - %s: false", property);
328     } else if (xmlStrcmp (prop_string, (xmlChar *) "true") == 0) {
329       GST_LOG (" - %s: true", property);
330       prop_bool = TRUE;
331     } else {
332       GST_WARNING ("failed to parse boolean property %s from xml string %s",
333           property, prop_string);
334     }
335     xmlFree (prop_string);
336   }
337
338   return prop_bool;
339 }
340
341 static GstMPDFileType
342 gst_mpdparser_get_xml_prop_type (xmlNode * a_node, const gchar * property)
343 {
344   xmlChar *prop_string;
345   GstMPDFileType prop_type = GST_MPD_FILE_TYPE_STATIC;  /* default */
346
347   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
348   if (prop_string) {
349     if (xmlStrcmp (prop_string, (xmlChar *) "OnDemand") == 0
350         || xmlStrcmp (prop_string, (xmlChar *) "static") == 0) {
351       GST_LOG (" - %s: static", property);
352       prop_type = GST_MPD_FILE_TYPE_STATIC;
353     } else if (xmlStrcmp (prop_string, (xmlChar *) "Live") == 0
354         || xmlStrcmp (prop_string, (xmlChar *) "dynamic") == 0) {
355       GST_LOG (" - %s: dynamic", property);
356       prop_type = GST_MPD_FILE_TYPE_DYNAMIC;
357     } else {
358       GST_WARNING ("failed to parse MPD type property %s from xml string %s",
359           property, prop_string);
360     }
361     xmlFree (prop_string);
362   }
363
364   return prop_type;
365 }
366
367 static GstSAPType
368 gst_mpdparser_get_xml_prop_SAP_type (xmlNode * a_node, const gchar * property)
369 {
370   xmlChar *prop_string;
371   guint prop_SAP_type = 0;
372
373   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
374   if (prop_string) {
375     if (sscanf ((gchar *) prop_string, "%u", &prop_SAP_type)
376         && prop_SAP_type <= 6) {
377       GST_LOG (" - %s: %u", property, prop_SAP_type);
378     } else {
379       GST_WARNING
380           ("failed to parse unsigned integer property %s from xml string %s",
381           property, prop_string);
382     }
383     xmlFree (prop_string);
384   }
385
386   return (GstSAPType) prop_SAP_type;
387 }
388
389 static GstRange *
390 gst_mpdparser_get_xml_prop_range (xmlNode * a_node, const gchar * property)
391 {
392   xmlChar *prop_string;
393   GstRange *prop_range = NULL;
394   guint64 first_byte_pos = 0, last_byte_pos = 0;
395   guint len, pos;
396   gchar *str;
397
398   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
399   if (prop_string) {
400     len = xmlStrlen (prop_string);
401     str = (gchar *) prop_string;
402     GST_TRACE ("range: %s, len %d", str, len);
403
404     /* read "-" */
405     pos = strcspn (str, "-");
406     if (pos >= len) {
407       GST_TRACE ("pos %d >= len %d", pos, len);
408       goto error;
409     }
410     /* read first_byte_pos */
411     if (pos != 0) {
412       if (sscanf (str, "%llu", &first_byte_pos) != 1) {
413         goto error;
414       }
415     }
416     /* read last_byte_pos */
417     if (pos < (len - 1)) {
418       if (sscanf (str + pos + 1, "%llu", &last_byte_pos) != 1) {
419         goto error;
420       }
421     }
422     /* malloc return data structure */
423     prop_range = g_slice_new0 (GstRange);
424     if (prop_range == NULL) {
425       GST_WARNING ("Allocation of GstRange failed!");
426       goto error;
427     }
428     prop_range->first_byte_pos = first_byte_pos;
429     prop_range->last_byte_pos = last_byte_pos;
430     GST_LOG (" - %s: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT,
431         property, first_byte_pos, last_byte_pos);
432     xmlFree (prop_string);
433   }
434
435   return prop_range;
436
437 error:
438   GST_WARNING ("failed to parse property %s from xml string %s", property,
439       prop_string);
440   return NULL;
441 }
442
443 static GstRatio *
444 gst_mpdparser_get_xml_prop_ratio (xmlNode * a_node, const gchar * property)
445 {
446   xmlChar *prop_string;
447   GstRatio *prop_ratio = NULL;
448   guint num = 0, den = 1;
449   guint len, pos;
450   gchar *str;
451
452   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
453   if (prop_string) {
454     len = xmlStrlen (prop_string);
455     str = (gchar *) prop_string;
456     GST_TRACE ("ratio: %s, len %d", str, len);
457
458     /* read ":" */
459     pos = strcspn (str, ":");
460     if (pos >= len) {
461       GST_TRACE ("pos %d >= len %d", pos, len);
462       goto error;
463     }
464     /* read num */
465     if (pos != 0) {
466       if (sscanf (str, "%u", &num) != 1) {
467         goto error;
468       }
469     }
470     /* read den */
471     if (pos < (len - 1)) {
472       if (sscanf (str + pos + 1, "%u", &den) != 1) {
473         goto error;
474       }
475     }
476     /* malloc return data structure */
477     prop_ratio = g_slice_new0 (GstRatio);
478     if (prop_ratio == NULL) {
479       GST_WARNING ("Allocation of GstRatio failed!");
480       goto error;
481     }
482     prop_ratio->num = num;
483     prop_ratio->den = den;
484     GST_LOG (" - %s: %u:%u", property, num, den);
485     xmlFree (prop_string);
486   }
487
488   return prop_ratio;
489
490 error:
491   GST_WARNING ("failed to parse property %s from xml string %s", property,
492       prop_string);
493   return NULL;
494 }
495
496 static GstFrameRate *
497 gst_mpdparser_get_xml_prop_framerate (xmlNode * a_node, const gchar * property)
498 {
499   xmlChar *prop_string;
500   GstFrameRate *prop_framerate = NULL;
501   guint num = 0, den = 1;
502   guint len, pos;
503   gchar *str;
504
505   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
506   if (prop_string) {
507     len = xmlStrlen (prop_string);
508     str = (gchar *) prop_string;
509     GST_TRACE ("framerate: %s, len %d", str, len);
510
511     /* read "/" if available */
512     pos = strcspn (str, "/");
513     /* read num */
514     if (pos != 0) {
515       if (sscanf (str, "%u", &num) != 1) {
516         goto error;
517       }
518     }
519     /* read den (if available) */
520     if (pos < (len - 1)) {
521       if (sscanf (str + pos + 1, "%u", &den) != 1) {
522         goto error;
523       }
524     }
525     /* alloc return data structure */
526     prop_framerate = g_slice_new0 (GstFrameRate);
527     if (prop_framerate == NULL) {
528       GST_WARNING ("Allocation of GstFrameRate failed!");
529       goto error;
530     }
531     prop_framerate->num = num;
532     prop_framerate->den = den;
533     if (den == 1)
534       GST_LOG (" - %s: %u", property, num);
535     else
536       GST_LOG (" - %s: %u/%u", property, num, den);
537     xmlFree (prop_string);
538   }
539
540   return prop_framerate;
541
542 error:
543   GST_WARNING ("failed to parse property %s from xml string %s", property,
544       prop_string);
545   return NULL;
546 }
547
548 static GstConditionalUintType *
549 gst_mpdparser_get_xml_prop_cond_uint (xmlNode * a_node, const gchar * property)
550 {
551   xmlChar *prop_string;
552   GstConditionalUintType *prop_cond_uint = NULL;
553   gchar *str;
554   gboolean flag;
555   guint val;
556
557   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
558   if (prop_string) {
559     str = (gchar *) prop_string;
560     GST_TRACE ("conditional uint: %s", str);
561
562     if (strcmp (str, "false") == 0) {
563       flag = FALSE;
564       val = 0;
565     } else if (strcmp (str, "true") == 0) {
566       flag = TRUE;
567       val = 0;
568     } else {
569       flag = TRUE;
570       if (sscanf (str, "%u", &val) != 1)
571         goto error;
572     }
573
574     /* alloc return data structure */
575     prop_cond_uint = g_slice_new0 (GstConditionalUintType);
576     if (prop_cond_uint == NULL) {
577       GST_WARNING ("Allocation of GstConditionalUintType failed!");
578       goto error;
579     }
580     prop_cond_uint->flag = flag;
581     prop_cond_uint->value = val;
582     GST_LOG (" - %s: flag=%s val=%u", property, flag ? "true" : "false", val);
583     xmlFree (prop_string);
584   }
585
586   return prop_cond_uint;
587
588 error:
589   GST_WARNING ("failed to parse property %s from xml string %s", property,
590       prop_string);
591   return NULL;
592 }
593
594 /*
595   DateTime Data Type
596
597   The dateTime data type is used to specify a date and a time.
598
599   The dateTime is specified in the following form "YYYY-MM-DDThh:mm:ss" where:
600
601     * YYYY indicates the year
602     * MM indicates the month
603     * DD indicates the day
604     * T indicates the start of the required time section
605     * hh indicates the hour
606     * mm indicates the minute
607     * ss indicates the second
608
609   Note: All components are required!
610 */
611
612 static GstDateTime *
613 gst_mpdparser_get_xml_prop_dateTime (xmlNode * a_node, const gchar * property)
614 {
615   xmlChar *prop_string;
616   gchar *str;
617   gint ret, len, pos;
618   gint year, month, day, hour, minute, second;
619
620   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
621   if (prop_string) {
622     len = xmlStrlen (prop_string);
623     str = (gchar *) prop_string;
624     GST_TRACE ("dateTime: %s, len %d", str, len);
625     /* parse year */
626     ret = sscanf (str, "%d", &year);
627     if (ret != 1)
628       goto error;
629     pos = strcspn (str, "-");
630     str += (pos + 1);
631     GST_TRACE (" - year %d", year);
632     /* parse month */
633     ret = sscanf (str, "%d", &month);
634     if (ret != 1)
635       goto error;
636     pos = strcspn (str, "-");
637     str += (pos + 1);
638     GST_TRACE (" - month %d", month);
639     /* parse day */
640     ret = sscanf (str, "%d", &day);
641     if (ret != 1)
642       goto error;
643     pos = strcspn (str, "T");
644     str += (pos + 1);
645     GST_TRACE (" - day %d", day);
646     /* parse hour */
647     ret = sscanf (str, "%d", &hour);
648     if (ret != 1)
649       goto error;
650     pos = strcspn (str, ":");
651     str += (pos + 1);
652     GST_TRACE (" - hour %d", hour);
653     /* parse minute */
654     ret = sscanf (str, "%d", &minute);
655     if (ret != 1)
656       goto error;
657     pos = strcspn (str, ":");
658     str += (pos + 1);
659     GST_TRACE (" - minute %d", minute);
660     /* parse second */
661     ret = sscanf (str, "%d", &second);
662     if (ret != 1)
663       goto error;
664     GST_TRACE (" - second %d", second);
665
666     GST_LOG (" - %s: %4d/%02d/%02d %02d:%02d:%02d", property,
667         year, month, day, hour, minute, second);
668
669     return gst_date_time_new (0, year, month, day, hour, minute, second);
670   }
671
672   return NULL;
673
674 error:
675   GST_WARNING ("failed to parse property %s from xml string %s", property,
676       prop_string);
677   return NULL;
678 }
679
680 /*
681   Duration Data Type
682
683   The duration data type is used to specify a time interval.
684
685   The time interval is specified in the following form "-PnYnMnDTnHnMnS" where:
686
687     * - indicates the negative sign (optional)
688     * P indicates the period (required)
689     * nY indicates the number of years
690     * nM indicates the number of months
691     * nD indicates the number of days
692     * T indicates the start of a time section (required if you are going to specify hours, minutes, or seconds)
693     * nH indicates the number of hours
694     * nM indicates the number of minutes
695     * nS indicates the number of seconds
696 */
697
698 /* this function computes decimals * 10 ^ (3 - pos) */
699 static gint
700 convert_to_millisecs (gint decimals, gint pos)
701 {
702   gint num = 1, den = 1, i = 3 - pos;
703
704   while (i < 0) {
705     den *= 10;
706     i++;
707   }
708   while (i > 0) {
709     num *= 10;
710     i--;
711   }
712   /* if i == 0 we have exactly 3 decimals and nothing to do */
713   return decimals * num / den;
714 }
715
716 static gint64
717 gst_mpdparser_get_xml_prop_duration (xmlNode * a_node, const gchar * property)
718 {
719   xmlChar *prop_string;
720   gchar *str;
721   gint64 prop_duration = -1;
722   gint ret, read, len, pos, posT;
723   gint years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds =
724       0, decimals = 0;
725   gint sign = 1;
726   gboolean have_ms = FALSE;
727
728   prop_string = xmlGetProp (a_node, (const xmlChar *) property);
729   if (prop_string) {
730     len = xmlStrlen (prop_string);
731     str = (gchar *) prop_string;
732     GST_TRACE ("duration: %s, len %d", str, len);
733     /* read "-" for sign, if present */
734     pos = strcspn (str, "-");
735     if (pos < len) {            /* found "-" */
736       if (pos != 0) {
737         GST_WARNING ("sign \"-\" non at the beginning of the string");
738         return -1;
739       }
740       GST_TRACE ("found - sign at the beginning");
741       sign = -1;
742       str++;
743       len--;
744     }
745     /* read "P" for period */
746     pos = strcspn (str, "P");
747     if (pos != 0) {
748       GST_WARNING ("P not found at the beginning of the string!");
749       return -1;
750     }
751     str++;
752     len--;
753     /* read "T" for time (if present) */
754     posT = strcspn (str, "T");
755     len -= posT;
756     if (posT > 0) {
757       /* there is some room between P and T, so there must be a period section */
758       /* read years, months, days */
759       do {
760         GST_TRACE ("parsing substring %s", str);
761         pos = strcspn (str, "YMD");
762         ret = sscanf (str, "%d", &read);
763         if (ret != 1) {
764           GST_WARNING ("can not read integer value from string %s!", str);
765           return -1;
766         }
767         switch (str[pos]) {
768           case 'Y':
769             years = read;
770             break;
771           case 'M':
772             months = read;
773             break;
774           case 'D':
775             days = read;
776             break;
777           default:
778             GST_WARNING ("unexpected char %c!", str[pos]);
779             return -1;
780             break;
781         }
782         GST_TRACE ("read number %d type %c", read, str[pos]);
783         str += (pos + 1);
784         posT -= (pos + 1);
785       } while (posT > 0);
786
787       GST_TRACE ("Y:M:D=%d:%d:%d", years, months, days);
788     }
789     /* read "T" for time (if present) */
790     /* here T is at pos == 0 */
791     str++;
792     len--;
793     pos = 0;
794     if (pos < len) {
795       /* T found, there is a time section */
796       /* read hours, minutes, seconds, cents of second */
797       do {
798         GST_TRACE ("parsing substring %s", str);
799         pos = strcspn (str, "HMS,.");
800         ret = sscanf (str, "%d", &read);
801         if (ret != 1) {
802           GST_WARNING ("can not read integer value from string %s!", str);
803           return -1;
804         }
805         switch (str[pos]) {
806           case 'H':
807             hours = read;
808             break;
809           case 'M':
810             minutes = read;
811             break;
812           case 'S':
813             if (have_ms) {
814               /* we have read the decimal part of the seconds */
815               decimals = convert_to_millisecs (read, pos);
816               GST_TRACE ("decimal number %d (%d digits) -> %d ms", read, pos,
817                   decimals);
818             } else {
819               /* no decimals */
820               seconds = read;
821             }
822             break;
823           case '.':
824           case ',':
825             /* we have read the integer part of a decimal number in seconds */
826             seconds = read;
827             have_ms = TRUE;
828             break;
829           default:
830             GST_WARNING ("unexpected char %c!", str[pos]);
831             return -1;
832             break;
833         }
834         GST_TRACE ("read number %d type %c", read, str[pos]);
835         str += pos + 1;
836         len -= (pos + 1);
837       } while (len > 0);
838
839       GST_TRACE ("H:M:S.MS=%d:%d:%d.%03d", hours, minutes, seconds, decimals);
840     }
841
842     xmlFree (prop_string);
843     prop_duration =
844         sign * ((((((gint64) years * 365 + months * 30 + days) * 24 +
845                     hours) * 60 + minutes) * 60 + seconds) * 1000 + decimals);
846     GST_LOG (" - %s: %" G_GINT64_FORMAT, property, prop_duration);
847   }
848
849   return prop_duration;
850 }
851
852 static gchar *
853 gst_mpdparser_get_xml_node_content (xmlNode * a_node)
854 {
855   xmlChar *content = NULL;
856
857   content = xmlNodeGetContent (a_node);
858   if (content) {
859     GST_LOG (" - %s: %s", a_node->name, content);
860   }
861
862   return (gchar *) content;
863 }
864
865 static gchar *
866 gst_mpdparser_get_xml_node_namespace (xmlNode * a_node, const gchar * prefix)
867 {
868   xmlNs *curr_ns;
869   gchar *namespace = NULL;
870
871   if (prefix == NULL) {
872     /* return the default namespace */
873     namespace = g_strdup ((gchar *) a_node->ns->href);
874     if (namespace) {
875       GST_LOG (" - default namespace: %s", namespace);
876     }
877   } else {
878     /* look for the specified prefix in the namespace list */
879     for (curr_ns = a_node->ns; curr_ns; curr_ns = curr_ns->next) {
880       if (xmlStrcmp (curr_ns->prefix, (xmlChar *) prefix) == 0) {
881         namespace = g_strdup ((gchar *) curr_ns->href);
882         if (namespace) {
883           GST_LOG (" - %s namespace: %s", curr_ns->prefix, curr_ns->href);
884         }
885       }
886     }
887   }
888
889   return namespace;
890 }
891
892 static void
893 gst_mpdparser_parse_baseURL_node (GList ** list, xmlNode * a_node)
894 {
895   GstBaseURL *new_base_url;
896
897   new_base_url = g_slice_new0 (GstBaseURL);
898   if (new_base_url == NULL) {
899     GST_WARNING ("Allocation of BaseURL node failed!");
900     return;
901   }
902   *list = g_list_append (*list, new_base_url);
903
904   GST_LOG ("content of BaseURL node:");
905   new_base_url->baseURL = gst_mpdparser_get_xml_node_content (a_node);
906
907   GST_LOG ("attributes of BaseURL node:");
908   new_base_url->serviceLocation =
909       gst_mpdparser_get_xml_prop_string (a_node, "serviceLocation");
910   new_base_url->byteRange =
911       gst_mpdparser_get_xml_prop_string (a_node, "byteRange");
912 }
913
914 static void
915 gst_mpdparser_parse_descriptor_type_node (GList ** list, xmlNode * a_node)
916 {
917   GstDescriptorType *new_descriptor;
918
919   new_descriptor = g_slice_new0 (GstDescriptorType);
920   if (new_descriptor == NULL) {
921     GST_WARNING ("Allocation of DescriptorType node failed!");
922     return;
923   }
924   *list = g_list_append (*list, new_descriptor);
925
926   GST_LOG ("attributes of %s node:", a_node->name);
927   new_descriptor->schemeIdUri =
928       gst_mpdparser_get_xml_prop_string (a_node, "schemeIdUri");
929   new_descriptor->value = gst_mpdparser_get_xml_prop_string (a_node, "value");
930
931  /* For adding ContentProtection to caps , get string of <mspr:pro> */
932   if(xmlStrcmp (a_node->name,(xmlChar *) "ContentProtection") == 0) {
933     if (a_node->children->next){
934       if(xmlStrcmp (a_node->children->next->name,(xmlChar *) "pro") == 0){
935         if (a_node->children->next->type == XML_ELEMENT_NODE) {
936           new_descriptor->msprPro = gst_mpdparser_get_xml_node_content (a_node->children->next);
937           }
938         }
939       }
940     }
941 }
942
943 static void
944 gst_mpdparser_parse_content_component_node (GList ** list, xmlNode * a_node)
945 {
946   xmlNode *cur_node;
947   GstContentComponentNode *new_content_component;
948
949   new_content_component = g_slice_new0 (GstContentComponentNode);
950   if (new_content_component == NULL) {
951     GST_WARNING ("Allocation of ContentComponent node failed!");
952     return;
953   }
954   *list = g_list_append (*list, new_content_component);
955
956   GST_LOG ("attributes of ContentComponent node:");
957   new_content_component->id =
958       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "id", 0);
959   new_content_component->lang =
960       gst_mpdparser_get_xml_prop_string (a_node, "lang");
961   new_content_component->contentType =
962       gst_mpdparser_get_xml_prop_string (a_node, "contentType");
963   new_content_component->par = gst_mpdparser_get_xml_prop_ratio (a_node, "par");
964
965   /* explore children nodes */
966   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
967     if (cur_node->type == XML_ELEMENT_NODE) {
968       if (xmlStrcmp (cur_node->name, (xmlChar *) "Accessibility") == 0) {
969         gst_mpdparser_parse_descriptor_type_node (&new_content_component->
970             Accessibility, cur_node);
971       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Role") == 0) {
972         gst_mpdparser_parse_descriptor_type_node (&new_content_component->Role,
973             cur_node);
974       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Rating") == 0) {
975         gst_mpdparser_parse_descriptor_type_node (&new_content_component->
976             Rating, cur_node);
977       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Viewpoint") == 0) {
978         gst_mpdparser_parse_descriptor_type_node (&new_content_component->
979             Viewpoint, cur_node);
980       }
981     }
982   }
983 }
984
985 static void
986 gst_mpdparser_parse_location_node (GList ** list, xmlNode * a_node)
987 {
988   gchar *location;
989
990   GST_LOG ("content of Location node:");
991   location = gst_mpdparser_get_xml_node_content (a_node);
992
993   *list = g_list_append (*list, location);
994 }
995
996 static void
997 gst_mpdparser_parse_subrepresentation_node (GList ** list, xmlNode * a_node)
998 {
999   GstSubRepresentationNode *new_subrep;
1000
1001   new_subrep = g_slice_new0 (GstSubRepresentationNode);
1002   if (new_subrep == NULL) {
1003     GST_WARNING ("Allocation of SubRepresentation node failed!");
1004     return;
1005   }
1006   *list = g_list_append (*list, new_subrep);
1007
1008   GST_LOG ("attributes of SubRepresentation node:");
1009   new_subrep->level =
1010       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "level", 0);
1011   new_subrep->dependencyLevel =
1012       gst_mpdparser_get_xml_prop_uint_vector_type (a_node, "dependencyLevel",
1013       &new_subrep->size);
1014   new_subrep->bandwidth =
1015       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0);
1016   new_subrep->contentComponent =
1017       gst_mpdparser_get_xml_prop_string_vector_type (a_node,
1018       "contentComponent");
1019
1020   /* RepresentationBase extension */
1021   gst_mpdparser_parse_representation_base_type (&new_subrep->RepresentationBase,
1022       a_node);
1023 }
1024
1025 static void
1026 gst_mpdparser_parse_segment_url_node (GList ** list, xmlNode * a_node)
1027 {
1028   GstSegmentURLNode *new_segment_url;
1029
1030   new_segment_url = g_slice_new0 (GstSegmentURLNode);
1031   if (new_segment_url == NULL) {
1032     GST_WARNING ("Allocation of SegmentURL node failed!");
1033     return;
1034   }
1035   *list = g_list_append (*list, new_segment_url);
1036
1037   GST_LOG ("attributes of SegmentURL node:");
1038   new_segment_url->media = gst_mpdparser_get_xml_prop_string (a_node, "media");
1039   new_segment_url->mediaRange =
1040       gst_mpdparser_get_xml_prop_range (a_node, "mediaRange");
1041   new_segment_url->index = gst_mpdparser_get_xml_prop_string (a_node, "index");
1042   new_segment_url->indexRange =
1043       gst_mpdparser_get_xml_prop_range (a_node, "indexRange");
1044 }
1045
1046 static void
1047 gst_mpdparser_parse_url_type_node (GstURLType ** pointer, xmlNode * a_node)
1048 {
1049   GstURLType *new_url_type;
1050
1051   gst_mpdparser_free_url_type_node (*pointer);
1052   *pointer = new_url_type = g_slice_new0 (GstURLType);
1053   if (new_url_type == NULL) {
1054     GST_WARNING ("Allocation of URLType node failed!");
1055     return;
1056   }
1057
1058   GST_LOG ("attributes of URLType node:");
1059   new_url_type->sourceURL =
1060       gst_mpdparser_get_xml_prop_string (a_node, "sourceURL");
1061   new_url_type->range = gst_mpdparser_get_xml_prop_range (a_node, "range");
1062 }
1063
1064 static void
1065 gst_mpdparser_parse_seg_base_type_ext (GstSegmentBaseType ** pointer,
1066     xmlNode * a_node)
1067 {
1068   xmlNode *cur_node;
1069   GstSegmentBaseType *seg_base_type;
1070
1071   gst_mpdparser_free_seg_base_type_ext (*pointer);
1072   *pointer = seg_base_type = g_slice_new0 (GstSegmentBaseType);
1073   if (seg_base_type == NULL) {
1074     GST_WARNING ("Allocation of SegmentBaseType node failed!");
1075     return;
1076   }
1077
1078   GST_LOG ("attributes of SegmentBaseType extension:");
1079   seg_base_type->timescale =
1080       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "timescale", 0);
1081   seg_base_type->presentationTimeOffset =
1082       gst_mpdparser_get_xml_prop_unsigned_integer (a_node,
1083       "presentationTimeOffset", 0);
1084   seg_base_type->indexRange =
1085       gst_mpdparser_get_xml_prop_string (a_node, "indexRange");
1086   seg_base_type->indexRangeExact =
1087       gst_mpdparser_get_xml_prop_boolean (a_node, "indexRangeExact");
1088
1089   /* explore children nodes */
1090   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1091     if (cur_node->type == XML_ELEMENT_NODE) {
1092       if (xmlStrcmp (cur_node->name, (xmlChar *) "Initialization") == 0 ||
1093           xmlStrcmp (cur_node->name, (xmlChar *) "Initialisation") == 0) {
1094         gst_mpdparser_parse_url_type_node (&seg_base_type->Initialization,
1095             cur_node);
1096       } else if (xmlStrcmp (cur_node->name,
1097               (xmlChar *) "RepresentationIndex") == 0) {
1098         gst_mpdparser_parse_url_type_node (&seg_base_type->RepresentationIndex,
1099             cur_node);
1100       }
1101     }
1102   }
1103 }
1104
1105 static void
1106 gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node)
1107 {
1108   GstSNode *new_s_node;
1109
1110   new_s_node = g_slice_new0 (GstSNode);
1111   if (new_s_node == NULL) {
1112     GST_WARNING ("Allocation of S node failed!");
1113     return;
1114   }
1115   *list = g_list_append (*list, new_s_node);
1116
1117   GST_LOG ("attributes of S node:");
1118   new_s_node->t = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "t", 0);
1119   new_s_node->d = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "d", 0);
1120   new_s_node->r = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "r", 0);
1121 }
1122
1123 static void
1124 gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode ** pointer,
1125     xmlNode * a_node)
1126 {
1127   xmlNode *cur_node;
1128   GstSegmentTimelineNode *new_seg_timeline;
1129
1130   gst_mpdparser_free_segment_timeline_node (*pointer);
1131   *pointer = new_seg_timeline = g_slice_new0 (GstSegmentTimelineNode);
1132   if (new_seg_timeline == NULL) {
1133     GST_WARNING ("Allocation of SegmentTimeline node failed!");
1134     return;
1135   }
1136
1137   /* explore children nodes */
1138   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1139     if (cur_node->type == XML_ELEMENT_NODE) {
1140       if (xmlStrcmp (cur_node->name, (xmlChar *) "S") == 0) {
1141         gst_mpdparser_parse_s_node (&new_seg_timeline->S, cur_node);
1142       }
1143     }
1144   }
1145 }
1146
1147 static void
1148 gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType ** pointer,
1149     xmlNode * a_node)
1150 {
1151   xmlNode *cur_node;
1152   GstMultSegmentBaseType *mult_seg_base_type;
1153
1154   gst_mpdparser_free_mult_seg_base_type_ext (*pointer);
1155   *pointer = mult_seg_base_type = g_slice_new0 (GstMultSegmentBaseType);
1156   if (mult_seg_base_type == NULL) {
1157     GST_WARNING ("Allocation of MultipleSegmentBaseType node failed!");
1158     return;
1159   }
1160
1161   GST_LOG ("attributes of MultipleSegmentBaseType extension:");
1162   mult_seg_base_type->duration =
1163       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "duration", 0);
1164   mult_seg_base_type->startNumber =
1165       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "startNumber", 1);
1166
1167   GST_LOG ("extension of MultipleSegmentBaseType extension:");
1168   gst_mpdparser_parse_seg_base_type_ext (&mult_seg_base_type->SegBaseType,
1169       a_node);
1170
1171   /* explore children nodes */
1172   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1173     if (cur_node->type == XML_ELEMENT_NODE) {
1174       if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTimeline") == 0) {
1175         gst_mpdparser_parse_segment_timeline_node (&mult_seg_base_type->
1176             SegmentTimeline, cur_node);
1177       } else if (xmlStrcmp (cur_node->name,
1178               (xmlChar *) "BitstreamSwitching") == 0) {
1179         gst_mpdparser_parse_url_type_node (&mult_seg_base_type->
1180             BitstreamSwitching, cur_node);
1181       }
1182     }
1183   }
1184 }
1185
1186 static void
1187 gst_mpdparser_parse_segment_list_node (GstSegmentListNode ** pointer,
1188     xmlNode * a_node)
1189 {
1190   xmlNode *cur_node;
1191   GstSegmentListNode *new_segment_list;
1192
1193   gst_mpdparser_free_segment_list_node (*pointer);
1194   *pointer = new_segment_list = g_slice_new0 (GstSegmentListNode);
1195   if (new_segment_list == NULL) {
1196     GST_WARNING ("Allocation of SegmentList node failed!");
1197     return;
1198   }
1199
1200   GST_LOG ("extension of SegmentList node:");
1201   gst_mpdparser_parse_mult_seg_base_type_ext (&new_segment_list->
1202       MultSegBaseType, a_node);
1203
1204   /* explore children nodes */
1205   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1206     if (cur_node->type == XML_ELEMENT_NODE) {
1207       if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentURL") == 0) {
1208         gst_mpdparser_parse_segment_url_node (&new_segment_list->SegmentURL,
1209             cur_node);
1210       }
1211     }
1212   }
1213 }
1214
1215 static void
1216 gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType **
1217     pointer, xmlNode * a_node)
1218 {
1219   xmlNode *cur_node;
1220   GstRepresentationBaseType *representation_base;
1221
1222   gst_mpdparser_free_representation_base_type (*pointer);
1223   *pointer = representation_base = g_slice_new0 (GstRepresentationBaseType);
1224   if (representation_base == NULL) {
1225     GST_WARNING ("Allocation of RepresentationBaseType node failed!");
1226     return;
1227   }
1228
1229   GST_LOG ("attributes of RepresentationBaseType extension:");
1230   representation_base->profiles =
1231       gst_mpdparser_get_xml_prop_string (a_node, "profiles");
1232   representation_base->width =
1233       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "width", 0);
1234   representation_base->height =
1235       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "height", 0);
1236   representation_base->sar = gst_mpdparser_get_xml_prop_ratio (a_node, "sar");
1237   representation_base->frameRate =
1238       gst_mpdparser_get_xml_prop_framerate (a_node, "frameRate");
1239   representation_base->audioSamplingRate =
1240       gst_mpdparser_get_xml_prop_string (a_node, "audioSamplingRate");
1241   representation_base->mimeType =
1242       gst_mpdparser_get_xml_prop_string (a_node, "mimeType");
1243   representation_base->segmentProfiles =
1244       gst_mpdparser_get_xml_prop_string (a_node, "segmentProfiles");
1245   representation_base->codecs =
1246       gst_mpdparser_get_xml_prop_string (a_node, "codecs");
1247   representation_base->maximumSAPPeriod =
1248       gst_mpdparser_get_xml_prop_double (a_node, "maximumSAPPeriod");
1249   representation_base->startWithSAP =
1250       gst_mpdparser_get_xml_prop_SAP_type (a_node, "startWithSAP");
1251   representation_base->maxPlayoutRate =
1252       gst_mpdparser_get_xml_prop_double (a_node, "maxPlayoutRate");
1253   representation_base->codingDependency =
1254       gst_mpdparser_get_xml_prop_boolean (a_node, "codingDependency");
1255   representation_base->scanType =
1256       gst_mpdparser_get_xml_prop_string (a_node, "scanType");
1257
1258   /* explore children nodes */
1259   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1260     if (cur_node->type == XML_ELEMENT_NODE) {
1261       if (xmlStrcmp (cur_node->name, (xmlChar *) "FramePacking") == 0) {
1262         gst_mpdparser_parse_descriptor_type_node (&representation_base->
1263             FramePacking, cur_node);
1264       } else if (xmlStrcmp (cur_node->name,
1265               (xmlChar *) "AudioChannelConfiguration") == 0) {
1266         gst_mpdparser_parse_descriptor_type_node (&representation_base->
1267             AudioChannelConfiguration, cur_node);
1268       } else if (xmlStrcmp (cur_node->name,
1269               (xmlChar *) "ContentProtection") == 0) {
1270         gst_mpdparser_parse_descriptor_type_node (&representation_base->
1271             ContentProtection, cur_node);
1272       }
1273     }
1274   }
1275 }
1276
1277 static void
1278 gst_mpdparser_parse_representation_node (GList ** list, xmlNode * a_node)
1279 {
1280   xmlNode *cur_node;
1281   GstRepresentationNode *new_representation;
1282
1283   new_representation = g_slice_new0 (GstRepresentationNode);
1284   if (new_representation == NULL) {
1285     GST_WARNING ("Allocation of Representation node failed!");
1286     return;
1287   }
1288   *list = g_list_append (*list, new_representation);
1289
1290   GST_LOG ("attributes of Representation node:");
1291   new_representation->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1292   new_representation->bandwidth =
1293       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0);
1294   new_representation->qualityRanking =
1295       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "qualityRanking", 0);
1296   new_representation->dependencyId =
1297       gst_mpdparser_get_xml_prop_string_vector_type (a_node, "dependencyId");
1298   new_representation->mediaStreamStructureId =
1299       gst_mpdparser_get_xml_prop_string_vector_type (a_node,
1300       "mediaStreamStructureId");
1301
1302   /* RepresentationBase extension */
1303   gst_mpdparser_parse_representation_base_type (&new_representation->
1304       RepresentationBase, a_node);
1305
1306   /* explore children nodes */
1307   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1308     if (cur_node->type == XML_ELEMENT_NODE) {
1309       if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1310         gst_mpdparser_parse_seg_base_type_ext (&new_representation->SegmentBase,
1311             cur_node);
1312       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1313         gst_mpdparser_parse_segment_template_node (&new_representation->
1314             SegmentTemplate, cur_node);
1315       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1316         gst_mpdparser_parse_segment_list_node (&new_representation->SegmentList,
1317             cur_node);
1318       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1319         gst_mpdparser_parse_baseURL_node (&new_representation->BaseURLs,
1320             cur_node);
1321       } else if (xmlStrcmp (cur_node->name,
1322               (xmlChar *) "SubRepresentation") == 0) {
1323         gst_mpdparser_parse_subrepresentation_node (&new_representation->
1324             SubRepresentations, cur_node);
1325       }
1326     }
1327   }
1328 }
1329
1330 static void
1331 gst_mpdparser_parse_adaptation_set_node (GList ** list, xmlNode * a_node)
1332 {
1333   xmlNode *cur_node;
1334   GstAdaptationSetNode *new_adap_set;
1335
1336   new_adap_set = g_slice_new0 (GstAdaptationSetNode);
1337   if (new_adap_set == NULL) {
1338     GST_WARNING ("Allocation of AdaptationSet node failed!");
1339     return;
1340   }
1341   *list = g_list_append (*list, new_adap_set);
1342
1343   GST_LOG ("attributes of AdaptationSet node:");
1344   new_adap_set->id =
1345       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "id", 0);
1346   new_adap_set->group =
1347       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "group", 0);
1348   new_adap_set->lang = gst_mpdparser_get_xml_prop_string (a_node, "lang");
1349   new_adap_set->contentType =
1350       gst_mpdparser_get_xml_prop_string (a_node, "contentType");
1351   new_adap_set->par = gst_mpdparser_get_xml_prop_ratio (a_node, "par");
1352   new_adap_set->minBandwidth =
1353       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minBandwidth", 0);
1354   new_adap_set->maxBandwidth =
1355       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxBandwidth", 0);
1356   new_adap_set->minWidth =
1357       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minWidth", 0);
1358   new_adap_set->maxWidth =
1359       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxWidth", 0);
1360   new_adap_set->minHeight =
1361       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minHeight", 0);
1362   new_adap_set->maxHeight =
1363       gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxHeight", 0);
1364   new_adap_set->minFrameRate =
1365       gst_mpdparser_get_xml_prop_framerate (a_node, "minFrameRate");
1366   new_adap_set->maxFrameRate =
1367       gst_mpdparser_get_xml_prop_framerate (a_node, "maxFrameRate");
1368   new_adap_set->segmentAlignment =
1369       gst_mpdparser_get_xml_prop_cond_uint (a_node, "segmentAlignment");
1370   new_adap_set->subsegmentAlignment =
1371       gst_mpdparser_get_xml_prop_cond_uint (a_node, "subsegmentAlignment");
1372   new_adap_set->subsegmentStartsWithSAP =
1373       gst_mpdparser_get_xml_prop_SAP_type (a_node, "subsegmentStartsWithSAP");
1374   new_adap_set->bitstreamSwitching =
1375       gst_mpdparser_get_xml_prop_boolean (a_node, "bitstreamSwitching");
1376
1377   /* RepresentationBase extension */
1378   gst_mpdparser_parse_representation_base_type (&new_adap_set->
1379       RepresentationBase, a_node);
1380
1381   /* explore children nodes */
1382   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1383     if (cur_node->type == XML_ELEMENT_NODE) {
1384       if (xmlStrcmp (cur_node->name, (xmlChar *) "Accessibility") == 0) {
1385         gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Accessibility,
1386             cur_node);
1387       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Role") == 0) {
1388         gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Role,
1389             cur_node);
1390       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Rating") == 0) {
1391         gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Rating,
1392             cur_node);
1393       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Viewpoint") == 0) {
1394         gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Viewpoint,
1395             cur_node);
1396       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Representation") == 0) {
1397         gst_mpdparser_parse_representation_node (&new_adap_set->Representations,
1398             cur_node);
1399       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1400         gst_mpdparser_parse_baseURL_node (&new_adap_set->BaseURLs, cur_node);
1401       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1402         gst_mpdparser_parse_seg_base_type_ext (&new_adap_set->SegmentBase,
1403             cur_node);
1404       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1405         gst_mpdparser_parse_segment_list_node (&new_adap_set->SegmentList,
1406             cur_node);
1407       } else if (xmlStrcmp (cur_node->name,
1408               (xmlChar *) "ContentComponent") == 0) {
1409         gst_mpdparser_parse_content_component_node (&new_adap_set->
1410             ContentComponents, cur_node);
1411       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1412         gst_mpdparser_parse_segment_template_node (&new_adap_set->
1413             SegmentTemplate, cur_node);
1414       }
1415     }
1416   }
1417 }
1418
1419 static void
1420 gst_mpdparser_parse_subset_node (GList ** list, xmlNode * a_node)
1421 {
1422   GstSubsetNode *new_subset;
1423
1424   new_subset = g_slice_new0 (GstSubsetNode);
1425   if (new_subset == NULL) {
1426     GST_WARNING ("Allocation of Subset node failed!");
1427     return;
1428   }
1429   *list = g_list_append (*list, new_subset);
1430
1431   GST_LOG ("attributes of Subset node:");
1432   new_subset->contains =
1433       gst_mpdparser_get_xml_prop_uint_vector_type (a_node, "contains",
1434       &new_subset->size);
1435 }
1436
1437 static void
1438 gst_mpdparser_parse_segment_template_node (GstSegmentTemplateNode ** pointer,
1439     xmlNode * a_node)
1440 {
1441   GstSegmentTemplateNode *new_segment_template;
1442
1443   gst_mpdparser_free_segment_template_node (*pointer);
1444   *pointer = new_segment_template = g_slice_new0 (GstSegmentTemplateNode);
1445   if (new_segment_template == NULL) {
1446     GST_WARNING ("Allocation of SegmentTemplate node failed!");
1447     return;
1448   }
1449
1450   GST_LOG ("extension of SegmentTemplate node:");
1451   gst_mpdparser_parse_mult_seg_base_type_ext (&new_segment_template->
1452       MultSegBaseType, a_node);
1453
1454   GST_LOG ("attributes of SegmentTemplate node:");
1455   new_segment_template->media =
1456       gst_mpdparser_get_xml_prop_string (a_node, "media");
1457   new_segment_template->index =
1458       gst_mpdparser_get_xml_prop_string (a_node, "index");
1459   new_segment_template->initialization =
1460       gst_mpdparser_get_xml_prop_string (a_node, "initialization");
1461   new_segment_template->bitstreamSwitching =
1462       gst_mpdparser_get_xml_prop_string (a_node, "bitstreamSwitching");
1463 }
1464
1465 static void
1466 gst_mpdparser_parse_period_node (GList ** list, xmlNode * a_node)
1467 {
1468   xmlNode *cur_node;
1469   GstPeriodNode *new_period;
1470
1471   new_period = g_slice_new0 (GstPeriodNode);
1472   if (new_period == NULL) {
1473     GST_WARNING ("Allocation of Period node failed!");
1474     return;
1475   }
1476   *list = g_list_append (*list, new_period);
1477
1478   GST_LOG ("attributes of Period node:");
1479   new_period->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1480   new_period->start = gst_mpdparser_get_xml_prop_duration (a_node, "start");
1481   new_period->duration =
1482       gst_mpdparser_get_xml_prop_duration (a_node, "duration");
1483   new_period->bitstreamSwitching =
1484       gst_mpdparser_get_xml_prop_boolean (a_node, "bitstreamSwitching");
1485
1486   /* explore children nodes */
1487   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1488     if (cur_node->type == XML_ELEMENT_NODE) {
1489       if (xmlStrcmp (cur_node->name, (xmlChar *) "AdaptationSet") == 0) {
1490         gst_mpdparser_parse_adaptation_set_node (&new_period->AdaptationSets,
1491             cur_node);
1492       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1493         gst_mpdparser_parse_seg_base_type_ext (&new_period->SegmentBase,
1494             cur_node);
1495       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1496         gst_mpdparser_parse_segment_list_node (&new_period->SegmentList,
1497             cur_node);
1498       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1499         gst_mpdparser_parse_segment_template_node (&new_period->SegmentTemplate,
1500             cur_node);
1501       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Subset") == 0) {
1502         gst_mpdparser_parse_subset_node (&new_period->Subsets, cur_node);
1503       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1504         gst_mpdparser_parse_baseURL_node (&new_period->BaseURLs, cur_node);
1505       }
1506     }
1507   }
1508 }
1509
1510 static void
1511 gst_mpdparser_parse_program_info_node (GList ** list, xmlNode * a_node)
1512 {
1513   xmlNode *cur_node;
1514   GstProgramInformationNode *new_prog_info;
1515
1516   new_prog_info = g_slice_new0 (GstProgramInformationNode);
1517   if (new_prog_info == NULL) {
1518     GST_WARNING ("Allocation of ProgramInfo node failed!");
1519     return;
1520   }
1521   *list = g_list_append (*list, new_prog_info);
1522
1523   GST_LOG ("attributes of ProgramInformation node:");
1524   new_prog_info->lang = gst_mpdparser_get_xml_prop_string (a_node, "lang");
1525   new_prog_info->moreInformationURL =
1526       gst_mpdparser_get_xml_prop_string (a_node, "moreInformationURL");
1527
1528   /* explore children nodes */
1529   GST_LOG ("children of ProgramInformation node:");
1530   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1531     if (cur_node->type == XML_ELEMENT_NODE) {
1532       if (xmlStrcmp (cur_node->name, (xmlChar *) "Title") == 0) {
1533         new_prog_info->Title = gst_mpdparser_get_xml_node_content (cur_node);
1534       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Source") == 0) {
1535         new_prog_info->Source = gst_mpdparser_get_xml_node_content (cur_node);
1536       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Copyright") == 0) {
1537         new_prog_info->Copyright =
1538             gst_mpdparser_get_xml_node_content (cur_node);
1539       }
1540     }
1541   }
1542 }
1543
1544 static void
1545 gst_mpdparser_parse_metrics_range_node (GList ** list, xmlNode * a_node)
1546 {
1547   GstMetricsRangeNode *new_metrics_range;
1548
1549   new_metrics_range = g_slice_new0 (GstMetricsRangeNode);
1550   if (new_metrics_range == NULL) {
1551     GST_WARNING ("Allocation of Metrics Range node failed!");
1552     return;
1553   }
1554   *list = g_list_append (*list, new_metrics_range);
1555
1556   GST_LOG ("attributes of Metrics Range node:");
1557   new_metrics_range->starttime =
1558       gst_mpdparser_get_xml_prop_duration (a_node, "starttime");
1559   new_metrics_range->duration =
1560       gst_mpdparser_get_xml_prop_duration (a_node, "duration");
1561 }
1562
1563 static void
1564 gst_mpdparser_parse_metrics_node (GList ** list, xmlNode * a_node)
1565 {
1566   xmlNode *cur_node;
1567   GstMetricsNode *new_metrics;
1568
1569   new_metrics = g_slice_new0 (GstMetricsNode);
1570   if (new_metrics == NULL) {
1571     GST_WARNING ("Allocation of Metrics node failed!");
1572     return;
1573   }
1574   *list = g_list_append (*list, new_metrics);
1575
1576   GST_LOG ("attributes of Metrics node:");
1577   new_metrics->metrics = gst_mpdparser_get_xml_prop_string (a_node, "metrics");
1578
1579   /* explore children nodes */
1580   GST_LOG ("children of Metrics node:");
1581   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1582     if (cur_node->type == XML_ELEMENT_NODE) {
1583       if (xmlStrcmp (cur_node->name, (xmlChar *) "Range") == 0) {
1584         gst_mpdparser_parse_metrics_range_node (&new_metrics->MetricsRanges,
1585             cur_node);
1586       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Reporting") == 0) {
1587         /* No reporting scheme is specified in this part of ISO/IEC 23009.
1588          * It is expected that external specifications may define formats
1589          * and delivery for the reporting data. */
1590         GST_LOG (" - Reporting node found (unknown structure)");
1591       }
1592     }
1593   }
1594 }
1595
1596 static void
1597 gst_mpdparser_parse_root_node (GstMPDNode ** pointer, xmlNode * a_node)
1598 {
1599   xmlNode *cur_node;
1600   GstMPDNode *new_mpd;
1601
1602   gst_mpdparser_free_mpd_node (*pointer);
1603   *pointer = new_mpd = g_slice_new0 (GstMPDNode);
1604   if (new_mpd == NULL) {
1605     GST_WARNING ("Allocation of MPD node failed!");
1606     return;
1607   }
1608
1609   GST_LOG ("namespaces of root MPD node:");
1610   new_mpd->default_namespace =
1611       gst_mpdparser_get_xml_node_namespace (a_node, NULL);
1612   new_mpd->namespace_xsi = gst_mpdparser_get_xml_node_namespace (a_node, "xsi");
1613   new_mpd->namespace_ext = gst_mpdparser_get_xml_node_namespace (a_node, "ext");
1614
1615   GST_LOG ("attributes of root MPD node:");
1616   new_mpd->schemaLocation =
1617       gst_mpdparser_get_xml_prop_string (a_node, "schemaLocation");
1618   new_mpd->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1619   new_mpd->profiles = gst_mpdparser_get_xml_prop_string (a_node, "profiles");
1620   new_mpd->type = gst_mpdparser_get_xml_prop_type (a_node, "type");
1621   new_mpd->availabilityStartTime =
1622       gst_mpdparser_get_xml_prop_dateTime (a_node, "availabilityStartTime");
1623   new_mpd->availabilityEndTime =
1624       gst_mpdparser_get_xml_prop_dateTime (a_node, "availabilityEndTime");
1625   new_mpd->mediaPresentationDuration =
1626       gst_mpdparser_get_xml_prop_duration (a_node, "mediaPresentationDuration");
1627   new_mpd->minimumUpdatePeriod =
1628       gst_mpdparser_get_xml_prop_duration (a_node, "minimumUpdatePeriod");
1629   new_mpd->minBufferTime =
1630       gst_mpdparser_get_xml_prop_duration (a_node, "minBufferTime");
1631   new_mpd->timeShiftBufferDepth =
1632       gst_mpdparser_get_xml_prop_duration (a_node, "timeShiftBufferDepth");
1633   new_mpd->suggestedPresentationDelay =
1634       gst_mpdparser_get_xml_prop_duration (a_node,
1635       "suggestedPresentationDelay");
1636   new_mpd->maxSegmentDuration =
1637       gst_mpdparser_get_xml_prop_duration (a_node, "maxSegmentDuration");
1638   new_mpd->maxSubsegmentDuration =
1639       gst_mpdparser_get_xml_prop_duration (a_node, "maxSubsegmentDuration");
1640
1641   /* explore children Period nodes */
1642   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1643     if (cur_node->type == XML_ELEMENT_NODE) {
1644       if (xmlStrcmp (cur_node->name, (xmlChar *) "Period") == 0) {
1645         gst_mpdparser_parse_period_node (&new_mpd->Periods, cur_node);
1646       } else if (xmlStrcmp (cur_node->name,
1647               (xmlChar *) "ProgramInformation") == 0) {
1648         gst_mpdparser_parse_program_info_node (&new_mpd->ProgramInfo, cur_node);
1649       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1650         gst_mpdparser_parse_baseURL_node (&new_mpd->BaseURLs, cur_node);
1651       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Location") == 0) {
1652         gst_mpdparser_parse_location_node (&new_mpd->Locations, cur_node);
1653       } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Metrics") == 0) {
1654         gst_mpdparser_parse_metrics_node (&new_mpd->Metrics, cur_node);
1655       }
1656     }
1657   }
1658 }
1659
1660 /* comparison functions */
1661 static int
1662 strncmp_ext (const char *s1, const char *s2)
1663 {
1664   if (s1 == NULL && s2 == NULL)
1665     return 0;
1666   if (s1 == NULL && s2 != NULL)
1667     return 1;
1668   if (s2 == NULL && s1 != NULL)
1669     return 1;
1670   return strncmp (s1, s2, strlen (s2));
1671 }
1672
1673 /* navigation functions */
1674 static GstAdaptationSetNode *
1675 gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets,
1676     const gchar * mimeType)
1677 {
1678   GList *list;
1679   GstAdaptationSetNode *adapt_set;
1680
1681   if (AdaptationSets == NULL)
1682     return NULL;
1683
1684   for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1685     adapt_set = (GstAdaptationSetNode *) list->data;
1686     if (adapt_set) {
1687       gchar *this_mimeType = NULL;
1688       GstRepresentationNode *rep;
1689       rep =
1690           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1691       if (rep->RepresentationBase)
1692         this_mimeType = rep->RepresentationBase->mimeType;
1693       if (!this_mimeType && adapt_set->RepresentationBase) {
1694         this_mimeType = adapt_set->RepresentationBase->mimeType;
1695       }
1696       if (strncmp_ext (this_mimeType, mimeType) == 0)
1697         return adapt_set;
1698     }
1699   }
1700
1701   return NULL;
1702 }
1703
1704 /* if idx < 0, returns the highest adaptation set with the given mimeType
1705  * if idx >= 0, returns the highest adaptation set with the given mimeType and an index <= idx
1706  */
1707 static GstAdaptationSetNode *
1708 gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
1709     const gchar * mimeType, gint idx)
1710 {
1711   GList *list;
1712   GstAdaptationSetNode *adapt_set, *selected = NULL;
1713   gint i = 0;
1714
1715   if (AdaptationSets == NULL)
1716     return NULL;
1717
1718   for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1719     adapt_set = (GstAdaptationSetNode *) list->data;
1720     if (adapt_set) {
1721       gchar *this_mimeType = NULL;
1722       GstRepresentationNode *rep;
1723       rep =
1724           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1725       if (rep->RepresentationBase)
1726         this_mimeType = rep->RepresentationBase->mimeType;
1727       if (!this_mimeType && adapt_set->RepresentationBase) {
1728         this_mimeType = adapt_set->RepresentationBase->mimeType;
1729       }
1730       if (strncmp_ext (this_mimeType, mimeType) == 0) {
1731         if (idx < 0 || i <= idx)
1732           selected = adapt_set;
1733         i++;
1734       }
1735     }
1736   }
1737
1738   return selected;
1739 }
1740
1741 static GstAdaptationSetNode *
1742 gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *
1743     AdaptationSets, const gchar * mimeType, const gchar * lang)
1744 {
1745   GList *list;
1746   GstAdaptationSetNode *adapt_set;
1747
1748   if (AdaptationSets == NULL)
1749     return NULL;
1750
1751   for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1752     adapt_set = (GstAdaptationSetNode *) list->data;
1753     if (adapt_set) {
1754       GstRepresentationNode *rep;
1755       gchar *this_lang = adapt_set->lang;
1756       gchar *this_mimeType = NULL;
1757       rep =
1758           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1759       if (rep->RepresentationBase)
1760         this_mimeType = rep->RepresentationBase->mimeType;
1761       if (!this_mimeType && adapt_set->RepresentationBase) {
1762         this_mimeType = adapt_set->RepresentationBase->mimeType;
1763       }
1764       if (strncmp_ext (this_mimeType, mimeType) == 0
1765           && strncmp_ext (this_lang, lang) == 0)
1766         return adapt_set;
1767     }
1768   }
1769
1770   return NULL;
1771 }
1772
1773 static GstRepresentationNode *
1774 gst_mpdparser_get_lowest_representation (GList * Representations)
1775 {
1776   GList *list = NULL;
1777
1778   if (Representations == NULL)
1779     return NULL;
1780
1781   list = g_list_first (Representations);
1782
1783   return list ? (GstRepresentationNode *) list->data : NULL;
1784 }
1785
1786 #if 0
1787 static GstRepresentationNode *
1788 gst_mpdparser_get_highest_representation (GList * Representations)
1789 {
1790   GList *list = NULL;
1791
1792   if (Representations == NULL)
1793     return NULL;
1794
1795   list = g_list_last (Representations);
1796
1797   return list ? (GstRepresentationNode *) list->data : NULL;
1798 }
1799
1800 static GstRepresentationNode *
1801 gst_mpdparser_get_representation_with_max_bandwidth (GList * Representations,
1802     gint max_bandwidth)
1803 {
1804   GList *list = NULL;
1805   GstRepresentationNode *representation, *best_rep = NULL;
1806
1807   if (Representations == NULL)
1808     return NULL;
1809
1810   if (max_bandwidth <= 0)       /* 0 => get highest representation available */
1811     return gst_mpdparser_get_highest_representation (Representations);
1812
1813   for (list = g_list_first (Representations); list; list = g_list_next (list)) {
1814     representation = (GstRepresentationNode *) list->data;
1815     if (representation && representation->bandwidth <= max_bandwidth) {
1816       best_rep = representation;
1817     }
1818   }
1819
1820   return best_rep;
1821 }
1822 #endif
1823
1824 static GstSegmentBaseType *
1825 gst_mpdparser_get_segment_base (GstPeriodNode * Period,
1826     GstAdaptationSetNode * AdaptationSet,
1827     GstRepresentationNode * Representation)
1828 {
1829   GstSegmentBaseType *SegmentBase = NULL;
1830
1831   if (Representation && Representation->SegmentBase
1832       && Representation->SegmentBase->Initialization) {
1833     SegmentBase = Representation->SegmentBase;
1834   } else if (AdaptationSet && AdaptationSet->SegmentBase
1835       && AdaptationSet->SegmentBase->Initialization) {
1836     SegmentBase = AdaptationSet->SegmentBase;
1837   } else if (Period && Period->SegmentBase
1838       && Period->SegmentBase->Initialization) {
1839     SegmentBase = Period->SegmentBase;
1840   }
1841   /* the SegmentBase element could be encoded also inside a SegmentList element */
1842   if (SegmentBase == NULL) {
1843     if (Representation && Representation->SegmentList
1844         && Representation->SegmentList->MultSegBaseType
1845         && Representation->SegmentList->MultSegBaseType->SegBaseType
1846         && Representation->SegmentList->MultSegBaseType->SegBaseType->
1847         Initialization) {
1848       SegmentBase = Representation->SegmentList->MultSegBaseType->SegBaseType;
1849     } else if (AdaptationSet && AdaptationSet->SegmentList
1850         && AdaptationSet->SegmentList->MultSegBaseType
1851         && AdaptationSet->SegmentList->MultSegBaseType->SegBaseType
1852         && AdaptationSet->SegmentList->MultSegBaseType->SegBaseType->
1853         Initialization) {
1854       SegmentBase = AdaptationSet->SegmentList->MultSegBaseType->SegBaseType;
1855     } else if (Period && Period->SegmentList
1856         && Period->SegmentList->MultSegBaseType
1857         && Period->SegmentList->MultSegBaseType->SegBaseType
1858         && Period->SegmentList->MultSegBaseType->SegBaseType->Initialization) {
1859       SegmentBase = Period->SegmentList->MultSegBaseType->SegBaseType;
1860     }
1861   }
1862
1863   return SegmentBase;
1864 }
1865
1866 gint
1867 gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
1868     gint max_bandwidth)
1869 {
1870   GList *list = NULL, *best = NULL;
1871   GstRepresentationNode *representation;
1872
1873   if (Representations == NULL)
1874     return -1;
1875
1876   if (max_bandwidth <= 0)       /* 0 => get lowest representation available */
1877     return 0;
1878
1879   for (list = g_list_first (Representations); list; list = g_list_next (list)) {
1880     representation = (GstRepresentationNode *) list->data;
1881     if (representation && representation->bandwidth <= max_bandwidth) {
1882       best = list;
1883     }
1884   }
1885
1886   return best ? g_list_position (Representations, best) : -1;
1887 }
1888
1889 static GstSegmentListNode *
1890 gst_mpdparser_get_segment_list (GstPeriodNode * Period,
1891     GstAdaptationSetNode * AdaptationSet,
1892     GstRepresentationNode * Representation)
1893 {
1894   GstSegmentListNode *SegmentList = NULL;
1895
1896   if (Representation && Representation->SegmentList) {
1897     SegmentList = Representation->SegmentList;
1898   } else if (AdaptationSet && AdaptationSet->SegmentList) {
1899     SegmentList = AdaptationSet->SegmentList;
1900   } else {
1901     SegmentList = Period->SegmentList;
1902   }
1903
1904   return SegmentList;
1905 }
1906
1907 /* memory management functions */
1908 static void
1909 gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node)
1910 {
1911   if (mpd_node) {
1912     g_free (mpd_node->default_namespace);
1913     g_free (mpd_node->namespace_xsi);
1914     g_free (mpd_node->namespace_ext);
1915     g_free (mpd_node->schemaLocation);
1916     g_free (mpd_node->id);
1917     g_free (mpd_node->profiles);
1918     if (mpd_node->availabilityStartTime)
1919       gst_date_time_unref (mpd_node->availabilityStartTime);
1920     if (mpd_node->availabilityEndTime)
1921       gst_date_time_unref (mpd_node->availabilityEndTime);
1922     g_list_foreach (mpd_node->ProgramInfo,
1923         (GFunc) gst_mpdparser_free_prog_info_node, NULL);
1924     g_list_free (mpd_node->ProgramInfo);
1925     g_list_foreach (mpd_node->BaseURLs,
1926         (GFunc) gst_mpdparser_free_base_url_node, NULL);
1927     g_list_free (mpd_node->BaseURLs);
1928     g_list_foreach (mpd_node->Locations, (GFunc) g_free, NULL);
1929     g_list_free (mpd_node->Locations);
1930     g_list_foreach (mpd_node->Periods, (GFunc) gst_mpdparser_free_period_node,
1931         NULL);
1932     g_list_free (mpd_node->Periods);
1933     g_list_foreach (mpd_node->Metrics, (GFunc) gst_mpdparser_free_metrics_node,
1934         NULL);
1935     g_list_free (mpd_node->Metrics);
1936     g_slice_free (GstMPDNode, mpd_node);
1937   }
1938 }
1939
1940 static void
1941 gst_mpdparser_free_prog_info_node (GstProgramInformationNode * prog_info_node)
1942 {
1943   if (prog_info_node) {
1944     g_free (prog_info_node->lang);
1945     g_free (prog_info_node->moreInformationURL);
1946     g_free (prog_info_node->Title);
1947     g_free (prog_info_node->Source);
1948     g_free (prog_info_node->Copyright);
1949     g_slice_free (GstProgramInformationNode, prog_info_node);
1950   }
1951 }
1952
1953 static void
1954 gst_mpdparser_free_metrics_node (GstMetricsNode * metrics_node)
1955 {
1956   if (metrics_node) {
1957     g_free (metrics_node->metrics);
1958     g_list_foreach (metrics_node->MetricsRanges,
1959         (GFunc) gst_mpdparser_free_metrics_range_node, NULL);
1960     g_list_free (metrics_node->MetricsRanges);
1961   }
1962 }
1963
1964 static void
1965 gst_mpdparser_free_metrics_range_node (GstMetricsRangeNode * metrics_range_node)
1966 {
1967   if (metrics_range_node) {
1968     g_slice_free (GstMetricsRangeNode, metrics_range_node);
1969   }
1970 }
1971
1972 static void
1973 gst_mpdparser_free_period_node (GstPeriodNode * period_node)
1974 {
1975   if (period_node) {
1976     g_free (period_node->id);
1977     gst_mpdparser_free_seg_base_type_ext (period_node->SegmentBase);
1978     gst_mpdparser_free_segment_list_node (period_node->SegmentList);
1979     gst_mpdparser_free_segment_template_node (period_node->SegmentTemplate);
1980     g_list_foreach (period_node->AdaptationSets,
1981         (GFunc) gst_mpdparser_free_adaptation_set_node, NULL);
1982     g_list_free (period_node->AdaptationSets);
1983     g_list_foreach (period_node->Subsets,
1984         (GFunc) gst_mpdparser_free_subset_node, NULL);
1985     g_list_free (period_node->Subsets);
1986     g_list_foreach (period_node->BaseURLs,
1987         (GFunc) gst_mpdparser_free_base_url_node, NULL);
1988     g_list_free (period_node->BaseURLs);
1989     g_slice_free (GstPeriodNode, period_node);
1990   }
1991 }
1992
1993 static void
1994 gst_mpdparser_free_subset_node (GstSubsetNode * subset_node)
1995 {
1996   if (subset_node) {
1997     g_free (subset_node->contains);
1998     g_slice_free (GstSubsetNode, subset_node);
1999   }
2000 }
2001
2002 static void
2003 gst_mpdparser_free_segment_template_node (GstSegmentTemplateNode *
2004     segment_template_node)
2005 {
2006   if (segment_template_node) {
2007     g_free (segment_template_node->media);
2008     g_free (segment_template_node->index);
2009     g_free (segment_template_node->initialization);
2010     g_free (segment_template_node->bitstreamSwitching);
2011     /* MultipleSegmentBaseType extension */
2012     gst_mpdparser_free_mult_seg_base_type_ext
2013         (segment_template_node->MultSegBaseType);
2014     g_slice_free (GstSegmentTemplateNode, segment_template_node);
2015   }
2016 }
2017
2018 static void
2019 gst_mpdparser_free_representation_base_type (GstRepresentationBaseType *
2020     representation_base)
2021 {
2022   if (representation_base) {
2023     g_free (representation_base->profiles);
2024     g_slice_free (GstRatio, representation_base->sar);
2025     g_slice_free (GstFrameRate, representation_base->frameRate);
2026     g_free (representation_base->audioSamplingRate);
2027     g_free (representation_base->mimeType);
2028     g_free (representation_base->segmentProfiles);
2029     g_free (representation_base->codecs);
2030     g_free (representation_base->scanType);
2031     g_list_foreach (representation_base->FramePacking,
2032         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2033     g_list_free (representation_base->FramePacking);
2034     g_list_foreach (representation_base->AudioChannelConfiguration,
2035         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2036     g_list_free (representation_base->AudioChannelConfiguration);
2037     g_list_foreach (representation_base->ContentProtection,
2038         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2039     g_list_free (representation_base->ContentProtection);
2040     g_slice_free (GstRepresentationBaseType, representation_base);
2041   }
2042 }
2043
2044 static void
2045 gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode *
2046     adaptation_set_node)
2047 {
2048   if (adaptation_set_node) {
2049     g_free (adaptation_set_node->lang);
2050     g_free (adaptation_set_node->contentType);
2051     g_slice_free (GstRatio, adaptation_set_node->par);
2052     g_slice_free (GstFrameRate, adaptation_set_node->minFrameRate);
2053     g_slice_free (GstFrameRate, adaptation_set_node->maxFrameRate);
2054     g_slice_free (GstConditionalUintType,
2055         adaptation_set_node->segmentAlignment);
2056     g_slice_free (GstConditionalUintType,
2057         adaptation_set_node->subsegmentAlignment);
2058     g_list_foreach (adaptation_set_node->Accessibility,
2059         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2060     g_list_free (adaptation_set_node->Accessibility);
2061     g_list_foreach (adaptation_set_node->Role,
2062         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2063     g_list_free (adaptation_set_node->Role);
2064     g_list_foreach (adaptation_set_node->Rating,
2065         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2066     g_list_free (adaptation_set_node->Rating);
2067     g_list_foreach (adaptation_set_node->Viewpoint,
2068         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2069     g_list_free (adaptation_set_node->Viewpoint);
2070     gst_mpdparser_free_representation_base_type
2071         (adaptation_set_node->RepresentationBase);
2072     gst_mpdparser_free_seg_base_type_ext (adaptation_set_node->SegmentBase);
2073     gst_mpdparser_free_segment_list_node (adaptation_set_node->SegmentList);
2074     gst_mpdparser_free_segment_template_node (adaptation_set_node->
2075         SegmentTemplate);
2076     g_list_foreach (adaptation_set_node->BaseURLs,
2077         (GFunc) gst_mpdparser_free_base_url_node, NULL);
2078     g_list_free (adaptation_set_node->BaseURLs);
2079     g_list_foreach (adaptation_set_node->Representations,
2080         (GFunc) gst_mpdparser_free_representation_node, NULL);
2081     g_list_free (adaptation_set_node->Representations);
2082     g_list_foreach (adaptation_set_node->ContentComponents,
2083         (GFunc) gst_mpdparser_free_content_component_node, NULL);
2084     g_list_free (adaptation_set_node->ContentComponents);
2085     g_slice_free (GstAdaptationSetNode, adaptation_set_node);
2086   }
2087 }
2088
2089 static void
2090 gst_mpdparser_free_representation_node (GstRepresentationNode *
2091     representation_node)
2092 {
2093   if (representation_node) {
2094     g_free (representation_node->id);
2095     g_strfreev (representation_node->dependencyId);
2096     g_strfreev (representation_node->mediaStreamStructureId);
2097     gst_mpdparser_free_representation_base_type
2098         (representation_node->RepresentationBase);
2099     g_list_foreach (representation_node->SubRepresentations,
2100         (GFunc) gst_mpdparser_free_subrepresentation_node, NULL);
2101     g_list_free (representation_node->SubRepresentations);
2102     gst_mpdparser_free_seg_base_type_ext (representation_node->SegmentBase);
2103     gst_mpdparser_free_segment_template_node (representation_node->
2104         SegmentTemplate);
2105     gst_mpdparser_free_segment_list_node (representation_node->SegmentList);
2106     g_list_foreach (representation_node->BaseURLs,
2107         (GFunc) gst_mpdparser_free_base_url_node, NULL);
2108     g_list_free (representation_node->BaseURLs);
2109     g_slice_free (GstRepresentationNode, representation_node);
2110   }
2111 }
2112
2113 static void
2114 gst_mpdparser_free_subrepresentation_node (GstSubRepresentationNode *
2115     subrep_node)
2116 {
2117   if (subrep_node) {
2118     gst_mpdparser_free_representation_base_type (subrep_node->
2119         RepresentationBase);
2120     g_free (subrep_node->dependencyLevel);
2121     g_strfreev (subrep_node->contentComponent);
2122   }
2123 }
2124
2125 static void
2126 gst_mpdparser_free_s_node (GstSNode * s_node)
2127 {
2128   if (s_node) {
2129     g_slice_free (GstSNode, s_node);
2130   }
2131 }
2132
2133 static void
2134 gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode * seg_timeline)
2135 {
2136   if (seg_timeline) {
2137     g_list_foreach (seg_timeline->S, (GFunc) gst_mpdparser_free_s_node, NULL);
2138     g_list_free (seg_timeline->S);
2139     g_slice_free (GstSegmentTimelineNode, seg_timeline);
2140   }
2141 }
2142
2143 static void
2144 gst_mpdparser_free_url_type_node (GstURLType * url_type_node)
2145 {
2146   if (url_type_node) {
2147     g_free (url_type_node->sourceURL);
2148     g_slice_free (GstRange, url_type_node->range);
2149     g_slice_free (GstURLType, url_type_node);
2150   }
2151 }
2152
2153 static void
2154 gst_mpdparser_free_seg_base_type_ext (GstSegmentBaseType * seg_base_type)
2155 {
2156   if (seg_base_type) {
2157     g_free (seg_base_type->indexRange);
2158     gst_mpdparser_free_url_type_node (seg_base_type->Initialization);
2159     gst_mpdparser_free_url_type_node (seg_base_type->RepresentationIndex);
2160     g_slice_free (GstSegmentBaseType, seg_base_type);
2161   }
2162 }
2163
2164 static void
2165 gst_mpdparser_free_mult_seg_base_type_ext (GstMultSegmentBaseType *
2166     mult_seg_base_type)
2167 {
2168   if (mult_seg_base_type) {
2169     /* SegmentBaseType extension */
2170     gst_mpdparser_free_seg_base_type_ext (mult_seg_base_type->SegBaseType);
2171     gst_mpdparser_free_segment_timeline_node
2172         (mult_seg_base_type->SegmentTimeline);
2173     gst_mpdparser_free_url_type_node (mult_seg_base_type->BitstreamSwitching);
2174     g_slice_free (GstMultSegmentBaseType, mult_seg_base_type);
2175   }
2176 }
2177
2178 static void
2179 gst_mpdparser_free_segment_list_node (GstSegmentListNode * segment_list_node)
2180 {
2181   if (segment_list_node) {
2182     g_list_foreach (segment_list_node->SegmentURL,
2183         (GFunc) gst_mpdparser_free_segment_url_node, NULL);
2184     g_list_free (segment_list_node->SegmentURL);
2185     /* MultipleSegmentBaseType extension */
2186     gst_mpdparser_free_mult_seg_base_type_ext
2187         (segment_list_node->MultSegBaseType);
2188     g_slice_free (GstSegmentListNode, segment_list_node);
2189   }
2190 }
2191
2192 static void
2193 gst_mpdparser_free_segment_url_node (GstSegmentURLNode * segment_url)
2194 {
2195   if (segment_url) {
2196     g_free (segment_url->media);
2197     g_slice_free (GstRange, segment_url->mediaRange);
2198     g_free (segment_url->index);
2199     g_slice_free (GstRange, segment_url->indexRange);
2200     g_slice_free (GstSegmentURLNode, segment_url);
2201   }
2202 }
2203
2204 static void
2205 gst_mpdparser_free_base_url_node (GstBaseURL * base_url_node)
2206 {
2207   if (base_url_node) {
2208     g_free (base_url_node->baseURL);
2209     g_free (base_url_node->serviceLocation);
2210     g_free (base_url_node->byteRange);
2211     g_slice_free (GstBaseURL, base_url_node);
2212   }
2213 }
2214
2215 static void
2216 gst_mpdparser_free_descriptor_type_node (GstDescriptorType * descriptor_type)
2217 {
2218   if (descriptor_type) {
2219     g_free (descriptor_type->schemeIdUri);
2220     g_free (descriptor_type->value);
2221   }
2222 }
2223
2224 static void
2225 gst_mpdparser_free_content_component_node (GstContentComponentNode *
2226     content_component_node)
2227 {
2228   if (content_component_node) {
2229     g_free (content_component_node->lang);
2230     g_free (content_component_node->contentType);
2231     g_slice_free (GstRatio, content_component_node->par);
2232     g_list_foreach (content_component_node->Accessibility,
2233         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2234     g_list_free (content_component_node->Accessibility);
2235     g_list_foreach (content_component_node->Role,
2236         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2237     g_list_free (content_component_node->Role);
2238     g_list_foreach (content_component_node->Rating,
2239         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2240     g_list_free (content_component_node->Rating);
2241     g_list_foreach (content_component_node->Viewpoint,
2242         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2243     g_list_free (content_component_node->Viewpoint);
2244     g_slice_free (GstContentComponentNode, content_component_node);
2245   }
2246 }
2247
2248 static void
2249 gst_mpdparser_free_stream_period (GstStreamPeriod * stream_period)
2250 {
2251   if (stream_period) {
2252     g_slice_free (GstStreamPeriod, stream_period);
2253   }
2254 }
2255
2256 static void
2257 gst_mpdparser_free_media_segment (GstMediaSegment * media_segment)
2258 {
2259   if (media_segment) {
2260     g_slice_free (GstMediaSegment, media_segment);
2261   }
2262 }
2263
2264 static void
2265 gst_mpdparser_free_active_stream (GstActiveStream * active_stream)
2266 {
2267   if (active_stream) {
2268     g_list_foreach (active_stream->segments,
2269         (GFunc) gst_mpdparser_free_media_segment, NULL);
2270     g_list_free (active_stream->segments);
2271     g_slice_free (GstActiveStream, active_stream);
2272   }
2273 }
2274
2275 static gchar *
2276 gst_mpdparser_get_segmentURL_for_range (gchar * url, GstRange * range)
2277 {
2278   gchar *segmentURL;
2279
2280   if (range) {
2281     gchar *range_suffix;
2282     range_suffix =
2283         g_strdup_printf ("?range=%llu-%llu", range->first_byte_pos,
2284         range->last_byte_pos);
2285     segmentURL = g_strconcat (url, range_suffix, NULL);
2286     g_free (range_suffix);
2287   } else {
2288     segmentURL = g_strdup (url);
2289   }
2290
2291   return segmentURL;
2292 }
2293
2294 static gchar *
2295 gst_mpdparser_get_mediaURL (GstMpdClient * client,
2296     GstSegmentURLNode * segmentURL)
2297 {
2298   const gchar *url_prefix;
2299
2300   g_return_val_if_fail (client != NULL, NULL);
2301   g_return_val_if_fail (segmentURL != NULL, NULL);
2302
2303   url_prefix =
2304       segmentURL->media ? segmentURL->
2305       media : gst_mpdparser_get_baseURL (client);
2306   g_return_val_if_fail (url_prefix != NULL, NULL);
2307
2308   return gst_mpdparser_get_segmentURL_for_range (url_prefix,
2309       segmentURL->mediaRange);//if not present @media attribute, it is mapped to baseURL
2310 }
2311
2312 static gchar *
2313 gst_mpdparser_get_initializationURL (GstURLType * InitializationURL)
2314 {
2315   g_return_val_if_fail (InitializationURL != NULL, NULL);
2316   g_return_val_if_fail (InitializationURL->sourceURL != NULL, NULL);
2317
2318   return gst_mpdparser_get_segmentURL_for_range (InitializationURL->sourceURL,
2319       InitializationURL->range);
2320 }
2321
2322 static gchar *
2323 gst_mpdparser_build_URL_from_template (const gchar * url_template,
2324     const gchar * id, guint number, guint bandwidth, guint time)
2325 {
2326   static gchar default_format[] = "%01d";
2327   gchar **tokens, *token, *ret, *format;
2328   gint i, num_tokens;
2329   gboolean last_token_par = TRUE;       /* last token was a parameter */
2330
2331   g_return_val_if_fail (url_template != NULL, NULL);
2332   tokens = g_strsplit_set (url_template, "$", -1);
2333   if (!tokens) {
2334     GST_WARNING ("Scan of URL template failed!");
2335     return NULL;
2336   }
2337   num_tokens = g_strv_length (tokens);
2338
2339   for (i = 0; i < num_tokens; i++) {
2340     token = tokens[i];
2341     format = default_format;
2342
2343     if (!g_strcmp0 (token, "RepresentationID")) {
2344       tokens[i] = g_strdup_printf ("%s", id);
2345       g_free (token);
2346       last_token_par = TRUE;
2347     } else if (!strncmp (token, "Number", 6)) {
2348       if (strlen (token) > 6) {
2349         format = token + 6;     /* format tag */
2350       }
2351       tokens[i] = g_strdup_printf (format, number);
2352       g_free (token);
2353       last_token_par = TRUE;
2354     } else if (!strncmp (token, "Bandwidth", 9)) {
2355       if (strlen (token) > 9) {
2356         format = token + 9;     /* format tag */
2357       }
2358       tokens[i] = g_strdup_printf (format, bandwidth);
2359       g_free (token);
2360       last_token_par = TRUE;
2361     } else if (!strncmp (token, "Time", 4)) {
2362       if (strlen (token) > 4) {
2363         format = token + 4;     /* format tag */
2364       }
2365       tokens[i] = g_strdup_printf (format, time);
2366       g_free (token);
2367       last_token_par = TRUE;
2368     } else if (!g_strcmp0 (token, "")) {
2369       if (!last_token_par) {
2370         tokens[i] = g_strdup_printf ("%s", "$");
2371         g_free (token);
2372         last_token_par = TRUE;
2373       }
2374     } else {
2375       last_token_par = FALSE;
2376     }
2377   }
2378
2379   ret = g_strjoinv (NULL, tokens);
2380   g_strfreev (tokens);
2381
2382   return ret;
2383 }
2384
2385 static GstStreamPeriod *
2386 gst_mpdparser_get_stream_period (GstMpdClient * client)
2387 {
2388   g_return_val_if_fail (client != NULL, NULL);
2389   g_return_val_if_fail (client->periods != NULL, NULL);
2390
2391   return g_list_nth_data (client->periods, client->period_idx);
2392 }
2393
2394 /* select a stream and extract the baseURL (if present) */
2395 static gchar *
2396 gst_mpdparser_parse_baseURL (GstMpdClient * client)
2397 {
2398   GstActiveStream *stream;
2399   GstStreamPeriod *stream_period;
2400   GstBaseURL *baseURL;
2401   GList *list;
2402   static gchar *baseURL_array[5];
2403   static gchar empty[] = "";
2404   gchar *ret = NULL;
2405
2406   stream =
2407       gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
2408   g_return_val_if_fail (stream != NULL, empty);
2409   stream_period = gst_mpdparser_get_stream_period (client);
2410   g_return_val_if_fail (stream_period != NULL, empty);
2411   g_return_val_if_fail (stream_period->period != NULL, empty);
2412
2413   baseURL_array[0] = baseURL_array[1] = baseURL_array[2] = baseURL_array[3] =
2414       empty;
2415   baseURL_array[4] = NULL;
2416
2417   /* FIXME: this simple implementation is not fully compliant with RFC 3986 */
2418   if ((list = client->mpd_node->BaseURLs) != NULL) {
2419     baseURL = g_list_nth_data (list, stream->baseURL_idx);
2420     if (!baseURL) {
2421       baseURL = list->data;
2422     }
2423     baseURL_array[0] = baseURL->baseURL;
2424   }
2425   if ((list = stream_period->period->BaseURLs) != NULL) {
2426     baseURL = g_list_nth_data (list, stream->baseURL_idx);
2427     if (!baseURL) {
2428       baseURL = list->data;
2429     }
2430     baseURL_array[1] = baseURL->baseURL;
2431   }
2432   if ((list = stream->cur_adapt_set->BaseURLs) != NULL) {
2433     baseURL = g_list_nth_data (list, stream->baseURL_idx);
2434     if (!baseURL) {
2435       baseURL = list->data;
2436     }
2437     baseURL_array[2] = baseURL->baseURL;
2438   }
2439   if ((list = stream->cur_representation->BaseURLs) != NULL) {
2440     baseURL = g_list_nth_data (list, stream->baseURL_idx);
2441     if (!baseURL) {
2442       baseURL = list->data;
2443     }
2444     baseURL_array[3] = baseURL->baseURL;
2445   }
2446
2447   ret = g_strjoinv (NULL, baseURL_array);
2448   /* get base URI from MPD file URI, if the "http" scheme is missing */
2449   if (client->mpd_uri != NULL && strncmp (ret, "http://", 7) != 0) {
2450     gchar *last_sep, *tmp1, *tmp2;
2451     last_sep = strrchr (client->mpd_uri, '/');
2452     if (last_sep) {
2453       tmp1 = g_strndup (client->mpd_uri, last_sep - client->mpd_uri + 1);
2454       tmp2 = ret;
2455       GST_DEBUG ("Got base URI from MPD file URI %s", tmp1);
2456       ret = g_strconcat (tmp1, tmp2, NULL);
2457       g_free (tmp1);
2458       g_free (tmp2);
2459     }
2460   }
2461
2462   GST_DEBUG ("selected baseURL with index %d: %s", stream->baseURL_idx, ret);
2463
2464   return ret;
2465 }
2466
2467 static GstClockTime
2468 gst_mpd_client_get_segment_duration (GstMpdClient * client)
2469 {
2470   GstActiveStream *stream;
2471   GstStreamPeriod *stream_period;
2472   GstMultSegmentBaseType *base = NULL;
2473   GstClockTime duration;
2474   guint timescale;
2475
2476   stream =
2477       gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
2478   g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
2479   stream_period = gst_mpdparser_get_stream_period (client);
2480   g_return_val_if_fail (stream_period != NULL, GST_CLOCK_TIME_NONE);
2481
2482   if (stream->cur_segment_list) {
2483     base = stream->cur_segment_list->MultSegBaseType;
2484   } else if (stream->cur_seg_template) {
2485     base = stream->cur_seg_template->MultSegBaseType;
2486   }
2487
2488   if (base == NULL || base->SegBaseType == NULL) {
2489     /* this may happen when we have a single segment */
2490     duration = stream_period->duration;
2491   } else {
2492     duration = base->duration * GST_SECOND;
2493     timescale = base->SegBaseType->timescale;
2494
2495     if (timescale > 1)
2496       duration /= timescale;
2497   }
2498
2499   return duration;
2500 }
2501
2502 /*****************************/
2503 /******* API functions *******/
2504 /*****************************/
2505
2506 GstMpdClient *
2507 gst_mpd_client_new ()
2508 {
2509   GstMpdClient *client;
2510
2511   client = g_new0 (GstMpdClient, 1);
2512   client->lock = g_mutex_new ();
2513
2514   return client;
2515 }
2516
2517 void
2518 gst_active_streams_free (GstMpdClient * client)
2519 {
2520   if (client->active_streams) {
2521     g_list_foreach (client->active_streams,
2522         (GFunc) gst_mpdparser_free_active_stream, NULL);
2523     g_list_free (client->active_streams);
2524     client->active_streams = NULL;
2525   }
2526 }
2527
2528 void
2529 gst_mpd_client_free (GstMpdClient * client)
2530 {
2531   g_return_if_fail (client != NULL);
2532
2533   if (client->mpd_node)
2534     gst_mpdparser_free_mpd_node (client->mpd_node);
2535
2536   if (client->periods) {
2537     g_list_foreach (client->periods,
2538         (GFunc) gst_mpdparser_free_stream_period, NULL);
2539     g_list_free (client->periods);
2540   }
2541
2542   gst_active_streams_free (client);
2543
2544   if (client->lock)
2545     g_mutex_free (client->lock);
2546
2547   g_free (client->mpd_uri);
2548
2549   g_free (client);
2550 }
2551
2552 gboolean
2553 gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
2554 {
2555   if (data) {
2556     xmlDocPtr doc;
2557     xmlNode *root_element = NULL;
2558
2559     GST_DEBUG ("MPD file fully buffered, start parsing...");
2560
2561     GST_MPD_CLIENT_LOCK (client);
2562     /* parse the complete MPD file into a tree (using the libxml2 default parser API) */
2563
2564     /* this initialize the library and check potential ABI mismatches
2565      * between the version it was compiled for and the actual shared
2566      * library used
2567      */
2568     LIBXML_TEST_VERSION
2569         /* parse "data" into a document (which is a libxml2 tree structure xmlDoc) */
2570         doc = xmlReadMemory (data, size, "noname.xml", NULL, 0);
2571     if (doc == NULL) {
2572       GST_ERROR ("failed to parse the MPD file");
2573       GST_MPD_CLIENT_UNLOCK (client);
2574       return FALSE;
2575     } else {
2576       /* get the root element node */
2577       root_element = xmlDocGetRootElement (doc);
2578
2579       if (root_element->type != XML_ELEMENT_NODE
2580           || xmlStrcmp (root_element->name, (xmlChar *) "MPD") != 0) {
2581         GST_ERROR
2582             ("can not find the root element MPD, failed to parse the MPD file");
2583       } else {
2584         /* now we can parse the MPD root node and all children nodes, recursively */
2585         gst_mpdparser_parse_root_node (&client->mpd_node, root_element);
2586       }
2587       /* free the document */
2588       xmlFreeDoc (doc);
2589       /* cleanup function for the XML library */
2590       xmlCleanupParser ();
2591       /* dump XML library memory for debugging */
2592       xmlMemoryDump ();
2593     }
2594     GST_MPD_CLIENT_UNLOCK (client);
2595
2596     return TRUE;
2597   }
2598
2599   return FALSE;
2600 }
2601
2602 const gchar *
2603 gst_mpdparser_get_baseURL (GstMpdClient * client)
2604 {
2605   GstActiveStream *stream;
2606
2607   g_return_val_if_fail (client != NULL, NULL);
2608   g_return_val_if_fail (client->active_streams != NULL, NULL);
2609   stream = g_list_nth_data (client->active_streams, client->stream_idx);
2610   g_return_val_if_fail (stream != NULL, NULL);
2611
2612   return stream->baseURL;
2613 }
2614
2615 GstMediaSegment *
2616 gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
2617     guint indexChunk)
2618 {
2619   GstActiveStream *stream;
2620
2621   /* select stream */
2622   g_return_val_if_fail (client != NULL, NULL);
2623   g_return_val_if_fail (client->active_streams != NULL, NULL);
2624   stream = g_list_nth_data (client->active_streams, indexStream);
2625   g_return_val_if_fail (stream != NULL, NULL);
2626
2627   return (GstMediaSegment *) g_list_nth_data (stream->segments, indexChunk);
2628 }
2629
2630 static gboolean
2631 gst_mpd_client_add_media_segment (GstActiveStream * stream,
2632     GstSegmentURLNode * url_node, guint number, guint start,
2633     GstClockTime start_time, GstClockTime duration)
2634 {
2635   GstMediaSegment *media_segment;
2636
2637   media_segment = g_slice_new0 (GstMediaSegment);
2638   if (media_segment == NULL) {
2639     GST_WARNING ("Allocation of GstMediaSegment struct failed!");
2640     return FALSE;
2641   }
2642   stream->segments = g_list_append (stream->segments, media_segment);
2643   media_segment->SegmentURL = url_node;
2644   media_segment->number = number;
2645   media_segment->start = start;
2646   media_segment->start_time = start_time;
2647   media_segment->duration = duration;
2648
2649   return TRUE;
2650 }
2651
2652 gboolean
2653 gst_mpd_client_setup_representation (GstMpdClient * client,
2654     GstActiveStream * stream, GstRepresentationNode * representation)
2655 {
2656   GstStreamPeriod *stream_period;
2657   GList *rep_list;
2658   GstClockTime PeriodStart, PeriodEnd, start_time, duration;
2659   GstMediaSegment *last_media_segment;
2660   guint i, start;
2661
2662   if (stream->cur_adapt_set == NULL) {
2663     GST_WARNING ("No valid AdaptationSet node in the MPD file, aborting...");
2664     return FALSE;
2665   }
2666
2667   rep_list = stream->cur_adapt_set->Representations;
2668   stream->cur_representation = representation;
2669   stream->representation_idx = g_list_index (rep_list, representation);
2670
2671   /* clean the old segment list, if any */
2672   if (stream->segments) {
2673     g_list_foreach (stream->segments,
2674         (GFunc) gst_mpdparser_free_media_segment, NULL);
2675     g_list_free (stream->segments);
2676     stream->segments = NULL;
2677   }
2678
2679   stream_period = gst_mpdparser_get_stream_period (client);
2680   g_return_val_if_fail (stream_period != NULL, FALSE);
2681   g_return_val_if_fail (stream_period->period != NULL, FALSE);
2682
2683   PeriodStart = stream_period->start;
2684   if (GST_CLOCK_TIME_IS_VALID (stream_period->duration))
2685     PeriodEnd = stream_period->start + stream_period->duration;
2686   else
2687     PeriodEnd = GST_CLOCK_TIME_NONE;
2688
2689   GST_LOG ("Building segment list for Period from %" GST_TIME_FORMAT " to %"
2690       GST_TIME_FORMAT, GST_TIME_ARGS (PeriodStart), GST_TIME_ARGS (PeriodEnd));
2691
2692   if (representation->SegmentBase != NULL
2693       || representation->SegmentList != NULL) {
2694     GList *SegmentURL;
2695
2696     /* get the first segment_base of the selected representation */
2697     if ((stream->cur_segment_base =
2698             gst_mpdparser_get_segment_base (stream_period->period,
2699                 stream->cur_adapt_set, representation)) == NULL) {
2700       GST_DEBUG ("No useful SegmentBase node for the current Representation");
2701     }
2702
2703     /* get the first segment_list of the selected representation */
2704     if ((stream->cur_segment_list =
2705             gst_mpdparser_get_segment_list (stream_period->period,
2706                 stream->cur_adapt_set, representation)) == NULL) {
2707       GST_DEBUG ("No useful SegmentList node for the current Representation");
2708       /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
2709       if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, PeriodStart,
2710               PeriodEnd)) {
2711         return FALSE;
2712       }
2713     } else {
2714       /* build the list of GstMediaSegment nodes from the SegmentList node */
2715       SegmentURL = stream->cur_segment_list->SegmentURL;
2716       if (SegmentURL == NULL) {
2717         GST_WARNING
2718             ("No valid list of SegmentURL nodes in the MPD file, aborting...");
2719         return FALSE;
2720       }
2721
2722       /* build segment list */
2723       i = stream->cur_segment_list->MultSegBaseType->startNumber;
2724       start = 0;
2725       start_time = PeriodStart;
2726
2727       GST_LOG ("Building media segment list using a SegmentList node");
2728       if (stream->cur_segment_list->MultSegBaseType->SegmentTimeline) {
2729         GstSegmentTimelineNode *timeline;
2730         GstSNode *S;
2731         GList *list;
2732
2733         timeline = stream->cur_segment_list->MultSegBaseType->SegmentTimeline;
2734         for (list = g_list_first (timeline->S); list; list = g_list_next (list)) {
2735           guint j, timescale;
2736
2737           S = (GstSNode *) list->data;
2738           GST_LOG ("Processing S node: d=%d r=%d t=%d", S->d, S->r, S->t);
2739           duration = S->d * GST_SECOND;
2740           timescale =
2741               stream->cur_segment_list->MultSegBaseType->SegBaseType->timescale;
2742           if (timescale > 1)
2743             duration /= timescale;
2744           if (S->t > 0) {
2745             start = S->t;
2746             start_time = S->t * GST_SECOND;
2747             if (timescale > 1)
2748               start_time /= timescale;
2749           }
2750
2751           for (j = 0; j <= S->r && SegmentURL != NULL; j++) {
2752             if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i,
2753                     start, start_time, duration)) {
2754               return FALSE;
2755             }
2756             i++;
2757             start += S->d;
2758             start_time += duration;
2759             SegmentURL = g_list_next (SegmentURL);
2760           }
2761         }
2762       } else {
2763         duration = gst_mpd_client_get_segment_duration (client);
2764         if (!GST_CLOCK_TIME_IS_VALID (duration))
2765           return FALSE;
2766
2767         while (SegmentURL) {
2768           if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i, 0,
2769                   start_time, duration)) {
2770             return FALSE;
2771           }
2772           i++;
2773           start_time += duration;
2774           SegmentURL = g_list_next (SegmentURL);
2775         }
2776       }
2777     }
2778   } else {
2779     if (representation->SegmentTemplate != NULL) {
2780       stream->cur_seg_template = representation->SegmentTemplate;
2781     } else if (stream->cur_adapt_set->SegmentTemplate != NULL) {
2782       stream->cur_seg_template = stream->cur_adapt_set->SegmentTemplate;
2783     } else if (stream_period->period->SegmentTemplate != NULL) {
2784       stream->cur_seg_template = stream_period->period->SegmentTemplate;
2785     }
2786
2787     if (stream->cur_seg_template == NULL
2788         || stream->cur_seg_template->MultSegBaseType == NULL) {
2789       /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
2790       if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) {
2791         return FALSE;
2792       }
2793     } else {
2794       /* build segment list */
2795       i = stream->cur_seg_template->MultSegBaseType->startNumber;
2796       start = 0;
2797       start_time = PeriodStart;
2798
2799       GST_LOG ("Building media segment list using this template: %s",
2800           stream->cur_seg_template->media);
2801       if (stream->cur_seg_template->MultSegBaseType->SegmentTimeline) {
2802         GstSegmentTimelineNode *timeline;
2803         GstSNode *S;
2804         GList *list;
2805
2806         timeline = stream->cur_seg_template->MultSegBaseType->SegmentTimeline;
2807         for (list = g_list_first (timeline->S); list; list = g_list_next (list)) {
2808           guint j, timescale;
2809
2810           S = (GstSNode *) list->data;
2811           GST_LOG ("Processing S node: d=%d r=%d t=%d", S->d, S->r, S->t);
2812           duration = S->d * GST_SECOND;
2813           timescale =
2814               stream->cur_seg_template->MultSegBaseType->SegBaseType->timescale;
2815           if (timescale > 1)
2816             duration /= timescale;
2817           if (S->t > 0) {
2818             start = S->t;
2819             start_time = S->t * GST_SECOND;
2820             if (timescale > 1)
2821               start_time /= timescale;
2822           }
2823
2824           for (j = 0; j <= S->r; j++) {
2825             if (!gst_mpd_client_add_media_segment (stream, NULL, i, start,
2826                     start_time, duration)) {
2827               return FALSE;
2828             }
2829             i++;
2830             start += S->d;
2831             start_time += duration;
2832           }
2833         }
2834       } else {
2835         duration = gst_mpd_client_get_segment_duration (client);
2836         if (!GST_CLOCK_TIME_IS_VALID (duration)
2837             || !GST_CLOCK_TIME_IS_VALID (PeriodEnd))
2838           return FALSE;
2839
2840         while (PeriodStart + start_time < PeriodEnd) {
2841           if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time,
2842                   duration)) {
2843             return FALSE;
2844           }
2845           i++;
2846           start_time += duration;
2847         }
2848       }
2849     }
2850   }
2851
2852   /* check duration of last segment */
2853   if(stream->segments)
2854     last_media_segment = g_list_last (stream->segments)->data;
2855   else
2856     last_media_segment = NULL;
2857   if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
2858     if (last_media_segment->start_time + last_media_segment->duration >
2859         PeriodEnd) {
2860       last_media_segment->duration = PeriodEnd - last_media_segment->start_time;
2861       GST_LOG ("Fixed duration of last segment: %" GST_TIME_FORMAT,
2862           GST_TIME_ARGS (last_media_segment->duration));
2863     }
2864     GST_LOG ("Built a list of %d segments", last_media_segment->number);
2865   }
2866
2867   g_free (stream->baseURL);
2868   stream->baseURL = gst_mpdparser_parse_baseURL (client);
2869
2870   return TRUE;
2871 }
2872
2873 gboolean
2874 gst_mpd_client_setup_media_presentation (GstMpdClient * client)
2875 {
2876   GstStreamPeriod *stream_period;
2877   GstPeriodNode *period_node;
2878   GstClockTime start, duration;
2879   GList *list, *next;
2880   guint idx;
2881   gboolean ret = FALSE;
2882
2883   g_return_val_if_fail (client != NULL, FALSE);
2884   g_return_val_if_fail (client->mpd_node != NULL, FALSE);
2885
2886   GST_DEBUG ("Building the list of Periods in the Media Presentation");
2887   GST_MPD_CLIENT_LOCK (client);
2888   /* clean the old period list, if any */
2889   if (client->periods) {
2890     g_list_foreach (client->periods,
2891         (GFunc) gst_mpdparser_free_stream_period, NULL);
2892     g_list_free (client->periods);
2893     client->periods = NULL;
2894   }
2895
2896   idx = 0;
2897   start = 0;
2898   duration = GST_CLOCK_TIME_NONE;
2899   for (list = g_list_first (client->mpd_node->Periods); list;
2900       list = g_list_next (list)) {
2901     period_node = (GstPeriodNode *) list->data;
2902     if (period_node->start != -1) {
2903       /* we have a regular period */
2904       start = period_node->start * GST_MSECOND;
2905     } else if (duration != GST_CLOCK_TIME_NONE) {
2906       /* start time inferred from previous period, this is still a regular period */
2907       start += duration;
2908     } else if (idx == 0 && client->mpd_node->type == GST_MPD_FILE_TYPE_STATIC) {
2909       /* first period of a static MPD file, start time is 0 */
2910       start = 0;
2911     } else {
2912       /* this is an 'Early Available Period' */
2913       goto early;
2914     }
2915
2916     if (period_node->duration != -1) {
2917       duration = period_node->duration * GST_MSECOND;
2918     } else if ((next = g_list_next (list)) != NULL) {
2919       /* try to infer this period duration from the start time of the next period */
2920       GstPeriodNode *next_period_node = next->data;
2921       if (next_period_node->start != -1) {
2922         duration = next_period_node->start * GST_MSECOND - start;
2923       } else {
2924         /* Invalid MPD file! */
2925         goto syntax_error;
2926       }
2927     } else if (client->mpd_node->mediaPresentationDuration != -1) {
2928       /* last Period of the Media Presentation */
2929       duration =
2930           client->mpd_node->mediaPresentationDuration * GST_MSECOND - start;
2931     } else {
2932       /* Invalid MPD file! */
2933       goto syntax_error;
2934     }
2935
2936     stream_period = g_slice_new0 (GstStreamPeriod);
2937     if (stream_period == NULL) {
2938       goto no_mem;
2939     }
2940     client->periods = g_list_append (client->periods, stream_period);
2941     stream_period->period = period_node;
2942     stream_period->number = idx++;
2943     stream_period->start = start;
2944     stream_period->duration = duration;
2945     ret = TRUE;
2946     GST_LOG (" - added Period %d start=%" GST_TIME_FORMAT " duration=%"
2947         GST_TIME_FORMAT, idx, GST_TIME_ARGS (start), GST_TIME_ARGS (duration));
2948   }
2949
2950   GST_MPD_CLIENT_UNLOCK (client);
2951   GST_DEBUG ("Found a total of %d valid Periods in the Media Presentation",
2952       idx);
2953   return ret;
2954
2955 early:
2956   GST_MPD_CLIENT_UNLOCK (client);
2957   GST_WARNING
2958       ("Found an Early Available Period, skipping the rest of the Media Presentation");
2959   return ret;
2960
2961 syntax_error:
2962   GST_MPD_CLIENT_UNLOCK (client);
2963   GST_WARNING
2964       ("Cannot get the duration of the Period %d, skipping the rest of the Media Presentation",
2965       idx);
2966   return ret;
2967
2968 no_mem:
2969   GST_MPD_CLIENT_UNLOCK (client);
2970   GST_WARNING ("Allocation of GstStreamPeriod struct failed!");
2971   return FALSE;
2972 }
2973
2974 gboolean
2975 gst_mpd_client_setup_streaming (GstMpdClient * client,
2976     GstStreamMimeType mimeType, gchar * lang)
2977 {
2978   GstActiveStream *stream;
2979   GstStreamPeriod *stream_period;
2980   GstAdaptationSetNode *adapt_set;
2981   GstRepresentationNode *representation;
2982   GList *rep_list = NULL;
2983
2984   stream_period = gst_mpdparser_get_stream_period (client);
2985   if (stream_period == NULL || stream_period->period == NULL) {
2986     GST_DEBUG ("No more Period nodes in the MPD file, terminating...");
2987     return FALSE;
2988   }
2989
2990   switch (mimeType) {
2991     case GST_STREAM_VIDEO:
2992       /* select the adaptation set for the video pipeline */
2993       adapt_set =
2994           gst_mpdparser_get_adapt_set_with_mimeType_and_idx (stream_period->
2995           period->AdaptationSets, "video", 0);
2996       if (!adapt_set) {
2997         GST_INFO ("No video adaptation set found");
2998         return FALSE;
2999       }
3000       /* retrive the list of representations */
3001       rep_list = adapt_set->Representations;
3002       if (!rep_list) {
3003         GST_WARNING ("Can not retrieve any representation, aborting...");
3004         return FALSE;
3005       }
3006       break;
3007     case GST_STREAM_AUDIO:
3008       adapt_set =
3009           gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang
3010           (stream_period->period->AdaptationSets, "audio", lang);
3011       /* if we did not found the requested audio language, get the first one */
3012       if (!adapt_set)
3013         adapt_set =
3014             gst_mpdparser_get_first_adapt_set_with_mimeType (stream_period->
3015             period->AdaptationSets, "audio");
3016       if (!adapt_set) {
3017         GST_INFO ("No audio adaptation set found");
3018         return FALSE;
3019       }
3020       rep_list = adapt_set->Representations;
3021       if (!rep_list) {
3022         GST_WARNING ("Can not retrieve any representation, aborting...");
3023         return FALSE;
3024       }
3025       break;
3026     case GST_STREAM_APPLICATION:
3027       adapt_set =
3028           gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang
3029           (stream_period->period->AdaptationSets, "application", lang);
3030       /* if we did not found the requested subtitles language, get the first one */
3031       if (!adapt_set)
3032         adapt_set =
3033             gst_mpdparser_get_first_adapt_set_with_mimeType (stream_period->
3034             period->AdaptationSets, "application");
3035       if (!adapt_set) {
3036         GST_INFO ("No application adaptation set found");
3037         return FALSE;
3038       }
3039       rep_list = adapt_set->Representations;
3040       if (!rep_list) {
3041         GST_WARNING ("Can not retrieve any representation, aborting...");
3042         return FALSE;
3043       }
3044       break;
3045     default:
3046       GST_WARNING ("Unsupported mimeType %d", mimeType);
3047       return FALSE;
3048   }
3049
3050   stream = g_slice_new0 (GstActiveStream);
3051   if (stream == NULL) {
3052     GST_WARNING ("Allocation of active stream struct failed!");
3053     return FALSE;
3054   }
3055   client->active_streams = g_list_append (client->active_streams, stream);
3056
3057   stream->baseURL_idx = 0;
3058   stream->mimeType = mimeType;
3059   stream->cur_adapt_set = adapt_set;
3060
3061   /* retrive representation list */
3062   if (stream->cur_adapt_set != NULL)
3063     rep_list = stream->cur_adapt_set->Representations;
3064
3065 #if 0
3066   /* fast start */
3067   representation =
3068       gst_mpdparser_get_representation_with_max_bandwidth (rep_list,
3069       stream->max_bandwidth);
3070
3071   if (!representation) {
3072     GST_WARNING
3073         ("Can not retrieve a representation with the requested bandwidth");
3074     representation = gst_mpdparser_get_lowest_representation (rep_list);
3075   }
3076 #else
3077   /* slow start */
3078   representation = gst_mpdparser_get_lowest_representation (rep_list);
3079 #endif
3080
3081   if (!representation) {
3082     GST_WARNING ("No valid representation in the MPD file, aborting...");
3083     return FALSE;
3084   }
3085
3086   if (!gst_mpd_client_setup_representation (client, stream, representation))
3087     return FALSE;
3088
3089   GST_INFO ("Successfully setup the download pipeline for mimeType %d",
3090       mimeType);
3091
3092   return TRUE;
3093 }
3094
3095 gboolean
3096 gst_mpd_client_get_next_fragment (GstMpdClient * client,
3097     guint indexStream, gboolean * discontinuity, gchar ** uri,
3098     GstClockTime * duration, GstClockTime * timestamp)
3099 {
3100   GstActiveStream *stream = NULL;
3101   GstMediaSegment *currentChunk;
3102   gchar *mediaURL = NULL;
3103   guint segment_idx;
3104
3105   /* select stream */
3106   g_return_val_if_fail (client != NULL, FALSE);
3107   g_return_val_if_fail (client->active_streams != NULL, FALSE);
3108   stream = g_list_nth_data (client->active_streams, indexStream);
3109   g_return_val_if_fail (stream != NULL, FALSE);
3110   g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
3111   g_return_val_if_fail (discontinuity != NULL, FALSE);
3112
3113   GST_MPD_CLIENT_LOCK (client);
3114   segment_idx = gst_mpd_client_get_segment_index (stream);
3115   GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
3116
3117   currentChunk =
3118       gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx);
3119   if (currentChunk == NULL) {
3120     GST_MPD_CLIENT_UNLOCK (client);
3121     return FALSE;
3122   }
3123
3124   if (currentChunk->SegmentURL != NULL) {
3125     mediaURL = gst_mpdparser_get_mediaURL (client, currentChunk->SegmentURL);
3126   } else if (stream->cur_seg_template != NULL) {
3127     mediaURL =
3128         gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media,
3129         stream->cur_representation->id, currentChunk->number,
3130         stream->cur_representation->bandwidth, currentChunk->start);
3131   }
3132
3133   *timestamp = currentChunk->start_time;
3134   *duration = currentChunk->duration;
3135   *discontinuity = segment_idx != currentChunk->number;
3136   if (mediaURL == NULL) {
3137     /* single segment with URL encoded in the baseURL syntax element */
3138     *uri = g_strdup (gst_mpdparser_get_baseURL (client));
3139   } else if (strncmp (mediaURL, "http://", 7) != 0) {
3140     *uri = g_strconcat (gst_mpdparser_get_baseURL (client), mediaURL, NULL);
3141     g_free (mediaURL);
3142   } else {
3143     *uri = mediaURL;
3144   }
3145   gst_mpd_client_set_segment_index (stream, segment_idx + 1);
3146   GST_MPD_CLIENT_UNLOCK (client);
3147
3148   GST_DEBUG ("Loading chunk with URL %s", *uri);
3149
3150   return TRUE;
3151 }
3152
3153 gboolean
3154 gst_mpd_client_get_next_header (GstMpdClient * client, const gchar ** uri,
3155     guint stream_idx)
3156 {
3157   GstActiveStream *stream;
3158   GstStreamPeriod *stream_period;
3159
3160   stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
3161   g_return_val_if_fail (stream != NULL, FALSE);
3162   g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
3163   stream_period = gst_mpdparser_get_stream_period (client);
3164   g_return_val_if_fail (stream_period != NULL, FALSE);
3165   g_return_val_if_fail (stream_period->period != NULL, FALSE);
3166
3167   GST_DEBUG ("Looking for current representation header");
3168   GST_MPD_CLIENT_LOCK (client);
3169   *uri = NULL;
3170   if (stream->cur_segment_base && stream->cur_segment_base->Initialization) {
3171
3172     if (stream->cur_segment_base->Initialization->sourceURL == NULL) {
3173       stream->cur_segment_base->Initialization->sourceURL = gst_mpdparser_get_baseURL (client);
3174     }//if not present initialization @sourceURL attribute, it's mapped to baseURL
3175
3176     *uri =
3177         gst_mpdparser_get_initializationURL (stream->cur_segment_base->
3178         Initialization);
3179   } else if (stream->cur_seg_template) {
3180     const gchar *initialization = NULL;
3181     if (stream->cur_seg_template->initialization) {
3182       initialization = stream->cur_seg_template->initialization;
3183     } else if (stream->cur_adapt_set->SegmentTemplate
3184         && stream->cur_adapt_set->SegmentTemplate->initialization) {
3185       initialization = stream->cur_adapt_set->SegmentTemplate->initialization;
3186     } else if (stream_period->period->SegmentTemplate
3187         && stream_period->period->SegmentTemplate->initialization) {
3188       initialization = stream_period->period->SegmentTemplate->initialization;
3189     }
3190     *uri = gst_mpdparser_build_URL_from_template (initialization,
3191         stream->cur_representation->id, 0,
3192         stream->cur_representation->bandwidth, 0);
3193   }
3194   GST_MPD_CLIENT_UNLOCK (client);
3195
3196   return *uri == NULL ? FALSE : TRUE;
3197 }
3198
3199 GstClockTime
3200 gst_mpd_client_get_current_position (GstMpdClient * client)
3201 {
3202   GstActiveStream *stream;
3203   GstMediaSegment *media_segment;
3204
3205   stream = g_list_nth_data (client->active_streams, client->stream_idx);
3206   g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
3207
3208   media_segment =
3209       g_list_nth_data (stream->segments,
3210       gst_mpd_client_get_segment_index (stream));
3211   g_return_val_if_fail (media_segment != NULL, GST_CLOCK_TIME_NONE);
3212
3213   return media_segment->start_time;
3214 }
3215
3216 GstClockTime
3217 gst_mpd_client_get_next_fragment_duration (GstMpdClient * client)
3218 {
3219   GstActiveStream *stream;
3220   GstMediaSegment *media_segment;
3221
3222   stream = g_list_nth_data (client->active_streams, client->stream_idx);
3223   g_return_val_if_fail (stream != NULL, 0);
3224
3225   media_segment =
3226       g_list_nth_data (stream->segments,
3227       gst_mpd_client_get_segment_index (stream));
3228
3229   return media_segment == NULL ? 0 : media_segment->duration;
3230 }
3231
3232 GstClockTime
3233 gst_mpd_client_get_media_presentation_duration (GstMpdClient * client)
3234 {
3235   GstClockTime duration;
3236
3237   g_return_val_if_fail (client != NULL, GST_CLOCK_TIME_NONE);
3238
3239   GST_MPD_CLIENT_LOCK (client);
3240   if (client->mpd_node->mediaPresentationDuration != -1) {
3241     duration = client->mpd_node->mediaPresentationDuration * GST_MSECOND;
3242   } else {
3243     /* We can only get the duration for on-demand streams */
3244     duration = GST_CLOCK_TIME_NONE;
3245   }
3246   GST_MPD_CLIENT_UNLOCK (client);
3247
3248   return duration;
3249 }
3250
3251 gboolean
3252 gst_mpd_client_set_period_index (GstMpdClient * client, guint period_idx)
3253 {
3254   GstStreamPeriod *next_stream_period;
3255   gboolean ret = FALSE;
3256
3257   g_return_val_if_fail (client != NULL, FALSE);
3258   g_return_val_if_fail (client->periods != NULL, FALSE);
3259
3260   GST_MPD_CLIENT_LOCK (client);
3261   next_stream_period = g_list_nth_data (client->periods, period_idx);
3262   if (next_stream_period != NULL) {
3263     client->period_idx = period_idx;
3264     ret = TRUE;
3265   }
3266   GST_MPD_CLIENT_UNLOCK (client);
3267
3268   return ret;
3269 }
3270
3271 guint
3272 gst_mpd_client_get_period_index (GstMpdClient * client)
3273 {
3274   guint period_idx;
3275
3276   g_return_val_if_fail (client != NULL, 0);
3277   GST_MPD_CLIENT_LOCK (client);
3278   period_idx = client->period_idx;
3279   GST_MPD_CLIENT_UNLOCK (client);
3280
3281   return period_idx;
3282 }
3283
3284 void
3285 gst_mpd_client_set_segment_index_for_all_streams (GstMpdClient * client,
3286     guint segment_idx)
3287 {
3288   GList *list;
3289
3290   g_return_if_fail (client != NULL);
3291   g_return_if_fail (client->active_streams != NULL);
3292
3293   /* FIXME: support multiple streams with different segment duration */
3294   for (list = g_list_first (client->active_streams); list;
3295       list = g_list_next (list)) {
3296     GstActiveStream *stream = (GstActiveStream *) list->data;
3297     if (stream) {
3298       stream->segment_idx = segment_idx;
3299     }
3300   }
3301 }
3302
3303 static void
3304 gst_mpd_client_set_segment_index (GstActiveStream * stream, guint segment_idx)
3305 {
3306   g_return_if_fail (stream != NULL);
3307
3308   stream->segment_idx = segment_idx;
3309 }
3310
3311 guint
3312 gst_mpd_client_get_segment_index (GstActiveStream * stream)
3313 {
3314   g_return_val_if_fail (stream != NULL, 0);
3315
3316   return stream->segment_idx;
3317 }
3318
3319 gboolean
3320 gst_mpd_client_is_live (GstMpdClient * client)
3321 {
3322   g_return_val_if_fail (client != NULL, FALSE);
3323   g_return_val_if_fail (client->mpd_node != NULL, FALSE);
3324
3325   return client->mpd_node->type == GST_MPD_FILE_TYPE_DYNAMIC;
3326 }
3327
3328 guint
3329 gst_mpdparser_get_nb_active_stream (GstMpdClient * client)
3330 {
3331   g_return_val_if_fail (client != NULL, 0);
3332
3333   return g_list_length (client->active_streams);
3334 }
3335
3336 guint
3337 gst_mpdparser_get_nb_adaptationSet (GstMpdClient * client)
3338 {
3339   GstStreamPeriod *stream_period;
3340
3341   stream_period = gst_mpdparser_get_stream_period (client);
3342   g_return_val_if_fail (stream_period != NULL, 0);
3343   g_return_val_if_fail (stream_period->period != NULL, 0);
3344
3345   return g_list_length (stream_period->period->AdaptationSets);
3346 }
3347
3348 GstActiveStream *
3349 gst_mpdparser_get_active_stream_by_index (GstMpdClient * client,
3350     guint stream_idx)
3351 {
3352   g_return_val_if_fail (client != NULL, NULL);
3353   g_return_val_if_fail (client->active_streams != NULL, NULL);
3354
3355   return g_list_nth_data (client->active_streams, stream_idx);
3356 }
3357
3358 static const gchar *
3359 gst_mpdparser_mimetype_to_caps (const gchar * mimeType)
3360 {
3361   if (mimeType == NULL)
3362     return NULL;
3363   if (strcmp (mimeType, "video/mp2t") == 0) {
3364     return "video/mpegts";
3365   } else if (strcmp (mimeType, "video/mp4") == 0) {
3366     return "video/quicktime";
3367   } else if (strcmp (mimeType, "audio/mp4") == 0) {
3368     return "audio/x-m4a";
3369   } else
3370     return mimeType;
3371 }
3372
3373 const gchar *
3374 gst_mpd_client_get_stream_mimeType (GstActiveStream * stream)
3375 {
3376   const gchar *mimeType;
3377
3378   if (stream == NULL || stream->cur_adapt_set == NULL
3379       || stream->cur_representation == NULL)
3380     return NULL;
3381
3382   mimeType = stream->cur_representation->RepresentationBase->mimeType;
3383   if (mimeType == NULL) {
3384     mimeType = stream->cur_adapt_set->RepresentationBase->mimeType;
3385   }
3386
3387   return gst_mpdparser_mimetype_to_caps (mimeType);
3388 }
3389
3390 const gboolean
3391 gst_mpd_client_get_bitstream_switching_flag (GstActiveStream * stream)
3392 {
3393   if (stream == NULL || stream->cur_adapt_set == NULL)
3394     return FALSE;
3395
3396   return stream->cur_adapt_set->bitstreamSwitching;
3397 }
3398
3399 guint
3400 gst_mpd_client_get_video_stream_width (GstActiveStream * stream)
3401 {
3402   guint width;
3403
3404   if (stream == NULL || stream->cur_adapt_set == NULL
3405       || stream->cur_representation == NULL)
3406     return 0;
3407
3408   width = stream->cur_representation->RepresentationBase->width;
3409   if (width == 0) {
3410     width = stream->cur_adapt_set->RepresentationBase->width;
3411   }
3412
3413   return width;
3414 }
3415
3416 guint
3417 gst_mpd_client_get_video_stream_height (GstActiveStream * stream)
3418 {
3419   guint height;
3420
3421   if (stream == NULL || stream->cur_adapt_set == NULL
3422       || stream->cur_representation == NULL)
3423     return 0;
3424
3425   height = stream->cur_representation->RepresentationBase->height;
3426   if (height == 0) {
3427     height = stream->cur_adapt_set->RepresentationBase->height;
3428   }
3429
3430   return height;
3431 }
3432
3433 guint
3434 gst_mpd_client_get_audio_stream_rate (GstActiveStream * stream)
3435 {
3436   const gchar *rate;
3437
3438   if (stream == NULL || stream->cur_adapt_set == NULL
3439       || stream->cur_representation == NULL)
3440     return 0;
3441
3442   rate = stream->cur_representation->RepresentationBase->audioSamplingRate;
3443   if (rate == NULL) {
3444     rate = stream->cur_adapt_set->RepresentationBase->audioSamplingRate;
3445   }
3446
3447   return rate ? atoi (rate) : 0;
3448 }
3449
3450 guint
3451 gst_mpd_client_get_audio_stream_num_channels (GstActiveStream * stream)
3452 {
3453   if (stream == NULL || stream->cur_adapt_set == NULL
3454       || stream->cur_representation == NULL)
3455     return 0;
3456   /* TODO: here we have to parse the AudioChannelConfiguration descriptors */
3457   return 0;
3458 }
3459
3460 guint
3461 gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient * client,
3462     GList ** lang)
3463 {
3464   GstStreamPeriod *stream_period;
3465   GstAdaptationSetNode *adapt_set;
3466   GList *list;
3467   gchar *this_mimeType = "audio";
3468   gchar *mimeType = NULL;
3469   guint nb_adapatation_set = 0;
3470
3471   stream_period = gst_mpdparser_get_stream_period (client);
3472   g_return_val_if_fail (stream_period != NULL, 0);
3473   g_return_val_if_fail (stream_period->period != NULL, 0);
3474
3475   for (list = g_list_first (stream_period->period->AdaptationSets); list;
3476       list = g_list_next (list)) {
3477     adapt_set = (GstAdaptationSetNode *) list->data;
3478     if (adapt_set) {
3479       gchar *this_lang = adapt_set->lang;
3480       GstRepresentationNode *rep;
3481       rep =
3482           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
3483       if (rep->RepresentationBase)
3484         mimeType = rep->RepresentationBase->mimeType;
3485       if (!mimeType && adapt_set->RepresentationBase) {
3486         mimeType = adapt_set->RepresentationBase->mimeType;
3487       }
3488
3489       if (strncmp_ext (mimeType, this_mimeType) == 0) {
3490         if (this_lang) {
3491           nb_adapatation_set++;
3492           *lang = g_list_append (*lang, this_lang);
3493         }
3494       }
3495     }
3496   }
3497
3498   return nb_adapatation_set;
3499 }