77118118bf10b1be9619dc65026107f4695611d5
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / ext / adaptivedemux2 / mss / gstmssdemux.c
1 /* GStreamer
2  * Copyright (C) 2012 Smart TV Alliance
3  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>, Collabora Ltd.
4  *
5  * gstmssdemux.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 /**
24  * SECTION:element-mssdemux
25  * @title: mssdemux
26  *
27  * Demuxes a Microsoft's Smooth Streaming manifest into its audio and/or video streams.
28  *
29  */
30
31 /*
32  * == Internals
33  *
34  * = Smooth streaming in a few lines
35  * A SS stream is defined by a xml manifest file. This file has a list of
36  * tracks (StreamIndex), each one can have multiple QualityLevels, that define
37  * different encoding/bitrates. When playing a track, only one of those
38  * QualityLevels can be active at a time (per stream).
39  *
40  * The StreamIndex defines a URL with {time} and {bitrate} tags that are
41  * replaced by values indicated by the fragment start times and the selected
42  * QualityLevel, that generates the fragments URLs.
43  *
44  * Another relevant detail is that the Isomedia fragments for smoothstreaming
45  * won't contains a 'moov' atom, nor a 'stsd', so there is no information
46  * about the media type/configuration on the fragments, it must be extracted
47  * from the Manifest and passed downstream. mssdemux does this via GstCaps.
48  *
49  * = How mssdemux works
50  * There is a gstmssmanifest.c utility that holds the manifest and parses
51  * and has functions to extract information from it. mssdemux received the
52  * manifest from its sink pad and starts processing it when it gets EOS.
53  *
54  * The Manifest is parsed and the streams are exposed, 1 pad for each, with
55  * a initially selected QualityLevel. Each stream starts its own GstTaks that
56  * is responsible for downloading fragments and pushing them downstream.
57  *
58  * When a new connection-speed is set, mssdemux evaluates the available
59  * QualityLevels and might decide to switch to another one. In this case it
60  * pushes a new GstCaps event indicating the new caps on the pads.
61  *
62  * All operations that intend to update the GstTasks state should be protected
63  * with the GST_OBJECT_LOCK.
64  */
65
66 #ifdef HAVE_CONFIG_H
67 #include "config.h"
68 #endif
69
70 #include <glib/gi18n-lib.h>
71
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75
76 #include "gstadaptivedemuxelements.h"
77 #include "gstmssdemux.h"
78
79 GST_DEBUG_CATEGORY (mssdemux2_debug);
80 #define GST_CAT_DEFAULT mssdemux2_debug
81
82 static GstStaticPadTemplate gst_mss_demux_sink_template =
83 GST_STATIC_PAD_TEMPLATE ("sink",
84     GST_PAD_SINK,
85     GST_PAD_ALWAYS,
86     GST_STATIC_CAPS ("application/vnd.ms-sstr+xml")
87     );
88
89 static GstStaticPadTemplate gst_mss_demux_videosrc_template =
90 GST_STATIC_PAD_TEMPLATE ("video_%02u",
91     GST_PAD_SRC,
92     GST_PAD_SOMETIMES,
93     GST_STATIC_CAPS_ANY);
94
95 static GstStaticPadTemplate gst_mss_demux_audiosrc_template =
96 GST_STATIC_PAD_TEMPLATE ("audio_%02u",
97     GST_PAD_SRC,
98     GST_PAD_SOMETIMES,
99     GST_STATIC_CAPS_ANY);
100
101 typedef struct _GstMssDemux2 GstMssDemux2;
102 typedef struct _GstMssDemux2Class GstMssDemux2Class;
103
104 #define gst_mss_demux2_parent_class parent_class
105 G_DEFINE_TYPE (GstMssDemux2, gst_mss_demux2, GST_TYPE_ADAPTIVE_DEMUX);
106
107 #define gst_mss_demux_stream_parent_class stream_parent_class
108 G_DEFINE_TYPE (GstMssDemuxStream, gst_mss_demux_stream,
109     GST_TYPE_ADAPTIVE_DEMUX2_STREAM);
110
111 static gboolean mssdemux_element_init (GstPlugin * plugin);
112
113 GST_ELEMENT_REGISTER_DEFINE_CUSTOM (mssdemux2, mssdemux_element_init);
114
115 static void gst_mss_demux_dispose (GObject * object);
116
117 static gboolean gst_mss_demux_is_live (GstAdaptiveDemux * demux);
118 static gboolean gst_mss_demux_process_manifest (GstAdaptiveDemux * demux,
119     GstBuffer * buffer);
120 static GstClockTime gst_mss_demux_get_duration (GstAdaptiveDemux * demux);
121 static void gst_mss_demux_reset (GstAdaptiveDemux * demux);
122 static GstFlowReturn gst_mss_demux_stream_seek (GstAdaptiveDemux2Stream *
123     stream, gboolean forward, GstSeekFlags flags, GstClockTimeDiff ts,
124     GstClockTimeDiff * final_ts);
125 static gboolean gst_mss_demux_stream_has_next_fragment (GstAdaptiveDemux2Stream
126     * stream);
127 static GstFlowReturn
128 gst_mss_demux_stream_advance_fragment (GstAdaptiveDemux2Stream * stream);
129 static gboolean gst_mss_demux_stream_select_bitrate (GstAdaptiveDemux2Stream *
130     stream, guint64 bitrate);
131 static GstFlowReturn
132 gst_mss_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream);
133 static gboolean gst_mss_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
134 static gint64
135 gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux);
136 static GstClockTime
137 gst_mss_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux2Stream *
138     stream);
139 static GstFlowReturn
140 gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux,
141     GstBuffer * buffer);
142 static gboolean gst_mss_demux_get_live_seek_range (GstAdaptiveDemux * demux,
143     gint64 * start, gint64 * stop);
144 static GstFlowReturn gst_mss_demux_data_received (GstAdaptiveDemux * demux,
145     GstAdaptiveDemux2Stream * stream, GstBuffer * buffer);
146 static gboolean
147 gst_mss_demux_requires_periodical_playlist_update (GstAdaptiveDemux * demux);
148 GstStreamType gst_stream_type_from_mss_type (GstMssStreamType mtype);
149
150 static void
151 gst_mss_demux_stream_class_init (GstMssDemuxStreamClass * klass)
152 {
153 }
154
155 static void
156 gst_mss_demux_stream_init (GstMssDemuxStream * stream)
157 {
158 }
159
160 static void
161 gst_mss_demux2_class_init (GstMssDemuxClass * klass)
162 {
163   GObjectClass *gobject_class;
164   GstElementClass *gstelement_class;
165   GstAdaptiveDemuxClass *gstadaptivedemux_class;
166
167   gobject_class = (GObjectClass *) klass;
168   gstelement_class = (GstElementClass *) klass;
169   gstadaptivedemux_class = (GstAdaptiveDemuxClass *) klass;
170
171   gst_element_class_add_static_pad_template (gstelement_class,
172       &gst_mss_demux_sink_template);
173   gst_element_class_add_static_pad_template (gstelement_class,
174       &gst_mss_demux_videosrc_template);
175   gst_element_class_add_static_pad_template (gstelement_class,
176       &gst_mss_demux_audiosrc_template);
177   gst_element_class_set_static_metadata (gstelement_class,
178       "Smooth Streaming demuxer (v2)", "Codec/Demuxer/Adaptive",
179       "Parse and demultiplex a Smooth Streaming manifest into audio and video "
180       "streams", "Thiago Santos <thiago.sousa.santos@collabora.com>");
181
182   gobject_class->dispose = gst_mss_demux_dispose;
183
184   gstadaptivedemux_class->process_manifest = gst_mss_demux_process_manifest;
185   gstadaptivedemux_class->is_live = gst_mss_demux_is_live;
186   gstadaptivedemux_class->get_duration = gst_mss_demux_get_duration;
187   gstadaptivedemux_class->get_manifest_update_interval =
188       gst_mss_demux_get_manifest_update_interval;
189   gstadaptivedemux_class->reset = gst_mss_demux_reset;
190   gstadaptivedemux_class->seek = gst_mss_demux_seek;
191   gstadaptivedemux_class->stream_seek = gst_mss_demux_stream_seek;
192   gstadaptivedemux_class->stream_advance_fragment =
193       gst_mss_demux_stream_advance_fragment;
194   gstadaptivedemux_class->stream_has_next_fragment =
195       gst_mss_demux_stream_has_next_fragment;
196   gstadaptivedemux_class->stream_select_bitrate =
197       gst_mss_demux_stream_select_bitrate;
198   gstadaptivedemux_class->stream_update_fragment_info =
199       gst_mss_demux_stream_update_fragment_info;
200   gstadaptivedemux_class->stream_get_fragment_waiting_time =
201       gst_mss_demux_stream_get_fragment_waiting_time;
202   gstadaptivedemux_class->update_manifest_data =
203       gst_mss_demux_update_manifest_data;
204   gstadaptivedemux_class->get_live_seek_range =
205       gst_mss_demux_get_live_seek_range;
206   gstadaptivedemux_class->data_received = gst_mss_demux_data_received;
207   gstadaptivedemux_class->requires_periodical_playlist_update =
208       gst_mss_demux_requires_periodical_playlist_update;
209
210 }
211
212 static void
213 gst_mss_demux2_init (GstMssDemux * mssdemux)
214 {
215 }
216
217 static void
218 gst_mss_demux_reset (GstAdaptiveDemux * demux)
219 {
220   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
221
222   if (mssdemux->manifest) {
223     gst_mss_manifest_free (mssdemux->manifest);
224     mssdemux->manifest = NULL;
225   }
226   g_free (mssdemux->base_url);
227   mssdemux->base_url = NULL;
228 }
229
230 static void
231 gst_mss_demux_dispose (GObject * object)
232 {
233   gst_mss_demux_reset (GST_ADAPTIVE_DEMUX_CAST (object));
234
235   G_OBJECT_CLASS (parent_class)->dispose (object);
236 }
237
238 static gboolean
239 gst_mss_demux_is_live (GstAdaptiveDemux * demux)
240 {
241   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
242
243   g_return_val_if_fail (mssdemux->manifest != NULL, FALSE);
244
245   return gst_mss_manifest_is_live (mssdemux->manifest);
246 }
247
248 static GstClockTime
249 gst_mss_demux_get_duration (GstAdaptiveDemux * demux)
250 {
251   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
252
253   g_return_val_if_fail (mssdemux->manifest != NULL, FALSE);
254
255   return gst_mss_manifest_get_gst_duration (mssdemux->manifest);
256 }
257
258 static GstFlowReturn
259 gst_mss_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream)
260 {
261   GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
262   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (stream->demux);
263   GstFlowReturn ret;
264   gchar *path = NULL;
265
266   gst_adaptive_demux2_stream_fragment_clear (&stream->fragment);
267   ret = gst_mss_stream_get_fragment_url (mssstream->manifest_stream, &path);
268
269   if (ret == GST_FLOW_OK) {
270     GstUri *base_url, *frag_url;
271
272     base_url = gst_uri_from_string (mssdemux->base_url);
273     frag_url = gst_uri_from_string_with_base (base_url, path);
274
275     g_free (stream->fragment.uri);
276     stream->fragment.uri = gst_uri_to_string (frag_url);
277     stream->fragment.stream_time =
278         gst_mss_stream_get_fragment_gst_timestamp (mssstream->manifest_stream);
279     stream->fragment.duration =
280         gst_mss_stream_get_fragment_gst_duration (mssstream->manifest_stream);
281
282     gst_uri_unref (base_url);
283     gst_uri_unref (frag_url);
284   }
285   g_free (path);
286
287   return ret;
288 }
289
290 static GstFlowReturn
291 gst_mss_demux_stream_seek (GstAdaptiveDemux2Stream * stream, gboolean forward,
292     GstSeekFlags flags, GstClockTimeDiff ts, GstClockTimeDiff * final_ts)
293 {
294   GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
295
296   gst_mss_stream_seek (mssstream->manifest_stream, forward, flags, ts,
297       final_ts);
298   return GST_FLOW_OK;
299 }
300
301 static GstFlowReturn
302 gst_mss_demux_stream_advance_fragment (GstAdaptiveDemux2Stream * stream)
303 {
304   GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
305
306   if (stream->demux->segment.rate >= 0)
307     return gst_mss_stream_advance_fragment (mssstream->manifest_stream);
308   else
309     return gst_mss_stream_regress_fragment (mssstream->manifest_stream);
310 }
311
312 static GstCaps *
313 create_mss_caps (GstMssDemuxStream * stream, GstCaps * caps)
314 {
315   return gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING,
316       "mss-fragmented", "timescale", G_TYPE_UINT64,
317       gst_mss_stream_get_timescale (stream->manifest_stream), "media-caps",
318       GST_TYPE_CAPS, caps, NULL);
319 }
320
321 static void
322 gst_mss_demux_apply_protection_system (GstCaps * caps,
323     const gchar * selected_system)
324 {
325   GstStructure *s;
326
327   g_return_if_fail (selected_system);
328   s = gst_caps_get_structure (caps, 0);
329   gst_structure_set (s,
330       "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
331       GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
332       NULL);
333   gst_structure_set_name (s, "application/x-cenc");
334
335 }
336
337 static gboolean
338 gst_mss_demux_setup_streams (GstAdaptiveDemux * demux)
339 {
340   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
341   GSList *streams = gst_mss_manifest_get_streams (mssdemux->manifest);
342   GSList *active_streams = NULL;
343   GSList *iter;
344   const gchar *protection_system_id =
345       gst_mss_manifest_get_protection_system_id (mssdemux->manifest);
346   const gchar *protection_data =
347       gst_mss_manifest_get_protection_data (mssdemux->manifest);
348   gboolean protected = protection_system_id && protection_data;
349   const gchar *selected_system = NULL;
350   guint64 max_bitrate = G_MAXUINT64;
351
352   if (streams == NULL) {
353     GST_INFO_OBJECT (mssdemux, "No streams found in the manifest");
354     GST_ELEMENT_ERROR (mssdemux, STREAM, DEMUX,
355         (_("This file contains no playable streams.")),
356         ("no streams found at the Manifest"));
357     return FALSE;
358   }
359
360   if (protected) {
361     const gchar *sys_ids[2] = { protection_system_id, NULL };
362
363     selected_system = gst_protection_select_system (sys_ids);
364     if (!selected_system) {
365       GST_ERROR_OBJECT (mssdemux, "stream is protected, but no "
366           "suitable decryptor element has been found");
367       return FALSE;
368     }
369   }
370
371   if (demux->connection_speed != 0)
372     max_bitrate = demux->connection_speed;
373
374   for (iter = streams; iter; iter = g_slist_next (iter)) {
375     GstAdaptiveDemux2Stream *stream = NULL;
376     GstMssDemuxStream *mss_stream;
377     GstMssStream *manifeststream = iter->data;
378     GstAdaptiveDemuxTrack *track;
379     GstStreamType stream_type =
380         gst_stream_type_from_mss_type (gst_mss_stream_get_type
381         (manifeststream));
382     const gchar *lang = gst_mss_stream_get_lang (manifeststream);
383     const gchar *name = gst_mss_stream_get_name (manifeststream);
384     gchar *stream_id;
385     GstCaps *caps;
386     GstTagList *tags = NULL;
387
388     if (stream_type == GST_STREAM_TYPE_UNKNOWN) {
389       GST_WARNING_OBJECT (mssdemux, "Skipping unknown stream %s", name);
390       continue;
391     }
392
393     if (name)
394       stream_id =
395           g_strdup_printf ("mss-stream-%s-%s",
396           gst_stream_type_get_name (stream_type),
397           gst_mss_stream_get_name (manifeststream));
398     else if (lang)
399       stream_id =
400           g_strdup_printf ("mss-stream-%s-%s",
401           gst_stream_type_get_name (stream_type), lang);
402     else
403       stream_id =
404           g_strdup_printf ("mss-stream-%s",
405           gst_stream_type_get_name (stream_type));
406
407     mss_stream =
408         g_object_new (GST_TYPE_MSS_DEMUX_STREAM, "name", stream_id, NULL);
409
410     stream = GST_ADAPTIVE_DEMUX2_STREAM_CAST (mss_stream);
411     stream->stream_type = stream_type;
412
413     mss_stream->manifest_stream = manifeststream;
414     gst_mss_stream_set_active (manifeststream, TRUE);
415
416     /* Set the maximum bitrate now that the underlying stream is active. This
417      * ensures that we get the proper caps and information. */
418     gst_mss_stream_select_bitrate (manifeststream, max_bitrate);
419
420     caps = gst_mss_stream_get_caps (mss_stream->manifest_stream);
421     gst_adaptive_demux2_stream_set_caps (stream, create_mss_caps (mss_stream,
422             caps));
423     if (lang != NULL)
424       tags = gst_tag_list_new (GST_TAG_LANGUAGE_CODE, lang, NULL);
425
426     track = gst_adaptive_demux_track_new (demux, stream_type,
427         GST_STREAM_FLAG_NONE, (gchar *) stream_id, create_mss_caps (mss_stream,
428             caps), tags);
429
430     g_free (stream_id);
431     gst_adaptive_demux2_add_stream (demux, stream);
432     gst_adaptive_demux2_stream_add_track (stream, track);
433     gst_adaptive_demux_track_unref (track);
434
435     GST_DEBUG_OBJECT (stream, "Current quality bitrate %" G_GUINT64_FORMAT,
436         gst_mss_stream_get_current_bitrate (manifeststream));
437
438     if (tags)
439       gst_adaptive_demux2_stream_set_tags (stream, tags);
440
441     active_streams = g_slist_prepend (active_streams, mss_stream);
442   }
443
444   for (iter = active_streams; iter; iter = g_slist_next (iter)) {
445     GstMssDemuxStream *stream = iter->data;
446
447     if (protected) {
448       GstBuffer *protection_buffer =
449           gst_buffer_new_wrapped (g_strdup (protection_data),
450           strlen (protection_data));
451       GstEvent *event =
452           gst_event_new_protection (protection_system_id, protection_buffer,
453           "smooth-streaming");
454
455       GST_LOG_OBJECT (stream, "Queueing Protection event on source pad");
456       gst_adaptive_demux2_stream_queue_event ((GstAdaptiveDemux2Stream *)
457           stream, event);
458       gst_buffer_unref (protection_buffer);
459     }
460   }
461
462   g_slist_free (active_streams);
463   return TRUE;
464 }
465
466 static void
467 gst_mss_demux_update_base_url (GstMssDemux * mssdemux)
468 {
469   GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (mssdemux);
470   GstUri *base_url;
471   gchar *path;
472
473   g_free (mssdemux->base_url);
474
475   mssdemux->base_url =
476       g_strdup (demux->manifest_base_uri ? demux->manifest_base_uri : demux->
477       manifest_uri);
478
479   base_url = gst_uri_from_string (mssdemux->base_url);
480   path = gst_uri_get_path (base_url);
481   GST_DEBUG ("%s", path);
482
483   if (!g_str_has_suffix (path, "/Manifest")
484       && !g_str_has_suffix (path, "/manifest"))
485     GST_WARNING_OBJECT (mssdemux, "Stream's URI didn't end with /manifest");
486
487   g_free (path);
488   gst_uri_unref (base_url);
489 }
490
491 static gboolean
492 gst_mss_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
493 {
494   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
495
496   gst_mss_demux_update_base_url (mssdemux);
497
498   mssdemux->manifest = gst_mss_manifest_new (buf);
499   if (!mssdemux->manifest) {
500     GST_ELEMENT_ERROR (mssdemux, STREAM, FORMAT, ("Bad manifest file"),
501         ("Xml manifest file couldn't be parsed"));
502     return FALSE;
503   }
504   return gst_mss_demux_setup_streams (demux);
505 }
506
507 static gboolean
508 gst_mss_demux_stream_select_bitrate (GstAdaptiveDemux2Stream * stream,
509     guint64 bitrate)
510 {
511   GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
512   gboolean ret = FALSE;
513
514   GST_DEBUG_OBJECT (stream,
515       "Using stream download bitrate %" G_GUINT64_FORMAT, bitrate);
516
517   if (gst_mss_stream_select_bitrate (mssstream->manifest_stream,
518           bitrate / MAX (1.0, ABS (stream->demux->segment.rate)))) {
519     GstCaps *caps;
520     GstCaps *msscaps;
521     GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (stream->demux);
522     const gchar *protection_system_id =
523         gst_mss_manifest_get_protection_system_id (mssdemux->manifest);
524     const gchar *protection_data =
525         gst_mss_manifest_get_protection_data (mssdemux->manifest);
526     gboolean protected = protection_system_id && protection_data;
527
528     caps = gst_mss_stream_get_caps (mssstream->manifest_stream);
529
530     GST_DEBUG_OBJECT (stream,
531         "Starting streams reconfiguration due to bitrate changes");
532
533     if (protected) {
534       const gchar *sys_ids[2] = { protection_system_id, NULL };
535       const gchar *selected_system = gst_protection_select_system (sys_ids);
536
537       if (!selected_system) {
538         GST_ERROR_OBJECT (mssdemux, "stream is protected, but no "
539             "suitable decryptor element has been found");
540         gst_caps_unref (caps);
541         return FALSE;
542       }
543
544       gst_mss_demux_apply_protection_system (caps, selected_system);
545     }
546
547     msscaps = create_mss_caps (mssstream, caps);
548
549     GST_DEBUG_OBJECT (stream,
550         "Stream changed bitrate to %" G_GUINT64_FORMAT " caps: %"
551         GST_PTR_FORMAT,
552         gst_mss_stream_get_current_bitrate (mssstream->manifest_stream), caps);
553
554     gst_caps_unref (caps);
555
556     gst_adaptive_demux2_stream_set_caps (stream, msscaps);
557     ret = TRUE;
558     GST_DEBUG_OBJECT (stream, "Finished streams reconfiguration");
559   }
560   return ret;
561 }
562
563 #define SEEK_UPDATES_PLAY_POSITION(r, start_type, stop_type) \
564   ((r >= 0 && start_type != GST_SEEK_TYPE_NONE) || \
565    (r < 0 && stop_type != GST_SEEK_TYPE_NONE))
566
567 static gboolean
568 gst_mss_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
569 {
570   gdouble rate;
571   GstFormat format;
572   GstSeekFlags flags;
573   GstSeekType start_type, stop_type;
574   gint64 start, stop;
575   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
576
577   gst_event_parse_seek (seek, &rate, &format, &flags, &start_type, &start,
578       &stop_type, &stop);
579
580   GST_DEBUG_OBJECT (mssdemux,
581       "seek event, rate: %f start: %" GST_TIME_FORMAT " stop: %"
582       GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
583
584   if (SEEK_UPDATES_PLAY_POSITION (rate, start_type, stop_type)) {
585     if (rate >= 0)
586       gst_mss_manifest_seek (mssdemux->manifest, rate >= 0, start);
587     else
588       gst_mss_manifest_seek (mssdemux->manifest, rate >= 0, stop);
589   }
590
591   return TRUE;
592 }
593
594 static gboolean
595 gst_mss_demux_stream_has_next_fragment (GstAdaptiveDemux2Stream * stream)
596 {
597   GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
598
599   return gst_mss_stream_has_next_fragment (mssstream->manifest_stream);
600 }
601
602 static gint64
603 gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
604 {
605   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
606   GstClockTime interval;
607
608   /* Not much information about this in the MSS spec. It seems that
609    * the fragments contain an UUID box that should tell the next
610    * fragments time and duration so one wouldn't need to fetch
611    * the Manifest again, but we need a fallback here. So use 2 times
612    * the current fragment duration */
613
614   interval = gst_mss_manifest_get_min_fragment_duration (mssdemux->manifest);
615   if (!GST_CLOCK_TIME_IS_VALID (interval))
616     interval = 2 * GST_SECOND;  /* default to 2 seconds */
617
618   interval = 2 * (interval / GST_USECOND);
619
620   return interval;
621 }
622
623 static GstClockTime
624 gst_mss_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux2Stream *
625     stream)
626 {
627   /* Wait a second for live streams so we don't try premature fragments downloading */
628   return GST_SECOND;
629 }
630
631 static GstFlowReturn
632 gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux,
633     GstBuffer * buffer)
634 {
635   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
636
637   gst_mss_demux_update_base_url (mssdemux);
638
639   gst_mss_manifest_reload_fragments (mssdemux->manifest, buffer);
640   return GST_FLOW_OK;
641 }
642
643 static gboolean
644 gst_mss_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * start,
645     gint64 * stop)
646 {
647   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
648
649   return gst_mss_manifest_get_live_seek_range (mssdemux->manifest, start, stop);
650 }
651
652 static GstFlowReturn
653 gst_mss_demux_data_received (GstAdaptiveDemux * demux,
654     GstAdaptiveDemux2Stream * stream, GstBuffer * buffer)
655 {
656   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
657   GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
658   gsize available;
659
660   if (!gst_mss_manifest_is_live (mssdemux->manifest)) {
661     return gst_adaptive_demux2_stream_push_buffer (stream, buffer);
662   }
663
664   if (gst_mss_stream_fragment_parsing_needed (mssstream->manifest_stream)) {
665     gst_mss_manifest_live_adapter_push (mssstream->manifest_stream, buffer);
666     available =
667         gst_mss_manifest_live_adapter_available (mssstream->manifest_stream);
668     // FIXME: try to reduce this minimal size.
669     if (available < 4096) {
670       return GST_FLOW_OK;
671     } else {
672       GST_LOG_OBJECT (stream, "enough data, parsing fragment.");
673       buffer =
674           gst_mss_manifest_live_adapter_take_buffer (mssstream->manifest_stream,
675           available);
676       gst_mss_stream_parse_fragment (mssstream->manifest_stream, buffer);
677     }
678   }
679
680   return gst_adaptive_demux2_stream_push_buffer (stream, buffer);
681 }
682
683 static gboolean
684 gst_mss_demux_requires_periodical_playlist_update (GstAdaptiveDemux * demux)
685 {
686   return TRUE;
687 }
688
689 GstStreamType
690 gst_stream_type_from_mss_type (GstMssStreamType mtype)
691 {
692   switch (mtype) {
693     case MSS_STREAM_TYPE_AUDIO:
694       return GST_STREAM_TYPE_AUDIO;
695     case MSS_STREAM_TYPE_VIDEO:
696       return GST_STREAM_TYPE_VIDEO;
697     default:
698       return GST_STREAM_TYPE_UNKNOWN;
699   }
700 }
701
702 static gboolean
703 mssdemux_element_init (GstPlugin * plugin)
704 {
705   gboolean ret = TRUE;
706
707   GST_DEBUG_CATEGORY_INIT (mssdemux2_debug, "mssdemux2", 0,
708       "mssdemux2 element");
709
710   if (!adaptivedemux2_base_element_init (plugin))
711     return TRUE;
712
713   ret =
714       gst_element_register (plugin, "mssdemux2", GST_RANK_PRIMARY + 1,
715       GST_TYPE_MSS_DEMUX2);
716
717   return ret;
718 }