]> git.sesse.net Git - ffmpeg/blob - libavformat/applehttp.c
applehttp: Only check the discard flags if v->ctx actually is initialized
[ffmpeg] / libavformat / applehttp.c
1 /*
2  * Apple HTTP Live Streaming demuxer
3  * Copyright (c) 2010 Martin Storsjo
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; 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 #define _XOPEN_SOURCE 600
29 #include "libavutil/avstring.h"
30 #include "avformat.h"
31 #include "internal.h"
32 #include <unistd.h>
33 #include "avio_internal.h"
34 #include "url.h"
35
36 #define INITIAL_BUFFER_SIZE 32768
37
38 /*
39  * An apple http stream consists of a playlist with media segment files,
40  * played sequentially. There may be several playlists with the same
41  * video content, in different bandwidth variants, that are played in
42  * parallel (preferrably only one bandwidth variant at a time). In this case,
43  * the user supplied the url to a main playlist that only lists the variant
44  * playlists.
45  *
46  * If the main playlist doesn't point at any variants, we still create
47  * one anonymous toplevel variant for this, to maintain the structure.
48  */
49
50 struct segment {
51     int duration;
52     char url[MAX_URL_SIZE];
53 };
54
55 /*
56  * Each variant has its own demuxer. If it currently is active,
57  * it has an open AVIOContext too, and potentially an AVPacket
58  * containing the next packet from this stream.
59  */
60 struct variant {
61     int bandwidth;
62     char url[MAX_URL_SIZE];
63     AVIOContext pb;
64     uint8_t* read_buffer;
65     URLContext *input;
66     AVFormatContext *parent;
67     int index;
68     AVFormatContext *ctx;
69     AVPacket pkt;
70     int stream_offset;
71
72     int finished;
73     int target_duration;
74     int start_seq_no;
75     int n_segments;
76     struct segment **segments;
77     int needed, cur_needed;
78     int cur_seq_no;
79     int64_t last_load_time;
80 };
81
82 typedef struct AppleHTTPContext {
83     int n_variants;
84     struct variant **variants;
85     int cur_seq_no;
86     int end_of_segment;
87     int first_packet;
88 } AppleHTTPContext;
89
90 static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
91 {
92     int len = ff_get_line(s, buf, maxlen);
93     while (len > 0 && isspace(buf[len - 1]))
94         buf[--len] = '\0';
95     return len;
96 }
97
98 static void free_segment_list(struct variant *var)
99 {
100     int i;
101     for (i = 0; i < var->n_segments; i++)
102         av_free(var->segments[i]);
103     av_freep(&var->segments);
104     var->n_segments = 0;
105 }
106
107 static void free_variant_list(AppleHTTPContext *c)
108 {
109     int i;
110     for (i = 0; i < c->n_variants; i++) {
111         struct variant *var = c->variants[i];
112         free_segment_list(var);
113         av_free_packet(&var->pkt);
114         av_free(var->pb.buffer);
115         if (var->input)
116             ffurl_close(var->input);
117         if (var->ctx) {
118             var->ctx->pb = NULL;
119             av_close_input_file(var->ctx);
120         }
121         av_free(var);
122     }
123     av_freep(&c->variants);
124     c->n_variants = 0;
125 }
126
127 /*
128  * Used to reset a statically allocated AVPacket to a clean slate,
129  * containing no data.
130  */
131 static void reset_packet(AVPacket *pkt)
132 {
133     av_init_packet(pkt);
134     pkt->data = NULL;
135 }
136
137 static struct variant *new_variant(AppleHTTPContext *c, int bandwidth,
138                                    const char *url, const char *base)
139 {
140     struct variant *var = av_mallocz(sizeof(struct variant));
141     if (!var)
142         return NULL;
143     reset_packet(&var->pkt);
144     var->bandwidth = bandwidth;
145     ff_make_absolute_url(var->url, sizeof(var->url), base, url);
146     dynarray_add(&c->variants, &c->n_variants, var);
147     return var;
148 }
149
150 struct variant_info {
151     char bandwidth[20];
152 };
153
154 static void handle_variant_args(struct variant_info *info, const char *key,
155                                 int key_len, char **dest, int *dest_len)
156 {
157     if (!strncmp(key, "BANDWIDTH=", key_len)) {
158         *dest     =        info->bandwidth;
159         *dest_len = sizeof(info->bandwidth);
160     }
161 }
162
163 static int parse_playlist(AppleHTTPContext *c, const char *url,
164                           struct variant *var, AVIOContext *in)
165 {
166     int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
167     char line[1024];
168     const char *ptr;
169     int close_in = 0;
170
171     if (!in) {
172         close_in = 1;
173         if ((ret = avio_open(&in, url, AVIO_RDONLY)) < 0)
174             return ret;
175     }
176
177     read_chomp_line(in, line, sizeof(line));
178     if (strcmp(line, "#EXTM3U")) {
179         ret = AVERROR_INVALIDDATA;
180         goto fail;
181     }
182
183     if (var) {
184         free_segment_list(var);
185         var->finished = 0;
186     }
187     while (!in->eof_reached) {
188         read_chomp_line(in, line, sizeof(line));
189         if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
190             struct variant_info info = {{0}};
191             is_variant = 1;
192             ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args,
193                                &info);
194             bandwidth = atoi(info.bandwidth);
195         } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {
196             if (!var) {
197                 var = new_variant(c, 0, url, NULL);
198                 if (!var) {
199                     ret = AVERROR(ENOMEM);
200                     goto fail;
201                 }
202             }
203             var->target_duration = atoi(ptr);
204         } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
205             if (!var) {
206                 var = new_variant(c, 0, url, NULL);
207                 if (!var) {
208                     ret = AVERROR(ENOMEM);
209                     goto fail;
210                 }
211             }
212             var->start_seq_no = atoi(ptr);
213         } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) {
214             if (var)
215                 var->finished = 1;
216         } else if (av_strstart(line, "#EXTINF:", &ptr)) {
217             is_segment = 1;
218             duration   = atoi(ptr);
219         } else if (av_strstart(line, "#", NULL)) {
220             continue;
221         } else if (line[0]) {
222             if (is_variant) {
223                 if (!new_variant(c, bandwidth, line, url)) {
224                     ret = AVERROR(ENOMEM);
225                     goto fail;
226                 }
227                 is_variant = 0;
228                 bandwidth  = 0;
229             }
230             if (is_segment) {
231                 struct segment *seg;
232                 if (!var) {
233                     var = new_variant(c, 0, url, NULL);
234                     if (!var) {
235                         ret = AVERROR(ENOMEM);
236                         goto fail;
237                     }
238                 }
239                 seg = av_malloc(sizeof(struct segment));
240                 if (!seg) {
241                     ret = AVERROR(ENOMEM);
242                     goto fail;
243                 }
244                 seg->duration = duration;
245                 ff_make_absolute_url(seg->url, sizeof(seg->url), url, line);
246                 dynarray_add(&var->segments, &var->n_segments, seg);
247                 is_segment = 0;
248             }
249         }
250     }
251     if (var)
252         var->last_load_time = av_gettime();
253
254 fail:
255     if (close_in)
256         avio_close(in);
257     return ret;
258 }
259
260 static int read_data(void *opaque, uint8_t *buf, int buf_size)
261 {
262     struct variant *v = opaque;
263     AppleHTTPContext *c = v->parent->priv_data;
264     int ret, i;
265
266 restart:
267     if (!v->input) {
268 reload:
269         /* If this is a live stream and target_duration has elapsed since
270          * the last playlist reload, reload the variant playlists now. */
271         if (!v->finished &&
272             av_gettime() - v->last_load_time >= v->target_duration*1000000 &&
273             (ret = parse_playlist(c, v->url, v, NULL)) < 0)
274                 return ret;
275         if (v->cur_seq_no < v->start_seq_no) {
276             av_log(NULL, AV_LOG_WARNING,
277                    "skipping %d segments ahead, expired from playlists\n",
278                    v->start_seq_no - v->cur_seq_no);
279             v->cur_seq_no = v->start_seq_no;
280         }
281         if (v->cur_seq_no >= v->start_seq_no + v->n_segments) {
282             if (v->finished)
283                 return AVERROR_EOF;
284             while (av_gettime() - v->last_load_time <
285                    v->target_duration*1000000) {
286                 if (url_interrupt_cb())
287                     return AVERROR_EXIT;
288                 usleep(100*1000);
289             }
290             /* Enough time has elapsed since the last reload */
291             goto reload;
292         }
293
294         ret = ffurl_open(&v->input,
295                          v->segments[v->cur_seq_no - v->start_seq_no]->url,
296                          AVIO_RDONLY);
297         if (ret < 0)
298             return ret;
299     }
300     ret = ffurl_read(v->input, buf, buf_size);
301     if (ret > 0)
302         return ret;
303     if (ret < 0 && ret != AVERROR_EOF)
304         return ret;
305     ffurl_close(v->input);
306     v->input = NULL;
307     v->cur_seq_no++;
308
309     c->end_of_segment = 1;
310     c->cur_seq_no = v->cur_seq_no;
311
312     if (v->ctx) {
313         v->needed = 0;
314         for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams;
315              i++) {
316             if (v->parent->streams[i]->discard < AVDISCARD_ALL)
317                 v->needed = 1;
318         }
319     }
320     if (!v->needed) {
321         av_log(v->parent, AV_LOG_INFO, "No longer receiving variant %d\n",
322                v->index);
323         return AVERROR_EOF;
324     }
325     goto restart;
326 }
327
328 static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap)
329 {
330     AppleHTTPContext *c = s->priv_data;
331     int ret = 0, i, j, stream_offset = 0;
332
333     if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)
334         goto fail;
335
336     if (c->n_variants == 0) {
337         av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");
338         ret = AVERROR_EOF;
339         goto fail;
340     }
341     /* If the playlist only contained variants, parse each individual
342      * variant playlist. */
343     if (c->n_variants > 1 || c->variants[0]->n_segments == 0) {
344         for (i = 0; i < c->n_variants; i++) {
345             struct variant *v = c->variants[i];
346             if ((ret = parse_playlist(c, v->url, v, NULL)) < 0)
347                 goto fail;
348         }
349     }
350
351     if (c->variants[0]->n_segments == 0) {
352         av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");
353         ret = AVERROR_EOF;
354         goto fail;
355     }
356
357     /* If this isn't a live stream, calculate the total duration of the
358      * stream. */
359     if (c->variants[0]->finished) {
360         int64_t duration = 0;
361         for (i = 0; i < c->variants[0]->n_segments; i++)
362             duration += c->variants[0]->segments[i]->duration;
363         s->duration = duration * AV_TIME_BASE;
364     }
365
366     /* Open the demuxer for each variant */
367     for (i = 0; i < c->n_variants; i++) {
368         struct variant *v = c->variants[i];
369         AVInputFormat *in_fmt = NULL;
370         if (v->n_segments == 0)
371             continue;
372
373         v->index  = i;
374         v->needed = 1;
375         v->parent = s;
376
377         /* If this is a live stream with more than 3 segments, start at the
378          * third last segment. */
379         v->cur_seq_no = v->start_seq_no;
380         if (!v->finished && v->n_segments > 3)
381             v->cur_seq_no = v->start_seq_no + v->n_segments - 3;
382
383         v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);
384         ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v,
385                           read_data, NULL, NULL);
386         v->pb.seekable = 0;
387         ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url,
388                                     NULL, 0, 0);
389         if (ret < 0)
390             goto fail;
391         ret = av_open_input_stream(&v->ctx, &v->pb, v->segments[0]->url,
392                                    in_fmt, NULL);
393         if (ret < 0)
394             goto fail;
395         v->stream_offset = stream_offset;
396         /* Create new AVStreams for each stream in this variant */
397         for (j = 0; j < v->ctx->nb_streams; j++) {
398             AVStream *st = av_new_stream(s, i);
399             if (!st) {
400                 ret = AVERROR(ENOMEM);
401                 goto fail;
402             }
403             avcodec_copy_context(st->codec, v->ctx->streams[j]->codec);
404         }
405         stream_offset += v->ctx->nb_streams;
406     }
407
408     c->first_packet = 1;
409
410     return 0;
411 fail:
412     free_variant_list(c);
413     return ret;
414 }
415
416 static int recheck_discard_flags(AVFormatContext *s, int first)
417 {
418     AppleHTTPContext *c = s->priv_data;
419     int i, changed = 0;
420
421     /* Check if any new streams are needed */
422     for (i = 0; i < c->n_variants; i++)
423         c->variants[i]->cur_needed = 0;;
424
425     for (i = 0; i < s->nb_streams; i++) {
426         AVStream *st = s->streams[i];
427         struct variant *var = c->variants[s->streams[i]->id];
428         if (st->discard < AVDISCARD_ALL)
429             var->cur_needed = 1;
430     }
431     for (i = 0; i < c->n_variants; i++) {
432         struct variant *v = c->variants[i];
433         if (v->cur_needed && !v->needed) {
434             v->needed = 1;
435             changed = 1;
436             v->cur_seq_no = c->cur_seq_no;
437             v->pb.eof_reached = 0;
438             av_log(s, AV_LOG_INFO, "Now receiving variant %d\n", i);
439         } else if (first && !v->cur_needed && v->needed) {
440             if (v->input)
441                 ffurl_close(v->input);
442             v->input = NULL;
443             v->needed = 0;
444             changed = 1;
445             av_log(s, AV_LOG_INFO, "No longer receiving variant %d\n", i);
446         }
447     }
448     return changed;
449 }
450
451 static int applehttp_read_packet(AVFormatContext *s, AVPacket *pkt)
452 {
453     AppleHTTPContext *c = s->priv_data;
454     int ret, i, minvariant = -1;
455
456     if (c->first_packet) {
457         recheck_discard_flags(s, 1);
458         c->first_packet = 0;
459     }
460
461 start:
462     c->end_of_segment = 0;
463     for (i = 0; i < c->n_variants; i++) {
464         struct variant *var = c->variants[i];
465         /* Make sure we've got one buffered packet from each open variant
466          * stream */
467         if (var->needed && !var->pkt.data) {
468             ret = av_read_frame(var->ctx, &var->pkt);
469             if (ret < 0) {
470                 if (!var->pb.eof_reached)
471                     return ret;
472                 reset_packet(&var->pkt);
473             }
474         }
475         /* Check if this stream has the packet with the lowest dts */
476         if (var->pkt.data) {
477             if (minvariant < 0 ||
478                 var->pkt.dts < c->variants[minvariant]->pkt.dts)
479                 minvariant = i;
480         }
481     }
482     if (c->end_of_segment) {
483         if (recheck_discard_flags(s, 0))
484             goto start;
485     }
486     /* If we got a packet, return it */
487     if (minvariant >= 0) {
488         *pkt = c->variants[minvariant]->pkt;
489         pkt->stream_index += c->variants[minvariant]->stream_offset;
490         reset_packet(&c->variants[minvariant]->pkt);
491         return 0;
492     }
493     return AVERROR_EOF;
494 }
495
496 static int applehttp_close(AVFormatContext *s)
497 {
498     AppleHTTPContext *c = s->priv_data;
499
500     free_variant_list(c);
501     return 0;
502 }
503
504 static int applehttp_read_seek(AVFormatContext *s, int stream_index,
505                                int64_t timestamp, int flags)
506 {
507     AppleHTTPContext *c = s->priv_data;
508     int i, j, ret;
509
510     if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished)
511         return AVERROR(ENOSYS);
512
513     timestamp = av_rescale_rnd(timestamp, 1, stream_index >= 0 ?
514                                s->streams[stream_index]->time_base.den :
515                                AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
516                                AV_ROUND_DOWN : AV_ROUND_UP);
517     ret = AVERROR(EIO);
518     for (i = 0; i < c->n_variants; i++) {
519         /* Reset reading */
520         struct variant *var = c->variants[i];
521         int64_t pos = 0;
522         if (var->input) {
523             ffurl_close(var->input);
524             var->input = NULL;
525         }
526         av_free_packet(&var->pkt);
527         reset_packet(&var->pkt);
528         var->pb.eof_reached = 0;
529
530         /* Locate the segment that contains the target timestamp */
531         for (j = 0; j < var->n_segments; j++) {
532             if (timestamp >= pos &&
533                 timestamp < pos + var->segments[j]->duration) {
534                 var->cur_seq_no = var->start_seq_no + j;
535                 ret = 0;
536                 break;
537             }
538             pos += var->segments[j]->duration;
539         }
540     }
541     return ret;
542 }
543
544 static int applehttp_probe(AVProbeData *p)
545 {
546     /* Require #EXTM3U at the start, and either one of the ones below
547      * somewhere for a proper match. */
548     if (strncmp(p->buf, "#EXTM3U", 7))
549         return 0;
550     if (strstr(p->buf, "#EXT-X-STREAM-INF:")     ||
551         strstr(p->buf, "#EXT-X-TARGETDURATION:") ||
552         strstr(p->buf, "#EXT-X-MEDIA-SEQUENCE:"))
553         return AVPROBE_SCORE_MAX;
554     return 0;
555 }
556
557 AVInputFormat ff_applehttp_demuxer = {
558     "applehttp",
559     NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming format"),
560     sizeof(AppleHTTPContext),
561     applehttp_probe,
562     applehttp_read_header,
563     applehttp_read_packet,
564     applehttp_close,
565     applehttp_read_seek,
566 };