avformat/http: add -request-size option

It has come to my attention that a way to limit the request range size
would be useful in general, for reasons beyond just speeding up initial
header parsing.

This patch generalizez -initial_request_size to -request_size. I decided
to continue allowing both options to be used simultaneously, so users can
e.g. set -request_size to something large like 10 MiB, but still use a smaller
size for initial header parsing (e.g. 256 KiB).

Fixes: https://github.com/mpv-player/mpv/issues/8655
This commit is contained in:
Niklas Haas
2026-02-09 16:56:25 +01:00
committed by Niklas Haas
parent 3c03048837
commit 2e7078cda6
2 changed files with 26 additions and 14 deletions

View File

@@ -453,18 +453,27 @@ Set the Referer header. Include 'Referer: URL' header in HTTP request.
@item multiple_requests
Use persistent connections if set to 1, default is 0.
@item initial_request_size
Limit the size of initial requests. This is useful when dealing with formats
that require frequent seeks during initial parsing. This lasts until the
demuxer makes a read request larger than this size (without a seek in between),
after which the implementation will continue using unbounded requests as usual.
Disabled (set to 0) by default.
@item request_size
Limit the size of requests made. This is useful for some pathological servers
that throttle unbounded range requests, as well as when expecting to seek
frequently. Disabled (set to 0) by default.
Note that if enabling this option, it's strongly recommended to also enable
the @option{multiple_requests} option, as well as setting
@option{short_seek_size} to the same value or higher. Doing so allows FFmpeg
to reuse a single HTTP connection wherever possible, even for formats like
MXF or MOV that require frequent small seeks during initial parsing.
to reuse a single HTTP connection wherever possible.
@item initial_request_size
Limit the size of initial requests. Similar to @code{request_size}, but only
used during initial format parsing. Useful for formats like MXF or MOV that
require frequent seeks during header parsing. Lasts until the demuxer makes a
read request larger than this size (without a seek in between), after which
the implementation will continue using requests as usual. Disabled (set to 0)
by default.
Note that if enabling this option, it's strongly recommended to also enable
the @option{multiple_requests} option, as well as setting
@option{short_seek_size} to the same value or higher.
@item post_data
Set custom HTTP post data.

View File

@@ -147,7 +147,8 @@ typedef struct HTTPContext {
int reconnect_max_retries;
int reconnect_delay_total_max;
uint64_t initial_request_size;
int partial_requests; /* whether or not to limit requests to initial_request_size */
uint64_t request_size;
int initial_requests; /* whether or not to limit requests to initial_request_size */
/* Connection statistics */
int nb_connections;
int nb_requests;
@@ -173,6 +174,7 @@ static const AVOption options[] = {
{ "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
{ "referer", "override referer header", OFFSET(referer), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
{ "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D | E },
{ "request_size", "size (in bytes) of requests to make", OFFSET(request_size), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
{ "initial_request_size", "size (in bytes) of initial requests made during probing / header parsing", OFFSET(initial_request_size), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
{ "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E },
{ "mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY },
@@ -774,7 +776,7 @@ static int http_open(URLContext *h, const char *uri, int flags,
else
h->is_streamed = 1;
s->partial_requests = s->seekable != 0 && s->initial_request_size > 0;
s->initial_requests = s->seekable != 0 && s->initial_request_size > 0;
s->filesize = UINT64_MAX;
s->location = av_strdup(uri);
@@ -1477,7 +1479,7 @@ static int http_read_header(URLContext *h)
h->is_streamed = 1; /* we can in fact _not_ seek */
if (h->is_streamed)
s->partial_requests = 0; /* unable to use partial requests */
s->initial_requests = 0; /* unable to use partial requests */
// add any new cookies into the existing cookie string
cookie_string(s->cookie_dict, &s->cookies);
@@ -1588,8 +1590,9 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
// server supports seeking by analysing the reply headers.
if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable != 0)) {
av_bprintf(&request, "Range: bytes=%"PRIu64"-", s->off);
if (s->partial_requests && s->seekable != 0) {
uint64_t target_off = s->off + s->initial_request_size;
if ((s->initial_requests || s->request_size) && s->seekable != 0) {
uint64_t req_size = s->initial_requests ? s->initial_request_size : s->request_size;
uint64_t target_off = s->off + req_size;
if (target_off < s->off) /* overflow */
target_off = UINT64_MAX;
if (s->end_off)
@@ -1840,7 +1843,7 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
AVDictionary *options = NULL;
if (s->willclose)
ffurl_closep(&s->hd);
s->partial_requests = 0; /* continue streaming uninterrupted from now on */
s->initial_requests = 0; /* continue streaming uninterrupted from now on */
read_ret = http_open_cnx(h, &options);
av_dict_free(&options);
if (read_ret == 0)