Revision 6cc7f139 libavformat/applehttp.c

View differences:

libavformat/applehttp.c
30 30
#include "avformat.h"
31 31
#include "internal.h"
32 32
#include <unistd.h>
33
#include "avio_internal.h"
34

  
35
#define INITIAL_BUFFER_SIZE 32768
33 36

  
34 37
/*
35 38
 * An apple http stream consists of a playlist with media segment files,
......
56 59
struct variant {
57 60
    int bandwidth;
58 61
    char url[MAX_URL_SIZE];
59
    AVIOContext *pb;
62
    AVIOContext pb;
63
    uint8_t* read_buffer;
64
    URLContext *input;
65
    AVFormatContext *parent;
66
    int index;
60 67
    AVFormatContext *ctx;
61 68
    AVPacket pkt;
62 69
    int stream_offset;
......
66 73
    int start_seq_no;
67 74
    int n_segments;
68 75
    struct segment **segments;
69
    int needed;
76
    int needed, cur_needed;
77
    int cur_seq_no;
78
    int64_t last_load_time;
70 79
};
71 80

  
72 81
typedef struct AppleHTTPContext {
73 82
    int n_variants;
74 83
    struct variant **variants;
75 84
    int cur_seq_no;
76
    int64_t last_load_time;
77
    int64_t last_packet_dts;
78
    int max_start_seq, min_end_seq;
85
    int end_of_segment;
86
    int first_packet;
79 87
} AppleHTTPContext;
80 88

  
81 89
static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
......
102 110
        struct variant *var = c->variants[i];
103 111
        free_segment_list(var);
104 112
        av_free_packet(&var->pkt);
105
        if (var->pb)
106
            avio_close(var->pb);
113
        av_free(var->pb.buffer);
114
        if (var->input)
115
            url_close(var->input);
107 116
        if (var->ctx) {
108 117
            var->ctx->pb = NULL;
109 118
            av_close_input_file(var->ctx);
......
238 247
            }
239 248
        }
240 249
    }
241
    c->last_load_time = av_gettime();
250
    if (var)
251
        var->last_load_time = av_gettime();
242 252

  
243 253
fail:
244 254
    if (close_in)
......
246 256
    return ret;
247 257
}
248 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

  
249 324
static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap)
250 325
{
251 326
    AppleHTTPContext *c = s->priv_data;
......
284 359
        s->duration = duration * AV_TIME_BASE;
285 360
    }
286 361

  
287
    c->min_end_seq = INT_MAX;
288 362
    /* Open the demuxer for each variant */
289 363
    for (i = 0; i < c->n_variants; i++) {
290 364
        struct variant *v = c->variants[i];
365
        AVInputFormat *in_fmt = NULL;
291 366
        if (v->n_segments == 0)
292 367
            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);
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);
297 389
        if (ret < 0)
298 390
            goto fail;
299
        avio_close(v->ctx->pb);
300
        v->ctx->pb = NULL;
301 391
        v->stream_offset = stream_offset;
302 392
        /* Create new AVStreams for each stream in this variant */
303 393
        for (j = 0; j < v->ctx->nb_streams; j++) {
......
310 400
        }
311 401
        stream_offset += v->ctx->nb_streams;
312 402
    }
313
    c->last_packet_dts = AV_NOPTS_VALUE;
314 403

  
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
    if (!c->variants[0]->finished && c->min_end_seq - c->max_start_seq > 3)
319
        c->cur_seq_no = c->min_end_seq - 2;
404
    c->first_packet = 1;
320 405

  
321 406
    return 0;
322 407
fail:
......
324 409
    return ret;
325 410
}
326 411

  
327
static int open_variant(AppleHTTPContext *c, struct variant *var, int skip)
412
static int recheck_discard_flags(AVFormatContext *s, int first)
328 413
{
329
    int ret;
414
    AppleHTTPContext *c = s->priv_data;
415
    int i, changed = 0;
330 416

  
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;
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;
336 426
    }
337
    if (c->cur_seq_no - var->start_seq_no >= var->n_segments)
338
        return c->variants[0]->finished ? AVERROR_EOF : 0;
339
    ret = avio_open(&var->pb,
340
                    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);
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);
360 442
        }
361 443
    }
362
    return 0;
444
    return changed;
