d61c0ea9e207b1d68669b4f102dca171a4f574b4
[platform/upstream/gstreamer.git] / ext / smoothstreaming / gstmssmanifest.c
1 /* GStreamer
2  * Copyright (C) 2012 Smart TV Alliance
3  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>, Collabora Ltd.
4  *
5  * gstmssmanifest.c:
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <glib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <libxml/parser.h>
28 #include <libxml/tree.h>
29
30 /* for parsing h264 codec data */
31 #include <gst/codecparsers/gsth264parser.h>
32
33 #include "gstmssmanifest.h"
34
35 #define DEFAULT_TIMESCALE             10000000
36
37 #define MSS_NODE_STREAM_FRAGMENT      "c"
38 #define MSS_NODE_STREAM_QUALITY       "QualityLevel"
39
40 #define MSS_PROP_BITRATE              "Bitrate"
41 #define MSS_PROP_DURATION             "d"
42 #define MSS_PROP_NUMBER               "n"
43 #define MSS_PROP_STREAM_DURATION      "Duration"
44 #define MSS_PROP_TIME                 "t"
45 #define MSS_PROP_TIMESCALE            "TimeScale"
46 #define MSS_PROP_URL                  "Url"
47
48 typedef struct _GstMssStreamFragment
49 {
50   guint number;
51   guint64 time;
52   guint64 duration;
53 } GstMssStreamFragment;
54
55 typedef struct _GstMssStreamQuality
56 {
57   xmlNodePtr xmlnode;
58
59   gchar *bitrate_str;
60   guint64 bitrate;
61 } GstMssStreamQuality;
62
63 struct _GstMssStream
64 {
65   xmlNodePtr xmlnode;
66
67   gboolean active;              /* if the stream is currently being used */
68   gint selectedQualityIndex;
69
70   GList *fragments;
71   GList *qualities;
72
73   gchar *url;
74
75   GList *current_fragment;
76   GList *current_quality;
77
78   /* TODO move this to somewhere static */
79   GRegex *regex_bitrate;
80   GRegex *regex_position;
81 };
82
83 struct _GstMssManifest
84 {
85   xmlDocPtr xml;
86   xmlNodePtr xmlrootnode;
87
88   gboolean is_live;
89
90   GSList *streams;
91 };
92
93 static GstBuffer *gst_buffer_from_hex_string (const gchar * s);
94
95 static gboolean
96 node_has_type (xmlNodePtr node, const gchar * name)
97 {
98   return strcmp ((gchar *) node->name, name) == 0;
99 }
100
101 static GstMssStreamQuality *
102 gst_mss_stream_quality_new (xmlNodePtr node)
103 {
104   GstMssStreamQuality *q = g_slice_new (GstMssStreamQuality);
105
106   q->xmlnode = node;
107   q->bitrate_str = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_BITRATE);
108
109   if (q->bitrate_str != NULL)
110     q->bitrate = g_ascii_strtoull (q->bitrate_str, NULL, 10);
111   else
112     q->bitrate = 0;
113
114   return q;
115 }
116
117 static void
118 gst_mss_stream_quality_free (GstMssStreamQuality * quality)
119 {
120   g_return_if_fail (quality != NULL);
121
122   xmlFree (quality->bitrate_str);
123   g_slice_free (GstMssStreamQuality, quality);
124 }
125
126 static gint
127 compare_bitrate (GstMssStreamQuality * a, GstMssStreamQuality * b)
128 {
129   if (a->bitrate > b->bitrate)
130     return 1;
131   if (a->bitrate < b->bitrate)
132     return -1;
133   return 0;
134
135 }
136
137 static void
138 _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
139 {
140   xmlNodePtr iter;
141   GstMssStreamFragment *previous_fragment = NULL;
142   guint fragment_number = 0;
143   guint64 fragment_time_accum = 0;
144
145   stream->xmlnode = node;
146
147   /* get the base url path generator */
148   stream->url = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_URL);
149
150   for (iter = node->children; iter; iter = iter->next) {
151     if (node_has_type (iter, MSS_NODE_STREAM_FRAGMENT)) {
152       gchar *duration_str;
153       gchar *time_str;
154       gchar *seqnum_str;
155       GstMssStreamFragment *fragment = g_new (GstMssStreamFragment, 1);
156
157       duration_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_DURATION);
158       time_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_TIME);
159       seqnum_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_NUMBER);
160
161       /* use the node's seq number or use the previous + 1 */
162       if (seqnum_str) {
163         fragment->number = g_ascii_strtoull (seqnum_str, NULL, 10);
164         xmlFree (seqnum_str);
165         fragment_number = fragment->number;
166       } else {
167         fragment->number = fragment_number;
168       }
169       fragment_number = fragment->number + 1;
170
171       if (time_str) {
172         fragment->time = g_ascii_strtoull (time_str, NULL, 10);
173
174         xmlFree (time_str);
175         fragment_time_accum = fragment->time;
176       } else {
177         fragment->time = fragment_time_accum;
178       }
179
180       /* if we have a previous fragment, means we need to set its duration */
181       if (previous_fragment)
182         previous_fragment->duration = fragment->time - previous_fragment->time;
183
184       if (duration_str) {
185         fragment->duration = g_ascii_strtoull (duration_str, NULL, 10);
186
187         previous_fragment = NULL;
188         fragment_time_accum += fragment->duration;
189         xmlFree (duration_str);
190       } else {
191         /* store to set the duration at the next iteration */
192         previous_fragment = fragment;
193       }
194
195       /* we reverse it later */
196       stream->fragments = g_list_prepend (stream->fragments, fragment);
197     } else if (node_has_type (iter, MSS_NODE_STREAM_QUALITY)) {
198       GstMssStreamQuality *quality = gst_mss_stream_quality_new (iter);
199       stream->qualities = g_list_prepend (stream->qualities, quality);
200     } else {
201       /* TODO gst log this */
202     }
203   }
204
205   stream->fragments = g_list_reverse (stream->fragments);
206
207   /* order them from smaller to bigger based on bitrates */
208   stream->qualities =
209       g_list_sort (stream->qualities, (GCompareFunc) compare_bitrate);
210
211   stream->current_fragment = stream->fragments;
212   stream->current_quality = stream->qualities;
213
214   stream->regex_bitrate = g_regex_new ("\\{[Bb]itrate\\}", 0, 0, NULL);
215   stream->regex_position = g_regex_new ("\\{start[ _]time\\}", 0, 0, NULL);
216 }
217
218 GstMssManifest *
219 gst_mss_manifest_new (GstBuffer * data)
220 {
221   GstMssManifest *manifest;
222   xmlNodePtr root;
223   xmlNodePtr nodeiter;
224   gchar *live_str;
225   GstMapInfo mapinfo;
226
227   if (!gst_buffer_map (data, &mapinfo, GST_MAP_READ)) {
228     return NULL;
229   }
230
231   manifest = g_malloc0 (sizeof (GstMssManifest));
232
233   manifest->xml = xmlReadMemory ((const gchar *) mapinfo.data,
234       mapinfo.size, "manifest", NULL, 0);
235   root = manifest->xmlrootnode = xmlDocGetRootElement (manifest->xml);
236
237   live_str = (gchar *) xmlGetProp (root, (xmlChar *) "IsLive");
238   if (live_str) {
239     manifest->is_live = g_ascii_strcasecmp (live_str, "true") == 0;
240     xmlFree (live_str);
241   }
242
243   for (nodeiter = root->children; nodeiter; nodeiter = nodeiter->next) {
244     if (nodeiter->type == XML_ELEMENT_NODE
245         && (strcmp ((const char *) nodeiter->name, "StreamIndex") == 0)) {
246       GstMssStream *stream = g_new0 (GstMssStream, 1);
247
248       manifest->streams = g_slist_append (manifest->streams, stream);
249       _gst_mss_stream_init (stream, nodeiter);
250     }
251   }
252
253   gst_buffer_unmap (data, &mapinfo);
254
255   return manifest;
256 }
257
258 static void
259 gst_mss_stream_free (GstMssStream * stream)
260 {
261   g_list_free_full (stream->fragments, g_free);
262   g_list_free_full (stream->qualities,
263       (GDestroyNotify) gst_mss_stream_quality_free);
264   xmlFree (stream->url);
265   g_regex_unref (stream->regex_position);
266   g_regex_unref (stream->regex_bitrate);
267   g_free (stream);
268 }
269
270 void
271 gst_mss_manifest_free (GstMssManifest * manifest)
272 {
273   g_return_if_fail (manifest != NULL);
274
275   g_slist_free_full (manifest->streams, (GDestroyNotify) gst_mss_stream_free);
276
277   xmlFreeDoc (manifest->xml);
278   g_free (manifest);
279 }
280
281 GSList *
282 gst_mss_manifest_get_streams (GstMssManifest * manifest)
283 {
284   return manifest->streams;
285 }
286
287 GstMssStreamType
288 gst_mss_stream_get_type (GstMssStream * stream)
289 {
290   gchar *prop = (gchar *) xmlGetProp (stream->xmlnode, (xmlChar *) "Type");
291   GstMssStreamType ret = MSS_STREAM_TYPE_UNKNOWN;
292
293   if (prop == NULL)
294     return MSS_STREAM_TYPE_UNKNOWN;
295
296   if (strcmp (prop, "video") == 0) {
297     ret = MSS_STREAM_TYPE_VIDEO;
298   } else if (strcmp (prop, "audio") == 0) {
299     ret = MSS_STREAM_TYPE_AUDIO;
300   }
301   xmlFree (prop);
302   return ret;
303 }
304
305 static GstCaps *
306 _gst_mss_stream_video_caps_from_fourcc (gchar * fourcc)
307 {
308   if (!fourcc)
309     return NULL;
310
311   if (strcmp (fourcc, "H264") == 0 || strcmp (fourcc, "AVC1") == 0) {
312     return gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
313         "avc", NULL);
314   } else if (strcmp (fourcc, "WVC1") == 0) {
315     return gst_caps_new_simple ("video/x-wmv", "wmvversion", G_TYPE_INT, 3,
316         "format", G_TYPE_STRING, "WVC1", NULL);
317   }
318   return NULL;
319 }
320
321 static GstCaps *
322 _gst_mss_stream_audio_caps_from_fourcc (gchar * fourcc)
323 {
324   if (!fourcc)
325     return NULL;
326
327   if (strcmp (fourcc, "AACL") == 0) {
328     return gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4,
329         NULL);
330   } else if (strcmp (fourcc, "WmaPro") == 0 || strcmp (fourcc, "WMAP") == 0) {
331     return gst_caps_new_simple ("audio/x-wma", "wmaversion", G_TYPE_INT, 3,
332         NULL);
333   }
334   return NULL;
335 }
336
337 /* copied and adapted from h264parse */
338 static GstBuffer *
339 _make_h264_codec_data (GstBuffer * sps, GstBuffer * pps)
340 {
341   GstBuffer *buf;
342   gint sps_size = 0, pps_size = 0, num_sps = 0, num_pps = 0;
343   guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
344   guint8 *data;
345   gint nl;
346   GstMapInfo spsinfo, ppsinfo, codecdatainfo;
347
348   if (gst_buffer_get_size (sps) < 4)
349     return NULL;
350
351   gst_buffer_map (sps, &spsinfo, GST_MAP_READ);
352   gst_buffer_map (pps, &ppsinfo, GST_MAP_READ);
353
354   sps_size += spsinfo.size + 2;
355   profile_idc = spsinfo.data[1];
356   profile_comp = spsinfo.data[2];
357   level_idc = spsinfo.data[3];
358   num_sps = 1;
359
360   pps_size += ppsinfo.size + 2;
361   num_pps = 1;
362
363   buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size);
364   gst_buffer_map (buf, &codecdatainfo, GST_MAP_WRITE);
365   data = codecdatainfo.data;
366   nl = 4;
367
368   data[0] = 1;                  /* AVC Decoder Configuration Record ver. 1 */
369   data[1] = profile_idc;        /* profile_idc                             */
370   data[2] = profile_comp;       /* profile_compability                     */
371   data[3] = level_idc;          /* level_idc                               */
372   data[4] = 0xfc | (nl - 1);    /* nal_length_size_minus1                  */
373   data[5] = 0xe0 | num_sps;     /* number of SPSs */
374
375   data += 6;
376   GST_WRITE_UINT16_BE (data, spsinfo.size);
377   memcpy (data + 2, spsinfo.data, spsinfo.size);
378   data += 2 + spsinfo.size;
379
380   data[0] = num_pps;
381   data++;
382   GST_WRITE_UINT16_BE (data, ppsinfo.size);
383   memcpy (data + 2, ppsinfo.data, ppsinfo.size);
384   data += 2 + ppsinfo.size;
385
386   gst_buffer_unmap (sps, &spsinfo);
387   gst_buffer_unmap (pps, &ppsinfo);
388   gst_buffer_unmap (buf, &codecdatainfo);
389
390   return buf;
391 }
392
393 static void
394 _gst_mss_stream_add_h264_codec_data (GstCaps * caps, const gchar * codecdatastr)
395 {
396   GstBuffer *sps;
397   GstBuffer *pps;
398   GstBuffer *buffer;
399   gchar *sps_str;
400   gchar *pps_str;
401   GstH264NalUnit nalu;
402   GstH264SPS sps_struct;
403   GstH264ParserResult parseres;
404   GstMapInfo spsinfo;
405
406   /* search for the sps start */
407   if (g_str_has_prefix (codecdatastr, "00000001")) {
408     sps_str = (gchar *) codecdatastr + 8;
409   } else {
410     return;                     /* invalid mss codec data */
411   }
412
413   /* search for the pps start */
414   pps_str = g_strstr_len (sps_str, -1, "00000001");
415   if (!pps_str) {
416     return;                     /* invalid mss codec data */
417   }
418
419   pps_str[0] = '\0';
420   sps = gst_buffer_from_hex_string (sps_str);
421   pps_str[0] = '0';
422
423   pps_str = pps_str + 8;
424   pps = gst_buffer_from_hex_string (pps_str);
425
426   gst_buffer_map (sps, &spsinfo, GST_MAP_READ);
427
428   nalu.ref_idc = (spsinfo.data[0] & 0x60) >> 5;
429   nalu.type = GST_H264_NAL_SPS;
430   nalu.size = spsinfo.size;
431   nalu.data = spsinfo.data;
432   nalu.offset = 0;
433   nalu.sc_offset = 0;
434   nalu.valid = TRUE;
435
436   parseres = gst_h264_parse_sps (&nalu, &sps_struct, TRUE);
437   if (parseres == GST_H264_PARSER_OK) {
438     gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
439         sps_struct.fps_num, sps_struct.fps_den, NULL);
440   }
441
442   buffer = _make_h264_codec_data (sps, pps);
443   gst_buffer_unmap (sps, &spsinfo);
444   gst_buffer_unref (sps);
445   gst_buffer_unref (pps);
446
447   if (buffer != NULL) {
448     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL);
449     gst_buffer_unref (buffer);
450   }
451 }
452
453 static GstCaps *
454 _gst_mss_stream_video_caps_from_qualitylevel_xml (GstMssStreamQuality * q)
455 {
456   xmlNodePtr node = q->xmlnode;
457   GstCaps *caps;
458   GstStructure *structure;
459   gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
460   gchar *max_width = (gchar *) xmlGetProp (node, (xmlChar *) "MaxWidth");
461   gchar *max_height = (gchar *) xmlGetProp (node, (xmlChar *) "MaxHeight");
462   gchar *codec_data =
463       (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
464
465   if (!max_width)
466     max_width = (gchar *) xmlGetProp (node, (xmlChar *) "Width");
467   if (!max_height)
468     max_height = (gchar *) xmlGetProp (node, (xmlChar *) "Height");
469
470   caps = _gst_mss_stream_video_caps_from_fourcc (fourcc);
471   if (!caps)
472     goto end;
473
474   structure = gst_caps_get_structure (caps, 0);
475
476   if (max_width) {
477     gst_structure_set (structure, "width", G_TYPE_INT,
478         (int) g_ascii_strtoull (max_width, NULL, 10), NULL);
479   }
480   if (max_height) {
481     gst_structure_set (structure, "height", G_TYPE_INT,
482         (int) g_ascii_strtoull (max_height, NULL, 10), NULL);
483   }
484
485   if (codec_data && strlen (codec_data)) {
486     if (strcmp (fourcc, "H264") == 0 || strcmp (fourcc, "AVC1") == 0) {
487       _gst_mss_stream_add_h264_codec_data (caps, codec_data);
488     } else {
489       GstBuffer *buffer = gst_buffer_from_hex_string ((gchar *) codec_data);
490       gst_structure_set (structure, "codec_data", GST_TYPE_BUFFER, buffer,
491           NULL);
492       gst_buffer_unref (buffer);
493     }
494   }
495
496 end:
497   xmlFree (fourcc);
498   xmlFree (max_width);
499   xmlFree (max_height);
500   xmlFree (codec_data);
501
502   return caps;
503 }
504
505 static guint8
506 _frequency_index_from_sampling_rate (guint sampling_rate)
507 {
508   static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
509     32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
510   };
511
512   guint8 i;
513
514   for (i = 0; i < G_N_ELEMENTS (aac_sample_rates); i++) {
515     if (aac_sample_rates[i] == sampling_rate)
516       return i;
517   }
518   return 15;
519 }
520
521 static GstBuffer *
522 _make_aacl_codec_data (guint64 sampling_rate, guint64 channels)
523 {
524   GstBuffer *buf;
525   guint8 *data;
526   guint8 frequency_index;
527   guint8 buf_size;
528   GstMapInfo info;
529
530   buf_size = 2;
531   frequency_index = _frequency_index_from_sampling_rate (sampling_rate);
532   if (frequency_index == 15)
533     buf_size += 3;
534
535   buf = gst_buffer_new_and_alloc (buf_size);
536   gst_buffer_map (buf, &info, GST_MAP_WRITE);
537   data = info.data;
538
539   data[0] = 2 << 3;             /* AAC-LC object type is 2 */
540   data[0] += frequency_index >> 1;
541   data[1] = (frequency_index & 0x01) << 7;
542
543   /* Sampling rate is not in frequencies table, write manually */
544   if (frequency_index == 15) {
545     data[1] += sampling_rate >> 17;
546     data[2] = (sampling_rate >> 9) & 0xFF;
547     data[3] = (sampling_rate >> 1) & 0xFF;
548     data[4] = sampling_rate & 0x01;
549     data += 3;
550   }
551
552   data[1] += (channels & 0x0F) << 3;
553
554   gst_buffer_unmap (buf, &info);
555
556   return buf;
557 }
558
559 static GstCaps *
560 _gst_mss_stream_audio_caps_from_qualitylevel_xml (GstMssStreamQuality * q)
561 {
562   xmlNodePtr node = q->xmlnode;
563   GstCaps *caps;
564   GstStructure *structure;
565   gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
566   gchar *channels_str = (gchar *) xmlGetProp (node, (xmlChar *) "Channels");
567   gchar *rate_str = (gchar *) xmlGetProp (node, (xmlChar *) "SamplingRate");
568   gchar *block_align_str =
569       (gchar *) xmlGetProp (node, (xmlChar *) "PacketSize");
570   gchar *codec_data_str =
571       (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
572   GstBuffer *codec_data = NULL;
573   gint block_align = 0;
574   gint rate = 0;
575   gint channels = 0;
576
577   if (!fourcc)                  /* sometimes the fourcc is omitted, we fallback to the Subtype in the StreamIndex node */
578     fourcc = (gchar *) xmlGetProp (node->parent, (xmlChar *) "Subtype");
579
580   caps = _gst_mss_stream_audio_caps_from_fourcc (fourcc);
581   if (!caps)
582     goto end;
583
584   structure = gst_caps_get_structure (caps, 0);
585   if (codec_data_str && strlen (codec_data_str)) {
586     codec_data = gst_buffer_from_hex_string ((gchar *) codec_data_str);
587   }
588
589   if (rate_str)
590     rate = (gint) g_ascii_strtoull (rate_str, NULL, 10);
591   if (channels_str)
592     channels = (int) g_ascii_strtoull (channels_str, NULL, 10);
593   if (block_align_str)
594     block_align = (int) g_ascii_strtoull (block_align_str, NULL, 10);
595
596   if (!codec_data) {
597     GstMapInfo mapinfo;
598     codec_data_str = (gchar *) xmlGetProp (node, (xmlChar *) "WaveFormatEx");
599     if (codec_data_str && strlen (codec_data_str)) {
600       codec_data = gst_buffer_from_hex_string ((gchar *) codec_data_str);
601
602       /* since this is a waveformatex, try to get the block_align and rate */
603       gst_buffer_map (codec_data, &mapinfo, GST_MAP_READ);
604       if (mapinfo.size >= 14) {
605         if (!channels_str) {
606           channels = GST_READ_UINT16_LE (mapinfo.data + 2);
607         }
608         if (!rate_str) {
609           rate = GST_READ_UINT32_LE (mapinfo.data + 4);
610         }
611         block_align = GST_READ_UINT16_LE (mapinfo.data + 12);
612       }
613       gst_buffer_unmap (codec_data, &mapinfo);
614     }
615   }
616
617   if (!codec_data && strcmp (fourcc, "AACL") == 0 && rate && channels) {
618     codec_data = _make_aacl_codec_data (rate, channels);
619   }
620
621   if (block_align)
622     gst_structure_set (structure, "block_align", G_TYPE_INT, block_align, NULL);
623
624   if (channels)
625     gst_structure_set (structure, "channels", G_TYPE_INT, channels, NULL);
626
627   if (rate)
628     gst_structure_set (structure, "rate", G_TYPE_INT, rate, NULL);
629
630   if (q->bitrate)
631     gst_structure_set (structure, "bitrate", G_TYPE_INT, q->bitrate, NULL);
632
633   if (codec_data)
634     gst_structure_set (structure, "codec_data", GST_TYPE_BUFFER, codec_data,
635         NULL);
636
637 end:
638   if (codec_data)
639     gst_buffer_unref (codec_data);
640   xmlFree (fourcc);
641   xmlFree (channels_str);
642   xmlFree (rate_str);
643   xmlFree (block_align_str);
644   xmlFree (codec_data_str);
645
646   return caps;
647 }
648
649 void
650 gst_mss_stream_set_active (GstMssStream * stream, gboolean active)
651 {
652   stream->active = active;
653 }
654
655 guint64
656 gst_mss_stream_get_timescale (GstMssStream * stream)
657 {
658   gchar *timescale;
659   guint64 ts = DEFAULT_TIMESCALE;
660
661   timescale =
662       (gchar *) xmlGetProp (stream->xmlnode, (xmlChar *) MSS_PROP_TIMESCALE);
663   if (!timescale) {
664     timescale =
665         (gchar *) xmlGetProp (stream->xmlnode->parent,
666         (xmlChar *) MSS_PROP_TIMESCALE);
667   }
668
669   if (timescale) {
670     ts = g_ascii_strtoull (timescale, NULL, 10);
671     xmlFree (timescale);
672   }
673   return ts;
674 }
675
676 guint64
677 gst_mss_manifest_get_timescale (GstMssManifest * manifest)
678 {
679   gchar *timescale;
680   guint64 ts = DEFAULT_TIMESCALE;
681
682   timescale =
683       (gchar *) xmlGetProp (manifest->xmlrootnode,
684       (xmlChar *) MSS_PROP_TIMESCALE);
685   if (timescale) {
686     ts = g_ascii_strtoull (timescale, NULL, 10);
687     xmlFree (timescale);
688   }
689   return ts;
690 }
691
692 guint64
693 gst_mss_manifest_get_duration (GstMssManifest * manifest)
694 {
695   gchar *duration;
696   guint64 dur = -1;
697
698   duration =
699       (gchar *) xmlGetProp (manifest->xmlrootnode,
700       (xmlChar *) MSS_PROP_STREAM_DURATION);
701   if (duration) {
702     dur = g_ascii_strtoull (duration, NULL, 10);
703     xmlFree (duration);
704   }
705   return dur;
706 }
707
708
709 /**
710  * Gets the duration in nanoseconds
711  */
712 GstClockTime
713 gst_mss_manifest_get_gst_duration (GstMssManifest * manifest)
714 {
715   guint64 duration = -1;
716   guint64 timescale;
717   GstClockTime gstdur = GST_CLOCK_TIME_NONE;
718
719   duration = gst_mss_manifest_get_duration (manifest);
720   timescale = gst_mss_manifest_get_timescale (manifest);
721
722   if (duration != -1 && timescale != -1)
723     gstdur =
724         (GstClockTime) gst_util_uint64_scale_round (duration, GST_SECOND,
725         timescale);
726
727   return gstdur;
728 }
729
730 GstCaps *
731 gst_mss_stream_get_caps (GstMssStream * stream)
732 {
733   GstMssStreamType streamtype = gst_mss_stream_get_type (stream);
734   GstMssStreamQuality *qualitylevel = stream->current_quality->data;
735   GstCaps *caps = NULL;
736
737   if (streamtype == MSS_STREAM_TYPE_VIDEO)
738     caps = _gst_mss_stream_video_caps_from_qualitylevel_xml (qualitylevel);
739   else if (streamtype == MSS_STREAM_TYPE_AUDIO)
740     caps = _gst_mss_stream_audio_caps_from_qualitylevel_xml (qualitylevel);
741
742   return caps;
743 }
744
745 GstFlowReturn
746 gst_mss_stream_get_fragment_url (GstMssStream * stream, gchar ** url)
747 {
748   gchar *tmp;
749   gchar *start_time_str;
750   GstMssStreamFragment *fragment;
751   GstMssStreamQuality *quality = stream->current_quality->data;
752
753   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
754
755   if (stream->current_fragment == NULL) /* stream is over */
756     return GST_FLOW_EOS;
757
758   fragment = stream->current_fragment->data;
759
760   start_time_str = g_strdup_printf ("%" G_GUINT64_FORMAT, fragment->time);
761
762   tmp = g_regex_replace_literal (stream->regex_bitrate, stream->url,
763       strlen (stream->url), 0, quality->bitrate_str, 0, NULL);
764   *url = g_regex_replace_literal (stream->regex_position, tmp,
765       strlen (tmp), 0, start_time_str, 0, NULL);
766
767   g_free (tmp);
768   g_free (start_time_str);
769
770   if (*url == NULL)
771     return GST_FLOW_ERROR;
772
773   return GST_FLOW_OK;
774 }
775
776 GstClockTime
777 gst_mss_stream_get_fragment_gst_timestamp (GstMssStream * stream)
778 {
779   guint64 time;
780   guint64 timescale;
781   GstMssStreamFragment *fragment;
782
783   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
784
785   if (!stream->current_fragment)
786     return GST_CLOCK_TIME_NONE;
787
788   fragment = stream->current_fragment->data;
789
790   time = fragment->time;
791   timescale = gst_mss_stream_get_timescale (stream);
792   return (GstClockTime) gst_util_uint64_scale_round (time, GST_SECOND,
793       timescale);
794 }
795
796 GstClockTime
797 gst_mss_stream_get_fragment_gst_duration (GstMssStream * stream)
798 {
799   guint64 dur;
800   guint64 timescale;
801   GstMssStreamFragment *fragment;
802
803   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
804
805   if (!stream->current_fragment)
806     return GST_CLOCK_TIME_NONE;
807
808   fragment = stream->current_fragment->data;
809
810   dur = fragment->duration;
811   timescale = gst_mss_stream_get_timescale (stream);
812   return (GstClockTime) gst_util_uint64_scale_round (dur, GST_SECOND,
813       timescale);
814 }
815
816 GstFlowReturn
817 gst_mss_stream_advance_fragment (GstMssStream * stream)
818 {
819   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
820
821   if (stream->current_fragment == NULL)
822     return GST_FLOW_EOS;
823
824   stream->current_fragment = g_list_next (stream->current_fragment);
825   if (stream->current_fragment == NULL)
826     return GST_FLOW_EOS;
827   return GST_FLOW_OK;
828 }
829
830 const gchar *
831 gst_mss_stream_type_name (GstMssStreamType streamtype)
832 {
833   switch (streamtype) {
834     case MSS_STREAM_TYPE_VIDEO:
835       return "video";
836     case MSS_STREAM_TYPE_AUDIO:
837       return "audio";
838     case MSS_STREAM_TYPE_UNKNOWN:
839     default:
840       return "unknown";
841   }
842 }
843
844 /**
845  * Seeks all streams to the fragment that contains the set time
846  *
847  * @time: time in nanoseconds
848  */
849 gboolean
850 gst_mss_manifest_seek (GstMssManifest * manifest, guint64 time)
851 {
852   gboolean ret = TRUE;
853   GSList *iter;
854
855   for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
856     ret = gst_mss_stream_seek (iter->data, time) & ret;
857   }
858
859   return ret;
860 }
861
862 /**
863  * Seeks this stream to the fragment that contains the sample at time
864  *
865  * @time: time in nanoseconds
866  */
867 gboolean
868 gst_mss_stream_seek (GstMssStream * stream, guint64 time)
869 {
870   GList *iter;
871   guint64 timescale;
872
873   timescale = gst_mss_stream_get_timescale (stream);
874   time = gst_util_uint64_scale_round (time, timescale, GST_SECOND);
875
876   for (iter = stream->fragments; iter; iter = g_list_next (iter)) {
877     GList *next = g_list_next (iter);
878     if (next) {
879       GstMssStreamFragment *fragment = next->data;
880
881       if (fragment->time > time) {
882         stream->current_fragment = iter;
883         break;
884       }
885     } else {
886       GstMssStreamFragment *fragment = iter->data;
887       if (fragment->time + fragment->duration > time) {
888         stream->current_fragment = iter;
889       } else {
890         stream->current_fragment = NULL;        /* EOS */
891       }
892       break;
893     }
894   }
895
896   return TRUE;
897 }
898
899 guint64
900 gst_mss_manifest_get_current_bitrate (GstMssManifest * manifest)
901 {
902   guint64 bitrate = 0;
903   GSList *iter;
904
905   for (iter = gst_mss_manifest_get_streams (manifest); iter;
906       iter = g_slist_next (iter)) {
907     GstMssStream *stream = iter->data;
908     if (stream->active && stream->current_quality) {
909       GstMssStreamQuality *q = stream->current_quality->data;
910
911       bitrate += q->bitrate;
912     }
913   }
914
915   return bitrate;
916 }
917
918 gboolean
919 gst_mss_manifest_is_live (GstMssManifest * manifest)
920 {
921   return manifest->is_live;
922 }
923
924 static void
925 gst_mss_stream_reload_fragments (GstMssStream * stream, xmlNodePtr streamIndex)
926 {
927   xmlNodePtr iter;
928   GList *new_fragments = NULL;
929   GstMssStreamFragment *previous_fragment = NULL;
930   GstMssStreamFragment *current_fragment =
931       stream->current_fragment ? stream->current_fragment->data : NULL;
932   guint64 current_time = gst_mss_stream_get_fragment_gst_timestamp (stream);
933   guint fragment_number = 0;
934   guint64 fragment_time_accum = 0;
935
936   if (!current_fragment && stream->fragments) {
937     current_fragment = g_list_last (stream->fragments)->data;
938   } else if (g_list_previous (stream->current_fragment)) {
939     /* rewind one as this is the next to be pushed */
940     current_fragment = g_list_previous (stream->current_fragment)->data;
941   } else {
942     current_fragment = NULL;
943   }
944
945   if (current_fragment) {
946     current_time = current_fragment->time;
947     fragment_number = current_fragment->number;
948     fragment_time_accum = current_fragment->time;
949   }
950
951   for (iter = streamIndex->children; iter; iter = iter->next) {
952     if (node_has_type (iter, MSS_NODE_STREAM_FRAGMENT)) {
953       gchar *duration_str;
954       gchar *time_str;
955       gchar *seqnum_str;
956       GstMssStreamFragment *fragment = g_new (GstMssStreamFragment, 1);
957
958       duration_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_DURATION);
959       time_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_TIME);
960       seqnum_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_NUMBER);
961
962       /* use the node's seq number or use the previous + 1 */
963       if (seqnum_str) {
964         fragment->number = g_ascii_strtoull (seqnum_str, NULL, 10);
965         xmlFree (seqnum_str);
966       } else {
967         fragment->number = fragment_number;
968       }
969       fragment_number = fragment->number + 1;
970
971       if (time_str) {
972         fragment->time = g_ascii_strtoull (time_str, NULL, 10);
973         xmlFree (time_str);
974         fragment_time_accum = fragment->time;
975       } else {
976         fragment->time = fragment_time_accum;
977       }
978
979       /* if we have a previous fragment, means we need to set its duration */
980       if (previous_fragment)
981         previous_fragment->duration = fragment->time - previous_fragment->time;
982
983       if (duration_str) {
984         fragment->duration = g_ascii_strtoull (duration_str, NULL, 10);
985
986         previous_fragment = NULL;
987         fragment_time_accum += fragment->duration;
988         xmlFree (duration_str);
989       } else {
990         /* store to set the duration at the next iteration */
991         previous_fragment = fragment;
992       }
993
994       if (fragment->time > current_time) {
995         new_fragments = g_list_append (new_fragments, fragment);
996       } else {
997         previous_fragment = NULL;
998         g_free (fragment);
999       }
1000
1001     } else {
1002       /* TODO gst log this */
1003     }
1004   }
1005
1006   /* store the new fragments list */
1007   if (new_fragments) {
1008     g_list_free_full (stream->fragments, g_free);
1009     stream->fragments = new_fragments;
1010     stream->current_fragment = new_fragments;
1011   }
1012 }
1013
1014 static void
1015 gst_mss_manifest_reload_fragments_from_xml (GstMssManifest * manifest,
1016     xmlNodePtr root)
1017 {
1018   xmlNodePtr nodeiter;
1019   GSList *streams = manifest->streams;
1020
1021   /* we assume the server is providing the streams in the same order in
1022    * every manifest */
1023   for (nodeiter = root->children; nodeiter && streams;
1024       nodeiter = nodeiter->next) {
1025     if (nodeiter->type == XML_ELEMENT_NODE
1026         && (strcmp ((const char *) nodeiter->name, "StreamIndex") == 0)) {
1027       gst_mss_stream_reload_fragments (streams->data, nodeiter);
1028       streams = g_slist_next (streams);
1029     }
1030   }
1031 }
1032
1033 void
1034 gst_mss_manifest_reload_fragments (GstMssManifest * manifest, GstBuffer * data)
1035 {
1036   xmlDocPtr xml;
1037   xmlNodePtr root;
1038   GstMapInfo info;
1039
1040   g_return_if_fail (manifest->is_live);
1041
1042   gst_buffer_map (data, &info, GST_MAP_READ);
1043
1044   xml = xmlReadMemory ((const gchar *) info.data,
1045       info.size, "manifest", NULL, 0);
1046   root = xmlDocGetRootElement (xml);
1047
1048   gst_mss_manifest_reload_fragments_from_xml (manifest, root);
1049
1050   xmlFreeDoc (xml);
1051
1052   gst_buffer_unmap (data, &info);
1053 }
1054
1055 gboolean
1056 gst_mss_stream_select_bitrate (GstMssStream * stream, guint64 bitrate)
1057 {
1058   GList *iter = stream->current_quality;
1059   GList *next;
1060   GstMssStreamQuality *q = iter->data;
1061
1062   while (q->bitrate > bitrate) {
1063     next = g_list_previous (iter);
1064     if (next) {
1065       iter = next;
1066       q = iter->data;
1067     } else {
1068       break;
1069     }
1070   }
1071
1072   while (q->bitrate < bitrate) {
1073     GstMssStreamQuality *next_q;
1074     next = g_list_next (iter);
1075     if (next) {
1076       next_q = next->data;
1077       if (next_q->bitrate < bitrate) {
1078         iter = next;
1079         q = iter->data;
1080       } else {
1081         break;
1082       }
1083     } else {
1084       break;
1085     }
1086   }
1087
1088   if (iter == stream->current_quality)
1089     return FALSE;
1090   stream->current_quality = iter;
1091   return TRUE;
1092 }
1093
1094 guint64
1095 gst_mss_stream_get_current_bitrate (GstMssStream * stream)
1096 {
1097   GstMssStreamQuality *q;
1098   if (stream->current_quality == NULL)
1099     return 0;
1100
1101   q = stream->current_quality->data;
1102   return q->bitrate;
1103 }
1104
1105 /**
1106  * gst_mss_manifest_change_bitrate:
1107  * @manifest: the manifest
1108  * @bitrate: the maximum bitrate to use (bps)
1109  *
1110  * Iterates over the active streams and changes their bitrates to the maximum
1111  * value so that the bitrates of all streams are not larger than
1112  * @bitrate.
1113  *
1114  * Return: %TRUE if any stream changed its bitrate
1115  */
1116 gboolean
1117 gst_mss_manifest_change_bitrate (GstMssManifest * manifest, guint64 bitrate)
1118 {
1119   gboolean ret = FALSE;
1120   GSList *iter;
1121
1122   /* TODO This algorithm currently sets the same bitrate for all streams,
1123    * it should actually use the sum of all streams bitrates to compare to
1124    * the target value */
1125
1126   if (bitrate == 0) {
1127     /* use maximum */
1128     bitrate = G_MAXUINT64;
1129   }
1130
1131   for (iter = gst_mss_manifest_get_streams (manifest); iter;
1132       iter = g_slist_next (iter)) {
1133     GstMssStream *stream = iter->data;
1134     if (stream->active) {
1135       ret = ret | gst_mss_stream_select_bitrate (stream, bitrate);
1136     }
1137   }
1138
1139   return ret;
1140 }
1141
1142 static GstBuffer *
1143 gst_buffer_from_hex_string (const gchar * s)
1144 {
1145   GstBuffer *buffer = NULL;
1146   gint len;
1147   gchar ts[3];
1148   guint8 *data;
1149   gint i;
1150   GstMapInfo info;
1151
1152   len = strlen (s);
1153   if (len & 1)
1154     return NULL;
1155
1156   buffer = gst_buffer_new_and_alloc (len / 2);
1157   gst_buffer_map (buffer, &info, GST_MAP_WRITE);
1158   data = info.data;
1159   for (i = 0; i < len / 2; i++) {
1160     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1])) {
1161       gst_buffer_unref (buffer);
1162       return NULL;
1163     }
1164
1165     ts[0] = s[i * 2 + 0];
1166     ts[1] = s[i * 2 + 1];
1167     ts[2] = 0;
1168
1169     data[i] = (guint8) strtoul (ts, NULL, 16);
1170   }
1171
1172   gst_buffer_unmap (buffer, &info);
1173   return buffer;
1174 }