adaptive: extract variant info
[platform/upstream/gstreamer.git] / ext / 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  * Gsthlsdemux.c:
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with this library; if not, write to the
24  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27 /**
28  * SECTION:element-hlsdemux
29  * @title: hlsdemux
30  *
31  * HTTP Live Streaming demuxer element.
32  *
33  * ## Example launch line
34  * |[
35  * gst-launch-1.0 souphttpsrc location=http://devimages.apple.com/iphone/samples/bipbop/gear4/prog_index.m3u8 ! hlsdemux ! decodebin ! videoconvert ! videoscale ! autovideosink
36  * ]|
37  *
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #  include "config.h"
42 #endif
43
44 #include <string.h>
45 #include <gst/base/gsttypefindhelper.h>
46 #include "gsthlsdemux.h"
47
48 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src_%u",
49     GST_PAD_SRC,
50     GST_PAD_SOMETIMES,
51     GST_STATIC_CAPS_ANY);
52
53 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
54     GST_PAD_SINK,
55     GST_PAD_ALWAYS,
56     GST_STATIC_CAPS ("application/x-hls"));
57
58 GST_DEBUG_CATEGORY (gst_hls_demux_debug);
59 #define GST_CAT_DEFAULT gst_hls_demux_debug
60
61 #define GST_M3U8_CLIENT_LOCK(l) /* FIXME */
62 #define GST_M3U8_CLIENT_UNLOCK(l)       /* FIXME */
63
64 /* GObject */
65 static void gst_hls_demux_finalize (GObject * obj);
66
67 /* GstElement */
68 static GstStateChangeReturn
69 gst_hls_demux_change_state (GstElement * element, GstStateChange transition);
70
71 /* GstHLSDemux */
72 static gboolean gst_hls_demux_update_playlist (GstHLSDemux * demux,
73     gboolean update, GError ** err);
74 static gchar *gst_hls_src_buf_to_utf8_playlist (GstBuffer * buf);
75
76 static gboolean gst_hls_demux_change_playlist (GstHLSDemux * demux,
77     guint max_bitrate, gboolean * changed);
78 static GstBuffer *gst_hls_demux_decrypt_fragment (GstHLSDemux * demux,
79     GstHLSDemuxStream * stream, GstBuffer * encrypted_buffer, GError ** err);
80 static gboolean
81 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
82     const guint8 * key_data, const guint8 * iv_data);
83 static void gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream);
84
85 static gboolean gst_hls_demux_is_live (GstAdaptiveDemux * demux);
86 static GstClockTime gst_hls_demux_get_duration (GstAdaptiveDemux * demux);
87 static gint64 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux *
88     demux);
89 static gboolean gst_hls_demux_process_manifest (GstAdaptiveDemux * demux,
90     GstBuffer * buf);
91 static GstFlowReturn gst_hls_demux_update_manifest (GstAdaptiveDemux * demux);
92 static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
93 static GstFlowReturn gst_hls_demux_stream_seek (GstAdaptiveDemuxStream *
94     stream, gboolean forward, GstSeekFlags flags, GstClockTime ts,
95     GstClockTime * final_ts);
96 static gboolean
97 gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
98     GstAdaptiveDemuxStream * stream);
99 static GstFlowReturn gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
100     GstAdaptiveDemuxStream * stream);
101 static GstFlowReturn gst_hls_demux_data_received (GstAdaptiveDemux * demux,
102     GstAdaptiveDemuxStream * stream, GstBuffer * buffer);
103 static void gst_hls_demux_stream_free (GstAdaptiveDemuxStream * stream);
104 static gboolean gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemuxStream *
105     stream);
106 static GstFlowReturn gst_hls_demux_advance_fragment (GstAdaptiveDemuxStream *
107     stream);
108 static GstFlowReturn gst_hls_demux_update_fragment_info (GstAdaptiveDemuxStream
109     * stream);
110 static gboolean gst_hls_demux_select_bitrate (GstAdaptiveDemuxStream * stream,
111     guint64 bitrate);
112 static void gst_hls_demux_reset (GstAdaptiveDemux * demux);
113 static gboolean gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux,
114     gint64 * start, gint64 * stop);
115 static GstM3U8 *gst_hls_demux_stream_get_m3u8 (GstHLSDemuxStream * hls_stream);
116 static void gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
117     GstHLSVariantStream * variant);
118
119 #define gst_hls_demux_parent_class parent_class
120 G_DEFINE_TYPE (GstHLSDemux, gst_hls_demux, GST_TYPE_ADAPTIVE_DEMUX);
121
122 static void
123 gst_hls_demux_finalize (GObject * obj)
124 {
125   GstHLSDemux *demux = GST_HLS_DEMUX (obj);
126
127   gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
128   g_mutex_clear (&demux->keys_lock);
129   if (demux->keys) {
130     g_hash_table_unref (demux->keys);
131     demux->keys = NULL;
132   }
133
134   G_OBJECT_CLASS (parent_class)->finalize (obj);
135 }
136
137 static void
138 gst_hls_demux_class_init (GstHLSDemuxClass * klass)
139 {
140   GObjectClass *gobject_class;
141   GstElementClass *element_class;
142   GstAdaptiveDemuxClass *adaptivedemux_class;
143
144   gobject_class = (GObjectClass *) klass;
145   element_class = (GstElementClass *) klass;
146   adaptivedemux_class = (GstAdaptiveDemuxClass *) klass;
147
148   gobject_class->finalize = gst_hls_demux_finalize;
149
150   element_class->change_state = GST_DEBUG_FUNCPTR (gst_hls_demux_change_state);
151
152   gst_element_class_add_static_pad_template (element_class, &srctemplate);
153   gst_element_class_add_static_pad_template (element_class, &sinktemplate);
154
155   gst_element_class_set_static_metadata (element_class,
156       "HLS Demuxer",
157       "Codec/Demuxer/Adaptive",
158       "HTTP Live Streaming demuxer",
159       "Marc-Andre Lureau <marcandre.lureau@gmail.com>\n"
160       "Andoni Morales Alastruey <ylatuya@gmail.com>");
161
162   adaptivedemux_class->is_live = gst_hls_demux_is_live;
163   adaptivedemux_class->get_live_seek_range = gst_hls_demux_get_live_seek_range;
164   adaptivedemux_class->get_duration = gst_hls_demux_get_duration;
165   adaptivedemux_class->get_manifest_update_interval =
166       gst_hls_demux_get_manifest_update_interval;
167   adaptivedemux_class->process_manifest = gst_hls_demux_process_manifest;
168   adaptivedemux_class->update_manifest = gst_hls_demux_update_manifest;
169   adaptivedemux_class->reset = gst_hls_demux_reset;
170   adaptivedemux_class->seek = gst_hls_demux_seek;
171   adaptivedemux_class->stream_seek = gst_hls_demux_stream_seek;
172   adaptivedemux_class->stream_has_next_fragment =
173       gst_hls_demux_stream_has_next_fragment;
174   adaptivedemux_class->stream_advance_fragment = gst_hls_demux_advance_fragment;
175   adaptivedemux_class->stream_update_fragment_info =
176       gst_hls_demux_update_fragment_info;
177   adaptivedemux_class->stream_select_bitrate = gst_hls_demux_select_bitrate;
178   adaptivedemux_class->stream_free = gst_hls_demux_stream_free;
179
180   adaptivedemux_class->start_fragment = gst_hls_demux_start_fragment;
181   adaptivedemux_class->finish_fragment = gst_hls_demux_finish_fragment;
182   adaptivedemux_class->data_received = gst_hls_demux_data_received;
183
184   GST_DEBUG_CATEGORY_INIT (gst_hls_demux_debug, "hlsdemux", 0,
185       "hlsdemux element");
186 }
187
188 static void
189 gst_hls_demux_init (GstHLSDemux * demux)
190 {
191   gst_adaptive_demux_set_stream_struct_size (GST_ADAPTIVE_DEMUX_CAST (demux),
192       sizeof (GstHLSDemuxStream));
193
194   demux->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
195   g_mutex_init (&demux->keys_lock);
196 }
197
198 static GstStateChangeReturn
199 gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
200 {
201   GstStateChangeReturn ret;
202   GstHLSDemux *demux = GST_HLS_DEMUX (element);
203
204   switch (transition) {
205     case GST_STATE_CHANGE_READY_TO_PAUSED:
206       gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
207       break;
208     default:
209       break;
210   }
211
212   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
213
214   switch (transition) {
215     case GST_STATE_CHANGE_PAUSED_TO_READY:
216       gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
217       g_hash_table_remove_all (demux->keys);
218       break;
219     default:
220       break;
221   }
222   return ret;
223 }
224
225 static GstPad *
226 gst_hls_demux_create_pad (GstHLSDemux * hlsdemux)
227 {
228   gchar *name;
229   GstPad *pad;
230
231   name = g_strdup_printf ("src_%u", hlsdemux->srcpad_counter++);
232   pad = gst_pad_new_from_static_template (&srctemplate, name);
233   g_free (name);
234
235   return pad;
236 }
237
238 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
239 static GstPad *
240 gst_hls_demux_stream_create_pad (GstAdaptiveDemuxStream * stream)
241 {
242   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
243   return gst_hls_demux_create_pad (hlsdemux);
244 }
245 #endif
246
247 static guint64
248 gst_hls_demux_get_bitrate (GstHLSDemux * hlsdemux)
249 {
250   GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (hlsdemux);
251
252   /* Valid because hlsdemux only has a single output */
253   if (demux->streams) {
254     GstAdaptiveDemuxStream *stream = demux->streams->data;
255     return stream->current_download_rate;
256   }
257
258   return 0;
259 }
260
261 static void
262 gst_hls_demux_stream_clear_pending_data (GstHLSDemuxStream * hls_stream)
263 {
264   if (hls_stream->pending_encrypted_data)
265     gst_adapter_clear (hls_stream->pending_encrypted_data);
266   gst_buffer_replace (&hls_stream->pending_decrypted_buffer, NULL);
267   gst_buffer_replace (&hls_stream->pending_typefind_buffer, NULL);
268   gst_buffer_replace (&hls_stream->pending_pcr_buffer, NULL);
269   hls_stream->current_offset = -1;
270   gst_hls_demux_stream_decrypt_end (hls_stream);
271 }
272
273 static void
274 gst_hls_demux_clear_all_pending_data (GstHLSDemux * hlsdemux)
275 {
276   GstAdaptiveDemux *demux = (GstAdaptiveDemux *) hlsdemux;
277   GList *walk;
278
279   for (walk = demux->streams; walk != NULL; walk = walk->next) {
280     GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (walk->data);
281     gst_hls_demux_stream_clear_pending_data (hls_stream);
282   }
283 }
284
285 #if 0
286 static void
287 gst_hls_demux_set_current (GstHLSDemux * self, GstM3U8 * m3u8)
288 {
289   GST_M3U8_CLIENT_LOCK (self);
290   if (m3u8 != self->current) {
291     self->current = m3u8;
292     self->current->duration = GST_CLOCK_TIME_NONE;
293     self->current->current_file = NULL;
294
295 #if 0
296     // FIXME: this makes no sense after we just set self->current=m3u8 above (tpm)
297     // also, these values don't necessarily align between different lists
298     m3u8->current_file_duration = self->current->current_file_duration;
299     m3u8->sequence = self->current->sequence;
300     m3u8->sequence_position = self->current->sequence_position;
301     m3u8->highest_sequence_number = self->current->highest_sequence_number;
302     m3u8->first_file_start = self->current->first_file_start;
303     m3u8->last_file_end = self->current->last_file_end;
304 #endif
305   }
306   GST_M3U8_CLIENT_UNLOCK (self);
307 }
308 #endif
309
310 #define SEEK_UPDATES_PLAY_POSITION(r, start_type, stop_type) \
311   ((r >= 0 && start_type != GST_SEEK_TYPE_NONE) || \
312    (r < 0 && stop_type != GST_SEEK_TYPE_NONE))
313
314 #define IS_SNAP_SEEK(f) (f & (GST_SEEK_FLAG_SNAP_BEFORE |         \
315                               GST_SEEK_FLAG_SNAP_AFTER |          \
316                               GST_SEEK_FLAG_SNAP_NEAREST |        \
317                               GST_SEEK_FLAG_TRICKMODE_KEY_UNITS | \
318                               GST_SEEK_FLAG_KEY_UNIT))
319
320 static gboolean
321 gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
322 {
323   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
324   GstFormat format;
325   GstSeekFlags flags;
326   GstSeekType start_type, stop_type;
327   gint64 start, stop;
328   gdouble rate, old_rate;
329   GList *walk;
330   GstClockTime current_pos, target_pos, final_pos;
331   guint64 bitrate;
332
333   gst_event_parse_seek (seek, &rate, &format, &flags, &start_type, &start,
334       &stop_type, &stop);
335
336   if (!SEEK_UPDATES_PLAY_POSITION (rate, start_type, stop_type)) {
337     /* nothing to do if we don't have to update the current position */
338     return TRUE;
339   }
340
341   old_rate = demux->segment.rate;
342
343   bitrate = gst_hls_demux_get_bitrate (hlsdemux);
344
345   /* Use I-frame variants for trick modes */
346   if (hlsdemux->master->iframe_variants != NULL
347       && rate < -1.0 && old_rate >= -1.0 && old_rate <= 1.0) {
348     GError *err = NULL;
349
350     /* Switch to I-frame variant */
351     gst_hls_demux_set_current_variant (hlsdemux,
352         hlsdemux->master->iframe_variants->data);
353     gst_uri_downloader_reset (demux->downloader);
354     if (!gst_hls_demux_update_playlist (hlsdemux, FALSE, &err)) {
355       GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err);
356       return FALSE;
357     }
358     //hlsdemux->discont = TRUE;
359
360     gst_hls_demux_change_playlist (hlsdemux, bitrate / ABS (rate), NULL);
361   } else if (rate > -1.0 && rate <= 1.0 && (old_rate < -1.0 || old_rate > 1.0)) {
362     GError *err = NULL;
363     /* Switch to normal variant */
364     gst_hls_demux_set_current_variant (hlsdemux,
365         hlsdemux->master->variants->data);
366     gst_uri_downloader_reset (demux->downloader);
367     if (!gst_hls_demux_update_playlist (hlsdemux, FALSE, &err)) {
368       GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err);
369       return FALSE;
370     }
371     //hlsdemux->discont = TRUE;
372     /* TODO why not continue using the same? that was being used up to now? */
373     gst_hls_demux_change_playlist (hlsdemux, bitrate, NULL);
374   }
375
376   target_pos = rate < 0 ? stop : start;
377   final_pos = target_pos;
378
379   /* properly cleanup pending decryption status */
380   if (flags & GST_SEEK_FLAG_FLUSH) {
381     gst_hls_demux_clear_all_pending_data (hlsdemux);
382   }
383
384   for (walk = demux->streams; walk; walk = g_list_next (walk)) {
385     GstAdaptiveDemuxStream *stream =
386         GST_ADAPTIVE_DEMUX_STREAM_CAST (walk->data);
387
388     gst_hls_demux_stream_seek (stream, rate >= 0, flags, target_pos,
389         &current_pos);
390
391     /* FIXME: use minimum position always ? */
392     if (final_pos > current_pos)
393       final_pos = current_pos;
394   }
395
396   if (IS_SNAP_SEEK (flags)) {
397     if (rate >= 0)
398       gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
399           final_pos, stop_type, stop, NULL);
400     else
401       gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
402           start, stop_type, final_pos, NULL);
403   }
404
405   return TRUE;
406 }
407
408 static GstFlowReturn
409 gst_hls_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward,
410     GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts)
411 {
412   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
413   GList *walk;
414   GstClockTime current_pos;
415   gint64 current_sequence;
416   gboolean snap_after, snap_nearest;
417   GstM3U8MediaFile *file = NULL;
418
419   current_sequence = 0;
420   current_pos = gst_m3u8_is_live (hls_stream->playlist) ?
421       hls_stream->playlist->first_file_start : 0;
422
423   /* Snap to segment boundary. Improves seek performance on slow machines. */
424   snap_nearest =
425       (flags & GST_SEEK_FLAG_SNAP_NEAREST) == GST_SEEK_FLAG_SNAP_NEAREST;
426   snap_after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
427
428   GST_M3U8_CLIENT_LOCK (hlsdemux->client);
429   /* FIXME: Here we need proper discont handling */
430   for (walk = hls_stream->playlist->files; walk; walk = walk->next) {
431     file = walk->data;
432
433     current_sequence = file->sequence;
434     if ((forward && snap_after) || snap_nearest) {
435       if (current_pos >= ts)
436         break;
437       if (snap_nearest && ts - current_pos < file->duration / 2)
438         break;
439     } else if (!forward && snap_after) {
440       /* check if the next fragment is our target, in this case we want to
441        * start from the previous fragment */
442       GstClockTime next_pos = current_pos + file->duration;
443
444       if (next_pos <= ts && ts < next_pos + file->duration) {
445         break;
446       }
447     } else if (current_pos <= ts && ts < current_pos + file->duration) {
448       break;
449     }
450     current_pos += file->duration;
451   }
452
453   if (walk == NULL) {
454     GST_DEBUG_OBJECT (stream->pad, "seeking further than track duration");
455     current_sequence++;
456   }
457
458   GST_DEBUG_OBJECT (stream->pad, "seeking to sequence %u",
459       (guint) current_sequence);
460   hls_stream->reset_pts = TRUE;
461   hls_stream->playlist->sequence = current_sequence;
462   hls_stream->playlist->current_file = walk;
463   hls_stream->playlist->sequence_position = current_pos;
464   GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
465
466   /* Play from the end of the current selected segment */
467   if (file) {
468     if (!forward && IS_SNAP_SEEK (flags))
469       current_pos += file->duration;
470   }
471
472   /* update stream's segment position */
473   stream->segment.position = current_pos;
474
475   if (final_ts)
476     *final_ts = current_pos;
477
478   return GST_FLOW_OK;
479 }
480
481 static GstFlowReturn
482 gst_hls_demux_update_manifest (GstAdaptiveDemux * demux)
483 {
484   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
485   if (!gst_hls_demux_update_playlist (hlsdemux, TRUE, NULL))
486     return GST_FLOW_ERROR;
487
488   return GST_FLOW_OK;
489 }
490
491 static void
492 create_stream_for_playlist (GstAdaptiveDemux * demux, GstM3U8 * playlist,
493     gboolean is_primary_playlist, gboolean selected)
494 {
495   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
496   GstHLSDemuxStream *hlsdemux_stream;
497   GstAdaptiveDemuxStream *stream;
498
499   if (!selected) {
500     /* FIXME: Later, create the stream but mark not-selected */
501     GST_LOG_OBJECT (demux, "Ignoring not-selected stream");
502     return;
503   }
504
505   stream = gst_adaptive_demux_stream_new (demux,
506       gst_hls_demux_create_pad (hlsdemux));
507
508   hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
509
510   hlsdemux_stream->stream_type = GST_HLS_TSREADER_NONE;
511
512   hlsdemux_stream->playlist = gst_m3u8_ref (playlist);
513   hlsdemux_stream->is_primary_playlist = is_primary_playlist;
514
515   hlsdemux_stream->do_typefind = TRUE;
516   hlsdemux_stream->reset_pts = TRUE;
517 }
518
519 static gboolean
520 gst_hls_demux_setup_streams (GstAdaptiveDemux * demux)
521 {
522   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
523   GstHLSVariantStream *playlist = hlsdemux->current_variant;
524   gint i;
525
526   if (playlist == NULL) {
527     GST_WARNING_OBJECT (demux, "Can't configure streams - no variant selected");
528     return FALSE;
529   }
530
531   gst_hls_demux_clear_all_pending_data (hlsdemux);
532
533   /* 1 output for the main playlist */
534   create_stream_for_playlist (demux, playlist->m3u8, TRUE, TRUE);
535
536   for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
537     GList *mlist = playlist->media[i];
538     while (mlist != NULL) {
539       GstHLSMedia *media = mlist->data;
540
541       if (media->uri == NULL /* || media->mtype != GST_HLS_MEDIA_TYPE_AUDIO */ ) {
542         /* No uri means this is a placeholder for a stream
543          * contained in another mux */
544         GST_LOG_OBJECT (demux, "Skipping stream %s type %d with no URI",
545             media->name, media->mtype);
546         mlist = mlist->next;
547         continue;
548       }
549       GST_LOG_OBJECT (demux, "media of type %d - %s, uri: %s", i,
550           media->name, media->uri);
551       create_stream_for_playlist (demux, media->playlist, FALSE,
552           (media->mtype == GST_HLS_MEDIA_TYPE_VIDEO ||
553               media->mtype == GST_HLS_MEDIA_TYPE_AUDIO));
554
555       mlist = mlist->next;
556     }
557   }
558
559   return TRUE;
560 }
561
562 static const gchar *
563 gst_adaptive_demux_get_manifest_ref_uri (GstAdaptiveDemux * d)
564 {
565   return d->manifest_base_uri ? d->manifest_base_uri : d->manifest_uri;
566 }
567
568 static void
569 gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
570     GstHLSVariantStream * variant)
571 {
572   if (hlsdemux->current_variant == variant || variant == NULL)
573     return;
574
575   GST_INFO_OBJECT (hlsdemux, "%s variant %d, %d x %d", variant->name,
576                   variant->bandwidth, variant->width, variant->height);
577   if (hlsdemux->current_variant != NULL) {
578     gint i;
579
580     //#warning FIXME: Synching fragments across variants
581     //  should be done based on media timestamps, and
582     //  discont-sequence-numbers not sequence numbers.
583     variant->m3u8->sequence_position =
584         hlsdemux->current_variant->m3u8->sequence_position;
585     variant->m3u8->sequence = hlsdemux->current_variant->m3u8->sequence;
586
587     GST_DEBUG_OBJECT (hlsdemux,
588         "Switching Variant. Copying over sequence %" G_GINT64_FORMAT
589         " and sequence_pos %" GST_TIME_FORMAT, variant->m3u8->sequence,
590         GST_TIME_ARGS (variant->m3u8->sequence_position));
591
592     for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
593       GList *mlist = hlsdemux->current_variant->media[i];
594
595       while (mlist != NULL) {
596         GstHLSMedia *old_media = mlist->data;
597         GstHLSMedia *new_media =
598             gst_hls_variant_find_matching_media (variant, old_media);
599
600         if (new_media) {
601           new_media->playlist->sequence = old_media->playlist->sequence;
602           new_media->playlist->sequence_position =
603               old_media->playlist->sequence_position;
604         }
605         mlist = mlist->next;
606       }
607     }
608
609     gst_hls_variant_stream_unref (hlsdemux->current_variant);
610   }
611
612   hlsdemux->current_variant = gst_hls_variant_stream_ref (variant);
613
614 }
615
616 static gboolean
617 gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
618 {
619   GstHLSVariantStream *variant;
620   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
621   gchar *playlist = NULL;
622
623   GST_INFO_OBJECT (demux, "Initial playlist location: %s (base uri: %s)",
624       demux->manifest_uri, demux->manifest_base_uri);
625
626   playlist = gst_hls_src_buf_to_utf8_playlist (buf);
627   if (playlist == NULL) {
628     GST_WARNING_OBJECT (demux, "Error validating initial playlist");
629     return FALSE;
630   }
631
632   GST_M3U8_CLIENT_LOCK (self);
633   hlsdemux->master = gst_hls_master_playlist_new_from_data (playlist,
634       gst_adaptive_demux_get_manifest_ref_uri (demux));
635
636   if (hlsdemux->master == NULL || hlsdemux->master->variants == NULL) {
637     /* In most cases, this will happen if we set a wrong url in the
638      * source element and we have received the 404 HTML response instead of
639      * the playlist */
640     GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid playlist."),
641         ("Could not parse playlist. Check if the URL is correct."));
642     GST_M3U8_CLIENT_UNLOCK (self);
643     return FALSE;
644   }
645
646   /* select the initial variant stream */
647 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
648   if ((demux->connection_speed > 0) ||
649       (demux->max_bandwidth > DEFAULT_ADAPTIVE_VARIANT) ||
650       (demux->max_width > DEFAULT_ADAPTIVE_VARIANT) ||
651       (demux->max_height > DEFAULT_ADAPTIVE_VARIANT)) {
652     variant =
653         gst_hls_master_playlist_get_variant_for_max_limit (hlsdemux->master,
654         NULL, demux->connection_speed,
655         demux->max_bandwidth, demux->max_width, demux->max_height);
656   } else {
657     variant = hlsdemux->master->default_variant;
658   }
659 #else
660   if (demux->connection_speed == 0) {
661     variant = hlsdemux->master->default_variant;
662   } else {
663     variant =
664         gst_hls_master_playlist_get_variant_for_bitrate (hlsdemux->master,
665         NULL, demux->connection_speed);
666   }
667 #endif
668   if (variant)
669     gst_hls_demux_set_current_variant (hlsdemux, variant);
670
671   /* get the selected media playlist (unless the inital list was one already) */
672   if (!hlsdemux->master->is_simple) {
673     GError *err = NULL;
674
675     if (!gst_hls_demux_update_playlist (hlsdemux, FALSE, &err)) {
676       GST_ELEMENT_ERROR_FROM_ERROR (demux, "Could not fetch media playlist",
677           err);
678       GST_M3U8_CLIENT_UNLOCK (self);
679       return FALSE;
680     }
681   }
682   GST_M3U8_CLIENT_UNLOCK (self);
683
684   return gst_hls_demux_setup_streams (demux);
685 }
686
687 static GstClockTime
688 gst_hls_demux_get_duration (GstAdaptiveDemux * demux)
689 {
690   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
691   GstClockTime duration = GST_CLOCK_TIME_NONE;
692
693   if (hlsdemux->current_variant != NULL)
694     duration = gst_m3u8_get_duration (hlsdemux->current_variant->m3u8);
695
696   return duration;
697 }
698
699 static gboolean
700 gst_hls_demux_is_live (GstAdaptiveDemux * demux)
701 {
702   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
703   gboolean is_live = FALSE;
704
705   if (hlsdemux->current_variant)
706     is_live = gst_hls_variant_stream_is_live (hlsdemux->current_variant);
707
708   return is_live;
709 }
710
711 static const GstHLSKey *
712 gst_hls_demux_get_key (GstHLSDemux * demux, const gchar * key_url,
713     const gchar * referer, gboolean allow_cache)
714 {
715   GstFragment *key_fragment;
716   GstBuffer *key_buffer;
717   GstHLSKey *key;
718   GError *err = NULL;
719
720   GST_LOG_OBJECT (demux, "Looking up key for key url %s", key_url);
721
722   g_mutex_lock (&demux->keys_lock);
723
724   key = g_hash_table_lookup (demux->keys, key_url);
725
726   if (key != NULL) {
727     GST_LOG_OBJECT (demux, "Found key for key url %s in key cache", key_url);
728     goto out;
729   }
730
731   GST_INFO_OBJECT (demux, "Fetching key %s", key_url);
732 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
733   key_fragment =
734       gst_uri_downloader_fetch_uri (GST_ADAPTIVE_DEMUX (demux)->downloader,
735       key_url, referer, GST_ADAPTIVE_DEMUX (demux)->user_agent,
736       GST_ADAPTIVE_DEMUX (demux)->cookies, DEFAULT_ADAPTIVE_RETRY,
737       DEFAULT_ADAPTIVE_TIMEOUT, FALSE, FALSE, allow_cache, &err);
738 #else
739   key_fragment =
740       gst_uri_downloader_fetch_uri (GST_ADAPTIVE_DEMUX (demux)->downloader,
741       key_url, referer, FALSE, FALSE, allow_cache, &err);
742 #endif
743
744   if (key_fragment == NULL) {
745     GST_WARNING_OBJECT (demux, "Failed to download key to decrypt data: %s",
746         err ? err->message : "error");
747     g_clear_error (&err);
748     goto out;
749   }
750
751   key_buffer = gst_fragment_get_buffer (key_fragment);
752
753   key = g_new0 (GstHLSKey, 1);
754   if (gst_buffer_extract (key_buffer, 0, key->data, 16) < 16)
755     GST_WARNING_OBJECT (demux, "Download decryption key is too short!");
756
757   g_hash_table_insert (demux->keys, g_strdup (key_url), key);
758
759   gst_buffer_unref (key_buffer);
760   g_object_unref (key_fragment);
761
762 out:
763
764   g_mutex_unlock (&demux->keys_lock);
765
766   if (key != NULL)
767     GST_MEMDUMP_OBJECT (demux, "Key", key->data, 16);
768
769   return key;
770 }
771
772 static gboolean
773 gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
774     GstAdaptiveDemuxStream * stream)
775 {
776   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
777   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
778   const GstHLSKey *key;
779   GstM3U8 *m3u8;
780
781   gst_hls_demux_stream_clear_pending_data (hls_stream);
782
783   /* Init the timestamp reader for this fragment */
784   gst_hlsdemux_tsreader_init (&hls_stream->tsreader);
785   /* Reset the stream type if we already know it */
786   gst_hlsdemux_tsreader_set_type (&hls_stream->tsreader,
787       hls_stream->stream_type);
788
789   /* If no decryption is needed, there's nothing to be done here */
790   if (hls_stream->current_key == NULL)
791     return TRUE;
792
793   m3u8 = gst_hls_demux_stream_get_m3u8 (hls_stream);
794
795   key = gst_hls_demux_get_key (hlsdemux, hls_stream->current_key,
796       m3u8->uri, m3u8->allowcache);
797
798   if (key == NULL)
799     goto key_failed;
800
801   gst_hls_demux_stream_decrypt_start (hls_stream, key->data,
802       hls_stream->current_iv);
803
804   return TRUE;
805
806 key_failed:
807   {
808     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
809         ("Couldn't retrieve key for decryption"), (NULL));
810     GST_WARNING_OBJECT (demux, "Failed to decrypt data");
811     return FALSE;
812   }
813 }
814
815 static GstHLSTSReaderType
816 caps_to_reader (const GstCaps * caps)
817 {
818   const GstStructure *s = gst_caps_get_structure (caps, 0);
819
820   if (gst_structure_has_name (s, "video/mpegts"))
821     return GST_HLS_TSREADER_MPEGTS;
822   if (gst_structure_has_name (s, "application/x-id3"))
823     return GST_HLS_TSREADER_ID3;
824
825   return GST_HLS_TSREADER_NONE;
826 }
827
828 static GstFlowReturn
829 gst_hls_demux_handle_buffer (GstAdaptiveDemux * demux,
830     GstAdaptiveDemuxStream * stream, GstBuffer * buffer, gboolean at_eos)
831 {
832   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
833   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
834   GstMapInfo info;
835   GstClockTime first_pcr, last_pcr;
836   GstTagList *tags;
837
838   if (buffer == NULL)
839     return GST_FLOW_OK;
840
841   gst_buffer_map (buffer, &info, GST_MAP_READ);
842
843   if (G_UNLIKELY (hls_stream->do_typefind)) {
844     GstCaps *caps = NULL;
845     guint buffer_size;
846     GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
847
848     if (hls_stream->pending_typefind_buffer)
849       buffer = gst_buffer_append (hls_stream->pending_typefind_buffer, buffer);
850     hls_stream->pending_typefind_buffer = NULL;
851
852     gst_buffer_map (buffer, &info, GST_MAP_READ);
853     buffer_size = info.size;
854
855     /* Typefind could miss if buffer is too small. In this case we
856      * will retry later */
857     if (buffer_size >= (2 * 1024) || at_eos) {
858       caps =
859           gst_type_find_helper_for_data (GST_OBJECT_CAST (hlsdemux), info.data,
860           info.size, &prob);
861     }
862
863     if (G_UNLIKELY (!caps)) {
864       /* Won't need this mapping any more all paths return inside this if() */
865       gst_buffer_unmap (buffer, &info);
866
867       /* Only fail typefinding if we already a good amount of data
868        * and we still don't know the type */
869       if (buffer_size > (2 * 1024 * 1024) || at_eos) {
870         GST_ELEMENT_ERROR (hlsdemux, STREAM, TYPE_NOT_FOUND,
871             ("Could not determine type of stream"), (NULL));
872         gst_buffer_unref (buffer);
873         return GST_FLOW_NOT_NEGOTIATED;
874       }
875
876       hls_stream->pending_typefind_buffer = buffer;
877
878       return GST_FLOW_OK;
879     }
880
881     GST_DEBUG_OBJECT (hlsdemux, "Typefind result: %" GST_PTR_FORMAT " prob:%d",
882         caps, prob);
883
884     hls_stream->stream_type = caps_to_reader (caps);
885     gst_hlsdemux_tsreader_set_type (&hls_stream->tsreader,
886         hls_stream->stream_type);
887
888 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
889     gst_adaptive_demux_stream_check_switch_pad (stream, caps,
890         gst_hls_demux_stream_create_pad);
891     GST_DEBUG_OBJECT (stream->pad, "Overwriting PTS to %" GST_TIME_FORMAT,
892         GST_TIME_ARGS (hls_stream->current_pts));
893     stream->fragment.timestamp = hls_stream->current_pts;
894 #else
895     gst_adaptive_demux_stream_set_caps (stream, caps);
896 #endif
897     hls_stream->do_typefind = FALSE;
898   }
899   g_assert (hls_stream->pending_typefind_buffer == NULL);
900
901   gst_buffer_unmap (buffer, &info);
902
903   // Accumulate this buffer
904   if (hls_stream->pending_pcr_buffer) {
905     buffer = gst_buffer_append (hls_stream->pending_pcr_buffer, buffer);
906     hls_stream->pending_pcr_buffer = NULL;
907   }
908
909   if (!gst_hlsdemux_tsreader_find_pcrs (&hls_stream->tsreader, &buffer,
910           &first_pcr, &last_pcr, &tags)
911       && !at_eos) {
912     // Store this buffer for later
913     hls_stream->pending_pcr_buffer = buffer;
914     return GST_FLOW_OK;
915   }
916
917   if (tags) {
918     gst_adaptive_demux_stream_set_tags (stream, tags);
919     /* run typefind again on the trimmed buffer */
920     hls_stream->do_typefind = TRUE;
921     return gst_hls_demux_handle_buffer (demux, stream, buffer, at_eos);
922   }
923
924   if (buffer) {
925     buffer = gst_buffer_make_writable (buffer);
926     GST_BUFFER_OFFSET (buffer) = hls_stream->current_offset;
927     hls_stream->current_offset += gst_buffer_get_size (buffer);
928     GST_BUFFER_OFFSET_END (buffer) = hls_stream->current_offset;
929     return gst_adaptive_demux_stream_push_buffer (stream, buffer);
930   }
931   return GST_FLOW_OK;
932 }
933
934 static GstFlowReturn
935 gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
936     GstAdaptiveDemuxStream * stream)
937 {
938   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
939   GstFlowReturn ret = GST_FLOW_OK;
940
941   if (hls_stream->current_key)
942     gst_hls_demux_stream_decrypt_end (hls_stream);
943
944   if (stream->last_ret == GST_FLOW_OK) {
945     if (hls_stream->pending_decrypted_buffer) {
946       if (hls_stream->current_key) {
947         GstMapInfo info;
948         gssize unpadded_size;
949
950         /* Handle pkcs7 unpadding here */
951         gst_buffer_map (hls_stream->pending_decrypted_buffer, &info,
952             GST_MAP_READ);
953         unpadded_size = info.size - info.data[info.size - 1];
954         gst_buffer_unmap (hls_stream->pending_decrypted_buffer, &info);
955
956         gst_buffer_resize (hls_stream->pending_decrypted_buffer, 0,
957             unpadded_size);
958       }
959
960       ret =
961           gst_hls_demux_handle_buffer (demux, stream,
962           hls_stream->pending_decrypted_buffer, TRUE);
963       hls_stream->pending_decrypted_buffer = NULL;
964     }
965
966     if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED) {
967       if (G_UNLIKELY (hls_stream->pending_typefind_buffer)) {
968         GstBuffer *buf = hls_stream->pending_typefind_buffer;
969         hls_stream->pending_typefind_buffer = NULL;
970
971         gst_hls_demux_handle_buffer (demux, stream, buf, TRUE);
972       }
973
974       if (hls_stream->pending_pcr_buffer) {
975         GstBuffer *buf = hls_stream->pending_pcr_buffer;
976         hls_stream->pending_pcr_buffer = NULL;
977
978         ret = gst_hls_demux_handle_buffer (demux, stream, buf, TRUE);
979       }
980
981       GST_LOG_OBJECT (stream,
982           "Fragment PCRs were %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
983           GST_TIME_ARGS (hls_stream->tsreader.first_pcr),
984           GST_TIME_ARGS (hls_stream->tsreader.last_pcr));
985     }
986   }
987
988   gst_hls_demux_stream_clear_pending_data (hls_stream);
989
990   if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED)
991     return gst_adaptive_demux_stream_advance_fragment (demux, stream,
992         stream->fragment.duration);
993   return ret;
994 }
995
996 static GstFlowReturn
997 gst_hls_demux_data_received (GstAdaptiveDemux * demux,
998     GstAdaptiveDemuxStream * stream, GstBuffer * buffer)
999 {
1000   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1001   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1002
1003   if (hls_stream->current_offset == -1)
1004     hls_stream->current_offset = 0;
1005
1006   /* Is it encrypted? */
1007   if (hls_stream->current_key) {
1008     GError *err = NULL;
1009     gsize size;
1010     GstBuffer *tmp_buffer;
1011
1012     if (hls_stream->pending_encrypted_data == NULL)
1013       hls_stream->pending_encrypted_data = gst_adapter_new ();
1014
1015     gst_adapter_push (hls_stream->pending_encrypted_data, buffer);
1016     size = gst_adapter_available (hls_stream->pending_encrypted_data);
1017
1018     /* must be a multiple of 16 */
1019     size &= (~0xF);
1020
1021     if (size == 0) {
1022       return GST_FLOW_OK;
1023     }
1024
1025     buffer = gst_adapter_take_buffer (hls_stream->pending_encrypted_data, size);
1026     buffer =
1027         gst_hls_demux_decrypt_fragment (hlsdemux, hls_stream, buffer, &err);
1028     if (buffer == NULL) {
1029       GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Failed to decrypt buffer"),
1030           ("decryption failed %s", err->message));
1031       g_error_free (err);
1032       return GST_FLOW_ERROR;
1033     }
1034
1035     tmp_buffer = hls_stream->pending_decrypted_buffer;
1036     hls_stream->pending_decrypted_buffer = buffer;
1037     buffer = tmp_buffer;
1038   }
1039
1040   return gst_hls_demux_handle_buffer (demux, stream, buffer, FALSE);
1041 }
1042
1043 static void
1044 gst_hls_demux_stream_free (GstAdaptiveDemuxStream * stream)
1045 {
1046   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1047
1048   if (hls_stream->playlist) {
1049     gst_m3u8_unref (hls_stream->playlist);
1050     hls_stream->playlist = NULL;
1051   }
1052
1053   if (hls_stream->pending_encrypted_data)
1054     g_object_unref (hls_stream->pending_encrypted_data);
1055
1056   gst_buffer_replace (&hls_stream->pending_decrypted_buffer, NULL);
1057   gst_buffer_replace (&hls_stream->pending_typefind_buffer, NULL);
1058   gst_buffer_replace (&hls_stream->pending_pcr_buffer, NULL);
1059
1060   if (hls_stream->current_key) {
1061     g_free (hls_stream->current_key);
1062     hls_stream->current_key = NULL;
1063   }
1064   if (hls_stream->current_iv) {
1065     g_free (hls_stream->current_iv);
1066     hls_stream->current_iv = NULL;
1067   }
1068   gst_hls_demux_stream_decrypt_end (hls_stream);
1069 }
1070
1071 static GstM3U8 *
1072 gst_hls_demux_stream_get_m3u8 (GstHLSDemuxStream * hlsdemux_stream)
1073 {
1074   GstM3U8 *m3u8;
1075
1076   m3u8 = hlsdemux_stream->playlist;
1077
1078   return m3u8;
1079 }
1080
1081 static gboolean
1082 gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemuxStream * stream)
1083 {
1084   gboolean has_next;
1085   GstM3U8 *m3u8;
1086
1087   m3u8 = gst_hls_demux_stream_get_m3u8 (GST_HLS_DEMUX_STREAM_CAST (stream));
1088
1089   has_next = gst_m3u8_has_next_fragment (m3u8, stream->demux->segment.rate > 0);
1090
1091   return has_next;
1092 }
1093
1094 static GstFlowReturn
1095 gst_hls_demux_advance_fragment (GstAdaptiveDemuxStream * stream)
1096 {
1097   GstHLSDemuxStream *hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1098   GstM3U8 *m3u8;
1099
1100   m3u8 = gst_hls_demux_stream_get_m3u8 (hlsdemux_stream);
1101
1102   gst_m3u8_advance_fragment (m3u8, stream->demux->segment.rate > 0);
1103   hlsdemux_stream->reset_pts = FALSE;
1104
1105   return GST_FLOW_OK;
1106 }
1107
1108 static GstFlowReturn
1109 gst_hls_demux_update_fragment_info (GstAdaptiveDemuxStream * stream)
1110 {
1111   GstHLSDemuxStream *hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1112   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
1113   GstM3U8MediaFile *file;
1114   GstClockTime sequence_pos;
1115   gboolean discont, forward;
1116   GstM3U8 *m3u8;
1117
1118   m3u8 = gst_hls_demux_stream_get_m3u8 (hlsdemux_stream);
1119
1120   forward = (stream->demux->segment.rate > 0);
1121   file = gst_m3u8_get_next_fragment (m3u8, forward, &sequence_pos, &discont);
1122
1123   if (file == NULL) {
1124     GST_INFO_OBJECT (hlsdemux, "This playlist doesn't contain more fragments");
1125     return GST_FLOW_EOS;
1126   }
1127
1128   if (stream->discont)
1129     discont = TRUE;
1130
1131   /* set up our source for download */
1132 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
1133   hlsdemux_stream->current_pts = sequence_pos;
1134 #endif
1135   if (hlsdemux_stream->reset_pts || discont
1136       || stream->demux->segment.rate < 0.0) {
1137     stream->fragment.timestamp = sequence_pos;
1138   } else {
1139     stream->fragment.timestamp = GST_CLOCK_TIME_NONE;
1140   }
1141
1142   g_free (hlsdemux_stream->current_key);
1143   hlsdemux_stream->current_key = g_strdup (file->key);
1144   g_free (hlsdemux_stream->current_iv);
1145   hlsdemux_stream->current_iv = g_memdup (file->iv, sizeof (file->iv));
1146
1147   g_free (stream->fragment.uri);
1148   stream->fragment.uri = g_strdup (file->uri);
1149
1150   GST_DEBUG_OBJECT (hlsdemux, "Stream %p URI now %s", stream, file->uri);
1151
1152   stream->fragment.range_start = file->offset;
1153   if (file->size != -1)
1154     stream->fragment.range_end = file->offset + file->size - 1;
1155   else
1156     stream->fragment.range_end = -1;
1157
1158   stream->fragment.duration = file->duration;
1159
1160   if (discont)
1161     stream->discont = TRUE;
1162
1163   gst_m3u8_media_file_unref (file);
1164
1165   return GST_FLOW_OK;
1166 }
1167
1168 static gboolean
1169 gst_hls_demux_select_bitrate (GstAdaptiveDemuxStream * stream, guint64 bitrate)
1170 {
1171   GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (stream->demux);
1172   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
1173   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1174
1175   gboolean changed = FALSE;
1176
1177   GST_M3U8_CLIENT_LOCK (hlsdemux->client);
1178   if (hlsdemux->master == NULL || hlsdemux->master->is_simple) {
1179     GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
1180     return FALSE;
1181   }
1182   GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
1183
1184   if (hls_stream->is_primary_playlist == FALSE) {
1185     GST_LOG_OBJECT (hlsdemux,
1186         "Stream %p Not choosing new bitrate - not the primary stream", stream);
1187     return FALSE;
1188   }
1189
1190   gst_hls_demux_change_playlist (hlsdemux, bitrate / MAX (1.0,
1191           ABS (demux->segment.rate)), &changed);
1192 #ifndef TIZEN_FEATURE_AVOID_PAD_SWITCHING
1193   if (changed)
1194     gst_hls_demux_setup_streams (GST_ADAPTIVE_DEMUX_CAST (hlsdemux));
1195 #endif
1196   return changed;
1197 }
1198
1199 static void
1200 gst_hls_demux_reset (GstAdaptiveDemux * ademux)
1201 {
1202   GstHLSDemux *demux = GST_HLS_DEMUX_CAST (ademux);
1203
1204   GST_M3U8_CLIENT_LOCK (hlsdemux->client);
1205   if (demux->master) {
1206     gst_hls_master_playlist_unref (demux->master);
1207     demux->master = NULL;
1208   }
1209   if (demux->current_variant != NULL) {
1210     gst_hls_variant_stream_unref (demux->current_variant);
1211     demux->current_variant = NULL;
1212   }
1213   demux->srcpad_counter = 0;
1214
1215   gst_hls_demux_clear_all_pending_data (demux);
1216   GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
1217 }
1218
1219 static gchar *
1220 gst_hls_src_buf_to_utf8_playlist (GstBuffer * buf)
1221 {
1222   GstMapInfo info;
1223   gchar *playlist;
1224
1225   if (!gst_buffer_map (buf, &info, GST_MAP_READ))
1226     goto map_error;
1227
1228   if (!g_utf8_validate ((gchar *) info.data, info.size, NULL))
1229     goto validate_error;
1230
1231   /* alloc size + 1 to end with a null character */
1232   playlist = g_malloc0 (info.size + 1);
1233   memcpy (playlist, info.data, info.size);
1234
1235   gst_buffer_unmap (buf, &info);
1236   return playlist;
1237
1238 validate_error:
1239   gst_buffer_unmap (buf, &info);
1240 map_error:
1241   return NULL;
1242 }
1243
1244 static gint
1245 gst_hls_demux_find_variant_match (const GstHLSVariantStream * a,
1246     const GstHLSVariantStream * b)
1247 {
1248   if (g_strcmp0 (a->name, b->name) == 0 &&
1249       a->bandwidth == b->bandwidth &&
1250       a->program_id == b->program_id &&
1251       g_strcmp0 (a->codecs, b->codecs) == 0 &&
1252       a->width == b->width &&
1253       a->height == b->height && a->iframe == b->iframe) {
1254     return 0;
1255   }
1256
1257   return 1;
1258 }
1259
1260 /* Update the master playlist, which contains the list of available
1261  * variants */
1262 static gboolean
1263 gst_hls_demux_update_variant_playlist (GstHLSDemux * hlsdemux, gchar * data,
1264     const gchar * uri, const gchar * base_uri)
1265 {
1266   GstHLSMasterPlaylist *new_master, *old;
1267   gboolean ret = FALSE;
1268   GList *l, *unmatched_lists;
1269   GstHLSVariantStream *new_variant;
1270
1271   new_master = gst_hls_master_playlist_new_from_data (data, base_uri ? base_uri : uri); // FIXME: check which uri to use here
1272
1273   if (new_master == NULL)
1274     return ret;
1275
1276   if (new_master->is_simple) {
1277     // FIXME: we should be able to support this though, in the unlikely
1278     // case that it changed?
1279     GST_ERROR
1280         ("Cannot update variant playlist: New playlist is not a variant playlist");
1281     gst_hls_master_playlist_unref (new_master);
1282     return FALSE;
1283   }
1284
1285   GST_M3U8_CLIENT_LOCK (self);
1286
1287   if (hlsdemux->master->is_simple) {
1288     GST_ERROR
1289         ("Cannot update variant playlist: Current playlist is not a variant playlist");
1290     goto out;
1291   }
1292
1293   /* Now see if the variant playlist still has the same lists */
1294   unmatched_lists = g_list_copy (hlsdemux->master->variants);
1295   for (l = new_master->variants; l != NULL; l = l->next) {
1296     GList *match = g_list_find_custom (unmatched_lists, l->data,
1297         (GCompareFunc) gst_hls_demux_find_variant_match);
1298
1299     if (match) {
1300       GstHLSVariantStream *variant = l->data;
1301       GstHLSVariantStream *old = match->data;
1302
1303       unmatched_lists = g_list_delete_link (unmatched_lists, match);
1304       /* FIXME: Deal with losing position due to missing an update */
1305       variant->m3u8->sequence_position = old->m3u8->sequence_position;
1306       variant->m3u8->sequence = old->m3u8->sequence;
1307     }
1308   }
1309
1310   if (unmatched_lists != NULL) {
1311     GST_WARNING ("Unable to match all playlists");
1312
1313     for (l = unmatched_lists; l != NULL; l = l->next) {
1314       if (l->data == hlsdemux->current_variant) {
1315         GST_WARNING ("Unable to match current playlist");
1316       }
1317     }
1318
1319     g_list_free (unmatched_lists);
1320   }
1321
1322   /* Switch out the variant playlist */
1323   old = hlsdemux->master;
1324
1325   // FIXME: check all this and also switch of variants, if anything needs updating
1326   hlsdemux->master = new_master;
1327
1328   if (hlsdemux->current_variant == NULL) {
1329     new_variant = new_master->default_variant;
1330   } else {
1331     /* Find the same variant in the new playlist */
1332     new_variant =
1333         gst_hls_master_playlist_get_matching_variant (new_master,
1334         hlsdemux->current_variant);
1335   }
1336
1337   /* Use the function to set the current variant, as it copies over data */
1338   if (new_variant != NULL)
1339     gst_hls_demux_set_current_variant (hlsdemux, new_variant);
1340
1341   gst_hls_master_playlist_unref (old);
1342
1343   ret = (hlsdemux->current_variant != NULL);
1344 out:
1345   GST_M3U8_CLIENT_UNLOCK (self);
1346
1347   return ret;
1348 }
1349
1350 static gboolean
1351 gst_hls_demux_update_rendition_manifest (GstHLSDemux * demux,
1352     GstHLSMedia * media, GError ** err)
1353 {
1354   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX (demux);
1355   GstFragment *download;
1356   GstBuffer *buf;
1357   gchar *playlist;
1358   const gchar *main_uri;
1359   GstM3U8 *m3u8;
1360   gchar *uri = media->uri;
1361
1362   main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
1363 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1364   download =
1365       gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
1366       adaptive_demux->user_agent, adaptive_demux->cookies, DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT,
1367       TRUE, TRUE, TRUE, err);
1368 #else
1369   download =
1370       gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
1371       TRUE, TRUE, TRUE, err);
1372 #endif
1373   if (download == NULL)
1374     return FALSE;
1375
1376   m3u8 = media->playlist;
1377
1378   /* Set the base URI of the playlist to the redirect target if any */
1379   if (download->redirect_permanent && download->redirect_uri) {
1380     gst_m3u8_set_uri (m3u8, download->redirect_uri, NULL, media->name);
1381   } else {
1382     gst_m3u8_set_uri (m3u8, download->uri, download->redirect_uri, media->name);
1383   }
1384
1385   buf = gst_fragment_get_buffer (download);
1386   playlist = gst_hls_src_buf_to_utf8_playlist (buf);
1387   gst_buffer_unref (buf);
1388   g_object_unref (download);
1389
1390   if (playlist == NULL) {
1391     GST_WARNING_OBJECT (demux, "Couldn't validate playlist encoding");
1392     g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
1393         "Couldn't validate playlist encoding");
1394     return FALSE;
1395   }
1396
1397   if (!gst_m3u8_update (m3u8, playlist)) {
1398     GST_WARNING_OBJECT (demux, "Couldn't update playlist");
1399     g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
1400         "Couldn't update playlist");
1401     return FALSE;
1402   }
1403
1404   return TRUE;
1405 }
1406
1407 static gboolean
1408 gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
1409     GError ** err)
1410 {
1411   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX (demux);
1412   GstFragment *download;
1413   GstBuffer *buf;
1414   gchar *playlist;
1415   gboolean main_checked = FALSE;
1416   const gchar *main_uri;
1417   GstM3U8 *m3u8;
1418   gchar *uri;
1419   gint i;
1420
1421 retry:
1422   uri = gst_m3u8_get_uri (demux->current_variant->m3u8);
1423   main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
1424 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1425   download =
1426       gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
1427       adaptive_demux->user_agent, adaptive_demux->cookies, DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT,
1428       TRUE, TRUE, TRUE, err);
1429 #else
1430   download =
1431       gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
1432       TRUE, TRUE, TRUE, err);
1433 #endif
1434   if (download == NULL) {
1435     gchar *base_uri;
1436
1437     if (!update || main_checked || demux->master->is_simple) {
1438       g_free (uri);
1439       return FALSE;
1440     }
1441     g_clear_error (err);
1442     GST_INFO_OBJECT (demux,
1443         "Updating playlist %s failed, attempt to refresh variant playlist %s",
1444         uri, main_uri);
1445 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1446     download =
1447         gst_uri_downloader_fetch_uri (adaptive_demux->downloader, main_uri, NULL,
1448         adaptive_demux->user_agent, adaptive_demux->cookies, DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT,
1449         TRUE, TRUE, TRUE, err);
1450 #else
1451     download =
1452         gst_uri_downloader_fetch_uri (adaptive_demux->downloader,
1453         main_uri, NULL, TRUE, TRUE, TRUE, err);
1454 #endif
1455     if (download == NULL) {
1456       g_free (uri);
1457       return FALSE;
1458     }
1459
1460     buf = gst_fragment_get_buffer (download);
1461     playlist = gst_hls_src_buf_to_utf8_playlist (buf);
1462     gst_buffer_unref (buf);
1463
1464     if (playlist == NULL) {
1465       GST_WARNING_OBJECT (demux,
1466           "Failed to validate variant playlist encoding");
1467       g_free (uri);
1468       g_object_unref (download);
1469       g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
1470           "Couldn't validate playlist encoding");
1471       return FALSE;
1472     }
1473
1474     g_free (uri);
1475     if (download->redirect_permanent && download->redirect_uri) {
1476       uri = download->redirect_uri;
1477       base_uri = NULL;
1478     } else {
1479       uri = download->uri;
1480       base_uri = download->redirect_uri;
1481     }
1482
1483     if (!gst_hls_demux_update_variant_playlist (demux, playlist, uri, base_uri)) {
1484       GST_WARNING_OBJECT (demux, "Failed to update the variant playlist");
1485       g_object_unref (download);
1486       g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
1487           "Couldn't update playlist");
1488       return FALSE;
1489     }
1490
1491     g_object_unref (download);
1492
1493     main_checked = TRUE;
1494     goto retry;
1495   }
1496   g_free (uri);
1497
1498   m3u8 = demux->current_variant->m3u8;
1499
1500   /* Set the base URI of the playlist to the redirect target if any */
1501   if (download->redirect_permanent && download->redirect_uri) {
1502     gst_m3u8_set_uri (m3u8, download->redirect_uri, NULL,
1503         demux->current_variant->name);
1504   } else {
1505     gst_m3u8_set_uri (m3u8, download->uri, download->redirect_uri,
1506         demux->current_variant->name);
1507   }
1508
1509   buf = gst_fragment_get_buffer (download);
1510   playlist = gst_hls_src_buf_to_utf8_playlist (buf);
1511   gst_buffer_unref (buf);
1512   g_object_unref (download);
1513
1514   if (playlist == NULL) {
1515     GST_WARNING_OBJECT (demux, "Couldn't validate playlist encoding");
1516     g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
1517         "Couldn't validate playlist encoding");
1518     return FALSE;
1519   }
1520
1521   if (!gst_m3u8_update (m3u8, playlist)) {
1522     GST_WARNING_OBJECT (demux, "Couldn't update playlist");
1523     g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
1524         "Couldn't update playlist");
1525     return FALSE;
1526   }
1527
1528   for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
1529     GList *mlist = demux->current_variant->media[i];
1530
1531     while (mlist != NULL) {
1532       GstHLSMedia *media = mlist->data;
1533
1534       if (media->uri == NULL) {
1535         /* No uri means this is a placeholder for a stream
1536          * contained in another mux */
1537         mlist = mlist->next;
1538         continue;
1539       }
1540       GST_LOG_OBJECT (demux,
1541           "Updating playlist for media of type %d - %s, uri: %s", i,
1542           media->name, media->uri);
1543
1544       if (!gst_hls_demux_update_rendition_manifest (demux, media, err))
1545         return FALSE;
1546
1547       mlist = mlist->next;
1548     }
1549   }
1550
1551   /* If it's a live source, do not let the sequence number go beyond
1552    * three fragments before the end of the list */
1553   if (update == FALSE && gst_m3u8_is_live (m3u8)) {
1554     gint64 last_sequence, first_sequence;
1555
1556     GST_M3U8_CLIENT_LOCK (demux->client);
1557     last_sequence =
1558         GST_M3U8_MEDIA_FILE (g_list_last (m3u8->files)->data)->sequence;
1559     first_sequence =
1560         GST_M3U8_MEDIA_FILE (g_list_first (m3u8->files)->data)->sequence;
1561
1562     GST_DEBUG_OBJECT (demux,
1563         "sequence:%" G_GINT64_FORMAT " , first_sequence:%" G_GINT64_FORMAT
1564         " , last_sequence:%" G_GINT64_FORMAT, m3u8->sequence,
1565         first_sequence, last_sequence);
1566     if (m3u8->sequence > last_sequence - 3) {
1567       //demux->need_segment = TRUE;
1568       /* Make sure we never go below the minimum sequence number */
1569       m3u8->sequence = MAX (first_sequence, last_sequence - 3);
1570       GST_DEBUG_OBJECT (demux,
1571           "Sequence is beyond playlist. Moving back to %" G_GINT64_FORMAT,
1572           m3u8->sequence);
1573     }
1574     GST_M3U8_CLIENT_UNLOCK (demux->client);
1575   } else if (!gst_m3u8_is_live (m3u8)) {
1576     GstClockTime current_pos, target_pos;
1577     guint sequence = 0;
1578     GList *walk;
1579
1580     /* Sequence numbers are not guaranteed to be the same in different
1581      * playlists, so get the correct fragment here based on the current
1582      * position
1583      */
1584     GST_M3U8_CLIENT_LOCK (demux->client);
1585
1586     /* Valid because hlsdemux only has a single output */
1587     if (GST_ADAPTIVE_DEMUX_CAST (demux)->streams) {
1588       GstAdaptiveDemuxStream *stream =
1589           GST_ADAPTIVE_DEMUX_CAST (demux)->streams->data;
1590       target_pos = stream->segment.position;
1591     } else {
1592       target_pos = 0;
1593     }
1594     if (GST_CLOCK_TIME_IS_VALID (m3u8->sequence_position)) {
1595       target_pos = MAX (target_pos, m3u8->sequence_position);
1596     }
1597
1598     GST_LOG_OBJECT (demux, "Looking for sequence position %"
1599         GST_TIME_FORMAT " in updated playlist", GST_TIME_ARGS (target_pos));
1600
1601     current_pos = 0;
1602     for (walk = m3u8->files; walk; walk = walk->next) {
1603       GstM3U8MediaFile *file = walk->data;
1604
1605       sequence = file->sequence;
1606       if (current_pos <= target_pos
1607           && target_pos < current_pos + file->duration) {
1608         break;
1609       }
1610       current_pos += file->duration;
1611     }
1612     /* End of playlist */
1613     if (!walk)
1614       sequence++;
1615     m3u8->sequence = sequence;
1616     m3u8->sequence_position = current_pos;
1617     GST_M3U8_CLIENT_UNLOCK (demux->client);
1618   }
1619
1620 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1621   GST_DEBUG_OBJECT (demux, "post variant info message");
1622   gst_element_post_message (GST_ELEMENT_CAST (demux),
1623       gst_message_new_element (GST_OBJECT_CAST (demux),
1624           gst_structure_new (GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME,
1625               "video-variant-info", G_TYPE_POINTER,
1626               demux->master->variant_info, NULL)));
1627 #endif
1628
1629   return TRUE;
1630 }
1631
1632 static gboolean
1633 gst_hls_demux_change_playlist (GstHLSDemux * demux, guint max_bitrate,
1634     gboolean * changed)
1635 {
1636   GstHLSVariantStream *lowest_variant, *lowest_ivariant;
1637   GstHLSVariantStream *previous_variant, *new_variant;
1638   gint old_bandwidth, new_bandwidth;
1639   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX_CAST (demux);
1640   GstAdaptiveDemuxStream *stream;
1641
1642   g_return_val_if_fail (adaptive_demux->streams != NULL, FALSE);
1643
1644   stream = adaptive_demux->streams->data;
1645
1646   previous_variant = demux->current_variant;
1647 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1648   new_variant =
1649     gst_hls_master_playlist_get_variant_for_max_limit (demux->master,
1650                       demux->current_variant, max_bitrate,
1651                       adaptive_demux->max_bandwidth, adaptive_demux->max_width, adaptive_demux->max_height);
1652 #else
1653   new_variant =
1654       gst_hls_master_playlist_get_variant_for_bitrate (demux->master,
1655       demux->current_variant, max_bitrate);
1656 #endif
1657   GST_M3U8_CLIENT_LOCK (demux->client);
1658
1659 retry_failover_protection:
1660   old_bandwidth = previous_variant->bandwidth;
1661   new_bandwidth = new_variant->bandwidth;
1662
1663   /* Don't do anything else if the playlist is the same */
1664   if (new_bandwidth == old_bandwidth) {
1665     GST_M3U8_CLIENT_UNLOCK (demux->client);
1666     return TRUE;
1667   }
1668
1669   GST_M3U8_CLIENT_UNLOCK (demux->client);
1670
1671   gst_hls_demux_set_current_variant (demux, new_variant);
1672
1673   GST_INFO_OBJECT (demux, "Client was on %dbps, max allowed is %dbps, switching"
1674       " to bitrate %dbps", old_bandwidth, max_bitrate, new_bandwidth);
1675
1676   if (gst_hls_demux_update_playlist (demux, TRUE, NULL)) {
1677     const gchar *main_uri;
1678     gchar *uri;
1679
1680     uri = gst_m3u8_get_uri (new_variant->m3u8);
1681     main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
1682     gst_element_post_message (GST_ELEMENT_CAST (demux),
1683         gst_message_new_element (GST_OBJECT_CAST (demux),
1684             gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME,
1685                 "manifest-uri", G_TYPE_STRING,
1686                 main_uri, "uri", G_TYPE_STRING,
1687                 uri, "bitrate", G_TYPE_INT, new_bandwidth, NULL)));
1688     g_free (uri);
1689     if (changed)
1690       *changed = TRUE;
1691     stream->discont = TRUE;
1692   } else {
1693     GstHLSVariantStream *failover_variant = NULL;
1694     GList *failover;
1695
1696     GST_INFO_OBJECT (demux, "Unable to update playlist. Switching back");
1697     GST_M3U8_CLIENT_LOCK (demux->client);
1698
1699     /* we find variants by bitrate by going from highest to lowest, so it's
1700      * possible that there's another variant with the same bitrate before the
1701      * one selected which we can use as failover */
1702     failover = g_list_find (demux->master->variants, new_variant);
1703     if (failover != NULL)
1704       failover = failover->prev;
1705     if (failover != NULL)
1706       failover_variant = failover->data;
1707     if (failover_variant && new_bandwidth == failover_variant->bandwidth) {
1708       new_variant = failover_variant;
1709       goto retry_failover_protection;
1710     }
1711
1712     GST_M3U8_CLIENT_UNLOCK (demux->client);
1713     gst_hls_demux_set_current_variant (demux, previous_variant);
1714     /*  Try a lower bitrate (or stop if we just tried the lowest) */
1715     if (previous_variant->iframe) {
1716       lowest_ivariant = demux->master->iframe_variants->data;
1717       if (new_bandwidth == lowest_ivariant->bandwidth)
1718         return FALSE;
1719     } else {
1720       lowest_variant = demux->master->variants->data;
1721       if (new_bandwidth == lowest_variant->bandwidth)
1722         return FALSE;
1723     }
1724     return gst_hls_demux_change_playlist (demux, new_bandwidth - 1, changed);
1725   }
1726
1727   return TRUE;
1728 }
1729
1730 #if defined(HAVE_OPENSSL)
1731 static gboolean
1732 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
1733     const guint8 * key_data, const guint8 * iv_data)
1734 {
1735   EVP_CIPHER_CTX_init (&stream->aes_ctx);
1736   if (!EVP_DecryptInit_ex (&stream->aes_ctx, EVP_aes_128_cbc (), NULL, key_data,
1737           iv_data))
1738     return FALSE;
1739   EVP_CIPHER_CTX_set_padding (&stream->aes_ctx, 0);
1740   return TRUE;
1741 }
1742
1743 static gboolean
1744 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
1745     const guint8 * encrypted_data, guint8 * decrypted_data)
1746 {
1747   int len, flen = 0;
1748
1749   if (G_UNLIKELY (length > G_MAXINT || length % 16 != 0))
1750     return FALSE;
1751
1752   len = (int) length;
1753   if (!EVP_DecryptUpdate (&stream->aes_ctx, decrypted_data, &len,
1754           encrypted_data, len))
1755     return FALSE;
1756   EVP_DecryptFinal_ex (&stream->aes_ctx, decrypted_data + len, &flen);
1757   g_return_val_if_fail (len + flen == length, FALSE);
1758   return TRUE;
1759 }
1760
1761 static void
1762 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
1763 {
1764   EVP_CIPHER_CTX_cleanup (&stream->aes_ctx);
1765 }
1766
1767 #elif defined(HAVE_NETTLE)
1768 static gboolean
1769 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
1770     const guint8 * key_data, const guint8 * iv_data)
1771 {
1772   aes_set_decrypt_key (&stream->aes_ctx.ctx, 16, key_data);
1773   CBC_SET_IV (&stream->aes_ctx, iv_data);
1774
1775   return TRUE;
1776 }
1777
1778 static gboolean
1779 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
1780     const guint8 * encrypted_data, guint8 * decrypted_data)
1781 {
1782   if (length % 16 != 0)
1783     return FALSE;
1784
1785   CBC_DECRYPT (&stream->aes_ctx, aes_decrypt, length, decrypted_data,
1786       encrypted_data);
1787
1788   return TRUE;
1789 }
1790
1791 static void
1792 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
1793 {
1794   /* NOP */
1795 }
1796
1797 #else
1798 static gboolean
1799 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
1800     const guint8 * key_data, const guint8 * iv_data)
1801 {
1802   gcry_error_t err = 0;
1803   gboolean ret = FALSE;
1804
1805   err =
1806       gcry_cipher_open (&stream->aes_ctx, GCRY_CIPHER_AES128,
1807       GCRY_CIPHER_MODE_CBC, 0);
1808   if (err)
1809     goto out;
1810   err = gcry_cipher_setkey (stream->aes_ctx, key_data, 16);
1811   if (err)
1812     goto out;
1813   err = gcry_cipher_setiv (stream->aes_ctx, iv_data, 16);
1814   if (!err)
1815     ret = TRUE;
1816
1817 out:
1818   if (!ret)
1819     if (stream->aes_ctx)
1820       gcry_cipher_close (stream->aes_ctx);
1821
1822   return ret;
1823 }
1824
1825 static gboolean
1826 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
1827     const guint8 * encrypted_data, guint8 * decrypted_data)
1828 {
1829   gcry_error_t err = 0;
1830
1831   err = gcry_cipher_decrypt (stream->aes_ctx, decrypted_data, length,
1832       encrypted_data, length);
1833
1834   return err == 0;
1835 }
1836
1837 static void
1838 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
1839 {
1840   if (stream->aes_ctx) {
1841     gcry_cipher_close (stream->aes_ctx);
1842     stream->aes_ctx = NULL;
1843   }
1844 }
1845 #endif
1846
1847 static GstBuffer *
1848 gst_hls_demux_decrypt_fragment (GstHLSDemux * demux, GstHLSDemuxStream * stream,
1849     GstBuffer * encrypted_buffer, GError ** err)
1850 {
1851   GstBuffer *decrypted_buffer = NULL;
1852   GstMapInfo encrypted_info, decrypted_info;
1853
1854   decrypted_buffer =
1855       gst_buffer_new_allocate (NULL, gst_buffer_get_size (encrypted_buffer),
1856       NULL);
1857
1858   gst_buffer_map (encrypted_buffer, &encrypted_info, GST_MAP_READ);
1859   gst_buffer_map (decrypted_buffer, &decrypted_info, GST_MAP_WRITE);
1860
1861   if (!decrypt_fragment (stream, encrypted_info.size,
1862           encrypted_info.data, decrypted_info.data))
1863     goto decrypt_error;
1864
1865
1866   gst_buffer_unmap (decrypted_buffer, &decrypted_info);
1867   gst_buffer_unmap (encrypted_buffer, &encrypted_info);
1868
1869   gst_buffer_unref (encrypted_buffer);
1870
1871   return decrypted_buffer;
1872
1873 decrypt_error:
1874   GST_ERROR_OBJECT (demux, "Failed to decrypt fragment");
1875   g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_DECRYPT,
1876       "Failed to decrypt fragment");
1877
1878   gst_buffer_unmap (decrypted_buffer, &decrypted_info);
1879   gst_buffer_unmap (encrypted_buffer, &encrypted_info);
1880
1881   gst_buffer_unref (encrypted_buffer);
1882   gst_buffer_unref (decrypted_buffer);
1883
1884   return NULL;
1885 }
1886
1887 static gint64
1888 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
1889 {
1890   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1891   GstClockTime target_duration;
1892
1893   if (hlsdemux->current_variant) {
1894     target_duration =
1895         gst_m3u8_get_target_duration (hlsdemux->current_variant->m3u8);
1896   } else {
1897     target_duration = 5 * GST_SECOND;
1898   }
1899
1900   return gst_util_uint64_scale (target_duration, G_USEC_PER_SEC, GST_SECOND);
1901 }
1902
1903 static gboolean
1904 gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * start,
1905     gint64 * stop)
1906 {
1907   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1908   gboolean ret = FALSE;
1909
1910   if (hlsdemux->current_variant) {
1911     ret =
1912         gst_m3u8_get_seek_range (hlsdemux->current_variant->m3u8, start, stop);
1913   }
1914
1915   return ret;
1916 }