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