mssdemux2: Ensure stream/track uniqueness
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / ext / adaptivedemux2 / mss / gstmssmanifest.c
1 /* GStreamer
2  * Copyright (C) 2012 Smart TV Alliance
3  * Copyright (C) 2016 Igalia S.L
4  * Copyright (C) 2016 Metrological
5  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>, Collabora Ltd.
6  *
7  * gstmssmanifest.c:
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include <glib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <libxml/parser.h>
30 #include <libxml/tree.h>
31
32 #include "gstmssmanifest.h"
33 #include "gstmssfragmentparser.h"
34
35 GST_DEBUG_CATEGORY_EXTERN (mssdemux2_debug);
36 #define GST_CAT_DEFAULT mssdemux2_debug
37
38 #define DEFAULT_TIMESCALE             10000000
39
40 #define MSS_NODE_STREAM_FRAGMENT      "c"
41 #define MSS_NODE_STREAM_QUALITY       "QualityLevel"
42
43 #define MSS_PROP_BITRATE              "Bitrate"
44 #define MSS_PROP_DURATION             "d"
45 #define MSS_PROP_DVR_WINDOW_LENGTH    "DVRWindowLength"
46 #define MSS_PROP_LANGUAGE             "Language"
47 #define MSS_PROP_NAME                 "Name"
48 #define MSS_PROP_NUMBER               "n"
49 #define MSS_PROP_REPETITIONS          "r"
50 #define MSS_PROP_STREAM_DURATION      "Duration"
51 #define MSS_PROP_TIME                 "t"
52 #define MSS_PROP_TIMESCALE            "TimeScale"
53 #define MSS_PROP_URL                  "Url"
54
55 #define GST_MSSMANIFEST_LIVE_MIN_FRAGMENT_DISTANCE 3
56
57 typedef struct _GstMssStreamFragment
58 {
59   guint number;
60   guint64 time;
61   guint64 duration;
62   guint repetitions;
63 } GstMssStreamFragment;
64
65 typedef struct _GstMssStreamQuality
66 {
67   xmlNodePtr xmlnode;
68
69   gchar *bitrate_str;
70   guint64 bitrate;
71 } GstMssStreamQuality;
72
73 struct _GstMssStream
74 {
75   xmlNodePtr xmlnode;
76
77   gboolean active;              /* if the stream is currently being used */
78   gint selectedQualityIndex;
79
80   gboolean has_live_fragments;
81   GstAdapter *live_adapter;
82
83   GList *fragments;
84   GList *qualities;
85
86   gchar *url;
87   gchar *lang;
88   gchar *name;
89
90   GstMssFragmentParser fragment_parser;
91
92   guint fragment_repetition_index;
93   GList *current_fragment;
94   GList *current_quality;
95
96   /* TODO move this to somewhere static */
97   GRegex *regex_bitrate;
98   GRegex *regex_position;
99 };
100
101 struct _GstMssManifest
102 {
103   xmlDocPtr xml;
104   xmlNodePtr xmlrootnode;
105
106   gboolean is_live;
107   gint64 dvr_window;
108   guint64 look_ahead_fragment_count;
109
110   GString *protection_system_id;
111   gchar *protection_data;
112
113   GSList *streams;
114 };
115
116 /* For parsing and building a fragments list */
117 typedef struct _GstMssFragmentListBuilder
118 {
119   GList *fragments;
120
121   GstMssStreamFragment *previous_fragment;
122   guint fragment_number;
123   guint64 fragment_time_accum;
124 } GstMssFragmentListBuilder;
125
126 static void
127 gst_mss_fragment_list_builder_init (GstMssFragmentListBuilder * builder)
128 {
129   builder->fragments = NULL;
130   builder->previous_fragment = NULL;
131   builder->fragment_time_accum = 0;
132   builder->fragment_number = 0;
133 }
134
135 static void
136 gst_mss_fragment_list_builder_add (GstMssFragmentListBuilder * builder,
137     xmlNodePtr node)
138 {
139   gchar *duration_str;
140   gchar *time_str;
141   gchar *seqnum_str;
142   gchar *repetition_str;
143   GstMssStreamFragment *fragment = g_new (GstMssStreamFragment, 1);
144
145   duration_str = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_DURATION);
146   time_str = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_TIME);
147   seqnum_str = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_NUMBER);
148   repetition_str =
149       (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_REPETITIONS);
150
151   /* use the node's seq number or use the previous + 1 */
152   if (seqnum_str) {
153     fragment->number = g_ascii_strtoull (seqnum_str, NULL, 10);
154     xmlFree (seqnum_str);
155     builder->fragment_number = fragment->number;
156   } else {
157     fragment->number = builder->fragment_number;
158   }
159   builder->fragment_number = fragment->number + 1;
160
161   if (repetition_str) {
162     fragment->repetitions = g_ascii_strtoull (repetition_str, NULL, 10);
163     xmlFree (repetition_str);
164   } else {
165     fragment->repetitions = 1;
166   }
167
168   if (time_str) {
169     fragment->time = g_ascii_strtoull (time_str, NULL, 10);
170
171     xmlFree (time_str);
172     builder->fragment_time_accum = fragment->time;
173   } else {
174     fragment->time = builder->fragment_time_accum;
175   }
176
177   /* if we have a previous fragment, means we need to set its duration */
178   if (builder->previous_fragment)
179     builder->previous_fragment->duration =
180         (fragment->time -
181         builder->previous_fragment->time) /
182         builder->previous_fragment->repetitions;
183
184   if (duration_str) {
185     fragment->duration = g_ascii_strtoull (duration_str, NULL, 10);
186
187     builder->previous_fragment = NULL;
188     builder->fragment_time_accum += fragment->duration * fragment->repetitions;
189     xmlFree (duration_str);
190   } else {
191     /* store to set the duration at the next iteration */
192     builder->previous_fragment = fragment;
193   }
194
195   /* we reverse it later */
196   builder->fragments = g_list_prepend (builder->fragments, fragment);
197   GST_LOG ("Adding fragment number: %u, time: %" G_GUINT64_FORMAT
198       ", duration: %" G_GUINT64_FORMAT ", repetitions: %u",
199       fragment->number, fragment->time, fragment->duration,
200       fragment->repetitions);
201 }
202
203 static GstBuffer *gst_buffer_from_hex_string (const gchar * s);
204
205 static gboolean
206 node_has_type (xmlNodePtr node, const gchar * name)
207 {
208   return strcmp ((gchar *) node->name, name) == 0;
209 }
210
211 static GstMssStreamQuality *
212 gst_mss_stream_quality_new (xmlNodePtr node)
213 {
214   GstMssStreamQuality *q = g_slice_new (GstMssStreamQuality);
215
216   q->xmlnode = node;
217   q->bitrate_str = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_BITRATE);
218
219   if (q->bitrate_str != NULL)
220     q->bitrate = g_ascii_strtoull (q->bitrate_str, NULL, 10);
221   else
222     q->bitrate = 0;
223
224   return q;
225 }
226
227 static void
228 gst_mss_stream_quality_free (GstMssStreamQuality * quality)
229 {
230   g_return_if_fail (quality != NULL);
231
232   xmlFree (quality->bitrate_str);
233   g_slice_free (GstMssStreamQuality, quality);
234 }
235
236 static gint
237 compare_bitrate (GstMssStreamQuality * a, GstMssStreamQuality * b)
238 {
239   if (a->bitrate > b->bitrate)
240     return 1;
241   if (a->bitrate < b->bitrate)
242     return -1;
243   return 0;
244
245 }
246
247 static void
248 _gst_mss_stream_init (GstMssManifest * manifest, GstMssStream * stream,
249     xmlNodePtr node)
250 {
251   xmlNodePtr iter;
252   GstMssFragmentListBuilder builder;
253
254   gst_mss_fragment_list_builder_init (&builder);
255
256   stream->xmlnode = node;
257
258   /* get the base url path generator */
259   stream->name = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_NAME);
260   stream->url = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_URL);
261   stream->lang = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_LANGUAGE);
262
263   /* for live playback each fragment usually has timing
264    * information for the few next look-ahead fragments so the
265    * playlist can be built incrementally from the first fragment
266    * of the manifest.
267    */
268
269   GST_DEBUG ("lang '%s' url %s", stream->lang, stream->url);
270   GST_DEBUG ("Live stream: %s, look-ahead fragments: %" G_GUINT64_FORMAT,
271       manifest->is_live ? "yes" : "no", manifest->look_ahead_fragment_count);
272   stream->has_live_fragments = manifest->is_live
273       && manifest->look_ahead_fragment_count;
274
275   for (iter = node->children; iter; iter = iter->next) {
276     GST_LOG ("Handling child '%s'", iter->name);
277     if (node_has_type (iter, MSS_NODE_STREAM_FRAGMENT)) {
278       gst_mss_fragment_list_builder_add (&builder, iter);
279     } else if (node_has_type (iter, MSS_NODE_STREAM_QUALITY)) {
280       GstMssStreamQuality *quality = gst_mss_stream_quality_new (iter);
281       stream->qualities = g_list_prepend (stream->qualities, quality);
282     } else {
283       /* TODO gst log this */
284     }
285   }
286
287   if (stream->has_live_fragments) {
288     stream->live_adapter = gst_adapter_new ();
289   }
290
291   if (builder.fragments) {
292     stream->fragments = g_list_reverse (builder.fragments);
293     if (manifest->is_live) {
294       GList *iter = g_list_last (stream->fragments);
295       gint i;
296
297       for (i = 0; i < GST_MSSMANIFEST_LIVE_MIN_FRAGMENT_DISTANCE; i++) {
298         if (g_list_previous (iter)) {
299           iter = g_list_previous (iter);
300         } else {
301           break;
302         }
303       }
304       stream->current_fragment = iter;
305     } else {
306       stream->current_fragment = stream->fragments;
307     }
308   }
309
310   /* order them from smaller to bigger based on bitrates */
311   stream->qualities =
312       g_list_sort (stream->qualities, (GCompareFunc) compare_bitrate);
313   stream->current_quality = stream->qualities;
314
315   stream->regex_bitrate = g_regex_new ("\\{[Bb]itrate\\}", 0, 0, NULL);
316   stream->regex_position = g_regex_new ("\\{start[ _]time\\}", 0, 0, NULL);
317
318   gst_mss_fragment_parser_init (&stream->fragment_parser);
319 }
320
321
322 static void
323 _gst_mss_parse_protection (GstMssManifest * manifest,
324     xmlNodePtr protection_node)
325 {
326   xmlNodePtr nodeiter;
327
328   for (nodeiter = protection_node->children; nodeiter;
329       nodeiter = nodeiter->next) {
330     if (nodeiter->type == XML_ELEMENT_NODE
331         && (strcmp ((const char *) nodeiter->name, "ProtectionHeader") == 0)) {
332       xmlChar *system_id_attribute =
333           xmlGetProp (nodeiter, (xmlChar *) "SystemID");
334       gchar *value = (gchar *) system_id_attribute;
335       int id_len = strlen (value);
336       GString *system_id;
337
338       if (value[0] == '{') {
339         value++;
340         id_len--;
341       }
342
343       system_id = g_string_new (value);
344       system_id = g_string_ascii_down (system_id);
345       if (value[id_len - 1] == '}')
346         system_id = g_string_truncate (system_id, id_len - 1);
347
348       manifest->protection_system_id = system_id;
349       manifest->protection_data = (gchar *) xmlNodeGetContent (nodeiter);
350       xmlFree (system_id_attribute);
351       break;
352     }
353   }
354 }
355
356 GstMssManifest *
357 gst_mss_manifest_new (GstBuffer * data)
358 {
359   GstMssManifest *manifest;
360   xmlNodePtr root;
361   xmlNodePtr nodeiter;
362   gchar *live_str;
363   GstMapInfo mapinfo;
364   gchar *look_ahead_fragment_count_str;
365
366   if (!gst_buffer_map (data, &mapinfo, GST_MAP_READ)) {
367     return NULL;
368   }
369
370   manifest = g_malloc0 (sizeof (GstMssManifest));
371
372   manifest->xml = xmlReadMemory ((const gchar *) mapinfo.data,
373       mapinfo.size, "manifest", NULL, 0);
374   root = manifest->xmlrootnode = xmlDocGetRootElement (manifest->xml);
375   if (root == NULL) {
376     GST_WARNING ("No root node ! Invalid manifest");
377     gst_mss_manifest_free (manifest);
378     return NULL;
379   }
380
381   live_str = (gchar *) xmlGetProp (root, (xmlChar *) "IsLive");
382   if (live_str) {
383     manifest->is_live = g_ascii_strcasecmp (live_str, "true") == 0;
384     xmlFree (live_str);
385   }
386
387   /* the entire file is always available for non-live streams */
388   if (!manifest->is_live) {
389     manifest->dvr_window = 0;
390     manifest->look_ahead_fragment_count = 0;
391   } else {
392     /* if 0, or non-existent, the length is infinite */
393     gchar *dvr_window_str = (gchar *) xmlGetProp (root,
394         (xmlChar *) MSS_PROP_DVR_WINDOW_LENGTH);
395     if (dvr_window_str) {
396       manifest->dvr_window = g_ascii_strtoull (dvr_window_str, NULL, 10);
397       xmlFree (dvr_window_str);
398       if (manifest->dvr_window <= 0) {
399         manifest->dvr_window = 0;
400       }
401     }
402
403     look_ahead_fragment_count_str =
404         (gchar *) xmlGetProp (root, (xmlChar *) "LookAheadFragmentCount");
405     if (look_ahead_fragment_count_str) {
406       manifest->look_ahead_fragment_count =
407           g_ascii_strtoull (look_ahead_fragment_count_str, NULL, 10);
408       xmlFree (look_ahead_fragment_count_str);
409       if (manifest->look_ahead_fragment_count <= 0) {
410         manifest->look_ahead_fragment_count = 0;
411       }
412     }
413   }
414
415   for (nodeiter = root->children; nodeiter; nodeiter = nodeiter->next) {
416     if (nodeiter->type == XML_ELEMENT_NODE
417         && (strcmp ((const char *) nodeiter->name, "StreamIndex") == 0)) {
418       GstMssStream *stream = g_new0 (GstMssStream, 1);
419
420       manifest->streams = g_slist_append (manifest->streams, stream);
421       _gst_mss_stream_init (manifest, stream, nodeiter);
422     }
423
424     if (nodeiter->type == XML_ELEMENT_NODE
425         && (strcmp ((const char *) nodeiter->name, "Protection") == 0)) {
426       _gst_mss_parse_protection (manifest, nodeiter);
427     }
428   }
429
430   gst_buffer_unmap (data, &mapinfo);
431
432   return manifest;
433 }
434
435 static void
436 gst_mss_stream_free (GstMssStream * stream)
437 {
438   if (stream->live_adapter) {
439     gst_adapter_clear (stream->live_adapter);
440     g_object_unref (stream->live_adapter);
441   }
442
443   g_list_free_full (stream->fragments, g_free);
444   g_list_free_full (stream->qualities,
445       (GDestroyNotify) gst_mss_stream_quality_free);
446   xmlFree (stream->url);
447   xmlFree (stream->name);
448   xmlFree (stream->lang);
449   g_regex_unref (stream->regex_position);
450   g_regex_unref (stream->regex_bitrate);
451   gst_mss_fragment_parser_clear (&stream->fragment_parser);
452   g_free (stream);
453 }
454
455 void
456 gst_mss_manifest_free (GstMssManifest * manifest)
457 {
458   g_return_if_fail (manifest != NULL);
459
460   g_slist_free_full (manifest->streams, (GDestroyNotify) gst_mss_stream_free);
461
462   if (manifest->protection_system_id != NULL)
463     g_string_free (manifest->protection_system_id, TRUE);
464   xmlFree (manifest->protection_data);
465
466   xmlFreeDoc (manifest->xml);
467   g_free (manifest);
468 }
469
470 const gchar *
471 gst_mss_manifest_get_protection_system_id (GstMssManifest * manifest)
472 {
473   if (manifest->protection_system_id != NULL)
474     return manifest->protection_system_id->str;
475   return NULL;
476 }
477
478 const gchar *
479 gst_mss_manifest_get_protection_data (GstMssManifest * manifest)
480 {
481   return manifest->protection_data;
482 }
483
484 GSList *
485 gst_mss_manifest_get_streams (GstMssManifest * manifest)
486 {
487   return manifest->streams;
488 }
489
490 GstMssStreamType
491 gst_mss_stream_get_type (GstMssStream * stream)
492 {
493   gchar *prop = (gchar *) xmlGetProp (stream->xmlnode, (xmlChar *) "Type");
494   GstMssStreamType ret = MSS_STREAM_TYPE_UNKNOWN;
495
496   if (prop == NULL)
497     return MSS_STREAM_TYPE_UNKNOWN;
498
499   if (strcmp (prop, "video") == 0) {
500     ret = MSS_STREAM_TYPE_VIDEO;
501   } else if (strcmp (prop, "audio") == 0) {
502     ret = MSS_STREAM_TYPE_AUDIO;
503   } else {
504     GST_DEBUG ("Unsupported stream type: %s", prop);
505   }
506   xmlFree (prop);
507   return ret;
508 }
509
510 static GstCaps *
511 _gst_mss_stream_video_caps_from_fourcc (gchar * fourcc)
512 {
513   if (!fourcc)
514     return NULL;
515
516   if (strcmp (fourcc, "H264") == 0 || strcmp (fourcc, "AVC1") == 0) {
517     return gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
518         "avc", NULL);
519   } else if (strcmp (fourcc, "WVC1") == 0) {
520     return gst_caps_new_simple ("video/x-wmv", "wmvversion", G_TYPE_INT, 3,
521         "format", G_TYPE_STRING, "WVC1", NULL);
522   }
523   return NULL;
524 }
525
526 static GstCaps *
527 _gst_mss_stream_audio_caps_from_fourcc (gchar * fourcc)
528 {
529   if (!fourcc)
530     return NULL;
531
532   if (strcmp (fourcc, "AACL") == 0) {
533     return gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4,
534         NULL);
535   } else if (strcmp (fourcc, "WmaPro") == 0 || strcmp (fourcc, "WMAP") == 0) {
536     return gst_caps_new_simple ("audio/x-wma", "wmaversion", G_TYPE_INT, 3,
537         NULL);
538   }
539   return NULL;
540 }
541
542 static GstCaps *
543 _gst_mss_stream_audio_caps_from_audio_tag (gint audiotag)
544 {
545   switch (audiotag) {
546     case 83:                   /* MP3 */
547       return gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1,
548           "layer", G_TYPE_INT, 3, NULL);
549     case 255:                  /* AAC */
550       return gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4,
551           NULL);
552     default:
553       break;
554   }
555   return NULL;
556 }
557
558 /* copied and adapted from h264parse */
559 static GstBuffer *
560 _make_h264_codec_data (GstBuffer * sps, GstBuffer * pps)
561 {
562   GstBuffer *buf;
563   gint sps_size = 0, pps_size = 0, num_sps = 0, num_pps = 0;
564   guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
565   guint8 *data;
566   gint nl;
567   GstMapInfo spsinfo, ppsinfo, codecdatainfo;
568
569   if (gst_buffer_get_size (sps) < 4)
570     return NULL;
571
572   gst_buffer_map (sps, &spsinfo, GST_MAP_READ);
573   gst_buffer_map (pps, &ppsinfo, GST_MAP_READ);
574
575   sps_size += spsinfo.size + 2;
576   profile_idc = spsinfo.data[1];
577   profile_comp = spsinfo.data[2];
578   level_idc = spsinfo.data[3];
579   num_sps = 1;
580
581   pps_size += ppsinfo.size + 2;
582   num_pps = 1;
583
584   buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size);
585   gst_buffer_map (buf, &codecdatainfo, GST_MAP_WRITE);
586   data = codecdatainfo.data;
587   nl = 4;
588
589   data[0] = 1;                  /* AVC Decoder Configuration Record ver. 1 */
590   data[1] = profile_idc;        /* profile_idc                             */
591   data[2] = profile_comp;       /* profile_compability                     */
592   data[3] = level_idc;          /* level_idc                               */
593   data[4] = 0xfc | (nl - 1);    /* nal_length_size_minus1                  */
594   data[5] = 0xe0 | num_sps;     /* number of SPSs */
595
596   data += 6;
597   GST_WRITE_UINT16_BE (data, spsinfo.size);
598   memcpy (data + 2, spsinfo.data, spsinfo.size);
599   data += 2 + spsinfo.size;
600
601   data[0] = num_pps;
602   data++;
603   GST_WRITE_UINT16_BE (data, ppsinfo.size);
604   memcpy (data + 2, ppsinfo.data, ppsinfo.size);
605   data += 2 + ppsinfo.size;
606
607   gst_buffer_unmap (sps, &spsinfo);
608   gst_buffer_unmap (pps, &ppsinfo);
609   gst_buffer_unmap (buf, &codecdatainfo);
610
611   return buf;
612 }
613
614 static void
615 _gst_mss_stream_add_h264_codec_data (GstCaps * caps, const gchar * codecdatastr)
616 {
617   GstBuffer *sps;
618   GstBuffer *pps;
619   GstBuffer *buffer;
620   gchar *sps_str;
621   gchar *pps_str;
622
623   /* search for the sps start */
624   if (g_str_has_prefix (codecdatastr, "00000001")) {
625     sps_str = (gchar *) codecdatastr + 8;
626   } else {
627     return;                     /* invalid mss codec data */
628   }
629
630   /* search for the pps start */
631   pps_str = g_strstr_len (sps_str, -1, "00000001");
632   if (!pps_str) {
633     return;                     /* invalid mss codec data */
634   }
635
636   pps_str[0] = '\0';
637   sps = gst_buffer_from_hex_string (sps_str);
638   pps_str[0] = '0';
639
640   pps_str = pps_str + 8;
641   pps = gst_buffer_from_hex_string (pps_str);
642
643   buffer = _make_h264_codec_data (sps, pps);
644   gst_buffer_unref (sps);
645   gst_buffer_unref (pps);
646
647   if (buffer != NULL) {
648     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL);
649     gst_buffer_unref (buffer);
650   }
651 }
652
653 static GstCaps *
654 _gst_mss_stream_video_caps_from_qualitylevel_xml (GstMssStreamQuality * q)
655 {
656   xmlNodePtr node = q->xmlnode;
657   GstCaps *caps;
658   GstStructure *structure;
659   gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
660   gchar *max_width = (gchar *) xmlGetProp (node, (xmlChar *) "MaxWidth");
661   gchar *max_height = (gchar *) xmlGetProp (node, (xmlChar *) "MaxHeight");
662   gchar *codec_data =
663       (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
664
665   if (!max_width)
666     max_width = (gchar *) xmlGetProp (node, (xmlChar *) "Width");
667   if (!max_height)
668     max_height = (gchar *) xmlGetProp (node, (xmlChar *) "Height");
669
670   caps = _gst_mss_stream_video_caps_from_fourcc (fourcc);
671   if (!caps)
672     goto end;
673
674   structure = gst_caps_get_structure (caps, 0);
675
676   if (max_width) {
677     gst_structure_set (structure, "width", G_TYPE_INT,
678         (int) g_ascii_strtoull (max_width, NULL, 10), NULL);
679   }
680   if (max_height) {
681     gst_structure_set (structure, "height", G_TYPE_INT,
682         (int) g_ascii_strtoull (max_height, NULL, 10), NULL);
683   }
684
685   if (codec_data && strlen (codec_data)) {
686     if (strcmp (fourcc, "H264") == 0 || strcmp (fourcc, "AVC1") == 0) {
687       _gst_mss_stream_add_h264_codec_data (caps, codec_data);
688     } else {
689       GstBuffer *buffer = gst_buffer_from_hex_string ((gchar *) codec_data);
690       gst_structure_set (structure, "codec_data", GST_TYPE_BUFFER, buffer,
691           NULL);
692       gst_buffer_unref (buffer);
693     }
694   }
695
696 end:
697   xmlFree (fourcc);
698   xmlFree (max_width);
699   xmlFree (max_height);
700   xmlFree (codec_data);
701
702   return caps;
703 }
704
705 static guint8
706 _frequency_index_from_sampling_rate (guint sampling_rate)
707 {
708   static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
709     32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
710   };
711
712   guint8 i;
713
714   for (i = 0; i < G_N_ELEMENTS (aac_sample_rates); i++) {
715     if (aac_sample_rates[i] == sampling_rate)
716       return i;
717   }
718   return 15;
719 }
720
721 static GstBuffer *
722 _make_aacl_codec_data (guint64 sampling_rate, guint64 channels)
723 {
724   GstBuffer *buf;
725   guint8 *data;
726   guint8 frequency_index;
727   guint8 buf_size;
728   GstMapInfo info;
729
730   buf_size = 2;
731   frequency_index = _frequency_index_from_sampling_rate (sampling_rate);
732   if (frequency_index == 15)
733     buf_size += 3;
734
735   buf = gst_buffer_new_and_alloc (buf_size);
736   gst_buffer_map (buf, &info, GST_MAP_WRITE);
737   data = info.data;
738
739   data[0] = 2 << 3;             /* AAC-LC object type is 2 */
740   data[0] += frequency_index >> 1;
741   data[1] = (frequency_index & 0x01) << 7;
742
743   /* Sampling rate is not in frequencies table, write manually */
744   if (frequency_index == 15) {
745     data[1] += sampling_rate >> 17;
746     data[2] = (sampling_rate >> 9) & 0xFF;
747     data[3] = (sampling_rate >> 1) & 0xFF;
748     data[4] = sampling_rate & 0x01;
749     data += 3;
750   }
751
752   data[1] += (channels & 0x0F) << 3;
753
754   gst_buffer_unmap (buf, &info);
755
756   return buf;
757 }
758
759 static GstCaps *
760 _gst_mss_stream_audio_caps_from_qualitylevel_xml (GstMssStreamQuality * q)
761 {
762   xmlNodePtr node = q->xmlnode;
763   GstCaps *caps = NULL;
764   GstStructure *structure;
765   gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
766   gchar *audiotag = (gchar *) xmlGetProp (node, (xmlChar *) "AudioTag");
767   gchar *channels_str = (gchar *) xmlGetProp (node, (xmlChar *) "Channels");
768   gchar *rate_str = (gchar *) xmlGetProp (node, (xmlChar *) "SamplingRate");
769   gchar *depth_str = (gchar *) xmlGetProp (node, (xmlChar *) "BitsPerSample");
770   gchar *block_align_str =
771       (gchar *) xmlGetProp (node, (xmlChar *) "PacketSize");
772   gchar *codec_data_str =
773       (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
774   GstBuffer *codec_data = NULL;
775   gint depth = 0;
776   gint block_align = 0;
777   gint rate = 0;
778   gint channels = 0;
779   gint atag = 0;
780
781   if (!fourcc)                  /* sometimes the fourcc is omitted, we fallback to the Subtype in the StreamIndex node */
782     fourcc = (gchar *) xmlGetProp (node->parent, (xmlChar *) "Subtype");
783
784   if (fourcc) {
785     caps = _gst_mss_stream_audio_caps_from_fourcc (fourcc);
786   } else if (audiotag) {
787     atag = g_ascii_strtoull (audiotag, NULL, 10);
788     caps = _gst_mss_stream_audio_caps_from_audio_tag (atag);
789   }
790
791   if (!caps)
792     goto end;
793
794   structure = gst_caps_get_structure (caps, 0);
795   if (codec_data_str && strlen (codec_data_str)) {
796     codec_data = gst_buffer_from_hex_string ((gchar *) codec_data_str);
797   }
798
799   if (rate_str)
800     rate = (gint) g_ascii_strtoull (rate_str, NULL, 10);
801   if (channels_str)
802     channels = (int) g_ascii_strtoull (channels_str, NULL, 10);
803   if (depth_str)
804     depth = (gint) g_ascii_strtoull (depth_str, NULL, 10);
805   if (block_align_str)
806     block_align = (int) g_ascii_strtoull (block_align_str, NULL, 10);
807
808   if (!codec_data) {
809     gint codec_data_len;
810     codec_data_str = (gchar *) xmlGetProp (node, (xmlChar *) "WaveFormatEx");
811
812     if (codec_data_str != NULL) {
813       codec_data_len = strlen (codec_data_str) / 2;
814
815       /* a WAVEFORMATEX structure is 18 bytes */
816       if (codec_data_str && codec_data_len >= 18) {
817         GstMapInfo mapinfo;
818         codec_data = gst_buffer_from_hex_string ((gchar *) codec_data_str);
819
820         /* since this is a WAVEFORMATEX, try to get the block_align and rate */
821         gst_buffer_map (codec_data, &mapinfo, GST_MAP_READ);
822         if (!channels_str) {
823           channels = GST_READ_UINT16_LE (mapinfo.data + 2);
824         }
825         if (!rate_str) {
826           rate = GST_READ_UINT32_LE (mapinfo.data + 4);
827         }
828         if (!block_align) {
829           block_align = GST_READ_UINT16_LE (mapinfo.data + 12);
830         }
831         if (!depth) {
832           depth = GST_READ_UINT16_LE (mapinfo.data + 14);
833         }
834         gst_buffer_unmap (codec_data, &mapinfo);
835
836         /* Consume all the WAVEFORMATEX structure, and pass only the rest of
837          * the data as the codec private data */
838         gst_buffer_resize (codec_data, 18, -1);
839       } else {
840         GST_WARNING ("Dropping WaveFormatEx: data is %d bytes, "
841             "but at least 18 bytes are expected", codec_data_len);
842       }
843     }
844   }
845
846   if (!codec_data && ((fourcc && strcmp (fourcc, "AACL") == 0) || atag == 255)
847       && rate && channels) {
848     codec_data = _make_aacl_codec_data (rate, channels);
849   }
850
851   if (block_align)
852     gst_structure_set (structure, "block_align", G_TYPE_INT, block_align, NULL);
853
854   if (channels)
855     gst_structure_set (structure, "channels", G_TYPE_INT, channels, NULL);
856
857   if (rate)
858     gst_structure_set (structure, "rate", G_TYPE_INT, rate, NULL);
859
860   if (depth)
861     gst_structure_set (structure, "depth", G_TYPE_INT, depth, NULL);
862
863   if (q->bitrate)
864     gst_structure_set (structure, "bitrate", G_TYPE_INT, (int) q->bitrate,
865         NULL);
866
867   if (codec_data)
868     gst_structure_set (structure, "codec_data", GST_TYPE_BUFFER, codec_data,
869         NULL);
870
871 end:
872   if (codec_data)
873     gst_buffer_unref (codec_data);
874   xmlFree (fourcc);
875   xmlFree (audiotag);
876   xmlFree (channels_str);
877   xmlFree (rate_str);
878   xmlFree (depth_str);
879   xmlFree (block_align_str);
880   xmlFree (codec_data_str);
881
882   return caps;
883 }
884
885 void
886 gst_mss_stream_set_active (GstMssStream * stream, gboolean active)
887 {
888   stream->active = active;
889 }
890
891 guint64
892 gst_mss_stream_get_timescale (GstMssStream * stream)
893 {
894   gchar *timescale;
895   guint64 ts = DEFAULT_TIMESCALE;
896
897   timescale =
898       (gchar *) xmlGetProp (stream->xmlnode, (xmlChar *) MSS_PROP_TIMESCALE);
899   if (!timescale) {
900     timescale =
901         (gchar *) xmlGetProp (stream->xmlnode->parent,
902         (xmlChar *) MSS_PROP_TIMESCALE);
903   }
904
905   if (timescale) {
906     ts = g_ascii_strtoull (timescale, NULL, 10);
907     xmlFree (timescale);
908   }
909   return ts;
910 }
911
912 guint64
913 gst_mss_manifest_get_timescale (GstMssManifest * manifest)
914 {
915   gchar *timescale;
916   guint64 ts = DEFAULT_TIMESCALE;
917
918   timescale =
919       (gchar *) xmlGetProp (manifest->xmlrootnode,
920       (xmlChar *) MSS_PROP_TIMESCALE);
921   if (timescale) {
922     ts = g_ascii_strtoull (timescale, NULL, 10);
923     xmlFree (timescale);
924   }
925   return ts;
926 }
927
928 guint64
929 gst_mss_manifest_get_duration (GstMssManifest * manifest)
930 {
931   gchar *duration;
932   guint64 dur = 0;
933
934   /* try the property */
935   duration =
936       (gchar *) xmlGetProp (manifest->xmlrootnode,
937       (xmlChar *) MSS_PROP_STREAM_DURATION);
938   if (duration) {
939     dur = g_ascii_strtoull (duration, NULL, 10);
940     xmlFree (duration);
941   }
942   /* else use the fragment list */
943   if (dur <= 0) {
944     guint64 max_dur = 0;
945     GSList *iter;
946
947     for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
948       GstMssStream *stream = iter->data;
949
950       if (stream->active) {
951         if (stream->fragments) {
952           GList *l = g_list_last (stream->fragments);
953           GstMssStreamFragment *fragment = (GstMssStreamFragment *) l->data;
954           guint64 frag_dur =
955               fragment->time + fragment->duration * fragment->repetitions;
956           max_dur = MAX (frag_dur, max_dur);
957         }
958       }
959     }
960
961     if (max_dur != 0)
962       dur = max_dur;
963   }
964
965   return dur;
966 }
967
968
969 /*
970  * Gets the duration in nanoseconds
971  */
972 GstClockTime
973 gst_mss_manifest_get_gst_duration (GstMssManifest * manifest)
974 {
975   guint64 duration = -1;
976   guint64 timescale;
977   GstClockTime gstdur = GST_CLOCK_TIME_NONE;
978
979   duration = gst_mss_manifest_get_duration (manifest);
980   timescale = gst_mss_manifest_get_timescale (manifest);
981
982   if (duration != -1 && timescale != -1)
983     gstdur =
984         (GstClockTime) gst_util_uint64_scale_round (duration, GST_SECOND,
985         timescale);
986
987   return gstdur;
988 }
989
990 GstClockTime
991 gst_mss_manifest_get_min_fragment_duration (GstMssManifest * manifest)
992 {
993   GSList *iter;
994   GstClockTime dur = GST_CLOCK_TIME_NONE;
995   GstClockTime iter_dur;
996
997   for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
998     GstMssStream *stream = iter->data;
999
1000     iter_dur = gst_mss_stream_get_fragment_gst_duration (stream);
1001     if (iter_dur != GST_CLOCK_TIME_NONE && iter_dur != 0) {
1002       if (GST_CLOCK_TIME_IS_VALID (dur)) {
1003         dur = MIN (dur, iter_dur);
1004       } else {
1005         dur = iter_dur;
1006       }
1007     }
1008   }
1009
1010   return dur;
1011 }
1012
1013 GstCaps *
1014 gst_mss_stream_get_caps (GstMssStream * stream)
1015 {
1016   GstMssStreamType streamtype = gst_mss_stream_get_type (stream);
1017   GstMssStreamQuality *qualitylevel = stream->current_quality->data;
1018   GstCaps *caps = NULL;
1019
1020   if (streamtype == MSS_STREAM_TYPE_VIDEO)
1021     caps = _gst_mss_stream_video_caps_from_qualitylevel_xml (qualitylevel);
1022   else if (streamtype == MSS_STREAM_TYPE_AUDIO)
1023     caps = _gst_mss_stream_audio_caps_from_qualitylevel_xml (qualitylevel);
1024
1025   return caps;
1026 }
1027
1028 GstFlowReturn
1029 gst_mss_stream_get_fragment_url (GstMssStream * stream, gchar ** url)
1030 {
1031   gchar *tmp;
1032   gchar *start_time_str;
1033   guint64 time;
1034   GstMssStreamFragment *fragment;
1035   GstMssStreamQuality *quality = stream->current_quality->data;
1036
1037   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
1038
1039   if (stream->current_fragment == NULL) /* stream is over */
1040     return GST_FLOW_EOS;
1041
1042   fragment = stream->current_fragment->data;
1043
1044   time =
1045       fragment->time + fragment->duration * stream->fragment_repetition_index;
1046   start_time_str = g_strdup_printf ("%" G_GUINT64_FORMAT, time);
1047
1048   tmp = g_regex_replace_literal (stream->regex_bitrate, stream->url,
1049       strlen (stream->url), 0, quality->bitrate_str, 0, NULL);
1050   *url = g_regex_replace_literal (stream->regex_position, tmp,
1051       strlen (tmp), 0, start_time_str, 0, NULL);
1052
1053   g_free (tmp);
1054   g_free (start_time_str);
1055
1056   if (*url == NULL)
1057     return GST_FLOW_ERROR;
1058
1059   return GST_FLOW_OK;
1060 }
1061
1062 GstClockTime
1063 gst_mss_stream_get_fragment_gst_timestamp (GstMssStream * stream)
1064 {
1065   guint64 time;
1066   guint64 timescale;
1067   GstMssStreamFragment *fragment;
1068
1069   g_return_val_if_fail (stream->active, GST_CLOCK_TIME_NONE);
1070
1071   if (!stream->current_fragment) {
1072     GList *last = g_list_last (stream->fragments);
1073     if (last == NULL)
1074       return GST_CLOCK_TIME_NONE;
1075
1076     fragment = last->data;
1077     time = fragment->time + (fragment->duration * fragment->repetitions);
1078   } else {
1079     fragment = stream->current_fragment->data;
1080     time =
1081         fragment->time +
1082         (fragment->duration * stream->fragment_repetition_index);
1083   }
1084
1085   timescale = gst_mss_stream_get_timescale (stream);
1086   return (GstClockTime) gst_util_uint64_scale_round (time, GST_SECOND,
1087       timescale);
1088 }
1089
1090 GstClockTime
1091 gst_mss_stream_get_fragment_gst_duration (GstMssStream * stream)
1092 {
1093   guint64 dur;
1094   guint64 timescale;
1095   GstMssStreamFragment *fragment;
1096
1097   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
1098
1099   if (!stream->current_fragment)
1100     return GST_CLOCK_TIME_NONE;
1101
1102   fragment = stream->current_fragment->data;
1103
1104   dur = fragment->duration;
1105   timescale = gst_mss_stream_get_timescale (stream);
1106   return (GstClockTime) gst_util_uint64_scale_round (dur, GST_SECOND,
1107       timescale);
1108 }
1109
1110 gboolean
1111 gst_mss_stream_has_next_fragment (GstMssStream * stream)
1112 {
1113   g_return_val_if_fail (stream->active, FALSE);
1114
1115   if (stream->current_fragment == NULL)
1116     return FALSE;
1117
1118   return TRUE;
1119 }
1120
1121 GstFlowReturn
1122 gst_mss_stream_advance_fragment (GstMssStream * stream)
1123 {
1124   GstMssStreamFragment *fragment;
1125   const gchar *stream_type_name =
1126       gst_mss_stream_type_name (gst_mss_stream_get_type (stream));
1127
1128   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
1129
1130   if (stream->current_fragment == NULL)
1131     return GST_FLOW_EOS;
1132
1133   fragment = stream->current_fragment->data;
1134   stream->fragment_repetition_index++;
1135   if (stream->fragment_repetition_index < fragment->repetitions)
1136     goto beach;
1137
1138   stream->fragment_repetition_index = 0;
1139   stream->current_fragment = g_list_next (stream->current_fragment);
1140
1141   GST_DEBUG ("Advanced to fragment #%d on %s stream", fragment->number,
1142       stream_type_name);
1143   if (stream->current_fragment == NULL)
1144     return GST_FLOW_EOS;
1145
1146 beach:
1147   gst_mss_fragment_parser_clear (&stream->fragment_parser);
1148   gst_mss_fragment_parser_init (&stream->fragment_parser);
1149   return GST_FLOW_OK;
1150 }
1151
1152 GstFlowReturn
1153 gst_mss_stream_regress_fragment (GstMssStream * stream)
1154 {
1155   GstMssStreamFragment *fragment;
1156   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
1157
1158   if (stream->current_fragment == NULL)
1159     return GST_FLOW_EOS;
1160
1161   fragment = stream->current_fragment->data;
1162   if (stream->fragment_repetition_index == 0) {
1163     stream->current_fragment = g_list_previous (stream->current_fragment);
1164     if (stream->current_fragment == NULL)
1165       return GST_FLOW_EOS;
1166     fragment = stream->current_fragment->data;
1167     stream->fragment_repetition_index = fragment->repetitions - 1;
1168   } else {
1169     stream->fragment_repetition_index--;
1170   }
1171   return GST_FLOW_OK;
1172 }
1173
1174 const gchar *
1175 gst_mss_stream_type_name (GstMssStreamType streamtype)
1176 {
1177   switch (streamtype) {
1178     case MSS_STREAM_TYPE_VIDEO:
1179       return "video";
1180     case MSS_STREAM_TYPE_AUDIO:
1181       return "audio";
1182     case MSS_STREAM_TYPE_UNKNOWN:
1183     default:
1184       return "unknown";
1185   }
1186 }
1187
1188 /*
1189  * Seeks all streams to the fragment that contains the set time
1190  *
1191  * @forward: if this is forward playback
1192  * @time: time in nanoseconds
1193  */
1194 void
1195 gst_mss_manifest_seek (GstMssManifest * manifest, gboolean forward, gint64 time)
1196 {
1197   GSList *iter;
1198
1199   for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
1200     GstMssStream *stream = iter->data;
1201
1202     gst_mss_manifest_live_adapter_clear (stream);
1203     gst_mss_stream_seek (stream, forward, 0, time, NULL);
1204   }
1205 }
1206
1207 #define SNAP_AFTER(forward,flags) \
1208     ((forward && (flags & GST_SEEK_FLAG_SNAP_AFTER)) || \
1209     (!forward && (flags & GST_SEEK_FLAG_SNAP_BEFORE)))
1210
1211 /*
1212  * Seeks this stream to the fragment that contains the sample at time
1213  *
1214  * @time: time in nanoseconds
1215  */
1216 void
1217 gst_mss_stream_seek (GstMssStream * stream, gboolean forward,
1218     GstSeekFlags flags, gint64 time, gint64 * final_time)
1219 {
1220   GList *iter;
1221   guint64 timescale;
1222   GstMssStreamFragment *fragment = NULL;
1223
1224   timescale = gst_mss_stream_get_timescale (stream);
1225   time = gst_util_uint64_scale_round (time, timescale, GST_SECOND);
1226
1227   GST_DEBUG ("Stream %s seeking to %" G_GUINT64_FORMAT, stream->url, time);
1228   for (iter = stream->fragments; iter; iter = g_list_next (iter)) {
1229     fragment = iter->data;
1230     if (fragment->time + fragment->repetitions * fragment->duration > time) {
1231       stream->current_fragment = iter;
1232       stream->fragment_repetition_index =
1233           (time - fragment->time) / fragment->duration;
1234       if (((time - fragment->time) % fragment->duration) == 0) {
1235
1236         /* for reverse playback, start from the previous fragment when we are
1237          * exactly at a limit */
1238         if (!forward)
1239           stream->fragment_repetition_index--;
1240       } else if (SNAP_AFTER (forward, flags))
1241         stream->fragment_repetition_index++;
1242
1243       if (stream->fragment_repetition_index == fragment->repetitions) {
1244         /* move to the next one */
1245         stream->fragment_repetition_index = 0;
1246         stream->current_fragment = g_list_next (iter);
1247         fragment =
1248             stream->current_fragment ? stream->current_fragment->data : NULL;
1249
1250       } else if (stream->fragment_repetition_index == -1) {
1251         if (g_list_previous (iter)) {
1252           stream->current_fragment = g_list_previous (iter);
1253           fragment = stream->current_fragment->data;
1254           g_assert (fragment);
1255           stream->fragment_repetition_index = fragment->repetitions - 1;
1256         } else {
1257           stream->fragment_repetition_index = 0;
1258         }
1259       }
1260
1261       break;
1262     }
1263
1264   }
1265
1266   GST_DEBUG ("Stream %s seeked to fragment time %" G_GUINT64_FORMAT
1267       " repetition %u", stream->url,
1268       fragment ? fragment->time : GST_CLOCK_TIME_NONE,
1269       stream->fragment_repetition_index);
1270   if (final_time) {
1271     if (fragment) {
1272       *final_time = gst_util_uint64_scale_round (fragment->time +
1273           stream->fragment_repetition_index * fragment->duration,
1274           GST_SECOND, timescale);
1275     } else {
1276       GstMssStreamFragment *last_fragment = g_list_last (iter)->data;
1277       *final_time = gst_util_uint64_scale_round (last_fragment->time +
1278           last_fragment->repetitions * last_fragment->duration,
1279           GST_SECOND, timescale);
1280     }
1281   }
1282 }
1283
1284 guint64
1285 gst_mss_manifest_get_current_bitrate (GstMssManifest * manifest)
1286 {
1287   guint64 bitrate = 0;
1288   GSList *iter;
1289
1290   for (iter = gst_mss_manifest_get_streams (manifest); iter;
1291       iter = g_slist_next (iter)) {
1292     GstMssStream *stream = iter->data;
1293     if (stream->active && stream->current_quality) {
1294       GstMssStreamQuality *q = stream->current_quality->data;
1295
1296       bitrate += q->bitrate;
1297     }
1298   }
1299
1300   return bitrate;
1301 }
1302
1303 gboolean
1304 gst_mss_manifest_is_live (GstMssManifest * manifest)
1305 {
1306   return manifest->is_live;
1307 }
1308
1309 static void
1310 gst_mss_stream_reload_fragments (GstMssStream * stream, xmlNodePtr streamIndex)
1311 {
1312   xmlNodePtr iter;
1313   gint64 current_gst_time;
1314   GstMssFragmentListBuilder builder;
1315
1316   current_gst_time = gst_mss_stream_get_fragment_gst_timestamp (stream);
1317
1318   gst_mss_fragment_list_builder_init (&builder);
1319
1320   GST_DEBUG ("Current position: %" GST_TIME_FORMAT,
1321       GST_TIME_ARGS (current_gst_time));
1322
1323   for (iter = streamIndex->children; iter; iter = iter->next) {
1324     if (node_has_type (iter, MSS_NODE_STREAM_FRAGMENT)) {
1325       gst_mss_fragment_list_builder_add (&builder, iter);
1326     } else {
1327       /* TODO gst log this */
1328     }
1329   }
1330
1331   /* store the new fragments list */
1332   if (builder.fragments) {
1333     g_list_free_full (stream->fragments, g_free);
1334     stream->fragments = g_list_reverse (builder.fragments);
1335     stream->current_fragment = stream->fragments;
1336     /* TODO Verify how repositioning here works for reverse
1337      * playback - it might start from the wrong fragment */
1338     gst_mss_stream_seek (stream, TRUE, 0, current_gst_time, NULL);
1339   }
1340 }
1341
1342 static void
1343 gst_mss_manifest_reload_fragments_from_xml (GstMssManifest * manifest,
1344     xmlNodePtr root)
1345 {
1346   xmlNodePtr nodeiter;
1347   GSList *streams = manifest->streams;
1348
1349   /* we assume the server is providing the streams in the same order in
1350    * every manifest */
1351   for (nodeiter = root->children; nodeiter && streams;
1352       nodeiter = nodeiter->next) {
1353     if (nodeiter->type == XML_ELEMENT_NODE
1354         && (strcmp ((const char *) nodeiter->name, "StreamIndex") == 0)) {
1355       gst_mss_stream_reload_fragments (streams->data, nodeiter);
1356       streams = g_slist_next (streams);
1357     }
1358   }
1359 }
1360
1361 void
1362 gst_mss_manifest_reload_fragments (GstMssManifest * manifest, GstBuffer * data)
1363 {
1364   xmlDocPtr xml;
1365   xmlNodePtr root;
1366   GstMapInfo info;
1367
1368   gst_buffer_map (data, &info, GST_MAP_READ);
1369
1370   xml = xmlReadMemory ((const gchar *) info.data,
1371       info.size, "manifest", NULL, 0);
1372   root = xmlDocGetRootElement (xml);
1373
1374   gst_mss_manifest_reload_fragments_from_xml (manifest, root);
1375
1376   xmlFreeDoc (xml);
1377
1378   gst_buffer_unmap (data, &info);
1379 }
1380
1381 gboolean
1382 gst_mss_stream_select_bitrate (GstMssStream * stream, guint64 bitrate)
1383 {
1384   GList *iter = stream->current_quality;
1385   GList *next;
1386   GstMssStreamQuality *q = iter->data;
1387
1388   while (q->bitrate > bitrate) {
1389     next = g_list_previous (iter);
1390     if (next) {
1391       iter = next;
1392       q = iter->data;
1393     } else {
1394       break;
1395     }
1396   }
1397
1398   while (q->bitrate < bitrate) {
1399     GstMssStreamQuality *next_q;
1400     next = g_list_next (iter);
1401     if (next) {
1402       next_q = next->data;
1403       if (next_q->bitrate < bitrate) {
1404         iter = next;
1405         q = iter->data;
1406       } else {
1407         break;
1408       }
1409     } else {
1410       break;
1411     }
1412   }
1413
1414   if (iter == stream->current_quality)
1415     return FALSE;
1416   stream->current_quality = iter;
1417   return TRUE;
1418 }
1419
1420 guint64
1421 gst_mss_stream_get_current_bitrate (GstMssStream * stream)
1422 {
1423   GstMssStreamQuality *q;
1424   if (stream->current_quality == NULL)
1425     return 0;
1426
1427   q = stream->current_quality->data;
1428   return q->bitrate;
1429 }
1430
1431 /**
1432  * gst_mss_manifest_change_bitrate:
1433  * @manifest: the manifest
1434  * @bitrate: the maximum bitrate to use (bps)
1435  *
1436  * Iterates over the active streams and changes their bitrates to the maximum
1437  * value so that the bitrates of all streams are not larger than
1438  * @bitrate.
1439  *
1440  * Return: %TRUE if any stream changed its bitrate
1441  */
1442 gboolean
1443 gst_mss_manifest_change_bitrate (GstMssManifest * manifest, guint64 bitrate)
1444 {
1445   gboolean ret = FALSE;
1446   GSList *iter;
1447
1448   /* TODO This algorithm currently sets the same bitrate for all streams,
1449    * it should actually use the sum of all streams bitrates to compare to
1450    * the target value */
1451
1452   if (bitrate == 0) {
1453     /* use maximum */
1454     bitrate = G_MAXUINT64;
1455   }
1456
1457   for (iter = gst_mss_manifest_get_streams (manifest); iter;
1458       iter = g_slist_next (iter)) {
1459     GstMssStream *stream = iter->data;
1460     if (stream->active) {
1461       ret = ret | gst_mss_stream_select_bitrate (stream, bitrate);
1462     }
1463   }
1464
1465   return ret;
1466 }
1467
1468 static GstBuffer *
1469 gst_buffer_from_hex_string (const gchar * s)
1470 {
1471   GstBuffer *buffer = NULL;
1472   gint len;
1473   gchar ts[3];
1474   guint8 *data;
1475   gint i;
1476   GstMapInfo info;
1477
1478   len = strlen (s);
1479   if (len & 1)
1480     return NULL;
1481
1482   buffer = gst_buffer_new_and_alloc (len / 2);
1483   gst_buffer_map (buffer, &info, GST_MAP_WRITE);
1484   data = info.data;
1485   for (i = 0; i < len / 2; i++) {
1486     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1])) {
1487       gst_buffer_unref (buffer);
1488       return NULL;
1489     }
1490
1491     ts[0] = s[i * 2 + 0];
1492     ts[1] = s[i * 2 + 1];
1493     ts[2] = 0;
1494
1495     data[i] = (guint8) strtoul (ts, NULL, 16);
1496   }
1497
1498   gst_buffer_unmap (buffer, &info);
1499   return buffer;
1500 }
1501
1502 const gchar *
1503 gst_mss_stream_get_lang (GstMssStream * stream)
1504 {
1505   return stream->lang;
1506 }
1507
1508 const gchar *
1509 gst_mss_stream_get_name (GstMssStream * stream)
1510 {
1511   return stream->name;
1512 }
1513
1514 static GstClockTime
1515 gst_mss_manifest_get_dvr_window_length_clock_time (GstMssManifest * manifest)
1516 {
1517   gint64 timescale;
1518
1519   /* the entire file is always available for non-live streams */
1520   if (manifest->dvr_window == 0)
1521     return GST_CLOCK_TIME_NONE;
1522
1523   timescale = gst_mss_manifest_get_timescale (manifest);
1524   return (GstClockTime) gst_util_uint64_scale_round (manifest->dvr_window,
1525       GST_SECOND, timescale);
1526 }
1527
1528 static gboolean
1529 gst_mss_stream_get_live_seek_range (GstMssStream * stream, gint64 * start,
1530     gint64 * stop)
1531 {
1532   GList *l;
1533   GstMssStreamFragment *fragment;
1534   guint64 timescale = gst_mss_stream_get_timescale (stream);
1535
1536   g_return_val_if_fail (stream->active, FALSE);
1537
1538   /* XXX: assumes all the data in the stream is still available */
1539   l = g_list_first (stream->fragments);
1540   fragment = (GstMssStreamFragment *) l->data;
1541   *start = gst_util_uint64_scale_round (fragment->time, GST_SECOND, timescale);
1542
1543   l = g_list_last (stream->fragments);
1544   fragment = (GstMssStreamFragment *) l->data;
1545   *stop = gst_util_uint64_scale_round (fragment->time + fragment->duration *
1546       fragment->repetitions, GST_SECOND, timescale);
1547
1548   return TRUE;
1549 }
1550
1551 gboolean
1552 gst_mss_manifest_get_live_seek_range (GstMssManifest * manifest, gint64 * start,
1553     gint64 * stop)
1554 {
1555   GSList *iter;
1556   gboolean ret = FALSE;
1557
1558   for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
1559     GstMssStream *stream = iter->data;
1560
1561     if (stream->active) {
1562       /* FIXME: bound this correctly for multiple streams */
1563       if (!(ret = gst_mss_stream_get_live_seek_range (stream, start, stop)))
1564         break;
1565     }
1566   }
1567
1568   if (ret && gst_mss_manifest_is_live (manifest)) {
1569     GstClockTime dvr_window =
1570         gst_mss_manifest_get_dvr_window_length_clock_time (manifest);
1571
1572     if (GST_CLOCK_TIME_IS_VALID (dvr_window) && *stop - *start > dvr_window) {
1573       *start = *stop - dvr_window;
1574     }
1575   }
1576
1577   return ret;
1578 }
1579
1580 void
1581 gst_mss_manifest_live_adapter_push (GstMssStream * stream, GstBuffer * buffer)
1582 {
1583   gst_adapter_push (stream->live_adapter, buffer);
1584 }
1585
1586 gsize
1587 gst_mss_manifest_live_adapter_available (GstMssStream * stream)
1588 {
1589   return gst_adapter_available (stream->live_adapter);
1590 }
1591
1592 GstBuffer *
1593 gst_mss_manifest_live_adapter_take_buffer (GstMssStream * stream, gsize nbytes)
1594 {
1595   return gst_adapter_take_buffer (stream->live_adapter, nbytes);
1596 }
1597
1598 void
1599 gst_mss_manifest_live_adapter_clear (GstMssStream * stream)
1600 {
1601   if (stream->live_adapter)
1602     gst_adapter_clear (stream->live_adapter);
1603 }
1604
1605 gboolean
1606 gst_mss_stream_fragment_parsing_needed (GstMssStream * stream)
1607 {
1608   return stream->fragment_parser.status == GST_MSS_FRAGMENT_HEADER_PARSER_INIT;
1609 }
1610
1611 void
1612 gst_mss_stream_parse_fragment (GstMssStream * stream, GstBuffer * buffer)
1613 {
1614   const gchar *stream_type_name;
1615   guint8 index;
1616   GstMoofBox *moof;
1617   GstTrafBox *traf;
1618
1619   if (!stream->has_live_fragments)
1620     return;
1621
1622   if (!gst_mss_fragment_parser_add_buffer (&stream->fragment_parser, buffer))
1623     return;
1624
1625   moof = stream->fragment_parser.moof;
1626   traf = &g_array_index (moof->traf, GstTrafBox, 0);
1627
1628   stream_type_name =
1629       gst_mss_stream_type_name (gst_mss_stream_get_type (stream));
1630
1631   for (index = 0; index < traf->tfrf->entries_count; index++) {
1632     GstTfrfBoxEntry *entry =
1633         &g_array_index (traf->tfrf->entries, GstTfrfBoxEntry, index);
1634     GList *l = g_list_last (stream->fragments);
1635     GstMssStreamFragment *last;
1636     GstMssStreamFragment *fragment;
1637     guint64 parsed_time = entry->time;
1638     guint64 parsed_duration = entry->duration;
1639
1640     if (l == NULL)
1641       break;
1642
1643     last = (GstMssStreamFragment *) l->data;
1644
1645     /* only add the fragment to the list if it's outside the time in the
1646      * current list */
1647     if (last->time >= entry->time)
1648       continue;
1649
1650     fragment = g_new (GstMssStreamFragment, 1);
1651     fragment->number = last->number + 1;
1652     fragment->repetitions = 1;
1653     fragment->time = parsed_time;
1654     fragment->duration = parsed_duration;
1655
1656     stream->fragments = g_list_append (stream->fragments, fragment);
1657     GST_LOG ("Adding fragment number: %u to %s stream, time: %"
1658         G_GUINT64_FORMAT ", duration: %" G_GUINT64_FORMAT ", repetitions: %u",
1659         fragment->number, stream_type_name, fragment->time,
1660         fragment->duration, fragment->repetitions);
1661   }
1662 }