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 (const 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, GstActiveStream * stream);
128 static GstAdaptationSetNode
129 *gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets,
130 const gchar * mimeType);
131 static GstAdaptationSetNode
132 *gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
133 const gchar * mimeType, gint idx);
134 static GstAdaptationSetNode
135 *gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *
136 AdaptationSets, const gchar * mimeType, const gchar * lang);
139 static GstRepresentationNode *gst_mpdparser_get_lowest_representation (GList *
142 static GstRepresentationNode *gst_mpdparser_get_highest_representation (GList *
144 static GstRepresentationNode
145 *gst_mpdparser_get_representation_with_max_bandwidth (GList *
146 Representations, guint64 max_bandwidth);
148 static GstSegmentBaseType *gst_mpdparser_get_segment_base (GstPeriodNode *
149 Period, GstAdaptationSetNode * AdaptationSet,
150 GstRepresentationNode * Representation);
151 static GstSegmentListNode *gst_mpdparser_get_segment_list (GstPeriodNode *
152 Period, GstAdaptationSetNode * AdaptationSet,
153 GstRepresentationNode * Representation);
155 /* Memory management */
156 static void gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node);
157 static void gst_mpdparser_free_prog_info_node (GstProgramInformationNode *
159 static void gst_mpdparser_free_metrics_node (GstMetricsNode * metrics_node);
160 static void gst_mpdparser_free_metrics_range_node (GstMetricsRangeNode *
162 static void gst_mpdparser_free_period_node (GstPeriodNode * period_node);
163 static void gst_mpdparser_free_subset_node (GstSubsetNode * subset_node);
164 static void gst_mpdparser_free_segment_template_node (GstSegmentTemplateNode *
165 segment_template_node);
167 gst_mpdparser_free_representation_base_type (GstRepresentationBaseType *
168 representation_base);
169 static void gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode *
170 adaptation_set_node);
171 static void gst_mpdparser_free_representation_node (GstRepresentationNode *
172 representation_node);
173 static void gst_mpdparser_free_subrepresentation_node (GstSubRepresentationNode
175 static void gst_mpdparser_free_s_node (GstSNode * s_node);
176 static void gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode *
178 static void gst_mpdparser_free_url_type_node (GstURLType * url_type_node);
179 static void gst_mpdparser_free_seg_base_type_ext (GstSegmentBaseType *
181 static void gst_mpdparser_free_mult_seg_base_type_ext (GstMultSegmentBaseType *
183 static void gst_mpdparser_free_segment_list_node (GstSegmentListNode *
185 static void gst_mpdparser_free_segment_url_node (GstSegmentURLNode *
187 static void gst_mpdparser_free_base_url_node (GstBaseURL * base_url_node);
188 static void gst_mpdparser_free_descriptor_type_node (GstDescriptorType *
190 static void gst_mpdparser_free_content_component_node (GstContentComponentNode *
191 content_component_node);
192 static void gst_mpdparser_free_stream_period (GstStreamPeriod * stream_period);
193 static void gst_mpdparser_free_media_segment (GstMediaSegment * media_segment);
194 static void gst_mpdparser_free_active_stream (GstActiveStream * active_stream);
196 /* functions to parse node namespaces, content and properties */
198 gst_mpdparser_get_xml_prop_string (xmlNode * a_node, const gchar * property)
200 xmlChar *prop_string;
202 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
204 GST_LOG (" - %s: %s", property, prop_string);
207 return (gchar *) prop_string;
211 gst_mpdparser_get_xml_prop_string_vector_type (xmlNode * a_node,
212 const gchar * property)
214 xmlChar *prop_string;
215 gchar **prop_string_vector = NULL;
218 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
220 prop_string_vector = g_strsplit ((gchar *) prop_string, " ", -1);
221 if (!prop_string_vector) {
222 GST_WARNING ("Scan of string vector property failed!");
225 GST_LOG (" - %s:", property);
226 while (prop_string_vector[i]) {
227 GST_LOG (" %s", prop_string_vector[i]);
230 xmlFree (prop_string);
233 return prop_string_vector;
237 gst_mpdparser_get_xml_prop_unsigned_integer (xmlNode * a_node,
238 const gchar * property, guint default_val)
240 xmlChar *prop_string;
241 guint prop_unsigned_integer = default_val;
243 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
245 if (sscanf ((gchar *) prop_string, "%u", &prop_unsigned_integer)) {
246 GST_LOG (" - %s: %u", property, prop_unsigned_integer);
249 ("failed to parse unsigned integer property %s from xml string %s",
250 property, prop_string);
252 xmlFree (prop_string);
255 return prop_unsigned_integer;
259 gst_mpdparser_get_xml_prop_uint_vector_type (xmlNode * a_node,
260 const gchar * property, guint * size)
262 xmlChar *prop_string;
264 guint *prop_uint_vector = NULL, i;
266 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
268 str_vector = g_strsplit ((gchar *) prop_string, " ", -1);
270 GST_WARNING ("Scan of uint vector property failed!");
273 *size = g_strv_length (str_vector);
274 prop_uint_vector = g_malloc (*size * sizeof (guint));
275 if (!prop_uint_vector) {
276 GST_WARNING ("Array allocation failed!");
278 GST_LOG (" - %s:", property);
279 for (i = 0; i < *size; i++) {
280 if (sscanf ((gchar *) str_vector[i], "%u", &prop_uint_vector[i])) {
281 GST_LOG (" %u", prop_uint_vector[i]);
284 ("failed to parse uint vector type property %s from xml string %s",
285 property, str_vector[i]);
289 xmlFree (prop_string);
290 g_strfreev (str_vector);
293 return prop_uint_vector;
297 gst_mpdparser_get_xml_prop_double (xmlNode * a_node, const gchar * property)
299 xmlChar *prop_string;
300 gdouble prop_double = 0;
302 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
304 if (sscanf ((gchar *) prop_string, "%lf", &prop_double)) {
305 GST_LOG (" - %s: %lf", property, prop_double);
307 GST_WARNING ("failed to parse double property %s from xml string %s",
308 property, prop_string);
310 xmlFree (prop_string);
317 gst_mpdparser_get_xml_prop_boolean (xmlNode * a_node, const gchar * property)
319 xmlChar *prop_string;
320 gboolean prop_bool = FALSE;
322 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
324 if (xmlStrcmp (prop_string, (xmlChar *) "false") == 0) {
325 GST_LOG (" - %s: false", property);
326 } else if (xmlStrcmp (prop_string, (xmlChar *) "true") == 0) {
327 GST_LOG (" - %s: true", property);
330 GST_WARNING ("failed to parse boolean property %s from xml string %s",
331 property, prop_string);
333 xmlFree (prop_string);
339 static GstMPDFileType
340 gst_mpdparser_get_xml_prop_type (xmlNode * a_node, const gchar * property)
342 xmlChar *prop_string;
343 GstMPDFileType prop_type = GST_MPD_FILE_TYPE_STATIC; /* default */
345 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
347 if (xmlStrcmp (prop_string, (xmlChar *) "OnDemand") == 0
348 || xmlStrcmp (prop_string, (xmlChar *) "static") == 0) {
349 GST_LOG (" - %s: static", property);
350 prop_type = GST_MPD_FILE_TYPE_STATIC;
351 } else if (xmlStrcmp (prop_string, (xmlChar *) "Live") == 0
352 || xmlStrcmp (prop_string, (xmlChar *) "dynamic") == 0) {
353 GST_LOG (" - %s: dynamic", property);
354 prop_type = GST_MPD_FILE_TYPE_DYNAMIC;
356 GST_WARNING ("failed to parse MPD type property %s from xml string %s",
357 property, prop_string);
359 xmlFree (prop_string);
366 gst_mpdparser_get_xml_prop_SAP_type (xmlNode * a_node, const gchar * property)
368 xmlChar *prop_string;
369 guint prop_SAP_type = 0;
371 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
373 if (sscanf ((gchar *) prop_string, "%u", &prop_SAP_type)
374 && prop_SAP_type <= 6) {
375 GST_LOG (" - %s: %u", property, prop_SAP_type);
378 ("failed to parse unsigned integer property %s from xml string %s",
379 property, prop_string);
381 xmlFree (prop_string);
384 return (GstSAPType) prop_SAP_type;
388 gst_mpdparser_get_xml_prop_range (xmlNode * a_node, const gchar * property)
390 xmlChar *prop_string;
391 GstRange *prop_range = NULL;
392 guint64 first_byte_pos = 0, last_byte_pos = 0;
396 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
398 len = xmlStrlen (prop_string);
399 str = (gchar *) prop_string;
400 GST_TRACE ("range: %s, len %d", str, len);
403 pos = strcspn (str, "-");
405 GST_TRACE ("pos %d >= len %d", pos, len);
408 /* read first_byte_pos */
410 if (sscanf (str, "%llu", &first_byte_pos) != 1) {
414 /* read last_byte_pos */
415 if (pos < (len - 1)) {
416 if (sscanf (str + pos + 1, "%llu", &last_byte_pos) != 1) {
420 /* malloc return data structure */
421 prop_range = g_slice_new0 (GstRange);
422 if (prop_range == NULL) {
423 GST_WARNING ("Allocation of GstRange failed!");
426 prop_range->first_byte_pos = first_byte_pos;
427 prop_range->last_byte_pos = last_byte_pos;
428 GST_LOG (" - %s: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT,
429 property, first_byte_pos, last_byte_pos);
430 xmlFree (prop_string);
436 GST_WARNING ("failed to parse property %s from xml string %s", property,
442 gst_mpdparser_get_xml_prop_ratio (xmlNode * a_node, const gchar * property)
444 xmlChar *prop_string;
445 GstRatio *prop_ratio = NULL;
446 guint num = 0, den = 1;
450 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
452 len = xmlStrlen (prop_string);
453 str = (gchar *) prop_string;
454 GST_TRACE ("ratio: %s, len %d", str, len);
457 pos = strcspn (str, ":");
459 GST_TRACE ("pos %d >= len %d", pos, len);
464 if (sscanf (str, "%u", &num) != 1) {
469 if (pos < (len - 1)) {
470 if (sscanf (str + pos + 1, "%u", &den) != 1) {
474 /* malloc return data structure */
475 prop_ratio = g_slice_new0 (GstRatio);
476 if (prop_ratio == NULL) {
477 GST_WARNING ("Allocation of GstRatio failed!");
480 prop_ratio->num = num;
481 prop_ratio->den = den;
482 GST_LOG (" - %s: %u:%u", property, num, den);
483 xmlFree (prop_string);
489 GST_WARNING ("failed to parse property %s from xml string %s", property,
494 static GstFrameRate *
495 gst_mpdparser_get_xml_prop_framerate (xmlNode * a_node, const gchar * property)
497 xmlChar *prop_string;
498 GstFrameRate *prop_framerate = NULL;
499 guint num = 0, den = 1;
503 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
505 len = xmlStrlen (prop_string);
506 str = (gchar *) prop_string;
507 GST_TRACE ("framerate: %s, len %d", str, len);
509 /* read "/" if available */
510 pos = strcspn (str, "/");
513 if (sscanf (str, "%u", &num) != 1) {
517 /* read den (if available) */
518 if (pos < (len - 1)) {
519 if (sscanf (str + pos + 1, "%u", &den) != 1) {
523 /* alloc return data structure */
524 prop_framerate = g_slice_new0 (GstFrameRate);
525 if (prop_framerate == NULL) {
526 GST_WARNING ("Allocation of GstFrameRate failed!");
529 prop_framerate->num = num;
530 prop_framerate->den = den;
532 GST_LOG (" - %s: %u", property, num);
534 GST_LOG (" - %s: %u/%u", property, num, den);
535 xmlFree (prop_string);
538 return prop_framerate;
541 GST_WARNING ("failed to parse property %s from xml string %s", property,
546 static GstConditionalUintType *
547 gst_mpdparser_get_xml_prop_cond_uint (xmlNode * a_node, const gchar * property)
549 xmlChar *prop_string;
550 GstConditionalUintType *prop_cond_uint = NULL;
555 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
557 str = (gchar *) prop_string;
558 GST_TRACE ("conditional uint: %s", str);
560 if (strcmp (str, "false") == 0) {
563 } else if (strcmp (str, "true") == 0) {
568 if (sscanf (str, "%u", &val) != 1)
572 /* alloc return data structure */
573 prop_cond_uint = g_slice_new0 (GstConditionalUintType);
574 if (prop_cond_uint == NULL) {
575 GST_WARNING ("Allocation of GstConditionalUintType failed!");
578 prop_cond_uint->flag = flag;
579 prop_cond_uint->value = val;
580 GST_LOG (" - %s: flag=%s val=%u", property, flag ? "true" : "false", val);
581 xmlFree (prop_string);
584 return prop_cond_uint;
587 GST_WARNING ("failed to parse property %s from xml string %s", property,
595 The dateTime data type is used to specify a date and a time.
597 The dateTime is specified in the following form "YYYY-MM-DDThh:mm:ss" where:
599 * YYYY indicates the year
600 * MM indicates the month
601 * DD indicates the day
602 * T indicates the start of the required time section
603 * hh indicates the hour
604 * mm indicates the minute
605 * ss indicates the second
607 Note: All components are required!
611 gst_mpdparser_get_xml_prop_dateTime (xmlNode * a_node, const gchar * property)
613 xmlChar *prop_string;
616 gint year, month, day, hour, minute, second;
618 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
620 len = xmlStrlen (prop_string);
621 str = (gchar *) prop_string;
622 GST_TRACE ("dateTime: %s, len %d", str, len);
624 ret = sscanf (str, "%d", &year);
627 pos = strcspn (str, "-");
629 GST_TRACE (" - year %d", year);
631 ret = sscanf (str, "%d", &month);
634 pos = strcspn (str, "-");
636 GST_TRACE (" - month %d", month);
638 ret = sscanf (str, "%d", &day);
641 pos = strcspn (str, "T");
643 GST_TRACE (" - day %d", day);
645 ret = sscanf (str, "%d", &hour);
648 pos = strcspn (str, ":");
650 GST_TRACE (" - hour %d", hour);
652 ret = sscanf (str, "%d", &minute);
655 pos = strcspn (str, ":");
657 GST_TRACE (" - minute %d", minute);
659 ret = sscanf (str, "%d", &second);
662 GST_TRACE (" - second %d", second);
664 GST_LOG (" - %s: %4d/%02d/%02d %02d:%02d:%02d", property,
665 year, month, day, hour, minute, second);
667 return gst_date_time_new (0, year, month, day, hour, minute, second);
673 GST_WARNING ("failed to parse property %s from xml string %s", property,
681 The duration data type is used to specify a time interval.
683 The time interval is specified in the following form "-PnYnMnDTnHnMnS" where:
685 * - indicates the negative sign (optional)
686 * P indicates the period (required)
687 * nY indicates the number of years
688 * nM indicates the number of months
689 * nD indicates the number of days
690 * T indicates the start of a time section (required if you are going to specify hours, minutes, or seconds)
691 * nH indicates the number of hours
692 * nM indicates the number of minutes
693 * nS indicates the number of seconds
696 /* this function computes decimals * 10 ^ (3 - pos) */
698 convert_to_millisecs (gint decimals, gint pos)
700 gint num = 1, den = 1, i = 3 - pos;
710 /* if i == 0 we have exactly 3 decimals and nothing to do */
711 return decimals * num / den;
715 gst_mpdparser_get_xml_prop_duration (xmlNode * a_node, const gchar * property)
717 xmlChar *prop_string;
719 gint64 prop_duration = -1;
720 gint ret, read, len, pos, posT;
721 gint years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds =
724 gboolean have_ms = FALSE;
726 prop_string = xmlGetProp (a_node, (const xmlChar *) property);
728 len = xmlStrlen (prop_string);
729 str = (gchar *) prop_string;
730 GST_TRACE ("duration: %s, len %d", str, len);
731 /* read "-" for sign, if present */
732 pos = strcspn (str, "-");
733 if (pos < len) { /* found "-" */
735 GST_WARNING ("sign \"-\" non at the beginning of the string");
738 GST_TRACE ("found - sign at the beginning");
743 /* read "P" for period */
744 pos = strcspn (str, "P");
746 GST_WARNING ("P not found at the beginning of the string!");
751 /* read "T" for time (if present) */
752 posT = strcspn (str, "T");
755 /* there is some room between P and T, so there must be a period section */
756 /* read years, months, days */
758 GST_TRACE ("parsing substring %s", str);
759 pos = strcspn (str, "YMD");
760 ret = sscanf (str, "%d", &read);
762 GST_WARNING ("can not read integer value from string %s!", str);
776 GST_WARNING ("unexpected char %c!", str[pos]);
780 GST_TRACE ("read number %d type %c", read, str[pos]);
785 GST_TRACE ("Y:M:D=%d:%d:%d", years, months, days);
787 /* read "T" for time (if present) */
788 /* here T is at pos == 0 */
793 /* T found, there is a time section */
794 /* read hours, minutes, seconds, cents of second */
796 GST_TRACE ("parsing substring %s", str);
797 pos = strcspn (str, "HMS,.");
798 ret = sscanf (str, "%d", &read);
800 GST_WARNING ("can not read integer value from string %s!", str);
812 /* we have read the decimal part of the seconds */
813 decimals = convert_to_millisecs (read, pos);
814 GST_TRACE ("decimal number %d (%d digits) -> %d ms", read, pos,
823 /* we have read the integer part of a decimal number in seconds */
828 GST_WARNING ("unexpected char %c!", str[pos]);
832 GST_TRACE ("read number %d type %c", read, str[pos]);
837 GST_TRACE ("H:M:S.MS=%d:%d:%d.%03d", hours, minutes, seconds, decimals);
840 xmlFree (prop_string);
842 sign * ((((((gint64) years * 365 + months * 30 + days) * 24 +
843 hours) * 60 + minutes) * 60 + seconds) * 1000 + decimals);
844 GST_LOG (" - %s: %" G_GINT64_FORMAT, property, prop_duration);
847 return prop_duration;
851 gst_mpdparser_get_xml_node_content (xmlNode * a_node)
853 xmlChar *content = NULL;
855 content = xmlNodeGetContent (a_node);
857 GST_LOG (" - %s: %s", a_node->name, content);
860 return (gchar *) content;
864 gst_mpdparser_get_xml_node_namespace (xmlNode * a_node, const gchar * prefix)
867 gchar *namespace = NULL;
869 if (prefix == NULL) {
870 /* return the default namespace */
871 namespace = g_strdup ((gchar *) a_node->ns->href);
873 GST_LOG (" - default namespace: %s", namespace);
876 /* look for the specified prefix in the namespace list */
877 for (curr_ns = a_node->ns; curr_ns; curr_ns = curr_ns->next) {
878 if (xmlStrcmp (curr_ns->prefix, (xmlChar *) prefix) == 0) {
879 namespace = g_strdup ((gchar *) curr_ns->href);
881 GST_LOG (" - %s namespace: %s", curr_ns->prefix, curr_ns->href);
891 gst_mpdparser_parse_baseURL_node (GList ** list, xmlNode * a_node)
893 GstBaseURL *new_base_url;
895 new_base_url = g_slice_new0 (GstBaseURL);
896 if (new_base_url == NULL) {
897 GST_WARNING ("Allocation of BaseURL node failed!");
900 *list = g_list_append (*list, new_base_url);
902 GST_LOG ("content of BaseURL node:");
903 new_base_url->baseURL = gst_mpdparser_get_xml_node_content (a_node);
904 GST_LOG ("attributes of BaseURL node:");
905 new_base_url->serviceLocation =
906 gst_mpdparser_get_xml_prop_string (a_node, "serviceLocation");
907 new_base_url->byteRange =
908 gst_mpdparser_get_xml_prop_string (a_node, "byteRange");
912 gst_mpdparser_parse_descriptor_type_node (GList ** list, xmlNode * a_node)
914 GstDescriptorType *new_descriptor;
916 new_descriptor = g_slice_new0 (GstDescriptorType);
917 if (new_descriptor == NULL) {
918 GST_WARNING ("Allocation of DescriptorType node failed!");
921 *list = g_list_append (*list, new_descriptor);
923 GST_LOG ("attributes of %s node:", a_node->name);
924 new_descriptor->schemeIdUri =
925 gst_mpdparser_get_xml_prop_string (a_node, "schemeIdUri");
926 new_descriptor->value = gst_mpdparser_get_xml_prop_string (a_node, "value");
928 /* For adding ContentProtection to caps , get string of <mspr:pro> */
929 if(xmlStrcmp (a_node->name,(xmlChar *) "ContentProtection") == 0) {
930 if (a_node->children->next){
931 if(xmlStrcmp (a_node->children->next->name,(xmlChar *) "pro") == 0){
932 if (a_node->children->next->type == XML_ELEMENT_NODE) {
933 new_descriptor->msprPro = gst_mpdparser_get_xml_node_content (a_node->children->next);
941 gst_mpdparser_parse_content_component_node (GList ** list, xmlNode * a_node)
944 GstContentComponentNode *new_content_component;
946 new_content_component = g_slice_new0 (GstContentComponentNode);
947 if (new_content_component == NULL) {
948 GST_WARNING ("Allocation of ContentComponent node failed!");
951 *list = g_list_append (*list, new_content_component);
953 GST_LOG ("attributes of ContentComponent node:");
954 new_content_component->id =
955 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "id", 0);
956 new_content_component->lang =
957 gst_mpdparser_get_xml_prop_string (a_node, "lang");
958 new_content_component->contentType =
959 gst_mpdparser_get_xml_prop_string (a_node, "contentType");
960 new_content_component->par = gst_mpdparser_get_xml_prop_ratio (a_node, "par");
962 /* explore children nodes */
963 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
964 if (cur_node->type == XML_ELEMENT_NODE) {
965 if (xmlStrcmp (cur_node->name, (xmlChar *) "Accessibility") == 0) {
966 gst_mpdparser_parse_descriptor_type_node (&new_content_component->
967 Accessibility, cur_node);
968 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Role") == 0) {
969 gst_mpdparser_parse_descriptor_type_node (&new_content_component->Role,
971 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Rating") == 0) {
972 gst_mpdparser_parse_descriptor_type_node (&new_content_component->
974 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Viewpoint") == 0) {
975 gst_mpdparser_parse_descriptor_type_node (&new_content_component->
976 Viewpoint, cur_node);
983 gst_mpdparser_parse_location_node (GList ** list, xmlNode * a_node)
987 GST_LOG ("content of Location node:");
988 location = gst_mpdparser_get_xml_node_content (a_node);
990 *list = g_list_append (*list, location);
994 gst_mpdparser_parse_subrepresentation_node (GList ** list, xmlNode * a_node)
996 GstSubRepresentationNode *new_subrep;
998 new_subrep = g_slice_new0 (GstSubRepresentationNode);
999 if (new_subrep == NULL) {
1000 GST_WARNING ("Allocation of SubRepresentation node failed!");
1003 *list = g_list_append (*list, new_subrep);
1005 GST_LOG ("attributes of SubRepresentation node:");
1007 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "level", 0);
1008 new_subrep->dependencyLevel =
1009 gst_mpdparser_get_xml_prop_uint_vector_type (a_node, "dependencyLevel",
1011 new_subrep->bandwidth =
1012 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0);
1013 new_subrep->contentComponent =
1014 gst_mpdparser_get_xml_prop_string_vector_type (a_node,
1015 "contentComponent");
1017 /* RepresentationBase extension */
1018 gst_mpdparser_parse_representation_base_type (&new_subrep->RepresentationBase,
1023 gst_mpdparser_parse_segment_url_node (GList ** list, xmlNode * a_node)
1025 GstSegmentURLNode *new_segment_url;
1027 new_segment_url = g_slice_new0 (GstSegmentURLNode);
1028 if (new_segment_url == NULL) {
1029 GST_WARNING ("Allocation of SegmentURL node failed!");
1032 *list = g_list_append (*list, new_segment_url);
1034 GST_LOG ("attributes of SegmentURL node:");
1035 new_segment_url->media = gst_mpdparser_get_xml_prop_string (a_node, "media");
1036 new_segment_url->mediaRange =
1037 gst_mpdparser_get_xml_prop_range (a_node, "mediaRange");
1038 new_segment_url->index = gst_mpdparser_get_xml_prop_string (a_node, "index");
1039 new_segment_url->indexRange =
1040 gst_mpdparser_get_xml_prop_range (a_node, "indexRange");
1044 gst_mpdparser_parse_url_type_node (GstURLType ** pointer, xmlNode * a_node)
1046 GstURLType *new_url_type;
1048 gst_mpdparser_free_url_type_node (*pointer);
1049 *pointer = new_url_type = g_slice_new0 (GstURLType);
1050 if (new_url_type == NULL) {
1051 GST_WARNING ("Allocation of URLType node failed!");
1055 GST_LOG ("attributes of URLType node:");
1056 new_url_type->sourceURL =
1057 gst_mpdparser_get_xml_prop_string (a_node, "sourceURL");
1058 new_url_type->range = gst_mpdparser_get_xml_prop_range (a_node, "range");
1062 gst_mpdparser_parse_seg_base_type_ext (GstSegmentBaseType ** pointer,
1066 GstSegmentBaseType *seg_base_type;
1068 gst_mpdparser_free_seg_base_type_ext (*pointer);
1069 *pointer = seg_base_type = g_slice_new0 (GstSegmentBaseType);
1070 if (seg_base_type == NULL) {
1071 GST_WARNING ("Allocation of SegmentBaseType node failed!");
1075 GST_LOG ("attributes of SegmentBaseType extension:");
1076 seg_base_type->timescale =
1077 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "timescale", 0);
1078 seg_base_type->presentationTimeOffset =
1079 gst_mpdparser_get_xml_prop_unsigned_integer (a_node,
1080 "presentationTimeOffset", 0);
1081 seg_base_type->indexRange =
1082 gst_mpdparser_get_xml_prop_string (a_node, "indexRange");
1083 seg_base_type->indexRangeExact =
1084 gst_mpdparser_get_xml_prop_boolean (a_node, "indexRangeExact");
1086 /* explore children nodes */
1087 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1088 if (cur_node->type == XML_ELEMENT_NODE) {
1089 if (xmlStrcmp (cur_node->name, (xmlChar *) "Initialization") == 0 ||
1090 xmlStrcmp (cur_node->name, (xmlChar *) "Initialisation") == 0) {
1091 gst_mpdparser_parse_url_type_node (&seg_base_type->Initialization,
1093 } else if (xmlStrcmp (cur_node->name,
1094 (xmlChar *) "RepresentationIndex") == 0) {
1095 gst_mpdparser_parse_url_type_node (&seg_base_type->RepresentationIndex,
1103 gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node)
1105 GstSNode *new_s_node;
1107 new_s_node = g_slice_new0 (GstSNode);
1108 if (new_s_node == NULL) {
1109 GST_WARNING ("Allocation of S node failed!");
1112 *list = g_list_append (*list, new_s_node);
1114 GST_LOG ("attributes of S node:");
1115 new_s_node->t = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "t", 0);
1116 new_s_node->d = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "d", 0);
1117 new_s_node->r = gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "r", 0);
1121 gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode ** pointer,
1125 GstSegmentTimelineNode *new_seg_timeline;
1127 gst_mpdparser_free_segment_timeline_node (*pointer);
1128 *pointer = new_seg_timeline = g_slice_new0 (GstSegmentTimelineNode);
1129 if (new_seg_timeline == NULL) {
1130 GST_WARNING ("Allocation of SegmentTimeline node failed!");
1134 /* explore children nodes */
1135 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1136 if (cur_node->type == XML_ELEMENT_NODE) {
1137 if (xmlStrcmp (cur_node->name, (xmlChar *) "S") == 0) {
1138 gst_mpdparser_parse_s_node (&new_seg_timeline->S, cur_node);
1145 gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType ** pointer,
1149 GstMultSegmentBaseType *mult_seg_base_type;
1151 gst_mpdparser_free_mult_seg_base_type_ext (*pointer);
1152 *pointer = mult_seg_base_type = g_slice_new0 (GstMultSegmentBaseType);
1153 if (mult_seg_base_type == NULL) {
1154 GST_WARNING ("Allocation of MultipleSegmentBaseType node failed!");
1158 GST_LOG ("attributes of MultipleSegmentBaseType extension:");
1159 mult_seg_base_type->duration =
1160 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "duration", 0);
1161 mult_seg_base_type->startNumber =
1162 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "startNumber", 1);
1164 GST_LOG ("extension of MultipleSegmentBaseType extension:");
1165 gst_mpdparser_parse_seg_base_type_ext (&mult_seg_base_type->SegBaseType,
1168 /* explore children nodes */
1169 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1170 if (cur_node->type == XML_ELEMENT_NODE) {
1171 if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTimeline") == 0) {
1172 gst_mpdparser_parse_segment_timeline_node (&mult_seg_base_type->
1173 SegmentTimeline, cur_node);
1174 } else if (xmlStrcmp (cur_node->name,
1175 (xmlChar *) "BitstreamSwitching") == 0) {
1176 gst_mpdparser_parse_url_type_node (&mult_seg_base_type->
1177 BitstreamSwitching, cur_node);
1184 gst_mpdparser_parse_segment_list_node (GstSegmentListNode ** pointer,
1188 GstSegmentListNode *new_segment_list;
1190 gst_mpdparser_free_segment_list_node (*pointer);
1191 *pointer = new_segment_list = g_slice_new0 (GstSegmentListNode);
1192 if (new_segment_list == NULL) {
1193 GST_WARNING ("Allocation of SegmentList node failed!");
1197 GST_LOG ("extension of SegmentList node:");
1198 gst_mpdparser_parse_mult_seg_base_type_ext (&new_segment_list->
1199 MultSegBaseType, a_node);
1201 /* explore children nodes */
1202 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1203 if (cur_node->type == XML_ELEMENT_NODE) {
1204 if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentURL") == 0) {
1205 gst_mpdparser_parse_segment_url_node (&new_segment_list->SegmentURL,
1213 gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType **
1214 pointer, xmlNode * a_node)
1217 GstRepresentationBaseType *representation_base;
1219 gst_mpdparser_free_representation_base_type (*pointer);
1220 *pointer = representation_base = g_slice_new0 (GstRepresentationBaseType);
1221 if (representation_base == NULL) {
1222 GST_WARNING ("Allocation of RepresentationBaseType node failed!");
1226 GST_LOG ("attributes of RepresentationBaseType extension:");
1227 representation_base->profiles =
1228 gst_mpdparser_get_xml_prop_string (a_node, "profiles");
1229 representation_base->width =
1230 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "width", 0);
1231 representation_base->height =
1232 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "height", 0);
1233 representation_base->bandwidth =
1234 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0);
1235 representation_base->sar = gst_mpdparser_get_xml_prop_ratio (a_node, "sar");
1236 representation_base->frameRate =
1237 gst_mpdparser_get_xml_prop_framerate (a_node, "frameRate");
1238 representation_base->audioSamplingRate =
1239 gst_mpdparser_get_xml_prop_string (a_node, "audioSamplingRate");
1240 representation_base->mimeType =
1241 gst_mpdparser_get_xml_prop_string (a_node, "mimeType");
1242 representation_base->segmentProfiles =
1243 gst_mpdparser_get_xml_prop_string (a_node, "segmentProfiles");
1244 representation_base->codecs =
1245 gst_mpdparser_get_xml_prop_string (a_node, "codecs");
1246 representation_base->maximumSAPPeriod =
1247 gst_mpdparser_get_xml_prop_double (a_node, "maximumSAPPeriod");
1248 representation_base->startWithSAP =
1249 gst_mpdparser_get_xml_prop_SAP_type (a_node, "startWithSAP");
1250 representation_base->maxPlayoutRate =
1251 gst_mpdparser_get_xml_prop_double (a_node, "maxPlayoutRate");
1252 representation_base->codingDependency =
1253 gst_mpdparser_get_xml_prop_boolean (a_node, "codingDependency");
1254 representation_base->scanType =
1255 gst_mpdparser_get_xml_prop_string (a_node, "scanType");
1257 /* explore children nodes */
1258 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1259 if (cur_node->type == XML_ELEMENT_NODE) {
1260 if (xmlStrcmp (cur_node->name, (xmlChar *) "FramePacking") == 0) {
1261 gst_mpdparser_parse_descriptor_type_node (&representation_base->
1262 FramePacking, cur_node);
1263 } else if (xmlStrcmp (cur_node->name,
1264 (xmlChar *) "AudioChannelConfiguration") == 0) {
1265 gst_mpdparser_parse_descriptor_type_node (&representation_base->
1266 AudioChannelConfiguration, cur_node);
1267 } else if (xmlStrcmp (cur_node->name,
1268 (xmlChar *) "ContentProtection") == 0) {
1269 gst_mpdparser_parse_descriptor_type_node (&representation_base->
1270 ContentProtection, cur_node);
1277 gst_mpdparser_parse_representation_node (GList ** list, xmlNode * a_node)
1280 GstRepresentationNode *new_representation;
1282 new_representation = g_slice_new0 (GstRepresentationNode);
1283 if (new_representation == NULL) {
1284 GST_WARNING ("Allocation of Representation node failed!");
1287 *list = g_list_append (*list, new_representation);
1289 GST_LOG ("attributes of Representation node:");
1290 new_representation->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1291 new_representation->bandwidth =
1292 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0);
1293 new_representation->qualityRanking =
1294 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "qualityRanking", 0);
1295 new_representation->dependencyId =
1296 gst_mpdparser_get_xml_prop_string_vector_type (a_node, "dependencyId");
1297 new_representation->mediaStreamStructureId =
1298 gst_mpdparser_get_xml_prop_string_vector_type (a_node,
1299 "mediaStreamStructureId");
1301 /* RepresentationBase extension */
1302 gst_mpdparser_parse_representation_base_type (&new_representation->
1303 RepresentationBase, a_node);
1305 /* explore children nodes */
1306 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1307 if (cur_node->type == XML_ELEMENT_NODE) {
1308 if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1309 gst_mpdparser_parse_seg_base_type_ext (&new_representation->SegmentBase,
1311 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1312 gst_mpdparser_parse_segment_template_node (&new_representation->
1313 SegmentTemplate, cur_node);
1314 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1315 gst_mpdparser_parse_segment_list_node (&new_representation->SegmentList,
1317 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1318 gst_mpdparser_parse_baseURL_node (&new_representation->BaseURLs,
1320 } else if (xmlStrcmp (cur_node->name,
1321 (xmlChar *) "SubRepresentation") == 0) {
1322 gst_mpdparser_parse_subrepresentation_node (&new_representation->
1323 SubRepresentations, cur_node);
1330 gst_mpdparser_parse_adaptation_set_node (GList ** list, xmlNode * a_node)
1333 GstAdaptationSetNode *new_adap_set;
1335 new_adap_set = g_slice_new0 (GstAdaptationSetNode);
1336 if (new_adap_set == NULL) {
1337 GST_WARNING ("Allocation of AdaptationSet node failed!");
1340 *list = g_list_append (*list, new_adap_set);
1342 GST_LOG ("attributes of AdaptationSet node:");
1344 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "id", 0);
1345 new_adap_set->group =
1346 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "group", 0);
1347 new_adap_set->lang = gst_mpdparser_get_xml_prop_string (a_node, "lang");
1348 new_adap_set->contentType =
1349 gst_mpdparser_get_xml_prop_string (a_node, "contentType");
1350 new_adap_set->par = gst_mpdparser_get_xml_prop_ratio (a_node, "par");
1351 new_adap_set->minBandwidth =
1352 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minBandwidth", 0);
1353 new_adap_set->maxBandwidth =
1354 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxBandwidth", 0);
1355 new_adap_set->minWidth =
1356 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minWidth", 0);
1357 new_adap_set->maxWidth =
1358 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxWidth", 0);
1359 new_adap_set->minHeight =
1360 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "minHeight", 0);
1361 new_adap_set->maxHeight =
1362 gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "maxHeight", 0);
1363 new_adap_set->minFrameRate =
1364 gst_mpdparser_get_xml_prop_framerate (a_node, "minFrameRate");
1365 new_adap_set->maxFrameRate =
1366 gst_mpdparser_get_xml_prop_framerate (a_node, "maxFrameRate");
1367 new_adap_set->segmentAlignment =
1368 gst_mpdparser_get_xml_prop_cond_uint (a_node, "segmentAlignment");
1369 new_adap_set->subsegmentAlignment =
1370 gst_mpdparser_get_xml_prop_cond_uint (a_node, "subsegmentAlignment");
1371 new_adap_set->subsegmentStartsWithSAP =
1372 gst_mpdparser_get_xml_prop_SAP_type (a_node, "subsegmentStartsWithSAP");
1373 new_adap_set->bitstreamSwitching =
1374 gst_mpdparser_get_xml_prop_boolean (a_node, "bitstreamSwitching");
1376 /* RepresentationBase extension */
1377 gst_mpdparser_parse_representation_base_type (&new_adap_set->
1378 RepresentationBase, a_node);
1380 /* explore children nodes */
1381 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1382 if (cur_node->type == XML_ELEMENT_NODE) {
1383 if (xmlStrcmp (cur_node->name, (xmlChar *) "Accessibility") == 0) {
1384 gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Accessibility,
1386 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Role") == 0) {
1387 gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Role,
1389 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Rating") == 0) {
1390 gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Rating,
1392 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Viewpoint") == 0) {
1393 gst_mpdparser_parse_descriptor_type_node (&new_adap_set->Viewpoint,
1395 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Representation") == 0) {
1396 gst_mpdparser_parse_representation_node (&new_adap_set->Representations,
1398 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1399 gst_mpdparser_parse_baseURL_node (&new_adap_set->BaseURLs, cur_node);
1400 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1401 gst_mpdparser_parse_seg_base_type_ext (&new_adap_set->SegmentBase,
1403 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1404 gst_mpdparser_parse_segment_list_node (&new_adap_set->SegmentList,
1406 } else if (xmlStrcmp (cur_node->name,
1407 (xmlChar *) "ContentComponent") == 0) {
1408 gst_mpdparser_parse_content_component_node (&new_adap_set->
1409 ContentComponents, cur_node);
1410 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1411 gst_mpdparser_parse_segment_template_node (&new_adap_set->
1412 SegmentTemplate, cur_node);
1419 gst_mpdparser_parse_subset_node (GList ** list, xmlNode * a_node)
1421 GstSubsetNode *new_subset;
1423 new_subset = g_slice_new0 (GstSubsetNode);
1424 if (new_subset == NULL) {
1425 GST_WARNING ("Allocation of Subset node failed!");
1428 *list = g_list_append (*list, new_subset);
1430 GST_LOG ("attributes of Subset node:");
1431 new_subset->contains =
1432 gst_mpdparser_get_xml_prop_uint_vector_type (a_node, "contains",
1437 gst_mpdparser_parse_segment_template_node (GstSegmentTemplateNode ** pointer,
1440 GstSegmentTemplateNode *new_segment_template;
1442 gst_mpdparser_free_segment_template_node (*pointer);
1443 *pointer = new_segment_template = g_slice_new0 (GstSegmentTemplateNode);
1444 if (new_segment_template == NULL) {
1445 GST_WARNING ("Allocation of SegmentTemplate node failed!");
1449 GST_LOG ("extension of SegmentTemplate node:");
1450 gst_mpdparser_parse_mult_seg_base_type_ext (&new_segment_template->
1451 MultSegBaseType, a_node);
1453 GST_LOG ("attributes of SegmentTemplate node:");
1454 new_segment_template->media =
1455 gst_mpdparser_get_xml_prop_string (a_node, "media");
1456 new_segment_template->index =
1457 gst_mpdparser_get_xml_prop_string (a_node, "index");
1458 new_segment_template->initialization =
1459 gst_mpdparser_get_xml_prop_string (a_node, "initialization");
1460 new_segment_template->bitstreamSwitching =
1461 gst_mpdparser_get_xml_prop_string (a_node, "bitstreamSwitching");
1465 gst_mpdparser_parse_period_node (GList ** list, xmlNode * a_node)
1468 GstPeriodNode *new_period;
1470 new_period = g_slice_new0 (GstPeriodNode);
1471 if (new_period == NULL) {
1472 GST_WARNING ("Allocation of Period node failed!");
1475 *list = g_list_append (*list, new_period);
1477 GST_LOG ("attributes of Period node:");
1478 new_period->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1479 new_period->start = gst_mpdparser_get_xml_prop_duration (a_node, "start");
1480 new_period->duration =
1481 gst_mpdparser_get_xml_prop_duration (a_node, "duration");
1482 new_period->bitstreamSwitching =
1483 gst_mpdparser_get_xml_prop_boolean (a_node, "bitstreamSwitching");
1485 /* explore children nodes */
1486 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1487 if (cur_node->type == XML_ELEMENT_NODE) {
1488 if (xmlStrcmp (cur_node->name, (xmlChar *) "AdaptationSet") == 0) {
1489 gst_mpdparser_parse_adaptation_set_node (&new_period->AdaptationSets,
1491 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
1492 gst_mpdparser_parse_seg_base_type_ext (&new_period->SegmentBase,
1494 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
1495 gst_mpdparser_parse_segment_list_node (&new_period->SegmentList,
1497 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
1498 gst_mpdparser_parse_segment_template_node (&new_period->SegmentTemplate,
1500 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Subset") == 0) {
1501 gst_mpdparser_parse_subset_node (&new_period->Subsets, cur_node);
1502 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1503 gst_mpdparser_parse_baseURL_node (&new_period->BaseURLs, cur_node);
1510 gst_mpdparser_parse_program_info_node (GList ** list, xmlNode * a_node)
1513 GstProgramInformationNode *new_prog_info;
1515 new_prog_info = g_slice_new0 (GstProgramInformationNode);
1516 if (new_prog_info == NULL) {
1517 GST_WARNING ("Allocation of ProgramInfo node failed!");
1520 *list = g_list_append (*list, new_prog_info);
1522 GST_LOG ("attributes of ProgramInformation node:");
1523 new_prog_info->lang = gst_mpdparser_get_xml_prop_string (a_node, "lang");
1524 new_prog_info->moreInformationURL =
1525 gst_mpdparser_get_xml_prop_string (a_node, "moreInformationURL");
1527 /* explore children nodes */
1528 GST_LOG ("children of ProgramInformation node:");
1529 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1530 if (cur_node->type == XML_ELEMENT_NODE) {
1531 if (xmlStrcmp (cur_node->name, (xmlChar *) "Title") == 0) {
1532 new_prog_info->Title = gst_mpdparser_get_xml_node_content (cur_node);
1533 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Source") == 0) {
1534 new_prog_info->Source = gst_mpdparser_get_xml_node_content (cur_node);
1535 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Copyright") == 0) {
1536 new_prog_info->Copyright =
1537 gst_mpdparser_get_xml_node_content (cur_node);
1544 gst_mpdparser_parse_metrics_range_node (GList ** list, xmlNode * a_node)
1546 GstMetricsRangeNode *new_metrics_range;
1548 new_metrics_range = g_slice_new0 (GstMetricsRangeNode);
1549 if (new_metrics_range == NULL) {
1550 GST_WARNING ("Allocation of Metrics Range node failed!");
1553 *list = g_list_append (*list, new_metrics_range);
1555 GST_LOG ("attributes of Metrics Range node:");
1556 new_metrics_range->starttime =
1557 gst_mpdparser_get_xml_prop_duration (a_node, "starttime");
1558 new_metrics_range->duration =
1559 gst_mpdparser_get_xml_prop_duration (a_node, "duration");
1563 gst_mpdparser_parse_metrics_node (GList ** list, xmlNode * a_node)
1566 GstMetricsNode *new_metrics;
1568 new_metrics = g_slice_new0 (GstMetricsNode);
1569 if (new_metrics == NULL) {
1570 GST_WARNING ("Allocation of Metrics node failed!");
1573 *list = g_list_append (*list, new_metrics);
1575 GST_LOG ("attributes of Metrics node:");
1576 new_metrics->metrics = gst_mpdparser_get_xml_prop_string (a_node, "metrics");
1578 /* explore children nodes */
1579 GST_LOG ("children of Metrics node:");
1580 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1581 if (cur_node->type == XML_ELEMENT_NODE) {
1582 if (xmlStrcmp (cur_node->name, (xmlChar *) "Range") == 0) {
1583 gst_mpdparser_parse_metrics_range_node (&new_metrics->MetricsRanges,
1585 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Reporting") == 0) {
1586 /* No reporting scheme is specified in this part of ISO/IEC 23009.
1587 * It is expected that external specifications may define formats
1588 * and delivery for the reporting data. */
1589 GST_LOG (" - Reporting node found (unknown structure)");
1596 gst_mpdparser_parse_root_node (GstMPDNode ** pointer, xmlNode * a_node)
1599 GstMPDNode *new_mpd;
1601 gst_mpdparser_free_mpd_node (*pointer);
1602 *pointer = new_mpd = g_slice_new0 (GstMPDNode);
1603 if (new_mpd == NULL) {
1604 GST_WARNING ("Allocation of MPD node failed!");
1608 GST_LOG ("namespaces of root MPD node:");
1609 new_mpd->default_namespace =
1610 gst_mpdparser_get_xml_node_namespace (a_node, NULL);
1611 new_mpd->namespace_xsi = gst_mpdparser_get_xml_node_namespace (a_node, "xsi");
1612 new_mpd->namespace_ext = gst_mpdparser_get_xml_node_namespace (a_node, "ext");
1614 GST_LOG ("attributes of root MPD node:");
1615 new_mpd->schemaLocation =
1616 gst_mpdparser_get_xml_prop_string (a_node, "schemaLocation");
1617 new_mpd->id = gst_mpdparser_get_xml_prop_string (a_node, "id");
1618 new_mpd->profiles = gst_mpdparser_get_xml_prop_string (a_node, "profiles");
1619 new_mpd->type = gst_mpdparser_get_xml_prop_type (a_node, "type");
1620 new_mpd->availabilityStartTime =
1621 gst_mpdparser_get_xml_prop_dateTime (a_node, "availabilityStartTime");
1622 new_mpd->availabilityEndTime =
1623 gst_mpdparser_get_xml_prop_dateTime (a_node, "availabilityEndTime");
1624 new_mpd->mediaPresentationDuration =
1625 gst_mpdparser_get_xml_prop_duration (a_node, "mediaPresentationDuration");
1626 new_mpd->minimumUpdatePeriod =
1627 gst_mpdparser_get_xml_prop_duration (a_node, "minimumUpdatePeriod");
1628 new_mpd->minBufferTime =
1629 gst_mpdparser_get_xml_prop_duration (a_node, "minBufferTime");
1630 new_mpd->timeShiftBufferDepth =
1631 gst_mpdparser_get_xml_prop_duration (a_node, "timeShiftBufferDepth");
1632 new_mpd->suggestedPresentationDelay =
1633 gst_mpdparser_get_xml_prop_duration (a_node,
1634 "suggestedPresentationDelay");
1635 new_mpd->maxSegmentDuration =
1636 gst_mpdparser_get_xml_prop_duration (a_node, "maxSegmentDuration");
1637 new_mpd->maxSubsegmentDuration =
1638 gst_mpdparser_get_xml_prop_duration (a_node, "maxSubsegmentDuration");
1640 /* explore children Period nodes */
1641 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
1642 if (cur_node->type == XML_ELEMENT_NODE) {
1643 if (xmlStrcmp (cur_node->name, (xmlChar *) "Period") == 0) {
1644 gst_mpdparser_parse_period_node (&new_mpd->Periods, cur_node);
1645 } else if (xmlStrcmp (cur_node->name,
1646 (xmlChar *) "ProgramInformation") == 0) {
1647 gst_mpdparser_parse_program_info_node (&new_mpd->ProgramInfo, cur_node);
1648 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "BaseURL") == 0) {
1649 gst_mpdparser_parse_baseURL_node (&new_mpd->BaseURLs, cur_node);
1650 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Location") == 0) {
1651 gst_mpdparser_parse_location_node (&new_mpd->Locations, cur_node);
1652 } else if (xmlStrcmp (cur_node->name, (xmlChar *) "Metrics") == 0) {
1653 gst_mpdparser_parse_metrics_node (&new_mpd->Metrics, cur_node);
1659 /* comparison functions */
1661 strncmp_ext (const char *s1, const char *s2)
1663 if (s1 == NULL && s2 == NULL)
1665 if (s1 == NULL && s2 != NULL)
1667 if (s2 == NULL && s1 != NULL)
1669 return strncmp (s1, s2, strlen (s2));
1672 /* navigation functions */
1673 static GstAdaptationSetNode *
1674 gst_mpdparser_get_first_adapt_set_with_mimeType (GList * AdaptationSets,
1675 const gchar * mimeType)
1678 GstAdaptationSetNode *adapt_set;
1680 if (AdaptationSets == NULL)
1683 for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1684 adapt_set = (GstAdaptationSetNode *) list->data;
1686 gchar *this_mimeType = NULL;
1687 GstRepresentationNode *rep;
1689 gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1691 GST_WARNING ("No valid representation in the MPD file, aborting...");
1694 if (rep->RepresentationBase)
1695 this_mimeType = rep->RepresentationBase->mimeType;
1696 if (!this_mimeType && adapt_set->RepresentationBase) {
1697 this_mimeType = adapt_set->RepresentationBase->mimeType;
1699 if (strncmp_ext (this_mimeType, mimeType) == 0)
1707 /* if idx < 0, returns the highest adaptation set with the given mimeType
1708 * if idx >= 0, returns the highest adaptation set with the given mimeType and an index <= idx
1710 static GstAdaptationSetNode *
1711 gst_mpdparser_get_adapt_set_with_mimeType_and_idx (GList * AdaptationSets,
1712 const gchar * mimeType, gint idx)
1715 GstAdaptationSetNode *adapt_set, *selected = NULL;
1718 if (AdaptationSets == NULL)
1721 for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1722 adapt_set = (GstAdaptationSetNode *) list->data;
1724 gchar *this_mimeType = NULL;
1725 GstRepresentationNode *rep;
1727 gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1729 GST_WARNING ("No valid representation in the MPD file, aborting...");
1732 if (rep->RepresentationBase)
1733 this_mimeType = rep->RepresentationBase->mimeType;
1734 if (!this_mimeType && adapt_set->RepresentationBase) {
1735 this_mimeType = adapt_set->RepresentationBase->mimeType;
1737 if (strncmp_ext (this_mimeType, mimeType) == 0) {
1738 if (idx < 0 || i <= idx)
1739 selected = adapt_set;
1748 static GstAdaptationSetNode *
1749 gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang (GList *
1750 AdaptationSets, const gchar * mimeType, const gchar * lang)
1753 GstAdaptationSetNode *adapt_set;
1755 if (AdaptationSets == NULL)
1758 for (list = g_list_first (AdaptationSets); list; list = g_list_next (list)) {
1759 adapt_set = (GstAdaptationSetNode *) list->data;
1761 GstRepresentationNode *rep;
1762 gchar *this_lang = adapt_set->lang;
1763 gchar *this_mimeType = NULL;
1765 gst_mpdparser_get_lowest_representation (adapt_set->Representations);
1767 GST_WARNING ("No valid representation in the MPD file, aborting...");
1770 if (rep->RepresentationBase)
1771 this_mimeType = rep->RepresentationBase->mimeType;
1772 if (!this_mimeType && adapt_set->RepresentationBase) {
1773 this_mimeType = adapt_set->RepresentationBase->mimeType;
1775 if (strncmp_ext (this_mimeType, mimeType) == 0
1776 && strncmp_ext (this_lang, lang) == 0)
1784 static GstRepresentationNode *
1785 gst_mpdparser_get_lowest_representation (GList * Representations)
1789 if (Representations == NULL)
1792 list = g_list_first (Representations);
1794 return list ? (GstRepresentationNode *) list->data : NULL;
1798 static GstRepresentationNode *
1799 gst_mpdparser_get_highest_representation (GList * Representations)
1803 if (Representations == NULL)
1806 list = g_list_last (Representations);
1808 return list ? (GstRepresentationNode *) list->data : NULL;
1811 static GstRepresentationNode *
1812 gst_mpdparser_get_representation_with_max_bandwidth (GList * Representations,
1816 GstRepresentationNode *representation, *best_rep = NULL;
1818 if (Representations == NULL)
1821 if (max_bandwidth <= 0) /* 0 => get highest representation available */
1822 return gst_mpdparser_get_highest_representation (Representations);
1824 for (list = g_list_first (Representations); list; list = g_list_next (list)) {
1825 representation = (GstRepresentationNode *) list->data;
1826 if (representation && representation->bandwidth <= max_bandwidth) {
1827 best_rep = representation;
1835 static GstSegmentBaseType *
1836 gst_mpdparser_get_segment_base (GstPeriodNode * Period,
1837 GstAdaptationSetNode * AdaptationSet,
1838 GstRepresentationNode * Representation)
1840 GstSegmentBaseType *SegmentBase = NULL;
1842 if (Representation && Representation->SegmentBase
1843 && Representation->SegmentBase->Initialization) {
1844 SegmentBase = Representation->SegmentBase;
1845 } else if (AdaptationSet && AdaptationSet->SegmentBase
1846 && AdaptationSet->SegmentBase->Initialization) {
1847 SegmentBase = AdaptationSet->SegmentBase;
1848 } else if (Period && Period->SegmentBase
1849 && Period->SegmentBase->Initialization) {
1850 SegmentBase = Period->SegmentBase;
1852 /* the SegmentBase element could be encoded also inside a SegmentList element */
1853 if (SegmentBase == NULL) {
1854 if (Representation && Representation->SegmentList
1855 && Representation->SegmentList->MultSegBaseType
1856 && Representation->SegmentList->MultSegBaseType->SegBaseType
1857 && Representation->SegmentList->MultSegBaseType->SegBaseType->
1859 SegmentBase = Representation->SegmentList->MultSegBaseType->SegBaseType;
1860 } else if (AdaptationSet && AdaptationSet->SegmentList
1861 && AdaptationSet->SegmentList->MultSegBaseType
1862 && AdaptationSet->SegmentList->MultSegBaseType->SegBaseType
1863 && AdaptationSet->SegmentList->MultSegBaseType->SegBaseType->
1865 SegmentBase = AdaptationSet->SegmentList->MultSegBaseType->SegBaseType;
1866 } else if (Period && Period->SegmentList
1867 && Period->SegmentList->MultSegBaseType
1868 && Period->SegmentList->MultSegBaseType->SegBaseType
1869 && Period->SegmentList->MultSegBaseType->SegBaseType->Initialization) {
1870 SegmentBase = Period->SegmentList->MultSegBaseType->SegBaseType;
1878 gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
1879 guint64 max_bandwidth)
1881 GList *list = NULL, *best = NULL;
1882 GstRepresentationNode *representation;
1883 guint64 best_bandwidth = 0;
1885 GST_DEBUG ("max bandwidth %" G_GUINT64_FORMAT, max_bandwidth);
1887 if (Representations == NULL)
1890 if (max_bandwidth <= 0) /* 0 => get lowest representation available */
1893 for (list = g_list_first (Representations); list; list = g_list_next (list)) {
1894 representation = (GstRepresentationNode *) list->data;
1895 if (representation && representation->bandwidth <= max_bandwidth &&
1896 representation->bandwidth > best_bandwidth) {
1898 best_bandwidth = representation->bandwidth;
1902 return best ? g_list_position (Representations, best) : -1;
1905 static GstSegmentListNode *
1906 gst_mpdparser_get_segment_list (GstPeriodNode * Period,
1907 GstAdaptationSetNode * AdaptationSet,
1908 GstRepresentationNode * Representation)
1910 GstSegmentListNode *SegmentList = NULL;
1912 if (Representation && Representation->SegmentList) {
1913 SegmentList = Representation->SegmentList;
1914 } else if (AdaptationSet && AdaptationSet->SegmentList) {
1915 SegmentList = AdaptationSet->SegmentList;
1917 SegmentList = Period->SegmentList;
1923 /* memory management functions */
1925 gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node)
1928 g_free (mpd_node->default_namespace);
1929 g_free (mpd_node->namespace_xsi);
1930 g_free (mpd_node->namespace_ext);
1931 g_free (mpd_node->schemaLocation);
1932 g_free (mpd_node->id);
1933 g_free (mpd_node->profiles);
1934 if (mpd_node->availabilityStartTime)
1935 gst_date_time_unref (mpd_node->availabilityStartTime);
1936 if (mpd_node->availabilityEndTime)
1937 gst_date_time_unref (mpd_node->availabilityEndTime);
1938 g_list_foreach (mpd_node->ProgramInfo,
1939 (GFunc) gst_mpdparser_free_prog_info_node, NULL);
1940 g_list_free (mpd_node->ProgramInfo);
1941 g_list_foreach (mpd_node->BaseURLs,
1942 (GFunc) gst_mpdparser_free_base_url_node, NULL);
1943 g_list_free (mpd_node->BaseURLs);
1944 g_list_foreach (mpd_node->Locations, (GFunc) g_free, NULL);
1945 g_list_free (mpd_node->Locations);
1946 g_list_foreach (mpd_node->Periods, (GFunc) gst_mpdparser_free_period_node,
1948 g_list_free (mpd_node->Periods);
1949 g_list_foreach (mpd_node->Metrics, (GFunc) gst_mpdparser_free_metrics_node,
1951 g_list_free (mpd_node->Metrics);
1952 g_slice_free (GstMPDNode, mpd_node);
1957 gst_mpdparser_free_prog_info_node (GstProgramInformationNode * prog_info_node)
1959 if (prog_info_node) {
1960 g_free (prog_info_node->lang);
1961 g_free (prog_info_node->moreInformationURL);
1962 g_free (prog_info_node->Title);
1963 g_free (prog_info_node->Source);
1964 g_free (prog_info_node->Copyright);
1965 g_slice_free (GstProgramInformationNode, prog_info_node);
1970 gst_mpdparser_free_metrics_node (GstMetricsNode * metrics_node)
1973 g_free (metrics_node->metrics);
1974 g_list_foreach (metrics_node->MetricsRanges,
1975 (GFunc) gst_mpdparser_free_metrics_range_node, NULL);
1976 g_list_free (metrics_node->MetricsRanges);
1981 gst_mpdparser_free_metrics_range_node (GstMetricsRangeNode * metrics_range_node)
1983 if (metrics_range_node) {
1984 g_slice_free (GstMetricsRangeNode, metrics_range_node);
1989 gst_mpdparser_free_period_node (GstPeriodNode * period_node)
1992 g_free (period_node->id);
1993 gst_mpdparser_free_seg_base_type_ext (period_node->SegmentBase);
1994 gst_mpdparser_free_segment_list_node (period_node->SegmentList);
1995 gst_mpdparser_free_segment_template_node (period_node->SegmentTemplate);
1996 g_list_foreach (period_node->AdaptationSets,
1997 (GFunc) gst_mpdparser_free_adaptation_set_node, NULL);
1998 g_list_free (period_node->AdaptationSets);
1999 g_list_foreach (period_node->Subsets,
2000 (GFunc) gst_mpdparser_free_subset_node, NULL);
2001 g_list_free (period_node->Subsets);
2002 g_list_foreach (period_node->BaseURLs,
2003 (GFunc) gst_mpdparser_free_base_url_node, NULL);
2004 g_list_free (period_node->BaseURLs);
2005 g_slice_free (GstPeriodNode, period_node);
2010 gst_mpdparser_free_subset_node (GstSubsetNode * subset_node)
2013 g_free (subset_node->contains);
2014 g_slice_free (GstSubsetNode, subset_node);
2019 gst_mpdparser_free_segment_template_node (GstSegmentTemplateNode *
2020 segment_template_node)
2022 if (segment_template_node) {
2023 g_free (segment_template_node->media);
2024 g_free (segment_template_node->index);
2025 g_free (segment_template_node->initialization);
2026 g_free (segment_template_node->bitstreamSwitching);
2027 /* MultipleSegmentBaseType extension */
2028 gst_mpdparser_free_mult_seg_base_type_ext
2029 (segment_template_node->MultSegBaseType);
2030 g_slice_free (GstSegmentTemplateNode, segment_template_node);
2035 gst_mpdparser_free_representation_base_type (GstRepresentationBaseType *
2036 representation_base)
2038 if (representation_base) {
2039 g_free (representation_base->profiles);
2040 g_slice_free (GstRatio, representation_base->sar);
2041 g_slice_free (GstFrameRate, representation_base->frameRate);
2042 g_free (representation_base->audioSamplingRate);
2043 g_free (representation_base->mimeType);
2044 g_free (representation_base->segmentProfiles);
2045 g_free (representation_base->codecs);
2046 g_free (representation_base->scanType);
2047 g_list_foreach (representation_base->FramePacking,
2048 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2049 g_list_free (representation_base->FramePacking);
2050 g_list_foreach (representation_base->AudioChannelConfiguration,
2051 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2052 g_list_free (representation_base->AudioChannelConfiguration);
2053 g_list_foreach (representation_base->ContentProtection,
2054 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2055 g_list_free (representation_base->ContentProtection);
2056 g_slice_free (GstRepresentationBaseType, representation_base);
2061 gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode *
2062 adaptation_set_node)
2064 if (adaptation_set_node) {
2065 g_free (adaptation_set_node->lang);
2066 g_free (adaptation_set_node->contentType);
2067 g_slice_free (GstRatio, adaptation_set_node->par);
2068 g_slice_free (GstFrameRate, adaptation_set_node->minFrameRate);
2069 g_slice_free (GstFrameRate, adaptation_set_node->maxFrameRate);
2070 g_slice_free (GstConditionalUintType,
2071 adaptation_set_node->segmentAlignment);
2072 g_slice_free (GstConditionalUintType,
2073 adaptation_set_node->subsegmentAlignment);
2074 g_list_foreach (adaptation_set_node->Accessibility,
2075 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2076 g_list_free (adaptation_set_node->Accessibility);
2077 g_list_foreach (adaptation_set_node->Role,
2078 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2079 g_list_free (adaptation_set_node->Role);
2080 g_list_foreach (adaptation_set_node->Rating,
2081 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2082 g_list_free (adaptation_set_node->Rating);
2083 g_list_foreach (adaptation_set_node->Viewpoint,
2084 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2085 g_list_free (adaptation_set_node->Viewpoint);
2086 gst_mpdparser_free_representation_base_type
2087 (adaptation_set_node->RepresentationBase);
2088 gst_mpdparser_free_seg_base_type_ext (adaptation_set_node->SegmentBase);
2089 gst_mpdparser_free_segment_list_node (adaptation_set_node->SegmentList);
2090 gst_mpdparser_free_segment_template_node (adaptation_set_node->
2092 g_list_foreach (adaptation_set_node->BaseURLs,
2093 (GFunc) gst_mpdparser_free_base_url_node, NULL);
2094 g_list_free (adaptation_set_node->BaseURLs);
2095 g_list_foreach (adaptation_set_node->Representations,
2096 (GFunc) gst_mpdparser_free_representation_node, NULL);
2097 g_list_free (adaptation_set_node->Representations);
2098 g_list_foreach (adaptation_set_node->ContentComponents,
2099 (GFunc) gst_mpdparser_free_content_component_node, NULL);
2100 g_list_free (adaptation_set_node->ContentComponents);
2101 g_slice_free (GstAdaptationSetNode, adaptation_set_node);
2106 gst_mpdparser_free_representation_node (GstRepresentationNode *
2107 representation_node)
2109 if (representation_node) {
2110 g_free (representation_node->id);
2111 g_strfreev (representation_node->dependencyId);
2112 g_strfreev (representation_node->mediaStreamStructureId);
2113 gst_mpdparser_free_representation_base_type
2114 (representation_node->RepresentationBase);
2115 g_list_foreach (representation_node->SubRepresentations,
2116 (GFunc) gst_mpdparser_free_subrepresentation_node, NULL);
2117 g_list_free (representation_node->SubRepresentations);
2118 gst_mpdparser_free_seg_base_type_ext (representation_node->SegmentBase);
2119 gst_mpdparser_free_segment_template_node (representation_node->
2121 gst_mpdparser_free_segment_list_node (representation_node->SegmentList);
2122 g_list_foreach (representation_node->BaseURLs,
2123 (GFunc) gst_mpdparser_free_base_url_node, NULL);
2124 g_list_free (representation_node->BaseURLs);
2125 g_slice_free (GstRepresentationNode, representation_node);
2130 gst_mpdparser_free_subrepresentation_node (GstSubRepresentationNode *
2134 gst_mpdparser_free_representation_base_type (subrep_node->
2135 RepresentationBase);
2136 g_free (subrep_node->dependencyLevel);
2137 g_strfreev (subrep_node->contentComponent);
2142 gst_mpdparser_free_s_node (GstSNode * s_node)
2145 g_slice_free (GstSNode, s_node);
2150 gst_mpdparser_free_segment_timeline_node (GstSegmentTimelineNode * seg_timeline)
2153 g_list_foreach (seg_timeline->S, (GFunc) gst_mpdparser_free_s_node, NULL);
2154 g_list_free (seg_timeline->S);
2155 g_slice_free (GstSegmentTimelineNode, seg_timeline);
2160 gst_mpdparser_free_url_type_node (GstURLType * url_type_node)
2162 if (url_type_node) {
2163 g_free (url_type_node->sourceURL);
2164 g_slice_free (GstRange, url_type_node->range);
2165 g_slice_free (GstURLType, url_type_node);
2170 gst_mpdparser_free_seg_base_type_ext (GstSegmentBaseType * seg_base_type)
2172 if (seg_base_type) {
2173 g_free (seg_base_type->indexRange);
2174 gst_mpdparser_free_url_type_node (seg_base_type->Initialization);
2175 gst_mpdparser_free_url_type_node (seg_base_type->RepresentationIndex);
2176 g_slice_free (GstSegmentBaseType, seg_base_type);
2181 gst_mpdparser_free_mult_seg_base_type_ext (GstMultSegmentBaseType *
2184 if (mult_seg_base_type) {
2185 /* SegmentBaseType extension */
2186 gst_mpdparser_free_seg_base_type_ext (mult_seg_base_type->SegBaseType);
2187 gst_mpdparser_free_segment_timeline_node
2188 (mult_seg_base_type->SegmentTimeline);
2189 gst_mpdparser_free_url_type_node (mult_seg_base_type->BitstreamSwitching);
2190 g_slice_free (GstMultSegmentBaseType, mult_seg_base_type);
2195 gst_mpdparser_free_segment_list_node (GstSegmentListNode * segment_list_node)
2197 if (segment_list_node) {
2198 g_list_foreach (segment_list_node->SegmentURL,
2199 (GFunc) gst_mpdparser_free_segment_url_node, NULL);
2200 g_list_free (segment_list_node->SegmentURL);
2201 /* MultipleSegmentBaseType extension */
2202 gst_mpdparser_free_mult_seg_base_type_ext
2203 (segment_list_node->MultSegBaseType);
2204 g_slice_free (GstSegmentListNode, segment_list_node);
2209 gst_mpdparser_free_segment_url_node (GstSegmentURLNode * segment_url)
2212 g_free (segment_url->media);
2213 g_slice_free (GstRange, segment_url->mediaRange);
2214 g_free (segment_url->index);
2215 g_slice_free (GstRange, segment_url->indexRange);
2216 g_slice_free (GstSegmentURLNode, segment_url);
2221 gst_mpdparser_free_base_url_node (GstBaseURL * base_url_node)
2223 if (base_url_node) {
2224 g_free (base_url_node->baseURL);
2225 g_free (base_url_node->serviceLocation);
2226 g_free (base_url_node->byteRange);
2227 g_slice_free (GstBaseURL, base_url_node);
2232 gst_mpdparser_free_descriptor_type_node (GstDescriptorType * descriptor_type)
2234 if (descriptor_type) {
2235 g_free (descriptor_type->schemeIdUri);
2236 g_free (descriptor_type->value);
2241 gst_mpdparser_free_content_component_node (GstContentComponentNode *
2242 content_component_node)
2244 if (content_component_node) {
2245 g_free (content_component_node->lang);
2246 g_free (content_component_node->contentType);
2247 g_slice_free (GstRatio, content_component_node->par);
2248 g_list_foreach (content_component_node->Accessibility,
2249 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2250 g_list_free (content_component_node->Accessibility);
2251 g_list_foreach (content_component_node->Role,
2252 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2253 g_list_free (content_component_node->Role);
2254 g_list_foreach (content_component_node->Rating,
2255 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2256 g_list_free (content_component_node->Rating);
2257 g_list_foreach (content_component_node->Viewpoint,
2258 (GFunc) gst_mpdparser_free_descriptor_type_node, NULL);
2259 g_list_free (content_component_node->Viewpoint);
2260 g_slice_free (GstContentComponentNode, content_component_node);
2265 gst_mpdparser_free_stream_period (GstStreamPeriod * stream_period)
2267 if (stream_period) {
2268 g_slice_free (GstStreamPeriod, stream_period);
2273 gst_mpdparser_free_media_segment (GstMediaSegment * media_segment)
2275 if (media_segment) {
2276 g_slice_free (GstMediaSegment, media_segment);
2281 gst_mpdparser_free_active_stream (GstActiveStream * active_stream)
2283 if (active_stream) {
2284 g_list_foreach (active_stream->segments,
2285 (GFunc) gst_mpdparser_free_media_segment, NULL);
2286 if (active_stream->segments)
2287 g_list_free (active_stream->segments);
2288 g_slice_free (GstActiveStream, active_stream);
2293 gst_mpdparser_get_segmentURL_for_range (const gchar * url, GstRange * range)
2298 gchar *range_suffix;
2300 g_strdup_printf ("?range=%llu-%llu", range->first_byte_pos,
2301 range->last_byte_pos);
2302 segmentURL = g_strconcat (url, range_suffix, NULL);
2303 g_free (range_suffix);
2305 segmentURL = g_strdup (url);
2312 gst_mpdparser_get_mediaURL (GstMpdClient * client,
2313 GstSegmentURLNode * segmentURL)
2315 const gchar *url_prefix;
2317 g_return_val_if_fail (client != NULL, NULL);
2318 g_return_val_if_fail (segmentURL != NULL, NULL);
2321 segmentURL->media ? segmentURL->
2322 media : gst_mpdparser_get_baseURL (client);
2323 g_return_val_if_fail (url_prefix != NULL, NULL);
2325 return gst_mpdparser_get_segmentURL_for_range (url_prefix,
2326 segmentURL->mediaRange);//if not present @media attribute, it is mapped to baseURL
2330 gst_mpdparser_get_initializationURL (GstURLType * InitializationURL)
2332 g_return_val_if_fail (InitializationURL != NULL, NULL);
2333 g_return_val_if_fail (InitializationURL->sourceURL != NULL, NULL);
2335 return gst_mpdparser_get_segmentURL_for_range (InitializationURL->sourceURL,
2336 InitializationURL->range);
2340 gst_mpdparser_build_URL_from_template (const gchar * url_template,
2341 const gchar * id, guint number, guint bandwidth, guint time)
2343 static gchar default_format[] = "%01d";
2344 gchar **tokens, *token, *ret, *format;
2346 gboolean last_token_par = TRUE; /* last token was a parameter */
2348 g_return_val_if_fail (url_template != NULL, NULL);
2349 tokens = g_strsplit_set (url_template, "$", -1);
2351 GST_WARNING ("Scan of URL template failed!");
2354 num_tokens = g_strv_length (tokens);
2356 for (i = 0; i < num_tokens; i++) {
2358 format = default_format;
2360 if (!g_strcmp0 (token, "RepresentationID")) {
2361 tokens[i] = g_strdup_printf ("%s", id);
2363 last_token_par = TRUE;
2364 } else if (!strncmp (token, "Number", 6)) {
2365 if (strlen (token) > 6) {
2366 format = token + 6; /* format tag */
2368 tokens[i] = g_strdup_printf (format, number);
2370 last_token_par = TRUE;
2371 } else if (!strncmp (token, "Bandwidth", 9)) {
2372 if (strlen (token) > 9) {
2373 format = token + 9; /* format tag */
2375 tokens[i] = g_strdup_printf (format, bandwidth);
2377 last_token_par = TRUE;
2378 } else if (!strncmp (token, "Time", 4)) {
2379 if (strlen (token) > 4) {
2380 format = token + 4; /* format tag */
2382 tokens[i] = g_strdup_printf (format, time);
2384 last_token_par = TRUE;
2385 } else if (!g_strcmp0 (token, "")) {
2386 if (!last_token_par) {
2387 tokens[i] = g_strdup_printf ("%s", "$");
2389 last_token_par = TRUE;
2392 last_token_par = FALSE;
2396 ret = g_strjoinv (NULL, tokens);
2397 g_strfreev (tokens);
2402 static GstStreamPeriod *
2403 gst_mpdparser_get_stream_period (GstMpdClient * client)
2405 g_return_val_if_fail (client != NULL, NULL);
2406 g_return_val_if_fail (client->periods != NULL, NULL);
2408 return g_list_nth_data (client->periods, client->period_idx);
2411 /* select a stream and extract the baseURL (if present) */
2413 gst_mpdparser_parse_baseURL (GstMpdClient * client)
2415 GstActiveStream *stream;
2416 GstStreamPeriod *stream_period;
2417 GstBaseURL *baseURL;
2419 static gchar *baseURL_array[5];
2420 static gchar empty[] = "";
2424 gst_mpdparser_get_active_stream_by_index (client, client->stream_idx);
2425 g_return_val_if_fail (stream != NULL, empty);
2426 stream_period = gst_mpdparser_get_stream_period (client);
2427 g_return_val_if_fail (stream_period != NULL, empty);
2428 g_return_val_if_fail (stream_period->period != NULL, empty);
2430 baseURL_array[0] = baseURL_array[1] = baseURL_array[2] = baseURL_array[3] =
2432 baseURL_array[4] = NULL;
2434 /* FIXME: this simple implementation is not fully compliant with RFC 3986 */
2435 if ((list = client->mpd_node->BaseURLs) != NULL) {
2436 baseURL = g_list_nth_data (list, stream->mpd_baseURL_idx);
2438 baseURL = list->data;
2440 baseURL_array[0] = baseURL->baseURL;
2442 if ((list = stream_period->period->BaseURLs) != NULL) {
2443 baseURL = g_list_nth_data (list, stream->period_baseURL_idx);
2445 baseURL = list->data;
2447 baseURL_array[1] = baseURL->baseURL;
2449 if ((list = stream->cur_adapt_set->BaseURLs) != NULL) {
2450 baseURL = g_list_nth_data (list, stream->adaptset_baseURL_idx);
2452 baseURL = list->data;
2454 baseURL_array[2] = baseURL->baseURL;
2456 if ((list = stream->cur_representation->BaseURLs) != NULL) {
2457 baseURL = g_list_nth_data (list, stream->repr_baseURL_idx);
2459 baseURL = list->data;
2461 baseURL_array[3] = baseURL->baseURL;
2464 ret = g_strjoinv (NULL, baseURL_array);
2465 /* get base URI from MPD file URI, if the "http" scheme is missing */
2466 if (client->mpd_uri != NULL && strncmp (ret, "http://", 7) != 0) {
2467 gchar *last_sep, *tmp1, *tmp2;
2468 last_sep = strrchr (client->mpd_uri, '/');
2470 tmp1 = g_strndup (client->mpd_uri, last_sep - client->mpd_uri + 1);
2472 GST_DEBUG ("Got base URI from MPD file URI %s", tmp1);
2473 ret = g_strconcat (tmp1, tmp2, NULL);
2483 gst_mpd_client_get_segment_duration (GstMpdClient * client, GstActiveStream *stream)
2485 GstStreamPeriod *stream_period;
2486 GstMultSegmentBaseType *base = NULL;
2487 GstClockTime duration;
2490 g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
2491 stream_period = gst_mpdparser_get_stream_period (client);
2492 g_return_val_if_fail (stream_period != NULL, GST_CLOCK_TIME_NONE);
2494 if (stream->cur_segment_list) {
2495 base = stream->cur_segment_list->MultSegBaseType;
2496 } else if (stream->cur_seg_template) {
2497 base = stream->cur_seg_template->MultSegBaseType;
2500 if (base == NULL || base->SegBaseType == NULL) {
2501 /* this may happen when we have a single segment */
2502 duration = stream_period->duration;
2504 duration = base->duration * GST_SECOND;
2505 timescale = base->SegBaseType->timescale;
2508 duration /= timescale;
2514 /*****************************/
2515 /******* API functions *******/
2516 /*****************************/
2519 gst_mpd_client_new ()
2521 GstMpdClient *client;
2523 client = g_new0 (GstMpdClient, 1);
2524 client->lock = g_mutex_new ();
2526 client->download_failed_count = 0;
2532 gst_active_streams_free (GstMpdClient * client)
2534 if (client->active_streams) {
2535 g_list_foreach (client->active_streams,
2536 (GFunc) gst_mpdparser_free_active_stream, NULL);
2537 g_list_free (client->active_streams);
2538 client->active_streams = NULL;
2543 gst_mpd_client_free (GstMpdClient * client)
2545 g_return_if_fail (client != NULL);
2547 if (client->mpd_node)
2548 gst_mpdparser_free_mpd_node (client->mpd_node);
2550 if (client->periods) {
2551 g_list_foreach (client->periods,
2552 (GFunc) gst_mpdparser_free_stream_period, NULL);
2553 g_list_free (client->periods);
2556 gst_active_streams_free (client);
2559 g_mutex_free (client->lock);
2561 g_free (client->mpd_uri);
2567 gst_mpd_parse (GstMpdClient * client, const gchar * data, gint size)
2571 xmlNode *root_element = NULL;
2573 GST_DEBUG ("MPD file fully buffered, start parsing...");
2575 GST_MPD_CLIENT_LOCK (client);
2576 /* parse the complete MPD file into a tree (using the libxml2 default parser API) */
2578 /* this initialize the library and check potential ABI mismatches
2579 * between the version it was compiled for and the actual shared
2583 /* parse "data" into a document (which is a libxml2 tree structure xmlDoc) */
2584 doc = xmlReadMemory (data, size, "noname.xml", NULL, 0);
2586 GST_ERROR ("failed to parse the MPD file");
2587 GST_MPD_CLIENT_UNLOCK (client);
2590 /* get the root element node */
2591 root_element = xmlDocGetRootElement (doc);
2593 if (root_element->type != XML_ELEMENT_NODE
2594 || xmlStrcmp (root_element->name, (xmlChar *) "MPD") != 0) {
2596 ("can not find the root element MPD, failed to parse the MPD file");
2598 /* now we can parse the MPD root node and all children nodes, recursively */
2599 gst_mpdparser_parse_root_node (&client->mpd_node, root_element);
2601 /* free the document */
2603 /* dump XML library memory for debugging */
2606 GST_MPD_CLIENT_UNLOCK (client);
2615 gst_mpdparser_get_baseURL (GstMpdClient * client)
2617 GstActiveStream *stream;
2619 g_return_val_if_fail (client != NULL, NULL);
2620 g_return_val_if_fail (client->active_streams != NULL, NULL);
2621 stream = g_list_nth_data (client->active_streams, client->stream_idx);
2622 g_return_val_if_fail (stream != NULL, NULL);
2624 return stream->baseURL;
2628 gst_mpdparser_get_chunk_by_index (GstMpdClient * client, guint indexStream,
2629 guint indexChunk, GstMediaSegment *segment)
2631 GstActiveStream *stream;
2634 g_return_val_if_fail (client != NULL, FALSE);
2635 g_return_val_if_fail (segment != NULL, FALSE);
2636 g_return_val_if_fail (client->active_streams != NULL, FALSE);
2637 stream = g_list_nth_data (client->active_streams, indexStream);
2638 g_return_val_if_fail (stream != NULL, FALSE);
2640 if(stream->segments) {
2641 GstMediaSegment *list_segment;
2642 if ( indexChunk >= g_list_length (stream->segments))
2644 list_segment = g_list_nth_data (stream->segments, indexChunk);
2645 memcpy (segment, list_segment, sizeof (GstMediaSegment));
2647 GstClockTime duration;
2648 GstStreamPeriod *stream_period;
2649 GstClockTime start_time;
2650 stream_period = gst_mpdparser_get_stream_period (client);
2651 g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->SegmentTimeline == NULL, FALSE);
2652 g_return_val_if_fail (stream_period != NULL, FALSE);
2653 g_return_val_if_fail (stream_period->period != NULL, FALSE);
2655 duration = gst_mpd_client_get_segment_duration (client, stream);
2656 if (!GST_CLOCK_TIME_IS_VALID (duration))
2659 start_time = duration * indexChunk;
2660 if (GST_CLOCK_TIME_IS_VALID (stream_period->start) && GST_CLOCK_TIME_IS_VALID (stream_period->duration)
2661 && start_time >= stream_period->start + stream_period->duration)
2664 segment->number = indexChunk + stream->cur_seg_template->MultSegBaseType->startNumber;
2665 segment->start_time = start_time;
2666 segment->duration = duration;
2667 segment->SegmentURL = NULL;
2674 gst_mpd_client_add_media_segment (GstActiveStream * stream,
2675 GstSegmentURLNode * url_node, guint number, guint start,
2676 GstClockTime start_time, GstClockTime duration)
2678 GstMediaSegment *media_segment;
2680 media_segment = g_slice_new0 (GstMediaSegment);
2681 if (media_segment == NULL) {
2682 GST_WARNING ("Allocation of GstMediaSegment struct failed!");
2685 stream->segments = g_list_append (stream->segments, media_segment);
2686 media_segment->SegmentURL = url_node;
2687 media_segment->number = number;
2688 media_segment->start = start;
2689 media_segment->start_time = start_time;
2690 media_segment->duration = duration;
2696 gst_mpd_client_setup_representation (GstMpdClient * client,
2697 GstActiveStream * stream, GstRepresentationNode * representation)
2699 GstStreamPeriod *stream_period;
2701 GstClockTime PeriodStart, PeriodEnd, start_time, duration;
2702 GstMediaSegment *last_media_segment;
2705 if (stream->cur_adapt_set == NULL) {
2706 GST_WARNING ("No valid AdaptationSet node in the MPD file, aborting...");
2710 rep_list = stream->cur_adapt_set->Representations;
2711 stream->cur_representation = representation;
2712 stream->representation_idx = g_list_index (rep_list, representation);
2714 /* clean the old segment list, if any */
2715 if (stream->segments) {
2716 g_list_foreach (stream->segments,
2717 (GFunc) gst_mpdparser_free_media_segment, NULL);
2718 g_list_free (stream->segments);
2719 stream->segments = NULL;
2722 stream_period = gst_mpdparser_get_stream_period (client);
2723 g_return_val_if_fail (stream_period != NULL, FALSE);
2724 g_return_val_if_fail (stream_period->period != NULL, FALSE);
2726 PeriodStart = stream_period->start;
2727 if (GST_CLOCK_TIME_IS_VALID (stream_period->duration))
2728 PeriodEnd = stream_period->start + stream_period->duration;
2730 PeriodEnd = GST_CLOCK_TIME_NONE;
2732 GST_LOG ("Building segment list for Period from %" GST_TIME_FORMAT " to %"
2733 GST_TIME_FORMAT, GST_TIME_ARGS (PeriodStart), GST_TIME_ARGS (PeriodEnd));
2735 if (representation->SegmentBase != NULL
2736 || representation->SegmentList != NULL) {
2739 /* get the first segment_base of the selected representation */
2740 if ((stream->cur_segment_base =
2741 gst_mpdparser_get_segment_base (stream_period->period,
2742 stream->cur_adapt_set, representation)) == NULL) {
2743 GST_DEBUG ("No useful SegmentBase node for the current Representation");
2746 /* get the first segment_list of the selected representation */
2747 if ((stream->cur_segment_list =
2748 gst_mpdparser_get_segment_list (stream_period->period,
2749 stream->cur_adapt_set, representation)) == NULL) {
2750 GST_DEBUG ("No useful SegmentList node for the current Representation");
2751 /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
2752 if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, PeriodStart,
2757 /* build the list of GstMediaSegment nodes from the SegmentList node */
2758 SegmentURL = stream->cur_segment_list->SegmentURL;
2759 if (SegmentURL == NULL) {
2761 ("No valid list of SegmentURL nodes in the MPD file, aborting...");
2765 /* build segment list */
2766 i = stream->cur_segment_list->MultSegBaseType->startNumber;
2768 start_time = PeriodStart;
2770 GST_LOG ("Building media segment list using a SegmentList node");
2771 if (stream->cur_segment_list->MultSegBaseType->SegmentTimeline) {
2772 GstSegmentTimelineNode *timeline;
2776 timeline = stream->cur_segment_list->MultSegBaseType->SegmentTimeline;
2777 for (list = g_list_first (timeline->S); list; list = g_list_next (list)) {
2780 S = (GstSNode *) list->data;
2781 GST_LOG ("Processing S node: d=%d r=%d t=%d", S->d, S->r, S->t);
2782 duration = S->d * GST_SECOND;
2784 stream->cur_segment_list->MultSegBaseType->SegBaseType->timescale;
2786 duration /= timescale;
2789 start_time = S->t * GST_SECOND;
2791 start_time /= timescale;
2794 for (j = 0; j <= S->r && SegmentURL != NULL; j++) {
2795 if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i,
2796 start, start_time, duration)) {
2801 start_time += duration;
2802 SegmentURL = g_list_next (SegmentURL);
2806 duration =gst_mpd_client_get_segment_duration (client, stream);
2807 if (!GST_CLOCK_TIME_IS_VALID (duration))
2810 while (SegmentURL) {
2811 if (!gst_mpd_client_add_media_segment (stream, SegmentURL->data, i, 0,
2812 start_time, duration)) {
2816 start_time += duration;
2817 SegmentURL = g_list_next (SegmentURL);
2822 if (representation->SegmentTemplate != NULL) {
2823 stream->cur_seg_template = representation->SegmentTemplate;
2824 } else if (stream->cur_adapt_set->SegmentTemplate != NULL) {
2825 stream->cur_seg_template = stream->cur_adapt_set->SegmentTemplate;
2826 } else if (stream_period->period->SegmentTemplate != NULL) {
2827 stream->cur_seg_template = stream_period->period->SegmentTemplate;
2830 if (stream->cur_seg_template == NULL
2831 || stream->cur_seg_template->MultSegBaseType == NULL) {
2832 /* here we should have a single segment for each representation, whose URL is encoded in the baseURL element */
2833 if (!gst_mpd_client_add_media_segment (stream, NULL, 1, 0, 0, PeriodEnd)) {
2837 /* build segment list */
2838 i = stream->cur_seg_template->MultSegBaseType->startNumber;
2840 start_time = PeriodStart;
2842 GST_LOG ("Building media segment list using this template: %s",
2843 stream->cur_seg_template->media);
2844 if (stream->cur_seg_template->MultSegBaseType->SegmentTimeline) {
2845 GstSegmentTimelineNode *timeline;
2849 timeline = stream->cur_seg_template->MultSegBaseType->SegmentTimeline;
2850 for (list = g_list_first (timeline->S); list; list = g_list_next (list)) {
2853 S = (GstSNode *) list->data;
2854 GST_LOG ("Processing S node: d=%d r=%d t=%d", S->d, S->r, S->t);
2855 duration = S->d * GST_SECOND;
2857 stream->cur_seg_template->MultSegBaseType->SegBaseType->timescale;
2859 duration /= timescale;
2862 start_time = S->t * GST_SECOND;
2864 start_time /= timescale;
2867 for (j = 0; j <= S->r; j++) {
2868 if (!gst_mpd_client_add_media_segment (stream, NULL, i, start,
2869 start_time, duration)) {
2874 start_time += duration;
2878 /*The segment is created on demand with the template, no need to build a list */
2883 /* check duration of last segment */
2884 if(stream->segments)
2885 last_media_segment = g_list_last (stream->segments)->data;
2887 last_media_segment = NULL;
2888 if (last_media_segment && GST_CLOCK_TIME_IS_VALID (PeriodEnd)) {
2889 if (last_media_segment->start_time + last_media_segment->duration >
2891 last_media_segment->duration = PeriodEnd - last_media_segment->start_time;
2892 GST_LOG ("Fixed duration of last segment: %" GST_TIME_FORMAT,
2893 GST_TIME_ARGS (last_media_segment->duration));
2895 GST_LOG ("Built a list of %d segments", last_media_segment->number);
2898 g_free (stream->baseURL);
2899 stream->baseURL = gst_mpdparser_parse_baseURL (client);
2905 gst_mpd_client_setup_media_presentation (GstMpdClient * client)
2907 GstStreamPeriod *stream_period;
2908 GstPeriodNode *period_node;
2909 GstClockTime start, duration;
2912 gboolean ret = FALSE;
2914 g_return_val_if_fail (client != NULL, FALSE);
2915 g_return_val_if_fail (client->mpd_node != NULL, FALSE);
2917 GST_DEBUG ("Building the list of Periods in the Media Presentation");
2918 GST_MPD_CLIENT_LOCK (client);
2919 /* clean the old period list, if any */
2920 if (client->periods) {
2921 g_list_foreach (client->periods,
2922 (GFunc) gst_mpdparser_free_stream_period, NULL);
2923 g_list_free (client->periods);
2924 client->periods = NULL;
2929 duration = GST_CLOCK_TIME_NONE;
2930 for (list = g_list_first (client->mpd_node->Periods); list;
2931 list = g_list_next (list)) {
2932 period_node = (GstPeriodNode *) list->data;
2933 if (period_node->start != -1) {
2934 /* we have a regular period */
2935 start = period_node->start * GST_MSECOND;
2936 } else if (duration != GST_CLOCK_TIME_NONE) {
2937 /* start time inferred from previous period, this is still a regular period */
2939 } else if (idx == 0 && client->mpd_node->type == GST_MPD_FILE_TYPE_STATIC) {
2940 /* first period of a static MPD file, start time is 0 */
2942 } else if (gst_mpd_client_is_live (client)) {
2943 /*it should be a live stream, let this pass.*/
2945 /* this is an 'Early Available Period' */
2949 if (period_node->duration != -1) {
2950 duration = period_node->duration * GST_MSECOND;
2951 } else if ((next = g_list_next (list)) != NULL) {
2952 /* try to infer this period duration from the start time of the next period */
2953 GstPeriodNode *next_period_node = next->data;
2954 if (next_period_node->start != -1) {
2955 duration = next_period_node->start * GST_MSECOND - start;
2957 /* Invalid MPD file! */
2960 } else if (client->mpd_node->mediaPresentationDuration != -1) {
2961 /* last Period of the Media Presentation */
2963 client->mpd_node->mediaPresentationDuration * GST_MSECOND - start;
2964 } else if (gst_mpd_client_is_live (client)) {
2965 /*it should be a live stream, let this pass.*/
2967 /* Invalid MPD file! */
2971 stream_period = g_slice_new0 (GstStreamPeriod);
2972 if (stream_period == NULL) {
2975 client->periods = g_list_append (client->periods, stream_period);
2976 stream_period->period = period_node;
2977 stream_period->number = idx++;
2978 stream_period->start = start;
2979 stream_period->duration = duration;
2981 GST_LOG (" - added Period %d start=%" GST_TIME_FORMAT " duration=%"
2982 GST_TIME_FORMAT, idx, GST_TIME_ARGS (start), GST_TIME_ARGS (duration));
2985 GST_MPD_CLIENT_UNLOCK (client);
2986 GST_DEBUG ("Found a total of %d valid Periods in the Media Presentation",
2991 GST_MPD_CLIENT_UNLOCK (client);
2993 ("Found an Early Available Period, skipping the rest of the Media Presentation");
2997 GST_MPD_CLIENT_UNLOCK (client);
2999 ("Cannot get the duration of the Period %d, skipping the rest of the Media Presentation",
3004 GST_MPD_CLIENT_UNLOCK (client);
3005 GST_WARNING ("Allocation of GstStreamPeriod struct failed!");
3010 gst_mpd_client_setup_streaming (GstMpdClient * client,
3011 GstStreamMimeType mimeType, gchar * lang)
3013 GstActiveStream *stream;
3014 GstStreamPeriod *stream_period;
3015 GstAdaptationSetNode *adapt_set;
3016 GstRepresentationNode *representation;
3017 GList *rep_list = NULL;
3019 stream_period = gst_mpdparser_get_stream_period (client);
3020 if (stream_period == NULL || stream_period->period == NULL) {
3021 GST_DEBUG ("No more Period nodes in the MPD file, terminating...");
3026 case GST_STREAM_VIDEO:
3027 /* select the adaptation set for the video pipeline */
3029 gst_mpdparser_get_adapt_set_with_mimeType_and_idx (stream_period->
3030 period->AdaptationSets, "video", 0);
3032 GST_INFO ("No video adaptation set found");
3035 /* retrive the list of representations */
3036 rep_list = adapt_set->Representations;
3038 GST_WARNING ("Can not retrieve any representation, aborting...");
3042 case GST_STREAM_AUDIO:
3044 gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang
3045 (stream_period->period->AdaptationSets, "audio", lang);
3046 /* if we did not found the requested audio language, get the first one */
3049 gst_mpdparser_get_first_adapt_set_with_mimeType (stream_period->
3050 period->AdaptationSets, "audio");
3052 GST_INFO ("No audio adaptation set found");
3055 rep_list = adapt_set->Representations;
3057 GST_WARNING ("Can not retrieve any representation, aborting...");
3061 case GST_STREAM_APPLICATION:
3063 gst_mpdparser_get_first_adapt_set_with_mimeType_and_lang
3064 (stream_period->period->AdaptationSets, "application", lang);
3065 /* if we did not found the requested subtitles language, get the first one */
3068 gst_mpdparser_get_first_adapt_set_with_mimeType (stream_period->
3069 period->AdaptationSets, "application");
3071 GST_INFO ("No application adaptation set found");
3074 rep_list = adapt_set->Representations;
3076 GST_WARNING ("Can not retrieve any representation, aborting...");
3081 GST_WARNING ("Unsupported mimeType %d", mimeType);
3085 stream = g_slice_new0 (GstActiveStream);
3086 if (stream == NULL) {
3087 GST_WARNING ("Allocation of active stream struct failed!");
3090 client->active_streams = g_list_append (client->active_streams, stream);
3092 stream->mpd_baseURL_idx = 0;
3093 stream->period_baseURL_idx = 0;
3094 stream->adaptset_baseURL_idx = 0;
3095 stream->repr_baseURL_idx = 0;
3097 stream->mimeType = mimeType;
3098 stream->cur_adapt_set = adapt_set;
3100 /* retrive representation list */
3101 if (stream->cur_adapt_set != NULL)
3102 rep_list = stream->cur_adapt_set->Representations;
3106 gst_mpdparser_get_representation_with_max_bandwidth (rep_list,
3107 stream->max_bandwidth);
3109 if (!representation) {
3111 ("Can not retrieve a representation with the requested bandwidth");
3112 representation = gst_mpdparser_get_lowest_representation (rep_list);
3116 representation = gst_mpdparser_get_lowest_representation (rep_list);
3119 if (!representation) {
3120 GST_WARNING ("No valid representation in the MPD file, aborting...");
3124 if (!gst_mpd_client_setup_representation (client, stream, representation))
3127 GST_INFO ("Successfully setup the download pipeline for mimeType %d",
3134 gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client,
3135 guint stream_idx, GstClockTime * ts)
3137 GstActiveStream *stream;
3139 GstMediaSegment currentChunk;
3141 GST_DEBUG ("Stream index: %i", stream_idx);
3142 stream = g_list_nth_data (client->active_streams, stream_idx);
3143 g_return_val_if_fail (stream != NULL, 0);
3145 GST_MPD_CLIENT_LOCK (client);
3146 segment_idx = gst_mpd_client_get_segment_index (stream);
3147 GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
3150 if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx, ¤tChunk)) {
3151 GST_MPD_CLIENT_UNLOCK (client);
3155 *ts = currentChunk.start_time;
3156 GST_MPD_CLIENT_UNLOCK (client);
3162 gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client,
3163 guint stream_idx, GstClockTime * ts)
3165 GstActiveStream *stream;
3166 gint segment_idx = 0;
3167 GstMediaSegment currentChunk;
3169 GST_DEBUG ("Stream index: %i", stream_idx);
3170 stream = g_list_nth_data (client->active_streams, stream_idx);
3171 g_return_val_if_fail (stream != NULL, 0);
3173 GST_MPD_CLIENT_LOCK (client);
3174 if (stream->segments)
3175 segment_idx = g_list_length (stream->segments) - 1;
3176 GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
3178 if (!gst_mpdparser_get_chunk_by_index (client, stream_idx, segment_idx,
3180 GST_MPD_CLIENT_UNLOCK (client);
3184 *ts = currentChunk.start_time;
3185 GST_MPD_CLIENT_UNLOCK (client);
3191 gst_mpd_client_get_next_fragment (GstMpdClient * client,
3192 guint indexStream, gboolean * discontinuity, gchar ** uri,
3193 GstClockTime * duration, GstClockTime * timestamp)
3195 GstActiveStream *stream = NULL;
3196 GstMediaSegment currentChunk;
3197 gchar *mediaURL = NULL;
3201 g_return_val_if_fail (client != NULL, FALSE);
3202 g_return_val_if_fail (client->active_streams != NULL, FALSE);
3203 stream = g_list_nth_data (client->active_streams, indexStream);
3204 g_return_val_if_fail (stream != NULL, FALSE);
3205 g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
3206 g_return_val_if_fail (discontinuity != NULL, FALSE);
3208 GST_MPD_CLIENT_LOCK (client);
3209 segment_idx = gst_mpd_client_get_segment_index (stream);
3210 GST_DEBUG ("Looking for fragment sequence chunk %d", segment_idx);
3212 if (!gst_mpdparser_get_chunk_by_index (client, indexStream, segment_idx, ¤tChunk)) {
3213 GST_MPD_CLIENT_UNLOCK (client);
3217 if (currentChunk.SegmentURL != NULL) {
3218 mediaURL = gst_mpdparser_get_mediaURL (client, currentChunk.SegmentURL);
3219 } else if (stream->cur_seg_template != NULL) {
3221 gst_mpdparser_build_URL_from_template (stream->cur_seg_template->media,
3222 stream->cur_representation->id, currentChunk.number,
3223 stream->cur_representation->bandwidth, currentChunk.start);
3226 *timestamp = currentChunk.start_time;
3227 *duration = currentChunk.duration;
3228 *discontinuity = segment_idx != currentChunk.number;
3229 if (mediaURL == NULL) {
3230 /* single segment with URL encoded in the baseURL syntax element */
3231 *uri = g_strdup (gst_mpdparser_get_baseURL (client));
3232 } else if (strncmp (mediaURL, "http://", 7) != 0) {
3233 *uri = g_strconcat (gst_mpdparser_get_baseURL (client), mediaURL, NULL);
3238 gst_mpd_client_set_segment_index (stream, segment_idx + 1);
3239 GST_MPD_CLIENT_UNLOCK (client);
3241 GST_DEBUG ("Loading chunk with URL %s", *uri);
3247 gst_mpd_client_get_next_header (GstMpdClient * client, const gchar ** uri,
3250 GstActiveStream *stream;
3251 GstStreamPeriod *stream_period;
3253 stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
3254 g_return_val_if_fail (stream != NULL, FALSE);
3255 g_return_val_if_fail (stream->cur_representation != NULL, FALSE);
3256 stream_period = gst_mpdparser_get_stream_period (client);
3257 g_return_val_if_fail (stream_period != NULL, FALSE);
3258 g_return_val_if_fail (stream_period->period != NULL, FALSE);
3260 GST_DEBUG ("Looking for current representation header");
3261 GST_MPD_CLIENT_LOCK (client);
3263 if (stream->cur_segment_base && stream->cur_segment_base->Initialization) {
3265 if (stream->cur_segment_base->Initialization->sourceURL == NULL) {
3266 stream->cur_segment_base->Initialization->sourceURL = gst_mpdparser_get_baseURL (client);
3267 }//if not present initialization @sourceURL attribute, it's mapped to baseURL
3270 gst_mpdparser_get_initializationURL (stream->cur_segment_base->
3272 } else if (stream->cur_seg_template) {
3273 const gchar *initialization = NULL;
3274 if (stream->cur_seg_template->initialization) {
3275 initialization = stream->cur_seg_template->initialization;
3276 } else if (stream->cur_adapt_set->SegmentTemplate
3277 && stream->cur_adapt_set->SegmentTemplate->initialization) {
3278 initialization = stream->cur_adapt_set->SegmentTemplate->initialization;
3279 } else if (stream_period->period->SegmentTemplate
3280 && stream_period->period->SegmentTemplate->initialization) {
3281 initialization = stream_period->period->SegmentTemplate->initialization;
3283 *uri = gst_mpdparser_build_URL_from_template (initialization,
3284 stream->cur_representation->id, 0,
3285 stream->cur_representation->bandwidth, 0);
3287 GST_MPD_CLIENT_UNLOCK (client);
3289 return *uri == NULL ? FALSE : TRUE;
3293 gst_mpd_client_get_stream_current_position (GstMpdClient * client, guint stream_idx, GstClockTime *ts)
3295 GstActiveStream *stream;
3296 GstMediaSegment media_segment;
3297 stream = gst_mpdparser_get_active_stream_by_index( client, stream_idx);
3298 g_return_val_if_fail (stream != NULL, FALSE);
3299 if(!gst_mpdparser_get_chunk_by_index(client, stream_idx,
3300 gst_mpd_client_get_segment_index (stream), &media_segment))
3305 if (GST_CLOCK_TIME_IS_VALID (media_segment.start_time)) {
3306 *ts = media_segment.start_time;
3314 gst_mpd_client_get_next_fragment_duration (GstMpdClient * client)
3316 GstActiveStream *stream;
3317 GstMediaSegment *media_segment;
3320 stream = g_list_nth_data (client->active_streams, client->stream_idx);
3321 g_return_val_if_fail (stream != NULL, 0);
3322 seg_idx = gst_mpd_client_get_segment_index (stream);
3324 if(stream->segments) {
3326 g_list_nth_data (stream->segments, seg_idx);
3327 return media_segment == NULL ? 0 : media_segment->duration;
3329 GstClockTime duration =
3330 gst_mpd_client_get_segment_duration (client, stream);
3331 g_return_val_if_fail (stream->cur_seg_template->MultSegBaseType->
3332 SegmentTimeline == NULL, 0);
3334 if (GST_CLOCK_TIME_IS_VALID (duration))
3341 gst_mpd_client_get_media_presentation_duration (GstMpdClient * client)
3343 GstClockTime duration;
3345 g_return_val_if_fail (client != NULL, GST_CLOCK_TIME_NONE);
3347 GST_MPD_CLIENT_LOCK (client);
3348 if (client->mpd_node->mediaPresentationDuration != -1) {
3349 duration = client->mpd_node->mediaPresentationDuration * GST_MSECOND;
3351 /* We can only get the duration for on-demand streams */
3352 duration = GST_CLOCK_TIME_NONE;
3354 GST_MPD_CLIENT_UNLOCK (client);
3360 gst_mpd_client_set_period_index (GstMpdClient * client, guint period_idx)
3362 GstStreamPeriod *next_stream_period;
3363 gboolean ret = FALSE;
3365 g_return_val_if_fail (client != NULL, FALSE);
3366 g_return_val_if_fail (client->periods != NULL, FALSE);
3368 GST_MPD_CLIENT_LOCK (client);
3369 next_stream_period = g_list_nth_data (client->periods, period_idx);
3370 if (next_stream_period != NULL) {
3371 client->period_idx = period_idx;
3374 GST_MPD_CLIENT_UNLOCK (client);
3380 gst_mpd_client_get_period_index (GstMpdClient * client)
3384 g_return_val_if_fail (client != NULL, 0);
3385 GST_MPD_CLIENT_LOCK (client);
3386 period_idx = client->period_idx;
3387 GST_MPD_CLIENT_UNLOCK (client);
3393 gst_mpd_client_set_period_id (GstMpdClient * client, const gchar * period_id)
3395 GstStreamPeriod *next_stream_period;
3396 gboolean ret = FALSE;
3400 g_return_val_if_fail (client != NULL, FALSE);
3401 g_return_val_if_fail (client->periods != NULL, FALSE);
3402 g_return_val_if_fail (period_id != NULL, FALSE);
3404 GST_MPD_CLIENT_LOCK (client);
3405 for (iter = client->periods; iter; iter = g_list_next (iter)) {
3406 next_stream_period = iter->data;
3408 if (next_stream_period->period->id
3409 && strcmp (next_stream_period->period->id, period_id) == 0) {
3410 client->period_idx = index;
3416 GST_MPD_CLIENT_UNLOCK (client);
3422 gst_mpd_client_get_period_id (GstMpdClient * client)
3424 GstStreamPeriod *period;
3425 gchar *period_id = NULL;
3427 g_return_val_if_fail (client != NULL, 0);
3428 GST_MPD_CLIENT_LOCK (client);
3429 period = g_list_nth_data (client->periods, client->period_idx);
3430 if (period && period->period)
3431 period_id = period->period->id;
3432 GST_MPD_CLIENT_UNLOCK (client);
3438 gst_mpd_client_has_next_period (GstMpdClient * client)
3440 GList *next_stream_period;
3441 g_return_val_if_fail (client != NULL, FALSE);
3442 g_return_val_if_fail (client->periods != NULL, FALSE);
3444 GST_MPD_CLIENT_LOCK (client);
3445 next_stream_period =
3446 g_list_nth_data (client->periods, client->period_idx + 1);
3447 GST_MPD_CLIENT_UNLOCK (client);
3449 return next_stream_period != NULL;
3453 gst_mpd_client_set_segment_index_for_all_streams (GstMpdClient * client,
3458 g_return_if_fail (client != NULL);
3459 g_return_if_fail (client->active_streams != NULL);
3461 /* FIXME: support multiple streams with different segment duration */
3462 for (list = g_list_first (client->active_streams); list;
3463 list = g_list_next (list)) {
3464 GstActiveStream *stream = (GstActiveStream *) list->data;
3466 stream->segment_idx = segment_idx;
3472 gst_mpd_client_set_next_baseURL_for_stream (GstMpdClient * client)
3474 GstActiveStream *stream;
3475 GstStreamPeriod *stream_period;
3478 g_return_val_if_fail (client != NULL, FALSE);
3479 g_return_val_if_fail (client->active_streams != NULL, FALSE);
3481 stream = g_list_nth_data (client->active_streams,
3482 client->stream_idx);
3483 g_return_val_if_fail (stream != NULL, FALSE);
3484 stream_period = gst_mpdparser_get_stream_period (client);
3485 g_return_val_if_fail (stream_period != NULL, FALSE);
3487 if ((list = stream->cur_representation->BaseURLs) != NULL &&
3488 stream->repr_baseURL_idx < g_list_length (list) - 1) {
3489 stream->repr_baseURL_idx++;
3490 } else if ((list = stream->cur_adapt_set->BaseURLs) != NULL &&
3491 stream->adaptset_baseURL_idx < g_list_length (list) - 1) {
3492 stream->adaptset_baseURL_idx++;
3493 stream->repr_baseURL_idx = 0;
3494 } else if ((list = stream_period->period->BaseURLs) != NULL &&
3495 stream->period_baseURL_idx < g_list_length (list) - 1) {
3496 stream->period_baseURL_idx++;
3497 stream->adaptset_baseURL_idx = 0;
3498 stream->repr_baseURL_idx = 0;
3499 } else if ((list = client->mpd_node->BaseURLs) != NULL &&
3500 stream->mpd_baseURL_idx < g_list_length (list) - 1) {
3501 stream->mpd_baseURL_idx++;
3502 stream->period_baseURL_idx = 0;
3503 stream->adaptset_baseURL_idx = 0;
3504 stream->repr_baseURL_idx = 0;
3506 GST_WARNING ("Unable to change URI: No alternative baseURL available");
3510 stream->baseURL = gst_mpdparser_parse_baseURL (client);
3516 gst_mpd_client_set_segment_index (GstActiveStream * stream, guint segment_idx)
3518 g_return_if_fail (stream != NULL);
3520 stream->segment_idx = segment_idx;
3524 gst_mpd_client_get_segment_index (GstActiveStream * stream)
3526 g_return_val_if_fail (stream != NULL, 0);
3528 return stream->segment_idx;
3532 gst_mpd_client_is_live (GstMpdClient * client)
3534 g_return_val_if_fail (client != NULL, FALSE);
3535 g_return_val_if_fail (client->mpd_node != NULL, FALSE);
3537 return client->mpd_node->type == GST_MPD_FILE_TYPE_DYNAMIC;
3541 gst_mpdparser_get_nb_active_stream (GstMpdClient * client)
3543 g_return_val_if_fail (client != NULL, 0);
3545 return g_list_length (client->active_streams);
3549 gst_mpdparser_get_nb_adaptationSet (GstMpdClient * client)
3551 GstStreamPeriod *stream_period;
3553 stream_period = gst_mpdparser_get_stream_period (client);
3554 g_return_val_if_fail (stream_period != NULL, 0);
3555 g_return_val_if_fail (stream_period->period != NULL, 0);
3557 return g_list_length (stream_period->period->AdaptationSets);
3561 gst_mpdparser_get_active_stream_by_index (GstMpdClient * client,
3564 g_return_val_if_fail (client != NULL, NULL);
3565 g_return_val_if_fail (client->active_streams != NULL, NULL);
3567 return g_list_nth_data (client->active_streams, stream_idx);
3571 gst_mpd_client_get_video_active_stream_id(GstMpdClient *client) {
3573 g_return_val_if_fail (client != NULL, -1);
3574 g_return_val_if_fail (client->active_streams != NULL, -1);
3575 for (idx = 0; idx < gst_mpdparser_get_nb_active_stream(client); idx++) {
3576 GstActiveStream *stream = gst_mpdparser_get_active_stream_by_index(client, idx);
3577 if( strncmp_ext (gst_mpd_client_get_stream_mimeType (stream), "video") == 0 )
3584 gst_mpd_client_stream_seek (GstMpdClient * client, gint stream_idx, GstClockTime ts)
3586 guint segment_idx = 0;
3587 GstActiveStream *stream;
3588 GST_MPD_CLIENT_LOCK (client);
3589 GST_DEBUG ("mpd client seeking to %"GST_TIME_FORMAT" on stream %d", GST_TIME_ARGS(ts), stream_idx);
3590 stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
3591 g_return_val_if_fail (stream != NULL, FALSE);
3593 if ( GST_CLOCK_TIME_IS_VALID (gst_mpd_client_stream_find_segment (client,
3594 stream_idx, ts, &segment_idx))) {
3595 gst_mpd_client_set_segment_index(stream, segment_idx);
3597 GST_MPD_CLIENT_UNLOCK (client);
3602 _gst_date_time_to_g_date_time (GstDateTime * datetime)
3604 g_return_val_if_fail (datetime != NULL, NULL);
3605 return g_date_time_new_utc ( gst_date_time_get_year (datetime), gst_date_time_get_month(datetime),
3606 gst_date_time_get_day(datetime), gst_date_time_get_hour(datetime),
3607 gst_date_time_get_minute(datetime),gst_date_time_get_second(datetime));
3611 gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time)
3614 _gst_date_time_to_g_date_time (client->mpd_node->availabilityStartTime);
3615 GTimeSpan ts_microseconds;
3617 gboolean ret = TRUE;
3620 g_return_val_if_fail (gst_mpd_client_is_live (client), 0);
3622 ts_microseconds = g_date_time_difference (time, start);
3623 g_date_time_unref (start);
3625 ts = ts_microseconds * GST_USECOND;
3626 for (i=0; i < g_list_length (client->active_streams); i++) {
3627 ret = ret & gst_mpd_client_stream_seek (client, i, ts);
3633 gst_mpd_client_check_time_position (GstMpdClient * client,
3634 GstActiveStream * stream, GstClockTime ts, gint64 * diff)
3636 GDateTime *now = g_date_time_new_now_utc ();
3638 _gst_date_time_to_g_date_time (client->mpd_node->availabilityStartTime);
3639 GTimeSpan stream_now;
3640 GTimeSpan ts_microseconds;
3641 GstClockTime duration;
3643 g_return_val_if_fail (gst_mpd_client_is_live (client), 0);
3645 duration = gst_mpd_client_get_segment_duration (client, stream);
3646 stream_now = g_date_time_difference (now, start);
3647 g_date_time_unref (now);
3648 g_date_time_unref (start);
3650 /* sum duration to check if the segment is fully ready */
3651 ts_microseconds = (ts + duration) / GST_USECOND;
3654 * This functions checks if a given ts is in the 'available range' of
3655 * a DASH presentation. This only makes sense for live streams, which
3656 * are continuously adding new segments and removing old ones.
3658 * Note: Both the client and the server should use UTC as a time reference.
3660 * @ts is the time since the beginning of the stream and we need to find out
3661 * if it is currently available. The server should be hosting segments
3663 * * ---------------- ... --- * ----------- * ---- ...
3665 * | past(unavailable) | | available | future(unavailable yet)
3667 * * ---------------- ... --- * ----------- * ---- ...
3669 * availabilitStartTime | UTC now
3670 * UTC now - timeShiftBufferDepth
3672 * This function should return 0 if @ts is in the 'available' area, 1 for
3673 * 'future' and '-1' for past and the corresponding distance to the
3674 * 'available' area is set to @diff
3676 * TODO untested with live presentations with multiple periods as no
3677 * examples for it could be found/generated
3680 if (ts_microseconds > stream_now) {
3681 *diff = ts_microseconds - stream_now;
3684 if (GST_CLOCK_TIME_IS_VALID (client->mpd_node->timeShiftBufferDepth)
3685 && ts_microseconds <
3686 stream_now - client->mpd_node->timeShiftBufferDepth * GST_USECOND) {
3687 *diff = ts_microseconds - stream_now;
3695 /*Finds the segment with appropriate time*/
3697 gst_mpd_client_stream_find_segment(GstMpdClient *client, guint stream_idx,
3698 GstClockTime seek_pos, guint *seg_num)
3700 guint cur_segment_idx=0;
3701 GstMediaSegment *chunk;
3703 GstClockTime current_pos = 0;
3704 GstActiveStream *stream = gst_mpdparser_get_active_stream_by_index (client, stream_idx);
3705 g_return_val_if_fail (stream != NULL, GST_CLOCK_TIME_NONE);
3706 if(stream->segments != NULL) {
3707 for (list = g_list_first (stream->segments); list;
3708 list = g_list_next (list)) {
3710 current_pos = chunk->start_time;
3711 if (current_pos <= seek_pos
3712 && seek_pos < current_pos + chunk->duration) {
3718 *seg_num = cur_segment_idx;
3721 return GST_CLOCK_TIME_NONE;
3724 GstClockTime duration;
3725 duration = gst_mpd_client_get_segment_duration (client, stream);
3726 if( !GST_CLOCK_TIME_IS_VALID (duration) )
3728 *seg_num = seek_pos / duration;
3729 return *seg_num * duration;
3733 static const gchar *
3734 gst_mpdparser_mimetype_to_caps (const gchar * mimeType)
3736 if (mimeType == NULL)
3738 if (strcmp (mimeType, "video/mp2t") == 0) {
3739 return "video/mpegts";
3740 } else if (strcmp (mimeType, "video/mp4") == 0) {
3741 return "video/quicktime";
3742 } else if (strcmp (mimeType, "audio/mp4") == 0) {
3743 return "audio/x-m4a";
3749 gst_mpd_client_get_stream_mimeType (GstActiveStream * stream)
3751 const gchar *mimeType;
3753 if (stream == NULL || stream->cur_adapt_set == NULL
3754 || stream->cur_representation == NULL)
3757 mimeType = stream->cur_representation->RepresentationBase->mimeType;
3758 if (mimeType == NULL) {
3759 mimeType = stream->cur_adapt_set->RepresentationBase->mimeType;
3762 return gst_mpdparser_mimetype_to_caps (mimeType);
3766 gst_mpd_client_get_bitstream_switching_flag (GstActiveStream * stream)
3768 if (stream == NULL || stream->cur_adapt_set == NULL)
3771 return stream->cur_adapt_set->bitstreamSwitching;
3775 gst_mpd_client_get_max_video_dimensions (GstMpdClient *client, gint *max_width, gint *max_height)
3777 GList *period_it, *repr_it;
3778 GstStreamPeriod *period;
3779 GstAdaptationSetNode *adaptset;
3780 GstRepresentationNode *repr;
3782 g_return_val_if_fail (client != NULL, FALSE);
3783 g_return_val_if_fail (max_height != NULL, FALSE);
3784 g_return_val_if_fail (max_width != NULL, FALSE);
3789 period_it = client->periods;
3791 period = period_it->data;
3792 adaptset = gst_mpdparser_get_adapt_set_with_mimeType_and_idx (
3793 period->period->AdaptationSets, "video", 0);
3794 if(adaptset == NULL)
3796 repr_it = adaptset->Representations;
3798 if(adaptset->RepresentationBase->width > *max_width)
3799 *max_width = adaptset->RepresentationBase->width;
3800 if(adaptset->RepresentationBase->height > *max_height)
3801 *max_height = adaptset->RepresentationBase->height;
3804 repr = repr_it->data;
3805 if(repr->RepresentationBase->width > *max_width)
3806 *max_width = repr->RepresentationBase->width;
3807 if(repr->RepresentationBase->height > *max_height)
3808 *max_height = repr->RepresentationBase->height;
3809 repr_it = repr_it->next;
3812 period_it = period_it->next;
3814 if(*max_width == 0 && *max_height == 0)
3821 gst_mpd_client_get_video_stream_width (GstActiveStream * stream)
3825 if (stream == NULL || stream->cur_adapt_set == NULL
3826 || stream->cur_representation == NULL)
3829 width = stream->cur_representation->RepresentationBase->width;
3831 width = stream->cur_adapt_set->RepresentationBase->width;
3838 gst_mpd_client_get_video_stream_height (GstActiveStream * stream)
3842 if (stream == NULL || stream->cur_adapt_set == NULL
3843 || stream->cur_representation == NULL)
3846 height = stream->cur_representation->RepresentationBase->height;
3848 height = stream->cur_adapt_set->RepresentationBase->height;
3855 gst_mpd_client_get_video_stream_bandwidth (GstActiveStream * stream)
3859 if (stream == NULL || stream->cur_adapt_set == NULL
3860 || stream->cur_representation == NULL)
3863 bandwidth = stream->cur_representation->RepresentationBase->bandwidth;
3864 if (bandwidth == 0) {
3865 bandwidth = stream->cur_adapt_set->RepresentationBase->bandwidth;
3872 gst_mpd_client_get_audio_stream_rate (GstActiveStream * stream)
3876 if (stream == NULL || stream->cur_adapt_set == NULL
3877 || stream->cur_representation == NULL)
3880 rate = stream->cur_representation->RepresentationBase->audioSamplingRate;
3882 rate = stream->cur_adapt_set->RepresentationBase->audioSamplingRate;
3885 return rate ? atoi (rate) : 0;
3889 gst_mpd_client_get_audio_stream_num_channels (GstActiveStream * stream)
3891 if (stream == NULL || stream->cur_adapt_set == NULL
3892 || stream->cur_representation == NULL)
3894 /* TODO: here we have to parse the AudioChannelConfiguration descriptors */
3899 gst_mpdparser_get_list_and_nb_of_audio_language (GstMpdClient * client,
3902 GstStreamPeriod *stream_period;
3903 GstAdaptationSetNode *adapt_set;
3905 gchar *this_mimeType = "audio";
3906 gchar *mimeType = NULL;
3907 guint nb_adapatation_set = 0;
3909 stream_period = gst_mpdparser_get_stream_period (client);
3910 g_return_val_if_fail (stream_period != NULL, 0);
3911 g_return_val_if_fail (stream_period->period != NULL, 0);
3913 for (list = g_list_first (stream_period->period->AdaptationSets); list;
3914 list = g_list_next (list)) {
3915 adapt_set = (GstAdaptationSetNode *) list->data;
3917 gchar *this_lang = adapt_set->lang;
3918 GstRepresentationNode *rep;
3920 gst_mpdparser_get_lowest_representation (adapt_set->Representations);
3922 GST_WARNING ("No valid representation in the MPD file, aborting...");
3925 if (rep->RepresentationBase)
3926 mimeType = rep->RepresentationBase->mimeType;
3927 if (!mimeType && adapt_set->RepresentationBase) {
3928 mimeType = adapt_set->RepresentationBase->mimeType;
3931 if (strncmp_ext (mimeType, this_mimeType) == 0) {
3933 nb_adapatation_set++;
3934 *lang = g_list_append (*lang, this_lang);
3940 return nb_adapatation_set;