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