363 445
}
364 446

  
365 447
static int applehttp_read_packet(AVFormatContext *s, AVPacket *pkt)
366 448
{
367 449
    AppleHTTPContext *c = s->priv_data;
368
    int ret, i, minvariant = -1, first = 1, needed = 0, changed = 0,
369
        variants = 0;
450
    int ret, i, minvariant = -1;
370 451

  
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;
452
    if (c->first_packet) {
453
        recheck_discard_flags(s, 1);
454
        c->first_packet = 0;
384 455
    }
385
    if (!needed)
386
        return AVERROR_EOF;
456

  
387 457
start:
458
    c->end_of_segment = 0;
388 459
    for (i = 0; i < c->n_variants; i++) {
389 460
        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
            avio_close(var->pb);
397
            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
            if (first && !var->finished)
403
                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 461
        /* Make sure we've got one buffered packet from each open variant
414 462
         * stream */
415
        if (var->pb && !var->pkt.data) {
463
        if (var->needed && !var->pkt.data) {
416 464
            ret = av_read_frame(var->ctx, &var->pkt);
417 465
            if (ret < 0) {
418
                if (!var->pb->eof_reached)
466
                if (!var->pb.eof_reached)
419 467
                    return ret;
420 468
                reset_packet(&var->pkt);
421 469
            }
......
427 475
                minvariant = i;
428 476
        }
429 477
    }
430
    if (first && changed)
431
        av_log(s, AV_LOG_INFO, "Receiving %d variant streams\n", variants);
478
    if (c->end_of_segment) {
479
        if (recheck_discard_flags(s, 0))
480
            goto start;
481
    }
432 482
    /* If we got a packet, return it */
433 483
    if (minvariant >= 0) {
434 484
        *pkt = c->variants[minvariant]->pkt;
435 485
        pkt->stream_index += c->variants[minvariant]->stream_offset;
436 486
        reset_packet(&c->variants[minvariant]->pkt);
437
        c->last_packet_dts = pkt->dts;
438 487
        return 0;
439 488
    }
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
            avio_close(var->pb);
446
            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
    if (!c->variants[0]->finished) {
455
        /* 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
        if (now - c->last_load_time >= c->variants[0]->target_duration*1000000) {
459
            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
    /* If more segments exist, open the next one */
481
    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
    if (c->variants[0]->finished)
486
        return AVERROR_EOF;
487
    while (av_gettime() - c->last_load_time <
488
           c->variants[0]->target_duration*1000000) {
489
        if (url_interrupt_cb())
490
            return AVERROR_EXIT;
491
        usleep(100*1000);
492
    }
493
    /* Enough time has elapsed since the last reload */
494
    goto reload;
489
    return AVERROR_EOF;
495 490
}
496 491

  
497 492
static int applehttp_close(AVFormatContext *s)
......
506 501
                               int64_t timestamp, int flags)
507 502
{
508 503
    AppleHTTPContext *c = s->priv_data;
509
    int64_t pos = 0;
510
    int i;
511
    struct variant *var = c->variants[0];
504
    int i, j, ret;
512 505

  
513 506
    if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished)
514 507
        return AVERROR(ENOSYS);
515 508

  
516 509
    /* Reset the variants */
517
    c->last_packet_dts = AV_NOPTS_VALUE;
518 510
    for (i = 0; i < c->n_variants; i++) {
519 511
        struct variant *var = c->variants[i];
520
        if (var->pb) {
521
            avio_close(var->pb);
522
            var->pb = NULL;
512
        if (var->input) {
513
            url_close(var->input);
514
            var->input = NULL;
523 515
        }
524 516
        av_free_packet(&var->pkt);
525 517
        reset_packet(&var->pkt);
518
        var->pb.eof_reached = 0;
526 519
    }
527 520

  
528 521
    timestamp = av_rescale_rnd(timestamp, 1, stream_index >= 0 ?
529 522
                               s->streams[stream_index]->time_base.den :
530 523
                               AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
531 524
                               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;
525
    ret = AVERROR(EIO);
526
    for (i = 0; i < c->n_variants; i++) {
527
        struct variant *var = c->variants[i];
528
        int64_t pos = 0;
529
        /* Locate the segment that contains the target timestamp */
530
        for (j = 0; j < var->n_segments; j++) {
531
            if (timestamp >= pos &&
532
                timestamp < pos + var->segments[j]->duration) {
533
                var->cur_seq_no = var->start_seq_no + j;
534
                ret = 0;
535
                break;
536
            }
537
            pos += var->segments[j]->duration;
537 538
        }
538
        pos += var->segments[i]->duration;
539 539
    }
540
    return AVERROR(EIO);
540
    return ret;
541 541
}
542 542

  
543 543
static int applehttp_probe(AVProbeData *p)

Also available in: Unified diff