2 * DASH MPD parsing library
6 * Copyright (C) 2012 STMicroelectronics
9 * Gianluca Gennari <gennarone@gmail.com>
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.
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.
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.
28 #include <libxml/tree.h>
29 #include "gstfragmented.h"
30 #include "gstmpdparser.h"
32 #define GST_CAT_DEFAULT fragmented_debug
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);
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,
71 static void gst_mpdparser_parse_content_component_node (GList ** list,
73 static void gst_mpdparser_parse_location_node (GList ** list, xmlNode * a_node);
74 static void gst_mpdparser_parse_subrepresentation_node (GList ** list,
76 static void gst_mpdparser_parse_segment_url_node (GList ** list,
78 static void gst_mpdparser_parse_url_type_node (GstURLType ** pointer,
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);
90 gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType **
91 pointer, xmlNode * a_node);
92 static void gst_mpdparser_parse_representation_node (GList ** list,
94 static void gst_mpdparser_parse_adaptation_set_node (GList ** list,
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,
102 static void gst_mpdparser_parse_metrics_range_node (GList ** list,
104 static void gst_mpdparser_parse_metrics_node (GList ** list, xmlNode * a_node);
105 static void gst_mpdparser_parse_root_node (GstMPDNode ** pointer,
108 /* Helper functions */
109 static gint convert_to_millisecs (gint decimals, gint pos);
110 static int strncmp_ext (const char *s1, const char *s2);
111 static GstStreamPeriod *gst_mpdparser_get_stream_period (GstMpdClient * client);
112 static gchar *gst_mpdparser_parse_baseURL (GstMpdClient * client);
113 static gchar *gst_mpdparser_get_segmentURL_for_range (gchar * url,
115 static gchar *gst_mpdparser_get_mediaURL (GstMpdClient * client,
116 GstSegmentURLNode * segmentURL);
117 static gchar *gst_mpdparser_get_initializationURL (GstURLType *
119 static gchar *gst_mpdparser_build_URL_from_template (const gchar * url_template,
120 const gchar * id, guint number, guint bandwidth, guint time);
121 static gboolean gst_mpd_client_add_media_segment (GstActiveStream * stream,
122 GstSegmentURLNode * url_node, guint number, guint start,
123 GstClockTime start_time, GstClockTime duration);
124 static const gchar *gst_mpdparser_mimetype_to_caps (const gchar * mimeType);
125 static GstClockTime gst_mpd_client_get_segment_duration (GstMpdClient * client);
126 static void gst_mpd_client_set_segment_index (GstActiveStream * stream,
130 static GstAdaptationSetNode
131 *gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets,
132 const gchar * mimeType);
133 static GstAdaptationSetNode
134 *gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
135 const gchar * mimeType, gint idx);
136 static GstAdaptationSetNode
137 *gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *
138 AdaptationSets, const gchar * mimeType, const gchar * lang);
141 static GstRepresentationNode *gst_mpdparser_get_lowest_representation (GList *
144 static GstRepresentationNode *gst_mpdparser_get_highest_representation (GList *
146 static GstRepresentationNode
147 *gst_mpdparser_get_representation_with_max_bandwidth (GList *
148 Representations, gint max_bandwidth);
150 static GstSegmentBaseType *gst_mpdparser_get_segment_base (GstPeriodNode *
151 Period, GstAdaptationSetNode * AdaptationSet,
152 GstRepresentationNode * Representation);
153 static GstSegmentListNode *gst_mpdparser_get_segment_list (GstPeriodNode *
154 Period, GstAdaptationSetNode * AdaptationSet,
155 GstRepresentationNode * Representation);
157 /* Memory management */
158 static void gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node);
159 static void gst_mpdparser_free_prog_info_node (GstProgramInformationNode *
161 static void gst_mpdparser_free_metrics_node (GstMetricsNode * metrics_node);
162 static void gst_mpdparser_free_metrics_range_node (GstMetricsRangeNode *
164 static void gst_mpdparser_free_period_node (GstPeriodNode * period_node);
165 static void gst_mpdparser_free_subset_node (GstSubsetNode * subset_node);
166 static void gst_mpdparser_free_segment_template_node (GstSegmentTemplateNode *
167 segment_template_node);
169 gst_mpdparser_free_representation_base_type (GstRepresentationBaseType *
170 representation_base);
171 static void gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode *
172 adaptation_set_node);
173 static void gst_mpdparser_free_representation_node (GstRepresentationNode *
174 representation_node);
175 static void gst_mpdparser_free_subrepresentation_node (GstSubRepresentationNode
177 static void gst_mpdparser_free_s_node (GstSNode * s_node);
178 static void gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode *
180 static void gst_mpdparser_free_url_type_node (GstURLType * url_type_node);
181 static void gst_mpdparser_free_seg_base_type_ext (GstSegmentBaseType *
183 static void gst_mpdparser_free_mult_seg_base_type_ext (GstMultSegmentBaseType *
185 static void gst_mpdparser_free_segment_list_node (GstSegmentListNode *
187 static void gst_mpdparser_free_segment_url_node (GstSegmentURLNode *
189 static void gst_mpdparser_free_base_url_node (GstBaseURL * base_url_node);
190 static void gst_mpdparser_free_descriptor_type_node (GstDescriptorType *
192 static void gst_mpdparser_free_content_component_node (GstContentComponentNode *
193 content_component_node);
194 static void gst_mpdparser_free_stream_period (GstStreamPeriod * stream_period);
195 static void gst_mpdparser_free_media_segment (GstMediaSegment * media_segment);
196 static void gst_mpdparser_free_active_stream (GstActiveStream * active_stream);
198 /* functions to parse node namespaces, content and properties */
200 gst_mpdparser_get_xml_prop_string (xmlNode * a_node, const gchar * property)
202 xmlChar *prop_string;
204 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
206 GST_LOG (" - %s: %s", property, prop_string);
209 return (gchar *) prop_string;
213 gst_mpdparser_get_xml_prop_string_vector_type (xmlNode * a_node,
214 const gchar * property)
216 xmlChar *prop_string;
217 gchar **prop_string_vector = NULL;
220 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
222 prop_string_vector = g_strsplit ((gchar *) prop_string, " ", -1);
223 if (!prop_string_vector) {
224 GST_WARNING ("Scan of string vector property failed!");
227 GST_LOG (" - %s:", property);
228 while (prop_string_vector[i]) {
229 GST_LOG (" %s", prop_string_vector[i]);
232 xmlFree (prop_string);
235 return prop_string_vector;
239 gst_mpdparser_get_xml_prop_unsigned_integer (xmlNode * a_node,
240 const gchar * property, guint default_val)
242 xmlChar *prop_string;
243 guint prop_unsigned_integer = default_val;
245 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
247 if (sscanf ((gchar *) prop_string, "%u", &prop_unsigned_integer)) {
248 GST_LOG (" - %s: %u", property, prop_unsigned_integer);
251 ("failed to parse unsigned integer property %s from xml string %s",
252 property, prop_string);
254 xmlFree (prop_string);
257 return prop_unsigned_integer;
261 gst_mpdparser_get_xml_prop_uint_vector_type (xmlNode * a_node,
262 const gchar * property, guint * size)
264 xmlChar *prop_string;
266 guint *prop_uint_vector = NULL, i;
268 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
270 str_vector = g_strsplit ((gchar *) prop_string, " ", -1);
272 GST_WARNING ("Scan of uint vector property failed!");
275 *size = g_strv_length (str_vector);
276 prop_uint_vector = g_malloc (*size * sizeof (guint));
277 if (!prop_uint_vector) {
278 GST_WARNING ("Array allocation failed!");
280 GST_LOG (" - %s:", property);
281 for (i = 0; i < *size; i++) {
282 if (sscanf ((gchar *) str_vector[i], "%u", &prop_uint_vector[i])) {
283 GST_LOG (" %u", prop_uint_vector[i]);
286 ("failed to parse uint vector type property %s from xml string %s",
287 property, str_vector[i]);
291 xmlFree (prop_string);
292 g_strfreev (str_vector);
295 return prop_uint_vector;
299 gst_mpdparser_get_xml_prop_double (xmlNode * a_node, const gchar * property)
301 xmlChar *prop_string;
302 gdouble prop_double = 0;
304 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
306 if (sscanf ((gchar *) prop_string, "%lf", &prop_double)) {
307 GST_LOG (" - %s: %lf", property, prop_double);
309 GST_WARNING ("failed to parse double property %s from xml string %s",
310 property, prop_string);
312 xmlFree (prop_string);
319 gst_mpdparser_get_xml_prop_boolean (xmlNode * a_node, const gchar * property)
321 xmlChar *prop_string;
322 gboolean prop_bool = FALSE;
324 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
326 if (xmlStrcmp (prop_string, (xmlChar *) "false") == 0) {
327 GST_LOG (" - %s: false", property);
328 } else if (xmlStrcmp (prop_string, (xmlChar *) "true") == 0) {
329 GST_LOG (" - %s: true", property);
332 GST_WARNING ("failed to parse boolean property %s from xml string %s",
333 property, prop_string);
335 xmlFree (prop_string);
341 static GstMPDFileType
342 gst_mpdparser_get_xml_prop_type (xmlNode * a_node, const gchar * property)
344 xmlChar *prop_string;
345 GstMPDFileType prop_type = GST_MPD_FILE_TYPE_STATIC; /* default */
347 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
349 if (xmlStrcmp (prop_string, (xmlChar *) "OnDemand") == 0
350 || xmlStrcmp (prop_string, (xmlChar *) "static") == 0) {
351 GST_LOG (" - %s: static", property);
352 prop_type = GST_MPD_FILE_TYPE_STATIC;
353 } else if (xmlStrcmp (prop_string, (xmlChar *) "Live") == 0
354 || xmlStrcmp (prop_string, (xmlChar *) "dynamic") == 0) {
355 GST_LOG (" - %s: dynamic", property);
356 prop_type = GST_MPD_FILE_TYPE_DYNAMIC;
358 GST_WARNING ("failed to parse MPD type property %s from xml string %s",
359 property, prop_string);
361 xmlFree (prop_string);
368 gst_mpdparser_get_xml_prop_SAP_type (xmlNode * a_node, const gchar * property)
370 xmlChar *prop_string;
371 guint prop_SAP_type = 0;
373 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
375 if (sscanf ((gchar *) prop_string, "%u", &prop_SAP_type)
376 && prop_SAP_type <= 6) {
377 GST_LOG (" - %s: %u", property, prop_SAP_type);
380 ("failed to parse unsigned integer property %s from xml string %s",
381 property, prop_string);
383 xmlFree (prop_string);
386 return (GstSAPType) prop_SAP_type;
390 gst_mpdparser_get_xml_prop_range (xmlNode * a_node, const gchar * property)
392 xmlChar *prop_string;
393 GstRange *prop_range = NULL;
394 guint64 first_byte_pos = 0, last_byte_pos = 0;
398 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
400 len = xmlStrlen (prop_string);
401 str = (gchar *) prop_string;
402 GST_TRACE ("range: %s, len %d", str, len);
405 pos = strcspn (str, "-");
407 GST_TRACE ("pos %d >= len %d", pos, len);
410 /* read first_byte_pos */
412 if (sscanf (str, "%llu", &first_byte_pos) != 1) {
416 /* read last_byte_pos */
417 if (pos < (len - 1)) {
418 if (sscanf (str + pos + 1, "%llu", &last_byte_pos) != 1) {
422 /* malloc return data structure */
423 prop_range = g_slice_new0 (GstRange);
424 if (prop_range == NULL) {
425 GST_WARNING ("Allocation of GstRange failed!");
428 prop_range->first_byte_pos = first_byte_pos;
429 prop_range->last_byte_pos = last_byte_pos;
430 GST_LOG (" - %s: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT,
431 property, first_byte_pos, last_byte_pos);
432 xmlFree (prop_string);
438 GST_WARNING ("failed to parse property %s from xml string %s", property,
444 gst_mpdparser_get_xml_prop_ratio (xmlNode * a_node, const gchar * property)
446 xmlChar *prop_string;
447 GstRatio *prop_ratio = NULL;
448 guint num = 0, den = 1;
452 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
454 len = xmlStrlen (prop_string);
455 str = (gchar *) prop_string;
456 GST_TRACE ("ratio: %s, len %d", str, len);
459 pos = strcspn (str, ":");
461 GST_TRACE ("pos %d >= len %d", pos, len);
466 if (sscanf (str, "%u", &num) != 1) {
471 if (pos < (len - 1)) {
472 if (sscanf (str + pos + 1, "%u", &den) != 1) {
476 /* malloc return data structure */
477 prop_ratio = g_slice_new0 (GstRatio);
478 if (prop_ratio == NULL) {
479 GST_WARNING ("Allocation of GstRatio failed!");
482 prop_ratio->num = num;
483 prop_ratio->den = den;
484 GST_LOG (" - %s: %u:%u", property, num, den);
485 xmlFree (prop_string);
491 GST_WARNING ("failed to parse property %s from xml string %s", property,
496 static GstFrameRate *
497 gst_mpdparser_get_xml_prop_framerate (xmlNode * a_node, const gchar * property)
499 xmlChar *prop_string;
500 GstFrameRate *prop_framerate = NULL;
501 guint num = 0, den = 1;
505 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
507 len = xmlStrlen (prop_string);
508 str = (gchar *) prop_string;
509 GST_TRACE ("framerate: %s, len %d", str, len);
511 /* read "/" if available */
512 pos = strcspn (str, "/");
515 if (sscanf (str, "%u", &num) != 1) {
519 /* read den (if available) */
520 if (pos < (len - 1)) {
521 if (sscanf (str + pos + 1, "%u", &den) != 1) {
525 /* alloc return data structure */
526 prop_framerate = g_slice_new0 (GstFrameRate);
527 if (prop_framerate == NULL) {
528 GST_WARNING ("Allocation of GstFrameRate failed!");
531 prop_framerate->num = num;
532 prop_framerate->den = den;
534 GST_LOG (" - %s: %u", property, num);
536 GST_LOG (" - %s: %u/%u", property, num, den);
537 xmlFree (prop_string);
540 return prop_framerate;
543 GST_WARNING ("failed to parse property %s from xml string %s", property,
548 static GstConditionalUintType *
549 gst_mpdparser_get_xml_prop_cond_uint (xmlNode * a_node, const gchar * property)
551 xmlChar *prop_string;
552 GstConditionalUintType *prop_cond_uint = NULL;
557 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
559 str = (gchar *) prop_string;
560 GST_TRACE ("conditional uint: %s", str);
562 if (strcmp (str, "false") == 0) {
565 } else if (strcmp (str, "true") == 0) {
570 if (sscanf (str, "%u", &val) != 1)
574 /* alloc return data structure */
575 prop_cond_uint = g_slice_new0 (GstConditionalUintType);
576 if (prop_cond_uint == NULL) {
577 GST_WARNING ("Allocation of GstConditionalUintType failed!");
580 prop_cond_uint->flag = flag;
581 prop_cond_uint->value = val;
582 GST_LOG (" - %s: flag=%s val=%u", property, flag ? "true" : "false", val);
583 xmlFree (prop_string);
586 return prop_cond_uint;
589 GST_WARNING ("failed to parse property %s from xml string %s", property,
597 The dateTime data type is used to specify a date and a time.
599 The dateTime is specified in the following form "YYYY-MM-DDThh:mm:ss" where:
601 * YYYY indicates the year
602 * MM indicates the month
603 * DD indicates the day
604 * T indicates the start of the required time section
605 * hh indicates the hour
606 * mm indicates the minute
607 * ss indicates the second
609 Note: All components are required!
613 gst_mpdparser_get_xml_prop_dateTime (xmlNode * a_node, const gchar * property)
615 xmlChar *prop_string;
618 gint year, month, day, hour, minute, second;
620 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
622 len = xmlStrlen (prop_string);
623 str = (gchar *) prop_string;
624 GST_TRACE ("dateTime: %s, len %d", str, len);
626 ret = sscanf (str, "%d", &year);
629 pos = strcspn (str, "-");
631 GST_TRACE (" - year %d", year);
633 ret = sscanf (str, "%d", &month);
636 pos = strcspn (str, "-");
638 GST_TRACE (" - month %d", month);
640 ret = sscanf (str, "%d", &day);
643 pos = strcspn (str, "T");
645 GST_TRACE (" - day %d", day);
647 ret = sscanf (str, "%d", &hour);
650 pos = strcspn (str, ":");
652 GST_TRACE (" - hour %d", hour);
654 ret = sscanf (str, "%d", &minute);
657 pos = strcspn (str, ":");
659 GST_TRACE (" - minute %d", minute);
661 ret = sscanf (str, "%d", &second);
664 GST_TRACE (" - second %d", second);
666 GST_LOG (" - %s: %4d/%02d/%02d %02d:%02d:%02d", property,
667 year, month, day, hour, minute, second);
669 return gst_date_time_new (0, year, month, day, hour, minute, second);
675 GST_WARNING ("failed to parse property %s from xml string %s", property,
683 The duration data type is used to specify a time interval.
685 The time interval is specified in the following form "-PnYnMnDTnHnMnS" where:
687 * - indicates the negative sign (optional)
688 * P indicates the period (required)
689 * nY indicates the number of years
690 * nM indicates the number of months
691 * nD indicates the number of days
692 * T indicates the start of a time section (required if you are going to specify hours, minutes, or seconds)
693 * nH indicates the number of hours
694 * nM indicates the number of minutes
695 * nS indicates the number of seconds
698 /* this function computes decimals * 10 ^ (3 - pos) */
700 convert_to_millisecs (gint decimals, gint pos)
702 gint num = 1, den = 1, i = 3 - pos;
712 /* if i == 0 we have exactly 3 decimals and nothing to do */
713 return decimals * num / den;
717 gst_mpdparser_get_xml_prop_duration (xmlNode * a_node, const gchar * property)
719 xmlChar *prop_string;
721 gint64 prop_duration = -1;
722 gint ret, read, len, pos, posT;
723 gint years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds =
726 gboolean have_ms = FALSE;
728 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
730 len = xmlStrlen (prop_string);
731 str = (gchar *) prop_string;
732 GST_TRACE ("duration: %s, len %d", str, len);
733 /* read "-" for sign, if present */
734 pos = strcspn (str, "-");
735 if (pos < len) { /* found "-" */
737 GST_WARNING ("sign \"-\" non at the beginning of the string");
740 GST_TRACE ("found - sign at the beginning");
745 /* read "P" for period */
746 pos = strcspn (str, "P");
748 GST_WARNING ("P not found at the beginning of the string!");
753 /* read "T" for time (if present) */
754 posT = strcspn (str, "T");
757 /* there is some room between P and T, so there must be a period section */
758 /* read years, months, days */
760 GST_TRACE ("parsing substring %s", str);
761 pos = strcspn (str, "YMD");
762 ret = sscanf (str, "%d", &read);
764 GST_WARNING ("can not read integer value from string %s!", str);
778 GST_WARNING ("unexpected char %c!", str[pos]);
782 GST_TRACE ("read number %d type %c", read, str[pos]);
787 GST_TRACE ("Y:M:D=%d:%d:%d", years, months, days);
789 /* read "T" for time (if present) */
790 /* here T is at pos == 0 */
795 /* T found, there is a time section */
796 /* read hours, minutes, seconds, cents of second */
798 GST_TRACE ("parsing substring %s", str);
799 pos = strcspn (str, "HMS,.");
800 ret = sscanf (str, "%d", &read);
802 GST_WARNING ("can not read integer value from string %s!", str);
814 /* we have read the decimal part of the seconds */
815 decimals = convert_to_millisecs (read, pos);
816 GST_TRACE ("decimal number %d (%d digits) -> %d ms", read, pos,
825 /* we have read the integer part of a decimal number in seconds */
830 GST_WARNING ("unexpected char %c!", str[pos]);
834 GST_TRACE ("read number %d type %c", read, str[pos]);
839 GST_TRACE ("H:M:S.MS=%d:%d:%d.%03d", hours, minutes, seconds, decimals);
842 xmlFree (prop_string);
844 sign * ((((((gint64) years * 365 + months * 30 + days) * 24 +
845 hours) * 60 + minutes) * 60 + seconds) * 1000 + decimals);
846 GST_LOG (" - %s: %" G_GINT64_FORMAT, property, prop_duration);
849 return prop_duration;
853 gst_mpdparser_get_xml_node_content (xmlNode * a_node)
855 xmlChar *content = NULL;
857 content = xmlNodeGetContent (a_node);
859 GST_LOG (" - %s: %s", a_node->name, content);
862 return (gchar *) content;
866 gst_mpdparser_get_xml_node_namespace (xmlNode * a_node, const gchar * prefix)
869 gchar *namespace = NULL;
871 if (prefix == NULL) {
872 /* return the default namespace */
873 namespace = g_strdup ((gchar *) a_node->ns->href);
875 GST_LOG (" - default namespace: %s", namespace);
878 /* look for the specified prefix in the namespace list */
879 for (curr_ns = a_node->ns; curr_ns; curr_ns = curr_ns->next) {
880 if (xmlStrcmp (curr_ns->prefix, (xmlChar *) prefix) == 0) {
881 namespace = g_strdup ((gchar *) curr_ns->href);
883 GST_LOG (" - %s namespace: %s", curr_ns->prefix, curr_ns->href);
893 gst_mpdparser_parse_baseURL_node (GList ** list, xmlNode * a_node)
895 GstBaseURL *new_base_url;
897 new_base_url = g_slice_new0 (GstBaseURL);
898 if (new_base_url == NULL) {
899 GST_WARNING ("Allocation of BaseURL node failed!");
902 *list = g_list_append (*list, new_base_url);
904 GST_LOG ("content of BaseURL node:");
905 new_base_url->baseURL = gst_mpdparser_get_xml_node_content (a_node);
907 GST_LOG ("attributes of BaseURL node:");
908 new_base_url->serviceLocation =
909 gst_mpdparser_get_xml_prop_string (a_node, "serviceLocation");
910 new_base_url->byteRange =
911 gst_mpdparser_get_xml_prop_string (a_node, "byteRange");
915 gst_mpdparser_parse_descriptor_type_node (GList ** list, xmlNode * a_node)
917 GstDescriptorType *new_descriptor;
919 new_descriptor = g_slice_new0 (GstDescriptorType);
920 if (new_descriptor == NULL) {
921 GST_WARNING ("Allocation of DescriptorType node failed!");
924 *list = g_list_append (*list, new_descriptor);
926 GST_LOG ("attributes of %s node:", a_node->name);
927 new_descriptor->schemeIdUri =
928 gst_mpdparser_get_xml_prop_string (a_node, "schemeIdUri");
929 new_descriptor->value = gst_mpdparser_get_xml_prop_string (a_node, "value");
931 /* For adding ContentProtection to caps , get string of <mspr:pro> */
932 if(xmlStrcmp (a_node->name,(xmlChar *) "ContentProtection") == 0) {
933 if (a_node->children->next){
934 if(xmlStrcmp (a_node->children->next->name,(xmlChar *) "pro") == 0){
935 if (a_node->children->next->type == XML_ELEMENT_NODE) {
936 new_descriptor->msprPro = gst_mpdparser_get_xml_node_content (a_node->children->next);
944 gst_mpdparser_parse_content_component_node (GList ** list, xmlNode * a_node)
947 GstContentComponentNode *new_content_component;
949 new_content_component = g_slice_new0 (GstContentComponentNode);
950 if (new_content_component == NULL) {
951 GST_WARNING ("Allocation of ContentComponent node failed!");
954 *list = g_list_append (*list, new_content_component);
956 GST_LOG ("attributes of ContentComponent node:");
957 new_content_component->id =
958 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "id", 0);
959 new_content_component->lang =
960 gst_mpdparser_get_xml_prop_string (a_node, "lang");
961 new_content_component->contentType =
962 gst_mpdparser_get_xml_prop_string (a_node, "contentType");
963 new_content_component->par = gst_mpdparser_get_xml_prop_ratio (a_node, "par");
965 /* explore children nodes */
966 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
967 if (cur_node->type == XML_ELEMENT_NODE) {
968 if (xmlStrcmp (cur_node->name, (xmlChar *) "Accessibility") == 0) {
969 gst_mpdparser_parse_descriptor_type_node (&new_content_component->
970 Accessibility, cur_node);
971 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Role") == 0) {
972 gst_mpdparser_parse_descriptor_type_node (&new_content_component->Role,
974 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Rating") == 0) {
975 gst_mpdparser_parse_descriptor_type_node (&new_content_component->
977 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Viewpoint") == 0) {
978 gst_mpdparser_parse_descriptor_type_node (&new_content_component->
979 Viewpoint, cur_node);
986 gst_mpdparser_parse_location_node (GList ** list, xmlNode * a_node)
990 GST_LOG ("content of Location node:");
991 location = gst_mpdparser_get_xml_node_content (a_node);
993 *list = g_list_append (*list, location);
997 gst_mpdparser_parse_subrepresentation_node (GList ** list, xmlNode * a_node)
999 GstSubRepresentationNode *new_subrep;
1001 new_subrep = g_slice_new0 (GstSubRepresentationNode);
1002 if (new_subrep == NULL) {
1003 GST_WARNING ("Allocation of SubRepresentation node failed!");
1006 *list = g_list_append (*list, new_subrep);
1008 GST_LOG ("attributes of SubRepresentation node:");
1010 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "level", 0);
1011 new_subrep->dependencyLevel =
1012 gst_mpdparser_get_xml_prop_uint_vector_type (a_node, "dependencyLevel",
1014 new_subrep->bandwidth =
1015 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0);
1016 new_subrep->contentComponent =
1017 gst_mpdparser_get_xml_prop_string_vector_type (a_node,
1018 "contentComponent");
1020 /* RepresentationBase extension */
1021 gst_mpdparser_parse_representation_base_type (&new_subrep->RepresentationBase,
1026 gst_mpdparser_parse_segment_url_node (GList ** list, xmlNode * a_node)
1028 GstSegmentURLNode *new_segment_url;
1030 new_segment_url = g_slice_new0 (GstSegmentURLNode);
1031 if (new_segment_url == NULL) {
1032 GST_WARNING ("Allocation of SegmentURL node failed!");
1035 *list = g_list_append (*list, new_segment_url);
1037 GST_LOG ("attributes of SegmentURL node:");
1038 new_segment_url->media = gst_mpdparser_get_xml_prop_string (a_node, "media");
1039 new_segment_url->mediaRange =
1040 gst_mpdparser_get_xml_prop_range (a_node, "mediaRange");
1041 new_segment_url->index = gst_mpdparser_get_xml_prop_string (a_node, "index");
1042 new_segment_url->indexRange =
1043 gst_mpdparser_get_xml_prop_range (a_node, "indexRange");
1047 gst_mpdparser_parse_url_type_node (GstURLType ** pointer, xmlNode * a_node)
1049 GstURLType *new_url_type;
1051 gst_mpdparser_free_url_type_node (*pointer);
1052 *pointer = new_url_type = g_slice_new0 (GstURLType);
1053 if (new_url_type == NULL) {
1054 GST_WARNING ("Allocation of URLType node failed!");
1058 GST_LOG ("attributes of URLType node:");
1059 new_url_type->sourceURL =
1060 gst_mpdparser_get_xml_prop_string (a_node, "sourceURL");
1061 new_url_type->range = gst_mpdparser_get_xml_prop_range (a_node, "range");
1065 gst_mpdparser_parse_seg_base_type_ext (GstSegmentBaseType ** pointer,
1069 GstSegmentBaseType *seg_base_type;
1071 gst_mpdparser_free_seg_base_type_ext (*pointer);
1072 *pointer = seg_base_type = g_slice_new0 (GstSegmentBaseType);
1073 if (seg_base_type == NULL) {
1074 GST_WARNING ("Allocation of SegmentBaseType node failed!");
1078 GST_LOG ("attributes of SegmentBaseType extension:");
1079 seg_base_type->timescale =
1080 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "timescale", 0);
1081 seg_base_type->presentationTimeOffset =
1082 gst_mpdparser_get_xml_prop_unsigned_integer (a_node,
1083 "presentationTimeOffset", 0);
1084 seg_base_type->indexRange =
1085 gst_mpdparser_get_xml_prop_string (a_node, "indexRange");
1086 seg_base_type->indexRangeExact =
1087 gst_mpdparser_get_xml_prop_boolean (a_node, "indexRangeExact");
1089 /* explore children nodes */
1090 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1091 if (cur_node->type == XML_ELEMENT_NODE) {
1092 if (xmlStrcmp (cur_node->name, (xmlChar *) "Initialization") == 0 ||
1093 xmlStrcmp (cur_node->name, (xmlChar *) "Initialisation") == 0) {
1094 gst_mpdparser_parse_url_type_node (&seg_base_type->Initialization,
1096 } else if (xmlStrcmp (cur_node->name,
1097 (xmlChar *) "RepresentationIndex") == 0) {
1098 gst_mpdparser_parse_url_type_node (&seg_base_type->RepresentationIndex,
1106 gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node)
1108 GstSNode *new_s_node;
1110 new_s_node = g_slice_new0 (GstSNode);
1111 if (new_s_node == NULL) {
1112 GST_WARNING ("Allocation of S node failed!");
1115 *list = g_list_append (*list, new_s_node);
1117 GST_LOG ("attributes of S node:");
1118 new_s_node->t = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "t", 0);
1119 new_s_node->d = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "d", 0);
1120 new_s_node->r = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "r", 0);
1124 gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode ** pointer,
1128 GstSegmentTimelineNode *new_seg_timeline;
1130 gst_mpdparser_free_segment_timeline_node (*pointer);
1131 *pointer = new_seg_timeline = g_slice_new0 (GstSegmentTimelineNode);
1132 if (new_seg_timeline == NULL) {
1133 GST_WARNING ("Allocation of SegmentTimeline node failed!");
1137 /* explore children nodes */
1138 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1139 if (cur_node->type == XML_ELEMENT_NODE) {
1140 if (xmlStrcmp (cur_node->name, (xmlChar *) "S") == 0) {
1141 gst_mpdparser_parse_s_node (&new_seg_timeline->S, cur_node);
1148 gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType ** pointer,
1152 GstMultSegmentBaseType *mult_seg_base_type;
1154 gst_mpdparser_free_mult_seg_base_type_ext (*pointer);
1155 *pointer = mult_seg_base_type = g_slice_new0 (GstMultSegmentBaseType);
1156 if (mult_seg_base_type == NULL) {
1157 GST_WARNING ("Allocation of MultipleSegmentBaseType node failed!");
1161 GST_LOG ("attributes of MultipleSegmentBaseType extension:");
1162 mult_seg_base_type->duration =
1163 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "duration", 0);
1164 mult_seg_base_type->startNumber =
1165 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "startNumber", 1);
1167 GST_LOG ("extension of MultipleSegmentBaseType extension:");
1168 gst_mpdparser_parse_seg_base_type_ext (&mult_seg_base_type->SegBaseType,
1171 /* explore children nodes */
1172 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1173 if (cur_node->type == XML_ELEMENT_NODE) {
1174 if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTimeline") == 0) {
1175 gst_mpdparser_parse_segment_timeline_node (&mult_seg_base_type->
1176 SegmentTimeline, cur_node);
1177 } else if (xmlStrcmp (cur_node->name,
1178 (xmlChar *) "BitstreamSwitching") == 0) {
1179 gst_mpdparser_parse_url_type_node (&mult_seg_base_type->
1180 BitstreamSwitching, cur_node);
1187 gst_mpdparser_parse_segment_list_node (GstSegmentListNode ** pointer,
1191 GstSegmentListNode *new_segment_list;
1193 gst_mpdparser_free_segment_list_node (*pointer);
1194 *pointer = new_segment_list = g_slice_new0 (GstSegmentListNode);
1195 if (new_segment_list == NULL) {
1196 GST_WARNING ("Allocation of SegmentList node failed!");
1200 GST_LOG ("extension of SegmentList node:");
1201 gst_mpdparser_parse_mult_seg_base_type_ext (&new_segment_list->
1202 MultSegBaseType, a_node);
1204 /* explore children nodes */
1205 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1206 if (cur_node->type == XML_ELEMENT_NODE) {
1207 if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentURL") == 0) {
1208 gst_mpdparser_parse_segment_url_node (&new_segment_list->SegmentURL,
1216 gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType **
1217 pointer, xmlNode * a_node)
1220 GstRepresentationBaseType *representation_base;
1222 gst_mpdparser_free_representation_base_type (*pointer);
1223 *pointer = representation_base = g_slice_new0 (GstRepresentationBaseType);
1224 if (representation_base == NULL) {
1225 GST_WARNING ("Allocation of RepresentationBaseType node failed!");
1229 GST_LOG ("attributes of RepresentationBaseType extension:");
1230 representation_base->profiles =
1231 gst_mpdparser_get_xml_prop_string (a_node, "profiles");
1232 representation_base->width =
1233 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "width", 0);
1234 representation_base->height =
1235 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "height", 0);
1236 representation_base->sar = gst_mpdparser_get_xml_prop_ratio (a_node, "sar");
1237 representation_base->frameRate =
1238 gst_mpdparser_get_xml_prop_framerate (a_node, "frameRate");
1239 representation_base->audioSamplingRate =
1240 gst_mpdparser_get_xml_prop_string (a_node, "audioSamplingRate");
1241 representation_base->mimeType =
1242 gst_mpdparser_get_xml_prop_string (a_node, "mimeType");
1243 representation_base->segmentProfiles =
1244 gst_mpdparser_get_xml_prop_string (a_node, "segmentProfiles");
1245 representation_base->codecs =
1246 gst_mpdparser_get_xml_prop_string (a_node, "codecs");
1247 representation_base->maximumSAPPeriod =
1248 gst_mpdparser_get_xml_prop_double (a_node, "maximumSAPPeriod");
1249 representation_base->startWithSAP =
1250 gst_mpdparser_get_xml_prop_SAP_type (a_node, "startWithSAP");
1251 representation_base->maxPlayoutRate =
1252 gst_mpdparser_get_xml_prop_double (a_node, "maxPlayoutRate");
1253 representation_base->codingDependency =
1254 gst_mpdparser_get_xml_prop_boolean (a_node, "codingDependency");
1255 representation_base->scanType =
1256 gst_mpdparser_get_xml_prop_string (a_node, "scanType");
1258 /* explore children nodes */
1259 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1260 if (cur_node->type == XML_ELEMENT_NODE) {
1261 if (xmlStrcmp (cur_node->name, (xmlChar *) "FramePacking") == 0) {
1262 gst_mpdparser_parse_descriptor_type_node (&representation_base->
1263 FramePacking, cur_node);
1264 } else if (xmlStrcmp (cur_node->name,
1265 (xmlChar *) "AudioChannelConfiguration") == 0) {
1266 gst_mpdparser_parse_descriptor_type_node (&representation_base->
1267 AudioChannelConfiguration, cur_node);
1268 } else if (xmlStrcmp (cur_node->name,
1269 (xmlChar *) "ContentProtection") == 0) {
1270 gst_mpdparser_parse_descriptor_type_node (&representation_base->
1271 ContentProtection, cur_node);
1278 gst_mpdparser_parse_representation_node (GList ** list, xmlNode * a_node)
1281 GstRepresentationNode *new_representation;
1283 new_representation = g_slice_new0 (GstRepresentationNode);
1284 if (new_representation == NULL) {
1285 GST_WARNING ("Allocation of Representation node failed!");
1288 *list = g_list_append (*list, new_representation);
1290 GST_LOG ("attributes of Representation node:");
1291 new_representation->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1292 new_representation->bandwidth =
1293 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0);
1294 new_representation->qualityRanking =
1295 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "qualityRanking", 0);
1296 new_representation->dependencyId =
1297 gst_mpdparser_get_xml_prop_string_vector_type (a_node, "dependencyId");
1298 new_representation->mediaStreamStructureId =
1299 gst_mpdparser_get_xml_prop_string_vector_type (a_node,
1300 "mediaStreamStructureId");
1302 /* RepresentationBase extension */
1303 gst_mpdparser_parse_representation_base_type (&new_representation->
1304 RepresentationBase, a_node);
1306 /* explore children nodes */
1307 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1308 if (cur_node->type == XML_ELEMENT_NODE) {
1309 if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1310 gst_mpdparser_parse_seg_base_type_ext (&new_representation->SegmentBase,
1312 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1313 gst_mpdparser_parse_segment_template_node (&new_representation->
1314 SegmentTemplate, cur_node);
1315 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1316 gst_mpdparser_parse_segment_list_node (&new_representation->SegmentList,
1318 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1319 gst_mpdparser_parse_baseURL_node (&new_representation->BaseURLs,
1321 } else if (xmlStrcmp (cur_node->name,
1322 (xmlChar *) "SubRepresentation") == 0) {
1323 gst_mpdparser_parse_subrepresentation_node (&new_representation->
1324 SubRepresentations, cur_node);
1331 gst_mpdparser_parse_adaptation_set_node (GList ** list, xmlNode * a_node)
1334 GstAdaptationSetNode *new_adap_set;
1336 new_adap_set = g_slice_new0 (GstAdaptationSetNode);
1337 if (new_adap_set == NULL) {
1338 GST_WARNING ("Allocation of AdaptationSet node failed!");
1341 *list = g_list_append (*list, new_adap_set);
1343 GST_LOG ("attributes of AdaptationSet node:");
1345 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "id", 0);
1346 new_adap_set->group =
1347 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "group", 0);
1348 new_adap_set->lang = gst_mpdparser_get_xml_prop_string (a_node, "lang");
1349 new_adap_set->contentType =
1350 gst_mpdparser_get_xml_prop_string (a_node, "contentType");
1351 new_adap_set->par = gst_mpdparser_get_xml_prop_ratio (a_node, "par");
1352 new_adap_set->minBandwidth =
1353 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minBandwidth", 0);
1354 new_adap_set->maxBandwidth =
1355 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxBandwidth", 0);
1356 new_adap_set->minWidth =
1357 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minWidth", 0);
1358 new_adap_set->maxWidth =
1359 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxWidth", 0);
1360 new_adap_set->minHeight =
1361 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minHeight", 0);
1362 new_adap_set->maxHeight =
1363 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxHeight", 0);
1364 new_adap_set->minFrameRate =
1365 gst_mpdparser_get_xml_prop_framerate (a_node, "minFrameRate");
1366 new_adap_set->maxFrameRate =
1367 gst_mpdparser_get_xml_prop_framerate (a_node, "maxFrameRate");
1368 new_adap_set->segmentAlignment =
1369 gst_mpdparser_get_xml_prop_cond_uint (a_node, "segmentAlignment");
1370 new_adap_set->subsegmentAlignment =
1371 gst_mpdparser_get_xml_prop_cond_uint (a_node, "subsegmentAlignment");
1372 new_adap_set->subsegmentStartsWithSAP =
1373 gst_mpdparser_get_xml_prop_SAP_type (a_node, "subsegmentStartsWithSAP");
1374 new_adap_set->bitstreamSwitching =
1375 gst_mpdparser_get_xml_prop_boolean (a_node, "bitstreamSwitching");
1377 /* RepresentationBase extension */
1378 gst_mpdparser_parse_representation_base_type (&new_adap_set->
1379 RepresentationBase, a_node);
1381 /* explore children nodes */
1382 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1383 if (cur_node->type == XML_ELEMENT_NODE) {
1384 if (xmlStrcmp (cur_node->name, (xmlChar *) "Accessibility") == 0) {
1385 gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Accessibility,
1387 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Role") == 0) {
1388 gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Role,
1390 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Rating") == 0) {
1391 gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Rating,
1393 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Viewpoint") == 0) {
1394 gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Viewpoint,
1396 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Representation") == 0) {
1397 gst_mpdparser_parse_representation_node (&new_adap_set->Representations,
1399 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1400 gst_mpdparser_parse_baseURL_node (&new_adap_set->BaseURLs, cur_node);
1401 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1402 gst_mpdparser_parse_seg_base_type_ext (&new_adap_set->SegmentBase,
1404 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1405 gst_mpdparser_parse_segment_list_node (&new_adap_set->SegmentList,
1407 } else if (xmlStrcmp (cur_node->name,
1408 (xmlChar *) "ContentComponent") == 0) {
1409 gst_mpdparser_parse_content_component_node (&new_adap_set->
1410 ContentComponents, cur_node);
1411 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1412 gst_mpdparser_parse_segment_template_node (&new_adap_set->
1413 SegmentTemplate, cur_node);
1420 gst_mpdparser_parse_subset_node (GList ** list, xmlNode * a_node)
1422 GstSubsetNode *new_subset;
1424 new_subset = g_slice_new0 (GstSubsetNode);
1425 if (new_subset == NULL) {
1426 GST_WARNING ("Allocation of Subset node failed!");
1429 *list = g_list_append (*list, new_subset);
1431 GST_LOG ("attributes of Subset node:");
1432 new_subset->contains =
1433 gst_mpdparser_get_xml_prop_uint_vector_type (a_node, "contains",
1438 gst_mpdparser_parse_segment_template_node (GstSegmentTemplateNode ** pointer,
1441 GstSegmentTemplateNode *new_segment_template;
1443 gst_mpdparser_free_segment_template_node (*pointer);
1444 *pointer = new_segment_template = g_slice_new0 (GstSegmentTemplateNode);
1445 if (new_segment_template == NULL) {
1446 GST_WARNING ("Allocation of SegmentTemplate node failed!");
1450 GST_LOG ("extension of SegmentTemplate node:");
1451 gst_mpdparser_parse_mult_seg_base_type_ext (&new_segment_template->
1452 MultSegBaseType, a_node);
1454 GST_LOG ("attributes of SegmentTemplate node:");
1455 new_segment_template->media =
1456 gst_mpdparser_get_xml_prop_string (a_node, "media");
1457 new_segment_template->index =
1458 gst_mpdparser_get_xml_prop_string (a_node, "index");
1459 new_segment_template->initialization =
1460 gst_mpdparser_get_xml_prop_string (a_node, "initialization");
1461 new_segment_template->bitstreamSwitching =
1462 gst_mpdparser_get_xml_prop_string (a_node, "bitstreamSwitching");
1466 gst_mpdparser_parse_period_node (GList ** list, xmlNode * a_node)
1469 GstPeriodNode *new_period;
1471 new_period = g_slice_new0 (GstPeriodNode);
1472 if (new_period == NULL) {
1473 GST_WARNING ("Allocation of Period node failed!");
1476 *list = g_list_append (*list, new_period);
1478 GST_LOG ("attributes of Period node:");
1479 new_period->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1480 new_period->start = gst_mpdparser_get_xml_prop_duration (a_node, "start");
1481 new_period->duration =
1482 gst_mpdparser_get_xml_prop_duration (a_node, "duration");
1483 new_period->bitstreamSwitching =
1484 gst_mpdparser_get_xml_prop_boolean (a_node, "bitstreamSwitching");
1486 /* explore children nodes */
1487 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1488 if (cur_node->type == XML_ELEMENT_NODE) {
1489 if (xmlStrcmp (cur_node->name, (xmlChar *) "AdaptationSet") == 0) {
1490 gst_mpdparser_parse_adaptation_set_node (&new_period->AdaptationSets,
1492 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1493 gst_mpdparser_parse_seg_base_type_ext (&new_period->SegmentBase,
1495 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1496 gst_mpdparser_parse_segment_list_node (&new_period->SegmentList,
1498 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1499 gst_mpdparser_parse_segment_template_node (&new_period->SegmentTemplate,
1501 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Subset") == 0) {
1502 gst_mpdparser_parse_subset_node (&new_period->Subsets, cur_node);
1503 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1504 gst_mpdparser_parse_baseURL_node (&new_period->BaseURLs, cur_node);
1511 gst_mpdparser_parse_program_info_node (GList ** list, xmlNode * a_node)
1514 GstProgramInformationNode *new_prog_info;
1516 new_prog_info = g_slice_new0 (GstProgramInformationNode);
1517 if (new_prog_info == NULL) {
1518 GST_WARNING ("Allocation of ProgramInfo node failed!");
1521 *list = g_list_append (*list, new_prog_info);
1523 GST_LOG ("attributes of ProgramInformation node:");
1524 new_prog_info->lang = gst_mpdparser_get_xml_prop_string (a_node, "lang");
1525 new_prog_info->moreInformationURL =
1526 gst_mpdparser_get_xml_prop_string (a_node, "moreInformationURL");
1528 /* explore children nodes */
1529 GST_LOG ("children of ProgramInformation node:");
1530 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1531 if (cur_node->type == XML_ELEMENT_NODE) {
1532 if (xmlStrcmp (cur_node->name, (xmlChar *) "Title") == 0) {
1533 new_prog_info->Title = gst_mpdparser_get_xml_node_content (cur_node);
1534 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Source") == 0) {
1535 new_prog_info->Source = gst_mpdparser_get_xml_node_content (cur_node);
1536 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Copyright") == 0) {
1537 new_prog_info->Copyright =
1538 gst_mpdparser_get_xml_node_content (cur_node);
1545 gst_mpdparser_parse_metrics_range_node (GList ** list, xmlNode * a_node)
1547 GstMetricsRangeNode *new_metrics_range;
1549 new_metrics_range = g_slice_new0 (GstMetricsRangeNode);
1550 if (new_metrics_range == NULL) {
1551 GST_WARNING ("Allocation of Metrics Range node failed!");
1554 *list = g_list_append (*list, new_metrics_range);
1556 GST_LOG ("attributes of Metrics Range node:");
1557 new_metrics_range->starttime =
1558 gst_mpdparser_get_xml_prop_duration (a_node, "starttime");
1559 new_metrics_range->duration =
1560 gst_mpdparser_get_xml_prop_duration (a_node, "duration");
1564 gst_mpdparser_parse_metrics_node (GList ** list, xmlNode * a_node)
1567 GstMetricsNode *new_metrics;
1569 new_metrics = g_slice_new0 (GstMetricsNode);
1570 if (new_metrics == NULL) {
1571 GST_WARNING ("Allocation of Metrics node failed!");
1574 *list = g_list_append (*list, new_metrics);
1576 GST_LOG ("attributes of Metrics node:");
1577 new_metrics->metrics = gst_mpdparser_get_xml_prop_string (a_node, "metrics");
1579 /* explore children nodes */
1580 GST_LOG ("children of Metrics node:");
1581 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1582 if (cur_node->type == XML_ELEMENT_NODE) {
1583 if (xmlStrcmp (cur_node->name, (xmlChar *) "Range") == 0) {
1584 gst_mpdparser_parse_metrics_range_node (&new_metrics->MetricsRanges,
1586 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Reporting") == 0) {
1587 /* No reporting scheme is specified in this part of ISO/IEC 23009.
1588 * It is expected that external specifications may define formats
1589 * and delivery for the reporting data. */
1590 GST_LOG (" - Reporting node found (unknown structure)");
1597 gst_mpdparser_parse_root_node (GstMPDNode ** pointer, xmlNode * a_node)
1600 GstMPDNode *new_mpd;
1602 gst_mpdparser_free_mpd_node (*pointer);
1603 *pointer = new_mpd = g_slice_new0 (GstMPDNode);
1604 if (new_mpd == NULL) {
1605 GST_WARNING ("Allocation of MPD node failed!");
1609 GST_LOG ("namespaces of root MPD node:");
1610 new_mpd->default_namespace =
1611 gst_mpdparser_get_xml_node_namespace (a_node, NULL);
1612 new_mpd->namespace_xsi = gst_mpdparser_get_xml_node_namespace (a_node, "xsi");
1613 new_mpd->namespace_ext = gst_mpdparser_get_xml_node_namespace (a_node, "ext");
1615 GST_LOG ("attributes of root MPD node:");
1616 new_mpd->schemaLocation =
1617 gst_mpdparser_get_xml_prop_string (a_node, "schemaLocation");
1618 new_mpd->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1619 new_mpd->profiles = gst_mpdparser_get_xml_prop_string (a_node, "profiles");
1620 new_mpd->type = gst_mpdparser_get_xml_prop_type (a_node, "type");
1621 new_mpd->availabilityStartTime =
1622 gst_mpdparser_get_xml_prop_dateTime (a_node, "availabilityStartTime");
1623 new_mpd->availabilityEndTime =
1624 gst_mpdparser_get_xml_prop_dateTime (a_node, "availabilityEndTime");
1625 new_mpd->mediaPresentationDuration =
1626 gst_mpdparser_get_xml_prop_duration (a_node, "mediaPresentationDuration");
1627 new_mpd->minimumUpdatePeriod =
1628 gst_mpdparser_get_xml_prop_duration (a_node, "minimumUpdatePeriod");
1629 new_mpd->minBufferTime =
1630 gst_mpdparser_get_xml_prop_duration (a_node, "minBufferTime");
1631 new_mpd->timeShiftBufferDepth =
1632 gst_mpdparser_get_xml_prop_duration (a_node, "timeShiftBufferDepth");
1633 new_mpd->suggestedPresentationDelay =
1634 gst_mpdparser_get_xml_prop_duration (a_node,
1635 "suggestedPresentationDelay");
1636 new_mpd->maxSegmentDuration =
1637 gst_mpdparser_get_xml_prop_duration (a_node, "maxSegmentDuration");
1638 new_mpd->maxSubsegmentDuration =
1639 gst_mpdparser_get_xml_prop_duration (a_node, "maxSubsegmentDuration");
1641 /* explore children Period nodes */
1642 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1643 if (cur_node->type == XML_ELEMENT_NODE) {
1644 if (xmlStrcmp (cur_node->name, (xmlChar *) "Period") == 0) {
1645 gst_mpdparser_parse_period_node (&new_mpd->Periods, cur_node);
1646 } else if (xmlStrcmp (cur_node->name,
1647 (xmlChar *) "ProgramInformation") == 0) {
1648 gst_mpdparser_parse_program_info_node (&new_mpd->ProgramInfo, cur_node);
1649 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1650 gst_mpdparser_parse_baseURL_node (&new_mpd->BaseURLs, cur_node);
1651 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Location") == 0) {
1652 gst_mpdparser_parse_location_node (&new_mpd->Locations, cur_node);
1653 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Metrics") == 0) {
1654 gst_mpdparser_parse_metrics_node (&new_mpd->Metrics, cur_node);
1660 /* comparison functions */
1662 strncmp_ext (const char *s1, const char *s2)
1664 if (s1 == NULL && s2 == NULL)
1666 if (s1 == NULL && s2 != NULL)
1668 if (s2 == NULL && s1 != NULL)
1670 return strncmp (s1, s2, strlen (s2));
1673 /* navigation functions */
1674 static GstAdaptationSetNode *
1675 gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets,
1676 const gchar * mimeType)
1679 GstAdaptationSetNode *adapt_set;
1681 if (AdaptationSets == NULL)
1684 for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1685 adapt_set = (GstAdaptationSetNode *) list->data;
1687 gchar *this_mimeType = NULL;
1688 GstRepresentationNode *rep;
1690 gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1691 if (rep->RepresentationBase)
1692 this_mimeType = rep->RepresentationBase->mimeType;
1693 if (!this_mimeType && adapt_set->RepresentationBase) {
1694 this_mimeType = adapt_set->RepresentationBase->mimeType;
1696 if (strncmp_ext (this_mimeType, mimeType) == 0)
1704 /* if idx < 0, returns the highest adaptation set with the given mimeType
1705 * if idx >= 0, returns the highest adaptation set with the given mimeType and an index <= idx
1707 static GstAdaptationSetNode *
1708 gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
1709 const gchar * mimeType, gint idx)
1712 GstAdaptationSetNode *adapt_set, *selected = NULL;
1715 if (AdaptationSets == NULL)
1718 for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1719 adapt_set = (GstAdaptationSetNode *) list->data;
1721 gchar *this_mimeType = NULL;
1722 GstRepresentationNode *rep;
1724 gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1725 if (rep->RepresentationBase)
1726 this_mimeType = rep->RepresentationBase->mimeType;
1727 if (!this_mimeType && adapt_set->RepresentationBase) {
1728 this_mimeType = adapt_set->RepresentationBase->mimeType;
1730 if (strncmp_ext (this_mimeType, mimeType) == 0) {
1731 if (idx < 0 || i <= idx)
1732 selected = adapt_set;
1741 static GstAdaptationSetNode *
1742 gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *
1743 AdaptationSets, const gchar * mimeType, const gchar * lang)
1746 GstAdaptationSetNode *adapt_set;
1748 if (AdaptationSets == NULL)
1751 for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1752 adapt_set = (GstAdaptationSetNode *) list->data;
1754 GstRepresentationNode *rep;
1755 gchar *this_lang = adapt_set->lang;
1756 gchar *this_mimeType = NULL;
1758 gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1759 if (rep->RepresentationBase)
1760 this_mimeType = rep->RepresentationBase->mimeType;
1761 if (!this_mimeType && adapt_set->RepresentationBase) {
1762 this_mimeType = adapt_set->RepresentationBase->mimeType;
1764 if (strncmp_ext (this_mimeType, mimeType) == 0
1765 && strncmp_ext (this_lang, lang) == 0)
1773 static GstRepresentationNode *
1774 gst_mpdparser_get_lowest_representation (GList * Representations)
1778 if (Representations == NULL)
1781 list = g_list_first (Representations);
1783 return list ? (GstRepresentationNode *) list->data : NULL;
1787 static GstRepresentationNode *
1788 gst_mpdparser_get_highest_representation (GList * Representations)
1792 if (Representations == NULL)
1795 list = g_list_last (Representations);
1797 return list ? (GstRepresentationNode *) list->data : NULL;
1800 static GstRepresentationNode *
1801 gst_mpdparser_get_representation_with_max_bandwidth (GList * Representations,
1805 GstRepresentationNode *representation, *best_rep = NULL;
1807 if (Representations == NULL)
1810 if (max_bandwidth <= 0) /* 0 => get highest representation available */
1811 return gst_mpdparser_get_highest_representation (Representations);
1813 for (list = g_list_first (Representations); list; list = g_list_next (list)) {
1814 representation = (GstRepresentationNode *) list->data;
1815 if (representation && representation->bandwidth <= max_bandwidth) {
1816 best_rep = representation;
1824 static GstSegmentBaseType *
1825 gst_mpdparser_get_segment_base (GstPeriodNode * Period,
1826 GstAdaptationSetNode * AdaptationSet,
1827 GstRepresentationNode * Representation)
1829 GstSegmentBaseType *SegmentBase = NULL;
1831 if (Representation && Representation->SegmentBase
1832 && Representation->SegmentBase->Initialization) {
1833 SegmentBase = Representation->SegmentBase;
1834 } else if (AdaptationSet && AdaptationSet->SegmentBase
1835 && AdaptationSet->SegmentBase->Initialization) {
1836 SegmentBase = AdaptationSet->SegmentBase;
1837 } else if (Period && Period->SegmentBase
1838 && Period->SegmentBase->Initialization) {
1839 SegmentBase = Period->SegmentBase;
1841 /* the SegmentBase element could be encoded also inside a SegmentList element */
1842 if (SegmentBase == NULL) {
1843 if (Representation && Representation->SegmentList
1844 && Representation->SegmentList->MultSegBaseType
1845 && Representation->SegmentList->MultSegBaseType->SegBaseType
1846 && Representation->SegmentList->MultSegBaseType->SegBaseType->
1848 SegmentBase = Representation->SegmentList->MultSegBaseType->SegBaseType;
1849 } else if (AdaptationSet && AdaptationSet->SegmentList
1850 && AdaptationSet->SegmentList->MultSegBaseType
1851 && AdaptationSet->SegmentList->MultSegBaseType->SegBaseType
1852 && AdaptationSet->SegmentList->MultSegBaseType->SegBaseType->
1854 SegmentBase = AdaptationSet->SegmentList->MultSegBaseType->SegBaseType;
1855 } else if (Period && Period->SegmentList
1856 && Period->SegmentList->MultSegBaseType
1857 && Period->SegmentList->MultSegBaseType->SegBaseType
1858 && Period->SegmentList->MultSegBaseType->SegBaseType->Initialization) {
1859 SegmentBase = Period->SegmentList->MultSegBaseType->SegBaseType;
1867 gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
1870 GList *list = NULL, *best = NULL;
1871 GstRepresentationNode *representation;
1873 if (Representations == NULL)
1876 if (max_bandwidth <= 0) /* 0 => get lowest representation available */
1879 for (list = g_list_first (Representations); list; list = g_list_next (list)) {
1880 representation = (GstRepresentationNode *) list->data;
1881 if (representation && representation->bandwidth <= max_bandwidth) {
1886 return best ? g_list_position (Representations, best) : -1;
1889 static GstSegmentListNode *
1890 gst_mpdparser_get_segment_list (GstPeriodNode * Period,
1891 GstAdaptationSetNode * AdaptationSet,
1892 GstRepresentationNode * Representation)
1894 GstSegmentListNode *SegmentList = NULL;
1896 if (Representation && Representation->SegmentList) {
1897 SegmentList = Representation->SegmentList;
1898 } else if (AdaptationSet && AdaptationSet->SegmentList) {
1899 SegmentList = AdaptationSet->SegmentList;
1901 SegmentList = Period->SegmentList;
1907 /* memory management functions */
1909 gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node)
1912 g_free (mpd_node->default_namespace);
1913 g_free (mpd_node->namespace_xsi);
1914 g_free (mpd_node->namespace_ext);
1915 g_free (mpd_node->schemaLocation);
1916 g_free (mpd_node->id);
1917 g_free (mpd_node->profiles);
1918 if (mpd_node->availabilityStartTime)
1919 gst_date_time_unref (mpd_node->availabilityStartTime);
1920 if (mpd_node->availabilityEndTime)
1921 gst_date_time_unref (mpd_node->availabilityEndTime);
1922 g_list_foreach (mpd_node->ProgramInfo,
1923 (GFunc) gst_mpdparser_free_prog_info_node, NULL);
1924 g_list_free (mpd_node->ProgramInfo);
1925 g_list_foreach (mpd_node->BaseURLs,
1926 (GFunc) gst_mpdparser_free_base_url_node, NULL);
1927 g_list_free (mpd_node->BaseURLs);
1928 g_list_foreach (mpd_node->Locations, (GFunc) g_free, NULL);
1929 g_list_free (mpd_node->Locations);
1930 g_list_foreach (mpd_node->Periods, (GFunc) gst_mpdparser_free_period_node,
1932 g_list_free (mpd_node->Periods);
1933 g_list_foreach (mpd_node->Metrics, (GFunc) gst_mpdparser_free_metrics_node,
1935 g_list_free (mpd_node->Metrics);
1936 g_slice_free (GstMPDNode, mpd_node);
1941 gst_mpdparser_free_prog_info_node (GstProgramInformationNode * prog_info_node)
1943 if (prog_info_node) {
1944 g_free (prog_info_node->lang);
1945 g_free (prog_info_node->moreInformationURL);
1946 g_free (prog_info_node->Title);
1947 g_free (prog_info_node->Source);
1948 g_free (prog_info_node->Copyright);
1949 g_slice_free (GstProgramInformationNode, prog_info_node);
1954 gst_mpdparser_free_metrics_node (GstMetricsNode * metrics_node)
1957 g_free (metrics_node->metrics);
1958 g_list_foreach (metrics_node->MetricsRanges,
1959 (GFunc) gst_mpdparser_free_metrics_range_node, NULL);
1960 g_list_free (metrics_node->MetricsRanges);
1965 gst_mpdparser_free_metrics_range_node (GstMetricsRangeNode * metrics_range_node)
1967 if (metrics_range_node) {
1968 g_slice_free (GstMetricsRangeNode, metrics_range_node);
1973 gst_mpdparser_free_period_node (GstPeriodNode * period_node)
1976 g_free (period_node->id);
1977 gst_mpdparser_free_seg_base_type_ext (period_node->SegmentBase);
1978 gst_mpdparser_free_segment_list_node (period_node->SegmentList);
1979 gst_mpdparser_free_segment_template_node (period_node->SegmentTemplate);
1980 g_list_foreach (period_node->AdaptationSets,
1981 (GFunc) gst_mpdparser_free_adaptation_set_node, NULL);
1982 g_list_free (period_node->AdaptationSets);
1983 g_list_foreach (period_node->Subsets,
1984 (GFunc) gst_mpdparser_free_subset_node, NULL);
1985 g_list_free (period_node->Subsets);
1986 g_list_foreach (period_node->BaseURLs,
1987 (GFunc) gst_mpdparser_free_base_url_node, NULL);
1988 g_list_free (period_node->BaseURLs);
1989 g_slice_free (GstPeriodNode, period_node);
1994 gst_mpdparser_free_subset_node (GstSubsetNode * subset_node)
1997 g_free (subset_node->contains);
1998 g_slice_free (GstSubsetNode, subset_node);
2003 gst_mpdparser_free_segment_template_node (GstSegmentTemplateNode *
2004 segment_template_node)
2006 if (segment_template_node) {
2007 g_free (segment_template_node->media);
2008 g_free (segment_template_node->index);
2009 g_free (segment_template_node->initialization);
2010 g_free (segment_template_node->bitstreamSwitching);
2011 /* MultipleSegmentBaseType extension */
2012 gst_mpdparser_free_mult_seg_base_type_ext
2013 (segment_template_node->MultSegBaseType);
2014 g_slice_free (GstSegmentTemplateNode, segment_template_node);
2019 gst_mpdparser_free_representation_base_type (GstRepresentationBaseType *
2020 representation_base)
2022 if (representation_base) {
2023 g_free (representation_base->profiles);
2024 g_slice_free (GstRatio, representation_base->sar);
2025 g_slice_free (GstFrameRate, representation_base->frameRate);
2026 g_free (representation_base->audioSamplingRate);
2027 g_free (representation_base->mimeType);
2028 g_free (representation_base->segmentProfiles);
2029 g_free (representation_base->codecs);
2030 g_free (representation_base->scanType);
2031 g_list_foreach (representation_base->FramePacking,
2032 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2033 g_list_free (representation_base->FramePacking);
2034 g_list_foreach (representation_base->AudioChannelConfiguration,
2035 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2036 g_list_free (representation_base->AudioChannelConfiguration);
2037 g_list_foreach (representation_base->ContentProtection,
2038 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2039 g_list_free (representation_base->ContentProtection);
2040 g_slice_free (GstRepresentationBaseType, representation_base);
2045 gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode *
2046 adaptation_set_node)
2048 if (adaptation_set_node) {
2049 g_free (adaptation_set_node->lang);
2050 g_free (adaptation_set_node->contentType);
2051 g_slice_free (GstRatio, adaptation_set_node->par);
2052 g_slice_free (GstFrameRate, adaptation_set_node->minFrameRate);
2053 g_slice_free (GstFrameRate, adaptation_set_node->maxFrameRate);
2054 g_slice_free (GstConditionalUintType,
2055 adaptation_set_node->segmentAlignment);
2056 g_slice_free (GstConditionalUintType,
2057 adaptation_set_node->subsegmentAlignment);
2058 g_list_foreach (adaptation_set_node->Accessibility,
2059 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2060 g_list_free (adaptation_set_node->Accessibility);
2061 g_list_foreach (adaptation_set_node->Role,
2062 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2063 g_list_free (adaptation_set_node->Role);
2064 g_list_foreach (adaptation_set_node->Rating,
2065 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2066 g_list_free (adaptation_set_node->Rating);
2067 g_list_foreach (adaptation_set_node->Viewpoint,
2068 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2069 g_list_free (adaptation_set_node->Viewpoint);
2070 gst_mpdparser_free_representation_base_type
2071 (adaptation_set_node->RepresentationBase);
2072 gst_mpdparser_free_seg_base_type_ext (adaptation_set_node->SegmentBase);
2073 gst_mpdparser_free_segment_list_node (adaptation_set_node->SegmentList);
2074 gst_mpdparser_free_segment_template_node (adaptation_set_node->
2076 g_list_foreach (adaptation_set_node->BaseURLs,
2077 (GFunc) gst_mpdparser_free_base_url_node, NULL);
2078 g_list_free (adaptation_set_node->BaseURLs);
2079 g_list_foreach (adaptation_set_node->Representations,
2080 (GFunc) gst_mpdparser_free_representation_node, NULL);
2081 g_list_free (adaptation_set_node->Representations);
2082 g_list_foreach (adaptation_set_node->ContentComponents,
2083 (GFunc) gst_mpdparser_free_content_component_node, NULL);
2084 g_list_free (adaptation_set_node->ContentComponents);
2085 g_slice_free (GstAdaptationSetNode, adaptation_set_node);
2090 gst_mpdparser_free_representation_node (GstRepresentationNode *
2091 representation_node)
2093 if (representation_node) {
2094 g_free (representation_node->id);
2095 g_strfreev (representation_node->dependencyId);
2096 g_strfreev (representation_node->mediaStreamStructureId);
2097 gst_mpdparser_free_representation_base_type
2098 (representation_node->RepresentationBase);
2099 g_list_foreach (representation_node->SubRepresentations,
2100 (GFunc) gst_mpdparser_free_subrepresentation_node, NULL);
2101 g_list_free (representation_node->SubRepresentations);
2102 gst_mpdparser_free_seg_base_type_ext (representation_node->SegmentBase);
2103 gst_mpdparser_free_segment_template_node (representation_node->
2105 gst_mpdparser_free_segment_list_node (representation_node->SegmentList);
2106 g_list_foreach (representation_node->BaseURLs,
2107 (GFunc) gst_mpdparser_free_base_url_node, NULL);
2108 g_list_free (representation_node->BaseURLs);
2109 g_slice_free (GstRepresentationNode, representation_node);
2114 gst_mpdparser_free_subrepresentation_node (GstSubRepresentationNode *
2118 gst_mpdparser_free_representation_base_type (subrep_node->
2119 RepresentationBase);
2120 g_free (subrep_node->dependencyLevel);
2121 g_strfreev (subrep_node->contentComponent);
2126 gst_mpdparser_free_s_node (GstSNode * s_node)
2129 g_slice_free (GstSNode, s_node);
2134 gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode * seg_timeline)
2137 g_list_foreach (seg_timeline->S, (GFunc) gst_mpdparser_free_s_node, NULL);
2138 g_list_free (seg_timeline->S);
2139 g_slice_free (GstSegmentTimelineNode, seg_timeline);
2144 gst_mpdparser_free_url_type_node (GstURLType * url_type_node)
2146 if (url_type_node) {
2147 g_free (url_type_node->sourceURL);
2148 g_slice_free (GstRange, url_type_node->range);
2149 g_slice_free (GstURLType, url_type_node);
2154 gst_mpdparser_free_seg_base_type_ext (GstSegmentBaseType * seg_base_type)
2156 if (seg_base_type) {
2157 g_free (seg_base_type->indexRange);
2158 gst_mpdparser_free_url_type_node (seg_base_type->Initialization);
2159 gst_mpdparser_free_url_type_node (seg_base_type->RepresentationIndex);
2160 g_slice_free (GstSegmentBaseType, seg_base_type);
2165 gst_mpdparser_free_mult_seg_base_type_ext (GstMultSegmentBaseType *
2168 if (mult_seg_base_type) {
2169 /* SegmentBaseType extension */
2170 gst_mpdparser_free_seg_base_type_ext (mult_seg_base_type->SegBaseType);
2171 gst_mpdparser_free_segment_timeline_node
2172 (mult_seg_base_type->SegmentTimeline);
2173 gst_mpdparser_free_url_type_node (mult_seg_base_type->BitstreamSwitching);
2174 g_slice_free (GstMultSegmentBaseType, mult_seg_base_type);
2179 gst_mpdparser_free_segment_list_node (GstSegmentListNode * segment_list_node)
2181 if (segment_list_node) {
2182 g_list_foreach (segment_list_node->SegmentURL,
2183 (GFunc) gst_mpdparser_free_segment_url_node, NULL);
2184 g_list_free (segment_list_node->SegmentURL);
2185 /* MultipleSegmentBaseType extension */
2186 gst_mpdparser_free_mult_seg_base_type_ext
2187 (segment_list_node->MultSegBaseType);
2188 g_slice_free (GstSegmentListNode, segment_list_node);
2193 gst_mpdparser_free_segment_url_node (GstSegmentURLNode * segment_url)
2196 g_free (segment_url->media);
2197 g_slice_free (GstRange, segment_url->mediaRange);
2198 g_free (segment_url->index);
2199 g_slice_free (GstRange, segment_url->indexRange);
2200 g_slice_free (GstSegmentURLNode, segment_url);
2205 gst_mpdparser_free_base_url_node (GstBaseURL * base_url_node)
2207 if (base_url_node) {
2208 g_free (base_url_node->baseURL);
2209 g_free (base_url_node->serviceLocation);
2210 g_free (base_url_node->byteRange);
2211 g_slice_free (GstBaseURL, base_url_node);
2216 gst_mpdparser_free_descriptor_type_node (GstDescriptorType * descriptor_type)
2218 if (descriptor_type) {
2219 g_free (descriptor_type->schemeIdUri);
2220 g_free (descriptor_type->value);
2225 gst_mpdparser_free_content_component_node (GstContentComponentNode *
2226 content_component_node)
2228 if (content_component_node) {
2229 g_free (content_component_node->lang);
2230 g_free (content_component_node->contentType);
2231 g_slice_free (GstRatio, content_component_node->par);
2232 g_list_foreach (content_component_node->Accessibility,
2233 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2234 g_list_free (content_component_node->Accessibility);
2235 g_list_foreach (content_component_node->Role,
2236 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2237 g_list_free (content_component_node->Role);
2238 g_list_foreach (content_component_node->Rating,
2239 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2240 g_list_free (content_component_node->Rating);
2241 g_list_foreach (content_component_node->Viewpoint,
2242 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2243 g_list_free (content_component_node->Viewpoint);
2244 g_slice_free (GstContentComponentNode, content_component_node);
2249 gst_mpdparser_free_stream_period (GstStreamPeriod * stream_period)
2251 if (stream_period) {
2252 g_slice_free (GstStreamPeriod, stream_period);
2257 gst_mpdparser_free_media_segment (GstMediaSegment * media_segment)
2259 if (media_segment) {
2260 g_slice_free (GstMediaSegment, media_segment);
2265 gst_mpdparser_free_active_stream (GstActiveStream * active_stream)
2267 if (active_stream) {
2268 g_list_foreach (active_stream->segments,
2269 (GFunc) gst_mpdparser_free_media_segment, NULL);
2270 g_list_free (active_stream->segments);
2271 g_slice_free (GstActiveStream, active_stream);
2276 gst_mpdparser_get_segmentURL_for_range (gchar * url, GstRange * range)
2281 gchar *range_suffix;
2283 g_strdup_printf ("?range=%llu-%llu", range->first_byte_pos,
2284 range->last_byte_pos);
2285 segmentURL = g_strconcat (url, range_suffix, NULL);
2286 g_free (range_suffix);
2288 segmentURL = g_strdup (url);
2295 gst_mpdparser_get_mediaURL (GstMpdClient * client,
2296 GstSegmentURLNode * segmentURL)
2298 const gchar *url_prefix;
2300 g_return_val_if_fail (client != NULL, NULL);
2301 g_return_val_if_fail (segmentURL != NULL, NULL);
2304 segmentURL->media ? segmentURL->
2305 media : gst_mpdparser_get_baseURL (client);
2306 g_return_val_if_fail (url_prefix != NULL, NULL);
2308 return gst_mpdparser_get_segmentURL_for_range (url_prefix,
2309 segmentURL->mediaRange);//if not present @media attribute, it is mapped to baseURL
2313 gst_mpdparser_get_initializationURL (GstURLType * InitializationURL)
2315 g_return_val_if_fail (InitializationURL != NULL, NULL);
2316 g_return_val_if_fail (InitializationURL->sourceURL != NULL, NULL);
2318 return gst_mpdparser_get_segmentURL_for_range (InitializationURL->sourceURL,
2319 InitializationURL->range);
2323 gst_mpdparser_build_URL_from_template (const gchar * url_template,
2324 const gchar * id, guint number, guint bandwidth, guint time)
2326 static gchar default_format[] = "%01d";
2327 gchar **tokens, *token, *ret, *format;
2329 gboolean last_token_par = TRUE; /* last token was a parameter */
2331 g_return_val_if_fail (url_template != NULL, NULL);
2332 tokens = g_strsplit_set (url_template, "$", -1);
2334 GST_WARNING ("Scan of URL template failed!");
2337 num_tokens = g_strv_length (tokens);
2339 for (i = 0; i < num_tokens; i++) {
2341 format = default_format;
2343 if (!g_strcmp0 (token, "RepresentationID")) {
2344 tokens[i] = g_strdup_printf ("%s", id);
2346 last_token_par = TRUE;
2347 } else if (!strncmp (token, "Number", 6)) {
2348 if (strlen (token) > 6) {
2349 format = token + 6; /* format tag */
2351 tokens[i] = g_strdup_printf (format, number);
2353 last_token_par = TRUE;
2354 } else if (!strncmp (token, "Bandwidth", 9)) {
2355 if (strlen (token) > 9) {
2356 format = token + 9; /* format tag */
2358 tokens[i] = g_strdup_printf (format, bandwidth);
2360 last_token_par = TRUE;
2361 } else if (!strncmp (token, "Time", 4)) {
2362 if (strlen (token) > 4) {
2363 format = token + 4; /* format tag */
2365 tokens[i] = g_strdup_printf (format, time);
2367 last_token_par = TRUE;
2368 } else if (!g_strcmp0 (token, "")) {
2369 if (!last_token_par) {
2370 tokens[i] = g_strdup_printf ("%s", "$");
2372 last_token_par = TRUE;
2375 last_token_par = FALSE;
2379 ret = g_strjoinv (NULL, tokens);
2380 g_strfreev (tokens);
2385 static GstStreamPeriod *
2386 gst_mpdparser_get_stream_period (GstMpdClient * client)
2388 g_return_val_if_fail (client != NULL, NULL);
2389 g_return_val_if_fail (client->periods != NULL, NULL);
2391 return g_list_nth_data (client->periods, client->period_idx);
2394 /* select a stream and extract the baseURL (if present) */
2396 gst_mpdparser_parse_baseURL (GstMpdClient * client)
2398 GstActiveStream *stream;
2399 GstStreamPeriod *stream_period;
2400 GstBaseURL *baseURL;
2402 static gchar *baseURL_array[5];
2403 static gchar empty[] = "";
2407 gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
2408 g_return_val_if_fail (stream != NULL, empty);
2409 stream_period = gst_mpdparser_get_stream_period (client);
2410 g_return_val_if_fail (stream_period != NULL, empty);
2411 g_return_val_if_fail (stream_period->period != NULL, empty);
2413 baseURL_array[0] = baseURL_array[1] = baseURL_array[2] = baseURL_array[3] =
2415 baseURL_array[4] = NULL;
2417 /* FIXME: this simple implementation is not fully compliant with RFC 3986 */
2418 if ((list = client->mpd_node->BaseURLs) != NULL) {
2419 baseURL = g_list_nth_data (list, stream->baseURL_idx);
2421 baseURL = list->data;
2423 baseURL_array[0] = baseURL->baseURL;
2425 if ((list = stream_period->period->BaseURLs) != NULL) {
2426 baseURL = g_list_nth_data (list, stream->baseURL_idx);
2428 baseURL = list->data;
2430 baseURL_array[1] = baseURL->baseURL;
2432 if ((list = stream->cur_adapt_set->BaseURLs) != NULL) {
2433 baseURL = g_list_nth_data (list, stream->baseURL_idx);
2435 baseURL = list->data;
2437 baseURL_array[2] = baseURL->baseURL;
2439 if ((list = stream->cur_representation->BaseURLs) != NULL) {
2440 baseURL = g_list_nth_data (list, stream->baseURL_idx);
2442 baseURL = list->data;
2444 baseURL_array[3] = baseURL->baseURL;
2447 ret = g_strjoinv (NULL, baseURL_array);
2448 /* get base URI from MPD file URI, if the "http" scheme is missing */
2449 if (client->mpd_uri != NULL && strncmp (ret, "http://", 7) != 0) {
2450 gchar *last_sep, *tmp1, *tmp2;
2451 last_sep = strrchr (client->mpd_uri, '/');
2453 tmp1 = g_strndup (client->mpd_uri, last_sep - client->mpd_uri + 1);
2455 GST_DEBUG ("Got base URI from MPD file URI %s", tmp1);
2456 ret = g_strconcat (tmp1, tmp2, NULL);
2462 GST_DEBUG ("selected baseURL with index %d: %s", stream->baseURL_idx, ret);
2468 gst_mpd_client_get_segment_duration (GstMpdClient * client)
2470 GstActiveStream *stream;
2471 GstStreamPeriod *stream_period;
2472 GstMultSegmentBaseType *base = NULL;
2473 GstClockTime duration;
2477 gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
2478 g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
2479 stream_period = gst_mpdparser_get_stream_period (client);
2480 g_return_val_if_fail (stream_period != NULL, GST_CLOCK_TIME_NONE);
2482 if (stream->cur_segment_list) {
2483 base = stream->cur_segment_list->MultSegBaseType;
2484 } else if (stream->cur_seg_template) {
2485 base = stream->cur_seg_template->MultSegBaseType;
2488 if (base == NULL || base->SegBaseType == NULL) {
2489 /* this may happen when we have a single segment */
2490 duration = stream_period->duration;
2492 duration = base->duration * GST_SECOND;
2493 timescale = base->SegBaseType->timescale;
2496 duration /= timescale;
2502 /*****************************/
2503 /******* API functions *******/
2504 /*****************************/
2507 gst_mpd_client_new ()
2509 GstMpdClient *client;
2511 client = g_new0 (GstMpdClient, 1);
2512 client->lock = g_mutex_new ();
2518 gst_active_streams_free (GstMpdClient * client)
2520 if (client->active_streams) {
2521 g_list_foreach (client->active_streams,
2522 (GFunc) gst_mpdparser_free_active_stream, NULL);
2523 g_list_free (client->active_streams);
2524 client->active_streams = NULL;
2529 gst_mpd_client_free (GstMpdClient * client)
2531 g_return_if_fail (client != NULL);
2533 if (client->mpd_node)
2534 gst_mpdparser_free_mpd_node (client->mpd_node);
2536 if (client->periods) {
2537 g_list_foreach (client->periods,
2538 (GFunc) gst_mpdparser_free_stream_period, NULL);
2539 g_list_free (client->periods);
2542 gst_active_streams_free (client);
2545 g_mutex_free (client->lock);
2547 g_free (client->mpd_uri);
2553 gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
2557 xmlNode *root_element = NULL;
2559 GST_DEBUG ("MPD file fully buffered, start parsing...");
2561 GST_MPD_CLIENT_LOCK (client);
2562 /* parse the complete MPD file into a tree (using the libxml2 default parser API) */
2564 /* this initialize the library and check potential ABI mismatches
2565 * between the version it was compiled for and the actual shared
2569 /* parse "data" into a document (which is a libxml2 tree structure xmlDoc) */
2570 doc = xmlReadMemory (data, size, "noname.xml", NULL, 0);
2572 GST_ERROR ("failed to parse the MPD file");
2573 GST_MPD_CLIENT_UNLOCK (client);
2576 /* get the root element node */
2577 root_element = xmlDocGetRootElement (doc);
2579 if (root_element->type != XML_ELEMENT_NODE
2580 || xmlStrcmp (root_element->name, (xmlChar *) "MPD") != 0) {
2582 ("can not find the root element MPD, failed to parse the MPD file");
2584 /* now we can parse the MPD root node and all children nodes, recursively */
2585 gst_mpdparser_parse_root_node (&client->mpd_node, root_element);
2587 /* free the document */
2589 /* cleanup function for the XML library */
2590 xmlCleanupParser ();
2591 /* dump XML library memory for debugging */
2594 GST_MPD_CLIENT_UNLOCK (client);
2603 gst_mpdparser_get_baseURL (GstMpdClient * client)
2605 GstActiveStream *stream;
2607 g_return_val_if_fail (client != NULL, NULL);
2608 g_return_val_if_fail (client->active_streams != NULL, NULL);
2609 stream = g_list_nth_data (client->active_streams, client->stream_idx);
2610 g_return_val_if_fail (stream != NULL, NULL);
2612 return stream->baseURL;
2616 gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
2619 GstActiveStream *stream;
2622 g_return_val_if_fail (client != NULL, NULL);
2623 g_return_val_if_fail (client->active_streams != NULL, NULL);
2624 stream = g_list_nth_data (client->active_streams, indexStream);
2625 g_return_val_if_fail (stream != NULL, NULL);
2627 return (GstMediaSegment *) g_list_nth_data (stream->segments, indexChunk);
2631 gst_mpd_client_add_media_segment (GstActiveStream * stream,
2632 GstSegmentURLNode * url_node, guint number, guint start,
2633 GstClockTime start_time, GstClockTime duration)
2635 GstMediaSegment *media_segment;
2637 media_segment = g_slice_new0 (GstMediaSegment);
2638 if (media_segment == NULL) {
2639 GST_WARNING ("Allocation of GstMediaSegment struct failed!");
2642 stream->segments = g_list_append (stream->segments, media_segment);
2643 media_segment->SegmentURL = url_node;
2644 media_segment->number = number;
2645 media_segment->start = start;
2646 media_segment->start_time = start_time;
2647 media_segment->duration = duration;
2653 gst_mpd_client_setup_representation (GstMpdClient * client,
2654 GstActiveStream * stream, GstRepresentationNode * representation)
2656 GstStreamPeriod *stream_period;
2658 GstClockTime PeriodStart, PeriodEnd, start_time, duration;
2659 GstMediaSegment *last_media_segment;
2662 if (stream->cur_adapt_set == NULL) {
2663 GST_WARNING ("No valid AdaptationSet node in the MPD file, aborting...");
2667 rep_list = stream->cur_adapt_set->Representations;
2668 stream->cur_representation = representation;
2669 stream->representation_idx = g_list_index (rep_list, representation);
2671 /* clean the old segment list, if any */
2672 if (stream->segments) {
2673 g_list_foreach (stream->segments,
2674 (GFunc) gst_mpdparser_free_media_segment, NULL);
2675 g_list_free (stream->segments);
2676 stream->segments = NULL;
2679 stream_period = gst_mpdparser_get_stream_period (client);
2680 g_return_val_if_fail (stream_period != NULL, FALSE);
2681 g_return_val_if_fail (stream_period->period != NULL, FALSE);
2683 PeriodStart = stream_period->start;
2684 if (GST_CLOCK_TIME_IS_VALID (stream_period->duration))
2685 PeriodEnd = stream_period->start + stream_period->duration;
2687 PeriodEnd = GST_CLOCK_TIME_NONE;
2689 GST_LOG ("Building segment list for Period from %" GST_TIME_FORMAT " to %"
2690 GST_TIME_FORMAT, GST_TIME_ARGS (PeriodStart), GST_TIME_ARGS (PeriodEnd));
2692 if (representation->SegmentBase != NULL
2693 || representation->SegmentList != NULL) {
2696 /* get the first segment_base of the selected representation */
2697 if ((stream->cur_segment_base =
2698 gst_mpdparser_get_segment_base (stream_period->period,
2699 stream->cur_adapt_set, representation)) == NULL) {
2700 GST_DEBUG ("No useful SegmentBase node for the current Representation");
2703 /* get the first segment_list of the selected representation */
2704 if ((stream->cur_segment_list =
2705 gst_mpdparser_get_segment_list (stream_period->period,
2706 stream->cur_adapt_set, representation)) == NULL) {
2707 GST_DEBUG ("No useful SegmentList node for the current Representation");
2708 /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
2709 if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, PeriodStart,
2714 /* build the list of GstMediaSegment nodes from the SegmentList node */
2715 SegmentURL = stream->cur_segment_list->SegmentURL;
2716 if (SegmentURL == NULL) {
2718 ("No valid list of SegmentURL nodes in the MPD file, aborting...");
2722 /* build segment list */
2723 i = stream->cur_segment_list->MultSegBaseType->startNumber;
2725 start_time = PeriodStart;
2727 GST_LOG ("Building media segment list using a SegmentList node");
2728 if (stream->cur_segment_list->MultSegBaseType->SegmentTimeline) {
2729 GstSegmentTimelineNode *timeline;
2733 timeline = stream->cur_segment_list->MultSegBaseType->SegmentTimeline;
2734 for (list = g_list_first (timeline->S); list; list = g_list_next (list)) {
2737 S = (GstSNode *) list->data;
2738 GST_LOG ("Processing S node: d=%d r=%d t=%d", S->d, S->r, S->t);
2739 duration = S->d * GST_SECOND;
2741 stream->cur_segment_list->MultSegBaseType->SegBaseType->timescale;
2743 duration /= timescale;
2746 start_time = S->t * GST_SECOND;
2748 start_time /= timescale;
2751 for (j = 0; j <= S->r && SegmentURL != NULL; j++) {
2752 if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i,
2753 start, start_time, duration)) {
2758 start_time += duration;
2759 SegmentURL = g_list_next (SegmentURL);
2763 duration = gst_mpd_client_get_segment_duration (client);
2764 if (!GST_CLOCK_TIME_IS_VALID (duration))
2767 while (SegmentURL) {
2768 if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i, 0,
2769 start_time, duration)) {
2773 start_time += duration;
2774 SegmentURL = g_list_next (SegmentURL);
2779 if (representation->SegmentTemplate != NULL) {
2780 stream->cur_seg_template = representation->SegmentTemplate;
2781 } else if (stream->cur_adapt_set->SegmentTemplate != NULL) {
2782 stream->cur_seg_template = stream->cur_adapt_set->SegmentTemplate;
2783 } else if (stream_period->period->SegmentTemplate != NULL) {
2784 stream->cur_seg_template = stream_period->period->SegmentTemplate;
2787 if (stream->cur_seg_template == NULL
2788 || stream->cur_seg_template->MultSegBaseType == NULL) {
2789 /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
2790 if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) {
2794 /* build segment list */
2795 i = stream->cur_seg_template->MultSegBaseType->startNumber;
2797 start_time = PeriodStart;
2799 GST_LOG ("Building media segment list using this template: %s",
2800 stream->cur_seg_template->media);
2801 if (stream->cur_seg_template->MultSegBaseType->SegmentTimeline) {
2802 GstSegmentTimelineNode *timeline;
2806 timeline = stream->cur_seg_template->MultSegBaseType->SegmentTimeline;
2807 for (list = g_list_first (timeline->S); list; list = g_list_next (list)) {
2810 S = (GstSNode *) list->data;
2811 GST_LOG ("Processing S node: d=%d r=%d t=%d", S->d, S->r, S->t);
2812 duration = S->d * GST_SECOND;
2814 stream->cur_seg_template->MultSegBaseType->SegBaseType->timescale;
2816 duration /= timescale;
2819 start_time = S->t * GST_SECOND;
2821 start_time /= timescale;
2824 for (j = 0; j <= S->r; j++) {
2825 if (!gst_mpd_client_add_media_segment (stream, NULL, i, start,
2826 start_time, duration)) {
2831 start_time += duration;
2835 duration = gst_mpd_client_get_segment_duration (client);
2836 if (!GST_CLOCK_TIME_IS_VALID (duration)
2837 || !GST_CLOCK_TIME_IS_VALID (PeriodEnd))
2840 while (PeriodStart + start_time < PeriodEnd) {
2841 if (!gst_mpd_client_add_media_segment (stream, NULL, i, 0, start_time,
2846 start_time += duration;
2852 /* check duration of last segment */
2853 if(stream->segments)
2854 last_media_segment = g_list_last (stream->segments)->data;
2856 last_media_segment = NULL;
2857 if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
2858 if (last_media_segment->start_time + last_media_segment->duration >
2860 last_media_segment->duration = PeriodEnd - last_media_segment->start_time;
2861 GST_LOG ("Fixed duration of last segment: %" GST_TIME_FORMAT,
2862 GST_TIME_ARGS (last_media_segment->duration));
2864 GST_LOG ("Built a list of %d segments", last_media_segment->number);
2867 g_free (stream->baseURL);
2868 stream->baseURL = gst_mpdparser_parse_baseURL (client);
2874 gst_mpd_client_setup_media_presentation (GstMpdClient * client)
2876 GstStreamPeriod *stream_period;
2877 GstPeriodNode *period_node;
2878 GstClockTime start, duration;
2881 gboolean ret = FALSE;
2883 g_return_val_if_fail (client != NULL, FALSE);
2884 g_return_val_if_fail (client->mpd_node != NULL, FALSE);
2886 GST_DEBUG ("Building the list of Periods in the Media Presentation");
2887 GST_MPD_CLIENT_LOCK (client);
2888 /* clean the old period list, if any */
2889 if (client->periods) {
2890 g_list_foreach (client->periods,
2891 (GFunc) gst_mpdparser_free_stream_period, NULL);
2892 g_list_free (client->periods);
2893 client->periods = NULL;
2898 duration = GST_CLOCK_TIME_NONE;
2899 for (list = g_list_first (client->mpd_node->Periods); list;
2900 list = g_list_next (list)) {
2901 period_node = (GstPeriodNode *) list->data;
2902 if (period_node->start != -1) {
2903 /* we have a regular period */
2904 start = period_node->start * GST_MSECOND;
2905 } else if (duration != GST_CLOCK_TIME_NONE) {
2906 /* start time inferred from previous period, this is still a regular period */
2908 } else if (idx == 0 && client->mpd_node->type == GST_MPD_FILE_TYPE_STATIC) {
2909 /* first period of a static MPD file, start time is 0 */
2912 /* this is an 'Early Available Period' */
2916 if (period_node->duration != -1) {
2917 duration = period_node->duration * GST_MSECOND;
2918 } else if ((next = g_list_next (list)) != NULL) {
2919 /* try to infer this period duration from the start time of the next period */
2920 GstPeriodNode *next_period_node = next->data;
2921 if (next_period_node->start != -1) {
2922 duration = next_period_node->start * GST_MSECOND - start;
2924 /* Invalid MPD file! */
2927 } else if (client->mpd_node->mediaPresentationDuration != -1) {
2928 /* last Period of the Media Presentation */
2930 client->mpd_node->mediaPresentationDuration * GST_MSECOND - start;
2932 /* Invalid MPD file! */
2936 stream_period = g_slice_new0 (GstStreamPeriod);
2937 if (stream_period == NULL) {
2940 client->periods = g_list_append (client->periods, stream_period);
2941 stream_period->period = period_node;
2942 stream_period->number = idx++;
2943 stream_period->start = start;
2944 stream_period->duration = duration;
2946 GST_LOG (" - added Period %d start=%" GST_TIME_FORMAT " duration=%"
2947 GST_TIME_FORMAT, idx, GST_TIME_ARGS (start), GST_TIME_ARGS (duration));
2950 GST_MPD_CLIENT_UNLOCK (client);
2951 GST_DEBUG ("Found a total of %d valid Periods in the Media Presentation",
2956 GST_MPD_CLIENT_UNLOCK (client);
2958 ("Found an Early Available Period, skipping the rest of the Media Presentation");
2962 GST_MPD_CLIENT_UNLOCK (client);
2964 ("Cannot get the duration of the Period %d, skipping the rest of the Media Presentation",
2969 GST_MPD_CLIENT_UNLOCK (client);
2970 GST_WARNING ("Allocation of GstStreamPeriod struct failed!");
2975 gst_mpd_client_setup_streaming (GstMpdClient * client,
2976 GstStreamMimeType mimeType, gchar * lang)
2978 GstActiveStream *stream;
2979 GstStreamPeriod *stream_period;
2980 GstAdaptationSetNode *adapt_set;
2981 GstRepresentationNode *representation;
2982 GList *rep_list = NULL;
2984 stream_period = gst_mpdparser_get_stream_period (client);
2985 if (stream_period == NULL || stream_period->period == NULL) {
2986 GST_DEBUG ("No more Period nodes in the MPD file, terminating...");
2991 case GST_STREAM_VIDEO:
2992 /* select the adaptation set for the video pipeline */
2994 gst_mpdparser_get_adapt_set_with_mimeType_and_idx (stream_period->
2995 period->AdaptationSets, "video", 0);
2997 GST_INFO ("No video adaptation set found");
3000 /* retrive the list of representations */
3001 rep_list = adapt_set->Representations;
3003 GST_WARNING ("Can not retrieve any representation, aborting...");
3007 case GST_STREAM_AUDIO:
3009 gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang
3010 (stream_period->period->AdaptationSets, "audio", lang);
3011 /* if we did not found the requested audio language, get the first one */
3014 gst_mpdparser_get_first_adapt_set_with_mimeType (stream_period->
3015 period->AdaptationSets, "audio");
3017 GST_INFO ("No audio adaptation set found");
3020 rep_list = adapt_set->Representations;
3022 GST_WARNING ("Can not retrieve any representation, aborting...");
3026 case GST_STREAM_APPLICATION:
3028 gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang
3029 (stream_period->period->AdaptationSets, "application", lang);
3030 /* if we did not found the requested subtitles language, get the first one */
3033 gst_mpdparser_get_first_adapt_set_with_mimeType (stream_period->
3034 period->AdaptationSets, "application");
3036 GST_INFO ("No application adaptation set found");
3039 rep_list = adapt_set->Representations;
3041 GST_WARNING ("Can not retrieve any representation, aborting...");
3046 GST_WARNING ("Unsupported mimeType %d", mimeType);
3050 stream = g_slice_new0 (GstActiveStream);
3051 if (stream == NULL) {
3052 GST_WARNING ("Allocation of active stream struct failed!");
3055 client->active_streams = g_list_append (client->active_streams, stream);
3057 stream->baseURL_idx = 0;
3058 stream->mimeType = mimeType;
3059 stream->cur_adapt_set = adapt_set;
3061 /* retrive representation list */
3062 if (stream->cur_adapt_set != NULL)
3063 rep_list = stream->cur_adapt_set->Representations;
3068 gst_mpdparser_get_representation_with_max_bandwidth (rep_list,
3069 stream->max_bandwidth);
3071 if (!representation) {
3073 ("Can not retrieve a representation with the requested bandwidth");
3074 representation = gst_mpdparser_get_lowest_representation (rep_list);
3078 representation = gst_mpdparser_get_lowest_representation (rep_list);
3081 if (!representation) {
3082 GST_WARNING ("No valid representation in the MPD file, aborting...");
3086 if (!gst_mpd_client_setup_representation (client, stream, representation))
3089 GST_INFO ("Successfully setup the download pipeline for mimeType %d",
3096 gst_mpd_client_get_next_fragment (GstMpdClient * client,
3097 guint indexStream, gboolean * discontinuity, gchar ** uri,
3098 GstClockTime * duration, GstClockTime * timestamp)
3100 GstActiveStream *stream = NULL;
3101 GstMediaSegment *currentChunk;
3102 gchar *mediaURL = NULL;
3106 g_return_val_if_fail (client != NULL, FALSE);
3107 g_return_val_if_fail (client->active_streams != NULL, FALSE);
3108 stream = g_list_nth_data (client->active_streams, indexStream);
3109 g_return_val_if_fail (stream != NULL, FALSE);
3110 g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
3111 g_return_val_if_fail (discontinuity != NULL, FALSE);
3113 GST_MPD_CLIENT_LOCK (client);
3114 segment_idx = gst_mpd_client_get_segment_index (stream);
3115 GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
3118 gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx);
3119 if (currentChunk == NULL) {
3120 GST_MPD_CLIENT_UNLOCK (client);
3124 if (currentChunk->SegmentURL != NULL) {
3125 mediaURL = gst_mpdparser_get_mediaURL (client, currentChunk->SegmentURL);
3126 } else if (stream->cur_seg_template != NULL) {
3128 gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media,
3129 stream->cur_representation->id, currentChunk->number,
3130 stream->cur_representation->bandwidth, currentChunk->start);
3133 *timestamp = currentChunk->start_time;
3134 *duration = currentChunk->duration;
3135 *discontinuity = segment_idx != currentChunk->number;
3136 if (mediaURL == NULL) {
3137 /* single segment with URL encoded in the baseURL syntax element */
3138 *uri = g_strdup (gst_mpdparser_get_baseURL (client));
3139 } else if (strncmp (mediaURL, "http://", 7) != 0) {
3140 *uri = g_strconcat (gst_mpdparser_get_baseURL (client), mediaURL, NULL);
3145 gst_mpd_client_set_segment_index (stream, segment_idx + 1);
3146 GST_MPD_CLIENT_UNLOCK (client);
3148 GST_DEBUG ("Loading chunk with URL %s", *uri);
3154 gst_mpd_client_get_next_header (GstMpdClient * client, const gchar ** uri,
3157 GstActiveStream *stream;
3158 GstStreamPeriod *stream_period;
3160 stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
3161 g_return_val_if_fail (stream != NULL, FALSE);
3162 g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
3163 stream_period = gst_mpdparser_get_stream_period (client);
3164 g_return_val_if_fail (stream_period != NULL, FALSE);
3165 g_return_val_if_fail (stream_period->period != NULL, FALSE);
3167 GST_DEBUG ("Looking for current representation header");
3168 GST_MPD_CLIENT_LOCK (client);
3170 if (stream->cur_segment_base && stream->cur_segment_base->Initialization) {
3172 if (stream->cur_segment_base->Initialization->sourceURL == NULL) {
3173 stream->cur_segment_base->Initialization->sourceURL = gst_mpdparser_get_baseURL (client);
3174 }//if not present initialization @sourceURL attribute, it's mapped to baseURL
3177 gst_mpdparser_get_initializationURL (stream->cur_segment_base->
3179 } else if (stream->cur_seg_template) {
3180 const gchar *initialization = NULL;
3181 if (stream->cur_seg_template->initialization) {
3182 initialization = stream->cur_seg_template->initialization;
3183 } else if (stream->cur_adapt_set->SegmentTemplate
3184 && stream->cur_adapt_set->SegmentTemplate->initialization) {
3185 initialization = stream->cur_adapt_set->SegmentTemplate->initialization;
3186 } else if (stream_period->period->SegmentTemplate
3187 && stream_period->period->SegmentTemplate->initialization) {
3188 initialization = stream_period->period->SegmentTemplate->initialization;
3190 *uri = gst_mpdparser_build_URL_from_template (initialization,
3191 stream->cur_representation->id, 0,
3192 stream->cur_representation->bandwidth, 0);
3194 GST_MPD_CLIENT_UNLOCK (client);
3196 return *uri == NULL ? FALSE : TRUE;
3200 gst_mpd_client_get_current_position (GstMpdClient * client)
3202 GstActiveStream *stream;
3203 GstMediaSegment *media_segment;
3205 stream = g_list_nth_data (client->active_streams, client->stream_idx);
3206 g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
3209 g_list_nth_data (stream->segments,
3210 gst_mpd_client_get_segment_index (stream));
3211 g_return_val_if_fail (media_segment != NULL, GST_CLOCK_TIME_NONE);
3213 return media_segment->start_time;
3217 gst_mpd_client_get_next_fragment_duration (GstMpdClient * client)
3219 GstActiveStream *stream;
3220 GstMediaSegment *media_segment;
3222 stream = g_list_nth_data (client->active_streams, client->stream_idx);
3223 g_return_val_if_fail (stream != NULL, 0);
3226 g_list_nth_data (stream->segments,
3227 gst_mpd_client_get_segment_index (stream));
3229 return media_segment == NULL ? 0 : media_segment->duration;
3233 gst_mpd_client_get_media_presentation_duration (GstMpdClient * client)
3235 GstClockTime duration;
3237 g_return_val_if_fail (client != NULL, GST_CLOCK_TIME_NONE);
3239 GST_MPD_CLIENT_LOCK (client);
3240 if (client->mpd_node->mediaPresentationDuration != -1) {
3241 duration = client->mpd_node->mediaPresentationDuration * GST_MSECOND;
3243 /* We can only get the duration for on-demand streams */
3244 duration = GST_CLOCK_TIME_NONE;
3246 GST_MPD_CLIENT_UNLOCK (client);
3252 gst_mpd_client_set_period_index (GstMpdClient * client, guint period_idx)
3254 GstStreamPeriod *next_stream_period;
3255 gboolean ret = FALSE;
3257 g_return_val_if_fail (client != NULL, FALSE);
3258 g_return_val_if_fail (client->periods != NULL, FALSE);
3260 GST_MPD_CLIENT_LOCK (client);
3261 next_stream_period = g_list_nth_data (client->periods, period_idx);
3262 if (next_stream_period != NULL) {
3263 client->period_idx = period_idx;
3266 GST_MPD_CLIENT_UNLOCK (client);
3272 gst_mpd_client_get_period_index (GstMpdClient * client)
3276 g_return_val_if_fail (client != NULL, 0);
3277 GST_MPD_CLIENT_LOCK (client);
3278 period_idx = client->period_idx;
3279 GST_MPD_CLIENT_UNLOCK (client);
3285 gst_mpd_client_set_segment_index_for_all_streams (GstMpdClient * client,
3290 g_return_if_fail (client != NULL);
3291 g_return_if_fail (client->active_streams != NULL);
3293 /* FIXME: support multiple streams with different segment duration */
3294 for (list = g_list_first (client->active_streams); list;
3295 list = g_list_next (list)) {
3296 GstActiveStream *stream = (GstActiveStream *) list->data;
3298 stream->segment_idx = segment_idx;
3304 gst_mpd_client_set_segment_index (GstActiveStream * stream, guint segment_idx)
3306 g_return_if_fail (stream != NULL);
3308 stream->segment_idx = segment_idx;
3312 gst_mpd_client_get_segment_index (GstActiveStream * stream)
3314 g_return_val_if_fail (stream != NULL, 0);
3316 return stream->segment_idx;
3320 gst_mpd_client_is_live (GstMpdClient * client)
3322 g_return_val_if_fail (client != NULL, FALSE);
3323 g_return_val_if_fail (client->mpd_node != NULL, FALSE);
3325 return client->mpd_node->type == GST_MPD_FILE_TYPE_DYNAMIC;
3329 gst_mpdparser_get_nb_active_stream (GstMpdClient * client)
3331 g_return_val_if_fail (client != NULL, 0);
3333 return g_list_length (client->active_streams);
3337 gst_mpdparser_get_nb_adaptationSet (GstMpdClient * client)
3339 GstStreamPeriod *stream_period;
3341 stream_period = gst_mpdparser_get_stream_period (client);
3342 g_return_val_if_fail (stream_period != NULL, 0);
3343 g_return_val_if_fail (stream_period->period != NULL, 0);
3345 return g_list_length (stream_period->period->AdaptationSets);
3349 gst_mpdparser_get_active_stream_by_index (GstMpdClient * client,
3352 g_return_val_if_fail (client != NULL, NULL);
3353 g_return_val_if_fail (client->active_streams != NULL, NULL);
3355 return g_list_nth_data (client->active_streams, stream_idx);
3358 static const gchar *
3359 gst_mpdparser_mimetype_to_caps (const gchar * mimeType)
3361 if (mimeType == NULL)
3363 if (strcmp (mimeType, "video/mp2t") == 0) {
3364 return "video/mpegts";
3365 } else if (strcmp (mimeType, "video/mp4") == 0) {
3366 return "video/quicktime";
3367 } else if (strcmp (mimeType, "audio/mp4") == 0) {
3368 return "audio/x-m4a";
3374 gst_mpd_client_get_stream_mimeType (GstActiveStream * stream)
3376 const gchar *mimeType;
3378 if (stream == NULL || stream->cur_adapt_set == NULL
3379 || stream->cur_representation == NULL)
3382 mimeType = stream->cur_representation->RepresentationBase->mimeType;
3383 if (mimeType == NULL) {
3384 mimeType = stream->cur_adapt_set->RepresentationBase->mimeType;
3387 return gst_mpdparser_mimetype_to_caps (mimeType);
3391 gst_mpd_client_get_bitstream_switching_flag (GstActiveStream * stream)
3393 if (stream == NULL || stream->cur_adapt_set == NULL)
3396 return stream->cur_adapt_set->bitstreamSwitching;
3400 gst_mpd_client_get_video_stream_width (GstActiveStream * stream)
3404 if (stream == NULL || stream->cur_adapt_set == NULL
3405 || stream->cur_representation == NULL)
3408 width = stream->cur_representation->RepresentationBase->width;
3410 width = stream->cur_adapt_set->RepresentationBase->width;
3417 gst_mpd_client_get_video_stream_height (GstActiveStream * stream)
3421 if (stream == NULL || stream->cur_adapt_set == NULL
3422 || stream->cur_representation == NULL)
3425 height = stream->cur_representation->RepresentationBase->height;
3427 height = stream->cur_adapt_set->RepresentationBase->height;
3434 gst_mpd_client_get_audio_stream_rate (GstActiveStream * stream)
3438 if (stream == NULL || stream->cur_adapt_set == NULL
3439 || stream->cur_representation == NULL)
3442 rate = stream->cur_representation->RepresentationBase->audioSamplingRate;
3444 rate = stream->cur_adapt_set->RepresentationBase->audioSamplingRate;
3447 return rate ? atoi (rate) : 0;
3451 gst_mpd_client_get_audio_stream_num_channels (GstActiveStream * stream)
3453 if (stream == NULL || stream->cur_adapt_set == NULL
3454 || stream->cur_representation == NULL)
3456 /* TODO: here we have to parse the AudioChannelConfiguration descriptors */
3461 gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient * client,
3464 GstStreamPeriod *stream_period;
3465 GstAdaptationSetNode *adapt_set;
3467 gchar *this_mimeType = "audio";
3468 gchar *mimeType = NULL;
3469 guint nb_adapatation_set = 0;
3471 stream_period = gst_mpdparser_get_stream_period (client);
3472 g_return_val_if_fail (stream_period != NULL, 0);
3473 g_return_val_if_fail (stream_period->period != NULL, 0);
3475 for (list = g_list_first (stream_period->period->AdaptationSets); list;
3476 list = g_list_next (list)) {
3477 adapt_set = (GstAdaptationSetNode *) list->data;
3479 gchar *this_lang = adapt_set->lang;
3480 GstRepresentationNode *rep;
3482 gst_mpdparser_get_lowest_representation (adapt_set->Representations);
3483 if (rep->RepresentationBase)
3484 mimeType = rep->RepresentationBase->mimeType;
3485 if (!mimeType && adapt_set->RepresentationBase) {
3486 mimeType = adapt_set->RepresentationBase->mimeType;
3489 if (strncmp_ext (mimeType, this_mimeType) == 0) {
3491 nb_adapatation_set++;
3492 *lang = g_list_append (*lang, this_lang);
3498 return nb_adapatation_set;