Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Apple HTTP Live Streaming demuxer |
||
3 | * Copyright (c) 2010 Martin Storsjo |
||
4 | * |
||
5 | * This file is part of FFmpeg. |
||
6 | * |
||
7 | * FFmpeg is free software; you can redistribute it and/or |
||
8 | * modify it under the terms of the GNU Lesser General Public |
||
9 | * License as published by the Free Software Foundation; either |
||
10 | * version 2.1 of the License, or (at your option) any later version. |
||
11 | * |
||
12 | * FFmpeg is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
15 | * Lesser General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU Lesser General Public |
||
18 | * License along with FFmpeg; if not, write to the Free Software |
||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
20 | */ |
||
21 | |||
22 | /** |
||
23 | * @file |
||
24 | * Apple HTTP Live Streaming demuxer |
||
25 | * http://tools.ietf.org/html/draft-pantos-http-live-streaming |
||
26 | */ |
||
27 | |||
28 | #include "libavutil/avstring.h" |
||
29 | #include "libavutil/intreadwrite.h" |
||
30 | #include "libavutil/mathematics.h" |
||
31 | #include "libavutil/opt.h" |
||
32 | #include "libavutil/dict.h" |
||
33 | #include "libavutil/time.h" |
||
34 | #include "avformat.h" |
||
35 | #include "internal.h" |
||
36 | #include "avio_internal.h" |
||
37 | #include "url.h" |
||
38 | |||
39 | #define INITIAL_BUFFER_SIZE 32768 |
||
40 | |||
41 | /* |
||
42 | * An apple http stream consists of a playlist with media segment files, |
||
43 | * played sequentially. There may be several playlists with the same |
||
44 | * video content, in different bandwidth variants, that are played in |
||
45 | * parallel (preferably only one bandwidth variant at a time). In this case, |
||
46 | * the user supplied the url to a main playlist that only lists the variant |
||
47 | * playlists. |
||
48 | * |
||
49 | * If the main playlist doesn't point at any variants, we still create |
||
50 | * one anonymous toplevel variant for this, to maintain the structure. |
||
51 | */ |
||
52 | |||
53 | enum KeyType { |
||
54 | KEY_NONE, |
||
55 | KEY_AES_128, |
||
56 | }; |
||
57 | |||
58 | struct segment { |
||
59 | int64_t duration; |
||
60 | char url[MAX_URL_SIZE]; |
||
61 | char key[MAX_URL_SIZE]; |
||
62 | enum KeyType key_type; |
||
63 | uint8_t iv[16]; |
||
64 | }; |
||
65 | |||
66 | /* |
||
67 | * Each variant has its own demuxer. If it currently is active, |
||
68 | * it has an open AVIOContext too, and potentially an AVPacket |
||
69 | * containing the next packet from this stream. |
||
70 | */ |
||
71 | struct variant { |
||
72 | int bandwidth; |
||
73 | char url[MAX_URL_SIZE]; |
||
74 | AVIOContext pb; |
||
75 | uint8_t* read_buffer; |
||
76 | URLContext *input; |
||
77 | AVFormatContext *parent; |
||
78 | int index; |
||
79 | AVFormatContext *ctx; |
||
80 | AVPacket pkt; |
||
81 | int stream_offset; |
||
82 | |||
83 | int finished; |
||
84 | int64_t target_duration; |
||
85 | int start_seq_no; |
||
86 | int n_segments; |
||
87 | struct segment **segments; |
||
88 | int needed, cur_needed; |
||
89 | int cur_seq_no; |
||
90 | int64_t last_load_time; |
||
91 | |||
92 | char key_url[MAX_URL_SIZE]; |
||
93 | uint8_t key[16]; |
||
94 | }; |
||
95 | |||
96 | typedef struct HLSContext { |
||
97 | int n_variants; |
||
98 | struct variant **variants; |
||
99 | int cur_seq_no; |
||
100 | int end_of_segment; |
||
101 | int first_packet; |
||
102 | int64_t first_timestamp; |
||
103 | int64_t seek_timestamp; |
||
104 | int seek_flags; |
||
105 | AVIOInterruptCB *interrupt_callback; |
||
106 | char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context |
||
107 | char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context |
||
108 | } HLSContext; |
||
109 | |||
110 | static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) |
||
111 | { |
||
112 | int len = ff_get_line(s, buf, maxlen); |
||
113 | while (len > 0 && av_isspace(buf[len - 1])) |
||
114 | buf[--len] = '\0'; |
||
115 | return len; |
||
116 | } |
||
117 | |||
118 | static void free_segment_list(struct variant *var) |
||
119 | { |
||
120 | int i; |
||
121 | for (i = 0; i < var->n_segments; i++) |
||
122 | av_free(var->segments[i]); |
||
123 | av_freep(&var->segments); |
||
124 | var->n_segments = 0; |
||
125 | } |
||
126 | |||
127 | static void free_variant_list(HLSContext *c) |
||
128 | { |
||
129 | int i; |
||
130 | for (i = 0; i < c->n_variants; i++) { |
||
131 | struct variant *var = c->variants[i]; |
||
132 | free_segment_list(var); |
||
133 | av_free_packet(&var->pkt); |
||
134 | av_free(var->pb.buffer); |
||
135 | if (var->input) |
||
136 | ffurl_close(var->input); |
||
137 | if (var->ctx) { |
||
138 | var->ctx->pb = NULL; |
||
139 | avformat_close_input(&var->ctx); |
||
140 | } |
||
141 | av_free(var); |
||
142 | } |
||
143 | av_freep(&c->variants); |
||
144 | av_freep(&c->cookies); |
||
145 | av_freep(&c->user_agent); |
||
146 | c->n_variants = 0; |
||
147 | } |
||
148 | |||
149 | /* |
||
150 | * Used to reset a statically allocated AVPacket to a clean slate, |
||
151 | * containing no data. |
||
152 | */ |
||
153 | static void reset_packet(AVPacket *pkt) |
||
154 | { |
||
155 | av_init_packet(pkt); |
||
156 | pkt->data = NULL; |
||
157 | } |
||
158 | |||
159 | static struct variant *new_variant(HLSContext *c, int bandwidth, |
||
160 | const char *url, const char *base) |
||
161 | { |
||
162 | struct variant *var = av_mallocz(sizeof(struct variant)); |
||
163 | if (!var) |
||
164 | return NULL; |
||
165 | reset_packet(&var->pkt); |
||
166 | var->bandwidth = bandwidth; |
||
167 | ff_make_absolute_url(var->url, sizeof(var->url), base, url); |
||
168 | dynarray_add(&c->variants, &c->n_variants, var); |
||
169 | return var; |
||
170 | } |
||
171 | |||
172 | struct variant_info { |
||
173 | char bandwidth[20]; |
||
174 | }; |
||
175 | |||
176 | static void handle_variant_args(struct variant_info *info, const char *key, |
||
177 | int key_len, char **dest, int *dest_len) |
||
178 | { |
||
179 | if (!strncmp(key, "BANDWIDTH=", key_len)) { |
||
180 | *dest = info->bandwidth; |
||
181 | *dest_len = sizeof(info->bandwidth); |
||
182 | } |
||
183 | } |
||
184 | |||
185 | struct key_info { |
||
186 | char uri[MAX_URL_SIZE]; |
||
187 | char method[10]; |
||
188 | char iv[35]; |
||
189 | }; |
||
190 | |||
191 | static void handle_key_args(struct key_info *info, const char *key, |
||
192 | int key_len, char **dest, int *dest_len) |
||
193 | { |
||
194 | if (!strncmp(key, "METHOD=", key_len)) { |
||
195 | *dest = info->method; |
||
196 | *dest_len = sizeof(info->method); |
||
197 | } else if (!strncmp(key, "URI=", key_len)) { |
||
198 | *dest = info->uri; |
||
199 | *dest_len = sizeof(info->uri); |
||
200 | } else if (!strncmp(key, "IV=", key_len)) { |
||
201 | *dest = info->iv; |
||
202 | *dest_len = sizeof(info->iv); |
||
203 | } |
||
204 | } |
||
205 | |||
206 | static int parse_playlist(HLSContext *c, const char *url, |
||
207 | struct variant *var, AVIOContext *in) |
||
208 | { |
||
209 | int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; |
||
210 | int64_t duration = 0; |
||
211 | enum KeyType key_type = KEY_NONE; |
||
212 | uint8_t iv[16] = ""; |
||
213 | int has_iv = 0; |
||
214 | char key[MAX_URL_SIZE] = ""; |
||
215 | char line[MAX_URL_SIZE]; |
||
216 | const char *ptr; |
||
217 | int close_in = 0; |
||
218 | |||
219 | if (!in) { |
||
220 | AVDictionary *opts = NULL; |
||
221 | close_in = 1; |
||
222 | /* Some HLS servers don't like being sent the range header */ |
||
223 | av_dict_set(&opts, "seekable", "0", 0); |
||
224 | |||
225 | // broker prior HTTP options that should be consistent across requests |
||
226 | av_dict_set(&opts, "user-agent", c->user_agent, 0); |
||
227 | av_dict_set(&opts, "cookies", c->cookies, 0); |
||
228 | |||
229 | ret = avio_open2(&in, url, AVIO_FLAG_READ, |
||
230 | c->interrupt_callback, &opts); |
||
231 | av_dict_free(&opts); |
||
232 | if (ret < 0) |
||
233 | return ret; |
||
234 | } |
||
235 | |||
236 | read_chomp_line(in, line, sizeof(line)); |
||
237 | if (strcmp(line, "#EXTM3U")) { |
||
238 | ret = AVERROR_INVALIDDATA; |
||
239 | goto fail; |
||
240 | } |
||
241 | |||
242 | if (var) { |
||
243 | free_segment_list(var); |
||
244 | var->finished = 0; |
||
245 | } |
||
246 | while (!url_feof(in)) { |
||
247 | read_chomp_line(in, line, sizeof(line)); |
||
248 | if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { |
||
249 | struct variant_info info = {{0}}; |
||
250 | is_variant = 1; |
||
251 | ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, |
||
252 | &info); |
||
253 | bandwidth = atoi(info.bandwidth); |
||
254 | } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { |
||
255 | struct key_info info = {{0}}; |
||
256 | ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, |
||
257 | &info); |
||
258 | key_type = KEY_NONE; |
||
259 | has_iv = 0; |
||
260 | if (!strcmp(info.method, "AES-128")) |
||
261 | key_type = KEY_AES_128; |
||
262 | if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) { |
||
263 | ff_hex_to_data(iv, info.iv + 2); |
||
264 | has_iv = 1; |
||
265 | } |
||
266 | av_strlcpy(key, info.uri, sizeof(key)); |
||
267 | } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { |
||
268 | if (!var) { |
||
269 | var = new_variant(c, 0, url, NULL); |
||
270 | if (!var) { |
||
271 | ret = AVERROR(ENOMEM); |
||
272 | goto fail; |
||
273 | } |
||
274 | } |
||
275 | var->target_duration = atoi(ptr) * AV_TIME_BASE; |
||
276 | } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { |
||
277 | if (!var) { |
||
278 | var = new_variant(c, 0, url, NULL); |
||
279 | if (!var) { |
||
280 | ret = AVERROR(ENOMEM); |
||
281 | goto fail; |
||
282 | } |
||
283 | } |
||
284 | var->start_seq_no = atoi(ptr); |
||
285 | } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { |
||
286 | if (var) |
||
287 | var->finished = 1; |
||
288 | } else if (av_strstart(line, "#EXTINF:", &ptr)) { |
||
289 | is_segment = 1; |
||
290 | duration = atof(ptr) * AV_TIME_BASE; |
||
291 | } else if (av_strstart(line, "#", NULL)) { |
||
292 | continue; |
||
293 | } else if (line[0]) { |
||
294 | if (is_variant) { |
||
295 | if (!new_variant(c, bandwidth, line, url)) { |
||
296 | ret = AVERROR(ENOMEM); |
||
297 | goto fail; |
||
298 | } |
||
299 | is_variant = 0; |
||
300 | bandwidth = 0; |
||
301 | } |
||
302 | if (is_segment) { |
||
303 | struct segment *seg; |
||
304 | if (!var) { |
||
305 | var = new_variant(c, 0, url, NULL); |
||
306 | if (!var) { |
||
307 | ret = AVERROR(ENOMEM); |
||
308 | goto fail; |
||
309 | } |
||
310 | } |
||
311 | seg = av_malloc(sizeof(struct segment)); |
||
312 | if (!seg) { |
||
313 | ret = AVERROR(ENOMEM); |
||
314 | goto fail; |
||
315 | } |
||
316 | seg->duration = duration; |
||
317 | seg->key_type = key_type; |
||
318 | if (has_iv) { |
||
319 | memcpy(seg->iv, iv, sizeof(iv)); |
||
320 | } else { |
||
321 | int seq = var->start_seq_no + var->n_segments; |
||
322 | memset(seg->iv, 0, sizeof(seg->iv)); |
||
323 | AV_WB32(seg->iv + 12, seq); |
||
324 | } |
||
325 | ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); |
||
326 | ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); |
||
327 | dynarray_add(&var->segments, &var->n_segments, seg); |
||
328 | is_segment = 0; |
||
329 | } |
||
330 | } |
||
331 | } |
||
332 | if (var) |
||
333 | var->last_load_time = av_gettime(); |
||
334 | |||
335 | fail: |
||
336 | if (close_in) |
||
337 | avio_close(in); |
||
338 | return ret; |
||
339 | } |
||
340 | |||
341 | static int open_input(HLSContext *c, struct variant *var) |
||
342 | { |
||
343 | AVDictionary *opts = NULL; |
||
344 | int ret; |
||
345 | struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no]; |
||
346 | |||
347 | // broker prior HTTP options that should be consistent across requests |
||
348 | av_dict_set(&opts, "user-agent", c->user_agent, 0); |
||
349 | av_dict_set(&opts, "cookies", c->cookies, 0); |
||
350 | av_dict_set(&opts, "seekable", "0", 0); |
||
351 | |||
352 | if (seg->key_type == KEY_NONE) { |
||
353 | ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ, |
||
354 | &var->parent->interrupt_callback, &opts); |
||
355 | goto cleanup; |
||
356 | } else if (seg->key_type == KEY_AES_128) { |
||
357 | char iv[33], key[33], url[MAX_URL_SIZE]; |
||
358 | if (strcmp(seg->key, var->key_url)) { |
||
359 | URLContext *uc; |
||
360 | if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ, |
||
361 | &var->parent->interrupt_callback, &opts) == 0) { |
||
362 | if (ffurl_read_complete(uc, var->key, sizeof(var->key)) |
||
363 | != sizeof(var->key)) { |
||
364 | av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", |
||
365 | seg->key); |
||
366 | } |
||
367 | ffurl_close(uc); |
||
368 | } else { |
||
369 | av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", |
||
370 | seg->key); |
||
371 | } |
||
372 | av_strlcpy(var->key_url, seg->key, sizeof(var->key_url)); |
||
373 | } |
||
374 | ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0); |
||
375 | ff_data_to_hex(key, var->key, sizeof(var->key), 0); |
||
376 | iv[32] = key[32] = '\0'; |
||
377 | if (strstr(seg->url, "://")) |
||
378 | snprintf(url, sizeof(url), "crypto+%s", seg->url); |
||
379 | else |
||
380 | snprintf(url, sizeof(url), "crypto:%s", seg->url); |
||
381 | if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ, |
||
382 | &var->parent->interrupt_callback)) < 0) |
||
383 | goto cleanup; |
||
384 | av_opt_set(var->input->priv_data, "key", key, 0); |
||
385 | av_opt_set(var->input->priv_data, "iv", iv, 0); |
||
386 | /* Need to repopulate options */ |
||
387 | av_dict_free(&opts); |
||
388 | av_dict_set(&opts, "seekable", "0", 0); |
||
389 | if ((ret = ffurl_connect(var->input, &opts)) < 0) { |
||
390 | ffurl_close(var->input); |
||
391 | var->input = NULL; |
||
392 | goto cleanup; |
||
393 | } |
||
394 | ret = 0; |
||
395 | } |
||
396 | else |
||
397 | ret = AVERROR(ENOSYS); |
||
398 | |||
399 | cleanup: |
||
400 | av_dict_free(&opts); |
||
401 | return ret; |
||
402 | } |
||
403 | |||
404 | static int read_data(void *opaque, uint8_t *buf, int buf_size) |
||
405 | { |
||
406 | struct variant *v = opaque; |
||
407 | HLSContext *c = v->parent->priv_data; |
||
408 | int ret, i; |
||
409 | |||
410 | restart: |
||
411 | if (!v->input) { |
||
412 | /* If this is a live stream and the reload interval has elapsed since |
||
413 | * the last playlist reload, reload the variant playlists now. */ |
||
414 | int64_t reload_interval = v->n_segments > 0 ? |
||
415 | v->segments[v->n_segments - 1]->duration : |
||
416 | v->target_duration; |
||
417 | |||
418 | reload: |
||
419 | if (!v->finished && |
||
420 | av_gettime() - v->last_load_time >= reload_interval) { |
||
421 | if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) |
||
422 | return ret; |
||
423 | /* If we need to reload the playlist again below (if |
||
424 | * there's still no more segments), switch to a reload |
||
425 | * interval of half the target duration. */ |
||
426 | reload_interval = v->target_duration / 2; |
||
427 | } |
||
428 | if (v->cur_seq_no < v->start_seq_no) { |
||
429 | av_log(NULL, AV_LOG_WARNING, |
||
430 | "skipping %d segments ahead, expired from playlists\n", |
||
431 | v->start_seq_no - v->cur_seq_no); |
||
432 | v->cur_seq_no = v->start_seq_no; |
||
433 | } |
||
434 | if (v->cur_seq_no >= v->start_seq_no + v->n_segments) { |
||
435 | if (v->finished) |
||
436 | return AVERROR_EOF; |
||
437 | while (av_gettime() - v->last_load_time < reload_interval) { |
||
438 | if (ff_check_interrupt(c->interrupt_callback)) |
||
439 | return AVERROR_EXIT; |
||
440 | av_usleep(100*1000); |
||
441 | } |
||
442 | /* Enough time has elapsed since the last reload */ |
||
443 | goto reload; |
||
444 | } |
||
445 | |||
446 | ret = open_input(c, v); |
||
447 | if (ret < 0) |
||
448 | return ret; |
||
449 | } |
||
450 | ret = ffurl_read(v->input, buf, buf_size); |
||
451 | if (ret > 0) |
||
452 | return ret; |
||
453 | ffurl_close(v->input); |
||
454 | v->input = NULL; |
||
455 | v->cur_seq_no++; |
||
456 | |||
457 | c->end_of_segment = 1; |
||
458 | c->cur_seq_no = v->cur_seq_no; |
||
459 | |||
460 | if (v->ctx && v->ctx->nb_streams && |
||
461 | v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) { |
||
462 | v->needed = 0; |
||
463 | for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; |
||
464 | i++) { |
||
465 | if (v->parent->streams[i]->discard < AVDISCARD_ALL) |
||
466 | v->needed = 1; |
||
467 | } |
||
468 | } |
||
469 | if (!v->needed) { |
||
470 | av_log(v->parent, AV_LOG_INFO, "No longer receiving variant %d\n", |
||
471 | v->index); |
||
472 | return AVERROR_EOF; |
||
473 | } |
||
474 | goto restart; |
||
475 | } |
||
476 | |||
477 | static int hls_read_header(AVFormatContext *s) |
||
478 | { |
||
479 | URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque; |
||
480 | HLSContext *c = s->priv_data; |
||
481 | int ret = 0, i, j, stream_offset = 0; |
||
482 | |||
483 | c->interrupt_callback = &s->interrupt_callback; |
||
484 | |||
485 | // if the URL context is good, read important options we must broker later |
||
486 | if (u && u->prot->priv_data_class) { |
||
487 | // get the previous user agent & set back to null if string size is zero |
||
488 | av_freep(&c->user_agent); |
||
489 | av_opt_get(u->priv_data, "user-agent", 0, (uint8_t**)&(c->user_agent)); |
||
490 | if (c->user_agent && !strlen(c->user_agent)) |
||
491 | av_freep(&c->user_agent); |
||
492 | |||
493 | // get the previous cookies & set back to null if string size is zero |
||
494 | av_freep(&c->cookies); |
||
495 | av_opt_get(u->priv_data, "cookies", 0, (uint8_t**)&(c->cookies)); |
||
496 | if (c->cookies && !strlen(c->cookies)) |
||
497 | av_freep(&c->cookies); |
||
498 | } |
||
499 | |||
500 | if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) |
||
501 | goto fail; |
||
502 | |||
503 | if (c->n_variants == 0) { |
||
504 | av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); |
||
505 | ret = AVERROR_EOF; |
||
506 | goto fail; |
||
507 | } |
||
508 | /* If the playlist only contained variants, parse each individual |
||
509 | * variant playlist. */ |
||
510 | if (c->n_variants > 1 || c->variants[0]->n_segments == 0) { |
||
511 | for (i = 0; i < c->n_variants; i++) { |
||
512 | struct variant *v = c->variants[i]; |
||
513 | if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) |
||
514 | goto fail; |
||
515 | } |
||
516 | } |
||
517 | |||
518 | if (c->variants[0]->n_segments == 0) { |
||
519 | av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); |
||
520 | ret = AVERROR_EOF; |
||
521 | goto fail; |
||
522 | } |
||
523 | |||
524 | /* If this isn't a live stream, calculate the total duration of the |
||
525 | * stream. */ |
||
526 | if (c->variants[0]->finished) { |
||
527 | int64_t duration = 0; |
||
528 | for (i = 0; i < c->variants[0]->n_segments; i++) |
||
529 | duration += c->variants[0]->segments[i]->duration; |
||
530 | s->duration = duration; |
||
531 | } |
||
532 | |||
533 | /* Open the demuxer for each variant */ |
||
534 | for (i = 0; i < c->n_variants; i++) { |
||
535 | struct variant *v = c->variants[i]; |
||
536 | AVInputFormat *in_fmt = NULL; |
||
537 | char bitrate_str[20]; |
||
538 | AVProgram *program; |
||
539 | |||
540 | if (v->n_segments == 0) |
||
541 | continue; |
||
542 | |||
543 | if (!(v->ctx = avformat_alloc_context())) { |
||
544 | ret = AVERROR(ENOMEM); |
||
545 | goto fail; |
||
546 | } |
||
547 | |||
548 | v->index = i; |
||
549 | v->needed = 1; |
||
550 | v->parent = s; |
||
551 | |||
552 | /* If this is a live stream with more than 3 segments, start at the |
||
553 | * third last segment. */ |
||
554 | v->cur_seq_no = v->start_seq_no; |
||
555 | if (!v->finished && v->n_segments > 3) |
||
556 | v->cur_seq_no = v->start_seq_no + v->n_segments - 3; |
||
557 | |||
558 | v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); |
||
559 | ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v, |
||
560 | read_data, NULL, NULL); |
||
561 | v->pb.seekable = 0; |
||
562 | ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url, |
||
563 | NULL, 0, 0); |
||
564 | if (ret < 0) { |
||
565 | /* Free the ctx - it isn't initialized properly at this point, |
||
566 | * so avformat_close_input shouldn't be called. If |
||
567 | * avformat_open_input fails below, it frees and zeros the |
||
568 | * context, so it doesn't need any special treatment like this. */ |
||
569 | av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", v->segments[0]->url); |
||
570 | avformat_free_context(v->ctx); |
||
571 | v->ctx = NULL; |
||
572 | goto fail; |
||
573 | } |
||
574 | v->ctx->pb = &v->pb; |
||
575 | v->stream_offset = stream_offset; |
||
576 | ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL); |
||
577 | if (ret < 0) |
||
578 | goto fail; |
||
579 | |||
580 | v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; |
||
581 | ret = avformat_find_stream_info(v->ctx, NULL); |
||
582 | if (ret < 0) |
||
583 | goto fail; |
||
584 | snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); |
||
585 | |||
586 | program = av_new_program(s, i); |
||
587 | if (!program) |
||
588 | goto fail; |
||
589 | av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0); |
||
590 | |||
591 | /* Create new AVStreams for each stream in this variant */ |
||
592 | for (j = 0; j < v->ctx->nb_streams; j++) { |
||
593 | AVStream *st = avformat_new_stream(s, NULL); |
||
594 | AVStream *ist = v->ctx->streams[j]; |
||
595 | if (!st) { |
||
596 | ret = AVERROR(ENOMEM); |
||
597 | goto fail; |
||
598 | } |
||
599 | ff_program_add_stream_index(s, i, stream_offset + j); |
||
600 | st->id = i; |
||
601 | avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); |
||
602 | avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); |
||
603 | if (v->bandwidth) |
||
604 | av_dict_set(&st->metadata, "variant_bitrate", bitrate_str, |
||
605 | 0); |
||
606 | } |
||
607 | stream_offset += v->ctx->nb_streams; |
||
608 | } |
||
609 | |||
610 | c->first_packet = 1; |
||
611 | c->first_timestamp = AV_NOPTS_VALUE; |
||
612 | c->seek_timestamp = AV_NOPTS_VALUE; |
||
613 | |||
614 | return 0; |
||
615 | fail: |
||
616 | free_variant_list(c); |
||
617 | return ret; |
||
618 | } |
||
619 | |||
620 | static int recheck_discard_flags(AVFormatContext *s, int first) |
||
621 | { |
||
622 | HLSContext *c = s->priv_data; |
||
623 | int i, changed = 0; |
||
624 | |||
625 | /* Check if any new streams are needed */ |
||
626 | for (i = 0; i < c->n_variants; i++) |
||
627 | c->variants[i]->cur_needed = 0; |
||
628 | |||
629 | for (i = 0; i < s->nb_streams; i++) { |
||
630 | AVStream *st = s->streams[i]; |
||
631 | struct variant *var = c->variants[s->streams[i]->id]; |
||
632 | if (st->discard < AVDISCARD_ALL) |
||
633 | var->cur_needed = 1; |
||
634 | } |
||
635 | for (i = 0; i < c->n_variants; i++) { |
||
636 | struct variant *v = c->variants[i]; |
||
637 | if (v->cur_needed && !v->needed) { |
||
638 | v->needed = 1; |
||
639 | changed = 1; |
||
640 | v->cur_seq_no = c->cur_seq_no; |
||
641 | v->pb.eof_reached = 0; |
||
642 | av_log(s, AV_LOG_INFO, "Now receiving variant %d\n", i); |
||
643 | } else if (first && !v->cur_needed && v->needed) { |
||
644 | if (v->input) |
||
645 | ffurl_close(v->input); |
||
646 | v->input = NULL; |
||
647 | v->needed = 0; |
||
648 | changed = 1; |
||
649 | av_log(s, AV_LOG_INFO, "No longer receiving variant %d\n", i); |
||
650 | } |
||
651 | } |
||
652 | return changed; |
||
653 | } |
||
654 | |||
655 | static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) |
||
656 | { |
||
657 | HLSContext *c = s->priv_data; |
||
658 | int ret, i, minvariant = -1; |
||
659 | |||
660 | if (c->first_packet) { |
||
661 | recheck_discard_flags(s, 1); |
||
662 | c->first_packet = 0; |
||
663 | } |
||
664 | |||
665 | start: |
||
666 | c->end_of_segment = 0; |
||
667 | for (i = 0; i < c->n_variants; i++) { |
||
668 | struct variant *var = c->variants[i]; |
||
669 | /* Make sure we've got one buffered packet from each open variant |
||
670 | * stream */ |
||
671 | if (var->needed && !var->pkt.data) { |
||
672 | while (1) { |
||
673 | int64_t ts_diff; |
||
674 | AVStream *st; |
||
675 | ret = av_read_frame(var->ctx, &var->pkt); |
||
676 | if (ret < 0) { |
||
677 | if (!url_feof(&var->pb) && ret != AVERROR_EOF) |
||
678 | return ret; |
||
679 | reset_packet(&var->pkt); |
||
680 | break; |
||
681 | } else { |
||
682 | if (c->first_timestamp == AV_NOPTS_VALUE && |
||
683 | var->pkt.dts != AV_NOPTS_VALUE) |
||
684 | c->first_timestamp = av_rescale_q(var->pkt.dts, |
||
685 | var->ctx->streams[var->pkt.stream_index]->time_base, |
||
686 | AV_TIME_BASE_Q); |
||
687 | } |
||
688 | |||
689 | if (c->seek_timestamp == AV_NOPTS_VALUE) |
||
690 | break; |
||
691 | |||
692 | if (var->pkt.dts == AV_NOPTS_VALUE) { |
||
693 | c->seek_timestamp = AV_NOPTS_VALUE; |
||
694 | break; |
||
695 | } |
||
696 | |||
697 | st = var->ctx->streams[var->pkt.stream_index]; |
||
698 | ts_diff = av_rescale_rnd(var->pkt.dts, AV_TIME_BASE, |
||
699 | st->time_base.den, AV_ROUND_DOWN) - |
||
700 | c->seek_timestamp; |
||
701 | if (ts_diff >= 0 && (c->seek_flags & AVSEEK_FLAG_ANY || |
||
702 | var->pkt.flags & AV_PKT_FLAG_KEY)) { |
||
703 | c->seek_timestamp = AV_NOPTS_VALUE; |
||
704 | break; |
||
705 | } |
||
706 | av_free_packet(&var->pkt); |
||
707 | reset_packet(&var->pkt); |
||
708 | } |
||
709 | } |
||
710 | /* Check if this stream still is on an earlier segment number, or |
||
711 | * has the packet with the lowest dts */ |
||
712 | if (var->pkt.data) { |
||
713 | struct variant *minvar = c->variants[minvariant]; |
||
714 | if (minvariant < 0 || var->cur_seq_no < minvar->cur_seq_no) { |
||
715 | minvariant = i; |
||
716 | } else if (var->cur_seq_no == minvar->cur_seq_no) { |
||
717 | int64_t dts = var->pkt.dts; |
||
718 | int64_t mindts = minvar->pkt.dts; |
||
719 | AVStream *st = var->ctx->streams[var->pkt.stream_index]; |
||
720 | AVStream *minst = minvar->ctx->streams[minvar->pkt.stream_index]; |
||
721 | |||
722 | if (dts == AV_NOPTS_VALUE) { |
||
723 | minvariant = i; |
||
724 | } else if (mindts != AV_NOPTS_VALUE) { |
||
725 | if (st->start_time != AV_NOPTS_VALUE) |
||
726 | dts -= st->start_time; |
||
727 | if (minst->start_time != AV_NOPTS_VALUE) |
||
728 | mindts -= minst->start_time; |
||
729 | |||
730 | if (av_compare_ts(dts, st->time_base, |
||
731 | mindts, minst->time_base) < 0) |
||
732 | minvariant = i; |
||
733 | } |
||
734 | } |
||
735 | } |
||
736 | } |
||
737 | if (c->end_of_segment) { |
||
738 | if (recheck_discard_flags(s, 0)) |
||
739 | goto start; |
||
740 | } |
||
741 | /* If we got a packet, return it */ |
||
742 | if (minvariant >= 0) { |
||
743 | *pkt = c->variants[minvariant]->pkt; |
||
744 | pkt->stream_index += c->variants[minvariant]->stream_offset; |
||
745 | reset_packet(&c->variants[minvariant]->pkt); |
||
746 | return 0; |
||
747 | } |
||
748 | return AVERROR_EOF; |
||
749 | } |
||
750 | |||
751 | static int hls_close(AVFormatContext *s) |
||
752 | { |
||
753 | HLSContext *c = s->priv_data; |
||
754 | |||
755 | free_variant_list(c); |
||
756 | return 0; |
||
757 | } |
||
758 | |||
759 | static int hls_read_seek(AVFormatContext *s, int stream_index, |
||
760 | int64_t timestamp, int flags) |
||
761 | { |
||
762 | HLSContext *c = s->priv_data; |
||
763 | int i, j, ret; |
||
764 | |||
765 | if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished) |
||
766 | return AVERROR(ENOSYS); |
||
767 | |||
768 | c->seek_flags = flags; |
||
769 | c->seek_timestamp = stream_index < 0 ? timestamp : |
||
770 | av_rescale_rnd(timestamp, AV_TIME_BASE, |
||
771 | s->streams[stream_index]->time_base.den, |
||
772 | flags & AVSEEK_FLAG_BACKWARD ? |
||
773 | AV_ROUND_DOWN : AV_ROUND_UP); |
||
774 | timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, stream_index >= 0 ? |
||
775 | s->streams[stream_index]->time_base.den : |
||
776 | AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ? |
||
777 | AV_ROUND_DOWN : AV_ROUND_UP); |
||
778 | if (s->duration < c->seek_timestamp) { |
||
779 | c->seek_timestamp = AV_NOPTS_VALUE; |
||
780 | return AVERROR(EIO); |
||
781 | } |
||
782 | |||
783 | ret = AVERROR(EIO); |
||
784 | for (i = 0; i < c->n_variants; i++) { |
||
785 | /* Reset reading */ |
||
786 | struct variant *var = c->variants[i]; |
||
787 | int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? |
||
788 | |||
789 | if (var->input) { |
||
790 | ffurl_close(var->input); |
||
791 | var->input = NULL; |
||
792 | } |
||
793 | av_free_packet(&var->pkt); |
||
794 | reset_packet(&var->pkt); |
||
795 | var->pb.eof_reached = 0; |
||
796 | /* Clear any buffered data */ |
||
797 | var->pb.buf_end = var->pb.buf_ptr = var->pb.buffer; |
||
798 | /* Reset the pos, to let the mpegts demuxer know we've seeked. */ |
||
799 | var->pb.pos = 0; |
||
800 | |||
801 | /* Locate the segment that contains the target timestamp */ |
||
802 | for (j = 0; j < var->n_segments; j++) { |
||
803 | if (timestamp >= pos && |
||
804 | timestamp < pos + var->segments[j]->duration) { |
||
805 | var->cur_seq_no = var->start_seq_no + j; |
||
806 | ret = 0; |
||
807 | break; |
||
808 | } |
||
809 | pos += var->segments[j]->duration; |
||
810 | } |
||
811 | if (ret) |
||
812 | c->seek_timestamp = AV_NOPTS_VALUE; |
||
813 | } |
||
814 | return ret; |
||
815 | } |
||
816 | |||
817 | static int hls_probe(AVProbeData *p) |
||
818 | { |
||
819 | /* Require #EXTM3U at the start, and either one of the ones below |
||
820 | * somewhere for a proper match. */ |
||
821 | if (strncmp(p->buf, "#EXTM3U", 7)) |
||
822 | return 0; |
||
823 | if (strstr(p->buf, "#EXT-X-STREAM-INF:") || |
||
824 | strstr(p->buf, "#EXT-X-TARGETDURATION:") || |
||
825 | strstr(p->buf, "#EXT-X-MEDIA-SEQUENCE:")) |
||
826 | return AVPROBE_SCORE_MAX; |
||
827 | return 0; |
||
828 | } |
||
829 | |||
830 | AVInputFormat ff_hls_demuxer = { |
||
831 | .name = "hls,applehttp", |
||
832 | .long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"), |
||
833 | .priv_data_size = sizeof(HLSContext), |
||
834 | .read_probe = hls_probe, |
||
835 | .read_header = hls_read_header, |
||
836 | .read_packet = hls_read_packet, |
||
837 | .read_close = hls_close, |
||
838 | .read_seek = hls_read_seek, |
||
839 | };>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |