From 0c73a5a53cc97f4291bbe9e1e68226edf6161744 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Thu, 23 Jul 2015 21:11:58 +0200 Subject: [PATCH] hls: Save and forward avio options Make possible to send the custom headers and override the user agent. Reported-by: BenWonder --- libavformat/hls.c | 93 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 13 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 8b52a35508606..467a4913a53c8 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -103,6 +103,7 @@ typedef struct HLSContext { int64_t seek_timestamp; int seek_flags; AVIOInterruptCB *interrupt_callback; + AVDictionary *avio_opts; } HLSContext; static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) @@ -199,6 +200,51 @@ static void handle_key_args(struct key_info *info, const char *key, } } +static int open_in(HLSContext *c, AVIOContext **in, const char *url) +{ + AVDictionary *tmp = NULL; + int ret; + + av_dict_copy(&tmp, c->avio_opts, 0); + + ret = avio_open2(in, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); + + av_dict_free(&tmp); + return ret; +} + +static int url_connect(struct variant *var, AVDictionary *opts) +{ + AVDictionary *tmp = NULL; + int ret; + + av_dict_copy(&tmp, opts, 0); + + av_opt_set_dict(var->input, &tmp); + + if ((ret = ffurl_connect(var->input, NULL)) < 0) { + ffurl_close(var->input); + var->input = NULL; + } + + av_dict_free(&tmp); + return ret; +} + +static int open_url(HLSContext *c, URLContext **uc, const char *url) +{ + AVDictionary *tmp = NULL; + int ret; + + av_dict_copy(&tmp, c->avio_opts, 0); + + ret = ffurl_open(uc, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); + + av_dict_free(&tmp); + + return ret; +} + static int parse_playlist(HLSContext *c, const char *url, struct variant *var, AVIOContext *in) { @@ -214,10 +260,10 @@ static int parse_playlist(HLSContext *c, const char *url, uint8_t *new_url = NULL; if (!in) { - close_in = 1; - if ((ret = avio_open2(&in, url, AVIO_FLAG_READ, - c->interrupt_callback, NULL)) < 0) + ret = open_in(c, &in, url); + if (ret < 0) return ret; + close_in = 1; } if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) @@ -333,15 +379,14 @@ static int open_input(struct variant *var) { struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no]; if (seg->key_type == KEY_NONE) { - return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ, - &var->parent->interrupt_callback, NULL); + return open_url(var->parent->priv_data, &var->input, seg->url); } else if (seg->key_type == KEY_AES_128) { + HLSContext *c = var->parent->priv_data; 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) { + if (open_url(var->parent->priv_data, &uc, seg->key) == 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", @@ -366,12 +411,8 @@ static int open_input(struct variant *var) return ret; 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) { - ffurl_close(var->input); - var->input = NULL; - return ret; - } - return 0; + + return url_connect(var, c->avio_opts); } return AVERROR(ENOSYS); } @@ -449,6 +490,26 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) goto restart; } +static int save_avio_options(AVFormatContext *s) +{ + HLSContext *c = s->priv_data; + const char *opts[] = { "headers", "user_agent", NULL }, **opt = opts; + uint8_t *buf; + int ret = 0; + + while (*opt) { + if (av_opt_get(s->pb, *opt, AV_OPT_SEARCH_CHILDREN, &buf) >= 0) { + ret = av_dict_set(&c->avio_opts, *opt, buf, + AV_DICT_DONT_STRDUP_VAL); + if (ret < 0) + return ret; + } + opt++; + } + + return ret; +} + static int hls_read_header(AVFormatContext *s) { HLSContext *c = s->priv_data; @@ -459,6 +520,9 @@ static int hls_read_header(AVFormatContext *s) if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; + if ((ret = save_avio_options(s)) < 0) + goto fail; + if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; @@ -712,6 +776,9 @@ static int hls_close(AVFormatContext *s) HLSContext *c = s->priv_data; free_variant_list(c); + + av_dict_free(&c->avio_opts); + return 0; }