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