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