hlsdemux: Reset m3u8 sequence when fail three times to get next fragment
[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 <gst/tag/tag.h>
47 #include "gsthlsdemux.h"
48
49 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src_%u",
50     GST_PAD_SRC,
51     GST_PAD_SOMETIMES,
52     GST_STATIC_CAPS_ANY);
53
54 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
55     GST_PAD_SINK,
56     GST_PAD_ALWAYS,
57     GST_STATIC_CAPS ("application/x-hls"));
58
59 GST_DEBUG_CATEGORY (gst_hls_demux_debug);
60 #define GST_CAT_DEFAULT gst_hls_demux_debug
61
62 #define GST_M3U8_CLIENT_LOCK(l) /* FIXME */
63 #define GST_M3U8_CLIENT_UNLOCK(l)       /* FIXME */
64
65 #ifdef TIZEN_FEATURE_HLSDEMUX_PROPERTY
66 enum
67 {
68   PROP_0,
69   PROP_IS_LIVE,
70   PROP_LIVE_START_TIME,
71   PROP_LIVE_END_TIME,
72   PROP_LAST
73 };
74 #endif
75
76 #ifdef TIZEN_FEATURE_HLSDEMUX_DISCONT
77 #define ABSDIFF(a,b) ((a) < (b) ? (b) - (a) : (a) - (b))
78 #endif
79
80 #ifdef TIZEN_FEATURE_HLSDEMUX_DISCONT_SEQUENCE
81 #define DEFAULT_FAILED_COUNT 3
82 #endif
83
84 /* GObject */
85 static void gst_hls_demux_finalize (GObject * obj);
86 #ifdef TIZEN_FEATURE_HLSDEMUX_PROPERTY
87 static void
88 gst_hls_demux_get_property (GObject * object, guint prop_id,
89     GValue * value, GParamSpec * pspec);
90 #endif
91
92 /* GstElement */
93 static GstStateChangeReturn
94 gst_hls_demux_change_state (GstElement * element, GstStateChange transition);
95
96 /* GstHLSDemux */
97 static gboolean gst_hls_demux_update_playlist (GstHLSDemux * demux,
98     gboolean update, GError ** err);
99 static gchar *gst_hls_src_buf_to_utf8_playlist (GstBuffer * buf);
100
101 /* FIXME: the return value is never used? */
102 static gboolean gst_hls_demux_change_playlist (GstHLSDemux * demux,
103     guint max_bitrate, gboolean * changed);
104 static GstBuffer *gst_hls_demux_decrypt_fragment (GstHLSDemux * demux,
105     GstHLSDemuxStream * stream, GstBuffer * encrypted_buffer, GError ** err);
106 static gboolean
107 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
108     const guint8 * key_data, const guint8 * iv_data);
109 static void gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream);
110
111 static gboolean gst_hls_demux_is_live (GstAdaptiveDemux * demux);
112 static GstClockTime gst_hls_demux_get_duration (GstAdaptiveDemux * demux);
113 static gint64 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux *
114     demux);
115 static gboolean gst_hls_demux_process_manifest (GstAdaptiveDemux * demux,
116     GstBuffer * buf);
117 static GstFlowReturn gst_hls_demux_update_manifest (GstAdaptiveDemux * demux);
118 static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
119 static GstFlowReturn gst_hls_demux_stream_seek (GstAdaptiveDemuxStream *
120     stream, gboolean forward, GstSeekFlags flags, GstClockTime ts,
121     GstClockTime * final_ts);
122 static gboolean
123 gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
124     GstAdaptiveDemuxStream * stream);
125 static GstFlowReturn gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
126     GstAdaptiveDemuxStream * stream);
127 static GstFlowReturn gst_hls_demux_data_received (GstAdaptiveDemux * demux,
128     GstAdaptiveDemuxStream * stream, GstBuffer * buffer);
129 static void gst_hls_demux_stream_free (GstAdaptiveDemuxStream * stream);
130 static gboolean gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemuxStream *
131     stream);
132 static GstFlowReturn gst_hls_demux_advance_fragment (GstAdaptiveDemuxStream *
133     stream);
134 static GstFlowReturn gst_hls_demux_update_fragment_info (GstAdaptiveDemuxStream
135     * stream);
136 static gboolean gst_hls_demux_select_bitrate (GstAdaptiveDemuxStream * stream,
137     guint64 bitrate);
138 static void gst_hls_demux_reset (GstAdaptiveDemux * demux);
139 static gboolean gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux,
140     gint64 * start, gint64 * stop);
141 static GstM3U8 *gst_hls_demux_stream_get_m3u8 (GstHLSDemuxStream * hls_stream);
142 static void gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
143     GstHLSVariantStream * variant);
144 #ifdef TIZEN_FEATURE_HLSDEMUX_LANG_TAG
145 static gboolean gst_hlsdemux_set_stream_event (GstAdaptiveDemuxStream * stream,
146     GstHLSMedia * media);
147 static gboolean gst_hlsdemux_set_language_tags (GstAdaptiveDemuxStream * stream,
148     const gchar * language);
149 #endif
150
151 #define gst_hls_demux_parent_class parent_class
152 G_DEFINE_TYPE (GstHLSDemux, gst_hls_demux, GST_TYPE_ADAPTIVE_DEMUX);
153
154 static void
155 gst_hls_demux_finalize (GObject * obj)
156 {
157   GstHLSDemux *demux = GST_HLS_DEMUX (obj);
158
159   gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
160   g_mutex_clear (&demux->keys_lock);
161   if (demux->keys) {
162     g_hash_table_unref (demux->keys);
163     demux->keys = NULL;
164   }
165
166   G_OBJECT_CLASS (parent_class)->finalize (obj);
167 }
168
169 static void
170 gst_hls_demux_class_init (GstHLSDemuxClass * klass)
171 {
172   GObjectClass *gobject_class;
173   GstElementClass *element_class;
174   GstAdaptiveDemuxClass *adaptivedemux_class;
175
176   gobject_class = (GObjectClass *) klass;
177   element_class = (GstElementClass *) klass;
178   adaptivedemux_class = (GstAdaptiveDemuxClass *) klass;
179
180 #ifdef TIZEN_FEATURE_HLSDEMUX_PROPERTY
181   gobject_class->get_property = gst_hls_demux_get_property;
182 #endif
183   gobject_class->finalize = gst_hls_demux_finalize;
184
185 #ifdef TIZEN_FEATURE_HLSDEMUX_PROPERTY
186   g_object_class_install_property (gobject_class, PROP_IS_LIVE,
187       g_param_spec_boolean ("is-live", "is-live", "Whether the source is live",
188           FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
189
190   g_object_class_install_property (gobject_class, PROP_LIVE_START_TIME,
191       g_param_spec_uint64 ("live-start-time",
192           "start time of the first fragment",
193           "start time of the first fragment in the current media playlist in case of live",
194           0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
195
196   g_object_class_install_property (gobject_class, PROP_LIVE_END_TIME,
197       g_param_spec_uint64 ("live-end-time", "end time of the last fragment",
198           "end time of the last fragment in the current media playlist in case of live",
199           0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
200 #endif
201
202   element_class->change_state = GST_DEBUG_FUNCPTR (gst_hls_demux_change_state);
203
204   gst_element_class_add_static_pad_template (element_class, &srctemplate);
205   gst_element_class_add_static_pad_template (element_class, &sinktemplate);
206
207   gst_element_class_set_static_metadata (element_class,
208       "HLS Demuxer",
209       "Codec/Demuxer/Adaptive",
210       "HTTP Live Streaming demuxer",
211       "Marc-Andre Lureau <marcandre.lureau@gmail.com>\n"
212       "Andoni Morales Alastruey <ylatuya@gmail.com>");
213
214   adaptivedemux_class->is_live = gst_hls_demux_is_live;
215   adaptivedemux_class->get_live_seek_range = gst_hls_demux_get_live_seek_range;
216   adaptivedemux_class->get_duration = gst_hls_demux_get_duration;
217   adaptivedemux_class->get_manifest_update_interval =
218       gst_hls_demux_get_manifest_update_interval;
219   adaptivedemux_class->process_manifest = gst_hls_demux_process_manifest;
220   adaptivedemux_class->update_manifest = gst_hls_demux_update_manifest;
221   adaptivedemux_class->reset = gst_hls_demux_reset;
222   adaptivedemux_class->seek = gst_hls_demux_seek;
223   adaptivedemux_class->stream_seek = gst_hls_demux_stream_seek;
224   adaptivedemux_class->stream_has_next_fragment =
225       gst_hls_demux_stream_has_next_fragment;
226   adaptivedemux_class->stream_advance_fragment = gst_hls_demux_advance_fragment;
227   adaptivedemux_class->stream_update_fragment_info =
228       gst_hls_demux_update_fragment_info;
229   adaptivedemux_class->stream_select_bitrate = gst_hls_demux_select_bitrate;
230   adaptivedemux_class->stream_free = gst_hls_demux_stream_free;
231
232   adaptivedemux_class->start_fragment = gst_hls_demux_start_fragment;
233   adaptivedemux_class->finish_fragment = gst_hls_demux_finish_fragment;
234   adaptivedemux_class->data_received = gst_hls_demux_data_received;
235
236   GST_DEBUG_CATEGORY_INIT (gst_hls_demux_debug, "hlsdemux", 0,
237       "hlsdemux element");
238 }
239
240 static void
241 gst_hls_demux_init (GstHLSDemux * demux)
242 {
243   gst_adaptive_demux_set_stream_struct_size (GST_ADAPTIVE_DEMUX_CAST (demux),
244       sizeof (GstHLSDemuxStream));
245
246   demux->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
247   g_mutex_init (&demux->keys_lock);
248 }
249
250 #ifdef TIZEN_FEATURE_HLSDEMUX_PROPERTY
251 static void
252 gst_hls_demux_get_property (GObject * object, guint prop_id,
253     GValue * value, GParamSpec * pspec)
254 {
255   GstAdaptiveDemux *adaptivedemux = GST_ADAPTIVE_DEMUX (object);
256   GstHLSDemux *demux = GST_HLS_DEMUX (adaptivedemux);
257   GstHLSVariantStream *variant = demux->current_variant;
258   gboolean is_live = FALSE;
259
260   if (variant)
261     is_live = gst_hls_variant_stream_is_live (variant);
262
263   switch (prop_id) {
264     case PROP_IS_LIVE:
265       g_value_set_boolean (value, is_live);
266       break;
267     case PROP_LIVE_START_TIME:{
268       GstClockTime start_time = 0;
269       if (is_live)
270         start_time = variant->m3u8->first_file_start;
271       g_value_set_uint64 (value, start_time);
272       break;
273     }
274     case PROP_LIVE_END_TIME:{
275       GstClockTime end_time = 0;
276       if (is_live)
277         end_time = variant->m3u8->last_file_end;
278       g_value_set_uint64 (value, end_time);
279       break;
280     }
281     default:
282       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283       break;
284   }
285 }
286 #endif
287
288 static GstStateChangeReturn
289 gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
290 {
291   GstStateChangeReturn ret;
292   GstHLSDemux *demux = GST_HLS_DEMUX (element);
293
294   switch (transition) {
295     case GST_STATE_CHANGE_READY_TO_PAUSED:
296       gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
297       break;
298     default:
299       break;
300   }
301
302   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
303
304   switch (transition) {
305     case GST_STATE_CHANGE_PAUSED_TO_READY:
306       gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
307       g_hash_table_remove_all (demux->keys);
308       break;
309     default:
310       break;
311   }
312   return ret;
313 }
314
315 static GstPad *
316 gst_hls_demux_create_pad (GstHLSDemux * hlsdemux)
317 {
318   gchar *name;
319   GstPad *pad;
320
321   name = g_strdup_printf ("src_%u", hlsdemux->srcpad_counter++);
322   pad = gst_pad_new_from_static_template (&srctemplate, name);
323   g_free (name);
324
325   return pad;
326 }
327
328 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
329 static GstPad *
330 gst_hls_demux_stream_create_pad (GstAdaptiveDemuxStream * stream)
331 {
332   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
333   return gst_hls_demux_create_pad (hlsdemux);
334 }
335 #endif
336
337 static guint64
338 gst_hls_demux_get_bitrate (GstHLSDemux * hlsdemux)
339 {
340   GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (hlsdemux);
341
342   /* FIXME !!!
343    *
344    * No, there isn't a single output :D */
345
346   /* Valid because hlsdemux only has a single output */
347   if (demux->streams) {
348     GstAdaptiveDemuxStream *stream = demux->streams->data;
349     return stream->current_download_rate;
350   }
351
352   return 0;
353 }
354
355 static void
356 gst_hls_demux_stream_clear_pending_data (GstHLSDemuxStream * hls_stream)
357 {
358   if (hls_stream->pending_encrypted_data)
359     gst_adapter_clear (hls_stream->pending_encrypted_data);
360   gst_buffer_replace (&hls_stream->pending_decrypted_buffer, NULL);
361   gst_buffer_replace (&hls_stream->pending_typefind_buffer, NULL);
362   gst_buffer_replace (&hls_stream->pending_pcr_buffer, NULL);
363   hls_stream->current_offset = -1;
364   gst_hls_demux_stream_decrypt_end (hls_stream);
365 }
366
367 static void
368 gst_hls_demux_clear_all_pending_data (GstHLSDemux * hlsdemux)
369 {
370   GstAdaptiveDemux *demux = (GstAdaptiveDemux *) hlsdemux;
371   GList *walk;
372
373   for (walk = demux->streams; walk != NULL; walk = walk->next) {
374     GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (walk->data);
375     gst_hls_demux_stream_clear_pending_data (hls_stream);
376   }
377 }
378
379 #if 0
380 static void
381 gst_hls_demux_set_current (GstHLSDemux * self, GstM3U8 * m3u8)
382 {
383   GST_M3U8_CLIENT_LOCK (self);
384   if (m3u8 != self->current) {
385     self->current = m3u8;
386     self->current->duration = GST_CLOCK_TIME_NONE;
387     self->current->current_file = NULL;
388
389 #if 0
390     // FIXME: this makes no sense after we just set self->current=m3u8 above (tpm)
391     // also, these values don't necessarily align between different lists
392     m3u8->current_file_duration = self->current->current_file_duration;
393     m3u8->sequence = self->current->sequence;
394     m3u8->sequence_position = self->current->sequence_position;
395     m3u8->highest_sequence_number = self->current->highest_sequence_number;
396     m3u8->first_file_start = self->current->first_file_start;
397     m3u8->last_file_end = self->current->last_file_end;
398 #endif
399   }
400   GST_M3U8_CLIENT_UNLOCK (self);
401 }
402 #endif
403
404 #define SEEK_UPDATES_PLAY_POSITION(r, start_type, stop_type) \
405   ((r >= 0 && start_type != GST_SEEK_TYPE_NONE) || \
406    (r < 0 && stop_type != GST_SEEK_TYPE_NONE))
407
408 #define IS_SNAP_SEEK(f) (f & (GST_SEEK_FLAG_SNAP_BEFORE |         \
409                               GST_SEEK_FLAG_SNAP_AFTER |          \
410                               GST_SEEK_FLAG_SNAP_NEAREST |        \
411                               GST_SEEK_FLAG_TRICKMODE_KEY_UNITS | \
412                               GST_SEEK_FLAG_KEY_UNIT))
413
414 static gboolean
415 gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
416 {
417   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
418   GstFormat format;
419   GstSeekFlags flags;
420   GstSeekType start_type, stop_type;
421   gint64 start, stop;
422   gdouble rate, old_rate;
423   GList *walk;
424   GstClockTime current_pos, target_pos, final_pos;
425   guint64 bitrate;
426
427   gst_event_parse_seek (seek, &rate, &format, &flags, &start_type, &start,
428       &stop_type, &stop);
429
430   if (!SEEK_UPDATES_PLAY_POSITION (rate, start_type, stop_type)) {
431     /* nothing to do if we don't have to update the current position */
432     return TRUE;
433   }
434
435   old_rate = demux->segment.rate;
436
437   bitrate = gst_hls_demux_get_bitrate (hlsdemux);
438
439   /* Use I-frame variants for trick modes */
440   if (hlsdemux->master->iframe_variants != NULL
441       && rate < -1.0 && old_rate >= -1.0 && old_rate <= 1.0) {
442     GError *err = NULL;
443
444     /* Switch to I-frame variant */
445     gst_hls_demux_set_current_variant (hlsdemux,
446         hlsdemux->master->iframe_variants->data);
447     gst_uri_downloader_reset (demux->downloader);
448     if (!gst_hls_demux_update_playlist (hlsdemux, FALSE, &err)) {
449       GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err);
450       return FALSE;
451     }
452     //hlsdemux->discont = TRUE;
453
454     gst_hls_demux_change_playlist (hlsdemux, bitrate / ABS (rate), NULL);
455   } else if (rate > -1.0 && rate <= 1.0 && (old_rate < -1.0 || old_rate > 1.0)) {
456     GError *err = NULL;
457     /* Switch to normal variant */
458     gst_hls_demux_set_current_variant (hlsdemux,
459         hlsdemux->master->variants->data);
460     gst_uri_downloader_reset (demux->downloader);
461     if (!gst_hls_demux_update_playlist (hlsdemux, FALSE, &err)) {
462       GST_ELEMENT_ERROR_FROM_ERROR (hlsdemux, "Could not switch playlist", err);
463       return FALSE;
464     }
465     //hlsdemux->discont = TRUE;
466     /* TODO why not continue using the same? that was being used up to now? */
467     gst_hls_demux_change_playlist (hlsdemux, bitrate, NULL);
468   }
469
470   target_pos = rate < 0 ? stop : start;
471   final_pos = target_pos;
472
473   /* properly cleanup pending decryption status */
474   if (flags & GST_SEEK_FLAG_FLUSH) {
475     gst_hls_demux_clear_all_pending_data (hlsdemux);
476   }
477
478   for (walk = demux->streams; walk; walk = g_list_next (walk)) {
479     GstAdaptiveDemuxStream *stream =
480         GST_ADAPTIVE_DEMUX_STREAM_CAST (walk->data);
481
482     gst_hls_demux_stream_seek (stream, rate >= 0, flags, target_pos,
483         &current_pos);
484
485     /* FIXME: use minimum position always ? */
486 #ifdef TIZEN_FEATURE_HLSDEMUX_UPDATE_SEGMENT
487     if ((final_pos > current_pos) &&
488         (GST_HLS_DEMUX_STREAM_CAST (stream)->stream_type !=
489             GST_HLS_TSREADER_NONE))
490 #else
491     if (final_pos > current_pos)
492 #endif
493       final_pos = current_pos;
494   }
495
496   if (IS_SNAP_SEEK (flags)) {
497     if (rate >= 0)
498       gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
499           final_pos, stop_type, stop, NULL);
500     else
501       gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
502           start, stop_type, final_pos, NULL);
503   }
504
505   return TRUE;
506 }
507
508 static GstFlowReturn
509 gst_hls_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward,
510     GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts)
511 {
512   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
513   GList *walk;
514   GstClockTime current_pos;
515   gint64 current_sequence;
516   gboolean snap_after, snap_nearest;
517   GstM3U8MediaFile *file = NULL;
518
519   current_sequence = 0;
520   current_pos = gst_m3u8_is_live (hls_stream->playlist) ?
521       hls_stream->playlist->first_file_start : 0;
522
523   /* Snap to segment boundary. Improves seek performance on slow machines. */
524   snap_nearest =
525       (flags & GST_SEEK_FLAG_SNAP_NEAREST) == GST_SEEK_FLAG_SNAP_NEAREST;
526   snap_after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
527
528   GST_M3U8_CLIENT_LOCK (hlsdemux->client);
529   /* FIXME: Here we need proper discont handling */
530   for (walk = hls_stream->playlist->files; walk; walk = walk->next) {
531     file = walk->data;
532
533     current_sequence = file->sequence;
534     if ((forward && snap_after) || snap_nearest) {
535       if (current_pos >= ts)
536         break;
537       if (snap_nearest && ts - current_pos < file->duration / 2)
538         break;
539     } else if (!forward && snap_after) {
540       /* check if the next fragment is our target, in this case we want to
541        * start from the previous fragment */
542       GstClockTime next_pos = current_pos + file->duration;
543
544       if (next_pos <= ts && ts < next_pos + file->duration) {
545         break;
546       }
547     } else if (current_pos <= ts && ts < current_pos + file->duration) {
548       break;
549     }
550     current_pos += file->duration;
551   }
552
553   if (walk == NULL) {
554     GST_DEBUG_OBJECT (stream->pad, "seeking further than track duration");
555     current_sequence++;
556   }
557
558   GST_DEBUG_OBJECT (stream->pad, "seeking to sequence %u",
559       (guint) current_sequence);
560   hls_stream->reset_pts = TRUE;
561   hls_stream->playlist->sequence = current_sequence;
562   hls_stream->playlist->current_file = walk;
563   hls_stream->playlist->sequence_position = current_pos;
564   GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
565
566   /* Play from the end of the current selected segment */
567   if (file) {
568     if (!forward && IS_SNAP_SEEK (flags))
569       current_pos += file->duration;
570   }
571
572   /* update stream's segment position */
573   stream->segment.position = current_pos;
574
575   if (final_ts)
576     *final_ts = current_pos;
577
578   return GST_FLOW_OK;
579 }
580
581 static GstFlowReturn
582 gst_hls_demux_update_manifest (GstAdaptiveDemux * demux)
583 {
584   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
585   if (!gst_hls_demux_update_playlist (hlsdemux, TRUE, NULL))
586     return GST_FLOW_ERROR;
587
588   return GST_FLOW_OK;
589 }
590
591 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
592 static GstAdaptiveDemuxStream *
593 gst_adaptive_demux_find_stream (GstAdaptiveDemux * demux,
594     gboolean is_primary_playlist, GstHLSMediaType type)
595 {
596   GstAdaptiveDemuxStream *stream;
597   GstHLSDemuxStream *hls_stream;
598   GList *iter;
599   GstCaps *caps;
600   gchar *caps_str;
601   gboolean find_stream = FALSE;
602
603   for (iter = demux->streams; iter; iter = g_list_next (iter)) {
604     stream = iter->data;
605     if (!stream) {
606       GST_ERROR_OBJECT (demux, "no stream data");
607       continue;
608     }
609     hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
610     if (is_primary_playlist && hls_stream->is_primary_playlist)
611       return stream;
612
613     caps = gst_pad_get_current_caps (stream->pad);
614     caps_str = gst_caps_to_string (caps);
615     GST_DEBUG_OBJECT (demux, "pad %s:%s, caps %s",
616         GST_DEBUG_PAD_NAME (stream->pad), caps_str);
617
618     if (((type == GST_HLS_MEDIA_TYPE_AUDIO) && (g_strrstr (caps_str, "audio")))
619         || ((type == GST_HLS_MEDIA_TYPE_VIDEO)
620             && (g_strrstr (caps_str, "video"))))
621       find_stream = TRUE;
622
623     g_free (caps_str);
624     gst_caps_unref (caps);
625
626     if (find_stream)
627       return stream;
628   }
629
630   GST_WARNING_OBJECT (demux, "failed to find stream %d %d", is_primary_playlist,
631       type);
632   return NULL;
633 }
634
635 static void
636 create_stream_for_playlist (GstAdaptiveDemux * demux, GstM3U8 * playlist,
637     gboolean is_primary_playlist, GstHLSMediaType type)
638 {
639   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
640   GstHLSDemuxStream *hlsdemux_stream = NULL;
641   GstAdaptiveDemuxStream *stream = NULL;
642
643   if (!is_primary_playlist &&
644       type != GST_HLS_MEDIA_TYPE_AUDIO && type != GST_HLS_MEDIA_TYPE_VIDEO) {
645     /* FIXME: Later, create the stream but mark not-selected */
646     GST_LOG_OBJECT (demux, "Ignoring not-selected stream");
647     return;
648   }
649
650   GST_DEBUG_OBJECT (demux, "streams list %d", g_list_length (demux->streams));
651
652   if (demux->streams)
653     stream = gst_adaptive_demux_find_stream (demux, is_primary_playlist, type);
654
655   if (!stream) {
656     GST_LOG_OBJECT (demux, "new pad will be created");
657     stream = gst_adaptive_demux_stream_new (demux,
658         gst_hls_demux_create_pad (hlsdemux));
659   }
660
661   hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
662
663   hlsdemux_stream->stream_type = GST_HLS_TSREADER_NONE;
664
665   hlsdemux_stream->playlist = gst_m3u8_ref (playlist);
666   hlsdemux_stream->is_primary_playlist = is_primary_playlist;
667
668   hlsdemux_stream->do_typefind = TRUE;
669   hlsdemux_stream->reset_pts = TRUE;
670 }
671 #else
672 static void
673 #ifdef TIZEN_FEATURE_HLSDEMUX_LANG_TAG
674 create_stream_for_playlist (GstAdaptiveDemux * demux, GstM3U8 * playlist,
675     gboolean is_primary_playlist, gboolean selected, GstHLSMedia * media)
676 #else
677 create_stream_for_playlist (GstAdaptiveDemux * demux, GstM3U8 * playlist,
678     gboolean is_primary_playlist, gboolean selected)
679 #endif
680 {
681   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
682   GstHLSDemuxStream *hlsdemux_stream;
683   GstAdaptiveDemuxStream *stream;
684
685   if (!selected) {
686     /* FIXME: Later, create the stream but mark not-selected */
687     GST_LOG_OBJECT (demux, "Ignoring not-selected stream");
688     return;
689   }
690 #ifdef TIZEN_FEATURE_UPSTREAM
691   GST_DEBUG_OBJECT (demux,
692       "is_primary_playlist:%d selected:%d playlist name '%s'",
693       is_primary_playlist, selected, playlist->name);
694 #endif
695
696   stream = gst_adaptive_demux_stream_new (demux,
697       gst_hls_demux_create_pad (hlsdemux));
698
699   hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
700
701   hlsdemux_stream->stream_type = GST_HLS_TSREADER_NONE;
702
703   hlsdemux_stream->playlist = gst_m3u8_ref (playlist);
704   hlsdemux_stream->is_primary_playlist = is_primary_playlist;
705
706   hlsdemux_stream->do_typefind = TRUE;
707   hlsdemux_stream->reset_pts = TRUE;
708 #ifdef TIZEN_FEATURE_HLSDEMUX_DISCONT_SEQUENCE
709   hlsdemux_stream->failed_count = 0;
710 #endif
711 #ifdef TIZEN_FEATURE_HLSDEMUX_DISCONT
712   hlsdemux_stream->sequence_pos = GST_CLOCK_TIME_NONE;
713   hlsdemux_stream->last_pcr = GST_CLOCK_TIME_NONE;
714 #endif
715
716 #ifdef TIZEN_FEATURE_HLSDEMUX_LANG_TAG
717   if (media) {
718     gst_hlsdemux_set_stream_event (stream, media);
719     return;
720   }
721
722   for (GList * mlist =
723       hlsdemux->current_variant->media[GST_HLS_MEDIA_TYPE_AUDIO]; mlist;
724       mlist = g_list_next (mlist)) {
725     GstHLSMedia *media = mlist->data;
726     if (!media->uri && gst_hlsdemux_set_stream_event (stream, media))
727       return;
728   }
729 #endif
730 }
731 #endif
732
733 #ifdef TIZEN_FEATURE_UPSTREAM
734 static GstHLSDemuxStream *
735 find_adaptive_stream_for_playlist (GstAdaptiveDemux * demux, GstM3U8 * playlist)
736 {
737   GList *tmp;
738
739   GST_DEBUG_OBJECT (demux, "Looking for existing stream for '%s' %s",
740       playlist->name, playlist->uri);
741
742   for (tmp = demux->streams; tmp; tmp = tmp->next) {
743     GstHLSDemuxStream *hlsstream = (GstHLSDemuxStream *) tmp->data;
744     if (hlsstream->playlist == playlist)
745       return hlsstream;
746   }
747
748   return NULL;
749 }
750
751 /* Returns TRUE if the previous and current (to switch to) variant are compatible.
752  *
753  * That is:
754  * * They have the same number of streams
755  * * The streams are of the same type
756  */
757 static gboolean
758 new_variant_is_compatible (GstAdaptiveDemux * demux)
759 {
760   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
761   GstHLSVariantStream *previous = hlsdemux->previous_variant;
762   GstHLSVariantStream *current = hlsdemux->current_variant;
763   gint i;
764
765   GST_DEBUG_OBJECT (demux,
766       "Checking whether new variant is compatible with previous");
767
768   for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
769     GList *mlist = current->media[i];
770     if (g_list_length (previous->media[i]) != g_list_length (current->media[i])) {
771       GST_LOG_OBJECT (demux, "Number of medias for type %s don't match",
772           gst_hls_media_type_get_name (i));
773       return FALSE;
774     }
775
776     /* Check if all new media were present in previous (if not there are new ones) */
777     while (mlist != NULL) {
778       GstHLSMedia *media = mlist->data;
779       if (!gst_hls_variant_find_matching_media (previous, media)) {
780         GST_LOG_OBJECT (demux,
781             "New stream of type %s present. Variant not compatible",
782             gst_hls_media_type_get_name (i));
783         return FALSE;
784       }
785       mlist = mlist->next;
786     }
787
788     /* Check if all old media are present in current (if not some have gone) */
789     mlist = previous->media[i];
790     while (mlist != NULL) {
791       GstHLSMedia *media = mlist->data;
792       if (!gst_hls_variant_find_matching_media (current, media)) {
793         GST_LOG_OBJECT (demux,
794             "Old stream of type %s gone. Variant not compatible",
795             gst_hls_media_type_get_name (i));
796         return FALSE;
797       }
798       mlist = mlist->next;
799     }
800   }
801
802   GST_DEBUG_OBJECT (demux, "Variants are compatible");
803
804   return TRUE;
805 }
806 #endif
807 static gboolean
808 gst_hls_demux_setup_streams (GstAdaptiveDemux * demux)
809 {
810   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
811   GstHLSVariantStream *playlist = hlsdemux->current_variant;
812   gint i;
813
814   if (playlist == NULL) {
815     GST_WARNING_OBJECT (demux, "Can't configure streams - no variant selected");
816     return FALSE;
817   }
818 #ifdef TIZEN_FEATURE_UPSTREAM
819   GST_DEBUG_OBJECT (demux, "Setting up streams");
820   if (hlsdemux->streams_aware && hlsdemux->previous_variant &&
821       new_variant_is_compatible (demux)) {
822     GstHLSDemuxStream *hlsstream;
823     GST_DEBUG_OBJECT (demux, "Have a previous variant, Re-using streams");
824
825     /* Carry over the main playlist */
826     hlsstream =
827         find_adaptive_stream_for_playlist (demux,
828         hlsdemux->previous_variant->m3u8);
829     if (G_UNLIKELY (hlsstream == NULL))
830       goto no_match_error;
831
832     gst_m3u8_unref (hlsstream->playlist);
833     hlsstream->playlist = gst_m3u8_ref (playlist->m3u8);
834
835     for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
836       GList *mlist = playlist->media[i];
837       while (mlist != NULL) {
838         GstHLSMedia *media = mlist->data;
839         GstHLSMedia *old_media =
840             gst_hls_variant_find_matching_media (hlsdemux->previous_variant,
841             media);
842
843         if (G_UNLIKELY (old_media == NULL)) {
844           GST_FIXME_OBJECT (demux, "Handle new stream !");
845           goto no_match_error;
846         }
847         if (!g_strcmp0 (media->uri, old_media->uri))
848           GST_DEBUG_OBJECT (demux, "Identical stream !");
849         if (media->mtype == GST_HLS_MEDIA_TYPE_AUDIO ||
850             media->mtype == GST_HLS_MEDIA_TYPE_VIDEO ||
851             media->mtype == GST_HLS_MEDIA_TYPE_SUBTITLES) {
852           hlsstream =
853               find_adaptive_stream_for_playlist (demux, old_media->playlist);
854           if (!hlsstream)
855             goto no_match_error;
856
857           GST_DEBUG_OBJECT (demux, "Found matching stream");
858           gst_m3u8_unref (hlsstream->playlist);
859           hlsstream->playlist = gst_m3u8_ref (media->playlist);
860         } else {
861           GST_DEBUG_OBJECT (demux, "Skipping stream of type %s",
862               gst_hls_media_type_get_name (media->mtype));
863         }
864
865         mlist = mlist->next;
866       }
867     }
868
869     return TRUE;
870   }
871
872   /* FIXME : This seems wrong and assumes there's only one stream :( */
873 #endif
874   gst_hls_demux_clear_all_pending_data (hlsdemux);
875
876   /* 1 output for the main playlist */
877 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
878   create_stream_for_playlist (demux, playlist->m3u8, TRUE,
879       GST_HLS_MEDIA_TYPE_INVALID);
880 #else
881 #ifdef TIZEN_FEATURE_HLSDEMUX_LANG_TAG
882   create_stream_for_playlist (demux, playlist->m3u8, TRUE, TRUE, NULL);
883 #else
884   create_stream_for_playlist (demux, playlist->m3u8, TRUE, TRUE);
885 #endif
886 #endif
887   for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
888     GList *mlist = playlist->media[i];
889     while (mlist != NULL) {
890       GstHLSMedia *media = mlist->data;
891
892       if (media->uri == NULL /* || media->mtype != GST_HLS_MEDIA_TYPE_AUDIO */ ) {
893         /* No uri means this is a placeholder for a stream
894          * contained in another mux */
895 #ifdef TIZEN_FEATURE_UPSTREAM
896         GST_LOG_OBJECT (demux, "Skipping stream %s type %s with no URI",
897             media->name, gst_hls_media_type_get_name (media->mtype));
898 #else
899         GST_LOG_OBJECT (demux, "Skipping stream %s type %d with no URI",
900             media->name, media->mtype);
901 #endif
902         mlist = mlist->next;
903         continue;
904       }
905 #ifdef TIZEN_FEATURE_UPSTREAM
906       GST_LOG_OBJECT (demux, "media of type %s - %s, uri: %s",
907           gst_hls_media_type_get_name (i), media->name, media->uri);
908 #else
909       GST_LOG_OBJECT (demux, "media of type %d - %s, uri: %s", i,
910           media->name, media->uri);
911 #endif
912
913 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
914       create_stream_for_playlist (demux, media->playlist, FALSE, media->mtype);
915 #else
916       create_stream_for_playlist (demux, media->playlist, FALSE,
917           (media->mtype == GST_HLS_MEDIA_TYPE_VIDEO
918               || media->mtype == GST_HLS_MEDIA_TYPE_AUDIO
919 #ifdef TIZEN_FEATURE_HLSDEMUX_LANG_TAG
920               || media->mtype == GST_HLS_MEDIA_TYPE_SUBTITLES), media);
921 #else
922               || media->mtype == GST_HLS_MEDIA_TYPE_SUBTITLES));
923 #endif
924 #endif
925
926       mlist = mlist->next;
927     }
928   }
929
930   return TRUE;
931
932 #ifdef TIZEN_FEATURE_UPSTREAM
933 no_match_error:
934   {
935     /* POST ERROR MESSAGE */
936     GST_ERROR_OBJECT (demux, "Should not happen ! Could not find old stream");
937     return FALSE;
938   }
939 #endif
940 }
941
942 static const gchar *
943 gst_adaptive_demux_get_manifest_ref_uri (GstAdaptiveDemux * d)
944 {
945   return d->manifest_base_uri ? d->manifest_base_uri : d->manifest_uri;
946 }
947
948 static void
949 gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
950     GstHLSVariantStream * variant)
951 {
952   if (hlsdemux->current_variant == variant || variant == NULL)
953     return;
954
955   GST_INFO_OBJECT (hlsdemux, "%s variant %d, %d x %d", variant->name,
956       variant->bandwidth, variant->width, variant->height);
957   if (hlsdemux->current_variant != NULL) {
958     gint i;
959
960     //#warning FIXME: Synching fragments across variants
961     //  should be done based on media timestamps, and
962     //  discont-sequence-numbers not sequence numbers.
963     variant->m3u8->sequence_position =
964         hlsdemux->current_variant->m3u8->sequence_position;
965     variant->m3u8->sequence = hlsdemux->current_variant->m3u8->sequence;
966
967     GST_DEBUG_OBJECT (hlsdemux,
968         "Switching Variant. Copying over sequence %" G_GINT64_FORMAT
969         " and sequence_pos %" GST_TIME_FORMAT, variant->m3u8->sequence,
970         GST_TIME_ARGS (variant->m3u8->sequence_position));
971
972     for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
973       GList *mlist = hlsdemux->current_variant->media[i];
974
975       while (mlist != NULL) {
976         GstHLSMedia *old_media = mlist->data;
977         GstHLSMedia *new_media =
978             gst_hls_variant_find_matching_media (variant, old_media);
979
980         if (new_media) {
981 #ifdef TIZEN_FEATURE_UPSTREAM
982           GST_LOG_OBJECT (hlsdemux, "Found matching GstHLSMedia");
983           GST_LOG_OBJECT (hlsdemux, "old_media '%s' '%s'", old_media->name,
984               old_media->uri);
985           GST_LOG_OBJECT (hlsdemux, "new_media '%s' '%s'", new_media->name,
986               new_media->uri);
987 #endif
988           new_media->playlist->sequence = old_media->playlist->sequence;
989           new_media->playlist->sequence_position =
990               old_media->playlist->sequence_position;
991 #ifdef TIZEN_FEATURE_UPSTREAM
992         } else {
993           GST_LOG_OBJECT (hlsdemux,
994               "Didn't find a matching variant for '%s' '%s'", old_media->name,
995               old_media->uri);
996 #endif
997         }
998         mlist = mlist->next;
999       }
1000     }
1001 #ifdef TIZEN_FEATURE_UPSTREAM
1002     if (hlsdemux->previous_variant)
1003       gst_hls_variant_stream_unref (hlsdemux->previous_variant);
1004     /* Steal the reference */
1005     hlsdemux->previous_variant = hlsdemux->current_variant;
1006 #else
1007     gst_hls_variant_stream_unref (hlsdemux->current_variant);
1008 #endif
1009   }
1010
1011   hlsdemux->current_variant = gst_hls_variant_stream_ref (variant);
1012
1013 }
1014
1015 static gboolean
1016 gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
1017 {
1018   GstHLSVariantStream *variant;
1019   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1020   gchar *playlist = NULL;
1021
1022   GST_INFO_OBJECT (demux, "Initial playlist location: %s (base uri: %s)",
1023       demux->manifest_uri, demux->manifest_base_uri);
1024
1025   playlist = gst_hls_src_buf_to_utf8_playlist (buf);
1026   if (playlist == NULL) {
1027     GST_WARNING_OBJECT (demux, "Error validating initial playlist");
1028     return FALSE;
1029   }
1030
1031   GST_M3U8_CLIENT_LOCK (self);
1032   hlsdemux->master = gst_hls_master_playlist_new_from_data (playlist,
1033       gst_adaptive_demux_get_manifest_ref_uri (demux));
1034
1035   if (hlsdemux->master == NULL || hlsdemux->master->variants == NULL) {
1036     /* In most cases, this will happen if we set a wrong url in the
1037      * source element and we have received the 404 HTML response instead of
1038      * the playlist */
1039     GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid playlist."),
1040         ("Could not parse playlist. Check if the URL is correct."));
1041     GST_M3U8_CLIENT_UNLOCK (self);
1042     return FALSE;
1043   }
1044
1045   /* select the initial variant stream */
1046 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1047   variant =
1048       gst_hls_master_playlist_get_variant_for_bandwitdh_limit (hlsdemux->master,
1049       NULL, demux->connection_speed, demux->start_bandwidth,
1050       demux->min_bandwidth, demux->max_bandwidth, demux->max_width,
1051       demux->max_height);
1052
1053   if (!variant)
1054     variant = hlsdemux->master->default_variant;
1055
1056   if (variant) {
1057     GST_INFO_OBJECT (hlsdemux, "selected %s, %d, %d x %d",
1058         variant->name, variant->bandwidth, variant->width, variant->height);
1059     gst_hls_demux_set_current_variant (hlsdemux, variant);
1060   }
1061 #else
1062   if (demux->connection_speed == 0) {
1063     variant = hlsdemux->master->default_variant;
1064   } else {
1065     variant =
1066         gst_hls_master_playlist_get_variant_for_bitrate (hlsdemux->master,
1067         NULL, demux->connection_speed);
1068   }
1069   if (variant) {
1070     GST_INFO_OBJECT (hlsdemux, "selected %s", variant->name);
1071     gst_hls_demux_set_current_variant (hlsdemux, variant);      // FIXME: inline?
1072   }
1073 #endif
1074
1075 #ifdef TIZEN_FEATURE_AD
1076   if (variant) {
1077     GST_DEBUG_OBJECT (hlsdemux, "post AD info");
1078     gst_element_post_message (GST_ELEMENT_CAST (hlsdemux),
1079         gst_message_new_element (GST_OBJECT_CAST (hlsdemux),
1080             gst_structure_new ("adaptive-ad-info",
1081                 "ad-info", G_TYPE_POINTER, variant->m3u8->ad_info, NULL)));
1082
1083     GST_DEBUG_OBJECT (hlsdemux, "post current bandwidth info : %d",
1084         variant->bandwidth);
1085     gst_element_post_message (GST_ELEMENT_CAST (hlsdemux),
1086         gst_message_new_element (GST_OBJECT_CAST (hlsdemux),
1087             gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME,
1088                 "bitrate", G_TYPE_INT, variant->bandwidth, NULL)));
1089   }
1090 #endif
1091
1092   /* get the selected media playlist (unless the inital list was one already) */
1093   if (!hlsdemux->master->is_simple) {
1094     GError *err = NULL;
1095
1096     if (!gst_hls_demux_update_playlist (hlsdemux, FALSE, &err)) {
1097       GST_ELEMENT_ERROR_FROM_ERROR (demux, "Could not fetch media playlist",
1098           err);
1099       GST_M3U8_CLIENT_UNLOCK (self);
1100       return FALSE;
1101     }
1102   }
1103   GST_M3U8_CLIENT_UNLOCK (self);
1104
1105   return gst_hls_demux_setup_streams (demux);
1106 }
1107
1108 static GstClockTime
1109 gst_hls_demux_get_duration (GstAdaptiveDemux * demux)
1110 {
1111   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1112   GstClockTime duration = GST_CLOCK_TIME_NONE;
1113
1114   if (hlsdemux->current_variant != NULL)
1115     duration = gst_m3u8_get_duration (hlsdemux->current_variant->m3u8);
1116
1117   return duration;
1118 }
1119
1120 static gboolean
1121 gst_hls_demux_is_live (GstAdaptiveDemux * demux)
1122 {
1123   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1124   gboolean is_live = FALSE;
1125
1126   if (hlsdemux->current_variant)
1127     is_live = gst_hls_variant_stream_is_live (hlsdemux->current_variant);
1128
1129   return is_live;
1130 }
1131
1132 static const GstHLSKey *
1133 gst_hls_demux_get_key (GstHLSDemux * demux, const gchar * key_url,
1134     const gchar * referer, gboolean allow_cache)
1135 {
1136   GstFragment *key_fragment;
1137   GstBuffer *key_buffer;
1138   GstHLSKey *key;
1139   GError *err = NULL;
1140
1141   GST_LOG_OBJECT (demux, "Looking up key for key url %s", key_url);
1142
1143   g_mutex_lock (&demux->keys_lock);
1144
1145   key = g_hash_table_lookup (demux->keys, key_url);
1146
1147   if (key != NULL) {
1148     GST_LOG_OBJECT (demux, "Found key for key url %s in key cache", key_url);
1149     goto out;
1150   }
1151
1152   GST_INFO_OBJECT (demux, "Fetching key %s", key_url);
1153 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1154   key_fragment =
1155       gst_uri_downloader_fetch_uri (GST_ADAPTIVE_DEMUX (demux)->downloader,
1156       key_url, referer, GST_ADAPTIVE_DEMUX (demux)->user_agent,
1157       GST_ADAPTIVE_DEMUX (demux)->cookies, DEFAULT_ADAPTIVE_RETRY,
1158       DEFAULT_ADAPTIVE_TIMEOUT, FALSE, FALSE, allow_cache, &err);
1159 #else
1160   key_fragment =
1161       gst_uri_downloader_fetch_uri (GST_ADAPTIVE_DEMUX (demux)->downloader,
1162       key_url, referer, FALSE, FALSE, allow_cache, &err);
1163 #endif
1164
1165   if (key_fragment == NULL) {
1166     GST_WARNING_OBJECT (demux, "Failed to download key to decrypt data: %s",
1167         err ? err->message : "error");
1168     g_clear_error (&err);
1169     goto out;
1170   }
1171
1172   key_buffer = gst_fragment_get_buffer (key_fragment);
1173
1174   key = g_new0 (GstHLSKey, 1);
1175   if (gst_buffer_extract (key_buffer, 0, key->data, 16) < 16)
1176     GST_WARNING_OBJECT (demux, "Download decryption key is too short!");
1177
1178   g_hash_table_insert (demux->keys, g_strdup (key_url), key);
1179
1180   gst_buffer_unref (key_buffer);
1181   g_object_unref (key_fragment);
1182
1183 out:
1184
1185   g_mutex_unlock (&demux->keys_lock);
1186
1187   if (key != NULL)
1188     GST_MEMDUMP_OBJECT (demux, "Key", key->data, 16);
1189
1190   return key;
1191 }
1192
1193 static gboolean
1194 gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
1195     GstAdaptiveDemuxStream * stream)
1196 {
1197   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1198   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1199   const GstHLSKey *key;
1200   GstM3U8 *m3u8;
1201
1202   gst_hls_demux_stream_clear_pending_data (hls_stream);
1203
1204   /* Init the timestamp reader for this fragment */
1205   gst_hlsdemux_tsreader_init (&hls_stream->tsreader);
1206   /* Reset the stream type if we already know it */
1207   gst_hlsdemux_tsreader_set_type (&hls_stream->tsreader,
1208       hls_stream->stream_type);
1209
1210   /* If no decryption is needed, there's nothing to be done here */
1211   if (hls_stream->current_key == NULL)
1212     return TRUE;
1213
1214   m3u8 = gst_hls_demux_stream_get_m3u8 (hls_stream);
1215
1216   key = gst_hls_demux_get_key (hlsdemux, hls_stream->current_key,
1217       m3u8->uri, m3u8->allowcache);
1218
1219   if (key == NULL)
1220     goto key_failed;
1221
1222   gst_hls_demux_stream_decrypt_start (hls_stream, key->data,
1223       hls_stream->current_iv);
1224
1225   return TRUE;
1226
1227 key_failed:
1228   {
1229     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
1230         ("Couldn't retrieve key for decryption"), (NULL));
1231     GST_WARNING_OBJECT (demux, "Failed to decrypt data");
1232     return FALSE;
1233   }
1234 }
1235
1236 static GstHLSTSReaderType
1237 caps_to_reader (const GstCaps * caps)
1238 {
1239   const GstStructure *s = gst_caps_get_structure (caps, 0);
1240
1241   if (gst_structure_has_name (s, "video/mpegts"))
1242     return GST_HLS_TSREADER_MPEGTS;
1243   if (gst_structure_has_name (s, "application/x-id3"))
1244     return GST_HLS_TSREADER_ID3;
1245
1246   return GST_HLS_TSREADER_NONE;
1247 }
1248
1249 static GstFlowReturn
1250 gst_hls_demux_handle_buffer (GstAdaptiveDemux * demux,
1251     GstAdaptiveDemuxStream * stream, GstBuffer * buffer, gboolean at_eos)
1252 {
1253   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
1254   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1255   GstClockTime first_pcr, last_pcr;
1256   GstTagList *tags;
1257
1258   if (buffer == NULL)
1259     return GST_FLOW_OK;
1260
1261   if (G_UNLIKELY (hls_stream->do_typefind)) {
1262     GstCaps *caps = NULL;
1263     guint buffer_size;
1264     GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1265     GstMapInfo info;
1266
1267     if (hls_stream->pending_typefind_buffer)
1268       buffer = gst_buffer_append (hls_stream->pending_typefind_buffer, buffer);
1269     hls_stream->pending_typefind_buffer = NULL;
1270
1271     gst_buffer_map (buffer, &info, GST_MAP_READ);
1272     buffer_size = info.size;
1273
1274     /* Typefind could miss if buffer is too small. In this case we
1275      * will retry later */
1276     if (buffer_size >= (2 * 1024) || at_eos) {
1277       caps =
1278           gst_type_find_helper_for_data (GST_OBJECT_CAST (hlsdemux), info.data,
1279           info.size, &prob);
1280     }
1281
1282     if (G_UNLIKELY (!caps)) {
1283 #ifdef TIZEN_FEATURE_HLSDEMUX_EMPTY_VTT
1284       if (at_eos && info.data
1285           && g_strrstr ((const gchar *) info.data, "WEBVTT")) {
1286         gchar *dummy =
1287             g_strdup ("WEBVTT\nX-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:0");
1288         GstBuffer *dummy_buffer =
1289             gst_buffer_new_wrapped (dummy, strlen (dummy));
1290
1291         gst_buffer_unmap (buffer, &info);
1292         gst_buffer_unref (buffer);
1293
1294         GST_WARNING_OBJECT (stream->pad,
1295             "replace the empty VTT buffer with dummy");
1296
1297         buffer = dummy_buffer;
1298         gst_buffer_map (buffer, &info, GST_MAP_READ);
1299
1300         caps = gst_caps_new_simple ("application/x-subtitle-vtt",
1301             "parsed", G_TYPE_BOOLEAN, FALSE, NULL);
1302       } else
1303 #endif
1304       {
1305         /* Won't need this mapping any more all paths return inside this if() */
1306         gst_buffer_unmap (buffer, &info);
1307
1308         /* Only fail typefinding if we already a good amount of data
1309          * and we still don't know the type */
1310         if (buffer_size > (2 * 1024 * 1024) || at_eos) {
1311           GST_ELEMENT_ERROR (hlsdemux, STREAM, TYPE_NOT_FOUND,
1312               ("Could not determine type of stream"), (NULL));
1313           gst_buffer_unref (buffer);
1314           return GST_FLOW_NOT_NEGOTIATED;
1315         }
1316
1317         hls_stream->pending_typefind_buffer = buffer;
1318         return GST_FLOW_OK;
1319       }
1320     }
1321 #ifdef TIZEN_FEATURE_UPSTREAM
1322     GST_DEBUG_OBJECT (stream->pad,
1323         "Typefind result: %" GST_PTR_FORMAT " prob:%d", caps, prob);
1324 #else
1325     GST_DEBUG_OBJECT (hlsdemux, "Typefind result: %" GST_PTR_FORMAT " prob:%d",
1326         caps, prob);
1327 #endif
1328
1329     hls_stream->stream_type = caps_to_reader (caps);
1330     gst_hlsdemux_tsreader_set_type (&hls_stream->tsreader,
1331         hls_stream->stream_type);
1332
1333 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
1334     gst_adaptive_demux_stream_check_switch_pad (stream, caps,
1335         gst_hls_demux_stream_create_pad);
1336     GST_DEBUG_OBJECT (stream->pad, "Overwriting PTS to %" GST_TIME_FORMAT,
1337         GST_TIME_ARGS (hls_stream->current_pts));
1338     stream->fragment.timestamp = hls_stream->current_pts;
1339 #else
1340     gst_adaptive_demux_stream_set_caps (stream, caps);
1341 #endif
1342     hls_stream->do_typefind = FALSE;
1343
1344     gst_buffer_unmap (buffer, &info);
1345   }
1346   g_assert (hls_stream->pending_typefind_buffer == NULL);
1347
1348   // Accumulate this buffer
1349   if (hls_stream->pending_pcr_buffer) {
1350     buffer = gst_buffer_append (hls_stream->pending_pcr_buffer, buffer);
1351     hls_stream->pending_pcr_buffer = NULL;
1352   }
1353
1354   if (!gst_hlsdemux_tsreader_find_pcrs (&hls_stream->tsreader, &buffer,
1355           &first_pcr, &last_pcr, &tags)
1356       && !at_eos) {
1357     // Store this buffer for later
1358     hls_stream->pending_pcr_buffer = buffer;
1359     return GST_FLOW_OK;
1360   }
1361 #ifdef TIZEN_FEATURE_HLSDEMUX_DISCONT
1362   if (stream->first_fragment_buffer && !stream->discont
1363       && GST_CLOCK_TIME_IS_VALID (hls_stream->last_pcr)
1364       && GST_CLOCK_TIME_IS_VALID (last_pcr)) {
1365     if (G_UNLIKELY (ABSDIFF (hls_stream->last_pcr, last_pcr) > 1 * GST_SECOND)
1366         && (stream->fragment.timestamp != hls_stream->sequence_pos)) {
1367       GST_DEBUG_OBJECT (stream->pad,
1368           "Overwriting fragment timestamp [%" GST_TIME_FORMAT "] to [%"
1369           GST_TIME_FORMAT "]", GST_TIME_ARGS (stream->fragment.timestamp),
1370           GST_TIME_ARGS (hls_stream->sequence_pos));
1371       stream->fragment.timestamp = hls_stream->sequence_pos;
1372       stream->discont = TRUE;
1373     }
1374   }
1375
1376   if (GST_CLOCK_TIME_IS_VALID (last_pcr))
1377     hls_stream->last_pcr = last_pcr;
1378 #endif
1379
1380   if (tags) {
1381 #ifdef TIZEN_FEATURE_HLSDEMUX_LANG_TAG
1382     if (stream->pending_tags)
1383       gst_tag_list_insert (tags, stream->pending_tags, GST_TAG_MERGE_APPEND);
1384 #endif
1385     gst_adaptive_demux_stream_set_tags (stream, tags);
1386     /* run typefind again on the trimmed buffer */
1387     hls_stream->do_typefind = TRUE;
1388     return gst_hls_demux_handle_buffer (demux, stream, buffer, at_eos);
1389   }
1390
1391   if (buffer) {
1392     buffer = gst_buffer_make_writable (buffer);
1393     GST_BUFFER_OFFSET (buffer) = hls_stream->current_offset;
1394     hls_stream->current_offset += gst_buffer_get_size (buffer);
1395     GST_BUFFER_OFFSET_END (buffer) = hls_stream->current_offset;
1396     return gst_adaptive_demux_stream_push_buffer (stream, buffer);
1397   }
1398   return GST_FLOW_OK;
1399 }
1400
1401 static GstFlowReturn
1402 gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
1403     GstAdaptiveDemuxStream * stream)
1404 {
1405   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
1406   GstFlowReturn ret = GST_FLOW_OK;
1407
1408   if (hls_stream->current_key)
1409     gst_hls_demux_stream_decrypt_end (hls_stream);
1410
1411 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
1412   gst_adaptive_demux_push_fragment_finished_event (demux, stream);
1413 #endif
1414   if (stream->last_ret == GST_FLOW_OK) {
1415     if (hls_stream->pending_decrypted_buffer) {
1416       if (hls_stream->current_key) {
1417         GstMapInfo info;
1418         gssize unpadded_size;
1419
1420         /* Handle pkcs7 unpadding here */
1421         gst_buffer_map (hls_stream->pending_decrypted_buffer, &info,
1422             GST_MAP_READ);
1423         unpadded_size = info.size - info.data[info.size - 1];
1424         gst_buffer_unmap (hls_stream->pending_decrypted_buffer, &info);
1425
1426         gst_buffer_resize (hls_stream->pending_decrypted_buffer, 0,
1427             unpadded_size);
1428       }
1429
1430       ret =
1431           gst_hls_demux_handle_buffer (demux, stream,
1432           hls_stream->pending_decrypted_buffer, TRUE);
1433       hls_stream->pending_decrypted_buffer = NULL;
1434     }
1435
1436     if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED) {
1437       if (G_UNLIKELY (hls_stream->pending_typefind_buffer)) {
1438         GstBuffer *buf = hls_stream->pending_typefind_buffer;
1439         hls_stream->pending_typefind_buffer = NULL;
1440
1441         gst_hls_demux_handle_buffer (demux, stream, buf, TRUE);
1442       }
1443
1444       if (hls_stream->pending_pcr_buffer) {
1445         GstBuffer *buf = hls_stream->pending_pcr_buffer;
1446         hls_stream->pending_pcr_buffer = NULL;
1447
1448         ret = gst_hls_demux_handle_buffer (demux, stream, buf, TRUE);
1449       }
1450
1451       GST_LOG_OBJECT (stream,
1452           "Fragment PCRs were %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1453           GST_TIME_ARGS (hls_stream->tsreader.first_pcr),
1454           GST_TIME_ARGS (hls_stream->tsreader.last_pcr));
1455     }
1456   }
1457
1458   gst_hls_demux_stream_clear_pending_data (hls_stream);
1459
1460   if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED)
1461     return gst_adaptive_demux_stream_advance_fragment (demux, stream,
1462         stream->fragment.duration);
1463   return ret;
1464 }
1465
1466 static GstFlowReturn
1467 gst_hls_demux_data_received (GstAdaptiveDemux * demux,
1468     GstAdaptiveDemuxStream * stream, GstBuffer * buffer)
1469 {
1470   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1471   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
1472
1473   if (hls_stream->current_offset == -1)
1474     hls_stream->current_offset = 0;
1475
1476   /* Is it encrypted? */
1477   if (hls_stream->current_key) {
1478     GError *err = NULL;
1479     gsize size;
1480     GstBuffer *tmp_buffer;
1481
1482     if (hls_stream->pending_encrypted_data == NULL)
1483       hls_stream->pending_encrypted_data = gst_adapter_new ();
1484
1485     gst_adapter_push (hls_stream->pending_encrypted_data, buffer);
1486     size = gst_adapter_available (hls_stream->pending_encrypted_data);
1487
1488     /* must be a multiple of 16 */
1489     size &= (~0xF);
1490
1491     if (size == 0) {
1492       return GST_FLOW_OK;
1493     }
1494
1495     buffer = gst_adapter_take_buffer (hls_stream->pending_encrypted_data, size);
1496     buffer =
1497         gst_hls_demux_decrypt_fragment (hlsdemux, hls_stream, buffer, &err);
1498     if (buffer == NULL) {
1499       GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Failed to decrypt buffer"),
1500           ("decryption failed %s", err->message));
1501       g_error_free (err);
1502       return GST_FLOW_ERROR;
1503     }
1504
1505     tmp_buffer = hls_stream->pending_decrypted_buffer;
1506     hls_stream->pending_decrypted_buffer = buffer;
1507     buffer = tmp_buffer;
1508   }
1509
1510   return gst_hls_demux_handle_buffer (demux, stream, buffer, FALSE);
1511 }
1512
1513 static void
1514 gst_hls_demux_stream_free (GstAdaptiveDemuxStream * stream)
1515 {
1516   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1517
1518   if (hls_stream->playlist) {
1519     gst_m3u8_unref (hls_stream->playlist);
1520     hls_stream->playlist = NULL;
1521   }
1522
1523   if (hls_stream->pending_encrypted_data)
1524     g_object_unref (hls_stream->pending_encrypted_data);
1525
1526   gst_buffer_replace (&hls_stream->pending_decrypted_buffer, NULL);
1527   gst_buffer_replace (&hls_stream->pending_typefind_buffer, NULL);
1528   gst_buffer_replace (&hls_stream->pending_pcr_buffer, NULL);
1529
1530   if (hls_stream->current_key) {
1531     g_free (hls_stream->current_key);
1532     hls_stream->current_key = NULL;
1533   }
1534   if (hls_stream->current_iv) {
1535     g_free (hls_stream->current_iv);
1536     hls_stream->current_iv = NULL;
1537   }
1538   gst_hls_demux_stream_decrypt_end (hls_stream);
1539 }
1540
1541 static GstM3U8 *
1542 gst_hls_demux_stream_get_m3u8 (GstHLSDemuxStream * hlsdemux_stream)
1543 {
1544   GstM3U8 *m3u8;
1545
1546   m3u8 = hlsdemux_stream->playlist;
1547
1548   return m3u8;
1549 }
1550
1551 static gboolean
1552 gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemuxStream * stream)
1553 {
1554   gboolean has_next;
1555   GstM3U8 *m3u8;
1556
1557   m3u8 = gst_hls_demux_stream_get_m3u8 (GST_HLS_DEMUX_STREAM_CAST (stream));
1558
1559   has_next = gst_m3u8_has_next_fragment (m3u8, stream->demux->segment.rate > 0);
1560
1561   return has_next;
1562 }
1563
1564 static GstFlowReturn
1565 gst_hls_demux_advance_fragment (GstAdaptiveDemuxStream * stream)
1566 {
1567   GstHLSDemuxStream *hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1568   GstM3U8 *m3u8;
1569
1570   m3u8 = gst_hls_demux_stream_get_m3u8 (hlsdemux_stream);
1571
1572   gst_m3u8_advance_fragment (m3u8, stream->demux->segment.rate > 0);
1573   hlsdemux_stream->reset_pts = FALSE;
1574
1575   return GST_FLOW_OK;
1576 }
1577
1578 static GstFlowReturn
1579 gst_hls_demux_update_fragment_info (GstAdaptiveDemuxStream * stream)
1580 {
1581   GstHLSDemuxStream *hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1582   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
1583   GstM3U8MediaFile *file;
1584   GstClockTime sequence_pos;
1585   gboolean discont, forward;
1586   GstM3U8 *m3u8;
1587
1588   m3u8 = gst_hls_demux_stream_get_m3u8 (hlsdemux_stream);
1589
1590   forward = (stream->demux->segment.rate > 0);
1591   file = gst_m3u8_get_next_fragment (m3u8, forward, &sequence_pos, &discont);
1592
1593   if (file == NULL) {
1594     GST_INFO_OBJECT (hlsdemux, "This playlist doesn't contain more fragments");
1595 #ifdef TIZEN_FEATURE_HLSDEMUX_DISCONT_SEQUENCE
1596     if (++hlsdemux_stream->failed_count > DEFAULT_FAILED_COUNT) {
1597       GST_WARNING_OBJECT (hlsdemux,
1598           "Reset media sequence(fail %d times to gst_m3u8_get_next_fragment)",
1599           hlsdemux_stream->failed_count);
1600       m3u8->sequence = 0;
1601     }
1602 #endif
1603     return GST_FLOW_EOS;
1604   }
1605 #ifdef TIZEN_FEATURE_HLSDEMUX_DISCONT_SEQUENCE
1606   hlsdemux_stream->failed_count = 0;
1607 #endif
1608
1609   if (stream->discont)
1610     discont = TRUE;
1611
1612 #ifdef TIZEN_FEATURE_HLSDEMUX_DISCONT
1613   hlsdemux_stream->sequence_pos = sequence_pos;
1614 #endif
1615   /* set up our source for download */
1616 #ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
1617   stream->fragment.timestamp = hlsdemux_stream->current_pts = sequence_pos;
1618 #else
1619   if (hlsdemux_stream->reset_pts || discont
1620       || stream->demux->segment.rate < 0.0) {
1621     stream->fragment.timestamp = sequence_pos;
1622   } else {
1623     stream->fragment.timestamp = GST_CLOCK_TIME_NONE;
1624   }
1625 #endif
1626
1627   g_free (hlsdemux_stream->current_key);
1628   hlsdemux_stream->current_key = g_strdup (file->key);
1629   g_free (hlsdemux_stream->current_iv);
1630   hlsdemux_stream->current_iv = g_memdup (file->iv, sizeof (file->iv));
1631
1632   g_free (stream->fragment.uri);
1633   stream->fragment.uri = g_strdup (file->uri);
1634
1635   GST_DEBUG_OBJECT (hlsdemux, "Stream %p URI now %s", stream, file->uri);
1636
1637   stream->fragment.range_start = file->offset;
1638   if (file->size != -1)
1639     stream->fragment.range_end = file->offset + file->size - 1;
1640   else
1641     stream->fragment.range_end = -1;
1642
1643   stream->fragment.duration = file->duration;
1644
1645   if (discont)
1646     stream->discont = TRUE;
1647
1648   gst_m3u8_media_file_unref (file);
1649
1650   return GST_FLOW_OK;
1651 }
1652
1653 static gboolean
1654 gst_hls_demux_select_bitrate (GstAdaptiveDemuxStream * stream, guint64 bitrate)
1655 {
1656   GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (stream->demux);
1657   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
1658   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
1659
1660   gboolean changed = FALSE;
1661
1662   GST_M3U8_CLIENT_LOCK (hlsdemux->client);
1663   if (hlsdemux->master == NULL || hlsdemux->master->is_simple) {
1664     GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
1665     return FALSE;
1666   }
1667   GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
1668
1669   if (hls_stream->is_primary_playlist == FALSE) {
1670     GST_LOG_OBJECT (hlsdemux,
1671         "Stream %p Not choosing new bitrate - not the primary stream", stream);
1672     return FALSE;
1673   }
1674
1675   gst_hls_demux_change_playlist (hlsdemux, bitrate / MAX (1.0,
1676           ABS (demux->segment.rate)), &changed);
1677   if (changed)
1678     gst_hls_demux_setup_streams (GST_ADAPTIVE_DEMUX_CAST (hlsdemux));
1679   return changed;
1680 }
1681
1682 static void
1683 gst_hls_demux_reset (GstAdaptiveDemux * ademux)
1684 {
1685   GstHLSDemux *demux = GST_HLS_DEMUX_CAST (ademux);
1686
1687   GST_DEBUG_OBJECT (demux, "resetting");
1688
1689   GST_M3U8_CLIENT_LOCK (hlsdemux->client);
1690   if (demux->master) {
1691     gst_hls_master_playlist_unref (demux->master);
1692     demux->master = NULL;
1693   }
1694   if (demux->current_variant != NULL) {
1695     gst_hls_variant_stream_unref (demux->current_variant);
1696     demux->current_variant = NULL;
1697   }
1698 #ifdef TIZEN_FEATURE_UPSTREAM
1699   if (demux->previous_variant != NULL) {
1700     gst_hls_variant_stream_unref (demux->previous_variant);
1701     demux->previous_variant = NULL;
1702   }
1703 #endif
1704   demux->srcpad_counter = 0;
1705 #ifdef TIZEN_FEATURE_UPSTREAM
1706   demux->streams_aware = GST_OBJECT_PARENT (demux)
1707       && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (demux),
1708       GST_BIN_FLAG_STREAMS_AWARE);
1709   GST_DEBUG_OBJECT (demux, "Streams aware : %d", demux->streams_aware);
1710 #endif
1711
1712   gst_hls_demux_clear_all_pending_data (demux);
1713   GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
1714 }
1715
1716 static gchar *
1717 gst_hls_src_buf_to_utf8_playlist (GstBuffer * buf)
1718 {
1719   GstMapInfo info;
1720   gchar *playlist;
1721
1722   if (!gst_buffer_map (buf, &info, GST_MAP_READ))
1723     goto map_error;
1724
1725   if (!g_utf8_validate ((gchar *) info.data, info.size, NULL))
1726     goto validate_error;
1727
1728   /* alloc size + 1 to end with a null character */
1729   playlist = g_malloc0 (info.size + 1);
1730   memcpy (playlist, info.data, info.size);
1731
1732   gst_buffer_unmap (buf, &info);
1733   return playlist;
1734
1735 validate_error:
1736   gst_buffer_unmap (buf, &info);
1737 map_error:
1738   return NULL;
1739 }
1740
1741 static gint
1742 gst_hls_demux_find_variant_match (const GstHLSVariantStream * a,
1743     const GstHLSVariantStream * b)
1744 {
1745   if (g_strcmp0 (a->name, b->name) == 0 &&
1746       a->bandwidth == b->bandwidth &&
1747       a->program_id == b->program_id &&
1748       g_strcmp0 (a->codecs, b->codecs) == 0 &&
1749       a->width == b->width &&
1750       a->height == b->height && a->iframe == b->iframe) {
1751     return 0;
1752   }
1753
1754   return 1;
1755 }
1756
1757 /* Update the master playlist, which contains the list of available
1758  * variants */
1759 static gboolean
1760 gst_hls_demux_update_variant_playlist (GstHLSDemux * hlsdemux, gchar * data,
1761     const gchar * uri, const gchar * base_uri)
1762 {
1763   GstHLSMasterPlaylist *new_master, *old;
1764   gboolean ret = FALSE;
1765   GList *l, *unmatched_lists;
1766   GstHLSVariantStream *new_variant;
1767
1768   new_master = gst_hls_master_playlist_new_from_data (data, base_uri ? base_uri : uri); // FIXME: check which uri to use here
1769
1770   if (new_master == NULL)
1771     return ret;
1772
1773   if (new_master->is_simple) {
1774     // FIXME: we should be able to support this though, in the unlikely
1775     // case that it changed?
1776     GST_ERROR
1777         ("Cannot update variant playlist: New playlist is not a variant playlist");
1778     gst_hls_master_playlist_unref (new_master);
1779     return FALSE;
1780   }
1781
1782   GST_M3U8_CLIENT_LOCK (self);
1783
1784   if (hlsdemux->master->is_simple) {
1785     GST_ERROR
1786         ("Cannot update variant playlist: Current playlist is not a variant playlist");
1787     gst_hls_master_playlist_unref (new_master);
1788     goto out;
1789   }
1790
1791   /* Now see if the variant playlist still has the same lists */
1792   unmatched_lists = g_list_copy (hlsdemux->master->variants);
1793   for (l = new_master->variants; l != NULL; l = l->next) {
1794     GList *match = g_list_find_custom (unmatched_lists, l->data,
1795         (GCompareFunc) gst_hls_demux_find_variant_match);
1796
1797     if (match) {
1798       GstHLSVariantStream *variant = l->data;
1799       GstHLSVariantStream *old = match->data;
1800
1801       unmatched_lists = g_list_delete_link (unmatched_lists, match);
1802       /* FIXME: Deal with losing position due to missing an update */
1803       variant->m3u8->sequence_position = old->m3u8->sequence_position;
1804       variant->m3u8->sequence = old->m3u8->sequence;
1805     }
1806   }
1807
1808   if (unmatched_lists != NULL) {
1809     GST_WARNING ("Unable to match all playlists");
1810
1811     for (l = unmatched_lists; l != NULL; l = l->next) {
1812       if (l->data == hlsdemux->current_variant) {
1813         GST_WARNING ("Unable to match current playlist");
1814       }
1815     }
1816
1817     g_list_free (unmatched_lists);
1818   }
1819
1820   /* Switch out the variant playlist */
1821   old = hlsdemux->master;
1822
1823   // FIXME: check all this and also switch of variants, if anything needs updating
1824   hlsdemux->master = new_master;
1825
1826   if (hlsdemux->current_variant == NULL) {
1827     new_variant = new_master->default_variant;
1828   } else {
1829     /* Find the same variant in the new playlist */
1830     new_variant =
1831         gst_hls_master_playlist_get_matching_variant (new_master,
1832         hlsdemux->current_variant);
1833   }
1834
1835   /* Use the function to set the current variant, as it copies over data */
1836   if (new_variant != NULL)
1837     gst_hls_demux_set_current_variant (hlsdemux, new_variant);
1838
1839   gst_hls_master_playlist_unref (old);
1840
1841   ret = (hlsdemux->current_variant != NULL);
1842 out:
1843   GST_M3U8_CLIENT_UNLOCK (self);
1844
1845   return ret;
1846 }
1847
1848 static gboolean
1849 gst_hls_demux_update_rendition_manifest (GstHLSDemux * demux,
1850     GstHLSMedia * media, GError ** err)
1851 {
1852   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX (demux);
1853   GstFragment *download;
1854   GstBuffer *buf;
1855   gchar *playlist;
1856   const gchar *main_uri;
1857   GstM3U8 *m3u8;
1858   gchar *uri = media->uri;
1859
1860   main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
1861 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1862   download =
1863       gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
1864       adaptive_demux->user_agent, adaptive_demux->cookies,
1865       DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT, TRUE, TRUE, TRUE, err);
1866 #else
1867   download =
1868       gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
1869       TRUE, TRUE, TRUE, err);
1870 #endif
1871   if (download == NULL)
1872     return FALSE;
1873
1874   m3u8 = media->playlist;
1875
1876   /* Set the base URI of the playlist to the redirect target if any */
1877   if (download->redirect_permanent && download->redirect_uri) {
1878     gst_m3u8_set_uri (m3u8, download->redirect_uri, NULL, media->name);
1879   } else {
1880     gst_m3u8_set_uri (m3u8, download->uri, download->redirect_uri, media->name);
1881   }
1882
1883   buf = gst_fragment_get_buffer (download);
1884   playlist = gst_hls_src_buf_to_utf8_playlist (buf);
1885   gst_buffer_unref (buf);
1886   g_object_unref (download);
1887
1888   if (playlist == NULL) {
1889     GST_WARNING_OBJECT (demux, "Couldn't validate playlist encoding");
1890     g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
1891         "Couldn't validate playlist encoding");
1892     return FALSE;
1893   }
1894
1895   if (!gst_m3u8_update (m3u8, playlist)) {
1896     GST_WARNING_OBJECT (demux, "Couldn't update playlist");
1897     g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
1898         "Couldn't update playlist");
1899     return FALSE;
1900   }
1901
1902   return TRUE;
1903 }
1904
1905 static gboolean
1906 gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
1907     GError ** err)
1908 {
1909   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX (demux);
1910   GstFragment *download;
1911   GstBuffer *buf;
1912   gchar *playlist;
1913   gboolean main_checked = FALSE;
1914   const gchar *main_uri;
1915   GstM3U8 *m3u8;
1916   gchar *uri;
1917   gint i;
1918
1919 retry:
1920   uri = gst_m3u8_get_uri (demux->current_variant->m3u8);
1921   main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
1922 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1923   download =
1924       gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
1925       adaptive_demux->user_agent, adaptive_demux->cookies,
1926       DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT, TRUE, TRUE, TRUE, err);
1927 #else
1928   download =
1929       gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
1930       TRUE, TRUE, TRUE, err);
1931 #endif
1932   if (download == NULL) {
1933     gchar *base_uri;
1934
1935     if (!update || main_checked || demux->master->is_simple
1936         || !gst_adaptive_demux_is_running (GST_ADAPTIVE_DEMUX_CAST (demux))) {
1937       g_free (uri);
1938       return FALSE;
1939     }
1940     g_clear_error (err);
1941     GST_INFO_OBJECT (demux,
1942         "Updating playlist %s failed, attempt to refresh variant playlist %s",
1943         uri, main_uri);
1944 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
1945     download =
1946         gst_uri_downloader_fetch_uri (adaptive_demux->downloader, main_uri,
1947         NULL, adaptive_demux->user_agent, adaptive_demux->cookies,
1948         DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT, TRUE, TRUE, TRUE,
1949         err);
1950 #else
1951     download =
1952         gst_uri_downloader_fetch_uri (adaptive_demux->downloader,
1953         main_uri, NULL, TRUE, TRUE, TRUE, err);
1954 #endif
1955     if (download == NULL) {
1956       g_free (uri);
1957       return FALSE;
1958     }
1959
1960     buf = gst_fragment_get_buffer (download);
1961     playlist = gst_hls_src_buf_to_utf8_playlist (buf);
1962     gst_buffer_unref (buf);
1963
1964     if (playlist == NULL) {
1965       GST_WARNING_OBJECT (demux,
1966           "Failed to validate variant playlist encoding");
1967       g_free (uri);
1968       g_object_unref (download);
1969       g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
1970           "Couldn't validate playlist encoding");
1971       return FALSE;
1972     }
1973
1974     g_free (uri);
1975     if (download->redirect_permanent && download->redirect_uri) {
1976       uri = download->redirect_uri;
1977       base_uri = NULL;
1978     } else {
1979       uri = download->uri;
1980       base_uri = download->redirect_uri;
1981     }
1982
1983     if (!gst_hls_demux_update_variant_playlist (demux, playlist, uri, base_uri)) {
1984       GST_WARNING_OBJECT (demux, "Failed to update the variant playlist");
1985       g_object_unref (download);
1986       g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
1987           "Couldn't update playlist");
1988       return FALSE;
1989     }
1990
1991     g_object_unref (download);
1992
1993     main_checked = TRUE;
1994     goto retry;
1995   }
1996   g_free (uri);
1997
1998   m3u8 = demux->current_variant->m3u8;
1999
2000   /* Set the base URI of the playlist to the redirect target if any */
2001   if (download->redirect_permanent && download->redirect_uri) {
2002     gst_m3u8_set_uri (m3u8, download->redirect_uri, NULL,
2003         demux->current_variant->name);
2004   } else {
2005     gst_m3u8_set_uri (m3u8, download->uri, download->redirect_uri,
2006         demux->current_variant->name);
2007   }
2008
2009   buf = gst_fragment_get_buffer (download);
2010   playlist = gst_hls_src_buf_to_utf8_playlist (buf);
2011   gst_buffer_unref (buf);
2012   g_object_unref (download);
2013
2014   if (playlist == NULL) {
2015     GST_WARNING_OBJECT (demux, "Couldn't validate playlist encoding");
2016     g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
2017         "Couldn't validate playlist encoding");
2018     return FALSE;
2019   }
2020
2021   if (!gst_m3u8_update (m3u8, playlist)) {
2022     GST_WARNING_OBJECT (demux, "Couldn't update playlist");
2023     g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
2024         "Couldn't update playlist");
2025     return FALSE;
2026   }
2027
2028   for (i = 0; i < GST_HLS_N_MEDIA_TYPES; ++i) {
2029     GList *mlist = demux->current_variant->media[i];
2030
2031     while (mlist != NULL) {
2032       GstHLSMedia *media = mlist->data;
2033
2034       if (media->uri == NULL) {
2035         /* No uri means this is a placeholder for a stream
2036          * contained in another mux */
2037         mlist = mlist->next;
2038         continue;
2039       }
2040       GST_LOG_OBJECT (demux,
2041           "Updating playlist for media of type %d - %s, uri: %s", i,
2042           media->name, media->uri);
2043
2044       if (!gst_hls_demux_update_rendition_manifest (demux, media, err))
2045         return FALSE;
2046
2047       mlist = mlist->next;
2048     }
2049   }
2050
2051   /* If it's a live source, do not let the sequence number go beyond
2052    * three fragments before the end of the list */
2053   if (update == FALSE && gst_m3u8_is_live (m3u8)) {
2054     gint64 last_sequence, first_sequence;
2055
2056     GST_M3U8_CLIENT_LOCK (demux->client);
2057     last_sequence =
2058         GST_M3U8_MEDIA_FILE (g_list_last (m3u8->files)->data)->sequence;
2059     first_sequence =
2060         GST_M3U8_MEDIA_FILE (g_list_first (m3u8->files)->data)->sequence;
2061
2062     GST_DEBUG_OBJECT (demux,
2063         "sequence:%" G_GINT64_FORMAT " , first_sequence:%" G_GINT64_FORMAT
2064         " , last_sequence:%" G_GINT64_FORMAT, m3u8->sequence,
2065         first_sequence, last_sequence);
2066     if (m3u8->sequence > last_sequence - 3) {
2067       //demux->need_segment = TRUE;
2068       /* Make sure we never go below the minimum sequence number */
2069       m3u8->sequence = MAX (first_sequence, last_sequence - 3);
2070       GST_DEBUG_OBJECT (demux,
2071           "Sequence is beyond playlist. Moving back to %" G_GINT64_FORMAT,
2072           m3u8->sequence);
2073     }
2074     GST_M3U8_CLIENT_UNLOCK (demux->client);
2075   } else if (!gst_m3u8_is_live (m3u8)) {
2076     GstClockTime current_pos, target_pos;
2077     guint sequence = 0;
2078     GList *walk;
2079
2080     /* Sequence numbers are not guaranteed to be the same in different
2081      * playlists, so get the correct fragment here based on the current
2082      * position
2083      */
2084     GST_M3U8_CLIENT_LOCK (demux->client);
2085
2086     /* Valid because hlsdemux only has a single output */
2087     if (GST_ADAPTIVE_DEMUX_CAST (demux)->streams) {
2088       GstAdaptiveDemuxStream *stream =
2089           GST_ADAPTIVE_DEMUX_CAST (demux)->streams->data;
2090       target_pos = stream->segment.position;
2091     } else {
2092       target_pos = 0;
2093     }
2094     if (GST_CLOCK_TIME_IS_VALID (m3u8->sequence_position)) {
2095       target_pos = MAX (target_pos, m3u8->sequence_position);
2096     }
2097
2098     GST_LOG_OBJECT (demux, "Looking for sequence position %"
2099         GST_TIME_FORMAT " in updated playlist", GST_TIME_ARGS (target_pos));
2100
2101     current_pos = 0;
2102     for (walk = m3u8->files; walk; walk = walk->next) {
2103       GstM3U8MediaFile *file = walk->data;
2104
2105       sequence = file->sequence;
2106       if (current_pos <= target_pos
2107           && target_pos < current_pos + file->duration) {
2108         break;
2109       }
2110       current_pos += file->duration;
2111     }
2112     /* End of playlist */
2113     if (!walk)
2114       sequence++;
2115     m3u8->sequence = sequence;
2116     m3u8->sequence_position = current_pos;
2117     GST_M3U8_CLIENT_UNLOCK (demux->client);
2118   }
2119 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
2120   GST_DEBUG_OBJECT (demux, "post variant info message");
2121   gst_element_post_message (GST_ELEMENT_CAST (demux),
2122       gst_message_new_element (GST_OBJECT_CAST (demux),
2123           gst_structure_new (GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME,
2124               "video-variant-info", G_TYPE_POINTER,
2125               demux->master->variant_info, NULL)));
2126 #endif
2127
2128   return TRUE;
2129 }
2130
2131 static gboolean
2132 gst_hls_demux_change_playlist (GstHLSDemux * demux, guint max_bitrate,
2133     gboolean * changed)
2134 {
2135   GstHLSVariantStream *lowest_variant, *lowest_ivariant;
2136   GstHLSVariantStream *previous_variant, *new_variant;
2137   gint old_bandwidth, new_bandwidth;
2138   GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX_CAST (demux);
2139   GstAdaptiveDemuxStream *stream;
2140
2141   g_return_val_if_fail (adaptive_demux->streams != NULL, FALSE);
2142
2143   stream = adaptive_demux->streams->data;
2144
2145 #ifdef TIZEN_FEATURE_UPSTREAM
2146   /* Make sure we keep a reference in case we need to switch back */
2147   previous_variant = gst_hls_variant_stream_ref (demux->current_variant);
2148 #else
2149   previous_variant = demux->current_variant;
2150 #endif
2151 #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
2152   new_variant =
2153       gst_hls_master_playlist_get_variant_for_bandwitdh_limit (demux->master,
2154       demux->current_variant, max_bitrate, NULL, adaptive_demux->min_bandwidth,
2155       adaptive_demux->max_bandwidth, adaptive_demux->max_width,
2156       adaptive_demux->max_height);
2157
2158   GST_INFO_OBJECT (demux, "new_variant : %d, %d x %d",
2159       new_variant->bandwidth, new_variant->width, new_variant->height);
2160 #else
2161   new_variant =
2162       gst_hls_master_playlist_get_variant_for_bitrate (demux->master,
2163       demux->current_variant, max_bitrate);
2164 #endif
2165   GST_M3U8_CLIENT_LOCK (demux->client);
2166
2167 retry_failover_protection:
2168   old_bandwidth = previous_variant->bandwidth;
2169   new_bandwidth = new_variant->bandwidth;
2170
2171   /* Don't do anything else if the playlist is the same */
2172   if (new_bandwidth == old_bandwidth) {
2173     GST_M3U8_CLIENT_UNLOCK (demux->client);
2174 #ifdef TIZEN_FEATURE_UPSTREAM
2175     gst_hls_variant_stream_unref (previous_variant);
2176 #endif
2177     return TRUE;
2178   }
2179
2180   GST_M3U8_CLIENT_UNLOCK (demux->client);
2181
2182   gst_hls_demux_set_current_variant (demux, new_variant);
2183
2184   GST_INFO_OBJECT (demux, "Client was on %dbps, max allowed is %dbps, switching"
2185       " to bitrate %dbps", old_bandwidth, max_bitrate, new_bandwidth);
2186
2187   if (gst_hls_demux_update_playlist (demux, TRUE, NULL)) {
2188     const gchar *main_uri;
2189     gchar *uri;
2190
2191     uri = gst_m3u8_get_uri (new_variant->m3u8);
2192     main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
2193     gst_element_post_message (GST_ELEMENT_CAST (demux),
2194         gst_message_new_element (GST_OBJECT_CAST (demux),
2195             gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME,
2196                 "manifest-uri", G_TYPE_STRING,
2197                 main_uri, "uri", G_TYPE_STRING,
2198                 uri, "bitrate", G_TYPE_INT, new_bandwidth, NULL)));
2199     g_free (uri);
2200     if (changed)
2201       *changed = TRUE;
2202     stream->discont = TRUE;
2203   } else if (gst_adaptive_demux_is_running (GST_ADAPTIVE_DEMUX_CAST (demux))) {
2204     GstHLSVariantStream *failover_variant = NULL;
2205     GList *failover;
2206
2207     GST_INFO_OBJECT (demux, "Unable to update playlist. Switching back");
2208     GST_M3U8_CLIENT_LOCK (demux->client);
2209
2210     /* we find variants by bitrate by going from highest to lowest, so it's
2211      * possible that there's another variant with the same bitrate before the
2212      * one selected which we can use as failover */
2213     failover = g_list_find (demux->master->variants, new_variant);
2214     if (failover != NULL)
2215       failover = failover->prev;
2216     if (failover != NULL)
2217       failover_variant = failover->data;
2218     if (failover_variant && new_bandwidth == failover_variant->bandwidth) {
2219       new_variant = failover_variant;
2220       goto retry_failover_protection;
2221     }
2222
2223     GST_M3U8_CLIENT_UNLOCK (demux->client);
2224     gst_hls_demux_set_current_variant (demux, previous_variant);
2225     /*  Try a lower bitrate (or stop if we just tried the lowest) */
2226     if (previous_variant->iframe) {
2227       lowest_ivariant = demux->master->iframe_variants->data;
2228       if (new_bandwidth == lowest_ivariant->bandwidth)
2229         return FALSE;
2230     } else {
2231       lowest_variant = demux->master->variants->data;
2232       if (new_bandwidth == lowest_variant->bandwidth)
2233         return FALSE;
2234     }
2235     return gst_hls_demux_change_playlist (demux, new_bandwidth - 1, changed);
2236   }
2237 #ifdef TIZEN_FEATURE_UPSTREAM
2238   gst_hls_variant_stream_unref (previous_variant);
2239 #endif
2240   return TRUE;
2241 }
2242
2243 #if defined(HAVE_OPENSSL)
2244 static gboolean
2245 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
2246     const guint8 * key_data, const guint8 * iv_data)
2247 {
2248   EVP_CIPHER_CTX *ctx;
2249 #if OPENSSL_VERSION_NUMBER < 0x10100000L
2250   EVP_CIPHER_CTX_init (&stream->aes_ctx);
2251   ctx = &stream->aes_ctx;
2252 #else
2253   stream->aes_ctx = EVP_CIPHER_CTX_new ();
2254   ctx = stream->aes_ctx;
2255 #endif
2256   if (!EVP_DecryptInit_ex (ctx, EVP_aes_128_cbc (), NULL, key_data, iv_data))
2257     return FALSE;
2258   EVP_CIPHER_CTX_set_padding (ctx, 0);
2259   return TRUE;
2260 }
2261
2262 static gboolean
2263 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
2264     const guint8 * encrypted_data, guint8 * decrypted_data)
2265 {
2266   int len, flen = 0;
2267   EVP_CIPHER_CTX *ctx;
2268
2269 #if OPENSSL_VERSION_NUMBER < 0x10100000L
2270   ctx = &stream->aes_ctx;
2271 #else
2272   ctx = stream->aes_ctx;
2273 #endif
2274
2275   if (G_UNLIKELY (length > G_MAXINT || length % 16 != 0))
2276     return FALSE;
2277
2278   len = (int) length;
2279   if (!EVP_DecryptUpdate (ctx, decrypted_data, &len, encrypted_data, len))
2280     return FALSE;
2281   EVP_DecryptFinal_ex (ctx, decrypted_data + len, &flen);
2282   g_return_val_if_fail (len + flen == length, FALSE);
2283   return TRUE;
2284 }
2285
2286 static void
2287 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
2288 {
2289 #if OPENSSL_VERSION_NUMBER < 0x10100000L
2290   EVP_CIPHER_CTX_cleanup (&stream->aes_ctx);
2291 #else
2292   EVP_CIPHER_CTX_free (stream->aes_ctx);
2293   stream->aes_ctx = NULL;
2294 #endif
2295 }
2296
2297 #elif defined(HAVE_NETTLE)
2298 static gboolean
2299 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
2300     const guint8 * key_data, const guint8 * iv_data)
2301 {
2302   aes_set_decrypt_key (&stream->aes_ctx.ctx, 16, key_data);
2303   CBC_SET_IV (&stream->aes_ctx, iv_data);
2304
2305   return TRUE;
2306 }
2307
2308 static gboolean
2309 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
2310     const guint8 * encrypted_data, guint8 * decrypted_data)
2311 {
2312   if (length % 16 != 0)
2313     return FALSE;
2314
2315   CBC_DECRYPT (&stream->aes_ctx, aes_decrypt, length, decrypted_data,
2316       encrypted_data);
2317
2318   return TRUE;
2319 }
2320
2321 static void
2322 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
2323 {
2324   /* NOP */
2325 }
2326
2327 #elif defined(HAVE_LIBGCRYPT)
2328 static gboolean
2329 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
2330     const guint8 * key_data, const guint8 * iv_data)
2331 {
2332   gcry_error_t err = 0;
2333   gboolean ret = FALSE;
2334
2335   err =
2336       gcry_cipher_open (&stream->aes_ctx, GCRY_CIPHER_AES128,
2337       GCRY_CIPHER_MODE_CBC, 0);
2338   if (err)
2339     goto out;
2340   err = gcry_cipher_setkey (stream->aes_ctx, key_data, 16);
2341   if (err)
2342     goto out;
2343   err = gcry_cipher_setiv (stream->aes_ctx, iv_data, 16);
2344   if (!err)
2345     ret = TRUE;
2346
2347 out:
2348   if (!ret)
2349     if (stream->aes_ctx)
2350       gcry_cipher_close (stream->aes_ctx);
2351
2352   return ret;
2353 }
2354
2355 static gboolean
2356 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
2357     const guint8 * encrypted_data, guint8 * decrypted_data)
2358 {
2359   gcry_error_t err = 0;
2360
2361   err = gcry_cipher_decrypt (stream->aes_ctx, decrypted_data, length,
2362       encrypted_data, length);
2363
2364   return err == 0;
2365 }
2366
2367 static void
2368 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
2369 {
2370   if (stream->aes_ctx) {
2371     gcry_cipher_close (stream->aes_ctx);
2372     stream->aes_ctx = NULL;
2373   }
2374 }
2375
2376 #else
2377 /* NO crypto available */
2378 static gboolean
2379 gst_hls_demux_stream_decrypt_start (GstHLSDemuxStream * stream,
2380     const guint8 * key_data, const guint8 * iv_data)
2381 {
2382   GST_ERROR ("No crypto available");
2383   return FALSE;
2384 }
2385
2386 static gboolean
2387 decrypt_fragment (GstHLSDemuxStream * stream, gsize length,
2388     const guint8 * encrypted_data, guint8 * decrypted_data)
2389 {
2390   GST_ERROR ("Cannot decrypt fragment, no crypto available");
2391   return FALSE;
2392 }
2393
2394 static void
2395 gst_hls_demux_stream_decrypt_end (GstHLSDemuxStream * stream)
2396 {
2397   return;
2398 }
2399 #endif
2400
2401 static GstBuffer *
2402 gst_hls_demux_decrypt_fragment (GstHLSDemux * demux, GstHLSDemuxStream * stream,
2403     GstBuffer * encrypted_buffer, GError ** err)
2404 {
2405   GstBuffer *decrypted_buffer = NULL;
2406   GstMapInfo encrypted_info, decrypted_info;
2407
2408   decrypted_buffer =
2409       gst_buffer_new_allocate (NULL, gst_buffer_get_size (encrypted_buffer),
2410       NULL);
2411
2412   gst_buffer_map (encrypted_buffer, &encrypted_info, GST_MAP_READ);
2413   gst_buffer_map (decrypted_buffer, &decrypted_info, GST_MAP_WRITE);
2414
2415   if (!decrypt_fragment (stream, encrypted_info.size,
2416           encrypted_info.data, decrypted_info.data))
2417     goto decrypt_error;
2418
2419
2420   gst_buffer_unmap (decrypted_buffer, &decrypted_info);
2421   gst_buffer_unmap (encrypted_buffer, &encrypted_info);
2422
2423   gst_buffer_unref (encrypted_buffer);
2424
2425   return decrypted_buffer;
2426
2427 decrypt_error:
2428   GST_ERROR_OBJECT (demux, "Failed to decrypt fragment");
2429   g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_DECRYPT,
2430       "Failed to decrypt fragment");
2431
2432   gst_buffer_unmap (decrypted_buffer, &decrypted_info);
2433   gst_buffer_unmap (encrypted_buffer, &encrypted_info);
2434
2435   gst_buffer_unref (encrypted_buffer);
2436   gst_buffer_unref (decrypted_buffer);
2437
2438   return NULL;
2439 }
2440
2441 static gint64
2442 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
2443 {
2444   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
2445   GstClockTime target_duration;
2446
2447   if (hlsdemux->current_variant) {
2448     target_duration =
2449         gst_m3u8_get_target_duration (hlsdemux->current_variant->m3u8);
2450   } else {
2451     target_duration = 5 * GST_SECOND;
2452   }
2453
2454   return gst_util_uint64_scale (target_duration, G_USEC_PER_SEC, GST_SECOND);
2455 }
2456
2457 static gboolean
2458 gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * start,
2459     gint64 * stop)
2460 {
2461   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
2462   gboolean ret = FALSE;
2463
2464   if (hlsdemux->current_variant) {
2465     ret =
2466         gst_m3u8_get_seek_range (hlsdemux->current_variant->m3u8, start, stop);
2467   }
2468
2469   return ret;
2470 }
2471
2472 #ifdef TIZEN_FEATURE_HLSDEMUX_LANG_TAG
2473 static gboolean
2474 gst_hlsdemux_set_stream_event (GstAdaptiveDemuxStream * stream,
2475     GstHLSMedia * media)
2476 {
2477   GstStructure *structure;
2478   GstEvent *event;
2479
2480   if (!stream) {
2481     GST_WARNING ("stream is NULL");
2482     return FALSE;
2483   }
2484
2485   if (!media) {
2486     GST_WARNING ("media is NULL");
2487     return FALSE;
2488   }
2489
2490   if (media->lang)
2491     gst_hlsdemux_set_language_tags (stream, media->lang);
2492
2493   structure =
2494       gst_structure_new ("GstHLSMedia", "mtype", G_TYPE_INT, media->mtype,
2495       "default", G_TYPE_BOOLEAN, media->is_default, "autoselect",
2496       G_TYPE_BOOLEAN, media->autoselect, "forced", G_TYPE_BOOLEAN,
2497       media->forced, NULL);
2498
2499   event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, structure);
2500
2501   gst_adaptive_demux_stream_queue_event (stream, event);
2502
2503   return TRUE;
2504 }
2505
2506 static gboolean
2507 gst_hlsdemux_set_language_tags (GstAdaptiveDemuxStream * stream,
2508     const gchar * language)
2509 {
2510   GstTagList *lang_tag = NULL;
2511
2512   if (!stream)
2513     return FALSE;
2514
2515   if (gst_tag_check_language_code (language))
2516     lang_tag = gst_tag_list_new (GST_TAG_LANGUAGE_CODE, language, NULL);
2517   else
2518     lang_tag = gst_tag_list_new (GST_TAG_LANGUAGE_NAME, language, NULL);
2519
2520   if (!lang_tag)
2521     return FALSE;
2522
2523   gst_adaptive_demux_stream_set_tags (stream, lang_tag);
2524
2525   return TRUE;
2526 }
2527 #endif