Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Apple HTTP Live Streaming demuxer | |
3 | * Copyright (c) 2010 Martin Storsjo | |
4 | * Copyright (c) 2013 Anssi Hannula | |
5 | * | |
6 | * This file is part of FFmpeg. | |
7 | * | |
8 | * FFmpeg is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License as published by the Free Software Foundation; either | |
11 | * version 2.1 of the License, or (at your option) any later version. | |
12 | * | |
13 | * FFmpeg is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public | |
19 | * License along with FFmpeg; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
21 | */ | |
22 | ||
23 | /** | |
24 | * @file | |
25 | * Apple HTTP Live Streaming demuxer | |
26 | * http://tools.ietf.org/html/draft-pantos-http-live-streaming | |
27 | */ | |
28 | ||
29 | #include "libavutil/avstring.h" | |
30 | #include "libavutil/avassert.h" | |
31 | #include "libavutil/intreadwrite.h" | |
32 | #include "libavutil/mathematics.h" | |
33 | #include "libavutil/opt.h" | |
34 | #include "libavutil/dict.h" | |
35 | #include "libavutil/time.h" | |
36 | #include "avformat.h" | |
37 | #include "internal.h" | |
38 | #include "avio_internal.h" | |
39 | #include "url.h" | |
40 | #include "id3v2.h" | |
41 | ||
42 | #define INITIAL_BUFFER_SIZE 32768 | |
43 | ||
44 | #define MAX_FIELD_LEN 64 | |
45 | #define MAX_CHARACTERISTICS_LEN 512 | |
46 | ||
47 | #define MPEG_TIME_BASE 90000 | |
48 | #define MPEG_TIME_BASE_Q (AVRational){1, MPEG_TIME_BASE} | |
49 | ||
50 | /* | |
51 | * An apple http stream consists of a playlist with media segment files, | |
52 | * played sequentially. There may be several playlists with the same | |
53 | * video content, in different bandwidth variants, that are played in | |
54 | * parallel (preferably only one bandwidth variant at a time). In this case, | |
55 | * the user supplied the url to a main playlist that only lists the variant | |
56 | * playlists. | |
57 | * | |
58 | * If the main playlist doesn't point at any variants, we still create | |
59 | * one anonymous toplevel variant for this, to maintain the structure. | |
60 | */ | |
61 | ||
62 | enum KeyType { | |
63 | KEY_NONE, | |
64 | KEY_AES_128, | |
65 | }; | |
66 | ||
67 | struct segment { | |
68 | int64_t duration; | |
69 | int64_t url_offset; | |
70 | int64_t size; | |
71 | char *url; | |
72 | char *key; | |
73 | enum KeyType key_type; | |
74 | uint8_t iv[16]; | |
75 | }; | |
76 | ||
77 | struct rendition; | |
78 | ||
79 | enum PlaylistType { | |
80 | PLS_TYPE_UNSPECIFIED, | |
81 | PLS_TYPE_EVENT, | |
82 | PLS_TYPE_VOD | |
83 | }; | |
84 | ||
85 | /* | |
86 | * Each playlist has its own demuxer. If it currently is active, | |
87 | * it has an open AVIOContext too, and potentially an AVPacket | |
88 | * containing the next packet from this stream. | |
89 | */ | |
90 | struct playlist { | |
91 | char url[MAX_URL_SIZE]; | |
92 | AVIOContext pb; | |
93 | uint8_t* read_buffer; | |
94 | URLContext *input; | |
95 | AVFormatContext *parent; | |
96 | int index; | |
97 | AVFormatContext *ctx; | |
98 | AVPacket pkt; | |
99 | int stream_offset; | |
100 | ||
101 | int finished; | |
102 | enum PlaylistType type; | |
103 | int64_t target_duration; | |
104 | int start_seq_no; | |
105 | int n_segments; | |
106 | struct segment **segments; | |
107 | int needed, cur_needed; | |
108 | int cur_seq_no; | |
109 | int64_t cur_seg_offset; | |
110 | int64_t last_load_time; | |
111 | ||
112 | char key_url[MAX_URL_SIZE]; | |
113 | uint8_t key[16]; | |
114 | ||
115 | /* ID3 timestamp handling (elementary audio streams have ID3 timestamps | |
116 | * (and possibly other ID3 tags) in the beginning of each segment) */ | |
117 | int is_id3_timestamped; /* -1: not yet known */ | |
118 | int64_t id3_mpegts_timestamp; /* in mpegts tb */ | |
119 | int64_t id3_offset; /* in stream original tb */ | |
120 | uint8_t* id3_buf; /* temp buffer for id3 parsing */ | |
121 | unsigned int id3_buf_size; | |
122 | AVDictionary *id3_initial; /* data from first id3 tag */ | |
123 | int id3_found; /* ID3 tag found at some point */ | |
124 | int id3_changed; /* ID3 tag data has changed at some point */ | |
125 | ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer is opened */ | |
126 | ||
127 | int64_t seek_timestamp; | |
128 | int seek_flags; | |
129 | int seek_stream_index; /* into subdemuxer stream array */ | |
130 | ||
131 | /* Renditions associated with this playlist, if any. | |
132 | * Alternative rendition playlists have a single rendition associated | |
133 | * with them, and variant main Media Playlists may have | |
134 | * multiple (playlist-less) renditions associated with them. */ | |
135 | int n_renditions; | |
136 | struct rendition **renditions; | |
137 | }; | |
138 | ||
139 | /* | |
140 | * Renditions are e.g. alternative subtitle or audio streams. | |
141 | * The rendition may either be an external playlist or it may be | |
142 | * contained in the main Media Playlist of the variant (in which case | |
143 | * playlist is NULL). | |
144 | */ | |
145 | struct rendition { | |
146 | enum AVMediaType type; | |
147 | struct playlist *playlist; | |
148 | char group_id[MAX_FIELD_LEN]; | |
149 | char language[MAX_FIELD_LEN]; | |
150 | char name[MAX_FIELD_LEN]; | |
151 | int disposition; | |
152 | }; | |
153 | ||
154 | struct variant { | |
155 | int bandwidth; | |
156 | ||
157 | /* every variant contains at least the main Media Playlist in index 0 */ | |
158 | int n_playlists; | |
159 | struct playlist **playlists; | |
160 | ||
161 | char audio_group[MAX_FIELD_LEN]; | |
162 | char video_group[MAX_FIELD_LEN]; | |
163 | char subtitles_group[MAX_FIELD_LEN]; | |
164 | }; | |
165 | ||
166 | typedef struct HLSContext { | |
167 | int n_variants; | |
168 | struct variant **variants; | |
169 | int n_playlists; | |
170 | struct playlist **playlists; | |
171 | int n_renditions; | |
172 | struct rendition **renditions; | |
173 | ||
174 | int cur_seq_no; | |
175 | int first_packet; | |
176 | int64_t first_timestamp; | |
177 | int64_t cur_timestamp; | |
178 | AVIOInterruptCB *interrupt_callback; | |
179 | char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context | |
180 | char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context | |
181 | char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context | |
182 | } HLSContext; | |
183 | ||
184 | static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) | |
185 | { | |
186 | int len = ff_get_line(s, buf, maxlen); | |
187 | while (len > 0 && av_isspace(buf[len - 1])) | |
188 | buf[--len] = '\0'; | |
189 | return len; | |
190 | } | |
191 | ||
192 | static void free_segment_list(struct playlist *pls) | |
193 | { | |
194 | int i; | |
195 | for (i = 0; i < pls->n_segments; i++) { | |
f6fa7814 DM |
196 | av_freep(&pls->segments[i]->key); |
197 | av_freep(&pls->segments[i]->url); | |
198 | av_freep(&pls->segments[i]); | |
2ba45a60 DM |
199 | } |
200 | av_freep(&pls->segments); | |
201 | pls->n_segments = 0; | |
202 | } | |
203 | ||
204 | static void free_playlist_list(HLSContext *c) | |
205 | { | |
206 | int i; | |
207 | for (i = 0; i < c->n_playlists; i++) { | |
208 | struct playlist *pls = c->playlists[i]; | |
209 | free_segment_list(pls); | |
210 | av_freep(&pls->renditions); | |
211 | av_freep(&pls->id3_buf); | |
212 | av_dict_free(&pls->id3_initial); | |
213 | ff_id3v2_free_extra_meta(&pls->id3_deferred_extra); | |
214 | av_free_packet(&pls->pkt); | |
f6fa7814 | 215 | av_freep(&pls->pb.buffer); |
2ba45a60 DM |
216 | if (pls->input) |
217 | ffurl_close(pls->input); | |
218 | if (pls->ctx) { | |
219 | pls->ctx->pb = NULL; | |
220 | avformat_close_input(&pls->ctx); | |
221 | } | |
222 | av_free(pls); | |
223 | } | |
224 | av_freep(&c->playlists); | |
225 | av_freep(&c->cookies); | |
226 | av_freep(&c->user_agent); | |
227 | c->n_playlists = 0; | |
228 | } | |
229 | ||
230 | static void free_variant_list(HLSContext *c) | |
231 | { | |
232 | int i; | |
233 | for (i = 0; i < c->n_variants; i++) { | |
234 | struct variant *var = c->variants[i]; | |
235 | av_freep(&var->playlists); | |
236 | av_free(var); | |
237 | } | |
238 | av_freep(&c->variants); | |
239 | c->n_variants = 0; | |
240 | } | |
241 | ||
242 | static void free_rendition_list(HLSContext *c) | |
243 | { | |
244 | int i; | |
245 | for (i = 0; i < c->n_renditions; i++) | |
f6fa7814 | 246 | av_freep(&c->renditions[i]); |
2ba45a60 DM |
247 | av_freep(&c->renditions); |
248 | c->n_renditions = 0; | |
249 | } | |
250 | ||
251 | /* | |
252 | * Used to reset a statically allocated AVPacket to a clean slate, | |
253 | * containing no data. | |
254 | */ | |
255 | static void reset_packet(AVPacket *pkt) | |
256 | { | |
257 | av_init_packet(pkt); | |
258 | pkt->data = NULL; | |
259 | } | |
260 | ||
261 | static struct playlist *new_playlist(HLSContext *c, const char *url, | |
262 | const char *base) | |
263 | { | |
264 | struct playlist *pls = av_mallocz(sizeof(struct playlist)); | |
265 | if (!pls) | |
266 | return NULL; | |
267 | reset_packet(&pls->pkt); | |
268 | ff_make_absolute_url(pls->url, sizeof(pls->url), base, url); | |
269 | pls->seek_timestamp = AV_NOPTS_VALUE; | |
270 | ||
271 | pls->is_id3_timestamped = -1; | |
272 | pls->id3_mpegts_timestamp = AV_NOPTS_VALUE; | |
273 | ||
274 | dynarray_add(&c->playlists, &c->n_playlists, pls); | |
275 | return pls; | |
276 | } | |
277 | ||
278 | struct variant_info { | |
279 | char bandwidth[20]; | |
280 | /* variant group ids: */ | |
281 | char audio[MAX_FIELD_LEN]; | |
282 | char video[MAX_FIELD_LEN]; | |
283 | char subtitles[MAX_FIELD_LEN]; | |
284 | }; | |
285 | ||
286 | static struct variant *new_variant(HLSContext *c, struct variant_info *info, | |
287 | const char *url, const char *base) | |
288 | { | |
289 | struct variant *var; | |
290 | struct playlist *pls; | |
291 | ||
292 | pls = new_playlist(c, url, base); | |
293 | if (!pls) | |
294 | return NULL; | |
295 | ||
296 | var = av_mallocz(sizeof(struct variant)); | |
297 | if (!var) | |
298 | return NULL; | |
299 | ||
300 | if (info) { | |
301 | var->bandwidth = atoi(info->bandwidth); | |
302 | strcpy(var->audio_group, info->audio); | |
303 | strcpy(var->video_group, info->video); | |
304 | strcpy(var->subtitles_group, info->subtitles); | |
305 | } | |
306 | ||
307 | dynarray_add(&c->variants, &c->n_variants, var); | |
308 | dynarray_add(&var->playlists, &var->n_playlists, pls); | |
309 | return var; | |
310 | } | |
311 | ||
312 | static void handle_variant_args(struct variant_info *info, const char *key, | |
313 | int key_len, char **dest, int *dest_len) | |
314 | { | |
315 | if (!strncmp(key, "BANDWIDTH=", key_len)) { | |
316 | *dest = info->bandwidth; | |
317 | *dest_len = sizeof(info->bandwidth); | |
318 | } else if (!strncmp(key, "AUDIO=", key_len)) { | |
319 | *dest = info->audio; | |
320 | *dest_len = sizeof(info->audio); | |
321 | } else if (!strncmp(key, "VIDEO=", key_len)) { | |
322 | *dest = info->video; | |
323 | *dest_len = sizeof(info->video); | |
324 | } else if (!strncmp(key, "SUBTITLES=", key_len)) { | |
325 | *dest = info->subtitles; | |
326 | *dest_len = sizeof(info->subtitles); | |
327 | } | |
328 | } | |
329 | ||
330 | struct key_info { | |
331 | char uri[MAX_URL_SIZE]; | |
332 | char method[10]; | |
333 | char iv[35]; | |
334 | }; | |
335 | ||
336 | static void handle_key_args(struct key_info *info, const char *key, | |
337 | int key_len, char **dest, int *dest_len) | |
338 | { | |
339 | if (!strncmp(key, "METHOD=", key_len)) { | |
340 | *dest = info->method; | |
341 | *dest_len = sizeof(info->method); | |
342 | } else if (!strncmp(key, "URI=", key_len)) { | |
343 | *dest = info->uri; | |
344 | *dest_len = sizeof(info->uri); | |
345 | } else if (!strncmp(key, "IV=", key_len)) { | |
346 | *dest = info->iv; | |
347 | *dest_len = sizeof(info->iv); | |
348 | } | |
349 | } | |
350 | ||
351 | struct rendition_info { | |
352 | char type[16]; | |
353 | char uri[MAX_URL_SIZE]; | |
354 | char group_id[MAX_FIELD_LEN]; | |
355 | char language[MAX_FIELD_LEN]; | |
356 | char assoc_language[MAX_FIELD_LEN]; | |
357 | char name[MAX_FIELD_LEN]; | |
358 | char defaultr[4]; | |
359 | char forced[4]; | |
360 | char characteristics[MAX_CHARACTERISTICS_LEN]; | |
361 | }; | |
362 | ||
363 | static struct rendition *new_rendition(HLSContext *c, struct rendition_info *info, | |
364 | const char *url_base) | |
365 | { | |
366 | struct rendition *rend; | |
367 | enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN; | |
368 | char *characteristic; | |
369 | char *chr_ptr; | |
370 | char *saveptr; | |
371 | ||
372 | if (!strcmp(info->type, "AUDIO")) | |
373 | type = AVMEDIA_TYPE_AUDIO; | |
374 | else if (!strcmp(info->type, "VIDEO")) | |
375 | type = AVMEDIA_TYPE_VIDEO; | |
376 | else if (!strcmp(info->type, "SUBTITLES")) | |
377 | type = AVMEDIA_TYPE_SUBTITLE; | |
378 | else if (!strcmp(info->type, "CLOSED-CAPTIONS")) | |
379 | /* CLOSED-CAPTIONS is ignored since we do not support CEA-608 CC in | |
380 | * AVC SEI RBSP anyway */ | |
381 | return NULL; | |
382 | ||
383 | if (type == AVMEDIA_TYPE_UNKNOWN) | |
384 | return NULL; | |
385 | ||
386 | /* URI is mandatory for subtitles as per spec */ | |
387 | if (type == AVMEDIA_TYPE_SUBTITLE && !info->uri[0]) | |
388 | return NULL; | |
389 | ||
390 | /* TODO: handle subtitles (each segment has to parsed separately) */ | |
391 | if (type == AVMEDIA_TYPE_SUBTITLE) | |
392 | return NULL; | |
393 | ||
394 | rend = av_mallocz(sizeof(struct rendition)); | |
395 | if (!rend) | |
396 | return NULL; | |
397 | ||
398 | dynarray_add(&c->renditions, &c->n_renditions, rend); | |
399 | ||
400 | rend->type = type; | |
401 | strcpy(rend->group_id, info->group_id); | |
402 | strcpy(rend->language, info->language); | |
403 | strcpy(rend->name, info->name); | |
404 | ||
405 | /* add the playlist if this is an external rendition */ | |
406 | if (info->uri[0]) { | |
407 | rend->playlist = new_playlist(c, info->uri, url_base); | |
408 | if (rend->playlist) | |
409 | dynarray_add(&rend->playlist->renditions, | |
410 | &rend->playlist->n_renditions, rend); | |
411 | } | |
412 | ||
413 | if (info->assoc_language[0]) { | |
414 | int langlen = strlen(rend->language); | |
415 | if (langlen < sizeof(rend->language) - 3) { | |
416 | rend->language[langlen] = ','; | |
417 | strncpy(rend->language + langlen + 1, info->assoc_language, | |
418 | sizeof(rend->language) - langlen - 2); | |
419 | } | |
420 | } | |
421 | ||
422 | if (!strcmp(info->defaultr, "YES")) | |
423 | rend->disposition |= AV_DISPOSITION_DEFAULT; | |
424 | if (!strcmp(info->forced, "YES")) | |
425 | rend->disposition |= AV_DISPOSITION_FORCED; | |
426 | ||
427 | chr_ptr = info->characteristics; | |
428 | while ((characteristic = av_strtok(chr_ptr, ",", &saveptr))) { | |
429 | if (!strcmp(characteristic, "public.accessibility.describes-music-and-sound")) | |
430 | rend->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; | |
431 | else if (!strcmp(characteristic, "public.accessibility.describes-video")) | |
432 | rend->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; | |
433 | ||
434 | chr_ptr = NULL; | |
435 | } | |
436 | ||
437 | return rend; | |
438 | } | |
439 | ||
440 | static void handle_rendition_args(struct rendition_info *info, const char *key, | |
441 | int key_len, char **dest, int *dest_len) | |
442 | { | |
443 | if (!strncmp(key, "TYPE=", key_len)) { | |
444 | *dest = info->type; | |
445 | *dest_len = sizeof(info->type); | |
446 | } else if (!strncmp(key, "URI=", key_len)) { | |
447 | *dest = info->uri; | |
448 | *dest_len = sizeof(info->uri); | |
449 | } else if (!strncmp(key, "GROUP-ID=", key_len)) { | |
450 | *dest = info->group_id; | |
451 | *dest_len = sizeof(info->group_id); | |
452 | } else if (!strncmp(key, "LANGUAGE=", key_len)) { | |
453 | *dest = info->language; | |
454 | *dest_len = sizeof(info->language); | |
455 | } else if (!strncmp(key, "ASSOC-LANGUAGE=", key_len)) { | |
456 | *dest = info->assoc_language; | |
457 | *dest_len = sizeof(info->assoc_language); | |
458 | } else if (!strncmp(key, "NAME=", key_len)) { | |
459 | *dest = info->name; | |
460 | *dest_len = sizeof(info->name); | |
461 | } else if (!strncmp(key, "DEFAULT=", key_len)) { | |
462 | *dest = info->defaultr; | |
463 | *dest_len = sizeof(info->defaultr); | |
464 | } else if (!strncmp(key, "FORCED=", key_len)) { | |
465 | *dest = info->forced; | |
466 | *dest_len = sizeof(info->forced); | |
467 | } else if (!strncmp(key, "CHARACTERISTICS=", key_len)) { | |
468 | *dest = info->characteristics; | |
469 | *dest_len = sizeof(info->characteristics); | |
470 | } | |
471 | /* | |
472 | * ignored: | |
473 | * - AUTOSELECT: client may autoselect based on e.g. system language | |
474 | * - INSTREAM-ID: EIA-608 closed caption number ("CC1".."CC4") | |
475 | */ | |
476 | } | |
477 | ||
478 | /* used by parse_playlist to allocate a new variant+playlist when the | |
479 | * playlist is detected to be a Media Playlist (not Master Playlist) | |
480 | * and we have no parent Master Playlist (parsing of which would have | |
481 | * allocated the variant and playlist already) */ | |
482 | static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url) | |
483 | { | |
484 | if (*pls) | |
485 | return 0; | |
486 | if (!new_variant(c, NULL, url, NULL)) | |
487 | return AVERROR(ENOMEM); | |
488 | *pls = c->playlists[c->n_playlists - 1]; | |
489 | return 0; | |
490 | } | |
491 | ||
492 | /* pls = NULL => Master Playlist or parentless Media Playlist | |
493 | * pls = !NULL => parented Media Playlist, playlist+variant allocated */ | |
494 | static int parse_playlist(HLSContext *c, const char *url, | |
495 | struct playlist *pls, AVIOContext *in) | |
496 | { | |
497 | int ret = 0, is_segment = 0, is_variant = 0; | |
498 | int64_t duration = 0; | |
499 | enum KeyType key_type = KEY_NONE; | |
500 | uint8_t iv[16] = ""; | |
501 | int has_iv = 0; | |
502 | char key[MAX_URL_SIZE] = ""; | |
503 | char line[MAX_URL_SIZE]; | |
504 | const char *ptr; | |
505 | int close_in = 0; | |
506 | int64_t seg_offset = 0; | |
507 | int64_t seg_size = -1; | |
508 | uint8_t *new_url = NULL; | |
509 | struct variant_info variant_info; | |
510 | char tmp_str[MAX_URL_SIZE]; | |
511 | ||
512 | if (!in) { | |
513 | AVDictionary *opts = NULL; | |
514 | close_in = 1; | |
515 | /* Some HLS servers don't like being sent the range header */ | |
516 | av_dict_set(&opts, "seekable", "0", 0); | |
517 | ||
518 | // broker prior HTTP options that should be consistent across requests | |
519 | av_dict_set(&opts, "user-agent", c->user_agent, 0); | |
520 | av_dict_set(&opts, "cookies", c->cookies, 0); | |
521 | av_dict_set(&opts, "headers", c->headers, 0); | |
522 | ||
523 | ret = avio_open2(&in, url, AVIO_FLAG_READ, | |
524 | c->interrupt_callback, &opts); | |
525 | av_dict_free(&opts); | |
526 | if (ret < 0) | |
527 | return ret; | |
528 | } | |
529 | ||
530 | if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) | |
531 | url = new_url; | |
532 | ||
533 | read_chomp_line(in, line, sizeof(line)); | |
534 | if (strcmp(line, "#EXTM3U")) { | |
535 | ret = AVERROR_INVALIDDATA; | |
536 | goto fail; | |
537 | } | |
538 | ||
539 | if (pls) { | |
540 | free_segment_list(pls); | |
541 | pls->finished = 0; | |
542 | pls->type = PLS_TYPE_UNSPECIFIED; | |
543 | } | |
544 | while (!avio_feof(in)) { | |
545 | read_chomp_line(in, line, sizeof(line)); | |
546 | if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { | |
547 | is_variant = 1; | |
548 | memset(&variant_info, 0, sizeof(variant_info)); | |
549 | ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, | |
550 | &variant_info); | |
551 | } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { | |
552 | struct key_info info = {{0}}; | |
553 | ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, | |
554 | &info); | |
555 | key_type = KEY_NONE; | |
556 | has_iv = 0; | |
557 | if (!strcmp(info.method, "AES-128")) | |
558 | key_type = KEY_AES_128; | |
559 | if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) { | |
560 | ff_hex_to_data(iv, info.iv + 2); | |
561 | has_iv = 1; | |
562 | } | |
563 | av_strlcpy(key, info.uri, sizeof(key)); | |
564 | } else if (av_strstart(line, "#EXT-X-MEDIA:", &ptr)) { | |
565 | struct rendition_info info = {{0}}; | |
566 | ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_rendition_args, | |
567 | &info); | |
568 | new_rendition(c, &info, url); | |
569 | } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { | |
570 | ret = ensure_playlist(c, &pls, url); | |
571 | if (ret < 0) | |
572 | goto fail; | |
573 | pls->target_duration = atoi(ptr) * AV_TIME_BASE; | |
574 | } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { | |
575 | ret = ensure_playlist(c, &pls, url); | |
576 | if (ret < 0) | |
577 | goto fail; | |
578 | pls->start_seq_no = atoi(ptr); | |
579 | } else if (av_strstart(line, "#EXT-X-PLAYLIST-TYPE:", &ptr)) { | |
580 | ret = ensure_playlist(c, &pls, url); | |
581 | if (ret < 0) | |
582 | goto fail; | |
583 | if (!strcmp(ptr, "EVENT")) | |
584 | pls->type = PLS_TYPE_EVENT; | |
585 | else if (!strcmp(ptr, "VOD")) | |
586 | pls->type = PLS_TYPE_VOD; | |
587 | } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { | |
588 | if (pls) | |
589 | pls->finished = 1; | |
590 | } else if (av_strstart(line, "#EXTINF:", &ptr)) { | |
591 | is_segment = 1; | |
592 | duration = atof(ptr) * AV_TIME_BASE; | |
593 | } else if (av_strstart(line, "#EXT-X-BYTERANGE:", &ptr)) { | |
594 | seg_size = atoi(ptr); | |
595 | ptr = strchr(ptr, '@'); | |
596 | if (ptr) | |
597 | seg_offset = atoi(ptr+1); | |
598 | } else if (av_strstart(line, "#", NULL)) { | |
599 | continue; | |
600 | } else if (line[0]) { | |
601 | if (is_variant) { | |
602 | if (!new_variant(c, &variant_info, line, url)) { | |
603 | ret = AVERROR(ENOMEM); | |
604 | goto fail; | |
605 | } | |
606 | is_variant = 0; | |
607 | } | |
608 | if (is_segment) { | |
609 | struct segment *seg; | |
610 | if (!pls) { | |
611 | if (!new_variant(c, 0, url, NULL)) { | |
612 | ret = AVERROR(ENOMEM); | |
613 | goto fail; | |
614 | } | |
615 | pls = c->playlists[c->n_playlists - 1]; | |
616 | } | |
617 | seg = av_malloc(sizeof(struct segment)); | |
618 | if (!seg) { | |
619 | ret = AVERROR(ENOMEM); | |
620 | goto fail; | |
621 | } | |
622 | seg->duration = duration; | |
623 | seg->key_type = key_type; | |
624 | if (has_iv) { | |
625 | memcpy(seg->iv, iv, sizeof(iv)); | |
626 | } else { | |
627 | int seq = pls->start_seq_no + pls->n_segments; | |
628 | memset(seg->iv, 0, sizeof(seg->iv)); | |
629 | AV_WB32(seg->iv + 12, seq); | |
630 | } | |
631 | ||
632 | if (key_type != KEY_NONE) { | |
633 | ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key); | |
634 | seg->key = av_strdup(tmp_str); | |
635 | if (!seg->key) { | |
636 | av_free(seg); | |
637 | ret = AVERROR(ENOMEM); | |
638 | goto fail; | |
639 | } | |
640 | } else { | |
641 | seg->key = NULL; | |
642 | } | |
643 | ||
644 | ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, line); | |
645 | seg->url = av_strdup(tmp_str); | |
646 | if (!seg->url) { | |
647 | av_free(seg->key); | |
648 | av_free(seg); | |
649 | ret = AVERROR(ENOMEM); | |
650 | goto fail; | |
651 | } | |
652 | ||
653 | dynarray_add(&pls->segments, &pls->n_segments, seg); | |
654 | is_segment = 0; | |
655 | ||
656 | seg->size = seg_size; | |
657 | if (seg_size >= 0) { | |
658 | seg->url_offset = seg_offset; | |
659 | seg_offset += seg_size; | |
660 | seg_size = -1; | |
661 | } else { | |
662 | seg->url_offset = 0; | |
663 | seg_offset = 0; | |
664 | } | |
665 | } | |
666 | } | |
667 | } | |
668 | if (pls) | |
f6fa7814 | 669 | pls->last_load_time = av_gettime_relative(); |
2ba45a60 DM |
670 | |
671 | fail: | |
672 | av_free(new_url); | |
673 | if (close_in) | |
674 | avio_close(in); | |
675 | return ret; | |
676 | } | |
677 | ||
678 | enum ReadFromURLMode { | |
679 | READ_NORMAL, | |
680 | READ_COMPLETE, | |
681 | }; | |
682 | ||
683 | /* read from URLContext, limiting read to current segment */ | |
684 | static int read_from_url(struct playlist *pls, uint8_t *buf, int buf_size, | |
685 | enum ReadFromURLMode mode) | |
686 | { | |
687 | int ret; | |
688 | struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no]; | |
689 | ||
690 | /* limit read if the segment was only a part of a file */ | |
691 | if (seg->size >= 0) | |
692 | buf_size = FFMIN(buf_size, seg->size - pls->cur_seg_offset); | |
693 | ||
694 | if (mode == READ_COMPLETE) | |
695 | ret = ffurl_read_complete(pls->input, buf, buf_size); | |
696 | else | |
697 | ret = ffurl_read(pls->input, buf, buf_size); | |
698 | ||
699 | if (ret > 0) | |
700 | pls->cur_seg_offset += ret; | |
701 | ||
702 | return ret; | |
703 | } | |
704 | ||
705 | /* Parse the raw ID3 data and pass contents to caller */ | |
706 | static void parse_id3(AVFormatContext *s, AVIOContext *pb, | |
707 | AVDictionary **metadata, int64_t *dts, | |
708 | ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta **extra_meta) | |
709 | { | |
710 | static const char id3_priv_owner_ts[] = "com.apple.streaming.transportStreamTimestamp"; | |
711 | ID3v2ExtraMeta *meta; | |
712 | ||
713 | ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta); | |
714 | for (meta = *extra_meta; meta; meta = meta->next) { | |
715 | if (!strcmp(meta->tag, "PRIV")) { | |
716 | ID3v2ExtraMetaPRIV *priv = meta->data; | |
717 | if (priv->datasize == 8 && !strcmp(priv->owner, id3_priv_owner_ts)) { | |
718 | /* 33-bit MPEG timestamp */ | |
719 | int64_t ts = AV_RB64(priv->data); | |
720 | av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp %"PRId64"\n", ts); | |
721 | if ((ts & ~((1ULL << 33) - 1)) == 0) | |
722 | *dts = ts; | |
723 | else | |
724 | av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio timestamp %"PRId64"\n", ts); | |
725 | } | |
726 | } else if (!strcmp(meta->tag, "APIC") && apic) | |
727 | *apic = meta->data; | |
728 | } | |
729 | } | |
730 | ||
731 | /* Check if the ID3 metadata contents have changed */ | |
732 | static int id3_has_changed_values(struct playlist *pls, AVDictionary *metadata, | |
733 | ID3v2ExtraMetaAPIC *apic) | |
734 | { | |
735 | AVDictionaryEntry *entry = NULL; | |
736 | AVDictionaryEntry *oldentry; | |
737 | /* check that no keys have changed values */ | |
738 | while ((entry = av_dict_get(metadata, "", entry, AV_DICT_IGNORE_SUFFIX))) { | |
739 | oldentry = av_dict_get(pls->id3_initial, entry->key, NULL, AV_DICT_MATCH_CASE); | |
740 | if (!oldentry || strcmp(oldentry->value, entry->value) != 0) | |
741 | return 1; | |
742 | } | |
743 | ||
744 | /* check if apic appeared */ | |
745 | if (apic && (pls->ctx->nb_streams != 2 || !pls->ctx->streams[1]->attached_pic.data)) | |
746 | return 1; | |
747 | ||
748 | if (apic) { | |
749 | int size = pls->ctx->streams[1]->attached_pic.size; | |
750 | if (size != apic->buf->size - FF_INPUT_BUFFER_PADDING_SIZE) | |
751 | return 1; | |
752 | ||
753 | if (memcmp(apic->buf->data, pls->ctx->streams[1]->attached_pic.data, size) != 0) | |
754 | return 1; | |
755 | } | |
756 | ||
757 | return 0; | |
758 | } | |
759 | ||
760 | /* Parse ID3 data and handle the found data */ | |
761 | static void handle_id3(AVIOContext *pb, struct playlist *pls) | |
762 | { | |
763 | AVDictionary *metadata = NULL; | |
764 | ID3v2ExtraMetaAPIC *apic = NULL; | |
765 | ID3v2ExtraMeta *extra_meta = NULL; | |
766 | int64_t timestamp = AV_NOPTS_VALUE; | |
767 | ||
768 | parse_id3(pls->ctx, pb, &metadata, ×tamp, &apic, &extra_meta); | |
769 | ||
770 | if (timestamp != AV_NOPTS_VALUE) { | |
771 | pls->id3_mpegts_timestamp = timestamp; | |
772 | pls->id3_offset = 0; | |
773 | } | |
774 | ||
775 | if (!pls->id3_found) { | |
776 | /* initial ID3 tags */ | |
777 | av_assert0(!pls->id3_deferred_extra); | |
778 | pls->id3_found = 1; | |
779 | ||
780 | /* get picture attachment and set text metadata */ | |
781 | if (pls->ctx->nb_streams) | |
782 | ff_id3v2_parse_apic(pls->ctx, &extra_meta); | |
783 | else | |
784 | /* demuxer not yet opened, defer picture attachment */ | |
785 | pls->id3_deferred_extra = extra_meta; | |
786 | ||
787 | av_dict_copy(&pls->ctx->metadata, metadata, 0); | |
788 | pls->id3_initial = metadata; | |
789 | ||
790 | } else { | |
791 | if (!pls->id3_changed && id3_has_changed_values(pls, metadata, apic)) { | |
792 | avpriv_report_missing_feature(pls->ctx, "Changing ID3 metadata in HLS audio elementary stream"); | |
793 | pls->id3_changed = 1; | |
794 | } | |
795 | av_dict_free(&metadata); | |
796 | } | |
797 | ||
798 | if (!pls->id3_deferred_extra) | |
799 | ff_id3v2_free_extra_meta(&extra_meta); | |
800 | } | |
801 | ||
802 | /* Intercept and handle ID3 tags between URLContext and AVIOContext */ | |
803 | static void intercept_id3(struct playlist *pls, uint8_t *buf, | |
804 | int buf_size, int *len) | |
805 | { | |
806 | /* intercept id3 tags, we do not want to pass them to the raw | |
807 | * demuxer on all segment switches */ | |
808 | int bytes; | |
809 | int id3_buf_pos = 0; | |
810 | int fill_buf = 0; | |
811 | ||
812 | /* gather all the id3 tags */ | |
813 | while (1) { | |
814 | /* see if we can retrieve enough data for ID3 header */ | |
815 | if (*len < ID3v2_HEADER_SIZE && buf_size >= ID3v2_HEADER_SIZE) { | |
816 | bytes = read_from_url(pls, buf + *len, ID3v2_HEADER_SIZE - *len, READ_COMPLETE); | |
817 | if (bytes > 0) { | |
818 | ||
819 | if (bytes == ID3v2_HEADER_SIZE - *len) | |
820 | /* no EOF yet, so fill the caller buffer again after | |
821 | * we have stripped the ID3 tags */ | |
822 | fill_buf = 1; | |
823 | ||
824 | *len += bytes; | |
825 | ||
826 | } else if (*len <= 0) { | |
827 | /* error/EOF */ | |
828 | *len = bytes; | |
829 | fill_buf = 0; | |
830 | } | |
831 | } | |
832 | ||
833 | if (*len < ID3v2_HEADER_SIZE) | |
834 | break; | |
835 | ||
836 | if (ff_id3v2_match(buf, ID3v2_DEFAULT_MAGIC)) { | |
837 | struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no]; | |
838 | int64_t maxsize = seg->size >= 0 ? seg->size : 1024*1024; | |
839 | int taglen = ff_id3v2_tag_len(buf); | |
840 | int tag_got_bytes = FFMIN(taglen, *len); | |
841 | int remaining = taglen - tag_got_bytes; | |
842 | ||
843 | if (taglen > maxsize) { | |
844 | av_log(pls->ctx, AV_LOG_ERROR, "Too large HLS ID3 tag (%d > %"PRId64" bytes)\n", | |
845 | taglen, maxsize); | |
846 | break; | |
847 | } | |
848 | ||
849 | /* | |
850 | * Copy the id3 tag to our temporary id3 buffer. | |
851 | * We could read a small id3 tag directly without memcpy, but | |
852 | * we would still need to copy the large tags, and handling | |
853 | * both of those cases together with the possibility for multiple | |
854 | * tags would make the handling a bit complex. | |
855 | */ | |
856 | pls->id3_buf = av_fast_realloc(pls->id3_buf, &pls->id3_buf_size, id3_buf_pos + taglen); | |
857 | if (!pls->id3_buf) | |
858 | break; | |
859 | memcpy(pls->id3_buf + id3_buf_pos, buf, tag_got_bytes); | |
860 | id3_buf_pos += tag_got_bytes; | |
861 | ||
862 | /* strip the intercepted bytes */ | |
863 | *len -= tag_got_bytes; | |
864 | memmove(buf, buf + tag_got_bytes, *len); | |
865 | av_log(pls->ctx, AV_LOG_DEBUG, "Stripped %d HLS ID3 bytes\n", tag_got_bytes); | |
866 | ||
867 | if (remaining > 0) { | |
868 | /* read the rest of the tag in */ | |
869 | if (read_from_url(pls, pls->id3_buf + id3_buf_pos, remaining, READ_COMPLETE) != remaining) | |
870 | break; | |
871 | id3_buf_pos += remaining; | |
872 | av_log(pls->ctx, AV_LOG_DEBUG, "Stripped additional %d HLS ID3 bytes\n", remaining); | |
873 | } | |
874 | ||
875 | } else { | |
876 | /* no more ID3 tags */ | |
877 | break; | |
878 | } | |
879 | } | |
880 | ||
881 | /* re-fill buffer for the caller unless EOF */ | |
882 | if (*len >= 0 && (fill_buf || *len == 0)) { | |
883 | bytes = read_from_url(pls, buf + *len, buf_size - *len, READ_NORMAL); | |
884 | ||
885 | /* ignore error if we already had some data */ | |
886 | if (bytes >= 0) | |
887 | *len += bytes; | |
888 | else if (*len == 0) | |
889 | *len = bytes; | |
890 | } | |
891 | ||
892 | if (pls->id3_buf) { | |
893 | /* Now parse all the ID3 tags */ | |
894 | AVIOContext id3ioctx; | |
895 | ffio_init_context(&id3ioctx, pls->id3_buf, id3_buf_pos, 0, NULL, NULL, NULL, NULL); | |
896 | handle_id3(&id3ioctx, pls); | |
897 | } | |
898 | ||
899 | if (pls->is_id3_timestamped == -1) | |
900 | pls->is_id3_timestamped = (pls->id3_mpegts_timestamp != AV_NOPTS_VALUE); | |
901 | } | |
902 | ||
903 | static int open_input(HLSContext *c, struct playlist *pls) | |
904 | { | |
905 | AVDictionary *opts = NULL; | |
906 | AVDictionary *opts2 = NULL; | |
907 | int ret; | |
908 | struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no]; | |
909 | ||
910 | // broker prior HTTP options that should be consistent across requests | |
911 | av_dict_set(&opts, "user-agent", c->user_agent, 0); | |
912 | av_dict_set(&opts, "cookies", c->cookies, 0); | |
913 | av_dict_set(&opts, "headers", c->headers, 0); | |
914 | av_dict_set(&opts, "seekable", "0", 0); | |
915 | ||
916 | // Same opts for key request (ffurl_open mutilates the opts so it cannot be used twice) | |
917 | av_dict_copy(&opts2, opts, 0); | |
918 | ||
919 | if (seg->size >= 0) { | |
920 | /* try to restrict the HTTP request to the part we want | |
921 | * (if this is in fact a HTTP request) */ | |
922 | av_dict_set_int(&opts, "offset", seg->url_offset, 0); | |
923 | av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0); | |
924 | } | |
925 | ||
926 | av_log(pls->parent, AV_LOG_VERBOSE, "HLS request for url '%s', offset %"PRId64", playlist %d\n", | |
927 | seg->url, seg->url_offset, pls->index); | |
928 | ||
929 | if (seg->key_type == KEY_NONE) { | |
930 | ret = ffurl_open(&pls->input, seg->url, AVIO_FLAG_READ, | |
931 | &pls->parent->interrupt_callback, &opts); | |
932 | ||
933 | } else if (seg->key_type == KEY_AES_128) { | |
934 | char iv[33], key[33], url[MAX_URL_SIZE]; | |
935 | if (strcmp(seg->key, pls->key_url)) { | |
936 | URLContext *uc; | |
937 | if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ, | |
938 | &pls->parent->interrupt_callback, &opts2) == 0) { | |
939 | if (ffurl_read_complete(uc, pls->key, sizeof(pls->key)) | |
940 | != sizeof(pls->key)) { | |
941 | av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", | |
942 | seg->key); | |
943 | } | |
944 | ffurl_close(uc); | |
945 | } else { | |
946 | av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", | |
947 | seg->key); | |
948 | } | |
949 | av_strlcpy(pls->key_url, seg->key, sizeof(pls->key_url)); | |
950 | } | |
951 | ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0); | |
952 | ff_data_to_hex(key, pls->key, sizeof(pls->key), 0); | |
953 | iv[32] = key[32] = '\0'; | |
954 | if (strstr(seg->url, "://")) | |
955 | snprintf(url, sizeof(url), "crypto+%s", seg->url); | |
956 | else | |
957 | snprintf(url, sizeof(url), "crypto:%s", seg->url); | |
958 | if ((ret = ffurl_alloc(&pls->input, url, AVIO_FLAG_READ, | |
959 | &pls->parent->interrupt_callback)) < 0) | |
960 | goto cleanup; | |
961 | av_opt_set(pls->input->priv_data, "key", key, 0); | |
962 | av_opt_set(pls->input->priv_data, "iv", iv, 0); | |
963 | ||
964 | if ((ret = ffurl_connect(pls->input, &opts)) < 0) { | |
965 | ffurl_close(pls->input); | |
966 | pls->input = NULL; | |
967 | goto cleanup; | |
968 | } | |
969 | ret = 0; | |
970 | } | |
971 | else | |
972 | ret = AVERROR(ENOSYS); | |
973 | ||
974 | /* Seek to the requested position. If this was a HTTP request, the offset | |
975 | * should already be where want it to, but this allows e.g. local testing | |
976 | * without a HTTP server. */ | |
977 | if (ret == 0 && seg->key_type == KEY_NONE) { | |
978 | int seekret = ffurl_seek(pls->input, seg->url_offset, SEEK_SET); | |
979 | if (seekret < 0) { | |
980 | av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url); | |
981 | ret = seekret; | |
982 | ffurl_close(pls->input); | |
983 | pls->input = NULL; | |
984 | } | |
985 | } | |
986 | ||
987 | cleanup: | |
988 | av_dict_free(&opts); | |
989 | av_dict_free(&opts2); | |
990 | pls->cur_seg_offset = 0; | |
991 | return ret; | |
992 | } | |
993 | ||
994 | static int64_t default_reload_interval(struct playlist *pls) | |
995 | { | |
996 | return pls->n_segments > 0 ? | |
997 | pls->segments[pls->n_segments - 1]->duration : | |
998 | pls->target_duration; | |
999 | } | |
1000 | ||
1001 | static int read_data(void *opaque, uint8_t *buf, int buf_size) | |
1002 | { | |
1003 | struct playlist *v = opaque; | |
1004 | HLSContext *c = v->parent->priv_data; | |
1005 | int ret, i; | |
1006 | int just_opened = 0; | |
1007 | ||
1008 | restart: | |
1009 | if (!v->needed) | |
1010 | return AVERROR_EOF; | |
1011 | ||
1012 | if (!v->input) { | |
1013 | int64_t reload_interval; | |
1014 | ||
1015 | /* Check that the playlist is still needed before opening a new | |
1016 | * segment. */ | |
1017 | if (v->ctx && v->ctx->nb_streams && | |
1018 | v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) { | |
1019 | v->needed = 0; | |
1020 | for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; | |
1021 | i++) { | |
1022 | if (v->parent->streams[i]->discard < AVDISCARD_ALL) | |
1023 | v->needed = 1; | |
1024 | } | |
1025 | } | |
1026 | if (!v->needed) { | |
1027 | av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d\n", | |
1028 | v->index); | |
1029 | return AVERROR_EOF; | |
1030 | } | |
1031 | ||
1032 | /* If this is a live stream and the reload interval has elapsed since | |
1033 | * the last playlist reload, reload the playlists now. */ | |
1034 | reload_interval = default_reload_interval(v); | |
1035 | ||
1036 | reload: | |
1037 | if (!v->finished && | |
f6fa7814 | 1038 | av_gettime_relative() - v->last_load_time >= reload_interval) { |
2ba45a60 DM |
1039 | if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) { |
1040 | av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n", | |
1041 | v->index); | |
1042 | return ret; | |
1043 | } | |
1044 | /* If we need to reload the playlist again below (if | |
1045 | * there's still no more segments), switch to a reload | |
1046 | * interval of half the target duration. */ | |
1047 | reload_interval = v->target_duration / 2; | |
1048 | } | |
1049 | if (v->cur_seq_no < v->start_seq_no) { | |
1050 | av_log(NULL, AV_LOG_WARNING, | |
1051 | "skipping %d segments ahead, expired from playlists\n", | |
1052 | v->start_seq_no - v->cur_seq_no); | |
1053 | v->cur_seq_no = v->start_seq_no; | |
1054 | } | |
1055 | if (v->cur_seq_no >= v->start_seq_no + v->n_segments) { | |
1056 | if (v->finished) | |
1057 | return AVERROR_EOF; | |
f6fa7814 | 1058 | while (av_gettime_relative() - v->last_load_time < reload_interval) { |
2ba45a60 DM |
1059 | if (ff_check_interrupt(c->interrupt_callback)) |
1060 | return AVERROR_EXIT; | |
1061 | av_usleep(100*1000); | |
1062 | } | |
1063 | /* Enough time has elapsed since the last reload */ | |
1064 | goto reload; | |
1065 | } | |
1066 | ||
1067 | ret = open_input(c, v); | |
1068 | if (ret < 0) { | |
1069 | av_log(v->parent, AV_LOG_WARNING, "Failed to open segment of playlist %d\n", | |
1070 | v->index); | |
1071 | return ret; | |
1072 | } | |
1073 | just_opened = 1; | |
1074 | } | |
1075 | ||
1076 | ret = read_from_url(v, buf, buf_size, READ_NORMAL); | |
1077 | if (ret > 0) { | |
1078 | if (just_opened && v->is_id3_timestamped != 0) { | |
1079 | /* Intercept ID3 tags here, elementary audio streams are required | |
1080 | * to convey timestamps using them in the beginning of each segment. */ | |
1081 | intercept_id3(v, buf, buf_size, &ret); | |
1082 | } | |
1083 | ||
1084 | return ret; | |
1085 | } | |
1086 | ffurl_close(v->input); | |
1087 | v->input = NULL; | |
1088 | v->cur_seq_no++; | |
1089 | ||
1090 | c->cur_seq_no = v->cur_seq_no; | |
1091 | ||
1092 | goto restart; | |
1093 | } | |
1094 | ||
1095 | static int playlist_in_multiple_variants(HLSContext *c, struct playlist *pls) | |
1096 | { | |
1097 | int variant_count = 0; | |
1098 | int i, j; | |
1099 | ||
1100 | for (i = 0; i < c->n_variants && variant_count < 2; i++) { | |
1101 | struct variant *v = c->variants[i]; | |
1102 | ||
1103 | for (j = 0; j < v->n_playlists; j++) { | |
1104 | if (v->playlists[j] == pls) { | |
1105 | variant_count++; | |
1106 | break; | |
1107 | } | |
1108 | } | |
1109 | } | |
1110 | ||
1111 | return variant_count >= 2; | |
1112 | } | |
1113 | ||
1114 | static void add_renditions_to_variant(HLSContext *c, struct variant *var, | |
1115 | enum AVMediaType type, const char *group_id) | |
1116 | { | |
1117 | int i; | |
1118 | ||
1119 | for (i = 0; i < c->n_renditions; i++) { | |
1120 | struct rendition *rend = c->renditions[i]; | |
1121 | ||
1122 | if (rend->type == type && !strcmp(rend->group_id, group_id)) { | |
1123 | ||
1124 | if (rend->playlist) | |
1125 | /* rendition is an external playlist | |
1126 | * => add the playlist to the variant */ | |
1127 | dynarray_add(&var->playlists, &var->n_playlists, rend->playlist); | |
1128 | else | |
1129 | /* rendition is part of the variant main Media Playlist | |
1130 | * => add the rendition to the main Media Playlist */ | |
1131 | dynarray_add(&var->playlists[0]->renditions, | |
1132 | &var->playlists[0]->n_renditions, | |
1133 | rend); | |
1134 | } | |
1135 | } | |
1136 | } | |
1137 | ||
1138 | static void add_metadata_from_renditions(AVFormatContext *s, struct playlist *pls, | |
1139 | enum AVMediaType type) | |
1140 | { | |
1141 | int rend_idx = 0; | |
1142 | int i; | |
1143 | ||
1144 | for (i = 0; i < pls->ctx->nb_streams; i++) { | |
1145 | AVStream *st = s->streams[pls->stream_offset + i]; | |
1146 | ||
1147 | if (st->codec->codec_type != type) | |
1148 | continue; | |
1149 | ||
1150 | for (; rend_idx < pls->n_renditions; rend_idx++) { | |
1151 | struct rendition *rend = pls->renditions[rend_idx]; | |
1152 | ||
1153 | if (rend->type != type) | |
1154 | continue; | |
1155 | ||
1156 | if (rend->language[0]) | |
1157 | av_dict_set(&st->metadata, "language", rend->language, 0); | |
1158 | if (rend->name[0]) | |
1159 | av_dict_set(&st->metadata, "comment", rend->name, 0); | |
1160 | ||
1161 | st->disposition |= rend->disposition; | |
1162 | } | |
1163 | if (rend_idx >=pls->n_renditions) | |
1164 | break; | |
1165 | } | |
1166 | } | |
1167 | ||
1168 | /* if timestamp was in valid range: returns 1 and sets seq_no | |
1169 | * if not: returns 0 and sets seq_no to closest segment */ | |
1170 | static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, | |
1171 | int64_t timestamp, int *seq_no) | |
1172 | { | |
1173 | int i; | |
1174 | int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? | |
1175 | 0 : c->first_timestamp; | |
1176 | ||
1177 | if (timestamp < pos) { | |
1178 | *seq_no = pls->start_seq_no; | |
1179 | return 0; | |
1180 | } | |
1181 | ||
1182 | for (i = 0; i < pls->n_segments; i++) { | |
1183 | int64_t diff = pos + pls->segments[i]->duration - timestamp; | |
1184 | if (diff > 0) { | |
1185 | *seq_no = pls->start_seq_no + i; | |
1186 | return 1; | |
1187 | } | |
1188 | pos += pls->segments[i]->duration; | |
1189 | } | |
1190 | ||
1191 | *seq_no = pls->start_seq_no + pls->n_segments - 1; | |
1192 | ||
1193 | return 0; | |
1194 | } | |
1195 | ||
1196 | static int select_cur_seq_no(HLSContext *c, struct playlist *pls) | |
1197 | { | |
1198 | int seq_no; | |
1199 | ||
1200 | if (!pls->finished && !c->first_packet && | |
f6fa7814 | 1201 | av_gettime_relative() - pls->last_load_time >= default_reload_interval(pls)) |
2ba45a60 DM |
1202 | /* reload the playlist since it was suspended */ |
1203 | parse_playlist(c, pls->url, pls, NULL); | |
1204 | ||
1205 | /* If playback is already in progress (we are just selecting a new | |
1206 | * playlist) and this is a complete file, find the matching segment | |
1207 | * by counting durations. */ | |
1208 | if (pls->finished && c->cur_timestamp != AV_NOPTS_VALUE) { | |
1209 | find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no); | |
1210 | return seq_no; | |
1211 | } | |
1212 | ||
1213 | if (!pls->finished) { | |
1214 | if (!c->first_packet && /* we are doing a segment selection during playback */ | |
1215 | c->cur_seq_no >= pls->start_seq_no && | |
1216 | c->cur_seq_no < pls->start_seq_no + pls->n_segments) | |
1217 | /* While spec 3.4.3 says that we cannot assume anything about the | |
1218 | * content at the same sequence number on different playlists, | |
1219 | * in practice this seems to work and doing it otherwise would | |
1220 | * require us to download a segment to inspect its timestamps. */ | |
1221 | return c->cur_seq_no; | |
1222 | ||
1223 | /* If this is a live stream with more than 3 segments, start at the | |
1224 | * third last segment. */ | |
1225 | if (pls->n_segments > 3) | |
1226 | return pls->start_seq_no + pls->n_segments - 3; | |
1227 | } | |
1228 | ||
1229 | /* Otherwise just start on the first segment. */ | |
1230 | return pls->start_seq_no; | |
1231 | } | |
1232 | ||
1233 | static int hls_read_header(AVFormatContext *s) | |
1234 | { | |
1235 | URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque; | |
1236 | HLSContext *c = s->priv_data; | |
1237 | int ret = 0, i, j, stream_offset = 0; | |
1238 | ||
1239 | c->interrupt_callback = &s->interrupt_callback; | |
1240 | ||
1241 | c->first_packet = 1; | |
1242 | c->first_timestamp = AV_NOPTS_VALUE; | |
1243 | c->cur_timestamp = AV_NOPTS_VALUE; | |
1244 | ||
1245 | // if the URL context is good, read important options we must broker later | |
1246 | if (u && u->prot->priv_data_class) { | |
1247 | // get the previous user agent & set back to null if string size is zero | |
1248 | av_freep(&c->user_agent); | |
1249 | av_opt_get(u->priv_data, "user-agent", 0, (uint8_t**)&(c->user_agent)); | |
1250 | if (c->user_agent && !strlen(c->user_agent)) | |
1251 | av_freep(&c->user_agent); | |
1252 | ||
1253 | // get the previous cookies & set back to null if string size is zero | |
1254 | av_freep(&c->cookies); | |
1255 | av_opt_get(u->priv_data, "cookies", 0, (uint8_t**)&(c->cookies)); | |
1256 | if (c->cookies && !strlen(c->cookies)) | |
1257 | av_freep(&c->cookies); | |
1258 | ||
1259 | // get the previous headers & set back to null if string size is zero | |
1260 | av_freep(&c->headers); | |
1261 | av_opt_get(u->priv_data, "headers", 0, (uint8_t**)&(c->headers)); | |
1262 | if (c->headers && !strlen(c->headers)) | |
1263 | av_freep(&c->headers); | |
1264 | } | |
1265 | ||
1266 | if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) | |
1267 | goto fail; | |
1268 | ||
1269 | if (c->n_variants == 0) { | |
1270 | av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); | |
1271 | ret = AVERROR_EOF; | |
1272 | goto fail; | |
1273 | } | |
1274 | /* If the playlist only contained playlists (Master Playlist), | |
1275 | * parse each individual playlist. */ | |
1276 | if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) { | |
1277 | for (i = 0; i < c->n_playlists; i++) { | |
1278 | struct playlist *pls = c->playlists[i]; | |
1279 | if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0) | |
1280 | goto fail; | |
1281 | } | |
1282 | } | |
1283 | ||
1284 | if (c->variants[0]->playlists[0]->n_segments == 0) { | |
1285 | av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); | |
1286 | ret = AVERROR_EOF; | |
1287 | goto fail; | |
1288 | } | |
1289 | ||
1290 | /* If this isn't a live stream, calculate the total duration of the | |
1291 | * stream. */ | |
1292 | if (c->variants[0]->playlists[0]->finished) { | |
1293 | int64_t duration = 0; | |
1294 | for (i = 0; i < c->variants[0]->playlists[0]->n_segments; i++) | |
1295 | duration += c->variants[0]->playlists[0]->segments[i]->duration; | |
1296 | s->duration = duration; | |
1297 | } | |
1298 | ||
1299 | /* Associate renditions with variants */ | |
1300 | for (i = 0; i < c->n_variants; i++) { | |
1301 | struct variant *var = c->variants[i]; | |
1302 | ||
1303 | if (var->audio_group[0]) | |
1304 | add_renditions_to_variant(c, var, AVMEDIA_TYPE_AUDIO, var->audio_group); | |
1305 | if (var->video_group[0]) | |
1306 | add_renditions_to_variant(c, var, AVMEDIA_TYPE_VIDEO, var->video_group); | |
1307 | if (var->subtitles_group[0]) | |
1308 | add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group); | |
1309 | } | |
1310 | ||
1311 | /* Open the demuxer for each playlist */ | |
1312 | for (i = 0; i < c->n_playlists; i++) { | |
1313 | struct playlist *pls = c->playlists[i]; | |
1314 | AVInputFormat *in_fmt = NULL; | |
1315 | ||
1316 | if (pls->n_segments == 0) | |
1317 | continue; | |
1318 | ||
1319 | if (!(pls->ctx = avformat_alloc_context())) { | |
1320 | ret = AVERROR(ENOMEM); | |
1321 | goto fail; | |
1322 | } | |
1323 | ||
1324 | pls->index = i; | |
1325 | pls->needed = 1; | |
1326 | pls->parent = s; | |
1327 | pls->cur_seq_no = select_cur_seq_no(c, pls); | |
1328 | ||
1329 | pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); | |
1330 | ffio_init_context(&pls->pb, pls->read_buffer, INITIAL_BUFFER_SIZE, 0, pls, | |
1331 | read_data, NULL, NULL); | |
1332 | pls->pb.seekable = 0; | |
1333 | ret = av_probe_input_buffer(&pls->pb, &in_fmt, pls->segments[0]->url, | |
1334 | NULL, 0, 0); | |
1335 | if (ret < 0) { | |
1336 | /* Free the ctx - it isn't initialized properly at this point, | |
1337 | * so avformat_close_input shouldn't be called. If | |
1338 | * avformat_open_input fails below, it frees and zeros the | |
1339 | * context, so it doesn't need any special treatment like this. */ | |
1340 | av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", pls->segments[0]->url); | |
1341 | avformat_free_context(pls->ctx); | |
1342 | pls->ctx = NULL; | |
1343 | goto fail; | |
1344 | } | |
1345 | pls->ctx->pb = &pls->pb; | |
1346 | pls->stream_offset = stream_offset; | |
f6fa7814 DM |
1347 | |
1348 | if ((ret = ff_copy_whitelists(pls->ctx, s)) < 0) | |
1349 | goto fail; | |
1350 | ||
2ba45a60 DM |
1351 | ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, NULL); |
1352 | if (ret < 0) | |
1353 | goto fail; | |
1354 | ||
1355 | if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) { | |
1356 | ff_id3v2_parse_apic(pls->ctx, &pls->id3_deferred_extra); | |
1357 | avformat_queue_attached_pictures(pls->ctx); | |
1358 | ff_id3v2_free_extra_meta(&pls->id3_deferred_extra); | |
1359 | pls->id3_deferred_extra = NULL; | |
1360 | } | |
1361 | ||
1362 | pls->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; | |
1363 | ret = avformat_find_stream_info(pls->ctx, NULL); | |
1364 | if (ret < 0) | |
1365 | goto fail; | |
1366 | ||
1367 | if (pls->is_id3_timestamped == -1) | |
1368 | av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been made\n"); | |
1369 | ||
1370 | /* Create new AVStreams for each stream in this playlist */ | |
1371 | for (j = 0; j < pls->ctx->nb_streams; j++) { | |
1372 | AVStream *st = avformat_new_stream(s, NULL); | |
1373 | AVStream *ist = pls->ctx->streams[j]; | |
1374 | if (!st) { | |
1375 | ret = AVERROR(ENOMEM); | |
1376 | goto fail; | |
1377 | } | |
1378 | st->id = i; | |
1379 | ||
1380 | avcodec_copy_context(st->codec, pls->ctx->streams[j]->codec); | |
1381 | ||
1382 | if (pls->is_id3_timestamped) /* custom timestamps via id3 */ | |
1383 | avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE); | |
1384 | else | |
1385 | avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); | |
1386 | } | |
1387 | ||
1388 | add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO); | |
1389 | add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO); | |
1390 | add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE); | |
1391 | ||
1392 | stream_offset += pls->ctx->nb_streams; | |
1393 | } | |
1394 | ||
1395 | /* Create a program for each variant */ | |
1396 | for (i = 0; i < c->n_variants; i++) { | |
1397 | struct variant *v = c->variants[i]; | |
1398 | AVProgram *program; | |
1399 | ||
1400 | program = av_new_program(s, i); | |
1401 | if (!program) | |
1402 | goto fail; | |
1403 | av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0); | |
1404 | ||
1405 | for (j = 0; j < v->n_playlists; j++) { | |
1406 | struct playlist *pls = v->playlists[j]; | |
1407 | int is_shared = playlist_in_multiple_variants(c, pls); | |
1408 | int k; | |
1409 | ||
1410 | for (k = 0; k < pls->ctx->nb_streams; k++) { | |
1411 | struct AVStream *st = s->streams[pls->stream_offset + k]; | |
1412 | ||
1413 | ff_program_add_stream_index(s, i, pls->stream_offset + k); | |
1414 | ||
1415 | /* Set variant_bitrate for streams unique to this variant */ | |
1416 | if (!is_shared && v->bandwidth) | |
1417 | av_dict_set_int(&st->metadata, "variant_bitrate", v->bandwidth, 0); | |
1418 | } | |
1419 | } | |
1420 | } | |
1421 | ||
1422 | return 0; | |
1423 | fail: | |
1424 | free_playlist_list(c); | |
1425 | free_variant_list(c); | |
1426 | free_rendition_list(c); | |
1427 | return ret; | |
1428 | } | |
1429 | ||
1430 | static int recheck_discard_flags(AVFormatContext *s, int first) | |
1431 | { | |
1432 | HLSContext *c = s->priv_data; | |
1433 | int i, changed = 0; | |
1434 | ||
1435 | /* Check if any new streams are needed */ | |
1436 | for (i = 0; i < c->n_playlists; i++) | |
1437 | c->playlists[i]->cur_needed = 0; | |
1438 | ||
1439 | for (i = 0; i < s->nb_streams; i++) { | |
1440 | AVStream *st = s->streams[i]; | |
1441 | struct playlist *pls = c->playlists[s->streams[i]->id]; | |
1442 | if (st->discard < AVDISCARD_ALL) | |
1443 | pls->cur_needed = 1; | |
1444 | } | |
1445 | for (i = 0; i < c->n_playlists; i++) { | |
1446 | struct playlist *pls = c->playlists[i]; | |
1447 | if (pls->cur_needed && !pls->needed) { | |
1448 | pls->needed = 1; | |
1449 | changed = 1; | |
1450 | pls->cur_seq_no = select_cur_seq_no(c, pls); | |
1451 | pls->pb.eof_reached = 0; | |
1452 | if (c->cur_timestamp != AV_NOPTS_VALUE) { | |
1453 | /* catch up */ | |
1454 | pls->seek_timestamp = c->cur_timestamp; | |
1455 | pls->seek_flags = AVSEEK_FLAG_ANY; | |
1456 | pls->seek_stream_index = -1; | |
1457 | } | |
1458 | av_log(s, AV_LOG_INFO, "Now receiving playlist %d, segment %d\n", i, pls->cur_seq_no); | |
1459 | } else if (first && !pls->cur_needed && pls->needed) { | |
1460 | if (pls->input) | |
1461 | ffurl_close(pls->input); | |
1462 | pls->input = NULL; | |
1463 | pls->needed = 0; | |
1464 | changed = 1; | |
1465 | av_log(s, AV_LOG_INFO, "No longer receiving playlist %d\n", i); | |
1466 | } | |
1467 | } | |
1468 | return changed; | |
1469 | } | |
1470 | ||
1471 | static void fill_timing_for_id3_timestamped_stream(struct playlist *pls) | |
1472 | { | |
1473 | if (pls->id3_offset >= 0) { | |
1474 | pls->pkt.dts = pls->id3_mpegts_timestamp + | |
1475 | av_rescale_q(pls->id3_offset, | |
1476 | pls->ctx->streams[pls->pkt.stream_index]->time_base, | |
1477 | MPEG_TIME_BASE_Q); | |
1478 | if (pls->pkt.duration) | |
1479 | pls->id3_offset += pls->pkt.duration; | |
1480 | else | |
1481 | pls->id3_offset = -1; | |
1482 | } else { | |
1483 | /* there have been packets with unknown duration | |
1484 | * since the last id3 tag, should not normally happen */ | |
1485 | pls->pkt.dts = AV_NOPTS_VALUE; | |
1486 | } | |
1487 | ||
1488 | if (pls->pkt.duration) | |
1489 | pls->pkt.duration = av_rescale_q(pls->pkt.duration, | |
1490 | pls->ctx->streams[pls->pkt.stream_index]->time_base, | |
1491 | MPEG_TIME_BASE_Q); | |
1492 | ||
1493 | pls->pkt.pts = AV_NOPTS_VALUE; | |
1494 | } | |
1495 | ||
1496 | static AVRational get_timebase(struct playlist *pls) | |
1497 | { | |
1498 | if (pls->is_id3_timestamped) | |
1499 | return MPEG_TIME_BASE_Q; | |
1500 | ||
1501 | return pls->ctx->streams[pls->pkt.stream_index]->time_base; | |
1502 | } | |
1503 | ||
1504 | static int compare_ts_with_wrapdetect(int64_t ts_a, struct playlist *pls_a, | |
1505 | int64_t ts_b, struct playlist *pls_b) | |
1506 | { | |
1507 | int64_t scaled_ts_a = av_rescale_q(ts_a, get_timebase(pls_a), MPEG_TIME_BASE_Q); | |
1508 | int64_t scaled_ts_b = av_rescale_q(ts_b, get_timebase(pls_b), MPEG_TIME_BASE_Q); | |
1509 | ||
1510 | return av_compare_mod(scaled_ts_a, scaled_ts_b, 1LL << 33); | |
1511 | } | |
1512 | ||
1513 | static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) | |
1514 | { | |
1515 | HLSContext *c = s->priv_data; | |
1516 | int ret, i, minplaylist = -1; | |
1517 | ||
1518 | recheck_discard_flags(s, c->first_packet); | |
1519 | ||
1520 | for (i = 0; i < c->n_playlists; i++) { | |
1521 | struct playlist *pls = c->playlists[i]; | |
1522 | /* Make sure we've got one buffered packet from each open playlist | |
1523 | * stream */ | |
1524 | if (pls->needed && !pls->pkt.data) { | |
1525 | while (1) { | |
1526 | int64_t ts_diff; | |
1527 | AVRational tb; | |
1528 | ret = av_read_frame(pls->ctx, &pls->pkt); | |
1529 | if (ret < 0) { | |
1530 | if (!avio_feof(&pls->pb) && ret != AVERROR_EOF) | |
1531 | return ret; | |
1532 | reset_packet(&pls->pkt); | |
1533 | break; | |
1534 | } else { | |
1535 | /* stream_index check prevents matching picture attachments etc. */ | |
1536 | if (pls->is_id3_timestamped && pls->pkt.stream_index == 0) { | |
1537 | /* audio elementary streams are id3 timestamped */ | |
1538 | fill_timing_for_id3_timestamped_stream(pls); | |
1539 | } | |
1540 | ||
1541 | if (c->first_timestamp == AV_NOPTS_VALUE && | |
1542 | pls->pkt.dts != AV_NOPTS_VALUE) | |
1543 | c->first_timestamp = av_rescale_q(pls->pkt.dts, | |
1544 | get_timebase(pls), AV_TIME_BASE_Q); | |
1545 | } | |
1546 | ||
1547 | if (pls->seek_timestamp == AV_NOPTS_VALUE) | |
1548 | break; | |
1549 | ||
1550 | if (pls->seek_stream_index < 0 || | |
1551 | pls->seek_stream_index == pls->pkt.stream_index) { | |
1552 | ||
1553 | if (pls->pkt.dts == AV_NOPTS_VALUE) { | |
1554 | pls->seek_timestamp = AV_NOPTS_VALUE; | |
1555 | break; | |
1556 | } | |
1557 | ||
1558 | tb = get_timebase(pls); | |
1559 | ts_diff = av_rescale_rnd(pls->pkt.dts, AV_TIME_BASE, | |
1560 | tb.den, AV_ROUND_DOWN) - | |
1561 | pls->seek_timestamp; | |
1562 | if (ts_diff >= 0 && (pls->seek_flags & AVSEEK_FLAG_ANY || | |
1563 | pls->pkt.flags & AV_PKT_FLAG_KEY)) { | |
1564 | pls->seek_timestamp = AV_NOPTS_VALUE; | |
1565 | break; | |
1566 | } | |
1567 | } | |
1568 | av_free_packet(&pls->pkt); | |
1569 | reset_packet(&pls->pkt); | |
1570 | } | |
1571 | } | |
1572 | /* Check if this stream has the packet with the lowest dts */ | |
1573 | if (pls->pkt.data) { | |
1574 | struct playlist *minpls = minplaylist < 0 ? | |
1575 | NULL : c->playlists[minplaylist]; | |
1576 | if (minplaylist < 0) { | |
1577 | minplaylist = i; | |
1578 | } else { | |
1579 | int64_t dts = pls->pkt.dts; | |
1580 | int64_t mindts = minpls->pkt.dts; | |
1581 | ||
1582 | if (dts == AV_NOPTS_VALUE || | |
1583 | (mindts != AV_NOPTS_VALUE && compare_ts_with_wrapdetect(dts, pls, mindts, minpls) < 0)) | |
1584 | minplaylist = i; | |
1585 | } | |
1586 | } | |
1587 | } | |
1588 | ||
1589 | /* If we got a packet, return it */ | |
1590 | if (minplaylist >= 0) { | |
1591 | struct playlist *pls = c->playlists[minplaylist]; | |
1592 | *pkt = pls->pkt; | |
1593 | pkt->stream_index += pls->stream_offset; | |
1594 | reset_packet(&c->playlists[minplaylist]->pkt); | |
1595 | ||
1596 | if (pkt->dts != AV_NOPTS_VALUE) | |
1597 | c->cur_timestamp = av_rescale_q(pkt->dts, | |
1598 | pls->ctx->streams[pls->pkt.stream_index]->time_base, | |
1599 | AV_TIME_BASE_Q); | |
1600 | ||
1601 | return 0; | |
1602 | } | |
1603 | return AVERROR_EOF; | |
1604 | } | |
1605 | ||
1606 | static int hls_close(AVFormatContext *s) | |
1607 | { | |
1608 | HLSContext *c = s->priv_data; | |
1609 | ||
1610 | free_playlist_list(c); | |
1611 | free_variant_list(c); | |
1612 | free_rendition_list(c); | |
1613 | return 0; | |
1614 | } | |
1615 | ||
1616 | static int hls_read_seek(AVFormatContext *s, int stream_index, | |
1617 | int64_t timestamp, int flags) | |
1618 | { | |
1619 | HLSContext *c = s->priv_data; | |
1620 | struct playlist *seek_pls = NULL; | |
1621 | int i, seq_no; | |
1622 | int64_t first_timestamp, seek_timestamp, duration; | |
1623 | ||
1624 | if ((flags & AVSEEK_FLAG_BYTE) || | |
1625 | !(c->variants[0]->playlists[0]->finished || c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT)) | |
1626 | return AVERROR(ENOSYS); | |
1627 | ||
1628 | first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ? | |
1629 | 0 : c->first_timestamp; | |
1630 | ||
1631 | seek_timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, | |
1632 | s->streams[stream_index]->time_base.den, | |
1633 | flags & AVSEEK_FLAG_BACKWARD ? | |
1634 | AV_ROUND_DOWN : AV_ROUND_UP); | |
1635 | ||
1636 | duration = s->duration == AV_NOPTS_VALUE ? | |
1637 | 0 : s->duration; | |
1638 | ||
1639 | if (0 < duration && duration < seek_timestamp - first_timestamp) | |
1640 | return AVERROR(EIO); | |
1641 | ||
1642 | /* find the playlist with the specified stream */ | |
1643 | for (i = 0; i < c->n_playlists; i++) { | |
1644 | struct playlist *pls = c->playlists[i]; | |
1645 | if (stream_index >= pls->stream_offset && | |
1646 | stream_index - pls->stream_offset < pls->ctx->nb_streams) { | |
1647 | seek_pls = pls; | |
1648 | break; | |
1649 | } | |
1650 | } | |
1651 | /* check if the timestamp is valid for the playlist with the | |
1652 | * specified stream index */ | |
1653 | if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no)) | |
1654 | return AVERROR(EIO); | |
1655 | ||
1656 | /* set segment now so we do not need to search again below */ | |
1657 | seek_pls->cur_seq_no = seq_no; | |
1658 | seek_pls->seek_stream_index = stream_index - seek_pls->stream_offset; | |
1659 | ||
1660 | for (i = 0; i < c->n_playlists; i++) { | |
1661 | /* Reset reading */ | |
1662 | struct playlist *pls = c->playlists[i]; | |
1663 | if (pls->input) { | |
1664 | ffurl_close(pls->input); | |
1665 | pls->input = NULL; | |
1666 | } | |
1667 | av_free_packet(&pls->pkt); | |
1668 | reset_packet(&pls->pkt); | |
1669 | pls->pb.eof_reached = 0; | |
1670 | /* Clear any buffered data */ | |
1671 | pls->pb.buf_end = pls->pb.buf_ptr = pls->pb.buffer; | |
1672 | /* Reset the pos, to let the mpegts demuxer know we've seeked. */ | |
1673 | pls->pb.pos = 0; | |
1674 | /* Flush the packet queue of the subdemuxer. */ | |
1675 | ff_read_frame_flush(pls->ctx); | |
1676 | ||
1677 | pls->seek_timestamp = seek_timestamp; | |
1678 | pls->seek_flags = flags; | |
1679 | ||
1680 | if (pls != seek_pls) { | |
1681 | /* set closest segment seq_no for playlists not handled above */ | |
1682 | find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no); | |
1683 | /* seek the playlist to the given position without taking | |
1684 | * keyframes into account since this playlist does not have the | |
1685 | * specified stream where we should look for the keyframes */ | |
1686 | pls->seek_stream_index = -1; | |
1687 | pls->seek_flags |= AVSEEK_FLAG_ANY; | |
1688 | } | |
1689 | } | |
1690 | ||
1691 | c->cur_timestamp = seek_timestamp; | |
1692 | ||
1693 | return 0; | |
1694 | } | |
1695 | ||
1696 | static int hls_probe(AVProbeData *p) | |
1697 | { | |
1698 | /* Require #EXTM3U at the start, and either one of the ones below | |
1699 | * somewhere for a proper match. */ | |
1700 | if (strncmp(p->buf, "#EXTM3U", 7)) | |
1701 | return 0; | |
1702 | if (strstr(p->buf, "#EXT-X-STREAM-INF:") || | |
1703 | strstr(p->buf, "#EXT-X-TARGETDURATION:") || | |
1704 | strstr(p->buf, "#EXT-X-MEDIA-SEQUENCE:")) | |
1705 | return AVPROBE_SCORE_MAX; | |
1706 | return 0; | |
1707 | } | |
1708 | ||
1709 | AVInputFormat ff_hls_demuxer = { | |
1710 | .name = "hls,applehttp", | |
1711 | .long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"), | |
1712 | .priv_data_size = sizeof(HLSContext), | |
1713 | .read_probe = hls_probe, | |
1714 | .read_header = hls_read_header, | |
1715 | .read_packet = hls_read_packet, | |
1716 | .read_close = hls_close, | |
1717 | .read_seek = hls_read_seek, | |
1718 | }; |