good:adaptivedemux: Add max video width/height limit property
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / ext / adaptivedemux2 / hls / gsthlsdemux.c
1 /* GStreamer
2  * Copyright (C) 2010 Marc-Andre Lureau <marcandre.lureau@gmail.com>
3  * Copyright (C) 2010 Andoni Morales Alastruey <ylatuya@gmail.com>
4  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
5  *  Author: Youness Alaoui <youness.alaoui@collabora.co.uk>, Collabora Ltd.
6  *  Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
7  * Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com>
8  * Copyright (C) 2015 Tim-Philipp Müller <tim@centricular.com>
9  *
10  * Copyright (C) 2021-2022 Centricular Ltd
11  *   Author: Edward Hervey <edward@centricular.com>
12  *   Author: Jan Schmidt <jan@centricular.com>
13  *
14  * Gsthlsdemux.c:
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Library General Public
18  * License as published by the Free Software Foundation; either
19  * version 2 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Library General Public License for more details.
25  *
26  * You should have received a copy of the GNU Library General Public
27  * License along with this library; if not, write to the
28  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
29  * Boston, MA 02110-1301, USA.
30  */
31 /**
32  * SECTION:element-hlsdemux2
33  * @title: hlsdemux2
34  *
35  * HTTP Live Streaming demuxer element.
36  *
37  * ## Example launch line
38  * |[
39  * gst-launch-1.0 playbin3 uri=http://devimages.apple.com/iphone/samples/bipbop/gear4/prog_index.m3u8
40  * ]|
41  *
42  * Since: 1.22
43  */
44
45 #ifdef HAVE_CONFIG_H
46 #  include "config.h"
47 #endif
48
49 #include <string.h>
50 #include <gst/base/gsttypefindhelper.h>
51 #include <gst/tag/tag.h>
52
53 #include "gsthlselements.h"
54 #include "gstadaptivedemuxelements.h"
55 #include "gsthlsdemux.h"
56
57 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
58     GST_PAD_SINK,
59     GST_PAD_ALWAYS,
60     GST_STATIC_CAPS ("application/x-hls"));
61
62 GST_DEBUG_CATEGORY (gst_hls_demux2_debug);
63 #define GST_CAT_DEFAULT gst_hls_demux2_debug
64
65 enum
66 {
67   PROP_0,
68
69   PROP_START_BITRATE,
70 };
71
72 #define DEFAULT_START_BITRATE 0
73
74 /* Maximum values for mpeg-ts DTS values */
75 #define MPEG_TS_MAX_PTS (((((guint64)1) << 33) * (guint64)100000) / 9)
76
77 /* GObject */
78 static void gst_hls_demux_finalize (GObject * obj);
79
80 /* GstElement */
81 static GstStateChangeReturn
82 gst_hls_demux_change_state (GstElement * element, GstStateChange transition);
83
84 /* GstHLSDemux */
85 static GstFlowReturn gst_hls_demux_update_playlist (GstHLSDemux * demux,
86     gboolean update, GError ** err);
87
88 /* FIXME: the return value is never used? */
89 static gboolean gst_hls_demux_change_playlist (GstHLSDemux * demux,
90     guint max_bitrate, gboolean * changed);
91 static GstBuffer *gst_hls_demux_decrypt_fragment (GstHLSDemux * demux,
92     GstHLSDemuxStream * stream, GstBuffer * encrypted_buffer, GError ** err);
93 static gboolean
94 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
95     const guint8 * key_data, const guint8 * iv_data);
96 static void gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream);
97
98 static gboolean gst_hls_demux_is_live (GstAdaptiveDemux * demux);
99 static GstClockTime gst_hls_demux_get_duration (GstAdaptiveDemux * demux);
100 static gint64 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux *
101     demux);
102 static gboolean gst_hls_demux_process_manifest (GstAdaptiveDemux * demux,
103     GstBuffer * buf);
104 static GstFlowReturn gst_hls_demux_stream_update_rendition_playlist (GstHLSDemux
105     * demux, GstHLSDemuxStream * stream);
106 static GstFlowReturn gst_hls_demux_update_manifest (GstAdaptiveDemux * demux);
107
108 static void setup_initial_playlist (GstHLSDemux * demux,
109     GstHLSMediaPlaylist * playlist);
110 static void gst_hls_demux_add_time_mapping (GstHLSDemux * demux,
111     gint64 dsn, GstClockTimeDiff stream_time, GDateTime * pdt);
112 static void
113 gst_hls_update_time_mappings (GstHLSDemux * demux,
114     GstHLSMediaPlaylist * playlist);
115
116 static void gst_hls_prune_time_mappings (GstHLSDemux * demux);
117
118 static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
119
120 static GstFlowReturn gst_hls_demux_stream_seek (GstAdaptiveDemux2Stream *
121     stream, gboolean forward, GstSeekFlags flags, GstClockTimeDiff ts,
122     GstClockTimeDiff * final_ts);
123
124 static gboolean
125 gst_hls_demux_stream_start_fragment (GstAdaptiveDemux2Stream * stream);
126 static GstFlowReturn
127 gst_hls_demux_stream_finish_fragment (GstAdaptiveDemux2Stream * stream);
128 static GstFlowReturn gst_hls_demux_stream_data_received (GstAdaptiveDemux2Stream
129     * stream, GstBuffer * buffer);
130
131 static gboolean gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemux2Stream
132     * stream);
133 static GstFlowReturn
134 gst_hls_demux_stream_advance_fragment (GstAdaptiveDemux2Stream * stream);
135 static GstFlowReturn
136 gst_hls_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream);
137 static gboolean gst_hls_demux_stream_can_start (GstAdaptiveDemux2Stream *
138     stream);
139 static void gst_hls_demux_stream_create_tracks (GstAdaptiveDemux2Stream *
140     stream);
141 static gboolean gst_hls_demux_stream_select_bitrate (GstAdaptiveDemux2Stream *
142     stream, guint64 bitrate);
143 static GstClockTime
144 gst_hls_demux_stream_get_presentation_offset (GstAdaptiveDemux2Stream * stream);
145
146 static void gst_hls_demux_stream_finalize (GObject * object);
147
148 #define gst_hls_demux_stream_parent_class stream_parent_class
149 G_DEFINE_TYPE (GstHLSDemuxStream, gst_hls_demux_stream,
150     GST_TYPE_ADAPTIVE_DEMUX2_STREAM);
151
152 static gboolean hlsdemux2_element_init (GstPlugin * plugin);
153
154 GST_ELEMENT_REGISTER_DEFINE_CUSTOM (hlsdemux2, hlsdemux2_element_init);
155
156 static void
157 gst_hls_demux_stream_class_init (GstHLSDemuxStreamClass * klass)
158 {
159   GObjectClass *gobject_class = (GObjectClass *) klass;
160   GstAdaptiveDemux2StreamClass *adaptivedemux2stream_class =
161       GST_ADAPTIVE_DEMUX2_STREAM_CLASS (klass);
162
163   gobject_class->finalize = gst_hls_demux_stream_finalize;
164
165   adaptivedemux2stream_class->update_fragment_info =
166       gst_hls_demux_stream_update_fragment_info;
167   adaptivedemux2stream_class->has_next_fragment =
168       gst_hls_demux_stream_has_next_fragment;
169   adaptivedemux2stream_class->stream_seek = gst_hls_demux_stream_seek;
170   adaptivedemux2stream_class->advance_fragment =
171       gst_hls_demux_stream_advance_fragment;
172   adaptivedemux2stream_class->select_bitrate =
173       gst_hls_demux_stream_select_bitrate;
174   adaptivedemux2stream_class->can_start = gst_hls_demux_stream_can_start;
175   adaptivedemux2stream_class->create_tracks =
176       gst_hls_demux_stream_create_tracks;
177
178   adaptivedemux2stream_class->start_fragment =
179       gst_hls_demux_stream_start_fragment;
180   adaptivedemux2stream_class->finish_fragment =
181       gst_hls_demux_stream_finish_fragment;
182   adaptivedemux2stream_class->data_received =
183       gst_hls_demux_stream_data_received;
184   adaptivedemux2stream_class->get_presentation_offset =
185       gst_hls_demux_stream_get_presentation_offset;
186 }
187
188 static void
189 gst_hls_demux_stream_init (GstHLSDemuxStream * stream)
190 {
191   stream->parser_type = GST_HLS_PARSER_NONE;
192   stream->do_typefind = TRUE;
193   stream->reset_pts = TRUE;
194   stream->presentation_offset = 60 * GST_SECOND;
195   stream->pdt_tag_sent = FALSE;
196 }
197
198 typedef struct _GstHLSDemux2 GstHLSDemux2;
199 typedef struct _GstHLSDemux2Class GstHLSDemux2Class;
200
201 #define gst_hls_demux2_parent_class parent_class
202 G_DEFINE_TYPE_WITH_CODE (GstHLSDemux2, gst_hls_demux2, GST_TYPE_ADAPTIVE_DEMUX,
203     hls2_element_init ());
204
205 static void gst_hls_demux_reset (GstAdaptiveDemux * demux);
206 static gboolean gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux,
207     gint64 * start, gint64 * stop);
208 static void gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
209     GstHLSVariantStream * variant);
210
211 static void
212 gst_hls_demux_finalize (GObject * obj)
213 {
214   GstHLSDemux *demux = GST_HLS_DEMUX (obj);
215
216   gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
217   g_mutex_clear (&demux->keys_lock);
218   if (demux->keys) {
219     g_hash_table_unref (demux->keys);
220     demux->keys = NULL;
221   }
222
223   G_OBJECT_CLASS (parent_class)->finalize (obj);
224 }
225
226 static void
227 gst_hls_demux_set_property (GObject * object, guint prop_id,
228     const GValue * value, GParamSpec * pspec)
229 {
230   GstHLSDemux *demux = GST_HLS_DEMUX (object);
231
232   switch (prop_id) {
233     case PROP_START_BITRATE:
234       demux->start_bitrate = g_value_get_uint (value);
235       break;
236     default:
237       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
238       break;
239   }
240 }
241
242 static void
243 gst_hls_demux_get_property (GObject * object, guint prop_id,
244     GValue * value, GParamSpec * pspec)
245 {
246   GstHLSDemux *demux = GST_HLS_DEMUX (object);
247
248   switch (prop_id) {
249     case PROP_START_BITRATE:
250       g_value_set_uint (value, demux->start_bitrate);
251       break;
252     default:
253       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
254       break;
255   }
256 }
257
258
259 static void
260 gst_hls_demux2_class_init (GstHLSDemux2Class * klass)
261 {
262   GObjectClass *gobject_class;
263   GstElementClass *element_class;
264   GstAdaptiveDemuxClass *adaptivedemux_class;
265
266   gobject_class = (GObjectClass *) klass;
267   element_class = (GstElementClass *) klass;
268   adaptivedemux_class = (GstAdaptiveDemuxClass *) klass;
269
270   gobject_class->set_property = gst_hls_demux_set_property;
271   gobject_class->get_property = gst_hls_demux_get_property;
272   gobject_class->finalize = gst_hls_demux_finalize;
273
274   g_object_class_install_property (gobject_class, PROP_START_BITRATE,
275       g_param_spec_uint ("start-bitrate", "Starting Bitrate",
276           "Initial bitrate to use to choose first alternate (0 = automatic) (bits/s)",
277           0, G_MAXUINT, DEFAULT_START_BITRATE,
278           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
279
280   element_class->change_state = GST_DEBUG_FUNCPTR (gst_hls_demux_change_state);
281
282   gst_element_class_add_static_pad_template (element_class, &sinktemplate);
283
284   gst_element_class_set_static_metadata (element_class,
285       "HLS Demuxer",
286       "Codec/Demuxer/Adaptive",
287       "HTTP Live Streaming demuxer",
288       "Edward Hervey <edward@centricular.com>\n"
289       "Jan Schmidt <jan@centricular.com>");
290
291   adaptivedemux_class->is_live = gst_hls_demux_is_live;
292   adaptivedemux_class->get_live_seek_range = gst_hls_demux_get_live_seek_range;
293   adaptivedemux_class->get_duration = gst_hls_demux_get_duration;
294   adaptivedemux_class->get_manifest_update_interval =
295       gst_hls_demux_get_manifest_update_interval;
296   adaptivedemux_class->process_manifest = gst_hls_demux_process_manifest;
297   adaptivedemux_class->update_manifest = gst_hls_demux_update_manifest;
298   adaptivedemux_class->reset = gst_hls_demux_reset;
299   adaptivedemux_class->seek = gst_hls_demux_seek;
300 }
301
302 static void
303 gst_hls_demux2_init (GstHLSDemux * demux)
304 {
305   demux->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
306   g_mutex_init (&demux->keys_lock);
307 }
308
309 static GstStateChangeReturn
310 gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
311 {
312   GstStateChangeReturn ret;
313   GstHLSDemux *demux = GST_HLS_DEMUX (element);
314
315   switch (transition) {
316     case GST_STATE_CHANGE_READY_TO_PAUSED:
317       gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
318       break;
319     default:
320       break;
321   }
322
323   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
324
325   switch (transition) {
326     case GST_STATE_CHANGE_PAUSED_TO_READY:
327       gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
328       g_hash_table_remove_all (demux->keys);
329       break;
330     default:
331       break;
332   }
333   return ret;
334 }
335
336 static guint64
337 gst_hls_demux_get_bitrate (GstHLSDemux * hlsdemux)
338 {
339   GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (hlsdemux);
340
341   /* FIXME !!!
342    *
343    * No, there isn't a single output :D */
344
345   /* Valid because hlsdemux only has a single output */
346   if (demux->input_period->streams) {
347     GstAdaptiveDemux2Stream *stream = demux->input_period->streams->data;
348     return stream->current_download_rate;
349   }
350
351   return 0;
352 }
353
354 static void
355 gst_hls_demux_stream_clear_pending_data (GstHLSDemuxStream * hls_stream,
356     gboolean force)
357 {
358   GST_DEBUG_OBJECT (hls_stream, "force : %d", force);
359   if (hls_stream->pending_encrypted_data)
360     gst_adapter_clear (hls_stream->pending_encrypted_data);
361   gst_buffer_replace (&hls_stream->pending_decrypted_buffer, NULL);
362   gst_buffer_replace (&hls_stream->pending_typefind_buffer, NULL);
363   if (force || !hls_stream->pending_data_is_header) {
364     gst_buffer_replace (&hls_stream->pending_segment_data, NULL);
365     hls_stream->pending_data_is_header = FALSE;
366   }
367   hls_stream->current_offset = -1;
368   hls_stream->process_buffer_content = TRUE;
369   gst_hls_demux_stream_decrypt_end (hls_stream);
370 }
371
372 static void
373 gst_hls_demux_clear_all_pending_data (GstHLSDemux * hlsdemux)
374 {
375   GstAdaptiveDemux *demux = (GstAdaptiveDemux *) hlsdemux;
376   GList *walk;
377
378   if (!demux->input_period)
379     return;
380
381   for (walk = demux->input_period->streams; walk != NULL; walk = walk->next) {
382     GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (walk->data);
383     gst_hls_demux_stream_clear_pending_data (hls_stream, TRUE);
384   }
385 }
386
387 #define SEEK_UPDATES_PLAY_POSITION(r, start_type, stop_type) \
388   ((r >= 0 && start_type != GST_SEEK_TYPE_NONE) || \
389    (r < 0 && stop_type != GST_SEEK_TYPE_NONE))
390
391 #define IS_SNAP_SEEK(f) (f & (GST_SEEK_FLAG_SNAP_BEFORE |         \
392                               GST_SEEK_FLAG_SNAP_AFTER |          \
393                               GST_SEEK_FLAG_SNAP_NEAREST |        \
394                               GST_SEEK_FLAG_TRICKMODE_KEY_UNITS | \
395                               GST_SEEK_FLAG_KEY_UNIT))
396
397 static gboolean
398 gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
399 {
400   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
401   GstFormat format;
402   GstSeekFlags flags;
403   GstSeekType start_type, stop_type;
404   gint64 start, stop;
405   gdouble rate, old_rate;
406   GList *walk;
407   gint64 current_pos, target_pos, final_pos;
408   guint64 bitrate;
409
410   gst_event_parse_seek (seek, &rate, &format, &flags, &start_type, &start,
411       &stop_type, &stop);
412
413   if (!SEEK_UPDATES_PLAY_POSITION (rate, start_type, stop_type)) {
414     /* nothing to do if we don't have to update the current position */
415     return TRUE;
416   }
417
418   old_rate = demux->segment.rate;
419
420   bitrate = gst_hls_demux_get_bitrate (hlsdemux);
421
422   /* Use I-frame variants for trick modes */
423   if (hlsdemux->master->iframe_variants != NULL
424       && rate < -1.0 && old_rate >= -1.0 && old_rate <= 1.0) {
425     GError *err = NULL;
426
427     /* Switch to I-frame variant */
428     gst_hls_demux_set_current_variant (hlsdemux,
429         hlsdemux->master->iframe_variants->data);
430
431     if (gst_hls_demux_update_playlist (hlsdemux, FALSE, &err) != GST_FLOW_OK) {
432       GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err);
433       return FALSE;
434     }
435     //hlsdemux->discont = TRUE;
436
437     gst_hls_demux_change_playlist (hlsdemux, bitrate / ABS (rate), NULL);
438   } else if (rate > -1.0 && rate <= 1.0 && (old_rate < -1.0 || old_rate > 1.0)) {
439     GError *err = NULL;
440     /* Switch to normal variant */
441     gst_hls_demux_set_current_variant (hlsdemux,
442         hlsdemux->master->variants->data);
443
444     if (gst_hls_demux_update_playlist (hlsdemux, FALSE, &err) != GST_FLOW_OK) {
445       GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err);
446       return FALSE;
447     }
448     //hlsdemux->discont = TRUE;
449     /* TODO why not continue using the same? that was being used up to now? */
450     gst_hls_demux_change_playlist (hlsdemux, bitrate, NULL);
451   }
452
453   target_pos = rate < 0 ? stop : start;
454   final_pos = target_pos;
455
456   /* properly cleanup pending decryption status */
457   if (flags & GST_SEEK_FLAG_FLUSH) {
458     gst_hls_demux_clear_all_pending_data (hlsdemux);
459     gst_hls_prune_time_mappings (hlsdemux);
460   }
461
462   for (walk = demux->input_period->streams; walk; walk = g_list_next (walk)) {
463     GstAdaptiveDemux2Stream *stream =
464         GST_ADAPTIVE_DEMUX2_STREAM_CAST (walk->data);
465
466     /* Only seek on selected streams */
467     if (!gst_adaptive_demux2_stream_is_selected (stream))
468       continue;
469
470     if (gst_hls_demux_stream_seek (stream, rate >= 0, flags, target_pos,
471             &current_pos) != GST_FLOW_OK) {
472       GST_ERROR_OBJECT (stream, "Failed to seek on stream");
473       return FALSE;
474     }
475
476     /* FIXME: use minimum position always ? */
477     if (final_pos > current_pos)
478       final_pos = current_pos;
479   }
480
481   if (IS_SNAP_SEEK (flags)) {
482     if (rate >= 0)
483       gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
484           final_pos, stop_type, stop, NULL);
485     else
486       gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
487           start, stop_type, final_pos, NULL);
488   }
489
490   return TRUE;
491 }
492
493 static GstFlowReturn
494 gst_hls_demux_stream_seek (GstAdaptiveDemux2Stream * stream, gboolean forward,
495     GstSeekFlags flags, GstClockTimeDiff ts, GstClockTimeDiff * final_ts)
496 {
497   GstFlowReturn ret = GST_FLOW_OK;
498   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
499   GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
500   GstM3U8MediaSegment *new_position;
501
502   GST_DEBUG_OBJECT (stream,
503       "is_variant:%d media:%p current_variant:%p forward:%d ts:%"
504       GST_TIME_FORMAT, hls_stream->is_variant, hls_stream->current_rendition,
505       hlsdemux->current_variant, forward, GST_TIME_ARGS (ts));
506
507   /* If the rendition playlist needs to be updated, do it now */
508   if (!hls_stream->is_variant && !hls_stream->playlist_fetched) {
509     ret = gst_hls_demux_stream_update_rendition_playlist (hlsdemux, hls_stream);
510     if (ret != GST_FLOW_OK) {
511       GST_WARNING_OBJECT (stream,
512           "Failed to update the rendition playlist before seeking");
513       return ret;
514     }
515   }
516
517   new_position =
518       gst_hls_media_playlist_seek (hls_stream->playlist, forward, flags, ts);
519   if (new_position) {
520     if (hls_stream->current_segment)
521       gst_m3u8_media_segment_unref (hls_stream->current_segment);
522     hls_stream->current_segment = new_position;
523     hls_stream->reset_pts = TRUE;
524     if (final_ts)
525       *final_ts = new_position->stream_time;
526   } else {
527     GST_WARNING_OBJECT (stream, "Seeking failed");
528     ret = GST_FLOW_ERROR;
529   }
530
531   return ret;
532 }
533
534 static GstFlowReturn
535 gst_hls_demux_update_manifest (GstAdaptiveDemux * demux)
536 {
537   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
538
539   return gst_hls_demux_update_playlist (hlsdemux, TRUE, NULL);
540 }
541
542 static GstAdaptiveDemux2Stream *
543 create_common_hls_stream (GstHLSDemux * demux, const gchar * name)
544 {
545   GstAdaptiveDemux2Stream *stream;
546
547   stream = g_object_new (GST_TYPE_HLS_DEMUX_STREAM, "name", name, NULL);
548   gst_adaptive_demux2_add_stream ((GstAdaptiveDemux *) demux, stream);
549
550   return stream;
551 }
552
553 static GstAdaptiveDemuxTrack *
554 new_track_for_rendition (GstHLSDemux * demux, GstHLSRenditionStream * rendition,
555     GstCaps * caps, GstStreamFlags flags, GstTagList * tags)
556 {
557   GstAdaptiveDemuxTrack *track;
558   gchar *stream_id;
559   GstStreamType stream_type = gst_stream_type_from_hls_type (rendition->mtype);
560
561   if (rendition->name)
562     stream_id =
563         g_strdup_printf ("%s-%s", gst_stream_type_get_name (stream_type),
564         rendition->name);
565   else if (rendition->lang)
566     stream_id =
567         g_strdup_printf ("%s-%s", gst_stream_type_get_name (stream_type),
568         rendition->lang);
569   else
570     stream_id = g_strdup (gst_stream_type_get_name (stream_type));
571
572   if (rendition->lang) {
573     if (tags == NULL)
574       tags = gst_tag_list_new_empty ();
575     if (gst_tag_check_language_code (rendition->lang))
576       gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_LANGUAGE_CODE,
577           rendition->lang, NULL);
578     else
579       gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_LANGUAGE_NAME,
580           rendition->lang, NULL);
581   }
582
583   if (stream_type == GST_STREAM_TYPE_TEXT)
584     flags |= GST_STREAM_FLAG_SPARSE;
585
586   if (rendition->is_default)
587     flags |= GST_STREAM_FLAG_SELECT;
588
589   track =
590       gst_adaptive_demux_track_new ((GstAdaptiveDemux *) demux, stream_type,
591       flags, stream_id, caps, tags);
592   g_free (stream_id);
593
594   return track;
595 }
596
597 static GstHLSRenditionStream *
598 find_uriless_rendition (GstHLSDemux * demux, GstStreamType stream_type)
599 {
600   GList *tmp;
601
602   for (tmp = demux->master->renditions; tmp; tmp = tmp->next) {
603     GstHLSRenditionStream *media = tmp->data;
604     if (media->uri == NULL &&
605         gst_stream_type_from_hls_type (media->mtype) == stream_type)
606       return media;
607   }
608   return NULL;
609 }
610
611 static GstCaps *
612 get_caps_of_stream_type (GstCaps * full_caps, GstStreamType streamtype)
613 {
614   GstCaps *ret = NULL;
615
616   guint i;
617   for (i = 0; i < gst_caps_get_size (full_caps); i++) {
618     GstStructure *st = gst_caps_get_structure (full_caps, i);
619
620     if (gst_hls_get_stream_type_from_structure (st) == streamtype) {
621       ret = gst_caps_new_empty ();
622       gst_caps_append_structure (ret, gst_structure_copy (st));
623       break;
624     }
625   }
626
627   return ret;
628 }
629
630 static void
631 gst_hls_demux_stream_create_tracks (GstAdaptiveDemux2Stream * stream)
632 {
633   GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
634   GstHLSDemuxStream *hlsdemux_stream = (GstHLSDemuxStream *) stream;
635   guint i;
636   GstStreamType uriless_types = 0;
637   GstCaps *variant_caps = NULL;
638
639   GST_DEBUG_OBJECT (stream, "Update tracks of variant stream");
640
641   if (hlsdemux->master->have_codecs) {
642     variant_caps = gst_hls_master_playlist_get_common_caps (hlsdemux->master);
643   }
644
645   /* Use the stream->stream_collection and manifest to create the appropriate tracks */
646   for (i = 0; i < gst_stream_collection_get_size (stream->stream_collection);
647       i++) {
648     GstStream *gst_stream =
649         gst_stream_collection_get_stream (stream->stream_collection, i);
650     GstStreamType stream_type = gst_stream_get_stream_type (gst_stream);
651     GstAdaptiveDemuxTrack *track;
652     GstHLSRenditionStream *embedded_media = NULL;
653     /* tracks from the variant streams should be prefered over those provided by renditions */
654     GstStreamFlags flags =
655         gst_stream_get_stream_flags (gst_stream) | GST_STREAM_FLAG_SELECT;
656     GstCaps *manifest_caps = NULL;
657
658     if (stream_type == GST_STREAM_TYPE_UNKNOWN)
659       continue;
660
661     if (variant_caps)
662       manifest_caps = get_caps_of_stream_type (variant_caps, stream_type);
663     hlsdemux_stream->rendition_type |= stream_type;
664
665     if ((uriless_types & stream_type) == 0) {
666       /* Do we have a uriless media for this stream type */
667       /* Find if there is a rendition without URI, it will be provided by this variant */
668       embedded_media = find_uriless_rendition (hlsdemux, stream_type);
669       /* Remember we used this type for a embedded media */
670       uriless_types |= stream_type;
671     }
672
673     if (embedded_media) {
674       GstTagList *tags = gst_stream_get_tags (gst_stream);
675       GST_DEBUG_OBJECT (stream, "Adding track '%s' to main variant stream",
676           embedded_media->name);
677       track =
678           new_track_for_rendition (hlsdemux, embedded_media, manifest_caps,
679           flags, tags ? gst_tag_list_make_writable (tags) : tags);
680     } else {
681       gchar *stream_id;
682       stream_id =
683           g_strdup_printf ("main-%s-%d", gst_stream_type_get_name (stream_type),
684           i);
685
686       GST_DEBUG_OBJECT (stream, "Adding track '%s' to main variant stream",
687           stream_id);
688       track =
689           gst_adaptive_demux_track_new (stream->demux, stream_type,
690           flags, stream_id, manifest_caps, NULL);
691       g_free (stream_id);
692     }
693     track->upstream_stream_id =
694         g_strdup (gst_stream_get_stream_id (gst_stream));
695     gst_adaptive_demux2_stream_add_track (stream, track);
696     gst_adaptive_demux_track_unref (track);
697   }
698
699   if (variant_caps)
700     gst_caps_unref (variant_caps);
701
702   /* Update the stream object with rendition types.
703    * FIXME: rendition_type could be removed */
704   stream->stream_type = hlsdemux_stream->rendition_type;
705 }
706
707 static void
708 create_main_variant_stream (GstHLSDemux * demux)
709 {
710   GstAdaptiveDemux2Stream *stream;
711   GstHLSDemuxStream *hlsdemux_stream;
712
713   GST_DEBUG_OBJECT (demux, "Creating main variant stream");
714
715   stream = create_common_hls_stream (demux, "hlsstream-variant");
716   demux->main_stream = hlsdemux_stream = (GstHLSDemuxStream *) stream;
717   hlsdemux_stream->is_variant = TRUE;
718   hlsdemux_stream->playlist_fetched = TRUE;
719   /* Due to HLS manifest information being so unreliable/inconsistent, we will
720    * create the actual tracks once we have information about the streams present
721    * in the variant data stream */
722   stream->pending_tracks = TRUE;
723 }
724
725 static GstHLSDemuxStream *
726 create_rendition_stream (GstHLSDemux * demux, GstHLSRenditionStream * media)
727 {
728   GstAdaptiveDemux2Stream *stream;
729   GstAdaptiveDemuxTrack *track;
730   GstHLSDemuxStream *hlsdemux_stream;
731   gchar *stream_name;
732
733   GST_DEBUG_OBJECT (demux,
734       "Creating stream for media %s lang:%s (%" GST_PTR_FORMAT ")", media->name,
735       media->lang, media->caps);
736
737   /* We can't reliably provide caps for HLS target tracks since they might
738    * change at any point in time */
739   track = new_track_for_rendition (demux, media, NULL, 0, NULL);
740
741   stream_name = g_strdup_printf ("hlsstream-%s", track->stream_id);
742   stream = create_common_hls_stream (demux, stream_name);
743   g_free (stream_name);
744   hlsdemux_stream = (GstHLSDemuxStream *) stream;
745
746   hlsdemux_stream->is_variant = FALSE;
747   hlsdemux_stream->playlist_fetched = FALSE;
748   stream->stream_type = hlsdemux_stream->rendition_type =
749       gst_stream_type_from_hls_type (media->mtype);
750   if (media->lang)
751     hlsdemux_stream->lang = g_strdup (media->lang);
752   if (media->name)
753     hlsdemux_stream->name = g_strdup (media->name);
754
755   gst_adaptive_demux2_stream_add_track (stream, track);
756   gst_adaptive_demux_track_unref (track);
757
758   return hlsdemux_stream;
759 }
760
761 static GstHLSDemuxStream *
762 existing_rendition_stream (GList * streams, GstHLSRenditionStream * media)
763 {
764   GList *tmp;
765   GstStreamType stream_type = gst_stream_type_from_hls_type (media->mtype);
766
767   for (tmp = streams; tmp; tmp = tmp->next) {
768     GstHLSDemuxStream *demux_stream = tmp->data;
769
770     if (demux_stream->is_variant)
771       continue;
772
773     if (demux_stream->rendition_type == stream_type) {
774       if (!g_strcmp0 (demux_stream->name, media->name))
775         return demux_stream;
776       if (media->lang && !g_strcmp0 (demux_stream->lang, media->lang))
777         return demux_stream;
778     }
779   }
780
781   return NULL;
782 }
783
784 static gboolean
785 gst_hls_demux_setup_streams (GstAdaptiveDemux * demux)
786 {
787   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
788   GstHLSVariantStream *playlist = hlsdemux->current_variant;
789   GList *tmp;
790   GList *streams = NULL;
791
792   if (playlist == NULL) {
793     GST_WARNING_OBJECT (demux, "Can't configure streams - no variant selected");
794     return FALSE;
795   }
796
797   GST_DEBUG_OBJECT (demux, "Setting up streams");
798
799   /* If there are alternate renditions, we will produce a GstAdaptiveDemux2Stream
800    * and GstAdaptiveDemuxTrack for each combination of GstStreamType and other
801    * unique identifier (for now just language)
802    *
803    * Which actual GstHLSMedia to use for each stream will be determined based on
804    * the `group-id` (if present and more than one) selected on the main variant
805    * stream */
806   for (tmp = hlsdemux->master->renditions; tmp; tmp = tmp->next) {
807     GstHLSRenditionStream *media = tmp->data;
808     GstHLSDemuxStream *media_stream, *previous_media_stream;
809
810     GST_LOG_OBJECT (demux, "Rendition %s name:'%s' lang:'%s' uri:%s",
811         gst_stream_type_get_name (gst_stream_type_from_hls_type (media->mtype)),
812         media->name, media->lang, media->uri);
813
814     if (media->uri == NULL) {
815       GST_DEBUG_OBJECT (demux,
816           "Skipping media '%s' , it's provided by the variant stream",
817           media->name);
818       continue;
819     }
820
821     media_stream = previous_media_stream =
822         existing_rendition_stream (streams, media);
823
824     if (!media_stream) {
825       media_stream = create_rendition_stream (hlsdemux, tmp->data);
826     } else
827       GST_DEBUG_OBJECT (demux, "Re-using existing GstHLSDemuxStream %s %s",
828           media_stream->name, media_stream->lang);
829
830     /* Is this rendition active in the current variant ? */
831     if (!g_strcmp0 (playlist->media_groups[media->mtype], media->group_id)) {
832       GST_DEBUG_OBJECT (demux, "Enabling rendition");
833       if (media_stream->current_rendition)
834         gst_hls_rendition_stream_unref (media_stream->current_rendition);
835       media_stream->current_rendition = gst_hls_rendition_stream_ref (media);
836     }
837
838     if (!previous_media_stream)
839       streams = g_list_append (streams, media_stream);
840   }
841
842   /* Free the list (but not the contents, which are stored
843    * elsewhere */
844   if (streams)
845     g_list_free (streams);
846
847   create_main_variant_stream (hlsdemux);
848
849   return TRUE;
850 }
851
852 static const gchar *
853 gst_adaptive_demux_get_manifest_ref_uri (GstAdaptiveDemux * d)
854 {
855   return d->manifest_base_uri ? d->manifest_base_uri : d->manifest_uri;
856 }
857
858 static void
859 gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
860     GstHLSVariantStream * variant)
861 {
862   if (hlsdemux->current_variant == variant || variant == NULL)
863     return;
864
865   if (hlsdemux->current_variant != NULL) {
866     GST_DEBUG_OBJECT (hlsdemux, "Will switch from variant '%s' to '%s'",
867         hlsdemux->current_variant->name, variant->name);
868     if (hlsdemux->pending_variant) {
869       GST_ERROR_OBJECT (hlsdemux, "Already waiting for pending variant '%s'",
870           hlsdemux->pending_variant->name);
871       gst_hls_variant_stream_unref (hlsdemux->pending_variant);
872     }
873     hlsdemux->pending_variant = gst_hls_variant_stream_ref (variant);
874   } else {
875     GST_DEBUG_OBJECT (hlsdemux, "Setting variant '%s'", variant->name);
876     hlsdemux->current_variant = gst_hls_variant_stream_ref (variant);
877   }
878 }
879
880 static gboolean
881 gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
882 {
883   GstHLSVariantStream *variant;
884   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
885   gchar *playlist = NULL;
886   gboolean ret;
887   GstHLSMediaPlaylist *simple_media_playlist = NULL;
888
889   GST_INFO_OBJECT (demux, "Initial playlist location: %s (base uri: %s)",
890       demux->manifest_uri, demux->manifest_base_uri);
891
892   playlist = gst_hls_buf_to_utf8_text (buf);
893   if (playlist == NULL) {
894     GST_WARNING_OBJECT (demux, "Error validating initial playlist");
895     return FALSE;
896   }
897
898   if (hlsdemux->master) {
899     gst_hls_master_playlist_unref (hlsdemux->master);
900     hlsdemux->master = NULL;
901   }
902   hlsdemux->master = gst_hls_master_playlist_new_from_data (playlist,
903       gst_adaptive_demux_get_manifest_ref_uri (demux));
904
905   if (hlsdemux->master == NULL) {
906     /* In most cases, this will happen if we set a wrong url in the
907      * source element and we have received the 404 HTML response instead of
908      * the playlist */
909     GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid playlist."),
910         ("Could not parse playlist. Check if the URL is correct."));
911     return FALSE;
912   }
913
914   if (hlsdemux->master->is_simple) {
915     simple_media_playlist =
916         gst_hls_media_playlist_parse (playlist,
917         gst_adaptive_demux_get_manifest_ref_uri (demux), NULL);
918   }
919
920   /* select the initial variant stream */
921   if (demux->connection_speed == 0) {
922     variant = hlsdemux->master->default_variant;
923   } else if (hlsdemux->start_bitrate > 0) {
924     variant =
925 #ifdef TIZEN_FEATURE_ADAPTIVE_VARIANT_LIMIT
926         gst_hls_master_playlist_get_variant_for_bitrate_and_resolution (
927         hlsdemux->master, NULL, hlsdemux->start_bitrate, demux->min_bitrate,
928         demux->max_width, demux->max_height);
929 #else
930         gst_hls_master_playlist_get_variant_for_bitrate (hlsdemux->master,
931         NULL, hlsdemux->start_bitrate, demux->min_bitrate);
932 #endif
933   } else {
934     variant =
935 #ifdef TIZEN_FEATURE_ADAPTIVE_VARIANT_LIMIT
936         gst_hls_master_playlist_get_variant_for_bitrate_and_resolution (
937         hlsdemux->master, NULL, demux->connection_speed, demux->min_bitrate,
938         demux->max_width, demux->max_height);
939 #else
940         gst_hls_master_playlist_get_variant_for_bitrate (hlsdemux->master,
941         NULL, demux->connection_speed, demux->min_bitrate);
942 #endif
943   }
944
945   if (variant) {
946     GST_INFO_OBJECT (hlsdemux,
947         "Manifest processed, initial variant selected : `%s`", variant->name);
948     gst_hls_demux_set_current_variant (hlsdemux, variant);      // FIXME: inline?
949   }
950
951   GST_DEBUG_OBJECT (hlsdemux, "Manifest handled, now setting up streams");
952
953   ret = gst_hls_demux_setup_streams (demux);
954
955   if (simple_media_playlist) {
956     hlsdemux->main_stream->playlist = simple_media_playlist;
957     hlsdemux->main_stream->current_segment =
958         gst_hls_media_playlist_get_starting_segment (simple_media_playlist);
959     setup_initial_playlist (hlsdemux, simple_media_playlist);
960     gst_hls_update_time_mappings (hlsdemux, simple_media_playlist);
961     gst_hls_media_playlist_dump (simple_media_playlist);
962   }
963
964   /* get the selected media playlist (unless the initial list was one already) */
965   if (!hlsdemux->master->is_simple) {
966     GError *err = NULL;
967
968     if (gst_hls_demux_update_playlist (hlsdemux, FALSE, &err) != GST_FLOW_OK) {
969       GST_ELEMENT_ERROR_FROM_ERROR (demux, "Could not fetch media playlist",
970           err);
971       return FALSE;
972     }
973   }
974
975   return ret;
976 }
977
978 static GstClockTime
979 gst_hls_demux_get_duration (GstAdaptiveDemux * demux)
980 {
981   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
982   GstClockTime duration = GST_CLOCK_TIME_NONE;
983
984   if (hlsdemux->main_stream)
985     duration =
986         gst_hls_media_playlist_get_duration (hlsdemux->main_stream->playlist);
987
988   return duration;
989 }
990
991 static gboolean
992 gst_hls_demux_is_live (GstAdaptiveDemux * demux)
993 {
994   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
995   gboolean is_live = FALSE;
996
997   if (hlsdemux->main_stream)
998     is_live = gst_hls_media_playlist_is_live (hlsdemux->main_stream->playlist);
999
1000   return is_live;
1001 }
1002
1003 static const GstHLSKey *
1004 gst_hls_demux_get_key (GstHLSDemux * demux, const gchar * key_url,
1005     const gchar * referer, gboolean allow_cache)
1006 {
1007   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX (demux);
1008   DownloadRequest *key_request;
1009   DownloadFlags dl_flags = DOWNLOAD_FLAG_NONE;
1010   GstBuffer *key_buffer;
1011   GstHLSKey *key;
1012   GError *err = NULL;
1013
1014   GST_LOG_OBJECT (demux, "Looking up key for key url %s", key_url);
1015
1016   g_mutex_lock (&demux->keys_lock);
1017
1018   key = g_hash_table_lookup (demux->keys, key_url);
1019
1020   if (key != NULL) {
1021     GST_LOG_OBJECT (demux, "Found key for key url %s in key cache", key_url);
1022     goto out;
1023   }
1024
1025   GST_INFO_OBJECT (demux, "Fetching key %s", key_url);
1026
1027   if (!allow_cache)
1028     dl_flags |= DOWNLOAD_FLAG_FORCE_REFRESH;
1029
1030   key_request =
1031       downloadhelper_fetch_uri (adaptive_demux->download_helper,
1032       key_url, referer, dl_flags, &err);
1033   if (key_request == NULL) {
1034     GST_WARNING_OBJECT (demux, "Failed to download key to decrypt data: %s",
1035         err ? err->message : "error");
1036     g_clear_error (&err);
1037     goto out;
1038   }
1039
1040   key_buffer = download_request_take_buffer (key_request);
1041   download_request_unref (key_request);
1042
1043   key = g_new0 (GstHLSKey, 1);
1044   if (gst_buffer_extract (key_buffer, 0, key->data, 16) < 16)
1045     GST_WARNING_OBJECT (demux, "Download decryption key is too short!");
1046
1047   g_hash_table_insert (demux->keys, g_strdup (key_url), key);
1048
1049   gst_buffer_unref (key_buffer);
1050
1051 out:
1052
1053   g_mutex_unlock (&demux->keys_lock);
1054
1055   if (key != NULL)
1056     GST_MEMDUMP_OBJECT (demux, "Key", key->data, 16);
1057
1058   return key;
1059 }
1060
1061 static gboolean
1062 gst_hls_demux_stream_start_fragment (GstAdaptiveDemux2Stream * stream)
1063 {
1064   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1065   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
1066   const GstHLSKey *key;
1067   GstHLSMediaPlaylist *m3u8;
1068
1069   GST_DEBUG_OBJECT (stream, "Fragment starting");
1070
1071   gst_hls_demux_stream_clear_pending_data (hls_stream, FALSE);
1072
1073   /* If no decryption is needed, there's nothing to be done here */
1074   if (hls_stream->current_key == NULL)
1075     return TRUE;
1076
1077   m3u8 = hls_stream->playlist;
1078
1079   key = gst_hls_demux_get_key (hlsdemux, hls_stream->current_key,
1080       m3u8->uri, m3u8->allowcache);
1081
1082   if (key == NULL)
1083     goto key_failed;
1084
1085   if (!gst_hls_demux_stream_decrypt_start (hls_stream, key->data,
1086           hls_stream->current_iv))
1087     goto decrypt_start_failed;
1088
1089   return TRUE;
1090
1091 key_failed:
1092   {
1093     GST_ELEMENT_ERROR (hlsdemux, STREAM, DECRYPT_NOKEY,
1094         ("Couldn't retrieve key for decryption"), (NULL));
1095     GST_WARNING_OBJECT (hlsdemux, "Failed to decrypt data");
1096     return FALSE;
1097   }
1098 decrypt_start_failed:
1099   {
1100     GST_ELEMENT_ERROR (hlsdemux, STREAM, DECRYPT, ("Failed to start decrypt"),
1101         ("Couldn't set key and IV or plugin was built without crypto library"));
1102     return FALSE;
1103   }
1104 }
1105
1106 static void
1107 gst_hls_demux_start_rendition_streams (GstHLSDemux * hlsdemux)
1108 {
1109   GstAdaptiveDemux *demux = (GstAdaptiveDemux *) hlsdemux;
1110   GList *tmp;
1111
1112   for (tmp = demux->input_period->streams; tmp; tmp = tmp->next) {
1113     GstAdaptiveDemux2Stream *stream = (GstAdaptiveDemux2Stream *) tmp->data;
1114     GstHLSDemuxStream *hls_stream = (GstHLSDemuxStream *) stream;
1115
1116     if (!hls_stream->is_variant
1117         && gst_adaptive_demux2_stream_is_selected (stream))
1118       gst_adaptive_demux2_stream_start (stream);
1119   }
1120 }
1121
1122 static GstHLSParserType
1123 caps_to_parser_type (const GstCaps * caps)
1124 {
1125   const GstStructure *s = gst_caps_get_structure (caps, 0);
1126
1127   if (gst_structure_has_name (s, "video/mpegts"))
1128     return GST_HLS_PARSER_MPEGTS;
1129   if (gst_structure_has_name (s, "application/x-id3"))
1130     return GST_HLS_PARSER_ID3;
1131   if (gst_structure_has_name (s, "application/x-subtitle-vtt"))
1132     return GST_HLS_PARSER_WEBVTT;
1133   if (gst_structure_has_name (s, "video/quicktime"))
1134     return GST_HLS_PARSER_ISOBMFF;
1135
1136   return GST_HLS_PARSER_NONE;
1137 }
1138
1139 /* Identify the nature of data for this stream
1140  *
1141  * Will also setup the appropriate parser (tsreader) if needed
1142  *
1143  * Consumes the input buffer when it returns FALSE, but
1144  * replaces / returns the input buffer in the `buffer` parameter
1145  * when it returns TRUE.
1146  *
1147  * Returns TRUE if we are done with typefinding */
1148 static gboolean
1149 gst_hls_demux_typefind_stream (GstHLSDemux * hlsdemux,
1150     GstAdaptiveDemux2Stream * stream, GstBuffer ** out_buffer, gboolean at_eos,
1151     GstFlowReturn * ret)
1152 {
1153   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
1154   GstCaps *caps = NULL;
1155   guint buffer_size;
1156   GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1157   GstMapInfo info;
1158   GstBuffer *buffer = *out_buffer;
1159
1160   if (hls_stream->pending_typefind_buffer) {
1161     /* Append to the existing typefind buffer and create a new one that
1162      * we'll return (or consume below) */
1163     buffer = *out_buffer =
1164         gst_buffer_append (hls_stream->pending_typefind_buffer, buffer);
1165     hls_stream->pending_typefind_buffer = NULL;
1166   }
1167
1168   gst_buffer_map (buffer, &info, GST_MAP_READ);
1169   buffer_size = info.size;
1170
1171   /* Typefind could miss if buffer is too small. In this case we
1172    * will retry later */
1173   if (buffer_size >= (2 * 1024) || at_eos) {
1174     caps =
1175         gst_type_find_helper_for_data (GST_OBJECT_CAST (hlsdemux), info.data,
1176         info.size, &prob);
1177   }
1178
1179   if (G_UNLIKELY (!caps)) {
1180     /* Won't need this mapping any more all paths return inside this if() */
1181     gst_buffer_unmap (buffer, &info);
1182
1183     /* Only fail typefinding if we already a good amount of data
1184      * and we still don't know the type */
1185     if (buffer_size > (2 * 1024 * 1024) || at_eos) {
1186       GST_ELEMENT_ERROR (hlsdemux, STREAM, TYPE_NOT_FOUND,
1187           ("Could not determine type of stream"), (NULL));
1188       gst_buffer_unref (buffer);
1189       *ret = GST_FLOW_NOT_NEGOTIATED;
1190     } else {
1191       GST_LOG_OBJECT (stream, "Not enough data to typefind");
1192       hls_stream->pending_typefind_buffer = buffer;     /* Transfer the ref */
1193       *ret = GST_FLOW_OK;
1194     }
1195     *out_buffer = NULL;
1196     return FALSE;
1197   }
1198
1199   GST_DEBUG_OBJECT (stream,
1200       "Typefind result: %" GST_PTR_FORMAT " prob:%d", caps, prob);
1201
1202   if (hls_stream->parser_type == GST_HLS_PARSER_NONE) {
1203     hls_stream->parser_type = caps_to_parser_type (caps);
1204     if (hls_stream->parser_type == GST_HLS_PARSER_NONE) {
1205       GST_WARNING_OBJECT (stream,
1206           "Unsupported stream type %" GST_PTR_FORMAT, caps);
1207       GST_MEMDUMP_OBJECT (stream, "unknown data", info.data,
1208           MIN (info.size, 128));
1209       gst_buffer_unref (buffer);
1210       *ret = GST_FLOW_ERROR;
1211       return FALSE;
1212     }
1213     if (hls_stream->parser_type == GST_HLS_PARSER_ISOBMFF)
1214       hls_stream->presentation_offset = 0;
1215   }
1216
1217   gst_adaptive_demux2_stream_set_caps (stream, caps);
1218
1219   hls_stream->do_typefind = FALSE;
1220
1221   gst_buffer_unmap (buffer, &info);
1222
1223   /* We are done with typefinding. Doesn't consume the input buffer */
1224   *ret = GST_FLOW_OK;
1225   return TRUE;
1226 }
1227
1228 static GstHLSTimeMap *
1229 time_map_in_list (GList * list, gint64 dsn)
1230 {
1231   GList *iter;
1232
1233   for (iter = list; iter; iter = iter->next) {
1234     GstHLSTimeMap *map = iter->data;
1235
1236     if (map->dsn == dsn)
1237       return map;
1238   }
1239
1240   return NULL;
1241 }
1242
1243 GstHLSTimeMap *
1244 gst_hls_find_time_map (GstHLSDemux * demux, gint64 dsn)
1245 {
1246   return time_map_in_list (demux->mappings, dsn);
1247 }
1248
1249 /* Compute the stream time for the given internal time, based on the provided
1250  * time map.
1251  *
1252  * Will handle mpeg-ts wraparound. */
1253 GstClockTimeDiff
1254 gst_hls_internal_to_stream_time (GstHLSTimeMap * map,
1255     GstClockTime internal_time)
1256 {
1257   if (map->internal_time == GST_CLOCK_TIME_NONE)
1258     return GST_CLOCK_STIME_NONE;
1259
1260   /* Handle MPEG-TS Wraparound */
1261   if (internal_time < map->internal_time &&
1262       map->internal_time - internal_time > (MPEG_TS_MAX_PTS / 2))
1263     internal_time += MPEG_TS_MAX_PTS;
1264
1265   return (map->stream_time + internal_time - map->internal_time);
1266 }
1267
1268 /* Handle the internal time discovered on a segment.
1269  *
1270  * This function is called by the individual buffer parsers once they have
1271  * extracted that internal time (which is most of the time based on mpegts time,
1272  * but can also be ISOBMFF pts).
1273  *
1274  * This will update the time map when appropriate.
1275  *
1276  * If a synchronization issue is detected, the appropriate steps will be taken
1277  * and the RESYNC return value will be returned
1278  */
1279 GstHLSParserResult
1280 gst_hlsdemux_handle_internal_time (GstHLSDemux * demux,
1281     GstHLSDemuxStream * hls_stream, GstClockTime internal_time)
1282 {
1283   GstM3U8MediaSegment *current_segment = hls_stream->current_segment;
1284   GstHLSTimeMap *map;
1285   GstClockTimeDiff current_stream_time;
1286   GstClockTimeDiff real_stream_time, difference;
1287
1288   g_return_val_if_fail (current_segment != NULL, GST_HLS_PARSER_RESULT_ERROR);
1289
1290   current_stream_time = current_segment->stream_time;
1291
1292   GST_DEBUG_OBJECT (hls_stream,
1293       "Got internal time %" GST_TIME_FORMAT " for current segment stream time %"
1294       GST_STIME_FORMAT, GST_TIME_ARGS (internal_time),
1295       GST_STIME_ARGS (current_stream_time));
1296
1297   map = gst_hls_find_time_map (demux, current_segment->discont_sequence);
1298
1299   /* Time mappings will always be created upon initial parsing and when advancing */
1300   g_assert (map);
1301
1302   /* Handle the first internal time of a discont sequence. We can only store/use
1303    * those values for variant streams. */
1304   if (!GST_CLOCK_TIME_IS_VALID (map->internal_time)) {
1305     if (!hls_stream->is_variant) {
1306       GST_WARNING_OBJECT (hls_stream,
1307           "Got data from a new discont sequence on a rendition stream, can't validate stream time");
1308       return GST_HLS_PARSER_RESULT_DONE;
1309     }
1310     GST_DEBUG_OBJECT (hls_stream,
1311         "Updating time map dsn:%" G_GINT64_FORMAT " stream_time:%"
1312         GST_STIME_FORMAT " internal_time:%" GST_TIME_FORMAT, map->dsn,
1313         GST_STIME_ARGS (current_stream_time), GST_TIME_ARGS (internal_time));
1314     /* The stream time for a mapping should always be positive ! */
1315     g_assert (current_stream_time >= 0);
1316
1317     if (hls_stream->parser_type == GST_HLS_PARSER_ISOBMFF)
1318       hls_stream->presentation_offset = internal_time - current_stream_time;
1319
1320     map->stream_time = current_stream_time;
1321     map->internal_time = internal_time;
1322
1323     gst_hls_demux_start_rendition_streams (demux);
1324     return GST_HLS_PARSER_RESULT_DONE;
1325   }
1326
1327   /* The information in a discont is always valid */
1328   if (current_segment->discont) {
1329     GST_DEBUG_OBJECT (hls_stream,
1330         "DISCONT segment, Updating time map to stream_time:%" GST_STIME_FORMAT
1331         " internal_time:%" GST_TIME_FORMAT, GST_STIME_ARGS (internal_time),
1332         GST_TIME_ARGS (current_stream_time));
1333     map->stream_time = current_stream_time;
1334     map->internal_time = internal_time;
1335     return GST_HLS_PARSER_RESULT_DONE;
1336   }
1337
1338   /* Check if the segment is the expected one */
1339   real_stream_time = gst_hls_internal_to_stream_time (map, internal_time);
1340   difference = current_stream_time - real_stream_time;
1341   GST_DEBUG_OBJECT (hls_stream,
1342       "Segment contains stream time %" GST_STIME_FORMAT
1343       " difference against expected : %" GST_STIME_FORMAT,
1344       GST_STIME_ARGS (real_stream_time), GST_STIME_ARGS (difference));
1345
1346   if (ABS (difference) > 10 * GST_MSECOND) {
1347     /* Update the value */
1348     GST_DEBUG_OBJECT (hls_stream,
1349         "Updating current stream time to %" GST_STIME_FORMAT,
1350         GST_STIME_ARGS (real_stream_time));
1351     current_segment->stream_time = real_stream_time;
1352
1353     gst_hls_media_playlist_recalculate_stream_time (hls_stream->playlist,
1354         hls_stream->current_segment);
1355     gst_hls_media_playlist_dump (hls_stream->playlist);
1356
1357     if (ABS (difference) > (hls_stream->current_segment->duration / 2)) {
1358       GstAdaptiveDemux2Stream *stream = (GstAdaptiveDemux2Stream *) hls_stream;
1359       GstM3U8MediaSegment *actual_segment;
1360
1361       /* We are at the wrong segment, try to figure out the *actual* segment */
1362       GST_DEBUG_OBJECT (hls_stream,
1363           "Trying to seek to the correct segment for %" GST_STIME_FORMAT,
1364           GST_STIME_ARGS (current_stream_time));
1365       actual_segment =
1366           gst_hls_media_playlist_seek (hls_stream->playlist, TRUE,
1367           GST_SEEK_FLAG_SNAP_NEAREST, current_stream_time);
1368
1369       if (actual_segment) {
1370         GST_DEBUG_OBJECT (hls_stream, "Synced to position %" GST_STIME_FORMAT,
1371             GST_STIME_ARGS (actual_segment->stream_time));
1372         gst_m3u8_media_segment_unref (hls_stream->current_segment);
1373         hls_stream->current_segment = actual_segment;
1374         /* Ask parent class to restart this fragment */
1375         return GST_HLS_PARSER_RESULT_RESYNC;
1376       }
1377
1378       GST_WARNING_OBJECT (hls_stream,
1379           "Could not find a replacement stream, carrying on with segment");
1380       stream->discont = TRUE;
1381       stream->fragment.stream_time = real_stream_time;
1382     }
1383   }
1384
1385   return GST_HLS_PARSER_RESULT_DONE;
1386 }
1387
1388 static GstHLSParserResult
1389 gst_hls_demux_handle_buffer_content (GstHLSDemux * demux,
1390     GstHLSDemuxStream * hls_stream, gboolean draining, GstBuffer ** buffer)
1391 {
1392   GstHLSTimeMap *map;
1393   GstAdaptiveDemux2Stream *stream = (GstAdaptiveDemux2Stream *) hls_stream;
1394   GstClockTimeDiff current_stream_time =
1395       hls_stream->current_segment->stream_time;
1396   GstClockTime current_duration = hls_stream->current_segment->duration;
1397   GstHLSParserResult parser_ret;
1398
1399   GST_LOG_OBJECT (stream,
1400       "stream_time:%" GST_STIME_FORMAT " duration:%" GST_TIME_FORMAT
1401       " discont:%d draining:%d header:%d index:%d",
1402       GST_STIME_ARGS (current_stream_time), GST_TIME_ARGS (current_duration),
1403       hls_stream->current_segment->discont, draining,
1404       stream->downloading_header, stream->downloading_index);
1405
1406   /* FIXME : Replace the boolean parser return value (and this function's return
1407    *  value) by an enum which clearly specifies whether:
1408    *
1409    * * The content parsing happened succesfully and it no longer needs to be
1410    *   called for the remainder of this fragment
1411    * * More data is needed in order to parse the data
1412    * * There was a fatal error parsing the contents (ex: invalid/incompatible
1413    *   content)
1414    * * The computed fragment stream time is out of sync
1415    */
1416
1417   g_assert (demux->mappings);
1418   map =
1419       gst_hls_find_time_map (demux,
1420       hls_stream->current_segment->discont_sequence);
1421   if (!map) {
1422     /* For rendition streams, we can't do anything without time mapping */
1423     if (!hls_stream->is_variant) {
1424       GST_DEBUG_OBJECT (stream,
1425           "No available time mapping for dsn:%" G_GINT64_FORMAT
1426           " using estimated stream time",
1427           hls_stream->current_segment->discont_sequence);
1428       goto out_done;
1429     }
1430
1431     /* Variants will be able to fill in the the time mapping, so we can carry on without a time mapping */
1432   } else {
1433     GST_DEBUG_OBJECT (stream,
1434         "Using mapping dsn:%" G_GINT64_FORMAT " stream_time:%" GST_TIME_FORMAT
1435         " internal_time:%" GST_TIME_FORMAT, map->dsn,
1436         GST_TIME_ARGS (map->stream_time), GST_TIME_ARGS (map->internal_time));
1437   }
1438
1439   switch (hls_stream->parser_type) {
1440     case GST_HLS_PARSER_MPEGTS:
1441       parser_ret =
1442           gst_hlsdemux_handle_content_mpegts (demux, hls_stream, draining,
1443           buffer);
1444       break;
1445     case GST_HLS_PARSER_ID3:
1446       parser_ret =
1447           gst_hlsdemux_handle_content_id3 (demux, hls_stream, draining, buffer);
1448       break;
1449     case GST_HLS_PARSER_WEBVTT:
1450     {
1451       /* Furthermore it will handle timeshifting itself */
1452       parser_ret =
1453           gst_hlsdemux_handle_content_webvtt (demux, hls_stream, draining,
1454           buffer);
1455       break;
1456     }
1457     case GST_HLS_PARSER_ISOBMFF:
1458       parser_ret =
1459           gst_hlsdemux_handle_content_isobmff (demux, hls_stream, draining,
1460           buffer);
1461       break;
1462     case GST_HLS_PARSER_NONE:
1463     default:
1464     {
1465       GST_ERROR_OBJECT (stream, "Unknown stream type");
1466       goto out_error;
1467     }
1468   }
1469
1470   if (parser_ret == GST_HLS_PARSER_RESULT_NEED_MORE_DATA) {
1471     if (stream->downloading_index || stream->downloading_header)
1472       goto out_need_more;
1473     /* Else if we're draining, it's an error */
1474     if (draining)
1475       goto out_error;
1476     /* Else we just need more data */
1477     goto out_need_more;
1478   }
1479
1480   if (parser_ret == GST_HLS_PARSER_RESULT_ERROR)
1481     goto out_error;
1482
1483   if (parser_ret == GST_HLS_PARSER_RESULT_RESYNC)
1484     goto out_resync;
1485
1486 out_done:
1487   GST_DEBUG_OBJECT (stream, "Done. Finished parsing");
1488   return GST_HLS_PARSER_RESULT_DONE;
1489
1490 out_error:
1491   GST_DEBUG_OBJECT (stream, "Done. Error while parsing");
1492   return GST_HLS_PARSER_RESULT_ERROR;
1493
1494 out_need_more:
1495   GST_DEBUG_OBJECT (stream, "Done. Need more data");
1496   return GST_HLS_PARSER_RESULT_NEED_MORE_DATA;
1497
1498 out_resync:
1499   GST_DEBUG_OBJECT (stream, "Done. Resync required");
1500   return GST_HLS_PARSER_RESULT_RESYNC;
1501 }
1502
1503 static GstFlowReturn
1504 gst_hls_demux_stream_handle_buffer (GstAdaptiveDemux2Stream * stream,
1505     GstBuffer * buffer, gboolean at_eos)
1506 {
1507   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
1508   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
1509   GstFlowReturn ret = GST_FLOW_OK;
1510   GstBuffer *pending_header_data = NULL;
1511
1512   /* If current segment is not present, this means that a playlist update
1513    * happened between the moment ::update_fragment_info() was called and the
1514    * moment we received data. And that playlist update couldn't match the
1515    * current position. This will happen in live playback when we are downloading
1516    * too slowly, therefore we try to "catch up" back to live
1517    */
1518   if (hls_stream->current_segment == NULL) {
1519     GST_WARNING_OBJECT (stream, "Lost sync");
1520     /* Drop the buffer */
1521     gst_buffer_unref (buffer);
1522     return GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC;
1523   }
1524
1525   GST_DEBUG_OBJECT (stream,
1526       "buffer:%p at_eos:%d do_typefind:%d uri:%s", buffer, at_eos,
1527       hls_stream->do_typefind, hls_stream->current_segment->uri);
1528
1529   if (buffer == NULL)
1530     goto out;
1531
1532   /* If we need to do typefind and we're not done with it (or we errored), return */
1533   if (G_UNLIKELY (hls_stream->do_typefind) &&
1534       !gst_hls_demux_typefind_stream (hlsdemux, stream, &buffer, at_eos,
1535           &ret)) {
1536     goto out;
1537   }
1538   g_assert (hls_stream->pending_typefind_buffer == NULL);
1539
1540   if (hls_stream->process_buffer_content) {
1541     GstHLSParserResult parse_ret;
1542
1543     if (hls_stream->pending_segment_data) {
1544       if (hls_stream->pending_data_is_header) {
1545         /* Keep a copy of the header data in case we need to requeue it
1546          * due to GST_ADAPTIVE_DEMUX_FLOW_RESTART_FRAGMENT below */
1547         pending_header_data = gst_buffer_ref (hls_stream->pending_segment_data);
1548       }
1549       buffer = gst_buffer_append (hls_stream->pending_segment_data, buffer);
1550       hls_stream->pending_segment_data = NULL;
1551     }
1552
1553     /* Try to get the timing information */
1554     parse_ret =
1555         gst_hls_demux_handle_buffer_content (hlsdemux, hls_stream, at_eos,
1556         &buffer);
1557
1558     switch (parse_ret) {
1559       case GST_HLS_PARSER_RESULT_NEED_MORE_DATA:
1560         /* If we don't have enough, store and return */
1561         hls_stream->pending_segment_data = buffer;
1562         hls_stream->pending_data_is_header =
1563             (stream->downloading_header == TRUE);
1564         if (hls_stream->pending_data_is_header)
1565           stream->send_segment = TRUE;
1566         goto out;
1567       case GST_HLS_PARSER_RESULT_ERROR:
1568         /* Error, drop buffer and return */
1569         gst_buffer_unref (buffer);
1570         ret = GST_FLOW_ERROR;
1571         goto out;
1572       case GST_HLS_PARSER_RESULT_RESYNC:
1573         /* Resync, drop buffer and return */
1574         gst_buffer_unref (buffer);
1575         ret = GST_ADAPTIVE_DEMUX_FLOW_RESTART_FRAGMENT;
1576         /* If we had a pending set of header data, requeue it */
1577         if (pending_header_data != NULL) {
1578           g_assert (hls_stream->pending_segment_data == NULL);
1579
1580           GST_DEBUG_OBJECT (hls_stream,
1581               "Requeueing header data %" GST_PTR_FORMAT
1582               " before returning RESTART_FRAGMENT", pending_header_data);
1583           hls_stream->pending_segment_data = pending_header_data;
1584           pending_header_data = NULL;
1585         }
1586         goto out;
1587       case GST_HLS_PARSER_RESULT_DONE:
1588         /* Done parsing, carry on */
1589         hls_stream->process_buffer_content = FALSE;
1590         break;
1591     }
1592   }
1593
1594   if (!buffer)
1595     goto out;
1596
1597   buffer = gst_buffer_make_writable (buffer);
1598
1599   GST_BUFFER_OFFSET (buffer) = hls_stream->current_offset;
1600   hls_stream->current_offset += gst_buffer_get_size (buffer);
1601   GST_BUFFER_OFFSET_END (buffer) = hls_stream->current_offset;
1602
1603   GST_DEBUG_OBJECT (stream, "We have a buffer, pushing: %" GST_PTR_FORMAT,
1604       buffer);
1605
1606   ret = gst_adaptive_demux2_stream_push_buffer (stream, buffer);
1607
1608 out:
1609   if (pending_header_data != NULL) {
1610     /* Throw away the pending header data now. If it wasn't consumed above,
1611      * we won't need it */
1612     gst_buffer_unref (pending_header_data);
1613   }
1614
1615   GST_DEBUG_OBJECT (stream, "Returning %s", gst_flow_get_name (ret));
1616   return ret;
1617 }
1618
1619 static GstFlowReturn
1620 gst_hls_demux_stream_finish_fragment (GstAdaptiveDemux2Stream * stream)
1621 {
1622   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
1623   GstFlowReturn ret = GST_FLOW_OK;
1624
1625   GST_DEBUG_OBJECT (stream, "Finishing fragment uri:%s",
1626       hls_stream->current_segment->uri);
1627
1628   /* Drain all pending data */
1629   if (hls_stream->current_key)
1630     gst_hls_demux_stream_decrypt_end (hls_stream);
1631
1632   if (hls_stream->current_segment && stream->last_ret == GST_FLOW_OK) {
1633     if (hls_stream->pending_decrypted_buffer) {
1634       if (hls_stream->current_key) {
1635         GstMapInfo info;
1636         gssize unpadded_size;
1637
1638         /* Handle pkcs7 unpadding here */
1639         gst_buffer_map (hls_stream->pending_decrypted_buffer, &info,
1640             GST_MAP_READ);
1641         unpadded_size = info.size - info.data[info.size - 1];
1642         gst_buffer_unmap (hls_stream->pending_decrypted_buffer, &info);
1643
1644         gst_buffer_resize (hls_stream->pending_decrypted_buffer, 0,
1645             unpadded_size);
1646       }
1647
1648       ret =
1649           gst_hls_demux_stream_handle_buffer (stream,
1650           hls_stream->pending_decrypted_buffer, TRUE);
1651       hls_stream->pending_decrypted_buffer = NULL;
1652     }
1653
1654     if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED) {
1655       if (G_UNLIKELY (hls_stream->pending_typefind_buffer)) {
1656         GstBuffer *buf = hls_stream->pending_typefind_buffer;
1657         hls_stream->pending_typefind_buffer = NULL;
1658
1659         gst_hls_demux_stream_handle_buffer (stream, buf, TRUE);
1660       }
1661
1662       if (hls_stream->pending_segment_data) {
1663         GstBuffer *buf = hls_stream->pending_segment_data;
1664         hls_stream->pending_segment_data = NULL;
1665
1666         ret = gst_hls_demux_stream_handle_buffer (stream, buf, TRUE);
1667       }
1668     }
1669   }
1670
1671   gst_hls_demux_stream_clear_pending_data (hls_stream, FALSE);
1672
1673   if (G_UNLIKELY (stream->downloading_header || stream->downloading_index))
1674     return GST_FLOW_OK;
1675
1676   if (hls_stream->current_segment == NULL) {
1677     /* We can't advance, we just return OK for now and let the base class
1678      * trigger a new download (or fail and resync itself) */
1679     return GST_FLOW_OK;
1680   }
1681
1682   if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED) {
1683     /* We can update the stream current position with a more accurate value
1684      * before advancing. Note that we don't have any period so we can set the
1685      * stream_time as-is on the stream current position */
1686     stream->current_position = hls_stream->current_segment->stream_time;
1687     return gst_adaptive_demux2_stream_advance_fragment (stream,
1688         hls_stream->current_segment->duration);
1689   }
1690   return ret;
1691 }
1692
1693 static GstFlowReturn
1694 gst_hls_demux_stream_data_received (GstAdaptiveDemux2Stream * stream,
1695     GstBuffer * buffer)
1696 {
1697   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1698   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
1699   GstM3U8MediaSegment *file = hls_stream->current_segment;
1700
1701   if (file == NULL)
1702     return GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC;
1703
1704   if (hls_stream->current_offset == -1)
1705     hls_stream->current_offset = 0;
1706
1707   /* Is it encrypted? */
1708   if (hls_stream->current_key) {
1709     GError *err = NULL;
1710     gsize size;
1711     GstBuffer *decrypted_buffer;
1712     GstBuffer *tmp_buffer;
1713
1714     if (hls_stream->pending_encrypted_data == NULL)
1715       hls_stream->pending_encrypted_data = gst_adapter_new ();
1716
1717     gst_adapter_push (hls_stream->pending_encrypted_data, buffer);
1718     size = gst_adapter_available (hls_stream->pending_encrypted_data);
1719
1720     /* must be a multiple of 16 */
1721     size &= (~0xF);
1722
1723     if (size == 0) {
1724       return GST_FLOW_OK;
1725     }
1726
1727     buffer = gst_adapter_take_buffer (hls_stream->pending_encrypted_data, size);
1728     decrypted_buffer =
1729         gst_hls_demux_decrypt_fragment (hlsdemux, hls_stream, buffer, &err);
1730     if (err) {
1731       GST_ELEMENT_ERROR (hlsdemux, STREAM, DECODE, ("Failed to decrypt buffer"),
1732           ("decryption failed %s", err->message));
1733       g_error_free (err);
1734       return GST_FLOW_ERROR;
1735     }
1736
1737     tmp_buffer = hls_stream->pending_decrypted_buffer;
1738     hls_stream->pending_decrypted_buffer = decrypted_buffer;
1739     buffer = tmp_buffer;
1740     if (!buffer)
1741       return GST_FLOW_OK;
1742   }
1743
1744   if (!hls_stream->pdt_tag_sent && file != NULL && file->datetime != NULL) {
1745     gst_adaptive_demux2_stream_set_tags (stream,
1746         gst_tag_list_new (GST_TAG_DATE_TIME,
1747             gst_date_time_new_from_g_date_time (g_date_time_ref
1748                 (file->datetime)), NULL));
1749     hls_stream->pdt_tag_sent = TRUE;
1750   }
1751
1752   return gst_hls_demux_stream_handle_buffer (stream, buffer, FALSE);
1753 }
1754
1755 static void
1756 gst_hls_demux_stream_finalize (GObject * object)
1757 {
1758   GstAdaptiveDemux2Stream *stream = (GstAdaptiveDemux2Stream *) object;
1759   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (object);
1760   GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
1761
1762   if (hls_stream == hlsdemux->main_stream)
1763     hlsdemux->main_stream = NULL;
1764
1765   g_free (hls_stream->lang);
1766   g_free (hls_stream->name);
1767
1768   if (hls_stream->playlist) {
1769     gst_hls_media_playlist_unref (hls_stream->playlist);
1770     hls_stream->playlist = NULL;
1771   }
1772
1773   if (hls_stream->init_file) {
1774     gst_m3u8_init_file_unref (hls_stream->init_file);
1775     hls_stream->init_file = NULL;
1776   }
1777
1778   if (hls_stream->pending_encrypted_data)
1779     g_object_unref (hls_stream->pending_encrypted_data);
1780
1781   gst_buffer_replace (&hls_stream->pending_decrypted_buffer, NULL);
1782   gst_buffer_replace (&hls_stream->pending_typefind_buffer, NULL);
1783   gst_buffer_replace (&hls_stream->pending_segment_data, NULL);
1784
1785   if (hls_stream->moov)
1786     gst_isoff_moov_box_free (hls_stream->moov);
1787
1788   if (hls_stream->current_key) {
1789     g_free (hls_stream->current_key);
1790     hls_stream->current_key = NULL;
1791   }
1792   if (hls_stream->current_iv) {
1793     g_free (hls_stream->current_iv);
1794     hls_stream->current_iv = NULL;
1795   }
1796   if (hls_stream->current_rendition) {
1797     gst_hls_rendition_stream_unref (hls_stream->current_rendition);
1798     hls_stream->current_rendition = NULL;
1799   }
1800   if (hls_stream->pending_rendition) {
1801     gst_hls_rendition_stream_unref (hls_stream->pending_rendition);
1802     hls_stream->pending_rendition = NULL;
1803   }
1804
1805   if (hls_stream->current_segment) {
1806     gst_m3u8_media_segment_unref (hls_stream->current_segment);
1807     hls_stream->current_segment = NULL;
1808   }
1809   gst_hls_demux_stream_decrypt_end (hls_stream);
1810
1811   G_OBJECT_CLASS (stream_parent_class)->finalize (object);
1812 }
1813
1814 static gboolean
1815 gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemux2Stream * stream)
1816 {
1817   GstHLSDemuxStream *hls_stream = (GstHLSDemuxStream *) stream;
1818
1819   GST_DEBUG_OBJECT (stream, "has next ?");
1820
1821   return gst_hls_media_playlist_has_next_fragment (hls_stream->playlist,
1822       hls_stream->current_segment, stream->demux->segment.rate > 0);
1823 }
1824
1825 static GstFlowReturn
1826 gst_hls_demux_stream_advance_fragment (GstAdaptiveDemux2Stream * stream)
1827 {
1828   GstHLSDemuxStream *hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1829   GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
1830   GstM3U8MediaSegment *new_segment = NULL;
1831
1832   GST_DEBUG_OBJECT (stream,
1833       "Current segment sn:%" G_GINT64_FORMAT " stream_time:%" GST_STIME_FORMAT
1834       " uri:%s", hlsdemux_stream->current_segment->sequence,
1835       GST_STIME_ARGS (hlsdemux_stream->current_segment->stream_time),
1836       hlsdemux_stream->current_segment->uri);
1837
1838   new_segment =
1839       gst_hls_media_playlist_advance_fragment (hlsdemux_stream->playlist,
1840       hlsdemux_stream->current_segment, stream->demux->segment.rate > 0);
1841   if (new_segment) {
1842     hlsdemux_stream->reset_pts = FALSE;
1843     if (new_segment->discont_sequence !=
1844         hlsdemux_stream->current_segment->discont_sequence)
1845       gst_hls_demux_add_time_mapping (hlsdemux, new_segment->discont_sequence,
1846           new_segment->stream_time, new_segment->datetime);
1847     gst_m3u8_media_segment_unref (hlsdemux_stream->current_segment);
1848     hlsdemux_stream->current_segment = new_segment;
1849     GST_DEBUG_OBJECT (stream,
1850         "Advanced to segment sn:%" G_GINT64_FORMAT " stream_time:%"
1851         GST_STIME_FORMAT " uri:%s", hlsdemux_stream->current_segment->sequence,
1852         GST_STIME_ARGS (hlsdemux_stream->current_segment->stream_time),
1853         hlsdemux_stream->current_segment->uri);
1854     return GST_FLOW_OK;
1855   }
1856
1857   GST_LOG_OBJECT (stream, "Could not advance to next fragment");
1858   if (GST_HLS_MEDIA_PLAYLIST_IS_LIVE (hlsdemux_stream->playlist)) {
1859     gst_m3u8_media_segment_unref (hlsdemux_stream->current_segment);
1860     hlsdemux_stream->current_segment = NULL;
1861     return GST_FLOW_OK;
1862   }
1863
1864   return GST_FLOW_EOS;
1865 }
1866
1867 static GstHLSMediaPlaylist *
1868 download_media_playlist (GstHLSDemux * demux, gchar * uri, GError ** err,
1869     GstHLSMediaPlaylist * current)
1870 {
1871   GstAdaptiveDemux *adaptive_demux;
1872   const gchar *main_uri;
1873   DownloadRequest *download;
1874   GstBuffer *buf;
1875   gchar *playlist_data;
1876   GstHLSMediaPlaylist *playlist = NULL;
1877   gchar *base_uri;
1878   gboolean playlist_uri_change = FALSE;
1879
1880   adaptive_demux = GST_ADAPTIVE_DEMUX (demux);
1881   main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
1882
1883   /* If there's no previous playlist, or the URI changed this
1884    * is not a refresh/update but a switch to a new playlist */
1885   playlist_uri_change = (current == NULL || g_strcmp0 (uri, current->uri) != 0);
1886
1887   if (!playlist_uri_change) {
1888     GST_LOG_OBJECT (demux, "Updating the playlist");
1889   }
1890
1891   download =
1892       downloadhelper_fetch_uri (adaptive_demux->download_helper,
1893       uri, main_uri, DOWNLOAD_FLAG_COMPRESS | DOWNLOAD_FLAG_FORCE_REFRESH, err);
1894
1895   if (download == NULL)
1896     return NULL;
1897
1898   /* Set the base URI of the playlist to the redirect target if any */
1899   if (download->redirect_permanent && download->redirect_uri) {
1900     uri = g_strdup (download->redirect_uri);
1901     base_uri = NULL;
1902   } else {
1903     uri = g_strdup (download->uri);
1904     base_uri = g_strdup (download->redirect_uri);
1905   }
1906
1907   if (download->state == DOWNLOAD_REQUEST_STATE_ERROR) {
1908     GST_WARNING_OBJECT (demux,
1909         "Couldn't get the playlist, got HTTP status code %d",
1910         download->status_code);
1911     download_request_unref (download);
1912     if (err)
1913       g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
1914           "Couldn't download the playlist");
1915     goto out;
1916   }
1917   buf = download_request_take_buffer (download);
1918   download_request_unref (download);
1919
1920   /* there should be a buf if there wasn't an error (handled above) */
1921   g_assert (buf);
1922
1923   playlist_data = gst_hls_buf_to_utf8_text (buf);
1924   gst_buffer_unref (buf);
1925
1926   if (playlist_data == NULL) {
1927     GST_WARNING_OBJECT (demux, "Couldn't validate playlist encoding");
1928     if (err)
1929       g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
1930           "Couldn't validate playlist encoding");
1931     goto out;
1932   }
1933
1934   if (!playlist_uri_change && current
1935       && gst_hls_media_playlist_has_same_data (current, playlist_data)) {
1936     GST_DEBUG_OBJECT (demux, "Same playlist data");
1937     playlist = gst_hls_media_playlist_ref (current);
1938     playlist->reloaded = TRUE;
1939     g_free (playlist_data);
1940   } else {
1941     playlist = gst_hls_media_playlist_parse (playlist_data, uri, base_uri);
1942     if (!playlist) {
1943       GST_WARNING_OBJECT (demux, "Couldn't parse playlist");
1944       if (err)
1945         g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
1946             "Couldn't parse playlist");
1947     }
1948   }
1949
1950 out:
1951   g_free (uri);
1952   g_free (base_uri);
1953
1954   return playlist;
1955 }
1956
1957 static GstHLSTimeMap *
1958 gst_hls_time_map_new (void)
1959 {
1960   GstHLSTimeMap *map = g_new0 (GstHLSTimeMap, 1);
1961
1962   map->stream_time = GST_CLOCK_TIME_NONE;
1963   map->internal_time = GST_CLOCK_TIME_NONE;
1964
1965   return map;
1966 }
1967
1968 static void
1969 gst_hls_time_map_free (GstHLSTimeMap * map)
1970 {
1971   if (map->pdt)
1972     g_date_time_unref (map->pdt);
1973   g_free (map);
1974 }
1975
1976 static void
1977 gst_hls_demux_add_time_mapping (GstHLSDemux * demux, gint64 dsn,
1978     GstClockTimeDiff stream_time, GDateTime * pdt)
1979 {
1980 #ifndef GST_DISABLE_GST_DEBUG
1981   gchar *datestring = NULL;
1982 #endif
1983   GstHLSTimeMap *map;
1984   GList *tmp;
1985   GstClockTime offset = 0;
1986
1987   /* Check if we don't already have a mapping for the given dsn */
1988   for (tmp = demux->mappings; tmp; tmp = tmp->next) {
1989     GstHLSTimeMap *map = tmp->data;
1990
1991     if (map->dsn == dsn) {
1992 #ifndef GST_DISABLE_GST_DEBUG
1993       if (map->pdt)
1994         datestring = g_date_time_format_iso8601 (map->pdt);
1995       GST_DEBUG_OBJECT (demux,
1996           "Already have mapping, dsn:%" G_GINT64_FORMAT " stream_time:%"
1997           GST_TIME_FORMAT " internal_time:%" GST_TIME_FORMAT " pdt:%s",
1998           map->dsn, GST_TIME_ARGS (map->stream_time),
1999           GST_TIME_ARGS (map->internal_time), datestring);
2000       g_free (datestring);
2001 #endif
2002       return;
2003     }
2004   }
2005
2006 #ifndef GST_DISABLE_GST_DEBUG
2007   if (pdt)
2008     datestring = g_date_time_format_iso8601 (pdt);
2009   GST_DEBUG_OBJECT (demux,
2010       "New mapping, dsn:%" G_GINT64_FORMAT " stream_time:%" GST_TIME_FORMAT
2011       " pdt:%s", dsn, GST_TIME_ARGS (stream_time), datestring);
2012   g_free (datestring);
2013 #endif
2014
2015   if (stream_time < 0) {
2016     offset = -stream_time;
2017     stream_time = 0;
2018     /* Handle negative stream times. This can happen for example when the server
2019      * returns an older playlist.
2020      *
2021      * Shift the values accordingly to end up with non-negative reference stream
2022      * time */
2023     GST_DEBUG_OBJECT (demux,
2024         "Shifting values before storage (offset : %" GST_TIME_FORMAT ")",
2025         GST_TIME_ARGS (offset));
2026   }
2027
2028   map = gst_hls_time_map_new ();
2029   map->dsn = dsn;
2030   map->stream_time = stream_time;
2031   if (pdt) {
2032     if (offset)
2033       map->pdt = g_date_time_add (pdt, offset / GST_USECOND);
2034     else
2035       map->pdt = g_date_time_ref (pdt);
2036   }
2037
2038   demux->mappings = g_list_append (demux->mappings, map);
2039 }
2040
2041 /* Remove any time mapping which isn't currently used by any stream playlist */
2042 static void
2043 gst_hls_prune_time_mappings (GstHLSDemux * hlsdemux)
2044 {
2045   GstAdaptiveDemux *demux = (GstAdaptiveDemux *) hlsdemux;
2046   GList *active = NULL;
2047   GList *iterstream;
2048
2049   for (iterstream = demux->input_period->streams; iterstream;
2050       iterstream = iterstream->next) {
2051     GstAdaptiveDemux2Stream *stream = iterstream->data;
2052     GstHLSDemuxStream *hls_stream = (GstHLSDemuxStream *) stream;
2053     gint64 dsn = G_MAXINT64;
2054     guint idx, len;
2055
2056     if (!hls_stream->playlist)
2057       continue;
2058     len = hls_stream->playlist->segments->len;
2059     for (idx = 0; idx < len; idx++) {
2060       GstM3U8MediaSegment *segment =
2061           g_ptr_array_index (hls_stream->playlist->segments, idx);
2062
2063       if (dsn == G_MAXINT64 || segment->discont_sequence != dsn) {
2064         dsn = segment->discont_sequence;
2065         if (!time_map_in_list (active, dsn)) {
2066           GstHLSTimeMap *map = gst_hls_find_time_map (hlsdemux, dsn);
2067           if (map) {
2068             GST_DEBUG_OBJECT (demux,
2069                 "Keeping active time map dsn:%" G_GINT64_FORMAT, map->dsn);
2070             /* Move active dsn to active list */
2071             hlsdemux->mappings = g_list_remove (hlsdemux->mappings, map);
2072             active = g_list_append (active, map);
2073           }
2074         }
2075       }
2076     }
2077   }
2078
2079   g_list_free_full (hlsdemux->mappings, (GDestroyNotify) gst_hls_time_map_free);
2080   hlsdemux->mappings = active;
2081 }
2082
2083 /* Go over the DSN from the playlist and add any missing time mapping */
2084 static void
2085 gst_hls_update_time_mappings (GstHLSDemux * demux,
2086     GstHLSMediaPlaylist * playlist)
2087 {
2088   guint idx, len = playlist->segments->len;
2089   gint64 dsn = G_MAXINT64;
2090
2091   for (idx = 0; idx < len; idx++) {
2092     GstM3U8MediaSegment *segment = g_ptr_array_index (playlist->segments, idx);
2093
2094     if (dsn == G_MAXINT64 || segment->discont_sequence != dsn) {
2095       dsn = segment->discont_sequence;
2096       if (!gst_hls_find_time_map (demux, segment->discont_sequence))
2097         gst_hls_demux_add_time_mapping (demux, segment->discont_sequence,
2098             segment->stream_time, segment->datetime);
2099     }
2100   }
2101 }
2102
2103 static void
2104 setup_initial_playlist (GstHLSDemux * demux, GstHLSMediaPlaylist * playlist)
2105 {
2106   guint idx, len = playlist->segments->len;
2107   GstM3U8MediaSegment *segment;
2108   GstClockTimeDiff pos = 0;
2109
2110   GST_DEBUG_OBJECT (demux,
2111       "Setting up initial variant segment and time mapping");
2112
2113   /* This is the initial variant playlist. We will use it to base all our timing
2114    * from. */
2115
2116   for (idx = 0; idx < len; idx++) {
2117     segment = g_ptr_array_index (playlist->segments, idx);
2118
2119     segment->stream_time = pos;
2120     pos += segment->duration;
2121   }
2122 }
2123
2124 /* Reset hlsdemux in case of live synchronization loss (i.e. when a media
2125  * playlist update doesn't match at all with the previous one) */
2126 static void
2127 gst_hls_demux_reset_for_lost_sync (GstHLSDemux * hlsdemux)
2128 {
2129   GstAdaptiveDemux *demux = (GstAdaptiveDemux *) hlsdemux;
2130   GList *iter;
2131
2132   GST_DEBUG_OBJECT (hlsdemux, "Resetting for lost sync");
2133
2134   for (iter = demux->input_period->streams; iter; iter = iter->next) {
2135     GstHLSDemuxStream *hls_stream = iter->data;
2136     GstAdaptiveDemux2Stream *stream = (GstAdaptiveDemux2Stream *) hls_stream;
2137
2138     if (hls_stream->current_segment)
2139       gst_m3u8_media_segment_unref (hls_stream->current_segment);
2140     hls_stream->current_segment = NULL;
2141
2142     if (hls_stream->is_variant) {
2143       GstHLSTimeMap *map;
2144       /* Resynchronize the variant stream */
2145       g_assert (stream->current_position != GST_CLOCK_STIME_NONE);
2146       hls_stream->current_segment =
2147           gst_hls_media_playlist_get_starting_segment (hls_stream->playlist);
2148       hls_stream->current_segment->stream_time = stream->current_position;
2149       gst_hls_media_playlist_recalculate_stream_time (hls_stream->playlist,
2150           hls_stream->current_segment);
2151       GST_DEBUG_OBJECT (stream,
2152           "Resynced variant playlist to %" GST_STIME_FORMAT,
2153           GST_STIME_ARGS (stream->current_position));
2154       map =
2155           gst_hls_find_time_map (hlsdemux,
2156           hls_stream->current_segment->discont_sequence);
2157       if (map)
2158         map->internal_time = GST_CLOCK_TIME_NONE;
2159       gst_hls_update_time_mappings (hlsdemux, hls_stream->playlist);
2160       gst_hls_media_playlist_dump (hls_stream->playlist);
2161     } else {
2162       /* Force playlist update for the rendition streams, it will resync to the
2163        * variant stream on the next round */
2164       if (hls_stream->playlist)
2165         gst_hls_media_playlist_unref (hls_stream->playlist);
2166       hls_stream->playlist = NULL;
2167       hls_stream->playlist_fetched = FALSE;
2168     }
2169   }
2170 }
2171
2172 static GstFlowReturn
2173 gst_hls_demux_stream_update_media_playlist (GstHLSDemux * demux,
2174     GstHLSDemuxStream * stream, gchar ** uri, GError ** err)
2175 {
2176   GstHLSMediaPlaylist *new_playlist;
2177
2178   GST_DEBUG_OBJECT (stream, "Updating %s", *uri);
2179
2180   new_playlist = download_media_playlist (demux, *uri, err, stream->playlist);
2181   if (new_playlist == NULL) {
2182     GST_WARNING_OBJECT (stream, "Could not get playlist '%s'", *uri);
2183     return GST_FLOW_ERROR;
2184   }
2185
2186   /* Check if a redirect happened */
2187   if (g_strcmp0 (*uri, new_playlist->uri)) {
2188     GST_DEBUG_OBJECT (stream, "Playlist URI update : '%s'  =>  '%s'", *uri,
2189         new_playlist->uri);
2190     g_free (*uri);
2191     *uri = g_strdup (new_playlist->uri);
2192   }
2193
2194   /* Synchronize playlist with previous one. If we can't update the playlist
2195    * timing and inform the base class that we lost sync */
2196   if (stream->playlist
2197       && !gst_hls_media_playlist_sync_to_playlist (new_playlist,
2198           stream->playlist)) {
2199     /* Failure to synchronize with the previous media playlist is only fatal for
2200      * variant streams. */
2201     if (stream->is_variant) {
2202       GST_DEBUG_OBJECT (stream,
2203           "Could not synchronize new variant playlist with previous one !");
2204       goto lost_sync;
2205     }
2206
2207     /* For rendition streams, we can attempt synchronization against the
2208      * variant playlist which is constantly updated */
2209     if (demux->main_stream->playlist
2210         && !gst_hls_media_playlist_sync_to_playlist (new_playlist,
2211             demux->main_stream->playlist)) {
2212       GST_DEBUG_OBJECT (stream,
2213           "Could not do fallback synchronization of rendition stream to variant stream");
2214       goto lost_sync;
2215     }
2216   } else if (!stream->is_variant && demux->main_stream->playlist) {
2217     /* For initial rendition media playlist, attempt to synchronize the playlist
2218      * against the variant stream. This is non-fatal if it fails. */
2219     GST_DEBUG_OBJECT (stream,
2220         "Attempting to synchronize initial rendition stream with variant stream");
2221     gst_hls_media_playlist_sync_to_playlist (new_playlist,
2222         demux->main_stream->playlist);
2223   }
2224
2225   if (stream->current_segment) {
2226     GstM3U8MediaSegment *new_segment;
2227     GST_DEBUG_OBJECT (stream,
2228         "Current segment sn:%" G_GINT64_FORMAT " stream_time:%" GST_STIME_FORMAT
2229         " uri:%s", stream->current_segment->sequence,
2230         GST_STIME_ARGS (stream->current_segment->stream_time),
2231         stream->current_segment->uri);
2232
2233     /* Use best-effort techniques to find the correponding current media segment
2234      * in the new playlist. This might be off in some cases, but it doesn't matter
2235      * since we will be checking the embedded timestamp later */
2236     new_segment =
2237         gst_hls_media_playlist_sync_to_segment (new_playlist,
2238         stream->current_segment);
2239     if (new_segment) {
2240       if (new_segment->discont_sequence !=
2241           stream->current_segment->discont_sequence)
2242         gst_hls_demux_add_time_mapping (demux, new_segment->discont_sequence,
2243             new_segment->stream_time, new_segment->datetime);
2244       /* This can happen in case of misaligned variants/renditions. Only warn about it */
2245       if (new_segment->stream_time != stream->current_segment->stream_time)
2246         GST_WARNING_OBJECT (stream,
2247             "Returned segment stream time %" GST_STIME_FORMAT
2248             " differs from current stream time %" GST_STIME_FORMAT,
2249             GST_STIME_ARGS (new_segment->stream_time),
2250             GST_STIME_ARGS (stream->current_segment->stream_time));
2251     } else {
2252       /* Not finding a matching segment only happens in live (otherwise we would
2253        * have found a match by stream time) when we are at the live edge. This is normal*/
2254       GST_DEBUG_OBJECT (stream, "Could not find a matching segment");
2255     }
2256     gst_m3u8_media_segment_unref (stream->current_segment);
2257     stream->current_segment = new_segment;
2258   } else {
2259     GST_DEBUG_OBJECT (stream, "No current segment");
2260   }
2261
2262   if (stream->playlist) {
2263     gst_hls_media_playlist_unref (stream->playlist);
2264     stream->playlist = new_playlist;
2265   } else {
2266     if (stream->is_variant) {
2267       GST_DEBUG_OBJECT (stream, "Setting up initial playlist");
2268       setup_initial_playlist (demux, new_playlist);
2269     }
2270     stream->playlist = new_playlist;
2271   }
2272
2273   if (stream->is_variant) {
2274     /* Update time mappings. We only use the variant stream for collecting
2275      * mappings since it is the reference on which rendition stream timing will
2276      * be based. */
2277     gst_hls_update_time_mappings (demux, stream->playlist);
2278   }
2279   gst_hls_media_playlist_dump (stream->playlist);
2280
2281   if (stream->current_segment) {
2282     GST_DEBUG_OBJECT (stream,
2283         "After update, current segment now sn:%" G_GINT64_FORMAT
2284         " stream_time:%" GST_STIME_FORMAT " uri:%s",
2285         stream->current_segment->sequence,
2286         GST_STIME_ARGS (stream->current_segment->stream_time),
2287         stream->current_segment->uri);
2288   } else {
2289     GST_DEBUG_OBJECT (stream, "No current segment selected");
2290   }
2291
2292   GST_DEBUG_OBJECT (stream, "done");
2293
2294   return GST_FLOW_OK;
2295
2296   /* ERRORS */
2297 lost_sync:
2298   {
2299     /* Set new playlist, lost sync handler will know what to do with it */
2300     if (stream->playlist)
2301       gst_hls_media_playlist_unref (stream->playlist);
2302     stream->playlist = new_playlist;
2303
2304     gst_hls_demux_reset_for_lost_sync (demux);
2305
2306     return GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC;
2307   }
2308 }
2309
2310 static GstFlowReturn
2311 gst_hls_demux_stream_update_rendition_playlist (GstHLSDemux * demux,
2312     GstHLSDemuxStream * stream)
2313 {
2314   GstFlowReturn ret = GST_FLOW_OK;
2315   GstHLSRenditionStream *target_rendition =
2316       stream->pending_rendition ? stream->
2317       pending_rendition : stream->current_rendition;
2318
2319   ret = gst_hls_demux_stream_update_media_playlist (demux, stream,
2320       &target_rendition->uri, NULL);
2321   if (ret != GST_FLOW_OK)
2322     return ret;
2323
2324   if (stream->pending_rendition) {
2325     gst_hls_rendition_stream_unref (stream->current_rendition);
2326     /* Stealing ref */
2327     stream->current_rendition = stream->pending_rendition;
2328     stream->pending_rendition = NULL;
2329   }
2330
2331   stream->playlist_fetched = TRUE;
2332
2333   return ret;
2334 }
2335
2336 static GstFlowReturn
2337 gst_hls_demux_stream_update_variant_playlist (GstHLSDemux * demux,
2338     GstHLSDemuxStream * stream, GError ** err)
2339 {
2340   GstFlowReturn ret = GST_FLOW_OK;
2341   GstHLSVariantStream *target_variant =
2342       demux->pending_variant ? demux->pending_variant : demux->current_variant;
2343
2344   ret = gst_hls_demux_stream_update_media_playlist (demux, stream,
2345       &target_variant->uri, err);
2346   if (ret != GST_FLOW_OK)
2347     return ret;
2348
2349   if (demux->pending_variant) {
2350     gst_hls_variant_stream_unref (demux->current_variant);
2351     /* Stealing ref */
2352     demux->current_variant = demux->pending_variant;
2353     demux->pending_variant = NULL;
2354   }
2355
2356   stream->playlist_fetched = TRUE;
2357
2358   return ret;
2359 }
2360
2361 static GstFlowReturn
2362 gst_hls_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream)
2363 {
2364   GstFlowReturn ret = GST_FLOW_OK;
2365   GstHLSDemuxStream *hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
2366   GstAdaptiveDemux *demux = stream->demux;
2367   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
2368   GstM3U8MediaSegment *file;
2369   gboolean discont;
2370
2371   /* If the rendition playlist needs to be updated, do it now */
2372   if (!hlsdemux_stream->is_variant && !hlsdemux_stream->playlist_fetched) {
2373     ret = gst_hls_demux_stream_update_rendition_playlist (hlsdemux,
2374         hlsdemux_stream);
2375     if (ret != GST_FLOW_OK)
2376       return ret;
2377   }
2378
2379   GST_DEBUG_OBJECT (stream,
2380       "Updating fragment information, current_position:%" GST_TIME_FORMAT,
2381       GST_TIME_ARGS (stream->current_position));
2382
2383   /* Find the current segment if we don't already have it */
2384   if (hlsdemux_stream->current_segment == NULL) {
2385     GST_LOG_OBJECT (stream, "No current segment");
2386     if (stream->current_position == GST_CLOCK_TIME_NONE) {
2387       GST_DEBUG_OBJECT (stream, "Setting up initial segment");
2388       hlsdemux_stream->current_segment =
2389           gst_hls_media_playlist_get_starting_segment
2390           (hlsdemux_stream->playlist);
2391     } else {
2392       if (gst_hls_media_playlist_has_lost_sync (hlsdemux_stream->playlist,
2393               stream->current_position)) {
2394         GST_WARNING_OBJECT (stream, "Lost SYNC !");
2395         return GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC;
2396       }
2397       GST_DEBUG_OBJECT (stream,
2398           "Looking up segment for position %" GST_TIME_FORMAT,
2399           GST_TIME_ARGS (stream->current_position));
2400       hlsdemux_stream->current_segment =
2401           gst_hls_media_playlist_seek (hlsdemux_stream->playlist, TRUE,
2402           GST_SEEK_FLAG_SNAP_NEAREST, stream->current_position);
2403
2404       if (hlsdemux_stream->current_segment == NULL) {
2405         GST_INFO_OBJECT (stream, "At the end of the current media playlist");
2406         return GST_FLOW_EOS;
2407       }
2408
2409       /* Update time mapping. If it already exists it will be ignored */
2410       gst_hls_demux_add_time_mapping (hlsdemux,
2411           hlsdemux_stream->current_segment->discont_sequence,
2412           hlsdemux_stream->current_segment->stream_time,
2413           hlsdemux_stream->current_segment->datetime);
2414     }
2415   }
2416
2417   file = hlsdemux_stream->current_segment;
2418
2419   GST_DEBUG_OBJECT (stream, "Current segment stream_time %" GST_STIME_FORMAT,
2420       GST_STIME_ARGS (file->stream_time));
2421
2422   discont = file->discont || stream->discont;
2423
2424   gboolean need_header = GST_ADAPTIVE_DEMUX2_STREAM_NEED_HEADER (stream);
2425
2426   /* Check if the MAP header file changed and update it */
2427   if (file->init_file != NULL
2428       && !gst_m3u8_init_file_equal (hlsdemux_stream->init_file,
2429           file->init_file)) {
2430     GST_DEBUG_OBJECT (stream, "MAP header info changed. Updating");
2431     if (hlsdemux_stream->init_file != NULL)
2432       gst_m3u8_init_file_unref (hlsdemux_stream->init_file);
2433     hlsdemux_stream->init_file = gst_m3u8_init_file_ref (file->init_file);
2434     need_header = TRUE;
2435   }
2436
2437   if (file->init_file && need_header) {
2438     GstM3U8InitFile *header_file = file->init_file;
2439     g_free (stream->fragment.header_uri);
2440     stream->fragment.header_uri = g_strdup (header_file->uri);
2441     stream->fragment.header_range_start = header_file->offset;
2442     if (header_file->size != -1) {
2443       stream->fragment.header_range_end =
2444           header_file->offset + header_file->size - 1;
2445     } else {
2446       stream->fragment.header_range_end = -1;
2447     }
2448
2449     stream->need_header = TRUE;
2450   }
2451
2452   /* set up our source for download */
2453   if (hlsdemux_stream->reset_pts || discont || demux->segment.rate < 0.0) {
2454     stream->fragment.stream_time = file->stream_time;
2455   } else {
2456     stream->fragment.stream_time = GST_CLOCK_STIME_NONE;
2457   }
2458
2459   g_free (hlsdemux_stream->current_key);
2460   hlsdemux_stream->current_key = g_strdup (file->key);
2461   g_free (hlsdemux_stream->current_iv);
2462   hlsdemux_stream->current_iv = g_memdup2 (file->iv, sizeof (file->iv));
2463
2464   g_free (stream->fragment.uri);
2465   stream->fragment.uri = g_strdup (file->uri);
2466
2467   GST_DEBUG_OBJECT (stream, "Stream URI now %s", file->uri);
2468
2469   stream->fragment.range_start = file->offset;
2470   if (file->size != -1)
2471     stream->fragment.range_end = file->offset + file->size - 1;
2472   else
2473     stream->fragment.range_end = -1;
2474
2475   stream->fragment.duration = file->duration;
2476
2477   stream->recommended_buffering_threshold =
2478       gst_hls_media_playlist_recommended_buffering_threshold
2479       (hlsdemux_stream->playlist);
2480
2481   if (discont)
2482     stream->discont = TRUE;
2483
2484   return ret;
2485 }
2486
2487 static gboolean
2488 gst_hls_demux_stream_can_start (GstAdaptiveDemux2Stream * stream)
2489 {
2490   GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
2491   GstHLSDemuxStream *hls_stream = (GstHLSDemuxStream *) stream;
2492   GList *tmp;
2493
2494   GST_DEBUG_OBJECT (stream, "is_variant:%d mappings:%p", hls_stream->is_variant,
2495       hlsdemux->mappings);
2496
2497   /* Variant streams can always start straight away */
2498   if (hls_stream->is_variant)
2499     return TRUE;
2500
2501   /* Renditions of the exact same type as the variant are pure alternatives,
2502    * they must be started. This can happen for example with audio-only manifests
2503    * where the initial stream selected is a rendition and not a variant */
2504   if (hls_stream->rendition_type == hlsdemux->main_stream->rendition_type)
2505     return TRUE;
2506
2507   /* Rendition streams only require delaying if we don't have time mappings yet */
2508   if (!hlsdemux->mappings)
2509     return FALSE;
2510
2511   /* We can start if we have at least one internal time observation */
2512   for (tmp = hlsdemux->mappings; tmp; tmp = tmp->next) {
2513     GstHLSTimeMap *map = tmp->data;
2514     if (map->internal_time != GST_CLOCK_TIME_NONE)
2515       return TRUE;
2516   }
2517
2518   /* Otherwise we have to wait */
2519   return FALSE;
2520 }
2521
2522 /* Returns TRUE if the rendition stream switched group-id */
2523 static gboolean
2524 gst_hls_demux_update_rendition_stream (GstHLSDemux * hlsdemux,
2525     GstHLSDemuxStream * hls_stream, GError ** err)
2526 {
2527   gchar *current_group_id, *requested_group_id;
2528   GstHLSRenditionStream *replacement_media = NULL;
2529   GList *tmp;
2530
2531   /* There always should be a current variant set */
2532   g_assert (hlsdemux->current_variant);
2533   /* There always is a GstHLSRenditionStream set for rendition streams */
2534   g_assert (hls_stream->current_rendition);
2535
2536   requested_group_id =
2537       hlsdemux->current_variant->media_groups[hls_stream->
2538       current_rendition->mtype];
2539   current_group_id = hls_stream->current_rendition->group_id;
2540
2541   GST_DEBUG_OBJECT (hlsdemux,
2542       "Checking playlist change for variant stream %s lang: %s current group-id: %s / requested group-id: %s",
2543       gst_stream_type_get_name (hls_stream->rendition_type), hls_stream->lang,
2544       current_group_id, requested_group_id);
2545
2546
2547   if (!g_strcmp0 (requested_group_id, current_group_id)) {
2548     GST_DEBUG_OBJECT (hlsdemux, "No change needed");
2549     return FALSE;
2550   }
2551
2552   GST_DEBUG_OBJECT (hlsdemux,
2553       "group-id changed, looking for replacement playlist");
2554
2555   /* Need to switch/update */
2556   for (tmp = hlsdemux->master->renditions; tmp; tmp = tmp->next) {
2557     GstHLSRenditionStream *cand = tmp->data;
2558
2559     if (cand->mtype == hls_stream->current_rendition->mtype
2560         && !g_strcmp0 (cand->lang, hls_stream->lang)
2561         && !g_strcmp0 (cand->group_id, requested_group_id)) {
2562       replacement_media = cand;
2563       break;
2564     }
2565   }
2566   if (!replacement_media) {
2567     GST_ERROR_OBJECT (hlsdemux,
2568         "Could not find a replacement playlist. Staying with previous one");
2569     return FALSE;
2570   }
2571
2572   GST_DEBUG_OBJECT (hlsdemux, "Use replacement playlist %s",
2573       replacement_media->name);
2574   hls_stream->playlist_fetched = FALSE;
2575   if (hls_stream->pending_rendition) {
2576     GST_ERROR_OBJECT (hlsdemux,
2577         "Already had a pending rendition switch to '%s'",
2578         hls_stream->pending_rendition->name);
2579     gst_hls_rendition_stream_unref (hls_stream->pending_rendition);
2580   }
2581   hls_stream->pending_rendition =
2582       gst_hls_rendition_stream_ref (replacement_media);
2583   return TRUE;
2584 }
2585
2586 static gboolean
2587 gst_hls_demux_stream_select_bitrate (GstAdaptiveDemux2Stream * stream,
2588     guint64 bitrate)
2589 {
2590   GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (stream->demux);
2591   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
2592   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
2593
2594   /* Fast-Path, no changes possible */
2595   if (hlsdemux->master == NULL || hlsdemux->master->is_simple)
2596     return FALSE;
2597
2598   if (hls_stream->is_variant) {
2599     gdouble play_rate = gst_adaptive_demux_play_rate (demux);
2600     gboolean changed = FALSE;
2601
2602     /* Handle variant streams */
2603     GST_DEBUG_OBJECT (hlsdemux,
2604         "Checking playlist change for main variant stream");
2605     gst_hls_demux_change_playlist (hlsdemux, bitrate / MAX (1.0,
2606             ABS (play_rate)), &changed);
2607
2608     GST_DEBUG_OBJECT (hlsdemux, "Returning changed: %d", changed);
2609     return changed;
2610   }
2611
2612   /* Handle rendition streams */
2613   return gst_hls_demux_update_rendition_stream (hlsdemux, hls_stream, NULL);
2614 }
2615
2616 static void
2617 gst_hls_demux_reset (GstAdaptiveDemux * ademux)
2618 {
2619   GstHLSDemux *demux = GST_HLS_DEMUX_CAST (ademux);
2620
2621   GST_DEBUG_OBJECT (demux, "resetting");
2622
2623   if (ademux->input_period) {
2624     GList *walk;
2625     for (walk = ademux->input_period->streams; walk != NULL; walk = walk->next) {
2626       GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (walk->data);
2627       hls_stream->pdt_tag_sent = FALSE;
2628     }
2629   }
2630
2631   if (demux->master) {
2632     gst_hls_master_playlist_unref (demux->master);
2633     demux->master = NULL;
2634   }
2635   if (demux->current_variant != NULL) {
2636     gst_hls_variant_stream_unref (demux->current_variant);
2637     demux->current_variant = NULL;
2638   }
2639   if (demux->pending_variant != NULL) {
2640     gst_hls_variant_stream_unref (demux->pending_variant);
2641     demux->pending_variant = NULL;
2642   }
2643
2644   g_list_free_full (demux->mappings, (GDestroyNotify) gst_hls_time_map_free);
2645   demux->mappings = NULL;
2646
2647   gst_hls_demux_clear_all_pending_data (demux);
2648 }
2649
2650 /*
2651  * update: TRUE only when requested from parent class (via
2652  * ::demux_update_manifest() or ::change_playlist() ).
2653  */
2654 static GstFlowReturn
2655 gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
2656     GError ** err)
2657 {
2658   GstFlowReturn ret = GST_FLOW_OK;
2659   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX (demux);
2660
2661   GST_DEBUG_OBJECT (demux, "update:%d", update);
2662
2663   /* Download and update the appropriate variant playlist (pending if any, else
2664    * current) */
2665   ret = gst_hls_demux_stream_update_variant_playlist (demux, demux->main_stream,
2666       err);
2667   if (ret != GST_FLOW_OK)
2668     return ret;
2669
2670   if (update && gst_hls_demux_is_live (adaptive_demux)) {
2671     GList *tmp;
2672     GST_DEBUG_OBJECT (demux,
2673         "LIVE, Marking rendition streams to be updated next");
2674     /* We're live, instruct all rendition medias to be updated next */
2675     for (tmp = adaptive_demux->input_period->streams; tmp; tmp = tmp->next) {
2676       GstHLSDemuxStream *hls_stream = tmp->data;
2677       if (!hls_stream->is_variant)
2678         hls_stream->playlist_fetched = FALSE;
2679     }
2680   }
2681
2682 #ifdef TIZEN_FEATURE_POST_VARIANT_INFO
2683   GST_DEBUG_OBJECT (demux, "post variant info message");
2684   gst_element_post_message (GST_ELEMENT_CAST (demux),
2685       gst_message_new_element (GST_OBJECT_CAST (demux),
2686           gst_structure_new (GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME,
2687               "video-variant-info", G_TYPE_POINTER,
2688               demux->master->variant_info, NULL)));
2689 #endif
2690
2691   return GST_FLOW_OK;
2692 }
2693
2694 static gboolean
2695 gst_hls_demux_change_playlist (GstHLSDemux * demux, guint max_bitrate,
2696     gboolean * changed)
2697 {
2698   GstHLSVariantStream *lowest_variant, *lowest_ivariant;
2699   GstHLSVariantStream *previous_variant, *new_variant;
2700   gint old_bandwidth, new_bandwidth;
2701   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX_CAST (demux);
2702   GstAdaptiveDemux2Stream *stream;
2703
2704   g_return_val_if_fail (demux->main_stream != NULL, FALSE);
2705   stream = (GstAdaptiveDemux2Stream *) demux->main_stream;
2706
2707   /* Make sure we keep a reference in case we need to switch back */
2708   previous_variant = gst_hls_variant_stream_ref (demux->current_variant);
2709   new_variant =
2710 #ifdef TIZEN_FEATURE_ADAPTIVE_VARIANT_LIMIT
2711       gst_hls_master_playlist_get_variant_for_bitrate_and_resolution (demux->master,
2712       demux->current_variant, max_bitrate, adaptive_demux->min_bitrate,
2713       adaptive_demux->max_width, adaptive_demux->max_height);
2714 #else
2715       gst_hls_master_playlist_get_variant_for_bitrate (demux->master,
2716       demux->current_variant, max_bitrate, adaptive_demux->min_bitrate);
2717 #endif
2718
2719 retry_failover_protection:
2720   old_bandwidth = previous_variant->bandwidth;
2721   new_bandwidth = new_variant->bandwidth;
2722
2723   /* Don't do anything else if the playlist is the same */
2724   if (new_bandwidth == old_bandwidth) {
2725     gst_hls_variant_stream_unref (previous_variant);
2726     return TRUE;
2727   }
2728
2729   gst_hls_demux_set_current_variant (demux, new_variant);
2730
2731   GST_INFO_OBJECT (demux, "Client was on %dbps, max allowed is %dbps, switching"
2732       " to bitrate %dbps", old_bandwidth, max_bitrate, new_bandwidth);
2733
2734   if (gst_hls_demux_update_playlist (demux, TRUE, NULL) == GST_FLOW_OK) {
2735     const gchar *main_uri;
2736     gchar *uri = new_variant->uri;
2737
2738     main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
2739     gst_element_post_message (GST_ELEMENT_CAST (demux),
2740         gst_message_new_element (GST_OBJECT_CAST (demux),
2741             gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME,
2742                 "manifest-uri", G_TYPE_STRING,
2743                 main_uri, "uri", G_TYPE_STRING,
2744                 uri, "bitrate", G_TYPE_INT, new_bandwidth, NULL)));
2745     if (changed)
2746       *changed = TRUE;
2747     stream->discont = TRUE;
2748   } else if (gst_adaptive_demux2_is_running (GST_ADAPTIVE_DEMUX_CAST (demux))) {
2749     GstHLSVariantStream *failover_variant = NULL;
2750     GList *failover;
2751
2752     GST_INFO_OBJECT (demux, "Unable to update playlist. Switching back");
2753
2754     /* we find variants by bitrate by going from highest to lowest, so it's
2755      * possible that there's another variant with the same bitrate before the
2756      * one selected which we can use as failover */
2757     failover = g_list_find (demux->master->variants, new_variant);
2758     if (failover != NULL)
2759       failover = failover->prev;
2760     if (failover != NULL)
2761       failover_variant = failover->data;
2762     if (failover_variant && new_bandwidth == failover_variant->bandwidth) {
2763       new_variant = failover_variant;
2764       goto retry_failover_protection;
2765     }
2766
2767     gst_hls_demux_set_current_variant (demux, previous_variant);
2768
2769     /*  Try a lower bitrate (or stop if we just tried the lowest) */
2770     if (previous_variant->iframe) {
2771       lowest_ivariant = demux->master->iframe_variants->data;
2772       if (new_bandwidth == lowest_ivariant->bandwidth) {
2773         gst_hls_variant_stream_unref (previous_variant);
2774         return FALSE;
2775       }
2776     } else {
2777       lowest_variant = demux->master->variants->data;
2778       if (new_bandwidth == lowest_variant->bandwidth) {
2779         gst_hls_variant_stream_unref (previous_variant);
2780         return FALSE;
2781       }
2782     }
2783     gst_hls_variant_stream_unref (previous_variant);
2784     return gst_hls_demux_change_playlist (demux, new_bandwidth - 1, changed);
2785   }
2786
2787   gst_hls_variant_stream_unref (previous_variant);
2788   return TRUE;
2789 }
2790
2791 #if defined(HAVE_OPENSSL)
2792 static gboolean
2793 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
2794     const guint8 * key_data, const guint8 * iv_data)
2795 {
2796   EVP_CIPHER_CTX *ctx;
2797 #if OPENSSL_VERSION_NUMBER < 0x10100000L
2798   EVP_CIPHER_CTX_init (&stream->aes_ctx);
2799   ctx = &stream->aes_ctx;
2800 #else
2801   stream->aes_ctx = EVP_CIPHER_CTX_new ();
2802   ctx = stream->aes_ctx;
2803 #endif
2804   if (!EVP_DecryptInit_ex (ctx, EVP_aes_128_cbc (), NULL, key_data, iv_data))
2805     return FALSE;
2806   EVP_CIPHER_CTX_set_padding (ctx, 0);
2807   return TRUE;
2808 }
2809
2810 static gboolean
2811 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
2812     const guint8 * encrypted_data, guint8 * decrypted_data)
2813 {
2814   int len, flen = 0;
2815   EVP_CIPHER_CTX *ctx;
2816
2817 #if OPENSSL_VERSION_NUMBER < 0x10100000L
2818   ctx = &stream->aes_ctx;
2819 #else
2820   ctx = stream->aes_ctx;
2821 #endif
2822
2823   if (G_UNLIKELY (length > G_MAXINT || length % 16 != 0))
2824     return FALSE;
2825
2826   len = (int) length;
2827   if (!EVP_DecryptUpdate (ctx, decrypted_data, &len, encrypted_data, len))
2828     return FALSE;
2829   EVP_DecryptFinal_ex (ctx, decrypted_data + len, &flen);
2830   g_return_val_if_fail (len + flen == length, FALSE);
2831   return TRUE;
2832 }
2833
2834 static void
2835 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
2836 {
2837 #if OPENSSL_VERSION_NUMBER < 0x10100000L
2838   EVP_CIPHER_CTX_cleanup (&stream->aes_ctx);
2839 #else
2840   EVP_CIPHER_CTX_free (stream->aes_ctx);
2841   stream->aes_ctx = NULL;
2842 #endif
2843 }
2844
2845 #elif defined(HAVE_NETTLE)
2846 static gboolean
2847 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
2848     const guint8 * key_data, const guint8 * iv_data)
2849 {
2850   aes128_set_decrypt_key (&stream->aes_ctx.ctx, key_data);
2851   CBC_SET_IV (&stream->aes_ctx, iv_data);
2852
2853   return TRUE;
2854 }
2855
2856 static gboolean
2857 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
2858     const guint8 * encrypted_data, guint8 * decrypted_data)
2859 {
2860   if (length % 16 != 0)
2861     return FALSE;
2862
2863   CBC_DECRYPT (&stream->aes_ctx, aes128_decrypt, length, decrypted_data,
2864       encrypted_data);
2865
2866   return TRUE;
2867 }
2868
2869 static void
2870 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
2871 {
2872   /* NOP */
2873 }
2874
2875 #elif defined(HAVE_LIBGCRYPT)
2876 static gboolean
2877 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
2878     const guint8 * key_data, const guint8 * iv_data)
2879 {
2880   gcry_error_t err = 0;
2881   gboolean ret = FALSE;
2882
2883   err =
2884       gcry_cipher_open (&stream->aes_ctx, GCRY_CIPHER_AES128,
2885       GCRY_CIPHER_MODE_CBC, 0);
2886   if (err)
2887     goto out;
2888   err = gcry_cipher_setkey (stream->aes_ctx, key_data, 16);
2889   if (err)
2890     goto out;
2891   err = gcry_cipher_setiv (stream->aes_ctx, iv_data, 16);
2892   if (!err)
2893     ret = TRUE;
2894
2895 out:
2896   if (!ret)
2897     if (stream->aes_ctx)
2898       gcry_cipher_close (stream->aes_ctx);
2899
2900   return ret;
2901 }
2902
2903 static gboolean
2904 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
2905     const guint8 * encrypted_data, guint8 * decrypted_data)
2906 {
2907   gcry_error_t err = 0;
2908
2909   err = gcry_cipher_decrypt (stream->aes_ctx, decrypted_data, length,
2910       encrypted_data, length);
2911
2912   return err == 0;
2913 }
2914
2915 static void
2916 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
2917 {
2918   if (stream->aes_ctx) {
2919     gcry_cipher_close (stream->aes_ctx);
2920     stream->aes_ctx = NULL;
2921   }
2922 }
2923
2924 #else
2925 /* NO crypto available */
2926 static gboolean
2927 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
2928     const guint8 * key_data, const guint8 * iv_data)
2929 {
2930   GST_ERROR ("No crypto available");
2931   return FALSE;
2932 }
2933
2934 static gboolean
2935 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
2936     const guint8 * encrypted_data, guint8 * decrypted_data)
2937 {
2938   GST_ERROR ("Cannot decrypt fragment, no crypto available");
2939   return FALSE;
2940 }
2941
2942 static void
2943 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
2944 {
2945   return;
2946 }
2947 #endif
2948
2949 static GstBuffer *
2950 gst_hls_demux_decrypt_fragment (GstHLSDemux * demux, GstHLSDemuxStream * stream,
2951     GstBuffer * encrypted_buffer, GError ** err)
2952 {
2953   GstBuffer *decrypted_buffer = NULL;
2954   GstMapInfo encrypted_info, decrypted_info;
2955
2956   decrypted_buffer =
2957       gst_buffer_new_allocate (NULL, gst_buffer_get_size (encrypted_buffer),
2958       NULL);
2959
2960   gst_buffer_map (encrypted_buffer, &encrypted_info, GST_MAP_READ);
2961   gst_buffer_map (decrypted_buffer, &decrypted_info, GST_MAP_WRITE);
2962
2963   if (!decrypt_fragment (stream, encrypted_info.size,
2964           encrypted_info.data, decrypted_info.data))
2965     goto decrypt_error;
2966
2967
2968   gst_buffer_unmap (decrypted_buffer, &decrypted_info);
2969   gst_buffer_unmap (encrypted_buffer, &encrypted_info);
2970
2971   gst_buffer_unref (encrypted_buffer);
2972
2973   return decrypted_buffer;
2974
2975 decrypt_error:
2976   GST_ERROR_OBJECT (demux, "Failed to decrypt fragment");
2977   g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_DECRYPT,
2978       "Failed to decrypt fragment");
2979
2980   gst_buffer_unmap (decrypted_buffer, &decrypted_info);
2981   gst_buffer_unmap (encrypted_buffer, &encrypted_info);
2982
2983   gst_buffer_unref (encrypted_buffer);
2984   gst_buffer_unref (decrypted_buffer);
2985
2986   return NULL;
2987 }
2988
2989 static gint64
2990 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
2991 {
2992   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
2993   GstClockTime target_duration = 5 * GST_SECOND;
2994
2995   if (hlsdemux->main_stream && hlsdemux->main_stream->playlist) {
2996     GstHLSMediaPlaylist *playlist = hlsdemux->main_stream->playlist;
2997
2998     if (playlist->version > 5) {
2999       target_duration = hlsdemux->main_stream->playlist->targetduration;
3000     } else if (playlist->segments->len) {
3001       GstM3U8MediaSegment *last_seg =
3002           g_ptr_array_index (playlist->segments, playlist->segments->len - 1);
3003       target_duration = last_seg->duration;
3004     }
3005     if (playlist->reloaded && target_duration > (playlist->targetduration / 2)) {
3006       GST_DEBUG_OBJECT (demux,
3007           "Playlist didn't change previously, returning lower update interval");
3008       target_duration /= 2;
3009     }
3010   }
3011
3012   GST_DEBUG_OBJECT (demux, "Returning update interval of %" GST_TIME_FORMAT,
3013       GST_TIME_ARGS (target_duration));
3014
3015   return gst_util_uint64_scale (target_duration, G_USEC_PER_SEC, GST_SECOND);
3016 }
3017
3018 static GstClockTime
3019 gst_hls_demux_stream_get_presentation_offset (GstAdaptiveDemux2Stream * stream)
3020 {
3021   GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
3022   GstHLSDemuxStream *hls_stream = (GstHLSDemuxStream *) stream;
3023
3024   GST_DEBUG_OBJECT (stream, "presentation_offset %" GST_TIME_FORMAT,
3025       GST_TIME_ARGS (hls_stream->presentation_offset));
3026
3027   /* If this stream and the variant stream are ISOBMFF, returns the presentation
3028    * offset of the variant stream */
3029   if (hls_stream->parser_type == GST_HLS_PARSER_ISOBMFF
3030       && hlsdemux->main_stream->parser_type == GST_HLS_PARSER_ISOBMFF)
3031     return hlsdemux->main_stream->presentation_offset;
3032   return hls_stream->presentation_offset;
3033 }
3034
3035 static gboolean
3036 gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * start,
3037     gint64 * stop)
3038 {
3039   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
3040   gboolean ret = FALSE;
3041
3042   if (hlsdemux->main_stream && hlsdemux->main_stream->playlist)
3043     ret =
3044         gst_hls_media_playlist_get_seek_range (hlsdemux->main_stream->playlist,
3045         start, stop);
3046
3047   return ret;
3048 }
3049
3050 static gboolean
3051 hlsdemux2_element_init (GstPlugin * plugin)
3052 {
3053   gboolean ret = TRUE;
3054
3055   GST_DEBUG_CATEGORY_INIT (gst_hls_demux2_debug, "hlsdemux2", 0,
3056       "hlsdemux2 element");
3057
3058   if (!adaptivedemux2_base_element_init (plugin))
3059     return TRUE;
3060
3061   ret = gst_element_register (plugin, "hlsdemux2",
3062       GST_RANK_PRIMARY + 1, GST_TYPE_HLS_DEMUX2);
3063
3064   return ret;
3065 }