tizen 2.3.1 release
[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) {
1691         GST_WARNING ("No valid representation in the MPD file, aborting...");
1692         return NULL;
1693       }
1694       if (rep->RepresentationBase)
1695         this_mimeType = rep->RepresentationBase->mimeType;
1696       if (!this_mimeType && adapt_set->RepresentationBase) {
1697         this_mimeType = adapt_set->RepresentationBase->mimeType;
1698       }
1699       if (strncmp_ext (this_mimeType, mimeType) == 0)
1700         return adapt_set;
1701     }
1702   }
1703
1704   return NULL;
1705 }
1706
1707 /* if idx < 0, returns the highest adaptation set with the given mimeType
1708  * if idx >= 0, returns the highest adaptation set with the given mimeType and an index <= idx
1709  */
1710 static GstAdaptationSetNode *
1711 gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
1712     const gchar * mimeType, gint idx)
1713 {
1714   GList *list;
1715   GstAdaptationSetNode *adapt_set, *selected = NULL;
1716   gint i = 0;
1717
1718   if (AdaptationSets == NULL)
1719     return NULL;
1720
1721   for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1722     adapt_set = (GstAdaptationSetNode *) list->data;
1723     if (adapt_set) {
1724       gchar *this_mimeType = NULL;
1725       GstRepresentationNode *rep;
1726       rep =
1727           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1728       if (!rep) {
1729         GST_WARNING ("No valid representation in the MPD file, aborting...");
1730         return NULL;
1731       }
1732       if (rep->RepresentationBase)
1733         this_mimeType = rep->RepresentationBase->mimeType;
1734       if (!this_mimeType && adapt_set->RepresentationBase) {
1735         this_mimeType = adapt_set->RepresentationBase->mimeType;
1736       }
1737       if (strncmp_ext (this_mimeType, mimeType) == 0) {
1738         if (idx < 0 || i <= idx)
1739           selected = adapt_set;
1740         i++;
1741       }
1742     }
1743   }
1744
1745   return selected;
1746 }
1747
1748 static GstAdaptationSetNode *
1749 gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *
1750     AdaptationSets, const gchar * mimeType, const gchar * lang)
1751 {
1752   GList *list;
1753   GstAdaptationSetNode *adapt_set;
1754
1755   if (AdaptationSets == NULL)
1756     return NULL;
1757
1758   for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1759     adapt_set = (GstAdaptationSetNode *) list->data;
1760     if (adapt_set) {
1761       GstRepresentationNode *rep;
1762       gchar *this_lang = adapt_set->lang;
1763       gchar *this_mimeType = NULL;
1764       rep =
1765           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1766       if (!rep) {
1767         GST_WARNING ("No valid representation in the MPD file, aborting...");
1768         return NULL;
1769       }
1770       if (rep->RepresentationBase)
1771         this_mimeType = rep->RepresentationBase->mimeType;
1772       if (!this_mimeType && adapt_set->RepresentationBase) {
1773         this_mimeType = adapt_set->RepresentationBase->mimeType;
1774       }
1775       if (strncmp_ext (this_mimeType, mimeType) == 0
1776           && strncmp_ext (this_lang, lang) == 0)
1777         return adapt_set;
1778     }
1779   }
1780
1781   return NULL;
1782 }
1783
1784 static GstRepresentationNode *
1785 gst_mpdparser_get_lowest_representation (GList * Representations)
1786 {
1787   GList *list = NULL;
1788
1789   if (Representations == NULL)
1790     return NULL;
1791
1792   list = g_list_first (Representations);
1793
1794   return list ? (GstRepresentationNode *) list->data : NULL;
1795 }
1796
1797 #if 0
1798 static GstRepresentationNode *
1799 gst_mpdparser_get_highest_representation (GList * Representations)
1800 {
1801   GList *list = NULL;
1802
1803   if (Representations == NULL)
1804     return NULL;
1805
1806   list = g_list_last (Representations);
1807
1808   return list ? (GstRepresentationNode *) list->data : NULL;
1809 }
1810
1811 static GstRepresentationNode *
1812 gst_mpdparser_get_representation_with_max_bandwidth (GList * Representations,
1813     gint max_bandwidth)
1814 {
1815   GList *list = NULL;
1816   GstRepresentationNode *representation, *best_rep = NULL;
1817
1818   if (Representations == NULL)
1819     return NULL;
1820
1821   if (max_bandwidth <= 0)       /* 0 => get highest representation available */
1822     return gst_mpdparser_get_highest_representation (Representations);
1823
1824   for (list = g_list_first (Representations); list; list = g_list_next (list)) {
1825     representation = (GstRepresentationNode *) list->data;
1826     if (representation && representation->bandwidth <= max_bandwidth) {
1827       best_rep = representation;
1828     }
1829   }
1830
1831   return best_rep;
1832 }
1833 #endif
1834
1835 static GstSegmentBaseType *
1836 gst_mpdparser_get_segment_base (GstPeriodNode * Period,
1837     GstAdaptationSetNode * AdaptationSet,
1838     GstRepresentationNode * Representation)
1839 {
1840   GstSegmentBaseType *SegmentBase = NULL;
1841
1842   if (Representation && Representation->SegmentBase
1843       && Representation->SegmentBase->Initialization) {
1844     SegmentBase = Representation->SegmentBase;
1845   } else if (AdaptationSet && AdaptationSet->SegmentBase
1846       && AdaptationSet->SegmentBase->Initialization) {
1847     SegmentBase = AdaptationSet->SegmentBase;
1848   } else if (Period && Period->SegmentBase
1849       && Period->SegmentBase->Initialization) {
1850     SegmentBase = Period->SegmentBase;
1851   }
1852   /* the SegmentBase element could be encoded also inside a SegmentList element */
1853   if (SegmentBase == NULL) {
1854     if (Representation && Representation->SegmentList
1855         && Representation->SegmentList->MultSegBaseType
1856         && Representation->SegmentList->MultSegBaseType->SegBaseType
1857         && Representation->SegmentList->MultSegBaseType->SegBaseType->
1858         Initialization) {
1859       SegmentBase = Representation->SegmentList->MultSegBaseType->SegBaseType;
1860     } else if (AdaptationSet && AdaptationSet->SegmentList
1861         && AdaptationSet->SegmentList->MultSegBaseType
1862         && AdaptationSet->SegmentList->MultSegBaseType->SegBaseType
1863         && AdaptationSet->SegmentList->MultSegBaseType->SegBaseType->
1864         Initialization) {
1865       SegmentBase = AdaptationSet->SegmentList->MultSegBaseType->SegBaseType;
1866     } else if (Period && Period->SegmentList
1867         && Period->SegmentList->MultSegBaseType
1868         && Period->SegmentList->MultSegBaseType->SegBaseType
1869         && Period->SegmentList->MultSegBaseType->SegBaseType->Initialization) {
1870       SegmentBase = Period->SegmentList->MultSegBaseType->SegBaseType;
1871     }
1872   }
1873
1874   return SegmentBase;
1875 }
1876
1877 gint
1878 gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
1879     guint64 max_bandwidth)
1880 {
1881   GList *list = NULL, *best = NULL;
1882   GstRepresentationNode *representation;
1883   guint64 best_bandwidth = 0;
1884
1885   GST_DEBUG ("max bandwidth %" G_GUINT64_FORMAT, max_bandwidth);
1886
1887   if (Representations == NULL)
1888     return -1;
1889
1890   if (max_bandwidth <= 0)       /* 0 => get lowest representation available */
1891     return 0;
1892
1893   for (list = g_list_first (Representations); list; list = g_list_next (list)) {
1894     representation = (GstRepresentationNode *) list->data;
1895     if (representation && representation->bandwidth <= max_bandwidth &&
1896         representation->bandwidth > best_bandwidth) {
1897       best = list;
1898       best_bandwidth = representation->bandwidth;
1899     }
1900   }
1901
1902   return best ? g_list_position (Representations, best) : -1;
1903 }
1904
1905 static GstSegmentListNode *
1906 gst_mpdparser_get_segment_list (GstPeriodNode * Period,
1907     GstAdaptationSetNode * AdaptationSet,
1908     GstRepresentationNode * Representation)
1909 {
1910   GstSegmentListNode *SegmentList = NULL;
1911
1912   if (Representation && Representation->SegmentList) {
1913     SegmentList = Representation->SegmentList;
1914   } else if (AdaptationSet && AdaptationSet->SegmentList) {
1915     SegmentList = AdaptationSet->SegmentList;
1916   } else {
1917     SegmentList = Period->SegmentList;
1918   }
1919
1920   return SegmentList;
1921 }
1922
1923 /* memory management functions */
1924 static void
1925 gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node)
1926 {
1927   if (mpd_node) {
1928     g_free (mpd_node->default_namespace);
1929     g_free (mpd_node->namespace_xsi);
1930     g_free (mpd_node->namespace_ext);
1931     g_free (mpd_node->schemaLocation);
1932     g_free (mpd_node->id);
1933     g_free (mpd_node->profiles);
1934     if (mpd_node->availabilityStartTime)
1935       gst_date_time_unref (mpd_node->availabilityStartTime);
1936     if (mpd_node->availabilityEndTime)
1937       gst_date_time_unref (mpd_node->availabilityEndTime);
1938     g_list_foreach (mpd_node->ProgramInfo,
1939         (GFunc) gst_mpdparser_free_prog_info_node, NULL);
1940     g_list_free (mpd_node->ProgramInfo);
1941     g_list_foreach (mpd_node->BaseURLs,
1942         (GFunc) gst_mpdparser_free_base_url_node, NULL);
1943     g_list_free (mpd_node->BaseURLs);
1944     g_list_foreach (mpd_node->Locations, (GFunc) g_free, NULL);
1945     g_list_free (mpd_node->Locations);
1946     g_list_foreach (mpd_node->Periods, (GFunc) gst_mpdparser_free_period_node,
1947         NULL);
1948     g_list_free (mpd_node->Periods);
1949     g_list_foreach (mpd_node->Metrics, (GFunc) gst_mpdparser_free_metrics_node,
1950         NULL);
1951     g_list_free (mpd_node->Metrics);
1952     g_slice_free (GstMPDNode, mpd_node);
1953   }
1954 }
1955
1956 static void
1957 gst_mpdparser_free_prog_info_node (GstProgramInformationNode * prog_info_node)
1958 {
1959   if (prog_info_node) {
1960     g_free (prog_info_node->lang);
1961     g_free (prog_info_node->moreInformationURL);
1962     g_free (prog_info_node->Title);
1963     g_free (prog_info_node->Source);
1964     g_free (prog_info_node->Copyright);
1965     g_slice_free (GstProgramInformationNode, prog_info_node);
1966   }
1967 }
1968
1969 static void
1970 gst_mpdparser_free_metrics_node (GstMetricsNode * metrics_node)
1971 {
1972   if (metrics_node) {
1973     g_free (metrics_node->metrics);
1974     g_list_foreach (metrics_node->MetricsRanges,
1975         (GFunc) gst_mpdparser_free_metrics_range_node, NULL);
1976     g_list_free (metrics_node->MetricsRanges);
1977   }
1978 }
1979
1980 static void
1981 gst_mpdparser_free_metrics_range_node (GstMetricsRangeNode * metrics_range_node)
1982 {
1983   if (metrics_range_node) {
1984     g_slice_free (GstMetricsRangeNode, metrics_range_node);
1985   }
1986 }
1987
1988 static void
1989 gst_mpdparser_free_period_node (GstPeriodNode * period_node)
1990 {
1991   if (period_node) {
1992     g_free (period_node->id);
1993     gst_mpdparser_free_seg_base_type_ext (period_node->SegmentBase);
1994     gst_mpdparser_free_segment_list_node (period_node->SegmentList);
1995     gst_mpdparser_free_segment_template_node (period_node->SegmentTemplate);
1996     g_list_foreach (period_node->AdaptationSets,
1997         (GFunc) gst_mpdparser_free_adaptation_set_node, NULL);
1998     g_list_free (period_node->AdaptationSets);
1999     g_list_foreach (period_node->Subsets,
2000         (GFunc) gst_mpdparser_free_subset_node, NULL);
2001     g_list_free (period_node->Subsets);
2002     g_list_foreach (period_node->BaseURLs,
2003         (GFunc) gst_mpdparser_free_base_url_node, NULL);
2004     g_list_free (period_node->BaseURLs);
2005     g_slice_free (GstPeriodNode, period_node);
2006   }
2007 }
2008
2009 static void
2010 gst_mpdparser_free_subset_node (GstSubsetNode * subset_node)
2011 {
2012   if (subset_node) {
2013     g_free (subset_node->contains);
2014     g_slice_free (GstSubsetNode, subset_node);
2015   }
2016 }
2017
2018 static void
2019 gst_mpdparser_free_segment_template_node (GstSegmentTemplateNode *
2020     segment_template_node)
2021 {
2022   if (segment_template_node) {
2023     g_free (segment_template_node->media);
2024     g_free (segment_template_node->index);
2025     g_free (segment_template_node->initialization);
2026     g_free (segment_template_node->bitstreamSwitching);
2027     /* MultipleSegmentBaseType extension */
2028     gst_mpdparser_free_mult_seg_base_type_ext
2029         (segment_template_node->MultSegBaseType);
2030     g_slice_free (GstSegmentTemplateNode, segment_template_node);
2031   }
2032 }
2033
2034 static void
2035 gst_mpdparser_free_representation_base_type (GstRepresentationBaseType *
2036     representation_base)
2037 {
2038   if (representation_base) {
2039     g_free (representation_base->profiles);
2040     g_slice_free (GstRatio, representation_base->sar);
2041     g_slice_free (GstFrameRate, representation_base->frameRate);
2042     g_free (representation_base->audioSamplingRate);
2043     g_free (representation_base->mimeType);
2044     g_free (representation_base->segmentProfiles);
2045     g_free (representation_base->codecs);
2046     g_free (representation_base->scanType);
2047     g_list_foreach (representation_base->FramePacking,
2048         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2049     g_list_free (representation_base->FramePacking);
2050     g_list_foreach (representation_base->AudioChannelConfiguration,
2051         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2052     g_list_free (representation_base->AudioChannelConfiguration);
2053     g_list_foreach (representation_base->ContentProtection,
2054         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2055     g_list_free (representation_base->ContentProtection);
2056     g_slice_free (GstRepresentationBaseType, representation_base);
2057   }
2058 }
2059
2060 static void
2061 gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode *
2062     adaptation_set_node)
2063 {
2064   if (adaptation_set_node) {
2065     g_free (adaptation_set_node->lang);
2066     g_free (adaptation_set_node->contentType);
2067     g_slice_free (GstRatio, adaptation_set_node->par);
2068     g_slice_free (GstFrameRate, adaptation_set_node->minFrameRate);
2069     g_slice_free (GstFrameRate, adaptation_set_node->maxFrameRate);
2070     g_slice_free (GstConditionalUintType,
2071         adaptation_set_node->segmentAlignment);
2072     g_slice_free (GstConditionalUintType,
2073         adaptation_set_node->subsegmentAlignment);
2074     g_list_foreach (adaptation_set_node->Accessibility,
2075         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2076     g_list_free (adaptation_set_node->Accessibility);
2077     g_list_foreach (adaptation_set_node->Role,
2078         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2079     g_list_free (adaptation_set_node->Role);
2080     g_list_foreach (adaptation_set_node->Rating,
2081         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2082     g_list_free (adaptation_set_node->Rating);
2083     g_list_foreach (adaptation_set_node->Viewpoint,
2084         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2085     g_list_free (adaptation_set_node->Viewpoint);
2086     gst_mpdparser_free_representation_base_type
2087         (adaptation_set_node->RepresentationBase);
2088     gst_mpdparser_free_seg_base_type_ext (adaptation_set_node->SegmentBase);
2089     gst_mpdparser_free_segment_list_node (adaptation_set_node->SegmentList);
2090     gst_mpdparser_free_segment_template_node (adaptation_set_node->
2091         SegmentTemplate);
2092     g_list_foreach (adaptation_set_node->BaseURLs,
2093         (GFunc) gst_mpdparser_free_base_url_node, NULL);
2094     g_list_free (adaptation_set_node->BaseURLs);
2095     g_list_foreach (adaptation_set_node->Representations,
2096         (GFunc) gst_mpdparser_free_representation_node, NULL);
2097     g_list_free (adaptation_set_node->Representations);
2098     g_list_foreach (adaptation_set_node->ContentComponents,
2099         (GFunc) gst_mpdparser_free_content_component_node, NULL);
2100     g_list_free (adaptation_set_node->ContentComponents);
2101     g_slice_free (GstAdaptationSetNode, adaptation_set_node);
2102   }
2103 }
2104
2105 static void
2106 gst_mpdparser_free_representation_node (GstRepresentationNode *
2107     representation_node)
2108 {
2109   if (representation_node) {
2110     g_free (representation_node->id);
2111     g_strfreev (representation_node->dependencyId);
2112     g_strfreev (representation_node->mediaStreamStructureId);
2113     gst_mpdparser_free_representation_base_type
2114         (representation_node->RepresentationBase);
2115     g_list_foreach (representation_node->SubRepresentations,
2116         (GFunc) gst_mpdparser_free_subrepresentation_node, NULL);
2117     g_list_free (representation_node->SubRepresentations);
2118     gst_mpdparser_free_seg_base_type_ext (representation_node->SegmentBase);
2119     gst_mpdparser_free_segment_template_node (representation_node->
2120         SegmentTemplate);
2121     gst_mpdparser_free_segment_list_node (representation_node->SegmentList);
2122     g_list_foreach (representation_node->BaseURLs,
2123         (GFunc) gst_mpdparser_free_base_url_node, NULL);
2124     g_list_free (representation_node->BaseURLs);
2125     g_slice_free (GstRepresentationNode, representation_node);
2126   }
2127 }
2128
2129 static void
2130 gst_mpdparser_free_subrepresentation_node (GstSubRepresentationNode *
2131     subrep_node)
2132 {
2133   if (subrep_node) {
2134     gst_mpdparser_free_representation_base_type (subrep_node->
2135         RepresentationBase);
2136     g_free (subrep_node->dependencyLevel);
2137     g_strfreev (subrep_node->contentComponent);
2138   }
2139 }
2140
2141 static void
2142 gst_mpdparser_free_s_node (GstSNode * s_node)
2143 {
2144   if (s_node) {
2145     g_slice_free (GstSNode, s_node);
2146   }
2147 }
2148
2149 static void
2150 gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode * seg_timeline)
2151 {
2152   if (seg_timeline) {
2153     g_list_foreach (seg_timeline->S, (GFunc) gst_mpdparser_free_s_node, NULL);
2154     g_list_free (seg_timeline->S);
2155     g_slice_free (GstSegmentTimelineNode, seg_timeline);
2156   }
2157 }
2158
2159 static void
2160 gst_mpdparser_free_url_type_node (GstURLType * url_type_node)
2161 {
2162   if (url_type_node) {
2163     g_free (url_type_node->sourceURL);
2164     g_slice_free (GstRange, url_type_node->range);
2165     g_slice_free (GstURLType, url_type_node);
2166   }
2167 }
2168
2169 static void
2170 gst_mpdparser_free_seg_base_type_ext (GstSegmentBaseType * seg_base_type)
2171 {
2172   if (seg_base_type) {
2173     g_free (seg_base_type->indexRange);
2174     gst_mpdparser_free_url_type_node (seg_base_type->Initialization);
2175     gst_mpdparser_free_url_type_node (seg_base_type->RepresentationIndex);
2176     g_slice_free (GstSegmentBaseType, seg_base_type);
2177   }
2178 }
2179
2180 static void
2181 gst_mpdparser_free_mult_seg_base_type_ext (GstMultSegmentBaseType *
2182     mult_seg_base_type)
2183 {
2184   if (mult_seg_base_type) {
2185     /* SegmentBaseType extension */
2186     gst_mpdparser_free_seg_base_type_ext (mult_seg_base_type->SegBaseType);
2187     gst_mpdparser_free_segment_timeline_node
2188         (mult_seg_base_type->SegmentTimeline);
2189     gst_mpdparser_free_url_type_node (mult_seg_base_type->BitstreamSwitching);
2190     g_slice_free (GstMultSegmentBaseType, mult_seg_base_type);
2191   }
2192 }
2193
2194 static void
2195 gst_mpdparser_free_segment_list_node (GstSegmentListNode * segment_list_node)
2196 {
2197   if (segment_list_node) {
2198     g_list_foreach (segment_list_node->SegmentURL,
2199         (GFunc) gst_mpdparser_free_segment_url_node, NULL);
2200     g_list_free (segment_list_node->SegmentURL);
2201     /* MultipleSegmentBaseType extension */
2202     gst_mpdparser_free_mult_seg_base_type_ext
2203         (segment_list_node->MultSegBaseType);
2204     g_slice_free (GstSegmentListNode, segment_list_node);
2205   }
2206 }
2207
2208 static void
2209 gst_mpdparser_free_segment_url_node (GstSegmentURLNode * segment_url)
2210 {
2211   if (segment_url) {
2212     g_free (segment_url->media);
2213     g_slice_free (GstRange, segment_url->mediaRange);
2214     g_free (segment_url->index);
2215     g_slice_free (GstRange, segment_url->indexRange);
2216     g_slice_free (GstSegmentURLNode, segment_url);
2217   }
2218 }
2219
2220 static void
2221 gst_mpdparser_free_base_url_node (GstBaseURL * base_url_node)
2222 {
2223   if (base_url_node) {
2224     g_free (base_url_node->baseURL);
2225     g_free (base_url_node->serviceLocation);
2226     g_free (base_url_node->byteRange);
2227     g_slice_free (GstBaseURL, base_url_node);
2228   }
2229 }
2230
2231 static void
2232 gst_mpdparser_free_descriptor_type_node (GstDescriptorType * descriptor_type)
2233 {
2234   if (descriptor_type) {
2235     g_free (descriptor_type->schemeIdUri);
2236     g_free (descriptor_type->value);
2237   }
2238 }
2239
2240 static void
2241 gst_mpdparser_free_content_component_node (GstContentComponentNode *
2242     content_component_node)
2243 {
2244   if (content_component_node) {
2245     g_free (content_component_node->lang);
2246     g_free (content_component_node->contentType);
2247     g_slice_free (GstRatio, content_component_node->par);
2248     g_list_foreach (content_component_node->Accessibility,
2249         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2250     g_list_free (content_component_node->Accessibility);
2251     g_list_foreach (content_component_node->Role,
2252         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2253     g_list_free (content_component_node->Role);
2254     g_list_foreach (content_component_node->Rating,
2255         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2256     g_list_free (content_component_node->Rating);
2257     g_list_foreach (content_component_node->Viewpoint,
2258         (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2259     g_list_free (content_component_node->Viewpoint);
2260     g_slice_free (GstContentComponentNode, content_component_node);
2261   }
2262 }
2263
2264 static void
2265 gst_mpdparser_free_stream_period (GstStreamPeriod * stream_period)
2266 {
2267   if (stream_period) {
2268     g_slice_free (GstStreamPeriod, stream_period);
2269   }
2270 }
2271
2272 static void
2273 gst_mpdparser_free_media_segment (GstMediaSegment * media_segment)
2274 {
2275   if (media_segment) {
2276     g_slice_free (GstMediaSegment, media_segment);
2277   }
2278 }
2279
2280 static void
2281 gst_mpdparser_free_active_stream (GstActiveStream * active_stream)
2282 {
2283   if (active_stream) {
2284     g_list_foreach (active_stream->segments,
2285         (GFunc) gst_mpdparser_free_media_segment, NULL);
2286     if (active_stream->segments)
2287       g_list_free (active_stream->segments);
2288     g_slice_free (GstActiveStream, active_stream);
2289   }
2290 }
2291
2292 static gchar *
2293 gst_mpdparser_get_segmentURL_for_range (const gchar * url, GstRange * range)
2294 {
2295   gchar *segmentURL;
2296
2297   if (range) {
2298     gchar *range_suffix;
2299     range_suffix =
2300         g_strdup_printf ("?range=%llu-%llu", range->first_byte_pos,
2301         range->last_byte_pos);
2302     segmentURL = g_strconcat (url, range_suffix, NULL);
2303     g_free (range_suffix);
2304   } else {
2305     segmentURL = g_strdup (url);
2306   }
2307
2308   return segmentURL;
2309 }
2310
2311 static gchar *
2312 gst_mpdparser_get_mediaURL (GstMpdClient * client,
2313     GstSegmentURLNode * segmentURL)
2314 {
2315   const gchar *url_prefix;
2316
2317   g_return_val_if_fail (client != NULL, NULL);
2318   g_return_val_if_fail (segmentURL != NULL, NULL);
2319
2320   url_prefix =
2321       segmentURL->media ? segmentURL->
2322       media : gst_mpdparser_get_baseURL (client);
2323   g_return_val_if_fail (url_prefix != NULL, NULL);
2324
2325   return gst_mpdparser_get_segmentURL_for_range (url_prefix,
2326       segmentURL->mediaRange);//if not present @media attribute, it is mapped to baseURL
2327 }
2328
2329 static gchar *
2330 gst_mpdparser_get_initializationURL (GstURLType * InitializationURL)
2331 {
2332   g_return_val_if_fail (InitializationURL != NULL, NULL);
2333   g_return_val_if_fail (InitializationURL->sourceURL != NULL, NULL);
2334
2335   return gst_mpdparser_get_segmentURL_for_range (InitializationURL->sourceURL,
2336       InitializationURL->range);
2337 }
2338
2339 static gchar *
2340 gst_mpdparser_build_URL_from_template (const gchar * url_template,
2341     const gchar * id, guint number, guint bandwidth, guint time)
2342 {
2343   static gchar default_format[] = "%01d";
2344   gchar **tokens, *token, *ret, *format;
2345   gint i, num_tokens;
2346   gboolean last_token_par = TRUE;       /* last token was a parameter */
2347
2348   g_return_val_if_fail (url_template != NULL, NULL);
2349   tokens = g_strsplit_set (url_template, "$", -1);
2350   if (!tokens) {
2351     GST_WARNING ("Scan of URL template failed!");
2352     return NULL;
2353   }
2354   num_tokens = g_strv_length (tokens);
2355
2356   for (i = 0; i < num_tokens; i++) {
2357     token = tokens[i];
2358     format = default_format;
2359
2360     if (!g_strcmp0 (token, "RepresentationID")) {
2361       tokens[i] = g_strdup_printf ("%s", id);
2362       g_free (token);
2363       last_token_par = TRUE;
2364     } else if (!strncmp (token, "Number", 6)) {
2365       if (strlen (token) > 6) {
2366         format = token + 6;     /* format tag */
2367       }
2368       tokens[i] = g_strdup_printf (format, number);
2369       g_free (token);
2370       last_token_par = TRUE;
2371     } else if (!strncmp (token, "Bandwidth", 9)) {
2372       if (strlen (token) > 9) {
2373         format = token + 9;     /* format tag */
2374       }
2375       tokens[i] = g_strdup_printf (format, bandwidth);
2376       g_free (token);
2377       last_token_par = TRUE;
2378     } else if (!strncmp (token, "Time", 4)) {
2379       if (strlen (token) > 4) {
2380         format = token + 4;     /* format tag */
2381       }
2382       tokens[i] = g_strdup_printf (format, time);
2383       g_free (token);
2384       last_token_par = TRUE;
2385     } else if (!g_strcmp0 (token, "")) {
2386       if (!last_token_par) {
2387         tokens[i] = g_strdup_printf ("%s", "$");
2388         g_free (token);
2389         last_token_par = TRUE;
2390       }
2391     } else {
2392       last_token_par = FALSE;
2393     }
2394   }
2395
2396   ret = g_strjoinv (NULL, tokens);
2397   g_strfreev (tokens);
2398
2399   return ret;
2400 }
2401
2402 static GstStreamPeriod *
2403 gst_mpdparser_get_stream_period (GstMpdClient * client)
2404 {
2405   g_return_val_if_fail (client != NULL, NULL);
2406   g_return_val_if_fail (client->periods != NULL, NULL);
2407
2408   return g_list_nth_data (client->periods, client->period_idx);
2409 }
2410
2411 /* select a stream and extract the baseURL (if present) */
2412 static gchar *
2413 gst_mpdparser_parse_baseURL (GstMpdClient * client)
2414 {
2415   GstActiveStream *stream;
2416   GstStreamPeriod *stream_period;
2417   GstBaseURL *baseURL;
2418   GList *list;
2419   static gchar *baseURL_array[5];
2420   static gchar empty[] = "";
2421   gchar *ret = NULL;
2422
2423   stream =
2424       gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
2425   g_return_val_if_fail (stream != NULL, empty);
2426   stream_period = gst_mpdparser_get_stream_period (client);
2427   g_return_val_if_fail (stream_period != NULL, empty);
2428   g_return_val_if_fail (stream_period->period != NULL, empty);
2429
2430   baseURL_array[0] = baseURL_array[1] = baseURL_array[2] = baseURL_array[3] =
2431       empty;
2432   baseURL_array[4] = NULL;
2433
2434   /* FIXME: this simple implementation is not fully compliant with RFC 3986 */
2435   if ((list = client->mpd_node->BaseURLs) != NULL) {
2436     baseURL = g_list_nth_data (list, stream->mpd_baseURL_idx);
2437     if (!baseURL) {
2438       baseURL = list->data;
2439     }
2440     baseURL_array[0] = baseURL->baseURL;
2441   }
2442   if ((list = stream_period->period->BaseURLs) != NULL) {
2443     baseURL = g_list_nth_data (list, stream->period_baseURL_idx);
2444     if (!baseURL) {
2445       baseURL = list->data;
2446     }
2447     baseURL_array[1] = baseURL->baseURL;
2448   }
2449   if ((list = stream->cur_adapt_set->BaseURLs) != NULL) {
2450     baseURL = g_list_nth_data (list, stream->adaptset_baseURL_idx);
2451     if (!baseURL) {
2452       baseURL = list->data;
2453     }
2454     baseURL_array[2] = baseURL->baseURL;
2455   }
2456   if ((list = stream->cur_representation->BaseURLs) != NULL) {
2457     baseURL = g_list_nth_data (list, stream->repr_baseURL_idx);
2458     if (!baseURL) {
2459       baseURL = list->data;
2460     }
2461     baseURL_array[3] = baseURL->baseURL;
2462   }
2463
2464   ret = g_strjoinv (NULL, baseURL_array);
2465   /* get base URI from MPD file URI, if the "http" scheme is missing */
2466   if (client->mpd_uri != NULL && strncmp (ret, "http://", 7) != 0) {
2467     gchar *last_sep, *tmp1, *tmp2;
2468     last_sep = strrchr (client->mpd_uri, '/');
2469     if (last_sep) {
2470       tmp1 = g_strndup (client->mpd_uri, last_sep - client->mpd_uri + 1);
2471       tmp2 = ret;
2472       GST_DEBUG ("Got base URI from MPD file URI %s", tmp1);
2473       ret = g_strconcat (tmp1, tmp2, NULL);
2474       g_free (tmp1);
2475       g_free (tmp2);
2476     }
2477   }
2478
2479   return ret;
2480 }
2481
2482 static GstClockTime
2483 gst_mpd_client_get_segment_duration (GstMpdClient * client, GstActiveStream *stream)
2484 {
2485   GstStreamPeriod *stream_period;
2486   GstMultSegmentBaseType *base = NULL;
2487   GstClockTime duration;
2488   guint timescale;
2489
2490   g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
2491   stream_period = gst_mpdparser_get_stream_period (client);
2492   g_return_val_if_fail (stream_period != NULL, GST_CLOCK_TIME_NONE);
2493
2494   if (stream->cur_segment_list) {
2495     base = stream->cur_segment_list->MultSegBaseType;
2496   } else if (stream->cur_seg_template) {
2497     base = stream->cur_seg_template->MultSegBaseType;
2498   }
2499
2500   if (base == NULL || base->SegBaseType == NULL) {
2501     /* this may happen when we have a single segment */
2502     duration = stream_period->duration;
2503   } else {
2504     duration = base->duration * GST_SECOND;
2505     timescale = base->SegBaseType->timescale;
2506
2507     if (timescale > 1)
2508       duration /= timescale;
2509   }
2510
2511   return duration;
2512 }
2513
2514 /*****************************/
2515 /******* API functions *******/
2516 /*****************************/
2517
2518 GstMpdClient *
2519 gst_mpd_client_new ()
2520 {
2521   GstMpdClient *client;
2522
2523   client = g_new0 (GstMpdClient, 1);
2524   client->lock = g_mutex_new ();
2525
2526   client->download_failed_count = 0;
2527
2528   return client;
2529 }
2530
2531 void
2532 gst_active_streams_free (GstMpdClient * client)
2533 {
2534   if (client->active_streams) {
2535     g_list_foreach (client->active_streams,
2536         (GFunc) gst_mpdparser_free_active_stream, NULL);
2537     g_list_free (client->active_streams);
2538     client->active_streams = NULL;
2539   }
2540 }
2541
2542 void
2543 gst_mpd_client_free (GstMpdClient * client)
2544 {
2545   g_return_if_fail (client != NULL);
2546
2547   if (client->mpd_node)
2548     gst_mpdparser_free_mpd_node (client->mpd_node);
2549
2550   if (client->periods) {
2551     g_list_foreach (client->periods,
2552         (GFunc) gst_mpdparser_free_stream_period, NULL);
2553     g_list_free (client->periods);
2554   }
2555
2556   gst_active_streams_free (client);
2557
2558   if (client->lock)
2559     g_mutex_free (client->lock);
2560
2561   g_free (client->mpd_uri);
2562
2563   g_free (client);
2564 }
2565
2566 gboolean
2567 gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
2568 {
2569   if (data) {
2570     xmlDocPtr doc;
2571     xmlNode *root_element = NULL;
2572
2573     GST_DEBUG ("MPD file fully buffered, start parsing...");
2574
2575     GST_MPD_CLIENT_LOCK (client);
2576     /* parse the complete MPD file into a tree (using the libxml2 default parser API) */
2577
2578     /* this initialize the library and check potential ABI mismatches
2579      * between the version it was compiled for and the actual shared
2580      * library used
2581      */
2582     LIBXML_TEST_VERSION
2583         /* parse "data" into a document (which is a libxml2 tree structure xmlDoc) */
2584         doc = xmlReadMemory (data, size, "noname.xml", NULL, 0);
2585     if (doc == NULL) {
2586       GST_ERROR ("failed to parse the MPD file");
2587       GST_MPD_CLIENT_UNLOCK (client);
2588       return FALSE;
2589     } else {
2590       /* get the root element node */
2591       root_element = xmlDocGetRootElement (doc);
2592
2593       if (root_element->type != XML_ELEMENT_NODE
2594           || xmlStrcmp (root_element->name, (xmlChar *) "MPD") != 0) {
2595         GST_ERROR
2596             ("can not find the root element MPD, failed to parse the MPD file");
2597       } else {
2598         /* now we can parse the MPD root node and all children nodes, recursively */
2599         gst_mpdparser_parse_root_node (&client->mpd_node, root_element);
2600       }
2601       /* free the document */
2602       xmlFreeDoc (doc);
2603       /* dump XML library memory for debugging */
2604       xmlMemoryDump ();
2605     }
2606     GST_MPD_CLIENT_UNLOCK (client);
2607
2608     return TRUE;
2609   }
2610
2611   return FALSE;
2612 }
2613
2614 const gchar *
2615 gst_mpdparser_get_baseURL (GstMpdClient * client)
2616 {
2617   GstActiveStream *stream;
2618
2619   g_return_val_if_fail (client != NULL, NULL);
2620   g_return_val_if_fail (client->active_streams != NULL, NULL);
2621   stream = g_list_nth_data (client->active_streams, client->stream_idx);
2622   g_return_val_if_fail (stream != NULL, NULL);
2623
2624   return stream->baseURL;
2625 }
2626
2627 gboolean
2628 gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
2629     guint indexChunk, GstMediaSegment *segment)
2630 {
2631   GstActiveStream *stream;
2632
2633   /* select stream */
2634   g_return_val_if_fail (client != NULL, FALSE);
2635   g_return_val_if_fail (segment != NULL, FALSE);
2636   g_return_val_if_fail (client->active_streams != NULL, FALSE);
2637   stream = g_list_nth_data (client->active_streams, indexStream);
2638   g_return_val_if_fail (stream != NULL, FALSE);
2639
2640   if(stream->segments) {
2641     GstMediaSegment *list_segment;
2642     if ( indexChunk >= g_list_length (stream->segments))
2643       return FALSE;
2644     list_segment = g_list_nth_data (stream->segments, indexChunk);
2645     memcpy (segment, list_segment, sizeof (GstMediaSegment));
2646   } else {
2647     GstClockTime duration;
2648     GstStreamPeriod *stream_period;
2649     GstClockTime start_time;
2650     stream_period = gst_mpdparser_get_stream_period (client);
2651     g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->SegmentTimeline == NULL, FALSE);
2652     g_return_val_if_fail (stream_period != NULL, FALSE);
2653     g_return_val_if_fail (stream_period->period != NULL, FALSE);
2654
2655     duration = gst_mpd_client_get_segment_duration (client, stream);
2656     if (!GST_CLOCK_TIME_IS_VALID (duration))
2657       return FALSE;
2658
2659     start_time = duration * indexChunk;
2660     if (GST_CLOCK_TIME_IS_VALID (stream_period->start) && GST_CLOCK_TIME_IS_VALID (stream_period->duration)
2661       && start_time >= stream_period->start + stream_period->duration)
2662       return FALSE;
2663
2664     segment->number = indexChunk + stream->cur_seg_template->MultSegBaseType->startNumber;
2665     segment->start_time = start_time;
2666     segment->duration = duration;
2667     segment->SegmentURL = NULL;
2668   }
2669
2670   return TRUE;
2671 }
2672
2673 static gboolean
2674 gst_mpd_client_add_media_segment (GstActiveStream * stream,
2675     GstSegmentURLNode * url_node, guint number, guint start,
2676     GstClockTime start_time, GstClockTime duration)
2677 {
2678   GstMediaSegment *media_segment;
2679
2680   media_segment = g_slice_new0 (GstMediaSegment);
2681   if (media_segment == NULL) {
2682     GST_WARNING ("Allocation of GstMediaSegment struct failed!");
2683     return FALSE;
2684   }
2685   stream->segments = g_list_append (stream->segments, media_segment);
2686   media_segment->SegmentURL = url_node;
2687   media_segment->number = number;
2688   media_segment->start = start;
2689   media_segment->start_time = start_time;
2690   media_segment->duration = duration;
2691
2692   return TRUE;
2693 }
2694
2695 gboolean
2696 gst_mpd_client_setup_representation (GstMpdClient * client,
2697     GstActiveStream * stream, GstRepresentationNode * representation)
2698 {
2699   GstStreamPeriod *stream_period;
2700   GList *rep_list;
2701   GstClockTime PeriodStart, PeriodEnd, start_time, duration;
2702   GstMediaSegment *last_media_segment;
2703   guint i, start;
2704
2705   if (stream->cur_adapt_set == NULL) {
2706     GST_WARNING ("No valid AdaptationSet node in the MPD file, aborting...");
2707     return FALSE;
2708   }
2709
2710   rep_list = stream->cur_adapt_set->Representations;
2711   stream->cur_representation = representation;
2712   stream->representation_idx = g_list_index (rep_list, representation);
2713
2714   /* clean the old segment list, if any */
2715   if (stream->segments) {
2716     g_list_foreach (stream->segments,
2717         (GFunc) gst_mpdparser_free_media_segment, NULL);
2718     g_list_free (stream->segments);
2719     stream->segments = NULL;
2720   }
2721
2722   stream_period = gst_mpdparser_get_stream_period (client);
2723   g_return_val_if_fail (stream_period != NULL, FALSE);
2724   g_return_val_if_fail (stream_period->period != NULL, FALSE);
2725
2726   PeriodStart = stream_period->start;
2727   if (GST_CLOCK_TIME_IS_VALID (stream_period->duration))
2728     PeriodEnd = stream_period->start + stream_period->duration;
2729   else
2730     PeriodEnd = GST_CLOCK_TIME_NONE;
2731
2732   GST_LOG ("Building segment list for Period from %" GST_TIME_FORMAT " to %"
2733       GST_TIME_FORMAT, GST_TIME_ARGS (PeriodStart), GST_TIME_ARGS (PeriodEnd));
2734
2735   if (representation->SegmentBase != NULL
2736       || representation->SegmentList != NULL) {
2737     GList *SegmentURL;
2738
2739     /* get the first segment_base of the selected representation */
2740     if ((stream->cur_segment_base =
2741             gst_mpdparser_get_segment_base (stream_period->period,
2742                 stream->cur_adapt_set, representation)) == NULL) {
2743       GST_DEBUG ("No useful SegmentBase node for the current Representation");
2744     }
2745
2746     /* get the first segment_list of the selected representation */
2747     if ((stream->cur_segment_list =
2748             gst_mpdparser_get_segment_list (stream_period->period,
2749                 stream->cur_adapt_set, representation)) == NULL) {
2750       GST_DEBUG ("No useful SegmentList node for the current Representation");
2751       /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
2752       if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, PeriodStart,
2753               PeriodEnd)) {
2754         return FALSE;
2755       }
2756     } else {
2757       /* build the list of GstMediaSegment nodes from the SegmentList node */
2758       SegmentURL = stream->cur_segment_list->SegmentURL;
2759       if (SegmentURL == NULL) {
2760         GST_WARNING
2761             ("No valid list of SegmentURL nodes in the MPD file, aborting...");
2762         return FALSE;
2763       }
2764
2765       /* build segment list */
2766       i = stream->cur_segment_list->MultSegBaseType->startNumber;
2767       start = 0;
2768       start_time = PeriodStart;
2769
2770       GST_LOG ("Building media segment list using a SegmentList node");
2771       if (stream->cur_segment_list->MultSegBaseType->SegmentTimeline) {
2772         GstSegmentTimelineNode *timeline;
2773         GstSNode *S;
2774         GList *list;
2775
2776         timeline = stream->cur_segment_list->MultSegBaseType->SegmentTimeline;
2777         for (list = g_list_first (timeline->S); list; list = g_list_next (list)) {
2778           guint j, timescale;
2779
2780           S = (GstSNode *) list->data;
2781           GST_LOG ("Processing S node: d=%d r=%d t=%d", S->d, S->r, S->t);
2782           duration = S->d * GST_SECOND;
2783           timescale =
2784               stream->cur_segment_list->MultSegBaseType->SegBaseType->timescale;
2785           if (timescale > 1)
2786             duration /= timescale;
2787           if (S->t > 0) {
2788             start = S->t;
2789             start_time = S->t * GST_SECOND;
2790             if (timescale > 1)
2791               start_time /= timescale;
2792           }
2793
2794           for (j = 0; j <= S->r && SegmentURL != NULL; j++) {
2795             if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i,
2796                     start, start_time, duration)) {
2797               return FALSE;
2798             }
2799             i++;
2800             start += S->d;
2801             start_time += duration;
2802             SegmentURL = g_list_next (SegmentURL);
2803           }
2804         }
2805       } else {
2806         duration =gst_mpd_client_get_segment_duration (client, stream);
2807         if (!GST_CLOCK_TIME_IS_VALID (duration))
2808           return FALSE;
2809
2810         while (SegmentURL) {
2811           if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i, 0,
2812                   start_time, duration)) {
2813             return FALSE;
2814           }
2815           i++;
2816           start_time += duration;
2817           SegmentURL = g_list_next (SegmentURL);
2818         }
2819       }
2820     }
2821   } else {
2822     if (representation->SegmentTemplate != NULL) {
2823       stream->cur_seg_template = representation->SegmentTemplate;
2824     } else if (stream->cur_adapt_set->SegmentTemplate != NULL) {
2825       stream->cur_seg_template = stream->cur_adapt_set->SegmentTemplate;
2826     } else if (stream_period->period->SegmentTemplate != NULL) {
2827       stream->cur_seg_template = stream_period->period->SegmentTemplate;
2828     }
2829
2830     if (stream->cur_seg_template == NULL
2831         || stream->cur_seg_template->MultSegBaseType == NULL) {
2832       /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
2833       if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) {
2834         return FALSE;
2835       }
2836     } else {
2837       /* build segment list */
2838       i = stream->cur_seg_template->MultSegBaseType->startNumber;
2839       start = 0;
2840       start_time = PeriodStart;
2841
2842       GST_LOG ("Building media segment list using this template: %s",
2843           stream->cur_seg_template->media);
2844       if (stream->cur_seg_template->MultSegBaseType->SegmentTimeline) {
2845         GstSegmentTimelineNode *timeline;
2846         GstSNode *S;
2847         GList *list;
2848
2849         timeline = stream->cur_seg_template->MultSegBaseType->SegmentTimeline;
2850         for (list = g_list_first (timeline->S); list; list = g_list_next (list)) {
2851           guint j, timescale;
2852
2853           S = (GstSNode *) list->data;
2854           GST_LOG ("Processing S node: d=%d r=%d t=%d", S->d, S->r, S->t);
2855           duration = S->d * GST_SECOND;
2856           timescale =
2857               stream->cur_seg_template->MultSegBaseType->SegBaseType->timescale;
2858           if (timescale > 1)
2859             duration /= timescale;
2860           if (S->t > 0) {
2861             start = S->t;
2862             start_time = S->t * GST_SECOND;
2863             if (timescale > 1)
2864               start_time /= timescale;
2865           }
2866
2867           for (j = 0; j <= S->r; j++) {
2868             if (!gst_mpd_client_add_media_segment (stream, NULL, i, start,
2869                     start_time, duration)) {
2870               return FALSE;
2871             }
2872             i++;
2873             start += S->d;
2874             start_time += duration;
2875           }
2876         }
2877       } else {
2878          /*The segment is created on demand with the template, no need to build a list */
2879       }
2880     }
2881   }
2882
2883   /* check duration of last segment */
2884   if(stream->segments)
2885     last_media_segment = g_list_last (stream->segments)->data;
2886   else
2887     last_media_segment = NULL;
2888   if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
2889     if (last_media_segment->start_time + last_media_segment->duration >
2890         PeriodEnd) {
2891       last_media_segment->duration = PeriodEnd - last_media_segment->start_time;
2892       GST_LOG ("Fixed duration of last segment: %" GST_TIME_FORMAT,
2893           GST_TIME_ARGS (last_media_segment->duration));
2894     }
2895     GST_LOG ("Built a list of %d segments", last_media_segment->number);
2896   }
2897
2898   g_free (stream->baseURL);
2899   stream->baseURL = gst_mpdparser_parse_baseURL (client);
2900
2901   return TRUE;
2902 }
2903
2904 gboolean
2905 gst_mpd_client_setup_media_presentation (GstMpdClient * client)
2906 {
2907   GstStreamPeriod *stream_period;
2908   GstPeriodNode *period_node;
2909   GstClockTime start, duration;
2910   GList *list, *next;
2911   guint idx;
2912   gboolean ret = FALSE;
2913
2914   g_return_val_if_fail (client != NULL, FALSE);
2915   g_return_val_if_fail (client->mpd_node != NULL, FALSE);
2916
2917   GST_DEBUG ("Building the list of Periods in the Media Presentation");
2918   GST_MPD_CLIENT_LOCK (client);
2919   /* clean the old period list, if any */
2920   if (client->periods) {
2921     g_list_foreach (client->periods,
2922         (GFunc) gst_mpdparser_free_stream_period, NULL);
2923     g_list_free (client->periods);
2924     client->periods = NULL;
2925   }
2926
2927   idx = 0;
2928   start = 0;
2929   duration = GST_CLOCK_TIME_NONE;
2930   for (list = g_list_first (client->mpd_node->Periods); list;
2931       list = g_list_next (list)) {
2932     period_node = (GstPeriodNode *) list->data;
2933     if (period_node->start != -1) {
2934       /* we have a regular period */
2935       start = period_node->start * GST_MSECOND;
2936     } else if (duration != GST_CLOCK_TIME_NONE) {
2937       /* start time inferred from previous period, this is still a regular period */
2938       start += duration;
2939     } else if (idx == 0 && client->mpd_node->type == GST_MPD_FILE_TYPE_STATIC) {
2940       /* first period of a static MPD file, start time is 0 */
2941       start = 0;
2942     } else if (gst_mpd_client_is_live (client)) {
2943       /*it should be a live stream, let this pass.*/
2944     } else {
2945       /* this is an 'Early Available Period' */
2946       goto early;
2947     }
2948
2949     if (period_node->duration != -1) {
2950       duration = period_node->duration * GST_MSECOND;
2951     } else if ((next = g_list_next (list)) != NULL) {
2952       /* try to infer this period duration from the start time of the next period */
2953       GstPeriodNode *next_period_node = next->data;
2954       if (next_period_node->start != -1) {
2955         duration = next_period_node->start * GST_MSECOND - start;
2956       } else {
2957         /* Invalid MPD file! */
2958         goto syntax_error;
2959       }
2960     } else if (client->mpd_node->mediaPresentationDuration != -1) {
2961       /* last Period of the Media Presentation */
2962       duration =
2963           client->mpd_node->mediaPresentationDuration * GST_MSECOND - start;
2964     } else if (gst_mpd_client_is_live (client)) {
2965       /*it should be a live stream, let this pass.*/
2966     } else {
2967       /* Invalid MPD file! */
2968       goto syntax_error;
2969     }
2970
2971     stream_period = g_slice_new0 (GstStreamPeriod);
2972     if (stream_period == NULL) {
2973       goto no_mem;
2974     }
2975     client->periods = g_list_append (client->periods, stream_period);
2976     stream_period->period = period_node;
2977     stream_period->number = idx++;
2978     stream_period->start = start;
2979     stream_period->duration = duration;
2980     ret = TRUE;
2981     GST_LOG (" - added Period %d start=%" GST_TIME_FORMAT " duration=%"
2982         GST_TIME_FORMAT, idx, GST_TIME_ARGS (start), GST_TIME_ARGS (duration));
2983   }
2984
2985   GST_MPD_CLIENT_UNLOCK (client);
2986   GST_DEBUG ("Found a total of %d valid Periods in the Media Presentation",
2987       idx);
2988   return ret;
2989
2990 early:
2991   GST_MPD_CLIENT_UNLOCK (client);
2992   GST_WARNING
2993       ("Found an Early Available Period, skipping the rest of the Media Presentation");
2994   return ret;
2995
2996 syntax_error:
2997   GST_MPD_CLIENT_UNLOCK (client);
2998   GST_WARNING
2999       ("Cannot get the duration of the Period %d, skipping the rest of the Media Presentation",
3000       idx);
3001   return ret;
3002
3003 no_mem:
3004   GST_MPD_CLIENT_UNLOCK (client);
3005   GST_WARNING ("Allocation of GstStreamPeriod struct failed!");
3006   return FALSE;
3007 }
3008
3009 gboolean
3010 gst_mpd_client_setup_streaming (GstMpdClient * client,
3011     GstStreamMimeType mimeType, gchar * lang)
3012 {
3013   GstActiveStream *stream;
3014   GstStreamPeriod *stream_period;
3015   GstAdaptationSetNode *adapt_set;
3016   GstRepresentationNode *representation;
3017   GList *rep_list = NULL;
3018
3019   stream_period = gst_mpdparser_get_stream_period (client);
3020   if (stream_period == NULL || stream_period->period == NULL) {
3021     GST_DEBUG ("No more Period nodes in the MPD file, terminating...");
3022     return FALSE;
3023   }
3024
3025   switch (mimeType) {
3026     case GST_STREAM_VIDEO:
3027       /* select the adaptation set for the video pipeline */
3028       adapt_set =
3029           gst_mpdparser_get_adapt_set_with_mimeType_and_idx (stream_period->
3030           period->AdaptationSets, "video", 0);
3031       if (!adapt_set) {
3032         GST_INFO ("No video adaptation set found");
3033         return FALSE;
3034       }
3035       /* retrive the list of representations */
3036       rep_list = adapt_set->Representations;
3037       if (!rep_list) {
3038         GST_WARNING ("Can not retrieve any representation, aborting...");
3039         return FALSE;
3040       }
3041       break;
3042     case GST_STREAM_AUDIO:
3043       adapt_set =
3044           gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang
3045           (stream_period->period->AdaptationSets, "audio", lang);
3046       /* if we did not found the requested audio language, get the first one */
3047       if (!adapt_set)
3048         adapt_set =
3049             gst_mpdparser_get_first_adapt_set_with_mimeType (stream_period->
3050             period->AdaptationSets, "audio");
3051       if (!adapt_set) {
3052         GST_INFO ("No audio adaptation set found");
3053         return FALSE;
3054       }
3055       rep_list = adapt_set->Representations;
3056       if (!rep_list) {
3057         GST_WARNING ("Can not retrieve any representation, aborting...");
3058         return FALSE;
3059       }
3060       break;
3061     case GST_STREAM_APPLICATION:
3062       adapt_set =
3063           gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang
3064           (stream_period->period->AdaptationSets, "application", lang);
3065       /* if we did not found the requested subtitles language, get the first one */
3066       if (!adapt_set)
3067         adapt_set =
3068             gst_mpdparser_get_first_adapt_set_with_mimeType (stream_period->
3069             period->AdaptationSets, "application");
3070       if (!adapt_set) {
3071         GST_INFO ("No application adaptation set found");
3072         return FALSE;
3073       }
3074       rep_list = adapt_set->Representations;
3075       if (!rep_list) {
3076         GST_WARNING ("Can not retrieve any representation, aborting...");
3077         return FALSE;
3078       }
3079       break;
3080     default:
3081       GST_WARNING ("Unsupported mimeType %d", mimeType);
3082       return FALSE;
3083   }
3084
3085   stream = g_slice_new0 (GstActiveStream);
3086   if (stream == NULL) {
3087     GST_WARNING ("Allocation of active stream struct failed!");
3088     return FALSE;
3089   }
3090   client->active_streams = g_list_append (client->active_streams, stream);
3091
3092   stream->mpd_baseURL_idx = 0;
3093   stream->period_baseURL_idx = 0;
3094   stream->adaptset_baseURL_idx = 0;
3095   stream->repr_baseURL_idx = 0;
3096
3097   stream->mimeType = mimeType;
3098   stream->cur_adapt_set = adapt_set;
3099
3100   /* retrive representation list */
3101   if (stream->cur_adapt_set != NULL)
3102     rep_list = stream->cur_adapt_set->Representations;
3103 #if 0
3104   /* fast start */
3105   representation =
3106       gst_mpdparser_get_representation_with_max_bandwidth (rep_list,
3107       stream->max_bandwidth);
3108
3109   if (!representation) {
3110     GST_WARNING
3111         ("Can not retrieve a representation with the requested bandwidth");
3112     representation = gst_mpdparser_get_lowest_representation (rep_list);
3113   }
3114 #else
3115   /* slow start */
3116   representation = gst_mpdparser_get_lowest_representation (rep_list);
3117 #endif
3118
3119   if (!representation) {
3120     GST_WARNING ("No valid representation in the MPD file, aborting...");
3121     return FALSE;
3122   }
3123
3124   if (!gst_mpd_client_setup_representation (client, stream, representation))
3125     return FALSE;
3126
3127   GST_INFO ("Successfully setup the download pipeline for mimeType %d",
3128       mimeType);
3129
3130   return TRUE;
3131 }
3132
3133 gboolean
3134 gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
3135     guint stream_idx, GstClockTime * ts)
3136 {
3137   GstActiveStream *stream;
3138   gint segment_idx;
3139   GstMediaSegment currentChunk;
3140
3141   GST_DEBUG ("Stream index: %i", stream_idx);
3142   stream = g_list_nth_data (client->active_streams, stream_idx);
3143   g_return_val_if_fail (stream != NULL, 0);
3144
3145   GST_MPD_CLIENT_LOCK (client);
3146   segment_idx = gst_mpd_client_get_segment_index (stream);
3147   GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
3148
3149
3150   if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx, &currentChunk)) {
3151     GST_MPD_CLIENT_UNLOCK (client);
3152     return FALSE;
3153   }
3154
3155   *ts = currentChunk.start_time;
3156   GST_MPD_CLIENT_UNLOCK (client);
3157
3158   return TRUE;
3159 }
3160
3161 gboolean
3162 gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client,
3163     guint stream_idx, GstClockTime * ts)
3164 {
3165   GstActiveStream *stream;
3166   gint segment_idx = 0;
3167   GstMediaSegment currentChunk;
3168
3169   GST_DEBUG ("Stream index: %i", stream_idx);
3170   stream = g_list_nth_data (client->active_streams, stream_idx);
3171   g_return_val_if_fail (stream != NULL, 0);
3172
3173   GST_MPD_CLIENT_LOCK (client);
3174   if (stream->segments)
3175     segment_idx = g_list_length (stream->segments) - 1;
3176   GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
3177
3178   if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx,
3179           &currentChunk)) {
3180     GST_MPD_CLIENT_UNLOCK (client);
3181     return FALSE;
3182   }
3183
3184   *ts = currentChunk.start_time;
3185   GST_MPD_CLIENT_UNLOCK (client);
3186
3187   return TRUE;
3188 }
3189
3190 gboolean
3191 gst_mpd_client_get_next_fragment (GstMpdClient * client,
3192     guint indexStream, gboolean * discontinuity, gchar ** uri,
3193     GstClockTime * duration, GstClockTime * timestamp)
3194 {
3195   GstActiveStream *stream = NULL;
3196   GstMediaSegment currentChunk;
3197   gchar *mediaURL = NULL;
3198   guint segment_idx;
3199
3200   /* select stream */
3201   g_return_val_if_fail (client != NULL, FALSE);
3202   g_return_val_if_fail (client->active_streams != NULL, FALSE);
3203   stream = g_list_nth_data (client->active_streams, indexStream);
3204   g_return_val_if_fail (stream != NULL, FALSE);
3205   g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
3206   g_return_val_if_fail (discontinuity != NULL, FALSE);
3207
3208   GST_MPD_CLIENT_LOCK (client);
3209   segment_idx = gst_mpd_client_get_segment_index (stream);
3210   GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
3211
3212   if (!gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx, &currentChunk)) {
3213     GST_MPD_CLIENT_UNLOCK (client);
3214     return FALSE;
3215   }
3216
3217   if (currentChunk.SegmentURL != NULL) {
3218     mediaURL = gst_mpdparser_get_mediaURL (client, currentChunk.SegmentURL);
3219   } else if (stream->cur_seg_template != NULL) {
3220     mediaURL =
3221         gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media,
3222         stream->cur_representation->id, currentChunk.number,
3223         stream->cur_representation->bandwidth, currentChunk.start);
3224   }
3225
3226   *timestamp = currentChunk.start_time;
3227   *duration = currentChunk.duration;
3228   *discontinuity = segment_idx != currentChunk.number;
3229   if (mediaURL == NULL) {
3230     /* single segment with URL encoded in the baseURL syntax element */
3231     *uri = g_strdup (gst_mpdparser_get_baseURL (client));
3232   } else if (strncmp (mediaURL, "http://", 7) != 0) {
3233     *uri = g_strconcat (gst_mpdparser_get_baseURL (client), mediaURL, NULL);
3234     g_free (mediaURL);
3235   } else {
3236     *uri = mediaURL;
3237   }
3238   gst_mpd_client_set_segment_index (stream, segment_idx + 1);
3239   GST_MPD_CLIENT_UNLOCK (client);
3240
3241   GST_DEBUG ("Loading chunk with URL %s", *uri);
3242
3243   return TRUE;
3244 }
3245
3246 gboolean
3247 gst_mpd_client_get_next_header (GstMpdClient * client, const gchar ** uri,
3248     guint stream_idx)
3249 {
3250   GstActiveStream *stream;
3251   GstStreamPeriod *stream_period;
3252
3253   stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
3254   g_return_val_if_fail (stream != NULL, FALSE);
3255   g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
3256   stream_period = gst_mpdparser_get_stream_period (client);
3257   g_return_val_if_fail (stream_period != NULL, FALSE);
3258   g_return_val_if_fail (stream_period->period != NULL, FALSE);
3259
3260   GST_DEBUG ("Looking for current representation header");
3261   GST_MPD_CLIENT_LOCK (client);
3262   *uri = NULL;
3263   if (stream->cur_segment_base && stream->cur_segment_base->Initialization) {
3264
3265     if (stream->cur_segment_base->Initialization->sourceURL == NULL) {
3266       stream->cur_segment_base->Initialization->sourceURL = gst_mpdparser_get_baseURL (client);
3267     }//if not present initialization @sourceURL attribute, it's mapped to baseURL
3268
3269     *uri =
3270         gst_mpdparser_get_initializationURL (stream->cur_segment_base->
3271         Initialization);
3272   } else if (stream->cur_seg_template) {
3273     const gchar *initialization = NULL;
3274     if (stream->cur_seg_template->initialization) {
3275       initialization = stream->cur_seg_template->initialization;
3276     } else if (stream->cur_adapt_set->SegmentTemplate
3277         && stream->cur_adapt_set->SegmentTemplate->initialization) {
3278       initialization = stream->cur_adapt_set->SegmentTemplate->initialization;
3279     } else if (stream_period->period->SegmentTemplate
3280         && stream_period->period->SegmentTemplate->initialization) {
3281       initialization = stream_period->period->SegmentTemplate->initialization;
3282     }
3283     *uri = gst_mpdparser_build_URL_from_template (initialization,
3284         stream->cur_representation->id, 0,
3285         stream->cur_representation->bandwidth, 0);
3286   }
3287   GST_MPD_CLIENT_UNLOCK (client);
3288
3289   return *uri == NULL ? FALSE : TRUE;
3290 }
3291
3292 gboolean
3293 gst_mpd_client_get_stream_current_position (GstMpdClient * client, guint stream_idx, GstClockTime *ts)
3294 {
3295   GstActiveStream *stream;
3296   GstMediaSegment media_segment;
3297   stream = gst_mpdparser_get_active_stream_by_index( client, stream_idx);
3298   g_return_val_if_fail (stream != NULL, FALSE);
3299   if(!gst_mpdparser_get_chunk_by_index(client, stream_idx,
3300                gst_mpd_client_get_segment_index (stream), &media_segment))
3301   {
3302    return FALSE;
3303   }
3304
3305   if (GST_CLOCK_TIME_IS_VALID (media_segment.start_time)) {
3306   *ts = media_segment.start_time;
3307    return TRUE;
3308   } else {
3309    return FALSE;
3310   }
3311 }
3312
3313 GstClockTime
3314 gst_mpd_client_get_next_fragment_duration (GstMpdClient * client)
3315 {
3316   GstActiveStream *stream;
3317   GstMediaSegment *media_segment;
3318   gint seg_idx;
3319
3320   stream = g_list_nth_data (client->active_streams, client->stream_idx);
3321   g_return_val_if_fail (stream != NULL, 0);
3322   seg_idx = gst_mpd_client_get_segment_index (stream);
3323
3324   if(stream->segments) {
3325     media_segment =
3326         g_list_nth_data (stream->segments, seg_idx);
3327     return media_segment == NULL ? 0 : media_segment->duration;
3328   } else {
3329     GstClockTime duration =
3330         gst_mpd_client_get_segment_duration (client, stream);
3331     g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
3332         SegmentTimeline == NULL, 0);
3333
3334     if (GST_CLOCK_TIME_IS_VALID (duration))
3335       return duration;
3336     return 0;
3337   }
3338 }
3339
3340 GstClockTime
3341 gst_mpd_client_get_media_presentation_duration (GstMpdClient * client)
3342 {
3343   GstClockTime duration;
3344
3345   g_return_val_if_fail (client != NULL, GST_CLOCK_TIME_NONE);
3346
3347   GST_MPD_CLIENT_LOCK (client);
3348   if (client->mpd_node->mediaPresentationDuration != -1) {
3349     duration = client->mpd_node->mediaPresentationDuration * GST_MSECOND;
3350   } else {
3351     /* We can only get the duration for on-demand streams */
3352     duration = GST_CLOCK_TIME_NONE;
3353   }
3354   GST_MPD_CLIENT_UNLOCK (client);
3355
3356   return duration;
3357 }
3358
3359 gboolean
3360 gst_mpd_client_set_period_index (GstMpdClient * client, guint period_idx)
3361 {
3362   GstStreamPeriod *next_stream_period;
3363   gboolean ret = FALSE;
3364
3365   g_return_val_if_fail (client != NULL, FALSE);
3366   g_return_val_if_fail (client->periods != NULL, FALSE);
3367
3368   GST_MPD_CLIENT_LOCK (client);
3369   next_stream_period = g_list_nth_data (client->periods, period_idx);
3370   if (next_stream_period != NULL) {
3371     client->period_idx = period_idx;
3372     ret = TRUE;
3373   }
3374   GST_MPD_CLIENT_UNLOCK (client);
3375
3376   return ret;
3377 }
3378
3379 guint
3380 gst_mpd_client_get_period_index (GstMpdClient * client)
3381 {
3382   guint period_idx;
3383
3384   g_return_val_if_fail (client != NULL, 0);
3385   GST_MPD_CLIENT_LOCK (client);
3386   period_idx = client->period_idx;
3387   GST_MPD_CLIENT_UNLOCK (client);
3388
3389   return period_idx;
3390 }
3391
3392 gboolean
3393 gst_mpd_client_set_period_id (GstMpdClient * client, const gchar * period_id)
3394 {
3395   GstStreamPeriod *next_stream_period;
3396   gboolean ret = FALSE;
3397   GList *iter;
3398   gint index = 0;
3399
3400   g_return_val_if_fail (client != NULL, FALSE);
3401   g_return_val_if_fail (client->periods != NULL, FALSE);
3402   g_return_val_if_fail (period_id != NULL, FALSE);
3403
3404   GST_MPD_CLIENT_LOCK (client);
3405   for (iter = client->periods; iter; iter = g_list_next (iter)) {
3406     next_stream_period = iter->data;
3407
3408     if (next_stream_period->period->id
3409         && strcmp (next_stream_period->period->id, period_id) == 0) {
3410       client->period_idx = index;
3411       ret = TRUE;
3412       break;
3413     }
3414     index++;
3415   }
3416   GST_MPD_CLIENT_UNLOCK (client);
3417
3418   return ret;
3419 }
3420
3421 const gchar *
3422 gst_mpd_client_get_period_id (GstMpdClient * client)
3423 {
3424   GstStreamPeriod *period;
3425   gchar *period_id = NULL;
3426
3427   g_return_val_if_fail (client != NULL, 0);
3428   GST_MPD_CLIENT_LOCK (client);
3429   period = g_list_nth_data (client->periods, client->period_idx);
3430   if (period && period->period)
3431     period_id = period->period->id;
3432   GST_MPD_CLIENT_UNLOCK (client);
3433
3434   return period_id;
3435 }
3436
3437 gboolean
3438 gst_mpd_client_has_next_period (GstMpdClient * client)
3439 {
3440   GList *next_stream_period;
3441   g_return_val_if_fail (client != NULL, FALSE);
3442   g_return_val_if_fail (client->periods != NULL, FALSE);
3443
3444   GST_MPD_CLIENT_LOCK (client);
3445   next_stream_period =
3446       g_list_nth_data (client->periods, client->period_idx + 1);
3447   GST_MPD_CLIENT_UNLOCK (client);
3448
3449   return next_stream_period != NULL;
3450 }
3451
3452 void
3453 gst_mpd_client_set_segment_index_for_all_streams (GstMpdClient * client,
3454     guint segment_idx)
3455 {
3456   GList *list;
3457
3458   g_return_if_fail (client != NULL);
3459   g_return_if_fail (client->active_streams != NULL);
3460
3461   /* FIXME: support multiple streams with different segment duration */
3462   for (list = g_list_first (client->active_streams); list;
3463       list = g_list_next (list)) {
3464     GstActiveStream *stream = (GstActiveStream *) list->data;
3465     if (stream) {
3466       stream->segment_idx = segment_idx;
3467     }
3468   }
3469 }
3470
3471 gboolean
3472 gst_mpd_client_set_next_baseURL_for_stream (GstMpdClient * client)
3473 {
3474   GstActiveStream *stream;
3475   GstStreamPeriod *stream_period;
3476   GList *list;
3477
3478   g_return_val_if_fail (client != NULL, FALSE);
3479   g_return_val_if_fail (client->active_streams != NULL, FALSE);
3480
3481   stream = g_list_nth_data (client->active_streams,
3482                             client->stream_idx);
3483   g_return_val_if_fail (stream != NULL, FALSE);
3484   stream_period = gst_mpdparser_get_stream_period (client);
3485   g_return_val_if_fail (stream_period != NULL, FALSE);
3486
3487   if ((list = stream->cur_representation->BaseURLs) != NULL &&
3488       stream->repr_baseURL_idx < g_list_length (list) - 1) {
3489     stream->repr_baseURL_idx++;
3490   } else if ((list = stream->cur_adapt_set->BaseURLs) != NULL &&
3491              stream->adaptset_baseURL_idx < g_list_length (list) - 1) {
3492     stream->adaptset_baseURL_idx++;
3493     stream->repr_baseURL_idx = 0;
3494   } else if ((list = stream_period->period->BaseURLs) != NULL &&
3495              stream->period_baseURL_idx < g_list_length (list) - 1) {
3496     stream->period_baseURL_idx++;
3497     stream->adaptset_baseURL_idx = 0;
3498     stream->repr_baseURL_idx = 0;
3499   } else if ((list = client->mpd_node->BaseURLs) != NULL &&
3500              stream->mpd_baseURL_idx < g_list_length (list) - 1) {
3501       stream->mpd_baseURL_idx++;
3502       stream->period_baseURL_idx = 0;
3503       stream->adaptset_baseURL_idx = 0;
3504       stream->repr_baseURL_idx = 0;
3505   } else {
3506     GST_WARNING ("Unable to change URI: No alternative baseURL available");
3507     return FALSE;
3508   }
3509
3510   stream->baseURL = gst_mpdparser_parse_baseURL (client);
3511
3512   return TRUE;
3513 }
3514
3515 void
3516 gst_mpd_client_set_segment_index (GstActiveStream * stream, guint segment_idx)
3517 {
3518   g_return_if_fail (stream != NULL);
3519
3520   stream->segment_idx = segment_idx;
3521 }
3522
3523 guint
3524 gst_mpd_client_get_segment_index (GstActiveStream * stream)
3525 {
3526   g_return_val_if_fail (stream != NULL, 0);
3527
3528   return stream->segment_idx;
3529 }
3530
3531 gboolean
3532 gst_mpd_client_is_live (GstMpdClient * client)
3533 {
3534   g_return_val_if_fail (client != NULL, FALSE);
3535   g_return_val_if_fail (client->mpd_node != NULL, FALSE);
3536
3537   return client->mpd_node->type == GST_MPD_FILE_TYPE_DYNAMIC;
3538 }
3539
3540 guint
3541 gst_mpdparser_get_nb_active_stream (GstMpdClient * client)
3542 {
3543   g_return_val_if_fail (client != NULL, 0);
3544
3545   return g_list_length (client->active_streams);
3546 }
3547
3548 guint
3549 gst_mpdparser_get_nb_adaptationSet (GstMpdClient * client)
3550 {
3551   GstStreamPeriod *stream_period;
3552
3553   stream_period = gst_mpdparser_get_stream_period (client);
3554   g_return_val_if_fail (stream_period != NULL, 0);
3555   g_return_val_if_fail (stream_period->period != NULL, 0);
3556
3557   return g_list_length (stream_period->period->AdaptationSets);
3558 }
3559
3560 GstActiveStream *
3561 gst_mpdparser_get_active_stream_by_index (GstMpdClient * client,
3562     guint stream_idx)
3563 {
3564   g_return_val_if_fail (client != NULL, NULL);
3565   g_return_val_if_fail (client->active_streams != NULL, NULL);
3566
3567   return g_list_nth_data (client->active_streams, stream_idx);
3568 }
3569
3570 gint
3571 gst_mpd_client_get_video_active_stream_id(GstMpdClient *client) {
3572   guint idx;
3573   g_return_val_if_fail (client != NULL, -1);
3574   g_return_val_if_fail (client->active_streams != NULL, -1);
3575   for (idx = 0; idx < gst_mpdparser_get_nb_active_stream(client); idx++) {
3576    GstActiveStream *stream = gst_mpdparser_get_active_stream_by_index(client, idx);
3577    if( strncmp_ext (gst_mpd_client_get_stream_mimeType (stream), "video") == 0 )
3578      return idx;
3579   }
3580   return -1;
3581 }
3582
3583 gboolean
3584 gst_mpd_client_stream_seek (GstMpdClient * client, gint stream_idx, GstClockTime ts)
3585 {
3586   guint segment_idx = 0;
3587   GstActiveStream *stream;
3588   GST_MPD_CLIENT_LOCK (client);
3589   GST_DEBUG ("mpd client seeking to %"GST_TIME_FORMAT" on stream %d", GST_TIME_ARGS(ts), stream_idx);
3590   stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
3591   g_return_val_if_fail (stream != NULL, FALSE);
3592
3593   if ( GST_CLOCK_TIME_IS_VALID (gst_mpd_client_stream_find_segment (client,
3594           stream_idx, ts, &segment_idx))) {
3595     gst_mpd_client_set_segment_index(stream, segment_idx);
3596   }
3597   GST_MPD_CLIENT_UNLOCK (client);
3598   return TRUE;
3599 }
3600
3601 static GDateTime *
3602 _gst_date_time_to_g_date_time (GstDateTime * datetime)
3603 {
3604   g_return_val_if_fail (datetime != NULL, NULL);
3605   return g_date_time_new_utc ( gst_date_time_get_year (datetime), gst_date_time_get_month(datetime),
3606          gst_date_time_get_day(datetime), gst_date_time_get_hour(datetime),
3607          gst_date_time_get_minute(datetime),gst_date_time_get_second(datetime));
3608 }
3609
3610 gboolean
3611 gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time)
3612 {
3613   GDateTime *start =
3614       _gst_date_time_to_g_date_time (client->mpd_node->availabilityStartTime);
3615   GTimeSpan ts_microseconds;
3616   GstClockTime ts;
3617   gboolean ret = TRUE;
3618   gint i;
3619
3620   g_return_val_if_fail (gst_mpd_client_is_live (client), 0);
3621
3622   ts_microseconds = g_date_time_difference (time, start);
3623   g_date_time_unref (start);
3624
3625   ts = ts_microseconds * GST_USECOND;
3626   for (i=0; i < g_list_length (client->active_streams); i++) {
3627     ret = ret & gst_mpd_client_stream_seek (client, i, ts);
3628   }
3629   return ret;
3630 }
3631
3632 gint
3633 gst_mpd_client_check_time_position (GstMpdClient * client,
3634     GstActiveStream * stream, GstClockTime ts, gint64 * diff)
3635 {
3636   GDateTime *now = g_date_time_new_now_utc ();
3637   GDateTime *start =
3638       _gst_date_time_to_g_date_time (client->mpd_node->availabilityStartTime);
3639   GTimeSpan stream_now;
3640   GTimeSpan ts_microseconds;
3641   GstClockTime duration;
3642
3643   g_return_val_if_fail (gst_mpd_client_is_live (client), 0);
3644
3645   duration = gst_mpd_client_get_segment_duration (client, stream);
3646   stream_now = g_date_time_difference (now, start);
3647   g_date_time_unref (now);
3648   g_date_time_unref (start);
3649
3650   /* sum duration to check if the segment is fully ready */
3651   ts_microseconds = (ts + duration) / GST_USECOND;
3652
3653   /*
3654    * This functions checks if a given ts is in the 'available range' of
3655    * a DASH presentation. This only makes sense for live streams, which
3656    * are continuously adding new segments and removing old ones.
3657    *
3658    * Note: Both the client and the server should use UTC as a time reference.
3659    *
3660    * @ts is the time since the beginning of the stream and we need to find out
3661    * if it is currently available. The server should be hosting segments
3662    *
3663    * * ---------------- ... --- * ----------- * ---- ...
3664    * |
3665    * | past(unavailable) |      | available   | future(unavailable yet)
3666    * |
3667    * * ---------------- ... --- * ----------- * ---- ...
3668    * |                          |             |
3669    * availabilitStartTime       |             UTC now
3670    *                            UTC now - timeShiftBufferDepth
3671    *
3672    * This function should return 0 if @ts is in the 'available' area, 1 for
3673    * 'future' and '-1' for past and the corresponding distance to the
3674    * 'available' area is set to @diff
3675    *
3676    * TODO untested with live presentations with multiple periods as no
3677    * examples for it could be found/generated
3678    */
3679
3680   if (ts_microseconds > stream_now) {
3681     *diff = ts_microseconds - stream_now;
3682     return 1;
3683   }
3684   if (GST_CLOCK_TIME_IS_VALID (client->mpd_node->timeShiftBufferDepth)
3685       && ts_microseconds <
3686       stream_now - client->mpd_node->timeShiftBufferDepth * GST_USECOND) {
3687     *diff = ts_microseconds - stream_now;
3688     return -1;
3689   }
3690
3691   *diff = 0;
3692   return 0;
3693 }
3694
3695 /*Finds the segment with appropriate time*/
3696 GstClockTime
3697 gst_mpd_client_stream_find_segment(GstMpdClient *client, guint stream_idx,
3698                                    GstClockTime seek_pos, guint *seg_num)
3699 {
3700   guint cur_segment_idx=0;
3701   GstMediaSegment *chunk;
3702   GList *list = NULL;
3703   GstClockTime current_pos = 0;
3704   GstActiveStream *stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
3705   g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
3706   if(stream->segments != NULL) {
3707     for (list = g_list_first (stream->segments); list;
3708         list = g_list_next (list)) {
3709       chunk = list->data;
3710       current_pos = chunk->start_time;
3711       if (current_pos <= seek_pos
3712           && seek_pos < current_pos + chunk->duration) {
3713         break;
3714       }
3715       cur_segment_idx++;
3716     }
3717     if(list != NULL) {
3718       *seg_num = cur_segment_idx;
3719       return current_pos;
3720     } else {
3721       return GST_CLOCK_TIME_NONE;
3722     }
3723   } else {
3724     GstClockTime duration;
3725     duration = gst_mpd_client_get_segment_duration (client, stream);
3726     if( !GST_CLOCK_TIME_IS_VALID (duration) )
3727       return FALSE;
3728     *seg_num = seek_pos / duration;
3729     return *seg_num * duration;
3730   }
3731 }
3732
3733 static const gchar *
3734 gst_mpdparser_mimetype_to_caps (const gchar * mimeType)
3735 {
3736   if (mimeType == NULL)
3737     return NULL;
3738   if (strcmp (mimeType, "video/mp2t") == 0) {
3739     return "video/mpegts";
3740   } else if (strcmp (mimeType, "video/mp4") == 0) {
3741     return "video/quicktime";
3742   } else if (strcmp (mimeType, "audio/mp4") == 0) {
3743     return "audio/x-m4a";
3744   } else
3745     return mimeType;
3746 }
3747
3748 const gchar *
3749 gst_mpd_client_get_stream_mimeType (GstActiveStream * stream)
3750 {
3751   const gchar *mimeType;
3752
3753   if (stream == NULL || stream->cur_adapt_set == NULL
3754       || stream->cur_representation == NULL)
3755     return NULL;
3756
3757   mimeType = stream->cur_representation->RepresentationBase->mimeType;
3758   if (mimeType == NULL) {
3759     mimeType = stream->cur_adapt_set->RepresentationBase->mimeType;
3760   }
3761
3762   return gst_mpdparser_mimetype_to_caps (mimeType);
3763 }
3764
3765 const gboolean
3766 gst_mpd_client_get_bitstream_switching_flag (GstActiveStream * stream)
3767 {
3768   if (stream == NULL || stream->cur_adapt_set == NULL)
3769     return FALSE;
3770
3771   return stream->cur_adapt_set->bitstreamSwitching;
3772 }
3773
3774 gboolean
3775 gst_mpd_client_get_max_video_dimensions (GstMpdClient *client, gint *max_width, gint *max_height)
3776 {
3777   GList *period_it, *repr_it;
3778   GstStreamPeriod *period;
3779   GstAdaptationSetNode *adaptset;
3780   GstRepresentationNode *repr;
3781
3782   g_return_val_if_fail (client != NULL, FALSE);
3783   g_return_val_if_fail (max_height != NULL, FALSE);
3784   g_return_val_if_fail (max_width != NULL, FALSE);
3785
3786   *max_width = 0;
3787   *max_height = 0;
3788
3789   period_it = client->periods;
3790   while(period_it) {
3791     period = period_it->data;
3792     adaptset = gst_mpdparser_get_adapt_set_with_mimeType_and_idx (
3793           period->period->AdaptationSets, "video", 0);
3794     if(adaptset == NULL)
3795       continue;
3796     repr_it = adaptset->Representations;
3797
3798     if(adaptset->RepresentationBase->width > *max_width)
3799       *max_width = adaptset->RepresentationBase->width;
3800     if(adaptset->RepresentationBase->height > *max_height)
3801       *max_height = adaptset->RepresentationBase->height;
3802
3803     while(repr_it) {
3804       repr = repr_it->data;
3805       if(repr->RepresentationBase->width > *max_width)
3806         *max_width = repr->RepresentationBase->width;
3807       if(repr->RepresentationBase->height > *max_height)
3808         *max_height = repr->RepresentationBase->height;
3809       repr_it = repr_it->next;
3810     }
3811
3812     period_it = period_it->next;
3813   }
3814   if(*max_width == 0 && *max_height == 0)
3815     return FALSE;
3816   else
3817     return TRUE;
3818 }
3819
3820 guint
3821 gst_mpd_client_get_video_stream_width (GstActiveStream * stream)
3822 {
3823   guint width;
3824
3825   if (stream == NULL || stream->cur_adapt_set == NULL
3826       || stream->cur_representation == NULL)
3827     return 0;
3828
3829   width = stream->cur_representation->RepresentationBase->width;
3830   if (width == 0) {
3831     width = stream->cur_adapt_set->RepresentationBase->width;
3832   }
3833
3834   return width;
3835 }
3836
3837 guint
3838 gst_mpd_client_get_video_stream_height (GstActiveStream * stream)
3839 {
3840   guint height;
3841
3842   if (stream == NULL || stream->cur_adapt_set == NULL
3843       || stream->cur_representation == NULL)
3844     return 0;
3845
3846   height = stream->cur_representation->RepresentationBase->height;
3847   if (height == 0) {
3848     height = stream->cur_adapt_set->RepresentationBase->height;
3849   }
3850
3851   return height;
3852 }
3853
3854 guint
3855 gst_mpd_client_get_video_stream_bandwidth (GstActiveStream * stream)
3856 {
3857   guint bandwidth;
3858
3859   if (stream == NULL || stream->cur_adapt_set == NULL
3860       || stream->cur_representation == NULL)
3861     return 0;
3862
3863   bandwidth = stream->cur_representation->RepresentationBase->bandwidth;
3864   if (bandwidth == 0) {
3865     bandwidth = stream->cur_adapt_set->RepresentationBase->bandwidth;
3866   }
3867
3868   return bandwidth;
3869 }
3870
3871 guint
3872 gst_mpd_client_get_audio_stream_rate (GstActiveStream * stream)
3873 {
3874   const gchar *rate;
3875
3876   if (stream == NULL || stream->cur_adapt_set == NULL
3877       || stream->cur_representation == NULL)
3878     return 0;
3879
3880   rate = stream->cur_representation->RepresentationBase->audioSamplingRate;
3881   if (rate == NULL) {
3882     rate = stream->cur_adapt_set->RepresentationBase->audioSamplingRate;
3883   }
3884
3885   return rate ? atoi (rate) : 0;
3886 }
3887
3888 guint
3889 gst_mpd_client_get_audio_stream_num_channels (GstActiveStream * stream)
3890 {
3891   if (stream == NULL || stream->cur_adapt_set == NULL
3892       || stream->cur_representation == NULL)
3893     return 0;
3894   /* TODO: here we have to parse the AudioChannelConfiguration descriptors */
3895   return 0;
3896 }
3897
3898 guint
3899 gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient * client,
3900     GList ** lang)
3901 {
3902   GstStreamPeriod *stream_period;
3903   GstAdaptationSetNode *adapt_set;
3904   GList *list;
3905   gchar *this_mimeType = "audio";
3906   gchar *mimeType = NULL;
3907   guint nb_adapatation_set = 0;
3908
3909   stream_period = gst_mpdparser_get_stream_period (client);
3910   g_return_val_if_fail (stream_period != NULL, 0);
3911   g_return_val_if_fail (stream_period->period != NULL, 0);
3912
3913   for (list = g_list_first (stream_period->period->AdaptationSets); list;
3914       list = g_list_next (list)) {
3915     adapt_set = (GstAdaptationSetNode *) list->data;
3916     if (adapt_set) {
3917       gchar *this_lang = adapt_set->lang;
3918       GstRepresentationNode *rep;
3919       rep =
3920           gst_mpdparser_get_lowest_representation (adapt_set->Representations);
3921       if (!rep) {
3922         GST_WARNING ("No valid representation in the MPD file, aborting...");
3923         return 0;
3924       }
3925       if (rep->RepresentationBase)
3926         mimeType = rep->RepresentationBase->mimeType;
3927       if (!mimeType && adapt_set->RepresentationBase) {
3928         mimeType = adapt_set->RepresentationBase->mimeType;
3929       }
3930
3931       if (strncmp_ext (mimeType, this_mimeType) == 0) {
3932         if (this_lang) {
3933           nb_adapatation_set++;
3934           *lang = g_list_append (*lang, this_lang);
3935         }
3936       }
3937     }
3938   }
3939
3940   return nb_adapatation_set;
3941 }