mssdemux: use streams bitrate individually
[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 /* TODO check if atoi is successful? */
49
50 typedef struct _GstMssStreamFragment
51 {
52   guint number;
53   guint64 time;
54   guint64 duration;
55 } GstMssStreamFragment;
56
57 typedef struct _GstMssStreamQuality
58 {
59   xmlNodePtr xmlnode;
60
61   gchar *bitrate_str;
62   guint64 bitrate;
63 } GstMssStreamQuality;
64
65 struct _GstMssStream
66 {
67   xmlNodePtr xmlnode;
68
69   gboolean active;              /* if the stream is currently being used */
70   gint selectedQualityIndex;
71
72   GList *fragments;
73   GList *qualities;
74
75   gchar *url;
76
77   GList *current_fragment;
78   GList *current_quality;
79
80   /* TODO move this to somewhere static */
81   GRegex *regex_bitrate;
82   GRegex *regex_position;
83 };
84
85 struct _GstMssManifest
86 {
87   xmlDocPtr xml;
88   xmlNodePtr xmlrootnode;
89
90   gboolean is_live;
91
92   GSList *streams;
93 };
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 (const GstBuffer * data)
220 {
221   GstMssManifest *manifest;
222   xmlNodePtr root;
223   xmlNodePtr nodeiter;
224   gchar *live_str;
225
226   manifest = g_malloc0 (sizeof (GstMssManifest));
227
228   manifest->xml = xmlReadMemory ((const gchar *) GST_BUFFER_DATA (data),
229       GST_BUFFER_SIZE (data), "manifest", NULL, 0);
230   root = manifest->xmlrootnode = xmlDocGetRootElement (manifest->xml);
231
232   live_str = (gchar *) xmlGetProp (root, (xmlChar *) "IsLive");
233   if (live_str) {
234     manifest->is_live = g_ascii_strcasecmp (live_str, "true") == 0;
235     xmlFree (live_str);
236   }
237
238   for (nodeiter = root->children; nodeiter; nodeiter = nodeiter->next) {
239     if (nodeiter->type == XML_ELEMENT_NODE
240         && (strcmp ((const char *) nodeiter->name, "StreamIndex") == 0)) {
241       GstMssStream *stream = g_new0 (GstMssStream, 1);
242
243       manifest->streams = g_slist_append (manifest->streams, stream);
244       _gst_mss_stream_init (stream, nodeiter);
245     }
246   }
247
248   return manifest;
249 }
250
251 static void
252 gst_mss_stream_free (GstMssStream * stream)
253 {
254   g_list_free_full (stream->fragments, g_free);
255   g_list_free_full (stream->qualities,
256       (GDestroyNotify) gst_mss_stream_quality_free);
257   xmlFree (stream->url);
258   g_regex_unref (stream->regex_position);
259   g_regex_unref (stream->regex_bitrate);
260   g_free (stream);
261 }
262
263 void
264 gst_mss_manifest_free (GstMssManifest * manifest)
265 {
266   g_return_if_fail (manifest != NULL);
267
268   g_slist_free_full (manifest->streams, (GDestroyNotify) gst_mss_stream_free);
269
270   xmlFreeDoc (manifest->xml);
271   g_free (manifest);
272 }
273
274 GSList *
275 gst_mss_manifest_get_streams (GstMssManifest * manifest)
276 {
277   return manifest->streams;
278 }
279
280 GstMssStreamType
281 gst_mss_stream_get_type (GstMssStream * stream)
282 {
283   gchar *prop = (gchar *) xmlGetProp (stream->xmlnode, (xmlChar *) "Type");
284   GstMssStreamType ret = MSS_STREAM_TYPE_UNKNOWN;
285
286   if (prop == NULL)
287     return MSS_STREAM_TYPE_UNKNOWN;
288
289   if (strcmp (prop, "video") == 0) {
290     ret = MSS_STREAM_TYPE_VIDEO;
291   } else if (strcmp (prop, "audio") == 0) {
292     ret = MSS_STREAM_TYPE_AUDIO;
293   }
294   xmlFree (prop);
295   return ret;
296 }
297
298 static GstCaps *
299 _gst_mss_stream_video_caps_from_fourcc (gchar * fourcc)
300 {
301   if (!fourcc)
302     return NULL;
303
304   if (strcmp (fourcc, "H264") == 0 || strcmp (fourcc, "AVC1") == 0) {
305     return gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
306         "avc", NULL);
307   } else if (strcmp (fourcc, "WVC1") == 0) {
308     return gst_caps_new_simple ("video/x-wmv", "wmvversion", G_TYPE_INT, 3,
309         NULL);
310   }
311   return NULL;
312 }
313
314 static GstCaps *
315 _gst_mss_stream_audio_caps_from_fourcc (gchar * fourcc)
316 {
317   if (!fourcc)
318     return NULL;
319
320   if (strcmp (fourcc, "AACL") == 0) {
321     return gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4,
322         NULL);
323   } else if (strcmp (fourcc, "WmaPro") == 0) {
324     return gst_caps_new_simple ("audio/x-wma", "wmaversion", G_TYPE_INT, 2,
325         NULL);
326   }
327   return NULL;
328 }
329
330 /* copied and adapted from h264parse */
331 static GstBuffer *
332 _make_h264_codec_data (GstBuffer * sps, GstBuffer * pps)
333 {
334   GstBuffer *buf;
335   gint sps_size = 0, pps_size = 0, num_sps = 0, num_pps = 0;
336   guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
337   guint8 *data;
338   gint nl;
339
340   if (GST_BUFFER_SIZE (sps) < 4)
341     return NULL;
342
343   sps_size += GST_BUFFER_SIZE (sps) + 2;
344   profile_idc = GST_BUFFER_DATA (sps)[1];
345   profile_comp = GST_BUFFER_DATA (sps)[2];
346   level_idc = GST_BUFFER_DATA (sps)[3];
347   num_sps = 1;
348
349   pps_size += GST_BUFFER_SIZE (pps) + 2;
350   num_pps = 1;
351
352   buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size);
353   data = GST_BUFFER_DATA (buf);
354   nl = 4;
355
356   data[0] = 1;                  /* AVC Decoder Configuration Record ver. 1 */
357   data[1] = profile_idc;        /* profile_idc                             */
358   data[2] = profile_comp;       /* profile_compability                     */
359   data[3] = level_idc;          /* level_idc                               */
360   data[4] = 0xfc | (nl - 1);    /* nal_length_size_minus1                  */
361   data[5] = 0xe0 | num_sps;     /* number of SPSs */
362
363   data += 6;
364   GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (sps));
365   memcpy (data + 2, GST_BUFFER_DATA (sps), GST_BUFFER_SIZE (sps));
366   data += 2 + GST_BUFFER_SIZE (sps);
367
368   data[0] = num_pps;
369   data++;
370   GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (pps));
371   memcpy (data + 2, GST_BUFFER_DATA (pps), GST_BUFFER_SIZE (pps));
372   data += 2 + GST_BUFFER_SIZE (pps);
373
374   return buf;
375 }
376
377 static void
378 _gst_mss_stream_add_h264_codec_data (GstCaps * caps, const gchar * codecdatastr)
379 {
380   GValue sps_value = { 0, };
381   GValue pps_value = { 0, };
382   GstBuffer *sps;
383   GstBuffer *pps;
384   GstBuffer *buffer;
385   gchar *sps_str;
386   gchar *pps_str;
387   GstH264NalUnit nalu;
388   GstH264SPS sps_struct;
389   GstH264ParserResult parseres;
390
391   /* search for the sps start */
392   if (g_str_has_prefix (codecdatastr, "00000001")) {
393     sps_str = (gchar *) codecdatastr + 8;
394   } else {
395     return;                     /* invalid mss codec data */
396   }
397
398   /* search for the pps start */
399   pps_str = g_strstr_len (sps_str, -1, "00000001");
400   if (!pps_str) {
401     return;                     /* invalid mss codec data */
402   }
403
404   g_value_init (&sps_value, GST_TYPE_BUFFER);
405   pps_str[0] = '\0';
406   gst_value_deserialize (&sps_value, sps_str);
407   pps_str[0] = '0';
408
409   g_value_init (&pps_value, GST_TYPE_BUFFER);
410   pps_str = pps_str + 8;
411   gst_value_deserialize (&pps_value, pps_str);
412
413   sps = gst_value_get_buffer (&sps_value);
414   pps = gst_value_get_buffer (&pps_value);
415
416   nalu.ref_idc = (GST_BUFFER_DATA (sps)[0] & 0x60) >> 5;
417   nalu.type = GST_H264_NAL_SPS;
418   nalu.size = GST_BUFFER_SIZE (sps);
419   nalu.data = GST_BUFFER_DATA (sps);
420   nalu.offset = 0;
421   nalu.sc_offset = 0;
422   nalu.valid = TRUE;
423
424   parseres = gst_h264_parse_sps (&nalu, &sps_struct, TRUE);
425   if (parseres == GST_H264_PARSER_OK) {
426     gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
427         sps_struct.fps_num, sps_struct.fps_den, NULL);
428   }
429
430   buffer = _make_h264_codec_data (sps, pps);
431   g_value_reset (&sps_value);
432   g_value_reset (&pps_value);
433
434   if (buffer != NULL) {
435     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL);
436     gst_buffer_unref (buffer);
437   }
438 }
439
440 static GstCaps *
441 _gst_mss_stream_video_caps_from_qualitylevel_xml (xmlNodePtr node)
442 {
443   GstCaps *caps;
444   GstStructure *structure;
445   gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
446   gchar *max_width = (gchar *) xmlGetProp (node, (xmlChar *) "MaxWidth");
447   gchar *max_height = (gchar *) xmlGetProp (node, (xmlChar *) "MaxHeight");
448   gchar *codec_data =
449       (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
450
451   if (!max_width)
452     max_width = (gchar *) xmlGetProp (node, (xmlChar *) "Width");
453   if (!max_height)
454     max_height = (gchar *) xmlGetProp (node, (xmlChar *) "Height");
455
456   caps = _gst_mss_stream_video_caps_from_fourcc (fourcc);
457   if (!caps)
458     goto end;
459
460   structure = gst_caps_get_structure (caps, 0);
461
462   if (max_width)
463     gst_structure_set (structure, "width", G_TYPE_INT,
464         g_ascii_strtoull (max_width, NULL, 10), NULL);
465   if (max_height)
466     gst_structure_set (structure, "height", G_TYPE_INT,
467         g_ascii_strtoull (max_height, NULL, 10), NULL);
468
469   if (codec_data && strlen (codec_data)) {
470     if (strcmp (fourcc, "H264") == 0 || strcmp (fourcc, "AVC1") == 0) {
471       _gst_mss_stream_add_h264_codec_data (caps, codec_data);
472     } else {
473       GValue *value = g_new0 (GValue, 1);
474       g_value_init (value, GST_TYPE_BUFFER);
475       gst_value_deserialize (value, (gchar *) codec_data);
476       gst_structure_take_value (structure, "codec_data", value);
477     }
478   }
479
480 end:
481   xmlFree (fourcc);
482   xmlFree (max_width);
483   xmlFree (max_height);
484   xmlFree (codec_data);
485
486   return caps;
487 }
488
489 static guint8
490 _frequency_index_from_sampling_rate (guint sampling_rate)
491 {
492   static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
493     32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
494   };
495
496   guint8 i;
497
498   for (i = 0; i < G_N_ELEMENTS (aac_sample_rates); i++) {
499     if (aac_sample_rates[i] == sampling_rate)
500       return i;
501   }
502   return 15;
503 }
504
505 static GstBuffer *
506 _make_aacl_codec_data (guint64 sampling_rate, guint64 channels)
507 {
508   GstBuffer *buf;
509   guint8 *data;
510   guint8 frequency_index;
511   guint8 buf_size;
512
513   buf_size = 2;
514   frequency_index = _frequency_index_from_sampling_rate (sampling_rate);
515   if (frequency_index == 15)
516     buf_size += 3;
517
518   buf = gst_buffer_new_and_alloc (buf_size);
519   data = GST_BUFFER_DATA (buf);
520
521   data[0] = 2 << 3;             /* AAC-LC object type is 2 */
522   data[0] += frequency_index >> 1;
523   data[1] = (frequency_index & 0x01) << 7;
524
525   /* Sampling rate is not in frequencies table, write manually */
526   if (frequency_index == 15) {
527     data[1] += sampling_rate >> 17;
528     data[2] = (sampling_rate >> 9) & 0xFF;
529     data[3] = (sampling_rate >> 1) & 0xFF;
530     data[4] = sampling_rate & 0x01;
531     data += 3;
532   }
533
534   data[1] += (channels & 0x0F) << 3;
535
536   return buf;
537 }
538
539 static GstCaps *
540 _gst_mss_stream_audio_caps_from_qualitylevel_xml (xmlNodePtr node)
541 {
542   GstCaps *caps;
543   GstStructure *structure;
544   gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
545   gchar *channels = (gchar *) xmlGetProp (node, (xmlChar *) "Channels");
546   gchar *rate = (gchar *) xmlGetProp (node, (xmlChar *) "SamplingRate");
547   gchar *codec_data =
548       (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
549
550   if (!fourcc)                  /* sometimes the fourcc is omitted, we fallback to the Subtype in the StreamIndex node */
551     fourcc = (gchar *) xmlGetProp (node->parent, (xmlChar *) "Subtype");
552   if (!codec_data)
553     codec_data = (gchar *) xmlGetProp (node, (xmlChar *) "WaveFormatEx");
554
555   caps = _gst_mss_stream_audio_caps_from_fourcc (fourcc);
556   if (!caps)
557     goto end;
558
559   structure = gst_caps_get_structure (caps, 0);
560
561   if (channels)
562     gst_structure_set (structure, "channels", G_TYPE_INT,
563         g_ascii_strtoull (channels, NULL, 10), NULL);
564   if (rate)
565     gst_structure_set (structure, "rate", G_TYPE_INT,
566         g_ascii_strtoull (rate, NULL, 10), NULL);
567
568   if (codec_data && strlen (codec_data)) {
569     GValue *value = g_new0 (GValue, 1);
570     g_value_init (value, GST_TYPE_BUFFER);
571     gst_value_deserialize (value, (gchar *) codec_data);
572     gst_structure_take_value (structure, "codec_data", value);
573   } else if (strcmp (fourcc, "AACL") == 0 && rate && channels) {
574     GstBuffer *buffer =
575         _make_aacl_codec_data (g_ascii_strtoull (rate, NULL, 10),
576         g_ascii_strtoull (channels, NULL, 10));
577     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL);
578     gst_buffer_unref (buffer);
579   }
580
581 end:
582   xmlFree (fourcc);
583   xmlFree (channels);
584   xmlFree (rate);
585   xmlFree (codec_data);
586
587   return caps;
588 }
589
590 void
591 gst_mss_stream_set_active (GstMssStream * stream, gboolean active)
592 {
593   stream->active = active;
594 }
595
596 guint64
597 gst_mss_stream_get_timescale (GstMssStream * stream)
598 {
599   gchar *timescale;
600   guint64 ts = DEFAULT_TIMESCALE;
601
602   timescale =
603       (gchar *) xmlGetProp (stream->xmlnode, (xmlChar *) MSS_PROP_TIMESCALE);
604   if (!timescale) {
605     timescale =
606         (gchar *) xmlGetProp (stream->xmlnode->parent,
607         (xmlChar *) MSS_PROP_TIMESCALE);
608   }
609
610   if (timescale) {
611     ts = g_ascii_strtoull (timescale, NULL, 10);
612     xmlFree (timescale);
613   }
614   return ts;
615 }
616
617 guint64
618 gst_mss_manifest_get_timescale (GstMssManifest * manifest)
619 {
620   gchar *timescale;
621   guint64 ts = DEFAULT_TIMESCALE;
622
623   timescale =
624       (gchar *) xmlGetProp (manifest->xmlrootnode,
625       (xmlChar *) MSS_PROP_TIMESCALE);
626   if (timescale) {
627     ts = g_ascii_strtoull (timescale, NULL, 10);
628     xmlFree (timescale);
629   }
630   return ts;
631 }
632
633 guint64
634 gst_mss_manifest_get_duration (GstMssManifest * manifest)
635 {
636   gchar *duration;
637   guint64 dur = -1;
638
639   duration =
640       (gchar *) xmlGetProp (manifest->xmlrootnode,
641       (xmlChar *) MSS_PROP_STREAM_DURATION);
642   if (duration) {
643     dur = g_ascii_strtoull (duration, NULL, 10);
644     xmlFree (duration);
645   }
646   return dur;
647 }
648
649
650 /**
651  * Gets the duration in nanoseconds
652  */
653 GstClockTime
654 gst_mss_manifest_get_gst_duration (GstMssManifest * manifest)
655 {
656   guint64 duration = -1;
657   guint64 timescale;
658   GstClockTime gstdur = GST_CLOCK_TIME_NONE;
659
660   duration = gst_mss_manifest_get_duration (manifest);
661   timescale = gst_mss_manifest_get_timescale (manifest);
662
663   if (duration != -1 && timescale != -1)
664     gstdur =
665         (GstClockTime) gst_util_uint64_scale_round (duration, GST_SECOND,
666         timescale);
667
668   return gstdur;
669 }
670
671 GstCaps *
672 gst_mss_stream_get_caps (GstMssStream * stream)
673 {
674   GstMssStreamType streamtype = gst_mss_stream_get_type (stream);
675   GstMssStreamQuality *qualitylevel = stream->current_quality->data;
676   GstCaps *caps = NULL;
677
678   if (streamtype == MSS_STREAM_TYPE_VIDEO)
679     caps =
680         _gst_mss_stream_video_caps_from_qualitylevel_xml
681         (qualitylevel->xmlnode);
682   else if (streamtype == MSS_STREAM_TYPE_AUDIO)
683     caps =
684         _gst_mss_stream_audio_caps_from_qualitylevel_xml
685         (qualitylevel->xmlnode);
686
687   return caps;
688 }
689
690 GstFlowReturn
691 gst_mss_stream_get_fragment_url (GstMssStream * stream, gchar ** url)
692 {
693   gchar *tmp;
694   gchar *start_time_str;
695   GstMssStreamFragment *fragment;
696   GstMssStreamQuality *quality = stream->current_quality->data;
697
698   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
699
700   if (stream->current_fragment == NULL) /* stream is over */
701     return GST_FLOW_UNEXPECTED;
702
703   fragment = stream->current_fragment->data;
704
705   start_time_str = g_strdup_printf ("%" G_GUINT64_FORMAT, fragment->time);
706
707   tmp = g_regex_replace_literal (stream->regex_bitrate, stream->url,
708       strlen (stream->url), 0, quality->bitrate_str, 0, NULL);
709   *url = g_regex_replace_literal (stream->regex_position, tmp,
710       strlen (tmp), 0, start_time_str, 0, NULL);
711
712   g_free (tmp);
713   g_free (start_time_str);
714
715   if (*url == NULL)
716     return GST_FLOW_ERROR;
717
718   return GST_FLOW_OK;
719 }
720
721 GstClockTime
722 gst_mss_stream_get_fragment_gst_timestamp (GstMssStream * stream)
723 {
724   guint64 time;
725   guint64 timescale;
726   GstMssStreamFragment *fragment;
727
728   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
729
730   if (!stream->current_fragment)
731     return GST_CLOCK_TIME_NONE;
732
733   fragment = stream->current_fragment->data;
734
735   time = fragment->time;
736   timescale = gst_mss_stream_get_timescale (stream);
737   return (GstClockTime) gst_util_uint64_scale_round (time, GST_SECOND,
738       timescale);
739 }
740
741 GstClockTime
742 gst_mss_stream_get_fragment_gst_duration (GstMssStream * stream)
743 {
744   guint64 dur;
745   guint64 timescale;
746   GstMssStreamFragment *fragment;
747
748   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
749
750   if (!stream->current_fragment)
751     return GST_CLOCK_TIME_NONE;
752
753   fragment = stream->current_fragment->data;
754
755   dur = fragment->duration;
756   timescale = gst_mss_stream_get_timescale (stream);
757   return (GstClockTime) gst_util_uint64_scale_round (dur, GST_SECOND,
758       timescale);
759 }
760
761 GstFlowReturn
762 gst_mss_stream_advance_fragment (GstMssStream * stream)
763 {
764   g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
765
766   if (stream->current_fragment == NULL)
767     return GST_FLOW_UNEXPECTED;
768
769   stream->current_fragment = g_list_next (stream->current_fragment);
770   if (stream->current_fragment == NULL)
771     return GST_FLOW_UNEXPECTED;
772   return GST_FLOW_OK;
773 }
774
775 const gchar *
776 gst_mss_stream_type_name (GstMssStreamType streamtype)
777 {
778   switch (streamtype) {
779     case MSS_STREAM_TYPE_VIDEO:
780       return "video";
781     case MSS_STREAM_TYPE_AUDIO:
782       return "audio";
783     case MSS_STREAM_TYPE_UNKNOWN:
784     default:
785       return "unknown";
786   }
787 }
788
789 /**
790  * Seeks all streams to the fragment that contains the set time
791  *
792  * @time: time in nanoseconds
793  */
794 gboolean
795 gst_mss_manifest_seek (GstMssManifest * manifest, guint64 time)
796 {
797   gboolean ret = TRUE;
798   GSList *iter;
799
800   for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
801     ret = gst_mss_stream_seek (iter->data, time) & ret;
802   }
803
804   return ret;
805 }
806
807 /**
808  * Seeks this stream to the fragment that contains the sample at time
809  *
810  * @time: time in nanoseconds
811  */
812 gboolean
813 gst_mss_stream_seek (GstMssStream * stream, guint64 time)
814 {
815   GList *iter;
816   guint64 timescale;
817
818   timescale = gst_mss_stream_get_timescale (stream);
819   time = gst_util_uint64_scale_round (time, timescale, GST_SECOND);
820
821   for (iter = stream->fragments; iter; iter = g_list_next (iter)) {
822     GList *next = g_list_next (iter);
823     if (next) {
824       GstMssStreamFragment *fragment = next->data;
825
826       if (fragment->time > time) {
827         stream->current_fragment = iter;
828         break;
829       }
830     } else {
831       GstMssStreamFragment *fragment = iter->data;
832       if (fragment->time + fragment->duration > time) {
833         stream->current_fragment = iter;
834       } else {
835         stream->current_fragment = NULL;        /* EOS */
836       }
837       break;
838     }
839   }
840
841   return TRUE;
842 }
843
844 guint64
845 gst_mss_manifest_get_current_bitrate (GstMssManifest * manifest)
846 {
847   guint64 bitrate = 0;
848   GSList *iter;
849
850   for (iter = gst_mss_manifest_get_streams (manifest); iter;
851       iter = g_slist_next (iter)) {
852     GstMssStream *stream = iter->data;
853     if (stream->active && stream->current_quality) {
854       GstMssStreamQuality *q = stream->current_quality->data;
855
856       bitrate += q->bitrate;
857     }
858   }
859
860   return bitrate;
861 }
862
863 gboolean
864 gst_mss_manifest_is_live (GstMssManifest * manifest)
865 {
866   return manifest->is_live;
867 }
868
869 static void
870 gst_mss_stream_reload_fragments (GstMssStream * stream, xmlNodePtr streamIndex)
871 {
872   xmlNodePtr iter;
873   GList *new_fragments = NULL;
874   GstMssStreamFragment *previous_fragment = NULL;
875   GstMssStreamFragment *current_fragment =
876       stream->current_fragment ? stream->current_fragment->data : NULL;
877   guint64 current_time = gst_mss_stream_get_fragment_gst_timestamp (stream);
878   guint fragment_number = 0;
879   guint64 fragment_time_accum = 0;
880
881   if (!current_fragment && stream->fragments) {
882     current_fragment = g_list_last (stream->fragments)->data;
883   } else if (g_list_previous (stream->current_fragment)) {
884     /* rewind one as this is the next to be pushed */
885     current_fragment = g_list_previous (stream->current_fragment)->data;
886   } else {
887     current_fragment = NULL;
888   }
889
890   if (current_fragment) {
891     current_time = current_fragment->time;
892     fragment_number = current_fragment->number;
893     fragment_time_accum = current_fragment->time;
894   }
895
896   for (iter = streamIndex->children; iter; iter = iter->next) {
897     if (node_has_type (iter, MSS_NODE_STREAM_FRAGMENT)) {
898       gchar *duration_str;
899       gchar *time_str;
900       gchar *seqnum_str;
901       GstMssStreamFragment *fragment = g_new (GstMssStreamFragment, 1);
902
903       duration_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_DURATION);
904       time_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_TIME);
905       seqnum_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_NUMBER);
906
907       /* use the node's seq number or use the previous + 1 */
908       if (seqnum_str) {
909         fragment->number = g_ascii_strtoull (seqnum_str, NULL, 10);
910         xmlFree (seqnum_str);
911       } else {
912         fragment->number = fragment_number;
913       }
914       fragment_number = fragment->number + 1;
915
916       if (time_str) {
917         fragment->time = g_ascii_strtoull (time_str, NULL, 10);
918         xmlFree (time_str);
919         fragment_time_accum = fragment->time;
920       } else {
921         fragment->time = fragment_time_accum;
922       }
923
924       /* if we have a previous fragment, means we need to set its duration */
925       if (previous_fragment)
926         previous_fragment->duration = fragment->time - previous_fragment->time;
927
928       if (duration_str) {
929         fragment->duration = g_ascii_strtoull (duration_str, NULL, 10);
930
931         previous_fragment = NULL;
932         fragment_time_accum += fragment->duration;
933         xmlFree (duration_str);
934       } else {
935         /* store to set the duration at the next iteration */
936         previous_fragment = fragment;
937       }
938
939       if (fragment->time > current_time) {
940         new_fragments = g_list_append (new_fragments, fragment);
941       } else {
942         previous_fragment = NULL;
943         g_free (fragment);
944       }
945
946     } else {
947       /* TODO gst log this */
948     }
949   }
950
951   /* store the new fragments list */
952   if (new_fragments) {
953     g_list_free_full (stream->fragments, g_free);
954     stream->fragments = new_fragments;
955     stream->current_fragment = new_fragments;
956   }
957 }
958
959 static void
960 gst_mss_manifest_reload_fragments_from_xml (GstMssManifest * manifest,
961     xmlNodePtr root)
962 {
963   xmlNodePtr nodeiter;
964   GSList *streams = manifest->streams;
965
966   /* we assume the server is providing the streams in the same order in
967    * every manifest */
968   for (nodeiter = root->children; nodeiter && streams;
969       nodeiter = nodeiter->next) {
970     if (nodeiter->type == XML_ELEMENT_NODE
971         && (strcmp ((const char *) nodeiter->name, "StreamIndex") == 0)) {
972       gst_mss_stream_reload_fragments (streams->data, nodeiter);
973       streams = g_slist_next (streams);
974     }
975   }
976 }
977
978 void
979 gst_mss_manifest_reload_fragments (GstMssManifest * manifest, GstBuffer * data)
980 {
981   xmlDocPtr xml;
982   xmlNodePtr root;
983
984   g_return_if_fail (manifest->is_live);
985
986   xml = xmlReadMemory ((const gchar *) GST_BUFFER_DATA (data),
987       GST_BUFFER_SIZE (data), "manifest", NULL, 0);
988   root = xmlDocGetRootElement (xml);
989
990   gst_mss_manifest_reload_fragments_from_xml (manifest, root);
991
992   xmlFreeDoc (xml);
993 }
994
995 gboolean
996 gst_mss_stream_select_bitrate (GstMssStream * stream, guint64 bitrate)
997 {
998   GList *iter = stream->current_quality;
999   GList *next;
1000   GstMssStreamQuality *q = iter->data;
1001
1002   while (q->bitrate > bitrate) {
1003     next = g_list_previous (iter);
1004     if (next) {
1005       iter = next;
1006       q = iter->data;
1007     } else {
1008       break;
1009     }
1010   }
1011
1012   while (q->bitrate < bitrate) {
1013     GstMssStreamQuality *next_q;
1014     next = g_list_next (iter);
1015     if (next) {
1016       next_q = next->data;
1017       if (next_q->bitrate < bitrate) {
1018         iter = next;
1019         q = iter->data;
1020       } else {
1021         break;
1022       }
1023     } else {
1024       break;
1025     }
1026   }
1027
1028   if (iter == stream->current_quality)
1029     return FALSE;
1030   stream->current_quality = iter;
1031   return TRUE;
1032 }
1033
1034 guint64
1035 gst_mss_stream_get_current_bitrate (GstMssStream * stream)
1036 {
1037   GstMssStreamQuality *q;
1038   if (stream->current_quality == NULL)
1039     return 0;
1040
1041   q = stream->current_quality->data;
1042   return q->bitrate;
1043 }
1044
1045 /**
1046  * gst_mss_manifest_change_bitrate:
1047  * @manifest: the manifest
1048  * @bitrate: the maximum bitrate to use (bps)
1049  *
1050  * Iterates over the active streams and changes their bitrates to the maximum
1051  * value so that the bitrates of all streams are not larger than
1052  * @bitrate.
1053  *
1054  * Return: %TRUE if any stream changed its bitrate
1055  */
1056 gboolean
1057 gst_mss_manifest_change_bitrate (GstMssManifest * manifest, guint64 bitrate)
1058 {
1059   gboolean ret = FALSE;
1060   GSList *iter;
1061
1062   /* TODO This algorithm currently sets the same bitrate for all streams,
1063    * it should actually use the sum of all streams bitrates to compare to
1064    * the target value */
1065
1066   if (bitrate == 0) {
1067     /* use maximum */
1068     bitrate = G_MAXUINT64;
1069   }
1070
1071   for (iter = gst_mss_manifest_get_streams (manifest); iter;
1072       iter = g_slist_next (iter)) {
1073     GstMssStream *stream = iter->data;
1074     if (stream->active) {
1075       ret = ret | gst_mss_stream_select_bitrate (stream, bitrate);
1076     }
1077   }
1078
1079   return ret;
1080 }