Statistics
| Branch: | Revision:

ffmpeg / libavformat / applehttp.c @ d3964da2

History | View | Annotate | Download (18 KB)

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