2eb187cb45b9449e951b25241ba1a9bcd1211602
[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 <libxml/parser.h>
26 #include <libxml/tree.h>
27
28 /* for parsing h264 codec data */
29 #include <gst/codecparsers/gsth264parser.h>
30
31 #include "gstmssmanifest.h"
32
33 #define DEFAULT_TIMESCALE             10000000
34
35 #define MSS_NODE_STREAM_FRAGMENT      "c"
36 #define MSS_NODE_STREAM_QUALITY       "QualityLevel"
37
38 #define MSS_PROP_BITRATE              "Bitrate"
39 #define MSS_PROP_DURATION             "d"
40 #define MSS_PROP_NUMBER               "n"
41 #define MSS_PROP_STREAM_DURATION      "Duration"
42 #define MSS_PROP_TIME                 "t"
43 #define MSS_PROP_TIMESCALE            "TimeScale"
44 #define MSS_PROP_URL                  "Url"
45
46 /* TODO check if atoi is successful? */
47
48 typedef struct _GstMssStreamFragment
49 {
50   guint number;
51   guint64 time;
52   guint64 duration;
53 } GstMssStreamFragment;
54
55 struct _GstMssStream
56 {
57   xmlNodePtr xmlnode;
58
59   gint selectedQualityIndex;
60
61   GList *fragments;
62   GList *qualities;
63
64   gchar *url;
65
66   GList *current_fragment;
67   GList *current_quality;
68
69   /* TODO move this to somewhere static */
70   GRegex *regex_bitrate;
71   GRegex *regex_position;
72 };
73
74 struct _GstMssManifest
75 {
76   xmlDocPtr xml;
77   xmlNodePtr xmlrootnode;
78
79   GSList *streams;
80 };
81
82 static gboolean
83 node_has_type (xmlNodePtr node, const gchar * name)
84 {
85   return strcmp ((gchar *) node->name, name) == 0;
86 }
87
88 static void
89 _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
90 {
91   xmlNodePtr iter;
92   GstMssStreamFragment *previous_fragment = NULL;
93   guint fragment_number = 0;
94   guint fragment_time_accum = 0;
95   GError *gerror = NULL;
96
97   stream->xmlnode = node;
98
99   /* get the base url path generator */
100   stream->url = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_URL);
101
102   for (iter = node->children; iter; iter = iter->next) {
103     if (node_has_type (iter, MSS_NODE_STREAM_FRAGMENT)) {
104       gchar *duration_str;
105       gchar *time_str;
106       gchar *seqnum_str;
107       GstMssStreamFragment *fragment = g_new (GstMssStreamFragment, 1);
108
109       duration_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_DURATION);
110       time_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_TIME);
111       seqnum_str = (gchar *) xmlGetProp (iter, (xmlChar *) MSS_PROP_NUMBER);
112
113       /* use the node's seq number or use the previous + 1 */
114       if (seqnum_str) {
115         fragment->number = atoi (seqnum_str);
116         g_free (seqnum_str);
117       } else {
118         fragment->number = fragment_number;
119       }
120       fragment_number = fragment->number + 1;
121
122       if (time_str) {
123         fragment->time = atoi (time_str);
124         g_free (time_str);
125       } else {
126         fragment->time = fragment_time_accum;
127       }
128
129       /* if we have a previous fragment, means we need to set its duration */
130       if (previous_fragment)
131         previous_fragment->duration = fragment->time - previous_fragment->time;
132
133       if (duration_str) {
134         fragment->duration = atoi (duration_str);
135
136         previous_fragment = NULL;
137         fragment_time_accum += fragment->duration;
138         g_free (duration_str);
139       } else {
140         /* store to set the duration at the next iteration */
141         previous_fragment = fragment;
142       }
143
144       /* we reverse it later */
145       stream->fragments = g_list_prepend (stream->fragments, fragment);
146
147     } else if (node_has_type (iter, MSS_NODE_STREAM_QUALITY)) {
148       stream->qualities = g_list_prepend (stream->qualities, iter);
149     } else {
150       /* TODO gst log this */
151     }
152   }
153
154   stream->fragments = g_list_reverse (stream->fragments);
155   stream->qualities = g_list_reverse (stream->qualities);
156
157   stream->current_fragment = stream->fragments;
158   stream->current_quality = stream->qualities;
159
160   stream->regex_bitrate = g_regex_new ("\\{[Bb]itrate\\}", 0, 0, &gerror);
161   stream->regex_position = g_regex_new ("\\{start[ _]time\\}", 0, 0, &gerror);
162 }
163
164 GstMssManifest *
165 gst_mss_manifest_new (const GstBuffer * data)
166 {
167   GstMssManifest *manifest;
168   xmlNodePtr root;
169   xmlNodePtr nodeiter;
170
171   manifest = g_malloc0 (sizeof (GstMssManifest));
172
173   manifest->xml = xmlReadMemory ((const gchar *) GST_BUFFER_DATA (data),
174       GST_BUFFER_SIZE (data), "manifest", NULL, 0);
175   root = manifest->xmlrootnode = xmlDocGetRootElement (manifest->xml);
176
177   for (nodeiter = root->children; nodeiter; nodeiter = nodeiter->next) {
178     if (nodeiter->type == XML_ELEMENT_NODE
179         && (strcmp ((const char *) nodeiter->name, "StreamIndex") == 0)) {
180       GstMssStream *stream = g_new0 (GstMssStream, 1);
181
182       manifest->streams = g_slist_append (manifest->streams, stream);
183       _gst_mss_stream_init (stream, nodeiter);
184     }
185   }
186
187   return manifest;
188 }
189
190 static void
191 gst_mss_stream_free (GstMssStream * stream)
192 {
193   g_list_free_full (stream->fragments, g_free);
194   g_list_free (stream->qualities);
195   g_free (stream->url);
196   g_regex_unref (stream->regex_position);
197   g_regex_unref (stream->regex_bitrate);
198   g_free (stream);
199 }
200
201 void
202 gst_mss_manifest_free (GstMssManifest * manifest)
203 {
204   g_return_if_fail (manifest != NULL);
205
206   g_slist_free_full (manifest->streams, (GDestroyNotify) gst_mss_stream_free);
207
208   xmlFreeDoc (manifest->xml);
209   g_free (manifest);
210 }
211
212 GSList *
213 gst_mss_manifest_get_streams (GstMssManifest * manifest)
214 {
215   return manifest->streams;
216 }
217
218 GstMssStreamType
219 gst_mss_stream_get_type (GstMssStream * stream)
220 {
221   gchar *prop = (gchar *) xmlGetProp (stream->xmlnode, (xmlChar *) "Type");
222   GstMssStreamType ret = MSS_STREAM_TYPE_UNKNOWN;
223
224   if (strcmp (prop, "video") == 0) {
225     ret = MSS_STREAM_TYPE_VIDEO;
226   } else if (strcmp (prop, "audio") == 0) {
227     ret = MSS_STREAM_TYPE_AUDIO;
228   }
229   xmlFree (prop);
230   return ret;
231 }
232
233 static GstCaps *
234 _gst_mss_stream_video_caps_from_fourcc (gchar * fourcc)
235 {
236   if (!fourcc)
237     return NULL;
238
239   if (strcmp (fourcc, "H264") == 0) {
240     return gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
241         "avc", NULL);
242   }
243   return NULL;
244 }
245
246 static GstCaps *
247 _gst_mss_stream_audio_caps_from_fourcc (gchar * fourcc)
248 {
249   if (!fourcc)
250     return NULL;
251
252   if (strcmp (fourcc, "AACL") == 0) {
253     return gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4,
254         NULL);
255   }
256   return NULL;
257 }
258
259 /* copied and adapted from h264parse */
260 static GstBuffer *
261 _make_h264_codec_data (GstBuffer * sps, GstBuffer * pps)
262 {
263   GstBuffer *buf;
264   gint sps_size = 0, pps_size = 0, num_sps = 0, num_pps = 0;
265   guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
266   guint8 *data;
267   gint nl;
268
269   sps_size += GST_BUFFER_SIZE (sps) + 2;
270   profile_idc = GST_BUFFER_DATA (sps)[1];
271   profile_comp = GST_BUFFER_DATA (sps)[2];
272   level_idc = GST_BUFFER_DATA (sps)[3];
273   num_sps = 1;
274
275   pps_size += GST_BUFFER_SIZE (pps) + 2;
276   num_pps = 1;
277
278   buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size);
279   data = GST_BUFFER_DATA (buf);
280   nl = 4;
281
282   data[0] = 1;                  /* AVC Decoder Configuration Record ver. 1 */
283   data[1] = profile_idc;        /* profile_idc                             */
284   data[2] = profile_comp;       /* profile_compability                     */
285   data[3] = level_idc;          /* level_idc                               */
286   data[4] = 0xfc | (nl - 1);    /* nal_length_size_minus1                  */
287   data[5] = 0xe0 | num_sps;     /* number of SPSs */
288
289   data += 6;
290   GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (sps));
291   memcpy (data + 2, GST_BUFFER_DATA (sps), GST_BUFFER_SIZE (sps));
292   data += 2 + GST_BUFFER_SIZE (sps);
293
294   data[0] = num_pps;
295   data++;
296   GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (pps));
297   memcpy (data + 2, GST_BUFFER_DATA (pps), GST_BUFFER_SIZE (pps));
298   data += 2 + GST_BUFFER_SIZE (pps);
299
300   return buf;
301 }
302
303 static void
304 _gst_mss_stream_add_h264_codec_data (GstCaps * caps, const gchar * codecdatastr)
305 {
306   GValue sps_value = { 0, };
307   GValue pps_value = { 0, };
308   GstBuffer *sps;
309   GstBuffer *pps;
310   GstBuffer *buffer;
311   gchar *sps_str;
312   gchar *pps_str;
313   GstH264NalUnit nalu;
314   GstH264SPS sps_struct;
315   GstH264ParserResult parseres;
316
317   /* search for the sps start */
318   if (g_str_has_prefix (codecdatastr, "00000001")) {
319     sps_str = (gchar *) codecdatastr + 8;
320   } else {
321     return;                     /* invalid mss codec data */
322   }
323
324   /* search for the pps start */
325   pps_str = g_strstr_len (sps_str, -1, "00000001");
326   if (!pps_str) {
327     return;                     /* invalid mss codec data */
328   }
329
330   g_value_init (&sps_value, GST_TYPE_BUFFER);
331   pps_str[0] = '\0';
332   gst_value_deserialize (&sps_value, sps_str);
333   pps_str[0] = '0';
334
335   g_value_init (&pps_value, GST_TYPE_BUFFER);
336   pps_str = pps_str + 8;
337   gst_value_deserialize (&pps_value, pps_str);
338
339   sps = gst_value_get_buffer (&sps_value);
340   pps = gst_value_get_buffer (&pps_value);
341
342   nalu.ref_idc = (GST_BUFFER_DATA (sps)[0] & 0x60) >> 5;
343   nalu.type = GST_H264_NAL_SPS;
344   nalu.size = GST_BUFFER_SIZE (sps);
345   nalu.data = GST_BUFFER_DATA (sps);
346   nalu.offset = 0;
347   nalu.sc_offset = 0;
348   nalu.valid = TRUE;
349
350   parseres = gst_h264_parse_sps (&nalu, &sps_struct, TRUE);
351   if (parseres == GST_H264_PARSER_OK) {
352     gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
353         sps_struct.fps_num, sps_struct.fps_den, NULL);
354   }
355
356   buffer = _make_h264_codec_data (sps, pps);
357   g_value_reset (&sps_value);
358   g_value_reset (&pps_value);
359
360   gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL);
361   gst_buffer_unref (buffer);
362 }
363
364 static GstCaps *
365 _gst_mss_stream_video_caps_from_qualitylevel_xml (xmlNodePtr node)
366 {
367   GstCaps *caps;
368   GstStructure *structure;
369   gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
370   gchar *max_width = (gchar *) xmlGetProp (node, (xmlChar *) "MaxWidth");
371   gchar *max_height = (gchar *) xmlGetProp (node, (xmlChar *) "MaxHeight");
372   gchar *codec_data =
373       (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
374
375   caps = _gst_mss_stream_video_caps_from_fourcc (fourcc);
376   if (!caps)
377     goto end;
378
379   structure = gst_caps_get_structure (caps, 0);
380
381   if (max_width)
382     gst_structure_set (structure, "width", G_TYPE_INT, atoi (max_width), NULL);
383   if (max_height)
384     gst_structure_set (structure, "height", G_TYPE_INT, atoi (max_height),
385         NULL);
386
387   if (codec_data) {
388     if (strcmp (fourcc, "H264") == 0) {
389       _gst_mss_stream_add_h264_codec_data (caps, codec_data);
390     } else {
391       GValue *value = g_new0 (GValue, 1);
392       g_value_init (value, GST_TYPE_BUFFER);
393       gst_value_deserialize (value, (gchar *) codec_data);
394       gst_structure_take_value (structure, "codec_data", value);
395     }
396   }
397
398 end:
399   g_free (fourcc);
400   g_free (max_width);
401   g_free (max_height);
402   g_free (codec_data);
403
404   return caps;
405 }
406
407 static GstCaps *
408 _gst_mss_stream_audio_caps_from_qualitylevel_xml (xmlNodePtr node)
409 {
410   GstCaps *caps;
411   GstStructure *structure;
412   gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
413   gchar *channels = (gchar *) xmlGetProp (node, (xmlChar *) "Channels");
414   gchar *rate = (gchar *) xmlGetProp (node, (xmlChar *) "SamplingRate");
415   gchar *codec_data =
416       (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
417
418   caps = _gst_mss_stream_audio_caps_from_fourcc (fourcc);
419   if (!caps)
420     goto end;
421
422   structure = gst_caps_get_structure (caps, 0);
423
424   if (channels)
425     gst_structure_set (structure, "channels", G_TYPE_INT, atoi (channels),
426         NULL);
427   if (rate)
428     gst_structure_set (structure, "rate", G_TYPE_INT, atoi (rate), NULL);
429
430   if (codec_data) {
431     GValue *value = g_new0 (GValue, 1);
432     g_value_init (value, GST_TYPE_BUFFER);
433     gst_value_deserialize (value, (gchar *) codec_data);
434     gst_structure_take_value (structure, "codec_data", value);
435   }
436
437 end:
438   g_free (fourcc);
439   g_free (channels);
440   g_free (rate);
441   g_free (codec_data);
442
443   return caps;
444 }
445
446 guint64
447 gst_mss_stream_get_timescale (GstMssStream * stream)
448 {
449   gchar *timescale;
450   guint64 ts = DEFAULT_TIMESCALE;
451
452   timescale =
453       (gchar *) xmlGetProp (stream->xmlnode, (xmlChar *) MSS_PROP_TIMESCALE);
454   if (!timescale) {
455     timescale =
456         (gchar *) xmlGetProp (stream->xmlnode->parent,
457         (xmlChar *) MSS_PROP_TIMESCALE);
458   }
459
460   if (timescale) {
461     ts = strtoull (timescale, NULL, 10);
462     g_free (timescale);
463   }
464   return ts;
465 }
466
467 guint64
468 gst_mss_manifest_get_timescale (GstMssManifest * manifest)
469 {
470   gchar *timescale;
471   guint64 ts = DEFAULT_TIMESCALE;
472
473   timescale =
474       (gchar *) xmlGetProp (manifest->xmlrootnode,
475       (xmlChar *) MSS_PROP_TIMESCALE);
476   if (timescale) {
477     ts = strtoull (timescale, NULL, 10);
478     g_free (timescale);
479   }
480   return ts;
481 }
482
483 guint64
484 gst_mss_manifest_get_duration (GstMssManifest * manifest)
485 {
486   gchar *duration;
487   guint64 dur = -1;
488
489   duration =
490       (gchar *) xmlGetProp (manifest->xmlrootnode,
491       (xmlChar *) MSS_PROP_STREAM_DURATION);
492   if (duration) {
493     dur = strtoull (duration, NULL, 10);
494     g_free (duration);
495   }
496   return dur;
497 }
498
499
500 /**
501  * Gets the duration in nanoseconds
502  */
503 GstClockTime
504 gst_mss_manifest_get_gst_duration (GstMssManifest * manifest)
505 {
506   guint64 duration = -1;
507   guint64 timescale;
508   GstClockTime gstdur = GST_CLOCK_TIME_NONE;
509
510   duration = gst_mss_manifest_get_duration (manifest);
511   timescale = gst_mss_manifest_get_timescale (manifest);
512
513   if (duration != -1 && timescale != -1)
514     gstdur =
515         (GstClockTime) gst_util_uint64_scale_round (duration, GST_SECOND,
516         timescale);
517
518   return gstdur;
519 }
520
521 GstCaps *
522 gst_mss_stream_get_caps (GstMssStream * stream)
523 {
524   GstMssStreamType streamtype = gst_mss_stream_get_type (stream);
525   xmlNodePtr qualitylevel = stream->current_quality->data;
526   GstCaps *caps = NULL;
527
528   if (streamtype == MSS_STREAM_TYPE_VIDEO)
529     caps = _gst_mss_stream_video_caps_from_qualitylevel_xml (qualitylevel);
530   else if (streamtype == MSS_STREAM_TYPE_AUDIO)
531     caps = _gst_mss_stream_audio_caps_from_qualitylevel_xml (qualitylevel);
532
533   return caps;
534 }
535
536 GstFlowReturn
537 gst_mss_stream_get_fragment_url (GstMssStream * stream, gchar ** url)
538 {
539   gchar *tmp;
540   gchar *bitrate_str;
541   gchar *start_time_str;
542   GstMssStreamFragment *fragment;
543
544   if (stream->current_fragment == NULL) /* stream is over */
545     return GST_FLOW_UNEXPECTED;
546
547   fragment = stream->current_fragment->data;
548
549   bitrate_str =
550       (gchar *) xmlGetProp (stream->current_quality->data,
551       (xmlChar *) MSS_PROP_BITRATE);
552   start_time_str = g_strdup_printf ("%" G_GUINT64_FORMAT, fragment->time);
553
554   tmp = g_regex_replace_literal (stream->regex_bitrate, stream->url,
555       strlen (stream->url), 0, bitrate_str, 0, NULL);
556   *url = g_regex_replace_literal (stream->regex_position, tmp,
557       strlen (tmp), 0, start_time_str, 0, NULL);
558
559   g_free (tmp);
560   g_free (start_time_str);
561   g_free (bitrate_str);
562   return GST_FLOW_OK;
563 }
564
565 GstClockTime
566 gst_mss_stream_get_fragment_gst_timestamp (GstMssStream * stream)
567 {
568   guint64 time;
569   guint64 timescale;
570   GstMssStreamFragment *fragment;
571
572   if (!stream->current_fragment)
573     return GST_CLOCK_TIME_NONE;
574
575   fragment = stream->current_fragment->data;
576
577   time = fragment->time;
578   timescale = gst_mss_stream_get_timescale (stream);
579   return (GstClockTime) gst_util_uint64_scale_round (time, GST_SECOND,
580       timescale);
581 }
582
583 GstClockTime
584 gst_mss_stream_get_fragment_gst_duration (GstMssStream * stream)
585 {
586   guint64 dur;
587   guint64 timescale;
588   GstMssStreamFragment *fragment;
589
590   if (!stream->current_fragment)
591     return GST_CLOCK_TIME_NONE;
592
593   fragment = stream->current_fragment->data;
594
595   dur = fragment->duration;
596   timescale = gst_mss_stream_get_timescale (stream);
597   return (GstClockTime) gst_util_uint64_scale_round (dur, GST_SECOND,
598       timescale);
599 }
600
601 GstFlowReturn
602 gst_mss_stream_advance_fragment (GstMssStream * stream)
603 {
604   if (stream->current_fragment == NULL)
605     return GST_FLOW_UNEXPECTED;
606
607   stream->current_fragment = g_list_next (stream->current_fragment);
608   if (stream->current_fragment == NULL)
609     return GST_FLOW_UNEXPECTED;
610   return GST_FLOW_OK;
611 }
612
613 const gchar *
614 gst_mss_stream_type_name (GstMssStreamType streamtype)
615 {
616   switch (streamtype) {
617     case MSS_STREAM_TYPE_VIDEO:
618       return "video";
619     case MSS_STREAM_TYPE_AUDIO:
620       return "audio";
621     case MSS_STREAM_TYPE_UNKNOWN:
622     default:
623       return "unknown";
624   }
625 }
626
627 /**
628  * Seeks all streams to the fragment that contains the set time
629  *
630  * @time: time in nanoseconds
631  */
632 gboolean
633 gst_mss_manifest_seek (GstMssManifest * manifest, guint64 time)
634 {
635   gboolean ret = TRUE;
636   GSList *iter;
637
638   for (iter = manifest->streams; iter; iter = g_slist_next (iter)) {
639     ret = gst_mss_stream_seek (iter->data, time) & ret;
640   }
641
642   return ret;
643 }
644
645 /**
646  * Seeks this stream to the fragment that contains the sample at time
647  *
648  * @time: time in nanoseconds
649  */
650 gboolean
651 gst_mss_stream_seek (GstMssStream * stream, guint64 time)
652 {
653   GList *iter;
654   guint64 timescale;
655
656   timescale = gst_mss_stream_get_timescale (stream);
657   time = gst_util_uint64_scale_round (time, timescale, GST_SECOND);
658
659   for (iter = stream->fragments; iter; iter = g_list_next (iter)) {
660     GList *next = g_list_next (iter);
661     if (next) {
662       GstMssStreamFragment *fragment = next->data;
663
664       if (fragment->time > time) {
665         stream->current_fragment = iter;
666         break;
667       }
668     } else {
669       GstMssStreamFragment *fragment = iter->data;
670       if (fragment->time + fragment->duration > time) {
671         stream->current_fragment = iter;
672       } else {
673         stream->current_fragment = NULL;        /* EOS */
674       }
675       break;
676     }
677   }
678
679   return TRUE;
680 }