X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fhls.c;h=8ad08baaed41c5af1f7c0551ddd507069c5eb935;hb=b80003fe286ed37c81624dd6ab624fc3dd20c9d2;hp=2387d06e5f7709840014e6ab48f7565de3ceebba;hpb=6fbfb20faf22d15c0c92d124e22eb8298fb10dcb;p=ffmpeg diff --git a/libavformat/hls.c b/libavformat/hls.c index 2387d06e5f7..8ad08baaed4 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -202,11 +202,6 @@ typedef struct HLSContext { int64_t first_timestamp; int64_t cur_timestamp; AVIOInterruptCB *interrupt_callback; - char *referer; ///< holds HTTP referer set as an AVOption to the HTTP protocol context - char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context - char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context - char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context - char *http_proxy; ///< holds the address of the HTTP proxy server AVDictionary *avio_opts; int strict_std_compliance; char *allowed_extensions; @@ -216,16 +211,21 @@ typedef struct HLSContext { AVIOContext *playlist_pb; } HLSContext; -static void free_segment_list(struct playlist *pls) +static void free_segment_dynarray(struct segment **segments, int n_segments) { int i; - for (i = 0; i < pls->n_segments; i++) { - av_freep(&pls->segments[i]->key); - av_freep(&pls->segments[i]->url); - av_freep(&pls->segments[i]); + for (i = 0; i < n_segments; i++) { + av_freep(&segments[i]->key); + av_freep(&segments[i]->url); + av_freep(&segments[i]); } - av_freep(&pls->segments); - pls->n_segments = 0; +} + +static void free_segment_list(struct playlist *pls) +{ + free_segment_dynarray(pls->segments, pls->n_segments); + av_freep(&pls->segments); + pls->n_segments = 0; } static void free_init_section_list(struct playlist *pls) @@ -267,10 +267,6 @@ static void free_playlist_list(HLSContext *c) av_free(pls); } av_freep(&c->playlists); - av_freep(&c->cookies); - av_freep(&c->user_agent); - av_freep(&c->headers); - av_freep(&c->http_proxy); c->n_playlists = 0; } @@ -593,14 +589,6 @@ static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url return 0; } -static void update_options(char **dest, const char *name, void *src) -{ - av_freep(dest); - av_opt_get(src, name, AV_OPT_SEARCH_CHILDREN, (uint8_t**)dest); - if (*dest && !strlen(*dest)) - av_freep(dest); -} - static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb, const char *url) { @@ -684,12 +672,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, if (!(s->flags & AVFMT_FLAG_CUSTOM_IO)) av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies); - if (new_cookies) { - av_free(c->cookies); - c->cookies = new_cookies; - } - - av_dict_set(&opts, "cookies", c->cookies, 0); + if (new_cookies) + av_dict_set(&opts, "cookies", new_cookies, AV_DICT_DONT_STRDUP_VAL); } av_dict_free(&tmp); @@ -719,6 +703,9 @@ static int parse_playlist(HLSContext *c, const char *url, char tmp_str[MAX_URL_SIZE]; struct segment *cur_init_section = NULL; int is_http = av_strstart(url, "http", NULL); + struct segment **prev_segments = NULL; + int prev_n_segments = 0; + int prev_start_seq_no = -1; if (is_http && !in && c->http_persistent && c->playlist_pb) { in = c->playlist_pb; @@ -736,14 +723,7 @@ static int parse_playlist(HLSContext *c, const char *url, if (!in) { AVDictionary *opts = NULL; - /* Some HLS servers don't like being sent the range header */ - av_dict_set(&opts, "seekable", "0", 0); - - // broker prior HTTP options that should be consistent across requests - av_dict_set(&opts, "user_agent", c->user_agent, 0); - av_dict_set(&opts, "cookies", c->cookies, 0); - av_dict_set(&opts, "headers", c->headers, 0); - av_dict_set(&opts, "http_proxy", c->http_proxy, 0); + av_dict_copy(&opts, c->avio_opts, 0); if (c->http_persistent) av_dict_set(&opts, "multiple_requests", "1", 0); @@ -769,7 +749,12 @@ static int parse_playlist(HLSContext *c, const char *url, } if (pls) { - free_segment_list(pls); + prev_start_seq_no = pls->start_seq_no; + prev_segments = pls->segments; + prev_n_segments = pls->n_segments; + pls->segments = NULL; + pls->n_segments = 0; + pls->finished = 0; pls->type = PLS_TYPE_UNSPECIFIED; } @@ -826,6 +811,27 @@ static int parse_playlist(HLSContext *c, const char *url, ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_init_section_args, &info); cur_init_section = new_init_section(pls, &info, url); + cur_init_section->key_type = key_type; + if (has_iv) { + memcpy(cur_init_section->iv, iv, sizeof(iv)); + } else { + int seq = pls->start_seq_no + pls->n_segments; + memset(cur_init_section->iv, 0, sizeof(cur_init_section->iv)); + AV_WB32(cur_init_section->iv + 12, seq); + } + + if (key_type != KEY_NONE) { + ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key); + cur_init_section->key = av_strdup(tmp_str); + if (!cur_init_section->key) { + av_free(cur_init_section); + ret = AVERROR(ENOMEM); + goto fail; + } + } else { + cur_init_section->key = NULL; + } + } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (pls) pls->finished = 1; @@ -909,6 +915,23 @@ static int parse_playlist(HLSContext *c, const char *url, } } } + if (prev_segments) { + if (pls->start_seq_no > prev_start_seq_no && c->first_timestamp != AV_NOPTS_VALUE) { + int64_t prev_timestamp = c->first_timestamp; + int i, diff = pls->start_seq_no - prev_start_seq_no; + for (i = 0; i < prev_n_segments && i < diff; i++) { + c->first_timestamp += prev_segments[i]->duration; + } + av_log(c->ctx, AV_LOG_DEBUG, "Media sequence change (%d -> %d)" + " reflected in first_timestamp: %"PRId64" -> %"PRId64"\n", + prev_start_seq_no, pls->start_seq_no, + prev_timestamp, c->first_timestamp); + } else if (pls->start_seq_no < prev_start_seq_no) { + av_log(c->ctx, AV_LOG_WARNING, "Media sequence changed unexpectedly: %d -> %d\n", + prev_start_seq_no, pls->start_seq_no); + } + free_segment_dynarray(prev_segments, prev_n_segments); + } if (pls) pls->last_load_time = av_gettime_relative(); @@ -947,9 +970,6 @@ static int read_from_url(struct playlist *pls, struct segment *seg, buf_size = FFMIN(buf_size, seg->size - pls->cur_seg_offset); ret = avio_read(pls->input, buf, buf_size); - if (ret != buf_size) - av_log(NULL, AV_LOG_ERROR, "Could not read complete segment.\n"); - if (ret > 0) pls->cur_seg_offset += ret; @@ -1160,14 +1180,6 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, int ret; int is_http = 0; - // broker prior HTTP options that should be consistent across requests - av_dict_set(&opts, "user_agent", c->user_agent, 0); - av_dict_set(&opts, "referer", c->referer, 0); - av_dict_set(&opts, "cookies", c->cookies, 0); - av_dict_set(&opts, "headers", c->headers, 0); - av_dict_set(&opts, "http_proxy", c->http_proxy, 0); - av_dict_set(&opts, "seekable", "0", 0); - if (c->http_persistent) av_dict_set(&opts, "multiple_requests", "1", 0); @@ -1184,7 +1196,6 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, if (seg->key_type == KEY_NONE) { ret = open_url(pls->parent, in, seg->url, c->avio_opts, opts, &is_http); } else if (seg->key_type == KEY_AES_128) { - AVDictionary *opts2 = NULL; char iv[33], key[33], url[MAX_URL_SIZE]; if (strcmp(seg->key, pls->key_url)) { AVIOContext *pb = NULL; @@ -1209,14 +1220,10 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, else snprintf(url, sizeof(url), "crypto:%s", seg->url); - av_dict_copy(&opts2, c->avio_opts, 0); - av_dict_set(&opts2, "key", key, 0); - av_dict_set(&opts2, "iv", iv, 0); - - ret = open_url(pls->parent, in, url, opts2, opts, &is_http); - - av_dict_free(&opts2); + av_dict_set(&opts, "key", key, 0); + av_dict_set(&opts, "iv", iv, 0); + ret = open_url(pls->parent, in, url, c->avio_opts, opts, &is_http); if (ret < 0) { goto cleanup; } @@ -1637,7 +1644,7 @@ static int save_avio_options(AVFormatContext *s) { HLSContext *c = s->priv_data; static const char * const opts[] = { - "headers", "http_proxy", "user_agent", "user-agent", "cookies", "referer", NULL }; + "headers", "http_proxy", "user_agent", "cookies", "referer", "rw_timeout", NULL }; const char * const * opt = opts; uint8_t *buf; int ret = 0; @@ -1772,7 +1779,6 @@ static int hls_close(AVFormatContext *s) static int hls_read_header(AVFormatContext *s) { - void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; HLSContext *c = s->priv_data; int ret = 0, i; int highest_cur_seq_no = 0; @@ -1785,29 +1791,15 @@ static int hls_read_header(AVFormatContext *s) c->first_timestamp = AV_NOPTS_VALUE; c->cur_timestamp = AV_NOPTS_VALUE; - if (u) { - // get the previous user agent & set back to null if string size is zero - update_options(&c->user_agent, "user_agent", u); - - // get the previous cookies & set back to null if string size is zero - update_options(&c->cookies, "cookies", u); - - // get the previous headers & set back to null if string size is zero - update_options(&c->headers, "headers", u); - - // get the previous http proxt & set back to null if string size is zero - update_options(&c->http_proxy, "http_proxy", u); - } - - if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0) - goto fail; - if ((ret = save_avio_options(s)) < 0) goto fail; /* Some HLS servers don't like being sent the range header */ av_dict_set(&c->avio_opts, "seekable", "0", 0); + if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0) + goto fail; + if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF;