diff options
Diffstat (limited to 'libavformat/hls.c')
-rw-r--r-- | libavformat/hls.c | 87 |
1 files changed, 61 insertions, 26 deletions
diff --git a/libavformat/hls.c b/libavformat/hls.c index 1f6b7d5..6675a1a 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -2,20 +2,20 @@ * Apple HTTP Live Streaming demuxer * Copyright (c) 2010 Martin Storsjo * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -42,7 +42,7 @@ * An apple http stream consists of a playlist with media segment files, * played sequentially. There may be several playlists with the same * video content, in different bandwidth variants, that are played in - * parallel (preferrably only one bandwidth variant at a time). In this case, + * parallel (preferably only one bandwidth variant at a time). In this case, * the user supplied the url to a main playlist that only lists the variant * playlists. * @@ -212,9 +212,14 @@ static int parse_playlist(HLSContext *c, const char *url, int close_in = 0; if (!in) { + AVDictionary *opts = NULL; close_in = 1; - if ((ret = avio_open2(&in, url, AVIO_FLAG_READ, - c->interrupt_callback, NULL)) < 0) + /* Some HLS servers dont like being sent the range header */ + av_dict_set(&opts, "seekable", "0", 0); + ret = avio_open2(&in, url, AVIO_FLAG_READ, + c->interrupt_callback, &opts); + av_dict_free(&opts); + if (ret < 0) return ret; } @@ -228,7 +233,7 @@ static int parse_playlist(HLSContext *c, const char *url, free_segment_list(var); var->finished = 0; } - while (!in->eof_reached) { + while (!url_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; @@ -325,17 +330,20 @@ fail: static int open_input(struct variant *var) { + AVDictionary *opts = NULL; + int ret; struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no]; + av_dict_set(&opts, "seekable", "0", 0); if (seg->key_type == KEY_NONE) { - return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ, - &var->parent->interrupt_callback, NULL); + ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ, + &var->parent->interrupt_callback, &opts); + goto cleanup; } else if (seg->key_type == KEY_AES_128) { char iv[33], key[33], url[MAX_URL_SIZE]; - int ret; if (strcmp(seg->key, var->key_url)) { URLContext *uc; if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ, - &var->parent->interrupt_callback, NULL) == 0) { + &var->parent->interrupt_callback, &opts) == 0) { if (ffurl_read_complete(uc, var->key, sizeof(var->key)) != sizeof(var->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", @@ -357,17 +365,25 @@ static int open_input(struct variant *var) snprintf(url, sizeof(url), "crypto:%s", seg->url); if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ, &var->parent->interrupt_callback)) < 0) - return ret; + goto cleanup; av_opt_set(var->input->priv_data, "key", key, 0); av_opt_set(var->input->priv_data, "iv", iv, 0); - if ((ret = ffurl_connect(var->input, NULL)) < 0) { + /* Need to repopulate options */ + av_dict_free(&opts); + av_dict_set(&opts, "seekable", "0", 0); + if ((ret = ffurl_connect(var->input, &opts)) < 0) { ffurl_close(var->input); var->input = NULL; - return ret; + goto cleanup; } - return 0; + ret = 0; } - return AVERROR(ENOSYS); + else + ret = AVERROR(ENOSYS); + +cleanup: + av_dict_free(&opts); + return ret; } static int read_data(void *opaque, uint8_t *buf, int buf_size) @@ -427,7 +443,7 @@ reload: c->end_of_segment = 1; c->cur_seq_no = v->cur_seq_no; - if (v->ctx && v->ctx->nb_streams) { + if (v->ctx && v->ctx->nb_streams && v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) { v->needed = 0; for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; i++) { @@ -517,6 +533,7 @@ static int hls_read_header(AVFormatContext *s) * so avformat_close_input shouldn't be called. If * avformat_open_input fails below, it frees and zeros the * context, so it doesn't need any special treatment like this. */ + av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", v->segments[0]->url); avformat_free_context(v->ctx); v->ctx = NULL; goto fail; @@ -525,7 +542,12 @@ static int hls_read_header(AVFormatContext *s) ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; + v->stream_offset = stream_offset; + v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; + ret = avformat_find_stream_info(v->ctx, NULL); + if (ret < 0) + goto fail; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); /* Create new AVStreams for each stream in this variant */ for (j = 0; j < v->ctx->nb_streams; j++) { @@ -560,7 +582,7 @@ static int recheck_discard_flags(AVFormatContext *s, int first) /* Check if any new streams are needed */ for (i = 0; i < c->n_variants; i++) - c->variants[i]->cur_needed = 0;; + c->variants[i]->cur_needed = 0; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; @@ -610,7 +632,7 @@ start: AVStream *st; ret = av_read_frame(var->ctx, &var->pkt); if (ret < 0) { - if (!var->pb.eof_reached) + if (!url_feof(&var->pb) && ret != AVERROR_EOF) return ret; reset_packet(&var->pkt); break; @@ -640,9 +662,21 @@ start: } /* Check if this stream has the packet with the lowest dts */ if (var->pkt.data) { - if (minvariant < 0 || - var->pkt.dts < c->variants[minvariant]->pkt.dts) + if(minvariant < 0) { minvariant = i; + } else { + struct variant *minvar = c->variants[minvariant]; + int64_t dts = var->pkt.dts; + int64_t mindts = minvar->pkt.dts; + AVStream *st = var->ctx->streams[ var->pkt.stream_index]; + AVStream *minst= minvar->ctx->streams[minvar->pkt.stream_index]; + + if( st->start_time != AV_NOPTS_VALUE) dts -= st->start_time; + if(minst->start_time != AV_NOPTS_VALUE) mindts -= minst->start_time; + + if (av_compare_ts(dts, st->time_base, mindts, minst->time_base) < 0) + minvariant = i; + } } } if (c->end_of_segment) { @@ -696,10 +730,11 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, /* Reset reading */ struct variant *var = c->variants[i]; int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 : - av_rescale_rnd(c->first_timestamp, 1, - stream_index >= 0 ? s->streams[stream_index]->time_base.den : AV_TIME_BASE, - flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP); - if (var->input) { + av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ? + s->streams[stream_index]->time_base.den : + AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ? + AV_ROUND_DOWN : AV_ROUND_UP); + if (var->input) { ffurl_close(var->input); var->input = NULL; } |