diff --git a/libavformat/http.c b/libavformat/http.c index 91650be47a..4415a26f2c 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -69,7 +69,9 @@ typedef struct HTTPContext { uint64_t chunksize; int chunkend; uint64_t off, end_off, filesize; + char *uri; char *location; + int cache_redirect; HTTPAuthState auth_state; HTTPAuthState proxy_auth_state; char *http_proxy; @@ -169,6 +171,7 @@ static const AVOption options[] = { { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, { "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E}, { "short_seek_size", "Threshold to favor readahead over seek.", OFFSET(short_seek_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D }, + { "cache_redirect", "Save redirected URL for subsequent seek operations", OFFSET(cache_redirect), AV_OPT_TYPE_BOOL, { .i64 = FF_HTTP_CACHE_REDIRECT_DEFAULT }, 0, 1, D }, { NULL } }; @@ -432,11 +435,17 @@ int ff_http_do_new_request2(URLContext *h, const char *uri, AVDictionary **opts) s->chunkend = 0; s->off = 0; s->icy_data_read = 0; + av_free(s->location); s->location = av_strdup(uri); if (!s->location) return AVERROR(ENOMEM); + av_free(s->uri); + s->uri = av_strdup(uri); + if (!s->uri) + return AVERROR(ENOMEM); + if ((ret = av_opt_set_dict(s, opts)) < 0) return ret; @@ -623,9 +632,15 @@ static int http_open(URLContext *h, const char *uri, int flags, h->is_streamed = 1; s->filesize = UINT64_MAX; + s->location = av_strdup(uri); if (!s->location) return AVERROR(ENOMEM); + + s->uri = av_strdup(uri); + if (!s->uri) + return AVERROR(ENOMEM); + if (options) av_dict_copy(&s->chained_options, *options, 0); @@ -651,6 +666,7 @@ bail_out: if (ret < 0) { av_dict_free(&s->chained_options); av_dict_free(&s->cookie_dict); + av_freep(&s->uri); } return ret; } @@ -1769,6 +1785,7 @@ static int http_close(URLContext *h) ffurl_closep(&s->hd); av_dict_free(&s->chained_options); av_dict_free(&s->cookie_dict); + av_freep(&s->uri); return ret; } @@ -1810,6 +1827,16 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo return s->off; } + /* if redirect caching is disabled, revert to the original uri */ + if (!s->cache_redirect && strcmp(s->uri, s->location)) { + char *new_uri; + new_uri = av_strdup(s->uri); + if (!new_uri) + return AVERROR(ENOMEM); + av_free(s->location); + s->location = new_uri; + } + /* we save the old context in case the seek fails */ old_buf_size = s->buf_end - s->buf_ptr; memcpy(old_buf, s->buf_ptr, old_buf_size); diff --git a/libavformat/version.h b/libavformat/version.h index 917b9ffa5d..f372380dcf 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -60,6 +60,7 @@ #define FF_API_AVIOCONTEXT_WRITTEN (LIBAVFORMAT_VERSION_MAJOR < 60) #define FF_HLS_TS_OPTIONS (LIBAVFORMAT_VERSION_MAJOR < 60) #define FF_API_AVSTREAM_CLASS (LIBAVFORMAT_VERSION_MAJOR > 59) +#define FF_HTTP_CACHE_REDIRECT_DEFAULT (LIBAVFORMAT_VERSION_MAJOR < 60) #define FF_API_R_FRAME_RATE 1