FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/hls.c
Date: 2026-07-21 08:37:06
Exec Total Coverage
Lines: 967 1638 59.0%
Functions: 45 56 80.4%
Branches: 560 1218 46.0%

Line Branch Exec Source
1 /*
2 * Apple HTTP Live Streaming demuxer
3 * Copyright (c) 2010 Martin Storsjo
4 * Copyright (c) 2013 Anssi Hannula
5 * Copyright (c) 2021 Nachiket Tarate
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 /**
25 * @file
26 * Apple HTTP Live Streaming demuxer
27 * https://www.rfc-editor.org/rfc/rfc8216.txt
28 */
29
30 #include "config_components.h"
31
32 #include "libavformat/http.h"
33 #include "libavutil/aes.h"
34 #include "libavutil/avstring.h"
35 #include "libavutil/avassert.h"
36 #include "libavutil/intreadwrite.h"
37 #include "libavutil/mathematics.h"
38 #include "libavutil/mem.h"
39 #include "libavutil/opt.h"
40 #include "libavutil/dict.h"
41 #include "libavutil/time.h"
42 #include "avformat.h"
43 #include "demux.h"
44 #include "internal.h"
45 #include "avio_internal.h"
46 #include "id3v2.h"
47 #include "url.h"
48
49 #include "hls_sample_encryption.h"
50
51 #define INITIAL_BUFFER_SIZE 32768
52
53 #define MAX_FIELD_LEN 64
54 #define MAX_CHARACTERISTICS_LEN 512
55
56 #define MPEG_TIME_BASE 90000
57 #define MPEG_TIME_BASE_Q (AVRational){1, MPEG_TIME_BASE}
58
59 /*
60 * An apple http stream consists of a playlist with media segment files,
61 * played sequentially. There may be several playlists with the same
62 * video content, in different bandwidth variants, that are played in
63 * parallel (preferably only one bandwidth variant at a time). In this case,
64 * the user supplied the url to a main playlist that only lists the variant
65 * playlists.
66 *
67 * If the main playlist doesn't point at any variants, we still create
68 * one anonymous toplevel variant for this, to maintain the structure.
69 */
70
71 enum KeyType {
72 KEY_NONE,
73 KEY_AES_128,
74 KEY_SAMPLE_AES
75 };
76
77 struct segment {
78 int64_t duration;
79 int64_t url_offset;
80 int64_t size;
81 char *url;
82 char *key;
83 enum KeyType key_type;
84 uint8_t iv[16];
85 /* associated Media Initialization Section, treated as a segment */
86 struct segment *init_section;
87 };
88
89 struct rendition;
90
91 enum PlaylistType {
92 PLS_TYPE_UNSPECIFIED,
93 PLS_TYPE_EVENT,
94 PLS_TYPE_VOD
95 };
96
97 /*
98 * Each playlist has its own demuxer. If it currently is active,
99 * it has an open AVIOContext too, and potentially an AVPacket
100 * containing the next packet from this stream.
101 */
102 struct playlist {
103 char url[MAX_URL_SIZE];
104 FFIOContext pb;
105 uint8_t* read_buffer;
106 AVIOContext *input;
107 int input_read_done;
108 int input_reuse;
109 AVIOContext *input_next;
110 int input_next_requested;
111 AVFormatContext *parent;
112 int index;
113 AVFormatContext *ctx;
114 AVPacket *pkt;
115 int has_noheader_flag;
116
117 /* main demuxer streams associated with this playlist
118 * indexed by the subdemuxer stream indexes */
119 AVStream **main_streams;
120 int n_main_streams;
121
122 int finished;
123 enum PlaylistType type;
124 int64_t target_duration;
125 int64_t start_seq_no;
126 int time_offset_flag;
127 int64_t start_time_offset;
128 int n_segments;
129 struct segment **segments;
130 int needed;
131 int broken;
132 int64_t cur_seq_no;
133 int64_t last_seq_no;
134 int m3u8_hold_counters;
135 int64_t cur_seg_offset;
136 int64_t last_load_time;
137
138 /* Currently active Media Initialization Section */
139 struct segment *cur_init_section;
140 uint8_t *init_sec_buf;
141 unsigned int init_sec_buf_size;
142 unsigned int init_sec_data_len;
143 unsigned int init_sec_buf_read_offset;
144
145 char key_url[MAX_URL_SIZE];
146 uint8_t key[16];
147
148 /* ID3 timestamp handling (elementary audio streams have ID3 timestamps
149 * (and possibly other ID3 tags) in the beginning of each segment) */
150 int is_id3_timestamped; /* -1: not yet known */
151 int64_t id3_mpegts_timestamp; /* in mpegts tb */
152 int64_t id3_offset; /* in stream original tb */
153 uint8_t* id3_buf; /* temp buffer for id3 parsing */
154 unsigned int id3_buf_size;
155 AVDictionary *id3_initial; /* data from first id3 tag */
156 int id3_found; /* ID3 tag found at some point */
157 int id3_changed; /* ID3 tag data has changed at some point */
158 ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer is opened */
159
160 HLSAudioSetupInfo audio_setup_info;
161
162 /* Constant offset of this playlist's DTS baseline relative to
163 * c->first_timestamp. */
164 int64_t ts_offset;
165 int64_t seek_timestamp;
166 int seek_flags;
167 int seek_stream_index; /* into subdemuxer stream array */
168
169 /* Renditions associated with this playlist, if any.
170 * Alternative rendition playlists have a single rendition associated
171 * with them, and variant main Media Playlists may have
172 * multiple (playlist-less) renditions associated with them. */
173 int n_renditions;
174 struct rendition **renditions;
175
176 /* Media Initialization Sections (EXT-X-MAP) associated with this
177 * playlist, if any. */
178 int n_init_sections;
179 struct segment **init_sections;
180 int is_subtitle; /* Indicates if it's a subtitle playlist */
181
182 /* Some HLS streams repeat the current timed-ID3 metadata at every segment
183 * boundary so late-joining clients get a fresh copy. Track the last seen
184 * value to avoid raising AVSTREAM_EVENT_FLAG_METADATA_UPDATED spuriously
185 * on those duplicates. timed_id3_stream_index is the subdemuxer stream
186 * index of the first timed-ID3 stream seen; -1 if none. */
187 AVDictionary *timed_id3_metadata;
188 int timed_id3_stream_index;
189 };
190
191 /*
192 * Renditions are e.g. alternative subtitle or audio streams.
193 * The rendition may either be an external playlist or it may be
194 * contained in the main Media Playlist of the variant (in which case
195 * playlist is NULL).
196 */
197 struct rendition {
198 enum AVMediaType type;
199 struct playlist *playlist;
200 char group_id[MAX_FIELD_LEN];
201 char language[MAX_FIELD_LEN];
202 char name[MAX_FIELD_LEN];
203 int disposition;
204 };
205
206 struct variant {
207 int bandwidth;
208
209 /* every variant contains at least the main Media Playlist in index 0 */
210 int n_playlists;
211 struct playlist **playlists;
212
213 char audio_group[MAX_FIELD_LEN];
214 char video_group[MAX_FIELD_LEN];
215 char subtitles_group[MAX_FIELD_LEN];
216 };
217
218 typedef struct HLSContext {
219 AVClass *class;
220 AVFormatContext *ctx;
221 int n_variants;
222 struct variant **variants;
223 int n_playlists;
224 struct playlist **playlists;
225 int n_renditions;
226 struct rendition **renditions;
227
228 int64_t cur_seq_no;
229 int m3u8_hold_counters;
230 int live_start_index;
231 int prefer_x_start;
232 int first_packet;
233 int64_t first_timestamp;
234 struct playlist *first_timestamp_pls;
235 int64_t cur_timestamp;
236 AVIOInterruptCB *interrupt_callback;
237 AVDictionary *avio_opts;
238 AVDictionary *seg_format_opts;
239 char *allowed_extensions;
240 char *allowed_segment_extensions;
241 int extension_picky;
242 int max_reload;
243 int http_persistent;
244 int http_multiple;
245 int http_seekable;
246 int seg_max_retry;
247 AVIOContext *playlist_pb;
248 HLSCryptoContext crypto_ctx;
249 } HLSContext;
250
251 17 static void free_segment_dynarray(struct segment **segments, int n_segments)
252 {
253 int i;
254
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 17 times.
97 for (i = 0; i < n_segments; i++) {
255 80 av_freep(&segments[i]->key);
256 80 av_freep(&segments[i]->url);
257 80 av_freep(&segments[i]);
258 }
259 17 }
260
261 17 static void free_segment_list(struct playlist *pls)
262 {
263 17 free_segment_dynarray(pls->segments, pls->n_segments);
264 17 av_freep(&pls->segments);
265 17 pls->n_segments = 0;
266 17 }
267
268 17 static void free_init_section_list(struct playlist *pls)
269 {
270 int i;
271
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 for (i = 0; i < pls->n_init_sections; i++) {
272 1 av_freep(&pls->init_sections[i]->key);
273 1 av_freep(&pls->init_sections[i]->url);
274 1 av_freep(&pls->init_sections[i]);
275 }
276 17 av_freep(&pls->init_sections);
277 17 pls->n_init_sections = 0;
278 17 }
279
280 16 static void free_playlist_list(HLSContext *c)
281 {
282 int i;
283
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 16 times.
33 for (i = 0; i < c->n_playlists; i++) {
284 17 struct playlist *pls = c->playlists[i];
285 17 free_segment_list(pls);
286 17 free_init_section_list(pls);
287 17 av_freep(&pls->main_streams);
288 17 av_freep(&pls->renditions);
289 17 av_freep(&pls->id3_buf);
290 17 av_dict_free(&pls->id3_initial);
291 17 av_dict_free(&pls->timed_id3_metadata);
292 17 ff_id3v2_free_extra_meta(&pls->id3_deferred_extra);
293 17 av_freep(&pls->init_sec_buf);
294 17 av_packet_free(&pls->pkt);
295 17 av_freep(&pls->pb.pub.buffer);
296 17 ff_format_io_close(c->ctx, &pls->input);
297 17 pls->input_read_done = 0;
298 17 pls->input_reuse = 0;
299 17 ff_format_io_close(c->ctx, &pls->input_next);
300 17 pls->input_next_requested = 0;
301
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (pls->ctx) {
302 17 pls->ctx->pb = NULL;
303 17 avformat_close_input(&pls->ctx);
304 }
305 17 av_free(pls);
306 }
307 16 av_freep(&c->playlists);
308 16 c->n_playlists = 0;
309 16 }
310
311 16 static void free_variant_list(HLSContext *c)
312 {
313 int i;
314
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 for (i = 0; i < c->n_variants; i++) {
315 16 struct variant *var = c->variants[i];
316 16 av_freep(&var->playlists);
317 16 av_free(var);
318 }
319 16 av_freep(&c->variants);
320 16 c->n_variants = 0;
321 16 }
322
323 16 static void free_rendition_list(HLSContext *c)
324 {
325 int i;
326
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 for (i = 0; i < c->n_renditions; i++)
327 1 av_freep(&c->renditions[i]);
328 16 av_freep(&c->renditions);
329 16 c->n_renditions = 0;
330 16 }
331
332 17 static struct playlist *new_playlist(HLSContext *c, const char *url,
333 const char *base)
334 {
335 struct playlist *pls;
336 char abs_url[MAX_URL_SIZE];
337
338 17 ff_make_absolute_url(abs_url, sizeof(abs_url), base, url);
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (!abs_url[0])
340 return NULL;
341
342
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 for (int i = 0; i < c->n_playlists; i++) {
343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!strcmp(c->playlists[i]->url, abs_url))
344 return c->playlists[i];
345 }
346
347 17 pls = av_mallocz(sizeof(struct playlist));
348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (!pls)
349 return NULL;
350 17 pls->pkt = av_packet_alloc();
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (!pls->pkt) {
352 av_free(pls);
353 return NULL;
354 }
355 17 av_strlcpy(pls->url, abs_url, sizeof(pls->url));
356 17 pls->ts_offset = AV_NOPTS_VALUE;
357 17 pls->seek_timestamp = AV_NOPTS_VALUE;
358
359 17 pls->is_id3_timestamped = -1;
360 17 pls->id3_mpegts_timestamp = AV_NOPTS_VALUE;
361 17 pls->timed_id3_stream_index = -1;
362
363 17 dynarray_add(&c->playlists, &c->n_playlists, pls);
364 17 return pls;
365 }
366
367 struct variant_info {
368 char bandwidth[20];
369 /* variant group ids: */
370 char audio[MAX_FIELD_LEN];
371 char video[MAX_FIELD_LEN];
372 char subtitles[MAX_FIELD_LEN];
373 };
374
375 16 static struct variant *new_variant(HLSContext *c, struct variant_info *info,
376 const char *url, const char *base)
377 {
378 struct variant *var;
379 struct playlist *pls;
380
381 16 pls = new_playlist(c, url, base);
382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!pls)
383 return NULL;
384
385 16 var = av_mallocz(sizeof(struct variant));
386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!var)
387 return NULL;
388
389
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 if (info) {
390 1 var->bandwidth = atoi(info->bandwidth);
391 1 strcpy(var->audio_group, info->audio);
392 1 strcpy(var->video_group, info->video);
393 1 strcpy(var->subtitles_group, info->subtitles);
394 }
395
396 16 dynarray_add(&c->variants, &c->n_variants, var);
397 16 dynarray_add(&var->playlists, &var->n_playlists, pls);
398 16 return var;
399 }
400
401 4 static void handle_variant_args(void *context, const char *key,
402 int key_len, char **dest, int *dest_len)
403 {
404 4 struct variant_info *info = context;
405
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (!strncmp(key, "BANDWIDTH=", key_len)) {
406 1 *dest = info->bandwidth;
407 1 *dest_len = sizeof(info->bandwidth);
408
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (!strncmp(key, "AUDIO=", key_len)) {
409 1 *dest = info->audio;
410 1 *dest_len = sizeof(info->audio);
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (!strncmp(key, "VIDEO=", key_len)) {
412 *dest = info->video;
413 *dest_len = sizeof(info->video);
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (!strncmp(key, "SUBTITLES=", key_len)) {
415 *dest = info->subtitles;
416 *dest_len = sizeof(info->subtitles);
417 }
418 4 }
419
420 struct key_info {
421 char uri[MAX_URL_SIZE];
422 char method[11];
423 char iv[35];
424 };
425
426 static void handle_key_args(void *context, const char *key,
427 int key_len, char **dest, int *dest_len)
428 {
429 struct key_info *info = context;
430 if (!strncmp(key, "METHOD=", key_len)) {
431 *dest = info->method;
432 *dest_len = sizeof(info->method);
433 } else if (!strncmp(key, "URI=", key_len)) {
434 *dest = info->uri;
435 *dest_len = sizeof(info->uri);
436 } else if (!strncmp(key, "IV=", key_len)) {
437 *dest = info->iv;
438 *dest_len = sizeof(info->iv);
439 }
440 }
441
442 struct init_section_info {
443 char uri[MAX_URL_SIZE];
444 char byterange[32];
445 };
446
447 1 static struct segment *new_init_section(struct playlist *pls,
448 struct init_section_info *info,
449 const char *url_base)
450 {
451 struct segment *sec;
452 1 char tmp_str[MAX_URL_SIZE], *ptr = tmp_str;
453
454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!info->uri[0])
455 return NULL;
456
457 1 sec = av_mallocz(sizeof(*sec));
458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!sec)
459 return NULL;
460
461
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!av_strncasecmp(info->uri, "data:", 5)) {
462 ptr = info->uri;
463 } else {
464 1 ff_make_absolute_url(tmp_str, sizeof(tmp_str), url_base, info->uri);
465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tmp_str[0]) {
466 av_free(sec);
467 return NULL;
468 }
469 }
470 1 sec->url = av_strdup(ptr);
471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!sec->url) {
472 av_free(sec);
473 return NULL;
474 }
475
476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (info->byterange[0]) {
477 sec->size = strtoll(info->byterange, NULL, 10);
478 ptr = strchr(info->byterange, '@');
479 if (ptr)
480 sec->url_offset = strtoll(ptr+1, NULL, 10);
481 if (sec->size < 0 || sec->url_offset < 0 || sec->size > INT64_MAX - sec->url_offset) {
482 av_freep(&sec->url);
483 av_free(sec);
484 return NULL;
485 }
486 } else {
487 /* the entire file is the init section */
488 1 sec->size = -1;
489 }
490
491 1 dynarray_add(&pls->init_sections, &pls->n_init_sections, sec);
492
493 1 return sec;
494 }
495
496 1 static void handle_init_section_args(void *context, const char *key,
497 int key_len, char **dest, int *dest_len)
498 {
499 1 struct init_section_info *info = context;
500
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!strncmp(key, "URI=", key_len)) {
501 1 *dest = info->uri;
502 1 *dest_len = sizeof(info->uri);
503 } else if (!strncmp(key, "BYTERANGE=", key_len)) {
504 *dest = info->byterange;
505 *dest_len = sizeof(info->byterange);
506 }
507 1 }
508
509 struct rendition_info {
510 char type[16];
511 char uri[MAX_URL_SIZE];
512 char group_id[MAX_FIELD_LEN];
513 char language[MAX_FIELD_LEN];
514 char assoc_language[MAX_FIELD_LEN];
515 char name[MAX_FIELD_LEN];
516 char defaultr[4];
517 char forced[4];
518 char characteristics[MAX_CHARACTERISTICS_LEN];
519 };
520
521 1 static struct rendition *new_rendition(HLSContext *c, struct rendition_info *info,
522 const char *url_base)
523 {
524 struct rendition *rend;
525 1 enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN;
526 char *characteristic;
527 char *chr_ptr;
528 char *saveptr;
529
530
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!strcmp(info->type, "AUDIO"))
531 1 type = AVMEDIA_TYPE_AUDIO;
532 else if (!strcmp(info->type, "VIDEO"))
533 type = AVMEDIA_TYPE_VIDEO;
534 else if (!strcmp(info->type, "SUBTITLES"))
535 type = AVMEDIA_TYPE_SUBTITLE;
536 else if (!strcmp(info->type, "CLOSED-CAPTIONS"))
537 /* CLOSED-CAPTIONS is ignored since we do not support CEA-608 CC in
538 * AVC SEI RBSP anyway */
539 return NULL;
540
541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (type == AVMEDIA_TYPE_UNKNOWN) {
542 av_log(c->ctx, AV_LOG_WARNING, "Can't support the type: %s\n", info->type);
543 return NULL;
544 }
545
546 /* URI is mandatory for subtitles as per spec */
547
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (type == AVMEDIA_TYPE_SUBTITLE && !info->uri[0]) {
548 av_log(c->ctx, AV_LOG_ERROR, "The URI tag is REQUIRED for subtitle.\n");
549 return NULL;
550 }
551
552 1 rend = av_mallocz(sizeof(struct rendition));
553
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!rend)
554 return NULL;
555
556 1 dynarray_add(&c->renditions, &c->n_renditions, rend);
557
558 1 rend->type = type;
559 1 strcpy(rend->group_id, info->group_id);
560 1 strcpy(rend->language, info->language);
561 1 strcpy(rend->name, info->name);
562
563 /* add the playlist if this is an external rendition */
564
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (info->uri[0]) {
565 1 rend->playlist = new_playlist(c, info->uri, url_base);
566
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (rend->playlist) {
567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (type == AVMEDIA_TYPE_SUBTITLE) {
568 rend->playlist->is_subtitle = 1;
569 rend->playlist->is_id3_timestamped = 0;
570 }
571 1 dynarray_add(&rend->playlist->renditions,
572 &rend->playlist->n_renditions, rend);
573 }
574 }
575
576
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (info->assoc_language[0]) {
577 size_t langlen = strlen(rend->language);
578 if (langlen < sizeof(rend->language) - 3) {
579 size_t assoc_len;
580 rend->language[langlen] = ',';
581 assoc_len = av_strlcpy(rend->language + langlen + 1,
582 info->assoc_language,
583 sizeof(rend->language) - langlen - 1);
584 if (langlen + assoc_len + 2 > sizeof(rend->language)) // truncation occurred
585 av_log(c->ctx, AV_LOG_WARNING, "Truncated rendition language: %s\n",
586 info->assoc_language);
587 }
588 }
589
590
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!strcmp(info->defaultr, "YES"))
591 1 rend->disposition |= AV_DISPOSITION_DEFAULT;
592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!strcmp(info->forced, "YES"))
593 rend->disposition |= AV_DISPOSITION_FORCED;
594
595 1 chr_ptr = info->characteristics;
596
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 while ((characteristic = av_strtok(chr_ptr, ",", &saveptr))) {
597 if (!strcmp(characteristic, "public.accessibility.describes-music-and-sound"))
598 rend->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
599 else if (!strcmp(characteristic, "public.accessibility.describes-video"))
600 rend->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
601
602 chr_ptr = NULL;
603 }
604
605 1 return rend;
606 }
607
608 6 static void handle_rendition_args(void *vinfo, const char *key,
609 int key_len, char **dest, int *dest_len)
610 {
611 6 struct rendition_info *info = vinfo;
612
613
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (!strncmp(key, "TYPE=", key_len)) {
614 1 *dest = info->type;
615 1 *dest_len = sizeof(info->type);
616
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 } else if (!strncmp(key, "URI=", key_len)) {
617 1 *dest = info->uri;
618 1 *dest_len = sizeof(info->uri);
619
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 } else if (!strncmp(key, "GROUP-ID=", key_len)) {
620 1 *dest = info->group_id;
621 1 *dest_len = sizeof(info->group_id);
622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (!strncmp(key, "LANGUAGE=", key_len)) {
623 *dest = info->language;
624 *dest_len = sizeof(info->language);
625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (!strncmp(key, "ASSOC-LANGUAGE=", key_len)) {
626 *dest = info->assoc_language;
627 *dest_len = sizeof(info->assoc_language);
628
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (!strncmp(key, "NAME=", key_len)) {
629 1 *dest = info->name;
630 1 *dest_len = sizeof(info->name);
631
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (!strncmp(key, "DEFAULT=", key_len)) {
632 1 *dest = info->defaultr;
633 1 *dest_len = sizeof(info->defaultr);
634
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } else if (!strncmp(key, "FORCED=", key_len)) {
635 *dest = info->forced;
636 *dest_len = sizeof(info->forced);
637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } else if (!strncmp(key, "CHARACTERISTICS=", key_len)) {
638 *dest = info->characteristics;
639 *dest_len = sizeof(info->characteristics);
640 }
641 /*
642 * ignored:
643 * - AUTOSELECT: client may autoselect based on e.g. system language
644 * - INSTREAM-ID: EIA-608 closed caption number ("CC1".."CC4")
645 */
646 6 }
647
648 /* used by parse_playlist to allocate a new variant+playlist when the
649 * playlist is detected to be a Media Playlist (not Master Playlist)
650 * and we have no parent Master Playlist (parsing of which would have
651 * allocated the variant and playlist already)
652 * *pls == NULL => Master Playlist or parentless Media Playlist
653 * *pls != NULL => parented Media Playlist, playlist+variant allocated */
654 115 static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url)
655 {
656
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 15 times.
115 if (*pls)
657 100 return 0;
658
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if (!new_variant(c, NULL, url, NULL))
659 return AVERROR(ENOMEM);
660 15 *pls = c->playlists[c->n_playlists - 1];
661 15 return 0;
662 }
663
664 static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb,
665 const char *url, AVDictionary **options)
666 {
667 #if !CONFIG_HTTP_PROTOCOL
668 return AVERROR_PROTOCOL_NOT_FOUND;
669 #else
670 int ret;
671 URLContext *uc = ffio_geturlcontext(*pb);
672 av_assert0(uc);
673 (*pb)->eof_reached = 0;
674 ret = ff_http_do_new_request2(uc, url, options);
675 if (ret < 0) {
676 ff_format_io_close(s, pb);
677 }
678 return ret;
679 #endif
680 }
681
682 112 static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
683 AVDictionary **opts, AVDictionary *opts2, int *is_http_out)
684 {
685 112 HLSContext *c = s->priv_data;
686 112 AVDictionary *tmp = NULL;
687 112 const char *proto_name = NULL;
688 int ret;
689 112 int is_http = 0;
690
691
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
112 if (av_strstart(url, "crypto", NULL)) {
692 if (url[6] == '+' || url[6] == ':')
693 proto_name = avio_find_protocol_name(url + 7);
694
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
112 } else if (av_strstart(url, "data", NULL)) {
695 if (url[4] == '+' || url[4] == ':')
696 proto_name = avio_find_protocol_name(url + 5);
697 }
698
699
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (!proto_name)
700 112 proto_name = avio_find_protocol_name(url);
701
702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (!proto_name)
703 return AVERROR_INVALIDDATA;
704
705 // only http(s) & file are allowed
706
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 if (av_strstart(proto_name, "file", NULL)) {
707
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 112 times.
112 if (strcmp(c->allowed_extensions, "ALL") && !av_match_ext(url, c->allowed_extensions)) {
708 av_log(s, AV_LOG_ERROR,
709 "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n"
710 "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n",
711 url);
712 return AVERROR_INVALIDDATA;
713 }
714 } else if (av_strstart(proto_name, "http", NULL)) {
715 is_http = 1;
716 } else if (av_strstart(proto_name, "data", NULL)) {
717 ;
718 } else
719 return AVERROR_INVALIDDATA;
720
721
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
112 if (!strncmp(proto_name, url, strlen(proto_name)) && url[strlen(proto_name)] == ':')
722 ;
723
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
112 else if (av_strstart(url, "crypto", NULL) && !strncmp(proto_name, url + 7, strlen(proto_name)) && url[7 + strlen(proto_name)] == ':')
724 ;
725
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
112 else if (av_strstart(url, "data", NULL) && !strncmp(proto_name, url + 5, strlen(proto_name)) && url[5 + strlen(proto_name)] == ':')
726 ;
727
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
112 else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5))
728 return AVERROR_INVALIDDATA;
729
730 112 av_dict_copy(&tmp, *opts, 0);
731 112 av_dict_copy(&tmp, opts2, 0);
732
733
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
112 if (is_http && c->http_persistent && *pb) {
734 ret = open_url_keepalive(c->ctx, pb, url, &tmp);
735 if (ret == AVERROR_EXIT) {
736 av_dict_free(&tmp);
737 return ret;
738 } else if (ret < 0) {
739 if (ret != AVERROR_EOF)
740 av_log(s, AV_LOG_WARNING,
741 "keepalive request failed for '%s' with error: '%s' when opening url, retrying with new connection\n",
742 url, av_err2str(ret));
743 av_dict_copy(&tmp, *opts, 0);
744 av_dict_copy(&tmp, opts2, 0);
745 ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp);
746 }
747 } else {
748 112 ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp);
749 }
750
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (ret >= 0) {
751 // update cookies on http response with setcookies.
752 112 char *new_cookies = NULL;
753
754
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (!(s->flags & AVFMT_FLAG_CUSTOM_IO))
755 112 av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies);
756
757
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (new_cookies)
758 av_dict_set(opts, "cookies", new_cookies, AV_DICT_DONT_STRDUP_VAL);
759 }
760
761 112 av_dict_free(&tmp);
762
763
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (is_http_out)
764 112 *is_http_out = is_http;
765
766 112 return ret;
767 }
768
769 160 static int test_segment(AVFormatContext *s, const AVInputFormat *in_fmt, struct playlist *pls, struct segment *seg)
770 {
771 160 HLSContext *c = s->priv_data;
772 160 int matchA = 3;
773 160 int matchF = 0;
774
775
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
160 if (!c->extension_picky)
776 return 0;
777
778
1/2
✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
160 if (strcmp(c->allowed_segment_extensions, "ALL"))
779 320 matchA = av_match_ext (seg->url, c->allowed_segment_extensions)
780
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 160 times.
160 + 2*(ff_match_url_ext(seg->url, c->allowed_segment_extensions) > 0);
781
782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
160 if (!matchA) {
783 av_log(s, AV_LOG_ERROR, "URL %s is not in allowed_segment_extensions, consider updating hls.c and submitting a patch to ffmpeg-devel, if this should be added\n", seg->url);
784 return AVERROR_INVALIDDATA;
785 }
786
787
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 80 times.
160 if (in_fmt) {
788
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 76 times.
80 if (in_fmt->extensions) {
789 4 matchF = av_match_ext( seg->url, in_fmt->extensions)
790
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 + 2*(ff_match_url_ext(seg->url, in_fmt->extensions) > 0);
791 // Youtube uses aac files with .ts extension
792
3/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
4 if(av_match_name("mp4", in_fmt->name) || av_match_name("aac", in_fmt->name)) {
793 1 matchF |= av_match_ext( seg->url, "ts,m2t,m2ts,mts,mpg,m4s,mpeg,mpegts,cmfv,cmfa")
794
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 + 2*(ff_match_url_ext(seg->url, "ts,m2t,m2ts,mts,mpg,m4s,mpeg,mpegts,cmfv,cmfa") > 0);
795 }
796
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 } else if (!strcmp(in_fmt->name, "mpegts")) {
797 76 const char *str = "ts,m2t,m2ts,mts,mpg,m4s,mpeg,mpegts"
798 ",html" // https://flash1.bogulus.cfd/
799 ;
800 152 matchF = av_match_ext( seg->url, str)
801
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
76 + 2*(ff_match_url_ext(seg->url, str) > 0);
802 } else if (!strcmp(in_fmt->name, "webvtt")) {
803 matchF = av_match_ext( seg->url, "vtt,webvtt")
804 + 2*(ff_match_url_ext(seg->url, "vtt,webvtt") > 0);
805 }
806
807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (!(matchA & matchF)) {
808 av_log(s, AV_LOG_ERROR, "detected format %s extension %s mismatches allowed extensions in url %s\n", in_fmt->name, in_fmt->extensions ? in_fmt->extensions : "none", seg->url);
809 return AVERROR_INVALIDDATA;
810 }
811 }
812
813 160 return 0;
814 }
815
816 18 static int parse_playlist(HLSContext *c, const char *url,
817 struct playlist *pls, AVIOContext *in)
818 {
819 18 int ret = 0, is_segment = 0, is_variant = 0;
820 18 int64_t duration = 0;
821 18 enum KeyType key_type = KEY_NONE;
822 18 uint8_t iv[16] = "";
823 18 int has_iv = 0;
824 18 char key[MAX_URL_SIZE] = "";
825 char line[MAX_URL_SIZE];
826 const char *ptr;
827 18 int close_in = 0;
828 18 int64_t seg_offset = 0;
829 18 int64_t seg_size = -1;
830 18 uint8_t *new_url = NULL;
831 struct variant_info variant_info;
832 char tmp_str[MAX_URL_SIZE];
833 18 struct segment *cur_init_section = NULL;
834 18 int is_http = av_strstart(url, "http", NULL);
835 18 struct segment **prev_segments = NULL;
836 18 int prev_n_segments = 0;
837 18 int64_t prev_start_seq_no = -1;
838
839
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18 if (is_http && !in && c->http_persistent && c->playlist_pb) {
840 in = c->playlist_pb;
841 ret = open_url_keepalive(c->ctx, &c->playlist_pb, url, NULL);
842 if (ret == AVERROR_EXIT) {
843 return ret;
844 } else if (ret < 0) {
845 if (ret != AVERROR_EOF)
846 av_log(c->ctx, AV_LOG_WARNING,
847 "keepalive request failed for '%s' with error: '%s' when parsing playlist\n",
848 url, av_err2str(ret));
849 in = NULL;
850 }
851 }
852
853
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (!in) {
854 2 AVDictionary *opts = NULL;
855 2 av_dict_copy(&opts, c->avio_opts, 0);
856
857
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (c->http_persistent)
858 2 av_dict_set(&opts, "multiple_requests", "1", 0);
859
860 2 ret = c->ctx->io_open(c->ctx, &in, url, AVIO_FLAG_READ, &opts);
861 2 av_dict_free(&opts);
862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
863 return ret;
864
865
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (is_http && c->http_persistent)
866 c->playlist_pb = in;
867 else
868 2 close_in = 1;
869 }
870
871
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0)
872 url = new_url;
873
874 18 ff_get_chomp_line(in, line, sizeof(line));
875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (strcmp(line, "#EXTM3U")) {
876 ret = AVERROR_INVALIDDATA;
877 goto fail;
878 }
879
880
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (pls) {
881 2 prev_start_seq_no = pls->start_seq_no;
882 2 prev_segments = pls->segments;
883 2 prev_n_segments = pls->n_segments;
884 2 pls->segments = NULL;
885 2 pls->n_segments = 0;
886
887 2 pls->finished = 0;
888 2 pls->type = PLS_TYPE_UNSPECIFIED;
889 }
890
2/2
✓ Branch 1 taken 273 times.
✓ Branch 2 taken 18 times.
291 while (!avio_feof(in)) {
891 273 ff_get_chomp_line(in, line, sizeof(line));
892
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 272 times.
273 if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (pls) {
894 av_log(c->ctx, AV_LOG_ERROR,
895 "Master Playlist tag found in a Media Playlist\n");
896 ret = AVERROR_INVALIDDATA;
897 goto fail;
898 }
899 1 is_variant = 1;
900 1 memset(&variant_info, 0, sizeof(variant_info));
901 1 ff_parse_key_value(ptr, handle_variant_args, &variant_info);
902
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 272 times.
272 } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) {
903 struct key_info info = {{0}};
904 ff_parse_key_value(ptr, handle_key_args, &info);
905 key_type = KEY_NONE;
906 has_iv = 0;
907 if (!strcmp(info.method, "AES-128"))
908 key_type = KEY_AES_128;
909 if (!strcmp(info.method, "SAMPLE-AES"))
910 key_type = KEY_SAMPLE_AES;
911 if (!av_strncasecmp(info.iv, "0x", 2)) {
912 ff_hex_to_data(iv, info.iv + 2);
913 has_iv = 1;
914 }
915 av_strlcpy(key, info.uri, sizeof(key));
916
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 271 times.
272 } else if (av_strstart(line, "#EXT-X-MEDIA:", &ptr)) {
917 1 struct rendition_info info = {{0}};
918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (pls) {
919 av_log(c->ctx, AV_LOG_ERROR,
920 "Master Playlist tag found in a Media Playlist\n");
921 ret = AVERROR_INVALIDDATA;
922 goto fail;
923 }
924 1 ff_parse_key_value(ptr, handle_rendition_args, &info);
925 1 new_rendition(c, &info, url);
926
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 254 times.
271 } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {
927 int64_t t;
928 17 ret = ensure_playlist(c, &pls, url);
929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (ret < 0)
930 goto fail;
931 17 t = strtoll(ptr, NULL, 10);
932
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
17 if (t < 0 || t >= INT64_MAX / AV_TIME_BASE) {
933 ret = AVERROR_INVALIDDATA;
934 goto fail;
935 }
936 17 pls->target_duration = t * AV_TIME_BASE;
937
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 238 times.
254 } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
938 uint64_t seq_no;
939 16 ret = ensure_playlist(c, &pls, url);
940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (ret < 0)
941 goto fail;
942 16 seq_no = strtoull(ptr, NULL, 10);
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (seq_no > INT64_MAX/2) {
944 av_log(c->ctx, AV_LOG_DEBUG, "MEDIA-SEQUENCE higher than "
945 "INT64_MAX/2, mask out the highest bit\n");
946 seq_no &= INT64_MAX/2;
947 }
948 16 pls->start_seq_no = seq_no;
949
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 237 times.
238 } else if (av_strstart(line, "#EXT-X-PLAYLIST-TYPE:", &ptr)) {
950 1 ret = ensure_playlist(c, &pls, url);
951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
952 goto fail;
953
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!strcmp(ptr, "EVENT"))
954 1 pls->type = PLS_TYPE_EVENT;
955 else if (!strcmp(ptr, "VOD"))
956 pls->type = PLS_TYPE_VOD;
957
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 236 times.
237 } else if (av_strstart(line, "#EXT-X-MAP:", &ptr)) {
958 1 struct init_section_info info = {{0}};
959 1 ret = ensure_playlist(c, &pls, url);
960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
961 goto fail;
962 1 ff_parse_key_value(ptr, handle_init_section_args, &info);
963 1 cur_init_section = new_init_section(pls, &info, url);
964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!cur_init_section) {
965 ret = AVERROR(ENOMEM);
966 goto fail;
967 }
968 1 cur_init_section->key_type = key_type;
969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (has_iv) {
970 memcpy(cur_init_section->iv, iv, sizeof(iv));
971 } else {
972 1 int64_t seq = pls->start_seq_no + pls->n_segments;
973 1 memset(cur_init_section->iv, 0, sizeof(cur_init_section->iv));
974 1 AV_WB64(cur_init_section->iv + 8, seq);
975 }
976
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (key_type != KEY_NONE) {
978 ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key);
979 if (!tmp_str[0]) {
980 av_free(cur_init_section);
981 ret = AVERROR_INVALIDDATA;
982 goto fail;
983 }
984 cur_init_section->key = av_strdup(tmp_str);
985 if (!cur_init_section->key) {
986 av_free(cur_init_section);
987 ret = AVERROR(ENOMEM);
988 goto fail;
989 }
990 } else {
991 1 cur_init_section->key = NULL;
992 }
993
994
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 236 times.
236 } else if (av_strstart(line, "#EXT-X-START:", &ptr)) {
995 const char *time_offset_value = NULL;
996 ret = ensure_playlist(c, &pls, url);
997 if (ret < 0) {
998 goto fail;
999 }
1000 if (av_strstart(ptr, "TIME-OFFSET=", &time_offset_value)) {
1001 double offset = strtod(time_offset_value, NULL) * AV_TIME_BASE;
1002 if (offset >= -0x1p63 && offset < 0x1p63) {
1003 pls->start_time_offset = offset;
1004 pls->time_offset_flag = 1;
1005 } else {
1006 av_log(c->ctx, AV_LOG_WARNING, "TIME-OFFSET value is"
1007 "invalid, it will be ignored");
1008 }
1009 } else {
1010 av_log(c->ctx, AV_LOG_WARNING, "#EXT-X-START value is"
1011 "invalid, it will be ignored");
1012 continue;
1013 }
1014
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 221 times.
236 } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) {
1015
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (pls)
1016 15 pls->finished = 1;
1017
2/2
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 141 times.
221 } else if (av_strstart(line, "#EXTINF:", &ptr)) {
1018 80 double d = atof(ptr) * AV_TIME_BASE;
1019
3/6
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 80 times.
80 if (d < 0 || d > INT64_MAX || isnan(d)) {
1020 av_log(c->ctx, AV_LOG_WARNING, "EXTINF %f unsupported\n", d / AV_TIME_BASE);
1021 d = 0;
1022 }
1023 80 duration = d;
1024 80 is_segment = 1;
1025
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 121 times.
141 } else if (av_strstart(line, "#EXT-X-BYTERANGE:", &ptr)) {
1026 20 seg_size = strtoll(ptr, NULL, 10);
1027 20 ptr = strchr(ptr, '@');
1028
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (ptr)
1029 20 seg_offset = strtoll(ptr+1, NULL, 10);
1030
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (seg_size < 0 || seg_offset > INT64_MAX - seg_size) {
1031 ret = AVERROR_INVALIDDATA;
1032 goto fail;
1033 }
1034
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 100 times.
121 } else if (av_strstart(line, "#", NULL)) {
1035 21 av_log(c->ctx, AV_LOG_VERBOSE, "Skip ('%s')\n", line);
1036 21 continue;
1037
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 19 times.
100 } else if (line[0]) {
1038
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 80 times.
81 if (is_variant) {
1039
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!new_variant(c, &variant_info, line, url)) {
1040 ret = AVERROR(ENOMEM);
1041 goto fail;
1042 }
1043 1 is_variant = 0;
1044 }
1045
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 1 times.
81 if (is_segment) {
1046 struct segment *seg;
1047 80 ret = ensure_playlist(c, &pls, url);
1048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (ret < 0)
1049 goto fail;
1050 80 seg = av_malloc(sizeof(struct segment));
1051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (!seg) {
1052 ret = AVERROR(ENOMEM);
1053 goto fail;
1054 }
1055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (has_iv) {
1056 memcpy(seg->iv, iv, sizeof(iv));
1057 } else {
1058 80 uint64_t seq = pls->start_seq_no + (uint64_t)pls->n_segments;
1059 80 memset(seg->iv, 0, sizeof(seg->iv));
1060 80 AV_WB64(seg->iv + 8, seq);
1061 }
1062
1063
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (key_type != KEY_NONE) {
1064 ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key);
1065 if (!tmp_str[0]) {
1066 ret = AVERROR_INVALIDDATA;
1067 av_free(seg);
1068 goto fail;
1069 }
1070 seg->key = av_strdup(tmp_str);
1071 if (!seg->key) {
1072 av_free(seg);
1073 ret = AVERROR(ENOMEM);
1074 goto fail;
1075 }
1076 } else {
1077 80 seg->key = NULL;
1078 }
1079
1080 80 ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, line);
1081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (!tmp_str[0]) {
1082 ret = AVERROR_INVALIDDATA;
1083 if (seg->key)
1084 av_free(seg->key);
1085 av_free(seg);
1086 goto fail;
1087 }
1088 80 seg->url = av_strdup(tmp_str);
1089
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (!seg->url) {
1090 av_free(seg->key);
1091 av_free(seg);
1092 ret = AVERROR(ENOMEM);
1093 goto fail;
1094 }
1095
1096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 ret = test_segment(c->ctx, pls->ctx ? pls->ctx->iformat : NULL, pls, seg);
1097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (ret < 0) {
1098 av_free(seg->url);
1099 av_free(seg->key);
1100 av_free(seg);
1101 goto fail;
1102 }
1103
1104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (duration < 0.001 * AV_TIME_BASE) {
1105 av_log(c->ctx, AV_LOG_WARNING, "Cannot get correct #EXTINF value of segment %s,"
1106 " set to default value to 1ms.\n", seg->url);
1107 duration = 0.001 * AV_TIME_BASE;
1108 }
1109 80 seg->duration = duration;
1110 80 seg->key_type = key_type;
1111 80 dynarray_add(&pls->segments, &pls->n_segments, seg);
1112 80 is_segment = 0;
1113
1114 80 seg->size = seg_size;
1115
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 60 times.
80 if (seg_size >= 0) {
1116 20 seg->url_offset = seg_offset;
1117 20 seg_offset += seg_size;
1118 20 seg_size = -1;
1119 } else {
1120 60 seg->url_offset = 0;
1121 60 seg_offset = 0;
1122 }
1123
1124 80 seg->init_section = cur_init_section;
1125 }
1126 }
1127 }
1128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (prev_segments) {
1129 if (pls->start_seq_no > prev_start_seq_no && c->first_timestamp != AV_NOPTS_VALUE &&
1130 c->first_timestamp_pls == pls) {
1131 int64_t prev_timestamp = c->first_timestamp;
1132 int i;
1133 int64_t diff = pls->start_seq_no - prev_start_seq_no;
1134 for (i = 0; i < prev_n_segments && i < diff; i++) {
1135 c->first_timestamp += prev_segments[i]->duration;
1136 }
1137 av_log(c->ctx, AV_LOG_DEBUG, "Media sequence change (%"PRId64" -> %"PRId64")"
1138 " reflected in first_timestamp: %"PRId64" -> %"PRId64"\n",
1139 prev_start_seq_no, pls->start_seq_no,
1140 prev_timestamp, c->first_timestamp);
1141 } else if (pls->start_seq_no < prev_start_seq_no) {
1142 av_log(c->ctx, AV_LOG_WARNING, "Media sequence changed unexpectedly: %"PRId64" -> %"PRId64"\n",
1143 prev_start_seq_no, pls->start_seq_no);
1144 }
1145 free_segment_dynarray(prev_segments, prev_n_segments);
1146 av_freep(&prev_segments);
1147 }
1148
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 if (pls)
1149 17 pls->last_load_time = av_gettime_relative();
1150
1151 1 fail:
1152 18 av_free(new_url);
1153
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (close_in)
1154 2 ff_format_io_close(c->ctx, &in);
1155 18 c->ctx->ctx_flags = c->ctx->ctx_flags & ~(unsigned)AVFMTCTX_UNSEEKABLE;
1156
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 if (!c->n_variants || !c->variants[0]->n_playlists ||
1157
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 !(c->variants[0]->playlists[0]->finished ||
1158
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT))
1159 3 c->ctx->ctx_flags |= AVFMTCTX_UNSEEKABLE;
1160
1161
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 if (c->n_variants && c->variants[0]->n_playlists &&
1162
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT &&
1163
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !c->variants[0]->playlists[0]->finished) {
1164 1 struct playlist *p = c->variants[0]->playlists[0];
1165 1 int64_t duration = 0;
1166
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 for (int i = 0; i < p->n_segments; i++)
1167 7 duration += p->segments[i]->duration;
1168 1 c->ctx->duration = duration;
1169 }
1170
1171 18 return ret;
1172 }
1173
1174 8276 static struct segment *current_segment(struct playlist *pls)
1175 {
1176 8276 int64_t n = pls->cur_seq_no - pls->start_seq_no;
1177
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8271 times.
8276 if (n >= pls->n_segments)
1178 5 return NULL;
1179 8271 return pls->segments[n];
1180 }
1181
1182 490 static struct segment *next_segment(struct playlist *pls)
1183 {
1184 490 int64_t n = pls->cur_seq_no - pls->start_seq_no + 1;
1185
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 409 times.
490 if (n >= pls->n_segments)
1186 81 return NULL;
1187 409 return pls->segments[n];
1188 }
1189
1190 /* True if 'next' can be reached by seeking the open 'in' instead of reopening.
1191 * An unencrypted, contiguous byte range directly following 'cur' in the same
1192 * seekable resource (i.e. consecutive EXT-X-BYTERANGE segments). */
1193 17 static int segment_reusable(AVIOContext *in, const struct segment *cur,
1194 const struct segment *next)
1195 {
1196
3/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 2 times.
17 return in && cur && next &&
1197
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 (in->seekable & AVIO_SEEKABLE_NORMAL) &&
1198
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 cur->size >= 0 && next->size >= 0 &&
1199
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 next->url_offset == cur->url_offset + cur->size &&
1200
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 cur->key_type == KEY_NONE && next->key_type == KEY_NONE &&
1201
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
49 next->init_section == cur->init_section &&
1202
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 !strcmp(next->url, cur->url);
1203 }
1204
1205 473 static int read_from_url(struct playlist *pls, struct segment *seg,
1206 uint8_t *buf, int buf_size)
1207 {
1208 int ret;
1209
1210 /* limit read if the segment was only a part of a file */
1211
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 373 times.
473 if (seg->size >= 0)
1212 100 buf_size = FFMIN(buf_size, seg->size - pls->cur_seg_offset);
1213
1214 473 ret = avio_read(pls->input, buf, buf_size);
1215
2/2
✓ Branch 0 taken 405 times.
✓ Branch 1 taken 68 times.
473 if (ret > 0)
1216 405 pls->cur_seg_offset += ret;
1217
1218 473 return ret;
1219 }
1220
1221 /* Parse the raw ID3 data and pass contents to caller */
1222 static void parse_id3(AVFormatContext *s, AVIOContext *pb,
1223 AVDictionary **metadata, int64_t *dts, HLSAudioSetupInfo *audio_setup_info,
1224 ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta **extra_meta)
1225 {
1226 static const char id3_priv_owner_ts[] = "com.apple.streaming.transportStreamTimestamp";
1227 static const char id3_priv_owner_audio_setup[] = "com.apple.streaming.audioDescription";
1228 ID3v2ExtraMeta *meta;
1229
1230 ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta);
1231 for (meta = *extra_meta; meta; meta = meta->next) {
1232 if (!strcmp(meta->tag, "PRIV")) {
1233 ID3v2ExtraMetaPRIV *priv = &meta->data.priv;
1234 if (priv->datasize == 8 && !av_strncasecmp(priv->owner, id3_priv_owner_ts, 44)) {
1235 /* 33-bit MPEG timestamp */
1236 int64_t ts = AV_RB64(priv->data);
1237 av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp %"PRId64"\n", ts);
1238 if ((ts & ~((1ULL << 33) - 1)) == 0)
1239 *dts = ts;
1240 else
1241 av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio timestamp %"PRId64"\n", ts);
1242 } else if (priv->datasize >= 8 && !av_strncasecmp(priv->owner, id3_priv_owner_audio_setup, 36)) {
1243 ff_hls_senc_read_audio_setup_info(audio_setup_info, priv->data, priv->datasize);
1244 }
1245 } else if (!strcmp(meta->tag, "APIC") && apic)
1246 *apic = &meta->data.apic;
1247 }
1248 }
1249
1250 /* Check if the ID3 metadata contents have changed */
1251 static int id3_has_changed_values(struct playlist *pls, AVDictionary *metadata,
1252 ID3v2ExtraMetaAPIC *apic)
1253 {
1254 const AVDictionaryEntry *entry = NULL;
1255 const AVDictionaryEntry *oldentry;
1256 /* check that no keys have changed values */
1257 while ((entry = av_dict_iterate(metadata, entry))) {
1258 oldentry = av_dict_get(pls->id3_initial, entry->key, NULL, AV_DICT_MATCH_CASE);
1259 if (!oldentry || strcmp(oldentry->value, entry->value) != 0)
1260 return 1;
1261 }
1262
1263 /* check if apic appeared */
1264 if (apic && (pls->ctx->nb_streams != 2 || !pls->ctx->streams[1]->attached_pic.data))
1265 return 1;
1266
1267 if (apic) {
1268 int size = pls->ctx->streams[1]->attached_pic.size;
1269 if (size != apic->buf->size - AV_INPUT_BUFFER_PADDING_SIZE)
1270 return 1;
1271
1272 if (memcmp(apic->buf->data, pls->ctx->streams[1]->attached_pic.data, size) != 0)
1273 return 1;
1274 }
1275
1276 return 0;
1277 }
1278
1279 /* Parse ID3 data and handle the found data */
1280 static void handle_id3(AVIOContext *pb, struct playlist *pls)
1281 {
1282 AVDictionary *metadata = NULL;
1283 ID3v2ExtraMetaAPIC *apic = NULL;
1284 ID3v2ExtraMeta *extra_meta = NULL;
1285 int64_t timestamp = AV_NOPTS_VALUE;
1286
1287 parse_id3(pls->ctx, pb, &metadata, &timestamp, &pls->audio_setup_info, &apic, &extra_meta);
1288
1289 if (timestamp != AV_NOPTS_VALUE) {
1290 pls->id3_mpegts_timestamp = timestamp;
1291 pls->id3_offset = 0;
1292 }
1293
1294 if (!pls->id3_found) {
1295 /* initial ID3 tags */
1296 av_assert0(!pls->id3_deferred_extra);
1297 pls->id3_found = 1;
1298
1299 /* get picture attachment and set text metadata */
1300 if (pls->ctx->nb_streams)
1301 ff_id3v2_parse_apic(pls->ctx, extra_meta);
1302 else
1303 /* demuxer not yet opened, defer picture attachment */
1304 pls->id3_deferred_extra = extra_meta;
1305
1306 ff_id3v2_parse_priv_dict(&metadata, extra_meta);
1307 av_dict_copy(&pls->ctx->metadata, metadata, 0);
1308 pls->id3_initial = metadata;
1309
1310 } else {
1311 if (!pls->id3_changed && id3_has_changed_values(pls, metadata, apic)) {
1312 avpriv_report_missing_feature(pls->parent, "Changing ID3 metadata in HLS audio elementary stream");
1313 pls->id3_changed = 1;
1314 }
1315 av_dict_free(&metadata);
1316 }
1317
1318 if (!pls->id3_deferred_extra)
1319 ff_id3v2_free_extra_meta(&extra_meta);
1320 }
1321
1322 16 static void intercept_id3(struct playlist *pls, uint8_t *buf,
1323 int buf_size, int *len)
1324 {
1325 /* intercept id3 tags, we do not want to pass them to the raw
1326 * demuxer on all segment switches */
1327 int bytes;
1328 16 int id3_buf_pos = 0;
1329 16 int fill_buf = 0;
1330 16 struct segment *seg = current_segment(pls);
1331
1332 /* gather all the id3 tags */
1333 while (1) {
1334 /* see if we can retrieve enough data for ID3 header */
1335
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
16 if (*len < ID3v2_HEADER_SIZE && buf_size >= ID3v2_HEADER_SIZE) {
1336 bytes = read_from_url(pls, seg, buf + *len, ID3v2_HEADER_SIZE - *len);
1337 if (bytes > 0) {
1338
1339 if (bytes == ID3v2_HEADER_SIZE - *len)
1340 /* no EOF yet, so fill the caller buffer again after
1341 * we have stripped the ID3 tags */
1342 fill_buf = 1;
1343
1344 *len += bytes;
1345
1346 } else if (*len <= 0) {
1347 /* error/EOF */
1348 *len = bytes;
1349 fill_buf = 0;
1350 }
1351 }
1352
1353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (*len < ID3v2_HEADER_SIZE)
1354 break;
1355
1356
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if (ff_id3v2_match(buf, ID3v2_DEFAULT_MAGIC)) {
1357 int64_t maxsize = seg->size >= 0 ? seg->size : 1024*1024;
1358 int taglen = ff_id3v2_tag_len(buf);
1359 int tag_got_bytes = FFMIN(taglen, *len);
1360 int remaining = taglen - tag_got_bytes;
1361
1362 if (taglen > maxsize) {
1363 av_log(pls->parent, AV_LOG_ERROR, "Too large HLS ID3 tag (%d > %"PRId64" bytes)\n",
1364 taglen, maxsize);
1365 break;
1366 }
1367
1368 /*
1369 * Copy the id3 tag to our temporary id3 buffer.
1370 * We could read a small id3 tag directly without memcpy, but
1371 * we would still need to copy the large tags, and handling
1372 * both of those cases together with the possibility for multiple
1373 * tags would make the handling a bit complex.
1374 */
1375 pls->id3_buf = av_fast_realloc(pls->id3_buf, &pls->id3_buf_size, id3_buf_pos + taglen);
1376 if (!pls->id3_buf)
1377 break;
1378 memcpy(pls->id3_buf + id3_buf_pos, buf, tag_got_bytes);
1379 id3_buf_pos += tag_got_bytes;
1380
1381 /* strip the intercepted bytes */
1382 *len -= tag_got_bytes;
1383 memmove(buf, buf + tag_got_bytes, *len);
1384 av_log(pls->parent, AV_LOG_DEBUG, "Stripped %d HLS ID3 bytes\n", tag_got_bytes);
1385
1386 if (remaining > 0) {
1387 /* read the rest of the tag in */
1388 if (read_from_url(pls, seg, pls->id3_buf + id3_buf_pos, remaining) != remaining)
1389 break;
1390 id3_buf_pos += remaining;
1391 av_log(pls->parent, AV_LOG_DEBUG, "Stripped additional %d HLS ID3 bytes\n", remaining);
1392 }
1393
1394 } else {
1395 /* no more ID3 tags */
1396 16 break;
1397 }
1398 }
1399
1400 /* re-fill buffer for the caller unless EOF */
1401
3/6
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
16 if (*len >= 0 && (fill_buf || *len == 0)) {
1402 bytes = read_from_url(pls, seg, buf + *len, buf_size - *len);
1403
1404 /* ignore error if we already had some data */
1405 if (bytes >= 0)
1406 *len += bytes;
1407 else if (*len == 0)
1408 *len = bytes;
1409 }
1410
1411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (pls->id3_buf) {
1412 /* Now parse all the ID3 tags */
1413 FFIOContext id3ioctx;
1414 ffio_init_read_context(&id3ioctx, pls->id3_buf, id3_buf_pos);
1415 handle_id3(&id3ioctx.pub, pls);
1416 }
1417
1418
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (pls->is_id3_timestamped == -1)
1419 16 pls->is_id3_timestamped = (pls->id3_mpegts_timestamp != AV_NOPTS_VALUE);
1420 16 }
1421
1422 static int read_key(HLSContext *c, struct playlist *pls, struct segment *seg)
1423 {
1424 AVIOContext *pb = NULL;
1425
1426 int ret = open_url(pls->parent, &pb, seg->key, &c->avio_opts, NULL, NULL);
1427 if (ret < 0) {
1428 av_log(pls->parent, AV_LOG_ERROR, "Unable to open key file %s, %s\n",
1429 seg->key, av_err2str(ret));
1430 return ret;
1431 }
1432
1433 ret = avio_read(pb, pls->key, sizeof(pls->key));
1434 ff_format_io_close(pls->parent, &pb);
1435 if (ret != sizeof(pls->key)) {
1436 if (ret < 0) {
1437 av_log(pls->parent, AV_LOG_ERROR, "Unable to read key file %s, %s\n",
1438 seg->key, av_err2str(ret));
1439 } else {
1440 av_log(pls->parent, AV_LOG_ERROR, "Unable to read key file %s, read bytes %d != %zu\n",
1441 seg->key, ret, sizeof(pls->key));
1442 ret = AVERROR_INVALIDDATA;
1443 }
1444
1445 return ret;
1446 }
1447
1448 av_strlcpy(pls->key_url, seg->key, sizeof(pls->key_url));
1449
1450 return 0;
1451 }
1452
1453 127 static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, AVIOContext **in)
1454 {
1455 127 AVDictionary *opts = NULL;
1456 int ret;
1457 127 int is_http = 0;
1458
1459 /* Reuse a kept-open connection to the same resource by seeking instead of
1460 * reopening. For contiguous ranges the seek is a no-op and issues no request. */
1461
4/6
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
127 if (*in && pls->input_reuse && seg->key_type == KEY_NONE &&
1462
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 ((*in)->seekable & AVIO_SEEKABLE_NORMAL)) {
1463 15 int64_t seek_ret = avio_seek(*in, seg->url_offset, SEEK_SET);
1464 15 pls->input_reuse = 0;
1465
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (seek_ret >= 0) {
1466 15 av_log(pls->parent, AV_LOG_VERBOSE,
1467 "HLS reusing connection for url '%s', offset %"PRId64", playlist %d\n",
1468 seg->url, seg->url_offset, pls->index);
1469 15 pls->input_read_done = 0;
1470 15 pls->cur_seg_offset = 0;
1471 15 return 0;
1472 }
1473 /* Seek failed: drop the connection and reopen. */
1474 ff_format_io_close(pls->parent, in);
1475 }
1476 112 pls->input_reuse = 0;
1477
1478
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (c->http_persistent)
1479 112 av_dict_set(&opts, "multiple_requests", "1", 0);
1480
1481
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 107 times.
112 if (seg->size >= 0) {
1482 /* Restrict the request to the wanted byte range. The end is extended
1483 * across following contiguous segments of the same resource so one
1484 * connection serves the whole run. */
1485 5 int64_t end_offset = seg->url_offset + seg->size;
1486
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if (seg == current_segment(pls)) {
1487 5 int64_t n = pls->cur_seq_no - pls->start_seq_no + 1;
1488
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 while (n < pls->n_segments) {
1489 18 struct segment *ns = pls->segments[n];
1490
3/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 3 times.
18 if (ns->size < 0 || ns->url_offset != end_offset ||
1491
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 ns->key_type != KEY_NONE ||
1492
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 ns->init_section != seg->init_section ||
1493
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 strcmp(ns->url, seg->url))
1494 break;
1495 15 end_offset = ns->url_offset + ns->size;
1496 15 n++;
1497 }
1498 }
1499 5 av_dict_set_int(&opts, "offset", seg->url_offset, 0);
1500 5 av_dict_set_int(&opts, "end_offset", end_offset, 0);
1501 }
1502
1503 112 av_log(pls->parent, AV_LOG_VERBOSE, "HLS request for url '%s', offset %"PRId64", playlist %d\n",
1504 seg->url, seg->url_offset, pls->index);
1505
1506
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
112 if (seg->key_type == KEY_AES_128 || seg->key_type == KEY_SAMPLE_AES) {
1507 if (strcmp(seg->key, pls->key_url)) {
1508 ret = read_key(c, pls, seg);
1509 if (ret < 0)
1510 goto cleanup;
1511 }
1512 }
1513
1514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (seg->key_type == KEY_AES_128) {
1515 char iv[33], key[33], url[MAX_URL_SIZE];
1516 ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0);
1517 ff_data_to_hex(key, pls->key, sizeof(pls->key), 0);
1518 if (strstr(seg->url, "://"))
1519 snprintf(url, sizeof(url), "crypto+%s", seg->url);
1520 else
1521 snprintf(url, sizeof(url), "crypto:%s", seg->url);
1522
1523 av_dict_set(&opts, "key", key, 0);
1524 av_dict_set(&opts, "iv", iv, 0);
1525
1526 ret = open_url(pls->parent, in, url, &c->avio_opts, opts, &is_http);
1527 if (ret < 0) {
1528 goto cleanup;
1529 }
1530 ret = 0;
1531 } else {
1532 112 ret = open_url(pls->parent, in, seg->url, &c->avio_opts, opts, &is_http);
1533 }
1534
1535 /* Seek to the requested position. If this was a HTTP request, the offset
1536 * should already be where want it to, but this allows e.g. local testing
1537 * without a HTTP server.
1538 *
1539 * This is not done for HTTP at all as avio_seek() does internal bookkeeping
1540 * of file offset which is out-of-sync with the actual offset when "offset"
1541 * AVOption is used with http protocol, causing the seek to not be a no-op
1542 * as would be expected. Wrong offset received from the server will not be
1543 * noticed without the call, though.
1544 */
1545
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
112 if (ret == 0 && !is_http && seg->url_offset) {
1546 int64_t seekret = avio_seek(*in, seg->url_offset, SEEK_SET);
1547 if (seekret < 0) {
1548 av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url);
1549 ret = seekret;
1550 ff_format_io_close(pls->parent, in);
1551 }
1552 }
1553
1554 112 cleanup:
1555 112 av_dict_free(&opts);
1556 112 pls->cur_seg_offset = 0;
1557 112 return ret;
1558 }
1559
1560 126 static int update_init_section(struct playlist *pls, struct segment *seg)
1561 {
1562 static const int max_init_section_size = 1024*1024;
1563 126 HLSContext *c = pls->parent->priv_data;
1564 int64_t sec_size;
1565 int64_t urlsize;
1566 int ret;
1567
1568
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 1 times.
126 if (seg->init_section == pls->cur_init_section)
1569 125 return 0;
1570
1571 1 pls->cur_init_section = NULL;
1572
1573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!seg->init_section)
1574 return 0;
1575
1576 1 ret = open_input(c, pls, seg->init_section, &pls->input);
1577
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1578 av_log(pls->parent, AV_LOG_WARNING,
1579 "Failed to open an initialization section in playlist %d\n",
1580 pls->index);
1581 return ret;
1582 }
1583
1584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (seg->init_section->size >= 0)
1585 sec_size = seg->init_section->size;
1586
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 else if ((urlsize = avio_size(pls->input)) >= 0)
1587 1 sec_size = urlsize;
1588 else
1589 sec_size = max_init_section_size;
1590
1591 1 av_log(pls->parent, AV_LOG_DEBUG,
1592 "Downloading an initialization section of size %"PRId64"\n",
1593 sec_size);
1594
1595 1 sec_size = FFMIN(sec_size, max_init_section_size);
1596
1597 1 av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size);
1598
1599 1 ret = read_from_url(pls, seg->init_section, pls->init_sec_buf,
1600 1 pls->init_sec_buf_size);
1601 1 ff_format_io_close(pls->parent, &pls->input);
1602
1603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
1604 return ret;
1605
1606 1 pls->cur_init_section = seg->init_section;
1607 1 pls->init_sec_data_len = ret;
1608 1 pls->init_sec_buf_read_offset = 0;
1609
1610 /* spec says audio elementary streams do not have media initialization
1611 * sections, so there should be no ID3 timestamps */
1612 1 pls->is_id3_timestamped = 0;
1613
1614 1 return 0;
1615 }
1616
1617 167 static int64_t default_reload_interval(struct playlist *pls)
1618 {
1619 167 return pls->n_segments > 0 ?
1620
1/2
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
167 pls->segments[pls->n_segments - 1]->duration :
1621 pls->target_duration;
1622 }
1623
1624 7459 static int playlist_needed(struct playlist *pls)
1625 {
1626 7459 AVFormatContext *s = pls->parent;
1627 int i, j;
1628 7459 int stream_needed = 0;
1629 int first_st;
1630
1631 /* If there is no context or streams yet, the playlist is needed */
1632
4/6
✓ Branch 0 taken 7459 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 7419 times.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
7459 if ((!pls->ctx || !pls->n_main_streams) && !pls->is_subtitle)
1633 40 return 1;
1634
1635 /* check if any of the streams in the playlist are needed */
1636
1/2
✓ Branch 0 taken 7419 times.
✗ Branch 1 not taken.
7419 for (i = 0; i < pls->n_main_streams; i++) {
1637
1/2
✓ Branch 0 taken 7419 times.
✗ Branch 1 not taken.
7419 if (pls->main_streams[i]->discard < AVDISCARD_ALL) {
1638 7419 stream_needed = 1;
1639 7419 break;
1640 }
1641 }
1642
1643 /* If all streams in the playlist were discarded, the playlist is not
1644 * needed (regardless of whether whole programs are discarded or not). */
1645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7419 times.
7419 if (!stream_needed)
1646 return 0;
1647
1648 /* Otherwise, check if all the programs (variants) this playlist is in are
1649 * discarded. Since all streams in the playlist are part of the same programs
1650 * we can just check the programs of the first stream. */
1651
1652 7419 first_st = pls->main_streams[0]->index;
1653
1654
1/2
✓ Branch 0 taken 7419 times.
✗ Branch 1 not taken.
7419 for (i = 0; i < s->nb_programs; i++) {
1655 7419 AVProgram *program = s->programs[i];
1656
1/2
✓ Branch 0 taken 7419 times.
✗ Branch 1 not taken.
7419 if (program->discard < AVDISCARD_ALL) {
1657
1/2
✓ Branch 0 taken 7620 times.
✗ Branch 1 not taken.
7620 for (j = 0; j < program->nb_stream_indexes; j++) {
1658
2/2
✓ Branch 0 taken 7419 times.
✓ Branch 1 taken 201 times.
7620 if (program->stream_index[j] == first_st) {
1659 /* playlist is in an undiscarded program */
1660 7419 return 1;
1661 }
1662 }
1663 }
1664 }
1665
1666 /* some streams were not discarded but all the programs were */
1667 return 0;
1668 }
1669
1670 514 static int reload_playlist(struct playlist *v, HLSContext *c)
1671 {
1672 514 int ret = 0;
1673 514 int reload_count = 0;
1674
1675 514 v->needed = playlist_needed(v);
1676
1677
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
514 if (!v->needed)
1678 return AVERROR_EOF;
1679
1680
5/6
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 152 times.
✓ Branch 2 taken 362 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 347 times.
514 if (!v->input || (c->http_persistent && v->input_read_done)) {
1681 int64_t reload_interval;
1682
1683 /* Check that the playlist is still needed before opening a new
1684 * segment. */
1685 167 v->needed = playlist_needed(v);
1686
1687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (!v->needed) {
1688 av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d ('%s')\n",
1689 v->index, v->url);
1690 return AVERROR_EOF;
1691 }
1692
1693 /* If this is a live stream and the reload interval has elapsed since
1694 * the last playlist reload, reload the playlists now. */
1695 167 reload_interval = default_reload_interval(v);
1696
1697 167 reload:
1698 167 reload_count++;
1699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (reload_count > c->max_reload)
1700 return AVERROR_EOF;
1701
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 160 times.
167 if (!v->finished &&
1702
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 av_gettime_relative() - v->last_load_time >= reload_interval) {
1703 if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) {
1704 if (ret != AVERROR_EXIT)
1705 av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n",
1706 v->index);
1707 return ret;
1708 }
1709 /* If we need to reload the playlist again below (if
1710 * there's still no more segments), switch to a reload
1711 * interval of half the target duration. */
1712 reload_interval = v->target_duration / 2;
1713 }
1714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (v->cur_seq_no < v->start_seq_no) {
1715 av_log(v->parent, AV_LOG_WARNING,
1716 "skipping %"PRId64" segments ahead, expired from playlists\n",
1717 v->start_seq_no - v->cur_seq_no);
1718 v->cur_seq_no = v->start_seq_no;
1719 }
1720
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 94 times.
167 if (v->cur_seq_no > v->last_seq_no) {
1721 73 v->last_seq_no = v->cur_seq_no;
1722 73 v->m3u8_hold_counters = 0;
1723
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 } else if (v->last_seq_no == v->cur_seq_no) {
1724 94 v->m3u8_hold_counters++;
1725
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 if (v->m3u8_hold_counters >= c->m3u8_hold_counters) {
1726 return AVERROR_EOF;
1727 }
1728 } else {
1729 av_log(v->parent, AV_LOG_WARNING, "The m3u8 list sequence may have been wrapped.\n");
1730 }
1731
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 126 times.
167 if (v->cur_seq_no >= v->start_seq_no + v->n_segments) {
1732
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
41 if (v->finished || v->is_subtitle)
1733 41 return AVERROR_EOF;
1734 while (av_gettime_relative() - v->last_load_time < reload_interval) {
1735 if (ff_check_interrupt(c->interrupt_callback))
1736 return AVERROR_EXIT;
1737 av_usleep(100*1000);
1738 }
1739 /* Enough time has elapsed since the last reload */
1740 goto reload;
1741 }
1742
1743 }
1744 473 return ret;
1745 }
1746
1747 446 static int read_data_continuous(void *opaque, uint8_t *buf, int buf_size)
1748 {
1749 446 struct playlist *v = opaque;
1750 446 HLSContext *c = v->parent->priv_data;
1751 int ret;
1752 446 int just_opened = 0;
1753 446 int segment_retries = 0;
1754 struct segment *seg;
1755
1756
2/4
✓ Branch 0 taken 446 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 446 times.
446 if (c->http_persistent && v->input_read_done) {
1757 ret = reload_playlist(v, c);
1758 if (ret < 0)
1759 return ret;
1760 }
1761
1762 446 v->input_read_done = 0;
1763
1764 68 restart:
1765 514 ret = reload_playlist(v, c);
1766
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 473 times.
514 if (ret < 0)
1767 41 return ret;
1768
1769 473 seg = current_segment(v);
1770
1771
4/4
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 347 times.
473 if (!v->input || v->input_read_done) {
1772 /* load/update Media Initialization Section, if any */
1773 126 ret = update_init_section(v, seg);
1774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (ret)
1775 return ret;
1776
1777
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
126 if (c->http_multiple == 1 && v->input_next_requested) {
1778 FFSWAP(AVIOContext *, v->input, v->input_next);
1779 v->cur_seg_offset = 0;
1780 v->input_next_requested = 0;
1781 ret = 0;
1782 } else {
1783 126 ret = open_input(c, v, seg, &v->input);
1784 }
1785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (ret < 0) {
1786 if (ff_check_interrupt(c->interrupt_callback))
1787 return AVERROR_EXIT;
1788 av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %"PRId64" of playlist %d\n",
1789 v->cur_seq_no,
1790 v->index);
1791 if (segment_retries >= c->seg_max_retry) {
1792 av_log(v->parent, AV_LOG_WARNING, "Segment %"PRId64" of playlist %d failed too many times, skipping\n",
1793 v->cur_seq_no,
1794 v->index);
1795 v->cur_seq_no++;
1796 segment_retries = 0;
1797 } else {
1798 segment_retries++;
1799 }
1800 goto restart;
1801 }
1802 126 segment_retries = 0;
1803 126 just_opened = 1;
1804 }
1805
1806
1/2
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
473 if (c->http_multiple == -1) {
1807 473 uint8_t *http_version_opt = NULL;
1808 473 int r = av_opt_get(v->input, "http_version", AV_OPT_SEARCH_CHILDREN, &http_version_opt);
1809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 473 times.
473 if (r >= 0) {
1810 c->http_multiple = (!strncmp((const char *)http_version_opt, "1.1", 3) || !strncmp((const char *)http_version_opt, "2.0", 3));
1811 av_freep(&http_version_opt);
1812 }
1813 }
1814
1815 473 seg = next_segment(v);
1816
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 473 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
473 if (c->http_multiple == 1 && !v->input_next_requested &&
1817 seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL) &&
1818 !segment_reusable(v->input, current_segment(v), seg)) {
1819 ret = open_input(c, v, seg, &v->input_next);
1820 if (ret < 0) {
1821 if (ff_check_interrupt(c->interrupt_callback))
1822 return AVERROR_EXIT;
1823 av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %"PRId64" of playlist %d\n",
1824 v->cur_seq_no + 1,
1825 v->index);
1826 } else {
1827 v->input_next_requested = 1;
1828 }
1829 }
1830
1831
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 472 times.
473 if (v->init_sec_buf_read_offset < v->init_sec_data_len) {
1832 /* Push init section out first before first actual segment */
1833 1 int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size);
1834 1 memcpy(buf, v->init_sec_buf, copy_size);
1835 1 v->init_sec_buf_read_offset += copy_size;
1836 1 return copy_size;
1837 }
1838
1839 472 seg = current_segment(v);
1840 472 ret = read_from_url(v, seg, buf, buf_size);
1841
2/2
✓ Branch 0 taken 404 times.
✓ Branch 1 taken 68 times.
472 if (ret > 0) {
1842
4/4
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 279 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 109 times.
404 if (just_opened && v->is_id3_timestamped != 0) {
1843 /* Intercept ID3 tags here, elementary audio streams are required
1844 * to convey timestamps using them in the beginning of each segment. */
1845 16 intercept_id3(v, buf, buf_size, &ret);
1846 }
1847
1848 404 return ret;
1849 }
1850
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 51 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 2 times.
68 if (ret == 0 && segment_reusable(v->input, seg, next_segment(v))) {
1851 /* Clean boundary, and the next segment continues this resource. Keep
1852 * the connection open and read it as a whole. Note that splitting
1853 * segments in these cases is useful for dynamic variant/quality
1854 * switching, but this is not supported by our HLS demuxer, so we
1855 * join the ranges. */
1856 15 v->input_reuse = 1;
1857 15 v->input_read_done = 1;
1858
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 } else if (c->http_persistent &&
1859
2/4
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 53 times.
53 seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) {
1860 v->input_read_done = 1;
1861 } else {
1862 53 ff_format_io_close(v->parent, &v->input);
1863 }
1864 68 v->cur_seq_no++;
1865
1866 68 c->cur_seq_no = v->cur_seq_no;
1867
1868 68 goto restart;
1869 }
1870
1871 static int read_data_subtitle_segment(void *opaque, uint8_t *buf, int buf_size)
1872 {
1873 struct playlist *v = opaque;
1874 HLSContext *c = v->parent->priv_data;
1875 int ret;
1876 struct segment *seg;
1877
1878 if (!v->needed || v->cur_seq_no - v->start_seq_no >= v->n_segments) {
1879 return AVERROR_EOF;
1880 } else {
1881 seg = current_segment(v);
1882 }
1883
1884 if (!v->input) {
1885 ret = open_input(c, v, seg, &v->input);
1886 if (ret < 0) {
1887 if (ff_check_interrupt(c->interrupt_callback))
1888 return AVERROR_EXIT;
1889 av_log(v->parent, AV_LOG_WARNING, "Failed to open segment of playlist %d\n",
1890 v->index);
1891 return ret;
1892 }
1893 }
1894
1895 return read_from_url(v, seg, buf, buf_size);
1896 }
1897
1898 static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url,
1899 int flags, AVDictionary **opts)
1900 {
1901 av_log(s, AV_LOG_ERROR,
1902 "A HLS playlist item '%s' referred to an external file '%s'. "
1903 "Opening this file was forbidden for security reasons\n",
1904 s->url, url);
1905 return AVERROR(EPERM);
1906 }
1907
1908 static int init_subtitle_context(struct playlist *pls)
1909 {
1910 HLSContext *c = pls->parent->priv_data;
1911 const AVInputFormat *in_fmt;
1912 AVDictionary *opts = NULL;
1913 int ret;
1914
1915 if (!(pls->ctx = avformat_alloc_context()))
1916 return AVERROR(ENOMEM);
1917
1918 pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);
1919 if (!pls->read_buffer) {
1920 avformat_free_context(pls->ctx);
1921 pls->ctx = NULL;
1922 return AVERROR(ENOMEM);
1923 }
1924
1925 ffio_init_context(&pls->pb, pls->read_buffer, INITIAL_BUFFER_SIZE, 0, pls,
1926 read_data_subtitle_segment, NULL, NULL);
1927 pls->pb.pub.seekable = 0;
1928 pls->ctx->pb = &pls->pb.pub;
1929 pls->ctx->io_open = nested_io_open;
1930
1931 ret = ff_copy_whiteblacklists(pls->ctx, pls->parent);
1932 if (ret < 0)
1933 return ret;
1934
1935 in_fmt = av_find_input_format("webvtt");
1936 av_dict_copy(&opts, c->seg_format_opts, 0);
1937 ret = avformat_open_input(&pls->ctx, current_segment(pls)->url, in_fmt, &opts);
1938 av_dict_free(&opts);
1939
1940 return ret;
1941 }
1942
1943 static int read_subtitle_packet(struct playlist *v, AVPacket *pkt)
1944 {
1945 HLSContext *c = v->parent->priv_data;
1946 int ret;
1947
1948 restart:
1949 ret = reload_playlist(v, c);
1950 if (ret < 0)
1951 return ret;
1952
1953 if (v->input && !v->ctx)
1954 ff_format_io_close(v->parent, &v->input);
1955
1956 if (!v->input && !v->ctx) {
1957 ret = init_subtitle_context(v);
1958 if (ret < 0)
1959 return ret;
1960 }
1961
1962 ret = av_read_frame(v->ctx, v->pkt);
1963 if (!ret) {
1964 return ret;
1965 }
1966 ff_format_io_close(v->parent, &v->input);
1967 v->cur_seq_no++;
1968 c->cur_seq_no = v->cur_seq_no;
1969
1970 avformat_close_input(&v->ctx);
1971
1972 goto restart;
1973 }
1974
1975 1 static void add_renditions_to_variant(HLSContext *c, struct variant *var,
1976 enum AVMediaType type, const char *group_id)
1977 {
1978 int i;
1979
1980
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < c->n_renditions; i++) {
1981 1 struct rendition *rend = c->renditions[i];
1982
1983
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (rend->type == type && !strcmp(rend->group_id, group_id)) {
1984
1985
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (rend->playlist)
1986 /* rendition is an external playlist
1987 * => add the playlist to the variant */
1988 1 dynarray_add(&var->playlists, &var->n_playlists, rend->playlist);
1989 else
1990 /* rendition is part of the variant main Media Playlist
1991 * => add the rendition to the main Media Playlist */
1992 dynarray_add(&var->playlists[0]->renditions,
1993 &var->playlists[0]->n_renditions,
1994 rend);
1995 }
1996 }
1997 1 }
1998
1999 51 static void add_metadata_from_renditions(AVFormatContext *s, struct playlist *pls,
2000 enum AVMediaType type)
2001 {
2002 51 int rend_idx = 0;
2003 int i;
2004
2005
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 35 times.
86 for (i = 0; i < pls->n_main_streams; i++) {
2006 51 AVStream *st = pls->main_streams[i];
2007
2008
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 16 times.
51 if (st->codecpar->codec_type != type)
2009 35 continue;
2010
2011
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 for (; rend_idx < pls->n_renditions; rend_idx++) {
2012 1 struct rendition *rend = pls->renditions[rend_idx];
2013
2014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (rend->type != type)
2015 continue;
2016
2017
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (rend->language[0])
2018 av_dict_set(&st->metadata, "language", rend->language, 0);
2019
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (rend->name[0])
2020 1 av_dict_set(&st->metadata, "comment", rend->name, 0);
2021
2022 1 st->disposition |= rend->disposition;
2023 }
2024
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (rend_idx >=pls->n_renditions)
2025 16 break;
2026 }
2027 51 }
2028
2029 /* if timestamp was in valid range: returns 1 and sets seq_no
2030 * if not: returns 0 and sets seq_no to closest segment */
2031 53 static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls,
2032 int64_t timestamp, int64_t *seq_no,
2033 int64_t *seg_start_ts)
2034 {
2035 int i;
2036 106 int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ?
2037
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 0 : c->first_timestamp;
2038
2039
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 33 times.
53 if (timestamp < pos) {
2040 /* Seeking before the start of the playlist, clamp to the first segment. */
2041 20 *seq_no = pls->start_seq_no;
2042
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 9 times.
20 if (seg_start_ts)
2043 11 *seg_start_ts = pos;
2044 20 return 1;
2045 }
2046
2047
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 for (i = 0; i < pls->n_segments; i++) {
2048 39 int64_t diff = pos + pls->segments[i]->duration - timestamp;
2049
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 6 times.
39 if (diff > 0) {
2050 33 *seq_no = pls->start_seq_no + i;
2051
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 17 times.
33 if (seg_start_ts) {
2052 16 *seg_start_ts = pos;
2053 }
2054 33 return 1;
2055 }
2056 6 pos += pls->segments[i]->duration;
2057 }
2058
2059 *seq_no = pls->start_seq_no + pls->n_segments - 1;
2060
2061 return 0;
2062 }
2063
2064 17 static int64_t select_cur_seq_no(HLSContext *c, struct playlist *pls)
2065 {
2066 int64_t seq_no;
2067
2068
3/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
17 if (!pls->finished && !c->first_packet &&
2069 av_gettime_relative() - pls->last_load_time >= default_reload_interval(pls))
2070 /* reload the playlist since it was suspended */
2071 parse_playlist(c, pls->url, pls, NULL);
2072
2073 /* If playback is already in progress (we are just selecting a new
2074 * playlist) and this is a complete file, find the matching segment
2075 * by counting durations. */
2076
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
17 if (pls->finished && c->cur_timestamp != AV_NOPTS_VALUE) {
2077 find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no, NULL);
2078 return seq_no;
2079 }
2080
2081
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
17 if (!pls->finished) {
2082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!c->first_packet && /* we are doing a segment selection during playback */
2083 c->cur_seq_no >= pls->start_seq_no &&
2084 c->cur_seq_no < pls->start_seq_no + pls->n_segments)
2085 /* While spec 3.4.3 says that we cannot assume anything about the
2086 * content at the same sequence number on different playlists,
2087 * in practice this seems to work and doing it otherwise would
2088 * require us to download a segment to inspect its timestamps. */
2089 return c->cur_seq_no;
2090
2091 /* If this is a live stream, start live_start_index segments from the
2092 * start or end */
2093
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (c->live_start_index < 0)
2094 2 seq_no = pls->start_seq_no + FFMAX(pls->n_segments +
2095 c->live_start_index, 0);
2096 else
2097 seq_no = pls->start_seq_no + FFMIN(c->live_start_index,
2098 pls->n_segments - 1);
2099
2100 /* If #EXT-X-START in playlist, need to recalculate */
2101
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (pls->time_offset_flag && c->prefer_x_start) {
2102 int64_t start_timestamp;
2103 int64_t playlist_duration = 0;
2104 int64_t cur_timestamp = c->cur_timestamp == AV_NOPTS_VALUE ? 0 :
2105 c->cur_timestamp;
2106
2107 for (int i = 0; i < pls->n_segments; i++)
2108 playlist_duration += pls->segments[i]->duration;
2109
2110 /* If the absolute value of TIME-OFFSET exceeds
2111 * the duration of the playlist, it indicates either the end of the
2112 * playlist (if positive) or the beginning of the playlist (if
2113 * negative). */
2114 if (pls->start_time_offset >=0 &&
2115 pls->start_time_offset > playlist_duration)
2116 start_timestamp = cur_timestamp + playlist_duration;
2117 else if (pls->start_time_offset >= 0 &&
2118 pls->start_time_offset <= playlist_duration)
2119 start_timestamp = cur_timestamp + pls->start_time_offset;
2120 else if (pls->start_time_offset < 0 &&
2121 pls->start_time_offset < -playlist_duration)
2122 start_timestamp = cur_timestamp;
2123 else if (pls->start_time_offset < 0 &&
2124 pls->start_time_offset > -playlist_duration)
2125 start_timestamp = cur_timestamp + playlist_duration +
2126 pls->start_time_offset;
2127 else
2128 start_timestamp = cur_timestamp;
2129
2130 find_timestamp_in_playlist(c, pls, start_timestamp, &seq_no, NULL);
2131 }
2132 2 return seq_no;
2133 }
2134
2135 /* Otherwise just start on the first segment. */
2136 15 return pls->start_seq_no;
2137 }
2138
2139 17 static void add_stream_to_programs(AVFormatContext *s, struct playlist *pls, AVStream *stream)
2140 {
2141 17 HLSContext *c = s->priv_data;
2142 int i, j;
2143 17 int bandwidth = -1;
2144
2145
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
34 for (i = 0; i < c->n_variants; i++) {
2146 17 struct variant *v = c->variants[i];
2147
2148
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 17 times.
36 for (j = 0; j < v->n_playlists; j++) {
2149
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17 times.
19 if (v->playlists[j] != pls)
2150 2 continue;
2151
2152 17 av_program_add_stream_index(s, i, stream->index);
2153
2154
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (bandwidth < 0)
2155 17 bandwidth = v->bandwidth;
2156 else if (bandwidth != v->bandwidth)
2157 bandwidth = -1; /* stream in multiple variants with different bandwidths */
2158 }
2159 }
2160
2161
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (bandwidth >= 0)
2162 17 av_dict_set_int(&stream->metadata, "variant_bitrate", bandwidth, 0);
2163 17 }
2164
2165 28 static int set_stream_info_from_input_stream(AVStream *st, struct playlist *pls, AVStream *ist)
2166 {
2167 int err;
2168
2169 28 err = avcodec_parameters_copy(st->codecpar, ist->codecpar);
2170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (err < 0)
2171 return err;
2172
2173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (pls->is_id3_timestamped) /* custom timestamps via id3 */
2174 avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE);
2175 else
2176 28 avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den);
2177
2178 // copy disposition
2179 28 st->disposition = ist->disposition;
2180
2181 28 av_dict_copy(&st->metadata, ist->metadata, 0);
2182
2183 28 ffstream(st)->need_context_update = 1;
2184
2185 28 return 0;
2186 }
2187
2188 /* add new subdemuxer streams to our context, if any */
2189 6662 static int update_streams_from_subdemuxer(AVFormatContext *s, struct playlist *pls)
2190 {
2191 int err;
2192
2193
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 6662 times.
13341 while (pls->n_main_streams < pls->ctx->nb_streams) {
2194 17 int ist_idx = pls->n_main_streams;
2195 17 AVStream *st = avformat_new_stream(s, NULL);
2196 17 AVStream *ist = pls->ctx->streams[ist_idx];
2197
2198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (!st)
2199 return AVERROR(ENOMEM);
2200
2201 17 st->id = pls->index;
2202 17 dynarray_add(&pls->main_streams, &pls->n_main_streams, st);
2203
2204 17 add_stream_to_programs(s, pls, st);
2205
2206 17 err = set_stream_info_from_input_stream(st, pls, ist);
2207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (err < 0)
2208 return err;
2209
2210
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
17 if (ist->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
2211
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pls->timed_id3_stream_index < 0)
2212 1 pls->timed_id3_stream_index = ist_idx;
2213 else
2214 av_log(s, AV_LOG_WARNING,
2215 "Playlist has multiple timed ID3 streams; "
2216 "only stream %d will be used for metadata propagation\n",
2217 pls->timed_id3_stream_index);
2218 }
2219 }
2220
2221 6662 return 0;
2222 }
2223
2224 30 static void update_noheader_flag(AVFormatContext *s)
2225 {
2226 30 HLSContext *c = s->priv_data;
2227 30 int flag_needed = 0;
2228 int i;
2229
2230
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 16 times.
48 for (i = 0; i < c->n_playlists; i++) {
2231 32 struct playlist *pls = c->playlists[i];
2232
2233
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 18 times.
32 if (pls->has_noheader_flag) {
2234 14 flag_needed = 1;
2235 14 break;
2236 }
2237 }
2238
2239
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 16 times.
30 if (flag_needed)
2240 14 s->ctx_flags |= AVFMTCTX_NOHEADER;
2241 else
2242 16 s->ctx_flags &= ~AVFMTCTX_NOHEADER;
2243 30 }
2244
2245 16 static int hls_close(AVFormatContext *s)
2246 {
2247 16 HLSContext *c = s->priv_data;
2248
2249 16 free_playlist_list(c);
2250 16 free_variant_list(c);
2251 16 free_rendition_list(c);
2252
2253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (c->crypto_ctx.aes_ctx)
2254 av_free(c->crypto_ctx.aes_ctx);
2255
2256 16 av_dict_free(&c->avio_opts);
2257 16 ff_format_io_close(c->ctx, &c->playlist_pb);
2258
2259 16 return 0;
2260 }
2261
2262 16 static int hls_read_header(AVFormatContext *s)
2263 {
2264 16 HLSContext *c = s->priv_data;
2265 16 int ret = 0, i;
2266 16 int64_t highest_cur_seq_no = 0;
2267
2268 16 c->ctx = s;
2269 16 c->interrupt_callback = &s->interrupt_callback;
2270
2271 16 c->first_packet = 1;
2272 16 c->first_timestamp = AV_NOPTS_VALUE;
2273 16 c->first_timestamp_pls = NULL;
2274 16 c->cur_timestamp = AV_NOPTS_VALUE;
2275
2276
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if ((ret = ffio_copy_url_options(s->pb, &c->avio_opts)) < 0)
2277 return ret;
2278
2279 /* http_persistent and http_multiple auto-detection both rely on the
2280 * AVIOContext being backed by the builtin URLContext. Neither works
2281 * when io_open is overridden with a custom callback. */
2282
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if (!ffio_geturlcontext(s->pb)) {
2283 if (c->http_persistent) {
2284 av_log(s, AV_LOG_WARNING, "Disabling http_persistent due to custom io_open.\n");
2285 c->http_persistent = 0;
2286 }
2287 /* Only auto-detection is disabled, enabling http_multiple can still work
2288 * with custom io_open. */
2289 if (c->http_multiple == -1) {
2290 av_log(s, AV_LOG_WARNING, "Disabling http_multiple due to custom io_open.\n");
2291 c->http_multiple = 0;
2292 }
2293 }
2294
2295 /* XXX: Some HLS servers don't like being sent the range header,
2296 in this case, we need to set http_seekable = 0 to disable
2297 the range header */
2298 16 av_dict_set_int(&c->avio_opts, "seekable", c->http_seekable, 0);
2299
2300
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0)
2301 return ret;
2302
2303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (c->n_variants == 0) {
2304 av_log(s, AV_LOG_WARNING, "Empty playlist\n");
2305 return AVERROR_EOF;
2306 }
2307 /* If the playlist only contained playlists (Master Playlist),
2308 * parse each individual playlist. */
2309
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
16 if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) {
2310
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < c->n_playlists; i++) {
2311 2 struct playlist *pls = c->playlists[i];
2312 2 pls->m3u8_hold_counters = 0;
2313
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0) {
2314 av_log(s, AV_LOG_WARNING, "parse_playlist error %s [%s]\n", av_err2str(ret), pls->url);
2315 pls->broken = 1;
2316 if (c->n_playlists > 1)
2317 continue;
2318 return ret;
2319 }
2320 }
2321 }
2322
2323
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 for (i = 0; i < c->n_variants; i++) {
2324
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (c->variants[i]->playlists[0]->n_segments == 0) {
2325 av_log(s, AV_LOG_WARNING, "Empty segment [%s]\n", c->variants[i]->playlists[0]->url);
2326 c->variants[i]->playlists[0]->broken = 1;
2327 }
2328 }
2329
2330 /* Calculate the total duration of the stream if all segments are
2331 * available (finished or EVENT playlists). */
2332
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 if (c->variants[0]->playlists[0]->finished ||
2333
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT) {
2334 15 int64_t duration = 0;
2335
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 15 times.
87 for (i = 0; i < c->variants[0]->playlists[0]->n_segments; i++)
2336 72 duration += c->variants[0]->playlists[0]->segments[i]->duration;
2337 15 s->duration = duration;
2338 }
2339
2340 /* Associate renditions with variants */
2341
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 for (i = 0; i < c->n_variants; i++) {
2342 16 struct variant *var = c->variants[i];
2343
2344
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 if (var->audio_group[0])
2345 1 add_renditions_to_variant(c, var, AVMEDIA_TYPE_AUDIO, var->audio_group);
2346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (var->video_group[0])
2347 add_renditions_to_variant(c, var, AVMEDIA_TYPE_VIDEO, var->video_group);
2348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (var->subtitles_group[0])
2349 add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group);
2350 }
2351
2352 /* Create a program for each variant */
2353
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 for (i = 0; i < c->n_variants; i++) {
2354 16 struct variant *v = c->variants[i];
2355 AVProgram *program;
2356
2357 16 program = av_new_program(s, i);
2358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!program)
2359 return AVERROR(ENOMEM);
2360 16 av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0);
2361 }
2362
2363 /* Select the starting segments */
2364
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 16 times.
33 for (i = 0; i < c->n_playlists; i++) {
2365 17 struct playlist *pls = c->playlists[i];
2366
2367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (pls->n_segments == 0)
2368 continue;
2369
2370 17 pls->cur_seq_no = select_cur_seq_no(c, pls);
2371 17 highest_cur_seq_no = FFMAX(highest_cur_seq_no, pls->cur_seq_no);
2372 }
2373
2374 16 av_dict_set(&c->seg_format_opts, "prefer_hls_mpegts_pts", "1", 0);
2375
2376 /* Open the demuxer for each playlist */
2377
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 16 times.
33 for (i = 0; i < c->n_playlists; i++) {
2378 17 struct playlist *pls = c->playlists[i];
2379 17 const AVInputFormat *in_fmt = NULL;
2380 char *url;
2381 17 AVDictionary *options = NULL;
2382 17 struct segment *seg = NULL;
2383
2384
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if (!(pls->ctx = avformat_alloc_context()))
2385 return AVERROR(ENOMEM);
2386
2387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (pls->n_segments == 0)
2388 continue;
2389
2390 17 pls->index = i;
2391 17 pls->needed = 1;
2392 17 pls->parent = s;
2393
2394 /*
2395 * If this is a live stream and this playlist looks like it is one segment
2396 * behind, try to sync it up so that every substream starts at the same
2397 * time position (so e.g. avformat_find_stream_info() will see packets from
2398 * all active streams within the first few seconds). This is not very generic,
2399 * though, as the sequence numbers are technically independent.
2400 */
2401
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
17 if (!pls->finished && pls->cur_seq_no == highest_cur_seq_no - 1 &&
2402 highest_cur_seq_no < pls->start_seq_no + pls->n_segments) {
2403 pls->cur_seq_no = highest_cur_seq_no;
2404 }
2405
2406 17 pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);
2407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (!pls->read_buffer){
2408 avformat_free_context(pls->ctx);
2409 pls->ctx = NULL;
2410 return AVERROR(ENOMEM);
2411 }
2412
2413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (pls->is_subtitle)
2414 ffio_init_context(&pls->pb, (unsigned char*)av_strdup("WEBVTT\n"), (int)strlen("WEBVTT\n"), 0, pls,
2415 NULL, NULL, NULL);
2416 else
2417 17 ffio_init_context(&pls->pb, pls->read_buffer, INITIAL_BUFFER_SIZE, 0, pls,
2418 read_data_continuous, NULL, NULL);
2419
2420 /*
2421 * If encryption scheme is SAMPLE-AES, try to read ID3 tags of
2422 * external audio track that contains audio setup information
2423 */
2424 17 seg = current_segment(pls);
2425
2/6
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
17 if (seg && seg->key_type == KEY_SAMPLE_AES && pls->n_renditions > 0 &&
2426 pls->renditions[0]->type == AVMEDIA_TYPE_AUDIO) {
2427 uint8_t buf[HLS_MAX_ID3_TAGS_DATA_LEN];
2428 if ((ret = avio_read(&pls->pb.pub, buf, HLS_MAX_ID3_TAGS_DATA_LEN)) < 0) {
2429 /* Fail if error was not end of file */
2430 if (ret != AVERROR_EOF) {
2431 avformat_free_context(pls->ctx);
2432 pls->ctx = NULL;
2433 return ret;
2434 }
2435 }
2436 ret = 0;
2437 /* Reset reading */
2438 ff_format_io_close(pls->parent, &pls->input);
2439 pls->input = NULL;
2440 pls->input_read_done = 0;
2441 pls->input_reuse = 0;
2442 ff_format_io_close(pls->parent, &pls->input_next);
2443 pls->input_next = NULL;
2444 pls->input_next_requested = 0;
2445 pls->cur_seg_offset = 0;
2446 pls->cur_init_section = NULL;
2447 /* Reset EOF flag */
2448 pls->pb.pub.eof_reached = 0;
2449 /* Clear any buffered data */
2450 pls->pb.pub.buf_end = pls->pb.pub.buf_ptr = pls->pb.pub.buffer;
2451 /* Reset the position */
2452 pls->pb.pub.pos = 0;
2453 }
2454
2455 /*
2456 * If encryption scheme is SAMPLE-AES and audio setup information is present in external audio track,
2457 * use that information to find the media format, otherwise probe input data
2458 */
2459 17 seg = current_segment(pls);
2460
2/6
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
17 if (seg && seg->key_type == KEY_SAMPLE_AES && pls->is_id3_timestamped &&
2461 pls->audio_setup_info.codec_id != AV_CODEC_ID_NONE) {
2462 av_assert1(pls->audio_setup_info.codec_id == AV_CODEC_ID_AAC ||
2463 pls->audio_setup_info.codec_id == AV_CODEC_ID_AC3 ||
2464 pls->audio_setup_info.codec_id == AV_CODEC_ID_EAC3);
2465 // Keep this list in sync with ff_hls_senc_read_audio_setup_info()
2466 in_fmt = av_find_input_format(pls->audio_setup_info.codec_id == AV_CODEC_ID_AAC ? "aac" :
2467 pls->audio_setup_info.codec_id == AV_CODEC_ID_AC3 ? "ac3" : "eac3");
2468 } else {
2469
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4;
2470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE;
2471 17 pls->ctx->interrupt_callback = s->interrupt_callback;
2472 17 url = av_strdup(pls->segments[0]->url);
2473 17 ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, url, NULL, 0, 0);
2474
2475
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 17 times.
97 for (int n = 0; n < pls->n_segments; n++)
2476
1/2
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
80 if (ret >= 0)
2477 80 ret = test_segment(s, in_fmt, pls, pls->segments[n]);
2478
2479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (ret < 0) {
2480 /* Free the ctx - it isn't initialized properly at this point,
2481 * so avformat_close_input shouldn't be called. If
2482 * avformat_open_input fails below, it frees and zeros the
2483 * context, so it doesn't need any special treatment like this. */
2484 av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", url);
2485 avformat_free_context(pls->ctx);
2486 pls->ctx = NULL;
2487 av_free(url);
2488 return ret;
2489 }
2490 17 av_free(url);
2491 }
2492
2493 17 seg = current_segment(pls);
2494
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
17 if (seg && seg->key_type == KEY_SAMPLE_AES) {
2495 if (strstr(in_fmt->name, "mov")) {
2496 char key[33];
2497 ff_data_to_hex(key, pls->key, sizeof(pls->key), 0);
2498 av_dict_set(&options, "decryption_key", key, 0);
2499 } else if (!c->crypto_ctx.aes_ctx) {
2500 c->crypto_ctx.aes_ctx = av_aes_alloc();
2501 if (!c->crypto_ctx.aes_ctx) {
2502 avformat_free_context(pls->ctx);
2503 pls->ctx = NULL;
2504 return AVERROR(ENOMEM);
2505 }
2506 }
2507 }
2508
2509 17 pls->ctx->pb = &pls->pb.pub;
2510 17 pls->ctx->io_open = nested_io_open;
2511 17 pls->ctx->flags |= s->flags & ~AVFMT_FLAG_CUSTOM_IO;
2512
2513
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
2514 return ret;
2515
2516 17 av_dict_copy(&options, c->seg_format_opts, 0);
2517
2518 17 ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, &options);
2519 17 av_dict_free(&options);
2520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (ret < 0)
2521 return ret;
2522
2523
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17 if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) {
2524 ff_id3v2_parse_apic(pls->ctx, pls->id3_deferred_extra);
2525 avformat_queue_attached_pictures(pls->ctx);
2526 ff_id3v2_parse_priv(pls->ctx, pls->id3_deferred_extra);
2527 ff_id3v2_free_extra_meta(&pls->id3_deferred_extra);
2528 }
2529
2530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (pls->is_id3_timestamped == -1)
2531 av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been made\n");
2532
2533 /*
2534 * For ID3 timestamped raw audio streams we need to detect the packet
2535 * durations to calculate timestamps in fill_timing_for_id3_timestamped_stream(),
2536 * but for other streams we can rely on our user calling avformat_find_stream_info()
2537 * on us if they want to.
2538 */
2539
4/6
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
17 if (pls->is_id3_timestamped || (pls->n_renditions > 0 && pls->renditions[0]->type == AVMEDIA_TYPE_AUDIO)) {
2540 1 seg = current_segment(pls);
2541
2/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (seg && seg->key_type == KEY_SAMPLE_AES && pls->audio_setup_info.setup_data_length > 0 &&
2542 pls->ctx->nb_streams == 1)
2543 ret = ff_hls_senc_parse_audio_setup_info(pls->ctx->streams[0], &pls->audio_setup_info);
2544 else
2545 1 ret = avformat_find_stream_info(pls->ctx, NULL);
2546
2547
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2548 return ret;
2549 }
2550
2551 17 pls->has_noheader_flag = !!(pls->ctx->ctx_flags & AVFMTCTX_NOHEADER);
2552
2553 /* Create new AVStreams for each stream in this playlist */
2554 17 ret = update_streams_from_subdemuxer(s, pls);
2555
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (ret < 0)
2556 return ret;
2557
2558 /*
2559 * Copy any metadata from playlist to main streams, but do not set
2560 * event flags.
2561 */
2562
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (pls->n_main_streams)
2563 17 av_dict_copy(&pls->main_streams[0]->metadata, pls->ctx->metadata, 0);
2564
2565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (pls->is_subtitle) {
2566 avformat_free_context(pls->ctx);
2567 pls->ctx = NULL;
2568 pls->needed = 0;
2569 pls->main_streams[0]->discard = AVDISCARD_ALL;
2570 }
2571
2572 17 add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO);
2573 17 add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO);
2574 17 add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE);
2575 }
2576
2577 16 update_noheader_flag(s);
2578
2579 16 return 0;
2580 }
2581
2582 6657 static int recheck_discard_flags(AVFormatContext *s, int first)
2583 {
2584 6657 HLSContext *c = s->priv_data;
2585 6657 int i, changed = 0;
2586 int cur_needed;
2587
2588 /* Check if any new streams are needed */
2589
2/2
✓ Branch 0 taken 6778 times.
✓ Branch 1 taken 6657 times.
13435 for (i = 0; i < c->n_playlists; i++) {
2590 6778 struct playlist *pls = c->playlists[i];
2591
2592 6778 cur_needed = playlist_needed(c->playlists[i]);
2593
2594
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6778 times.
6778 if (pls->broken) {
2595 continue;
2596 }
2597
2/4
✓ Branch 0 taken 6778 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6778 times.
6778 if (cur_needed && !pls->needed) {
2598 pls->needed = 1;
2599 changed = 1;
2600 pls->cur_seq_no = select_cur_seq_no(c, pls);
2601 pls->pb.pub.eof_reached = 0;
2602 if (c->cur_timestamp != AV_NOPTS_VALUE) {
2603 /* catch up */
2604 pls->seek_timestamp = c->cur_timestamp +
2605 (pls->ts_offset != AV_NOPTS_VALUE ? pls->ts_offset : 0);
2606 pls->seek_flags = AVSEEK_FLAG_ANY;
2607 pls->seek_stream_index = -1;
2608 }
2609 av_log(s, AV_LOG_INFO, "Now receiving playlist %d, segment %"PRId64"\n", i, pls->cur_seq_no);
2610
3/6
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 6761 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6778 } else if (first && !cur_needed && pls->needed) {
2611 ff_format_io_close(pls->parent, &pls->input);
2612 pls->input_read_done = 0;
2613 pls->input_reuse = 0;
2614 ff_format_io_close(pls->parent, &pls->input_next);
2615 pls->input_next_requested = 0;
2616 if (pls->is_subtitle)
2617 avformat_close_input(&pls->ctx);
2618 pls->needed = 0;
2619 changed = 1;
2620 av_log(s, AV_LOG_INFO, "No longer receiving playlist %d\n", i);
2621 }
2622 }
2623 6657 return changed;
2624 }
2625
2626 static void fill_timing_for_id3_timestamped_stream(struct playlist *pls)
2627 {
2628 if (pls->id3_offset >= 0) {
2629 pls->pkt->dts = pls->id3_mpegts_timestamp +
2630 av_rescale_q(pls->id3_offset,
2631 pls->ctx->streams[pls->pkt->stream_index]->time_base,
2632 MPEG_TIME_BASE_Q);
2633 if (pls->pkt->duration)
2634 pls->id3_offset += pls->pkt->duration;
2635 else
2636 pls->id3_offset = -1;
2637 } else {
2638 /* there have been packets with unknown duration
2639 * since the last id3 tag, should not normally happen */
2640 pls->pkt->dts = AV_NOPTS_VALUE;
2641 }
2642
2643 if (pls->pkt->duration)
2644 pls->pkt->duration = av_rescale_q(pls->pkt->duration,
2645 pls->ctx->streams[pls->pkt->stream_index]->time_base,
2646 MPEG_TIME_BASE_Q);
2647
2648 pls->pkt->pts = AV_NOPTS_VALUE;
2649 }
2650
2651 898 static AVRational get_timebase(struct playlist *pls)
2652 {
2653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 898 times.
898 if (pls->is_id3_timestamped)
2654 return MPEG_TIME_BASE_Q;
2655
2656 898 return pls->ctx->streams[pls->pkt->stream_index]->time_base;
2657 }
2658
2659 121 static int compare_ts_with_wrapdetect(int64_t ts_a, struct playlist *pls_a,
2660 int64_t ts_b, struct playlist *pls_b)
2661 {
2662 121 int64_t scaled_ts_a = av_rescale_q(ts_a, get_timebase(pls_a), MPEG_TIME_BASE_Q);
2663 121 int64_t scaled_ts_b = av_rescale_q(ts_b, get_timebase(pls_b), MPEG_TIME_BASE_Q);
2664
2665 121 return av_compare_mod(scaled_ts_a, scaled_ts_b, 1LL << 33);
2666 }
2667
2668 /**
2669 * Check whether any entry in @p update differs from the corresponding entry
2670 * in @p current.
2671 *
2672 * HLS segments can repeat timed ID3 metadata in every segment so that
2673 * listeners joining mid-stream immediately receive the current track
2674 * information. Only signal a metadata change when values actually differ
2675 * to avoid spurious updates on every segment boundary.
2676 */
2677 2 static int metadata_has_changed(const AVDictionary *current,
2678 const AVDictionary *update)
2679 {
2680
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 if (av_dict_count(current) != av_dict_count(update))
2681 1 return 1;
2682 1 const AVDictionaryEntry *e = NULL;
2683
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 while ((e = av_dict_iterate(update, e))) {
2684 1 const AVDictionaryEntry *cur = av_dict_get(current, e->key, NULL, 0);
2685
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!cur || strcmp(cur->value, e->value))
2686 return 1;
2687 }
2688 1 return 0;
2689 }
2690
2691 6657 static int hls_read_packet(AVFormatContext *s, AVPacket *pkt)
2692 {
2693 6657 HLSContext *c = s->priv_data;
2694 6657 int ret, i, minplaylist = -1;
2695
2696 6657 recheck_discard_flags(s, c->first_packet);
2697 6657 c->first_packet = 0;
2698
2699
2/2
✓ Branch 0 taken 6778 times.
✓ Branch 1 taken 6657 times.
13435 for (i = 0; i < c->n_playlists; i++) {
2700 6778 struct playlist *pls = c->playlists[i];
2701 /* Make sure we've got one buffered packet from each open playlist
2702 * stream */
2703
3/4
✓ Branch 0 taken 6778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6684 times.
✓ Branch 3 taken 94 times.
6778 if (pls->needed && !pls->pkt->data) {
2704 586 while (1) {
2705 int64_t ts_diff;
2706 AVRational tb;
2707 7270 struct segment *seg = NULL;
2708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7270 times.
7270 if (pls->is_subtitle)
2709 ret = read_subtitle_packet(pls, pls->pkt);
2710 else
2711 7270 ret = av_read_frame(pls->ctx, pls->pkt);
2712
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 7258 times.
7270 if (ret < 0) {
2713
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 if (!avio_feof(&pls->pb.pub) && ret != AVERROR_EOF)
2714 return ret;
2715 6684 break;
2716 } else {
2717 /* stream_index check prevents matching picture attachments etc. */
2718
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7258 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
7258 if (pls->is_id3_timestamped && pls->pkt->stream_index == 0) {
2719 /* audio elementary streams are id3 timestamped */
2720 fill_timing_for_id3_timestamped_stream(pls);
2721 }
2722
2723
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 7241 times.
7258 if (pls->ts_offset == AV_NOPTS_VALUE &&
2724
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 pls->pkt->dts != AV_NOPTS_VALUE) {
2725 17 int64_t seg_idx = pls->cur_seq_no - pls->start_seq_no;
2726 34 int64_t ts = av_rescale_q(pls->pkt->dts,
2727 17 get_timebase(pls), AV_TIME_BASE_Q);
2728
2729 /* EVENT playlists preserve all segments from the start */
2730
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (pls->type == PLS_TYPE_EVENT)
2731
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
5 for (int64_t k = 0; k < seg_idx && k < pls->n_segments; k++)
2732 4 ts -= pls->segments[k]->duration;
2733
2734
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
17 if (c->first_timestamp == AV_NOPTS_VALUE) {
2735 16 c->first_timestamp = ts;
2736 16 c->first_timestamp_pls = pls;
2737
2738
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 if (pls->type == PLS_TYPE_EVENT)
2739
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (unsigned k = 0; k < s->nb_streams; k++) {
2740 1 AVStream *st = s->streams[k];
2741
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (st->start_time == AV_NOPTS_VALUE)
2742 1 st->start_time = av_rescale_q(ts,
2743 1 AV_TIME_BASE_Q, st->time_base);
2744 }
2745 }
2746 17 pls->ts_offset = ts - c->first_timestamp;
2747 }
2748 }
2749
2750 7258 seg = current_segment(pls);
2751
3/6
✓ Branch 0 taken 7254 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7254 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
7258 if (seg && seg->key_type == KEY_SAMPLE_AES && !strstr(pls->ctx->iformat->name, "mov")) {
2752 enum AVCodecID codec_id = pls->ctx->streams[pls->pkt->stream_index]->codecpar->codec_id;
2753 memcpy(c->crypto_ctx.iv, seg->iv, sizeof(seg->iv));
2754 memcpy(c->crypto_ctx.key, pls->key, sizeof(pls->key));
2755 ff_hls_senc_decrypt_frame(codec_id, &c->crypto_ctx, pls->pkt);
2756 }
2757
2758
2/2
✓ Branch 0 taken 6619 times.
✓ Branch 1 taken 639 times.
7258 if (pls->seek_timestamp == AV_NOPTS_VALUE)
2759 6619 break;
2760
2761
2/2
✓ Branch 0 taken 356 times.
✓ Branch 1 taken 283 times.
639 if (pls->seek_stream_index < 0 ||
2762
1/2
✓ Branch 0 taken 356 times.
✗ Branch 1 not taken.
356 pls->seek_stream_index == pls->pkt->stream_index) {
2763
2764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 639 times.
639 if (pls->pkt->dts == AV_NOPTS_VALUE) {
2765 pls->seek_timestamp = AV_NOPTS_VALUE;
2766 break;
2767 }
2768
2769 639 tb = get_timebase(pls);
2770 639 ts_diff = av_rescale_rnd(pls->pkt->dts, AV_TIME_BASE,
2771 639 tb.den, AV_ROUND_DOWN) -
2772 639 pls->seek_timestamp;
2773
4/4
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 530 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 26 times.
639 if (ts_diff >= 0 && (pls->seek_flags & AVSEEK_FLAG_ANY ||
2774
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 56 times.
83 pls->pkt->flags & AV_PKT_FLAG_KEY)) {
2775 53 pls->seek_timestamp = AV_NOPTS_VALUE;
2776 53 break;
2777 }
2778 }
2779 586 av_packet_unref(pls->pkt);
2780 }
2781 }
2782 /* Check if this stream has the packet with the lowest dts */
2783
2/2
✓ Branch 0 taken 6766 times.
✓ Branch 1 taken 12 times.
6778 if (pls->pkt->data) {
2784 6766 struct playlist *minpls = minplaylist < 0 ?
2785
2/2
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 6645 times.
6766 NULL : c->playlists[minplaylist];
2786
2/2
✓ Branch 0 taken 6645 times.
✓ Branch 1 taken 121 times.
6766 if (minplaylist < 0) {
2787 6645 minplaylist = i;
2788 } else {
2789 121 int64_t dts = pls->pkt->dts;
2790 121 int64_t mindts = minpls->pkt->dts;
2791
2792
2/4
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
121 if (dts == AV_NOPTS_VALUE ||
2793
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 81 times.
121 (mindts != AV_NOPTS_VALUE && compare_ts_with_wrapdetect(dts, pls, mindts, minpls) < 0))
2794 40 minplaylist = i;
2795 }
2796 }
2797 }
2798
2799 /* If we got a packet, return it */
2800
2/2
✓ Branch 0 taken 6645 times.
✓ Branch 1 taken 12 times.
6657 if (minplaylist >= 0) {
2801 6645 struct playlist *pls = c->playlists[minplaylist];
2802 AVStream *ist;
2803 AVStream *st;
2804
2805 6645 ret = update_streams_from_subdemuxer(s, pls);
2806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6645 times.
6645 if (ret < 0) {
2807 av_packet_unref(pls->pkt);
2808 return ret;
2809 }
2810
2811 // If sub-demuxer reports updated metadata, copy it to the first stream
2812 // and set its AVSTREAM_EVENT_FLAG_METADATA_UPDATED flag.
2813
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6644 times.
6645 if (pls->ctx->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) {
2814
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pls->n_main_streams) {
2815 1 st = pls->main_streams[0];
2816 1 av_dict_copy(&st->metadata, pls->ctx->metadata, 0);
2817 1 st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
2818 }
2819 1 pls->ctx->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED;
2820 }
2821
2822 /* check if noheader flag has been cleared by the subdemuxer */
2823
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 6631 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
6645 if (pls->has_noheader_flag && !(pls->ctx->ctx_flags & AVFMTCTX_NOHEADER)) {
2824 14 pls->has_noheader_flag = 0;
2825 14 update_noheader_flag(s);
2826 }
2827
2828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6645 times.
6645 if (pls->pkt->stream_index >= pls->n_main_streams) {
2829 av_log(s, AV_LOG_ERROR, "stream index inconsistency: index %d, %d main streams, %d subdemuxer streams\n",
2830 pls->pkt->stream_index, pls->n_main_streams, pls->ctx->nb_streams);
2831 av_packet_unref(pls->pkt);
2832 return AVERROR_BUG;
2833 }
2834
2835 6645 ist = pls->ctx->streams[pls->pkt->stream_index];
2836 6645 st = pls->main_streams[pls->pkt->stream_index];
2837
2838 // Propagate timed-ID3 metadata changes to the main stream, suppressing
2839 // duplicate packets that repeat unchanged metadata at segment boundaries.
2840
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6643 times.
6645 if (ist->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3 &&
2841
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 pls->pkt->stream_index == pls->timed_id3_stream_index &&
2842
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 ist->event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) {
2843 2 ist->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
2844
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (metadata_has_changed(pls->timed_id3_metadata, ist->metadata)) {
2845 1 int ret = av_dict_copy(&st->metadata, ist->metadata, 0);
2846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2847 return ret;
2848 1 av_dict_free(&pls->timed_id3_metadata);
2849 1 ret = av_dict_copy(&pls->timed_id3_metadata, ist->metadata, 0);
2850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2851 return ret;
2852 1 st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
2853 }
2854 }
2855
2856 6645 av_packet_move_ref(pkt, pls->pkt);
2857 6645 pkt->stream_index = st->index;
2858
2859
1/2
✓ Branch 0 taken 6645 times.
✗ Branch 1 not taken.
6645 if (pkt->dts != AV_NOPTS_VALUE)
2860 6645 c->cur_timestamp = av_rescale_q(pkt->dts,
2861 ist->time_base,
2862 6645 AV_TIME_BASE_Q);
2863
2864 /* There may be more situations where this would be useful, but this at least
2865 * handles newly probed codecs properly (i.e. request_probe by mpegts). */
2866
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6634 times.
6645 if (ist->codecpar->codec_id != st->codecpar->codec_id) {
2867 11 ret = set_stream_info_from_input_stream(st, pls, ist);
2868
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ret < 0) {
2869 return ret;
2870 }
2871 }
2872
2873 6645 return 0;
2874 }
2875 12 return AVERROR_EOF;
2876 }
2877
2878 27 static int hls_read_seek(AVFormatContext *s, int stream_index,
2879 int64_t timestamp, int flags)
2880 {
2881 27 HLSContext *c = s->priv_data;
2882 27 struct playlist *seek_pls = NULL;
2883 int i, j;
2884 int stream_subdemuxer_index;
2885 int64_t first_timestamp, seek_timestamp, duration;
2886 int64_t seq_no, seg_start_ts;
2887
2888
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 if ((flags & AVSEEK_FLAG_BYTE) || (c->ctx->ctx_flags & AVFMTCTX_UNSEEKABLE))
2889 return AVERROR(ENOSYS);
2890
2891 54 first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ?
2892
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 0 : c->first_timestamp;
2893
2894 27 seek_timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE,
2895 27 s->streams[stream_index]->time_base.den,
2896 AV_ROUND_DOWN);
2897
2898 54 duration = s->duration == AV_NOPTS_VALUE ?
2899
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 0 : s->duration;
2900
2901
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 if (0 < duration && duration < seek_timestamp - first_timestamp)
2902 return AVERROR(EIO);
2903
2904 /* find the playlist with the specified stream */
2905
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 27 times.
80 for (i = 0; i < c->n_playlists; i++) {
2906 53 struct playlist *pls = c->playlists[i];
2907
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 26 times.
79 for (j = 0; j < pls->n_main_streams; j++) {
2908
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 26 times.
53 if (pls->main_streams[j] == s->streams[stream_index]) {
2909 27 seek_pls = pls;
2910 27 stream_subdemuxer_index = j;
2911 27 break;
2912 }
2913 }
2914 }
2915 /* check if the timestamp is valid for the playlist with the
2916 * specified stream index */
2917
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
27 if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no, &seg_start_ts))
2918 return AVERROR(EIO);
2919
2920
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 9 times.
27 if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
2921
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
18 flags & AVSEEK_FLAG_BACKWARD && !(flags & AVSEEK_FLAG_ANY)) {
2922 /* Seeking to start of segment ensures we seek to a keyframe located
2923 * before the given timestamp. */
2924 9 seek_timestamp = seg_start_ts;
2925 }
2926
2927 /* set segment now so we do not need to search again below */
2928 27 seek_pls->cur_seq_no = seq_no;
2929 27 seek_pls->seek_stream_index = stream_subdemuxer_index;
2930
2931 /* Reset PTS wrap detection so backward seeks don't get misinterpreted
2932 * as a forward PTS wrap. */
2933
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 27 times.
80 for (i = 0; i < (int)s->nb_streams; i++)
2934 53 ffstream(s->streams[i])->pts_wrap_reference = AV_NOPTS_VALUE;
2935
2936
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 27 times.
80 for (i = 0; i < c->n_playlists; i++) {
2937 /* Reset reading */
2938 53 struct playlist *pls = c->playlists[i];
2939 53 AVIOContext *const pb = &pls->pb.pub;
2940 53 ff_format_io_close(pls->parent, &pls->input);
2941 53 pls->input_read_done = 0;
2942 53 pls->input_reuse = 0;
2943 53 ff_format_io_close(pls->parent, &pls->input_next);
2944 53 pls->input_next_requested = 0;
2945 53 av_packet_unref(pls->pkt);
2946 53 pb->eof_reached = 0;
2947 /* Clear any buffered data */
2948 53 pb->buf_end = pb->buf_ptr = pb->buffer;
2949 /* Reset the pos, to let the mpegts/mov demuxer know we've seeked. */
2950 53 pb->pos = 0;
2951 /* Flush the packet queue of the subdemuxer. */
2952
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (pls->ctx) {
2953 53 ff_read_frame_flush(pls->ctx);
2954
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 53 times.
106 for (j = 0; j < (int)pls->ctx->nb_streams; j++)
2955 53 ffstream(pls->ctx->streams[j])->pts_wrap_reference = AV_NOPTS_VALUE;
2956 }
2957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (pls->is_subtitle)
2958 avformat_close_input(&pls->ctx);
2959
2960 /* Reset the init segment so it's re-fetched and served appropriately */
2961 53 pls->cur_init_section = NULL;
2962
2963 /* The discard in hls_read_packet compares this playlist's packet DTS
2964 * against seek_timestamp, but seek_timestamp is on c->first_timestamp's
2965 * baseline (whichever stream produced the first packet). Streams can
2966 * have different DTS baselines, so translate the threshold onto this
2967 * playlist's own baseline using its captured offset. */
2968
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 if (pls->ts_offset != AV_NOPTS_VALUE)
2969 53 pls->seek_timestamp = seek_timestamp + pls->ts_offset;
2970 else
2971 pls->seek_timestamp = seek_timestamp;
2972 53 pls->seek_flags = flags;
2973
2974
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 27 times.
53 if (pls != seek_pls) {
2975 /* set closest segment seq_no for playlists not handled above */
2976 26 find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no, NULL);
2977 /* seek the playlist to the given position without taking
2978 * keyframes into account since this playlist does not have the
2979 * specified stream where we should look for the keyframes */
2980 26 pls->seek_stream_index = -1;
2981 26 pls->seek_flags |= AVSEEK_FLAG_ANY;
2982 }
2983
2984 53 pls->last_seq_no = pls->cur_seq_no;
2985 }
2986
2987 27 c->cur_timestamp = seek_timestamp;
2988
2989 27 return 0;
2990 }
2991
2992 7778 static int hls_probe(const AVProbeData *p)
2993 {
2994 /* Require #EXTM3U at the start, and either one of the ones below
2995 * somewhere for a proper match. */
2996
2/2
✓ Branch 0 taken 7762 times.
✓ Branch 1 taken 16 times.
7778 if (strncmp(p->buf, "#EXTM3U", 7))
2997 7762 return 0;
2998
2999
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
16 if (strstr(p->buf, "#EXT-X-STREAM-INF:") ||
3000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 strstr(p->buf, "#EXT-X-TARGETDURATION:") ||
3001 strstr(p->buf, "#EXT-X-MEDIA-SEQUENCE:")) {
3002
3003
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
16 int mime_ok = p->mime_type && !(
3004 av_strcasecmp(p->mime_type, "application/vnd.apple.mpegurl") &&
3005 av_strcasecmp(p->mime_type, "audio/mpegurl")
3006 );
3007
3008
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
16 int mime_x = p->mime_type && !(
3009 av_strcasecmp(p->mime_type, "audio/x-mpegurl") &&
3010 av_strcasecmp(p->mime_type, "application/x-mpegurl")
3011 );
3012
3013
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 if (!mime_ok &&
3014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 !mime_x &&
3015
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
16 !av_match_ext (p->filename, "m3u8,m3u") &&
3016 ff_match_url_ext(p->filename, "m3u8,m3u") <= 0) {
3017 av_log(NULL, AV_LOG_ERROR, "Not detecting m3u8/hls with non standard extension and non standard mime type\n");
3018 return 0;
3019 }
3020
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (mime_x)
3021 av_log(NULL, AV_LOG_WARNING, "mime type is not rfc8216 compliant\n");
3022
3023 16 return AVPROBE_SCORE_MAX;
3024 }
3025 return 0;
3026 }
3027
3028 #define OFFSET(x) offsetof(HLSContext, x)
3029 #define FLAGS AV_OPT_FLAG_DECODING_PARAM
3030 static const AVOption hls_options[] = {
3031 {"live_start_index", "segment index to start live streams at (negative values are from the end)",
3032 OFFSET(live_start_index), AV_OPT_TYPE_INT, {.i64 = -3}, INT_MIN, INT_MAX, FLAGS},
3033 {"prefer_x_start", "prefer to use #EXT-X-START if it's in playlist instead of live_start_index",
3034 OFFSET(prefer_x_start), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS},
3035 {"allowed_extensions", "List of file extensions that hls is allowed to access",
3036 OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
3037 {.str = "3gp,aac,avi,ac3,eac3,flac,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,vtt,wav,webvtt"
3038 ",cmfv,cmfa" // Ticket11526 www.nicovideo.jp
3039 ",ec3" // part of Ticket11435 (Elisa Viihde (Finnish online recording service))
3040 ",fmp4" // https://github.com/yt-dlp/yt-dlp/issues/12700
3041 },
3042 INT_MIN, INT_MAX, FLAGS},
3043 {"allowed_segment_extensions", "List of file extensions that hls is allowed to access",
3044 OFFSET(allowed_segment_extensions), AV_OPT_TYPE_STRING,
3045 {.str = "3gp,aac,avi,ac3,eac3,flac,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,vtt,wav,webvtt"
3046 ",cmfv,cmfa" // Ticket11526 www.nicovideo.jp
3047 ",ec3" // part of Ticket11435 (Elisa Viihde (Finnish online recording service))
3048 ",fmp4" // https://github.com/yt-dlp/yt-dlp/issues/12700
3049 ",html" // https://flash1.bogulus.cfd/
3050 },
3051 INT_MIN, INT_MAX, FLAGS},
3052 {"extension_picky", "Be picky with all extensions matching",
3053 OFFSET(extension_picky), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS},
3054 {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded",
3055 OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 100}, 0, INT_MAX, FLAGS},
3056 {"m3u8_hold_counters", "The maximum number of times to load m3u8 when it refreshes without new segments",
3057 OFFSET(m3u8_hold_counters), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, FLAGS},
3058 {"http_persistent", "Use persistent HTTP connections",
3059 OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
3060 {"http_multiple", "Use multiple HTTP connections for fetching segments",
3061 OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, FLAGS},
3062 {"http_seekable", "Use HTTP partial requests, 0 = disable, 1 = enable, -1 = auto",
3063 OFFSET(http_seekable), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 1, FLAGS},
3064 {"seg_format_options", "Set options for segment demuxer",
3065 OFFSET(seg_format_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, FLAGS},
3066 {"seg_max_retry", "Maximum number of times to reload a segment on error.",
3067 OFFSET(seg_max_retry), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS},
3068 {NULL}
3069 };
3070
3071 static const AVClass hls_class = {
3072 .class_name = "hls demuxer",
3073 .item_name = av_default_item_name,
3074 .option = hls_options,
3075 .version = LIBAVUTIL_VERSION_INT,
3076 };
3077
3078 const FFInputFormat ff_hls_demuxer = {
3079 .p.name = "hls",
3080 .p.long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
3081 .p.priv_class = &hls_class,
3082 .p.flags = AVFMT_NOGENSEARCH | AVFMT_TS_DISCONT | AVFMT_NO_BYTE_SEEK | AVFMT_SHOW_IDS,
3083 .priv_data_size = sizeof(HLSContext),
3084 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
3085 .read_probe = hls_probe,
3086 .read_header = hls_read_header,
3087 .read_packet = hls_read_packet,
3088 .read_close = hls_close,
3089 .read_seek = hls_read_seek,
3090 };
3091