ffmpeg-cvslog
Threads by month
- ----- 2026 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
September 2025
- 1 participants
- 195 discussions
[ffmpeg] branch master updated. 8e11e2cdb8 avformat/tls_openssl: initialize underlying protocol early for dtls_start()
by ffmpeg-git@ffmpeg.org 01 Oct '25
by ffmpeg-git@ffmpeg.org 01 Oct '25
01 Oct '25
The branch, master has been updated
via 8e11e2cdb82299e7f0b6d8884bf2bc65c1c3f5e8 (commit)
via 2762ae74c53b058345660019ecce4ba41a85a050 (commit)
via 3166e3b5394540dd827691773f499e98d7c0c69b (commit)
via f231439ee747f2e72bacc9fe7af30bd117eb46a9 (commit)
via 49c6e6cc44f011ea43a3cab1b965510569bd229d (commit)
via 7e58fff9d0b9b05f118917b5eb5704bb3514c6bd (commit)
via 2d06ed9308ebaa785d8b3389ad8da033b8839c89 (commit)
via 70e0e3e2572447c559aac5179578be5a584e942b (commit)
via c5be4b70754d276e7370dd90e807e883c4bec627 (commit)
via 6f17053e6c75e5c44eaee9d4da0a4c80470274d0 (commit)
from 8cb1ff78ac62ff0f652b0cb06369ba50d5e946c6 (commit)
- Log -----------------------------------------------------------------
commit 8e11e2cdb82299e7f0b6d8884bf2bc65c1c3f5e8
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Wed Sep 3 00:55:46 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Wed Oct 1 00:34:19 2025 +0200
avformat/tls_openssl: initialize underlying protocol early for dtls_start()
The same way we do with TLS, so all tls URL options will be properly supported.
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/doc/protocols.texi b/doc/protocols.texi
index 9f88f005b9..b74383122a 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -2052,12 +2052,19 @@ Datagram Transport Layer Security (DTLS)
The required syntax for a DTLS URL is:
@example
-dtls://@var{hostname}:@var{port}
+dtls://@var{hostname}:@var{port}[?@var{options}]
@end example
+@var{options} contains a list of &-separated options of the form
+@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
+space) can be used to escape keys and values.
+
+Options can also can be specified via command line options (or in code via
+@code{AVOption}s).
+
DTLS shares most options with TLS, but operates over UDP instead of TCP.
-The following parameters can be set via command line options
-(or in code via @code{AVOption}s):
+
+The list of supported options follows.
@table @option
diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c
index 5fc0b639d7..c2adaa38d1 100644
--- a/libavformat/tls_openssl.c
+++ b/libavformat/tls_openssl.c
@@ -747,6 +747,13 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary **
int ret = 0;
s->is_dtls = 1;
+ if (!c->tls_shared.external_sock) {
+ if ((ret = ff_tls_open_underlying(&c->tls_shared, h, url, options)) < 0) {
+ av_log(c, AV_LOG_ERROR, "Failed to connect %s\n", url);
+ return ret;
+ }
+ }
+
c->ctx = SSL_CTX_new(s->listen ? DTLS_server_method() : DTLS_client_method());
if (!c->ctx) {
ret = AVERROR(ENOMEM);
@@ -799,13 +806,6 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary **
DTLS_set_link_mtu(c->ssl, s->mtu);
init_bio_method(h);
- if (!c->tls_shared.external_sock) {
- if ((ret = ff_tls_open_underlying(&c->tls_shared, h, url, options)) < 0) {
- av_log(c, AV_LOG_ERROR, "Failed to connect %s\n", url);
- return ret;
- }
- }
-
/* This seems to be necessary despite explicitly setting client/server method above. */
if (s->listen)
SSL_set_accept_state(c->ssl);
@@ -836,6 +836,7 @@ static int dtls_start(URLContext *h, const char *url, int flags, AVDictionary **
ret = 0;
fail:
+ tls_close(h);
return ret;
}
commit 2762ae74c53b058345660019ecce4ba41a85a050
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Tue Aug 26 00:23:16 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Wed Oct 1 00:34:19 2025 +0200
avformat/tls: use ff_parse_opts_from_query_string() to set URL parameters
Note that this changes the code to work the same way as other protocols where
an URL parameter can override an AVOption.
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/doc/protocols.texi b/doc/protocols.texi
index 3d9685ed6d..9f88f005b9 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1984,8 +1984,14 @@ The required syntax for a TLS/SSL url is:
tls://@var{hostname}:@var{port}[?@var{options}]
@end example
-The following parameters can be set via command line options
-(or in code via @code{AVOption}s):
+@var{options} contains a list of &-separated options of the form
+@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
+space) can be used to escape keys and values.
+
+Options can also can be specified via command line options (or in code via
+@code{AVOption}s).
+
+The list of supported options follows.
@table @option
diff --git a/libavformat/tls.c b/libavformat/tls.c
index bd9c05e6dc..2cf0c99a6b 100644
--- a/libavformat/tls.c
+++ b/libavformat/tls.c
@@ -31,41 +31,6 @@
#include "libavutil/mem.h"
#include "libavutil/parseutils.h"
-static int set_options(TLSShared *c, const char *uri)
-{
- char buf[1024];
- const char *p = strchr(uri, '?');
- if (!p)
- return 0;
-
- if (!c->ca_file && av_find_info_tag(buf, sizeof(buf), "cafile", p)) {
- c->ca_file = av_strdup(buf);
- if (!c->ca_file)
- return AVERROR(ENOMEM);
- }
-
- if (!c->verify && av_find_info_tag(buf, sizeof(buf), "verify", p)) {
- char *endptr = NULL;
- c->verify = strtol(buf, &endptr, 10);
- if (buf == endptr)
- c->verify = 1;
- }
-
- if (!c->cert_file && av_find_info_tag(buf, sizeof(buf), "cert", p)) {
- c->cert_file = av_strdup(buf);
- if (!c->cert_file)
- return AVERROR(ENOMEM);
- }
-
- if (!c->key_file && av_find_info_tag(buf, sizeof(buf), "key", p)) {
- c->key_file = av_strdup(buf);
- if (!c->key_file)
- return AVERROR(ENOMEM);
- }
-
- return 0;
-}
-
int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options)
{
int port;
@@ -77,17 +42,18 @@ int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AV
int use_proxy;
int ret;
- ret = set_options(c, uri);
- if (ret < 0)
- return ret;
+ p = strchr(uri, '?');
+ if (p) {
+ ret = ff_parse_opts_from_query_string(c, p, 1);
+ if (ret < 0)
+ return ret;
+ }
if (c->listen && !c->is_dtls)
snprintf(opts, sizeof(opts), "?listen=1");
av_url_split(NULL, 0, NULL, 0, c->underlying_host, sizeof(c->underlying_host), &port, NULL, 0, uri);
- p = strchr(uri, '?');
-
if (!p) {
p = opts;
} else {
diff --git a/libavformat/tls_mbedtls.c b/libavformat/tls_mbedtls.c
index 2bcd3cca63..8aa142b9d2 100644
--- a/libavformat/tls_mbedtls.c
+++ b/libavformat/tls_mbedtls.c
@@ -174,17 +174,6 @@ static void handle_handshake_error(URLContext *h, int ret)
}
}
-static void parse_options(TLSContext *tls_ctxc, const char *uri)
-{
- char buf[1024];
- const char *p = strchr(uri, '?');
- if (!p)
- return;
-
- if (!tls_ctxc->priv_key_pw && av_find_info_tag(buf, sizeof(buf), "key_password", p))
- tls_ctxc->priv_key_pw = av_strdup(buf);
-}
-
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
{
TLSContext *tls_ctx = h->priv_data;
@@ -192,9 +181,6 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
uint32_t verify_res_flags;
int ret;
- // parse additional options
- parse_options(tls_ctx, uri);
-
if ((ret = ff_tls_open_underlying(shr, h, uri, options)) < 0)
goto fail;
commit 3166e3b5394540dd827691773f499e98d7c0c69b
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Mon Aug 25 21:35:40 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Wed Oct 1 00:34:19 2025 +0200
avformat/rtpproto: use ff_parse_opts_from_query_string() to set URL parameters
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/doc/protocols.texi b/doc/protocols.texi
index 563aee6cc7..3d9685ed6d 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1162,9 +1162,13 @@ rtp://@var{hostname}[:@var{port}][?@var{options}]
@var{port} specifies the RTP port to use.
@var{options} contains a list of &-separated options of the form
-@var{key}=@var{val}.
+@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
+space) can be used to escape keys and values.
-The following options are supported:
+Options can also can be specified via command line options (or in code via
+@code{AVOption}s).
+
+The list of supported options follows.
@table @option
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c
index 69879b7fa8..c4309c19e4 100644
--- a/libavformat/rtpproto.c
+++ b/libavformat/rtpproto.c
@@ -29,6 +29,7 @@
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#include "avformat.h"
+#include "internal.h"
#include "rtp.h"
#include "rtpproto.h"
#include "url.h"
@@ -232,8 +233,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
RTPContext *s = h->priv_data;
AVDictionary *fec_opts = NULL;
int rtp_port;
- char hostname[256], include_sources[1024] = "", exclude_sources[1024] = "";
- char *sources = include_sources, *block = exclude_sources;
+ char hostname[256];
char *fec_protocol = NULL;
char buf[1024];
char path[1024];
@@ -250,58 +250,17 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
p = strchr(uri, '?');
if (p) {
- if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
- s->ttl = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
- s->rtcp_port = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
- s->local_rtpport = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
- s->local_rtpport = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
- s->local_rtcpport = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
- s->pkt_size = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
- s->connect = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) {
- s->write_to_source = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) {
- s->dscp = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
- s->rw_timeout = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
- av_strlcpy(include_sources, buf, sizeof(include_sources));
- ff_ip_parse_sources(h, buf, &s->filters);
- } else {
- ff_ip_parse_sources(h, s->sources, &s->filters);
- sources = s->sources;
- }
- if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
- av_strlcpy(exclude_sources, buf, sizeof(exclude_sources));
- ff_ip_parse_blocks(h, buf, &s->filters);
- } else {
- ff_ip_parse_blocks(h, s->block, &s->filters);
- block = s->block;
- }
- if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) {
- av_freep(&s->localaddr);
- s->localaddr = av_strdup(buf);
- if (!s->localaddr) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- }
+ ret = ff_parse_opts_from_query_string(s, p, 1);
+ if (ret < 0)
+ goto fail;
+ }
+ if (s->sources) {
+ if ((ret = ff_ip_parse_sources(h, s->sources, &s->filters)) < 0)
+ goto fail;
+ }
+ if (s->block) {
+ if ((ret = ff_ip_parse_blocks(h, s->block, &s->filters)) < 0)
+ goto fail;
}
if (s->rw_timeout >= 0)
h->rw_timeout = s->rw_timeout;
@@ -334,6 +293,8 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
}
for (i = 0; i < max_retry_count; i++) {
+ const char *sources = s->sources ? s->sources : "";
+ const char *block = s->block ? s->block : "";
build_udp_url(s, buf, sizeof(buf),
hostname, s->localaddr, rtp_port, s->local_rtpport,
sources, block);
commit f231439ee747f2e72bacc9fe7af30bd117eb46a9
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Mon Aug 25 02:09:26 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Wed Oct 1 00:34:19 2025 +0200
avformat/sctp: use ff_parse_opts_from_query_string() to set URL parameters
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/doc/protocols.texi b/doc/protocols.texi
index a329f59fe3..563aee6cc7 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1535,7 +1535,15 @@ The accepted URL syntax is:
sctp://@var{host}:@var{port}[?@var{options}]
@end example
-The protocol accepts the following options:
+@var{options} contains a list of &-separated options of the form
+@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
+space) can be used to escape keys and values.
+
+Options can also can be specified via command line options (or in code via
+@code{AVOption}s).
+
+The list of supported options follows.
+
@table @option
@item listen
If set to any value, listen for an incoming connection. Outgoing connection is done by default.
diff --git a/libavformat/sctp.c b/libavformat/sctp.c
index 9d9e90097e..4122fbe312 100644
--- a/libavformat/sctp.c
+++ b/libavformat/sctp.c
@@ -185,7 +185,6 @@ static int sctp_open(URLContext *h, const char *uri, int flags)
int fd = -1;
SCTPContext *s = h->priv_data;
const char *p;
- char buf[256];
int ret;
char hostname[1024], proto[1024], path[1024];
char portstr[10];
@@ -201,10 +200,9 @@ static int sctp_open(URLContext *h, const char *uri, int flags)
p = strchr(uri, '?');
if (p) {
- if (av_find_info_tag(buf, sizeof(buf), "listen", p))
- s->listen = 1;
- if (av_find_info_tag(buf, sizeof(buf), "max_streams", p))
- s->max_streams = strtol(buf, NULL, 10);
+ ret = ff_parse_opts_from_query_string(s, p, 0);
+ if (ret < 0)
+ return ret;
}
hints.ai_family = AF_UNSPEC;
commit 49c6e6cc44f011ea43a3cab1b965510569bd229d
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Mon Aug 25 01:52:00 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Wed Oct 1 00:34:19 2025 +0200
avformat/tcp: use ff_parse_opts_from_query_string() to set URL parameters
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/doc/protocols.texi b/doc/protocols.texi
index b4b6c25579..a329f59fe3 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1913,7 +1913,11 @@ tcp://@var{hostname}:@var{port}[?@var{options}]
@end example
@var{options} contains a list of &-separated options of the form
-@var{key}=@var{val}.
+@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
+space) can be used to escape keys and values.
+
+Options can also can be specified via command line options (or in code via
+@code{AVOption}s).
The list of supported options follows.
diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index c286698d33..ce9f69a50b 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -25,6 +25,7 @@
#include "libavutil/opt.h"
#include "libavutil/time.h"
+#include "internal.h"
#include "network.h"
#include "os_support.h"
#include "url.h"
@@ -151,7 +152,6 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
int port, fd = -1;
TCPContext *s = h->priv_data;
const char *p;
- char buf[256];
int ret;
char hostname[1024],proto[1024],path[1024];
char portstr[10];
@@ -167,37 +167,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
}
p = strchr(uri, '?');
if (p) {
- if (av_find_info_tag(buf, sizeof(buf), "listen", p)) {
- char *endptr = NULL;
- s->listen = strtol(buf, &endptr, 10);
- /* assume if no digits were found it is a request to enable it */
- if (buf == endptr)
- s->listen = 1;
- }
- if (av_find_info_tag(buf, sizeof(buf), "local_port", p)) {
- av_freep(&s->local_port);
- s->local_port = av_strdup(buf);
- if (!s->local_port)
- return AVERROR(ENOMEM);
- }
- if (av_find_info_tag(buf, sizeof(buf), "local_addr", p)) {
- av_freep(&s->local_addr);
- s->local_addr = av_strdup(buf);
- if (!s->local_addr)
- return AVERROR(ENOMEM);
- }
- if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
- s->rw_timeout = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
- s->listen_timeout = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "tcp_nodelay", p)) {
- s->tcp_nodelay = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "tcp_keepalive", p)) {
- s->tcp_keepalive = strtol(buf, NULL, 10);
- }
+ int ret = ff_parse_opts_from_query_string(s, p, 1);
+ if (ret < 0)
+ return ret;
}
if (s->rw_timeout >= 0) {
s->open_timeout =
commit 7e58fff9d0b9b05f118917b5eb5704bb3514c6bd
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Mon Aug 25 01:51:15 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Wed Oct 1 00:34:19 2025 +0200
avformat/udp: use ff_parse_opts_from_query_string() to set URL parameters
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/doc/protocols.texi b/doc/protocols.texi
index 133574b4db..b4b6c25579 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -2114,7 +2114,12 @@ The required syntax for an UDP URL is:
udp://@var{hostname}:@var{port}[?@var{options}]
@end example
-@var{options} contains a list of &-separated options of the form @var{key}=@var{val}.
+@var{options} contains a list of &-separated options of the form
+@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
+space) can be used to escape keys and values.
+
+Options can also can be specified via command line options (or in code via
+@code{AVOption}s).
In case threading is enabled on the system, a circular buffer is used
to store the incoming data, which allows one to reduce loss of data due to
diff --git a/libavformat/udp.c b/libavformat/udp.c
index 839c301369..87a9d5d431 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -36,6 +36,7 @@
#include "libavutil/opt.h"
#include "libavutil/log.h"
#include "libavutil/time.h"
+#include "internal.h"
#include "network.h"
#include "os_support.h"
#include "url.h"
@@ -695,7 +696,6 @@ static int udp_open(URLContext *h, const char *uri, int flags)
UDPContext *s = h->priv_data;
int is_output;
const char *p;
- char buf[256];
struct sockaddr_storage my_addr;
socklen_t len;
int ret;
@@ -706,87 +706,11 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (s->buffer_size < 0)
s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_RX_BUF_SIZE;
- if (s->sources) {
- if ((ret = ff_ip_parse_sources(h, s->sources, &s->filters)) < 0)
- goto fail;
- }
-
- if (s->block) {
- if ((ret = ff_ip_parse_blocks(h, s->block, &s->filters)) < 0)
- goto fail;
- }
-
p = strchr(uri, '?');
if (p) {
- if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) {
- char *endptr = NULL;
- s->reuse_socket = strtol(buf, &endptr, 10);
- /* assume if no digits were found it is a request to enable it */
- if (buf == endptr)
- s->reuse_socket = 1;
- }
- if (av_find_info_tag(buf, sizeof(buf), "overrun_nonfatal", p)) {
- char *endptr = NULL;
- s->overrun_nonfatal = strtol(buf, &endptr, 10);
- /* assume if no digits were found it is a request to enable it */
- if (buf == endptr)
- s->overrun_nonfatal = 1;
- }
- if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
- s->ttl = strtol(buf, NULL, 10);
- if (s->ttl < 0 || s->ttl > 255) {
- av_log(h, AV_LOG_ERROR, "ttl(%d) should be in range [0,255]\n", s->ttl);
- ret = AVERROR(EINVAL);
- goto fail;
- }
- }
- if (av_find_info_tag(buf, sizeof(buf), "udplite_coverage", p)) {
- s->udplite_coverage = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
- s->local_port = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
- s->pkt_size = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
- s->buffer_size = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
- s->is_connected = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) {
- s->dscp = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "fifo_size", p)) {
- s->circular_buffer_size = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "bitrate", p)) {
- s->bitrate = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "burst_bits", p)) {
- s->burst_bits = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) {
- av_freep(&s->localaddr);
- s->localaddr = av_strdup(buf);
- if (!s->localaddr) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- }
- if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
- if ((ret = ff_ip_parse_sources(h, buf, &s->filters)) < 0)
- goto fail;
- }
- if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
- if ((ret = ff_ip_parse_blocks(h, buf, &s->filters)) < 0)
- goto fail;
- }
- if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p))
- s->timeout = strtol(buf, NULL, 10);
- if (is_output && av_find_info_tag(buf, sizeof(buf), "broadcast", p))
- s->is_broadcast = strtol(buf, NULL, 10);
+ ret = ff_parse_opts_from_query_string(s, p, 1);
+ if (ret < 0)
+ goto fail;
}
if (!HAVE_PTHREAD_CANCEL) {
int64_t optvals[] = {s->overrun_nonfatal, s->bitrate, s->circular_buffer_size};
@@ -798,6 +722,15 @@ static int udp_open(URLContext *h, const char *uri, int flags)
"on this build (pthread support is required)\n", optnames[i]);
}
}
+ if (s->sources) {
+ if ((ret = ff_ip_parse_sources(h, s->sources, &s->filters)) < 0)
+ goto fail;
+ }
+ if (s->block) {
+ if ((ret = ff_ip_parse_blocks(h, s->block, &s->filters)) < 0)
+ goto fail;
+ }
+
/* handling needed to support options picking from both AVOption and URL */
s->circular_buffer_size *= 188;
if (flags & AVIO_FLAG_WRITE) {
commit 2d06ed9308ebaa785d8b3389ad8da033b8839c89
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Mon Aug 25 01:50:13 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Wed Oct 1 00:34:19 2025 +0200
avformat/libsrt: use ff_parse_opts_from_query_string() to set URL parameters
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/doc/protocols.texi b/doc/protocols.texi
index cd0726cc7a..133574b4db 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1554,18 +1554,13 @@ srt://@var{hostname}:@var{port}[?@var{options}]
@end example
@var{options} contains a list of &-separated options of the form
-@var{key}=@var{val}.
-
-or
+@var{key}=@var{val}. Standard percent-encoding (and using the plus sign for
+space) can be used to escape keys and values.
-@example
-@var{options} srt://@var{hostname}:@var{port}
-@end example
+Options can also can be specified via command line options (or in code via
+@code{AVOption}s).
-@var{options} contains a list of '-@var{key} @var{val}'
-options.
-
-This protocol accepts the following options.
+The list of supported options follows.
@table @option
@item connect_timeout=@var{milliseconds}
diff --git a/libavformat/libsrt.c b/libavformat/libsrt.c
index 9e860abccd..ba04d9f782 100644
--- a/libavformat/libsrt.c
+++ b/libavformat/libsrt.c
@@ -386,8 +386,6 @@ static int libsrt_setup(URLContext *h, const char *uri, int flags)
struct addrinfo hints = { 0 }, *ai, *cur_ai;
int port, fd;
SRTContext *s = h->priv_data;
- const char *p;
- char buf[256];
int ret;
char hostname[1024],proto[1024],path[1024];
char portstr[10];
@@ -402,15 +400,6 @@ static int libsrt_setup(URLContext *h, const char *uri, int flags)
av_log(h, AV_LOG_ERROR, "Port missing in uri\n");
return AVERROR(EINVAL);
}
- p = strchr(uri, '?');
- if (p) {
- if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
- s->rw_timeout = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
- s->listen_timeout = strtoll(buf, NULL, 10);
- }
- }
if (s->rw_timeout >= 0) {
open_timeout = h->rw_timeout = s->rw_timeout;
}
@@ -534,7 +523,6 @@ static int libsrt_open(URLContext *h, const char *uri, int flags)
{
SRTContext *s = h->priv_data;
const char * p;
- char buf[1024];
int ret = 0;
if (srt_startup() < 0) {
@@ -544,133 +532,9 @@ static int libsrt_open(URLContext *h, const char *uri, int flags)
/* SRT options (srt/srt.h) */
p = strchr(uri, '?');
if (p) {
- if (av_find_info_tag(buf, sizeof(buf), "maxbw", p)) {
- s->maxbw = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "pbkeylen", p)) {
- s->pbkeylen = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "passphrase", p)) {
- av_freep(&s->passphrase);
- s->passphrase = ff_urldecode(buf, 1);
- if (!s->passphrase) {
- ret = AVERROR(ENOMEM);
- goto err;
- }
- }
-#if SRT_VERSION_VALUE >= 0x010302
- if (av_find_info_tag(buf, sizeof(buf), "enforced_encryption", p)) {
- s->enforced_encryption = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "kmrefreshrate", p)) {
- s->kmrefreshrate = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "kmpreannounce", p)) {
- s->kmpreannounce = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "snddropdelay", p)) {
- s->snddropdelay = strtoll(buf, NULL, 10);
- }
-#endif
- if (av_find_info_tag(buf, sizeof(buf), "mss", p)) {
- s->mss = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "ffs", p)) {
- s->ffs = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "ipttl", p)) {
- s->ipttl = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "iptos", p)) {
- s->iptos = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "inputbw", p)) {
- s->inputbw = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "oheadbw", p)) {
- s->oheadbw = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "latency", p)) {
- s->latency = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "tsbpddelay", p)) {
- s->latency = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "rcvlatency", p)) {
- s->rcvlatency = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "peerlatency", p)) {
- s->peerlatency = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "tlpktdrop", p)) {
- s->tlpktdrop = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "nakreport", p)) {
- s->nakreport = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "connect_timeout", p)) {
- s->connect_timeout = strtoll(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "payload_size", p) ||
- av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
- s->payload_size = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "mode", p)) {
- if (!strcmp(buf, "caller")) {
- s->mode = SRT_MODE_CALLER;
- } else if (!strcmp(buf, "listener")) {
- s->mode = SRT_MODE_LISTENER;
- } else if (!strcmp(buf, "rendezvous")) {
- s->mode = SRT_MODE_RENDEZVOUS;
- } else {
- ret = AVERROR(EINVAL);
- goto err;
- }
- }
- if (av_find_info_tag(buf, sizeof(buf), "sndbuf", p)) {
- s->sndbuf = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "rcvbuf", p)) {
- s->rcvbuf = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "lossmaxttl", p)) {
- s->lossmaxttl = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "minversion", p)) {
- s->minversion = strtol(buf, NULL, 0);
- }
- if (av_find_info_tag(buf, sizeof(buf), "streamid", p)) {
- av_freep(&s->streamid);
- s->streamid = ff_urldecode(buf, 1);
- if (!s->streamid) {
- ret = AVERROR(ENOMEM);
- goto err;
- }
- }
- if (av_find_info_tag(buf, sizeof(buf), "smoother", p)) {
- av_freep(&s->smoother);
- s->smoother = ff_urldecode(buf, 1);
- if(!s->smoother) {
- ret = AVERROR(ENOMEM);
- goto err;
- }
- }
- if (av_find_info_tag(buf, sizeof(buf), "messageapi", p)) {
- s->messageapi = strtol(buf, NULL, 10);
- }
- if (av_find_info_tag(buf, sizeof(buf), "transtype", p)) {
- if (!strcmp(buf, "live")) {
- s->transtype = SRTT_LIVE;
- } else if (!strcmp(buf, "file")) {
- s->transtype = SRTT_FILE;
- } else {
- ret = AVERROR(EINVAL);
- goto err;
- }
- }
- if (av_find_info_tag(buf, sizeof(buf), "linger", p)) {
- s->linger = strtol(buf, NULL, 10);
- }
+ ret = ff_parse_opts_from_query_string(s, p, 0);
+ if (ret < 0)
+ goto err;
}
ret = libsrt_setup(h, uri, flags);
if (ret < 0)
commit 70e0e3e2572447c559aac5179578be5a584e942b
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Mon Aug 25 00:54:29 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Wed Oct 1 00:34:18 2025 +0200
avformat/utils: add helper function to set opts from query string
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/libavformat/internal.h b/libavformat/internal.h
index 0dfbf02ca0..1a50ba07d3 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -649,4 +649,16 @@ int ff_bprint_get_frame_filename(struct AVBPrint *buf, const char *path, int64_t
*/
int ff_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp);
+/**
+ * Set a list of query string options on an object. Only the objects own
+ * options will be set.
+ *
+ * @param obj the object to set options on
+ * @param str the query string
+ * @param allow_unknown ignore unknown query string options. This can be OK if
+ * nested protocols are used.
+ * @return <0 on error
+ */
+int ff_parse_opts_from_query_string(void *obj, const char *str, int allow_unkown);
+
#endif /* AVFORMAT_INTERNAL_H */
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 3573aa918e..7a74e63d68 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -24,11 +24,14 @@
#include "config.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
#include "libavutil/dict.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
#include "libavutil/time.h"
#include "libavutil/time_internal.h"
@@ -41,6 +44,7 @@
#include "network.h"
#endif
#include "os_support.h"
+#include "urldecode.h"
/**
* @file
@@ -618,3 +622,65 @@ int ff_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestam
return AVERROR_EXTERNAL;
}
}
+
+static const AVOption* find_opt(void *obj, const char *name, size_t len)
+{
+ char decoded_name[128];
+
+ if (ff_urldecode_len(decoded_name, sizeof(decoded_name), name, len, 1) < 0)
+ return NULL;
+
+ return av_opt_find(obj, decoded_name, NULL, 0, 0);
+}
+
+int ff_parse_opts_from_query_string(void *obj, const char *str, int allow_unknown)
+{
+ const AVOption *opt;
+ char optval[512];
+ int ret;
+
+ if (*str == '?')
+ str++;
+ while (*str) {
+ size_t len = strcspn(str, "=&");
+ opt = find_opt(obj, str, len);
+ if (!opt) {
+ if (!allow_unknown) {
+ av_log(obj, AV_LOG_ERROR, "Query string option '%.*s' does not exist\n", (int)len, str);
+ return AVERROR_OPTION_NOT_FOUND;
+ }
+ av_log(obj, AV_LOG_VERBOSE, "Ignoring unknown query string option '%.*s'\n", (int)len, str);
+ }
+ str += len;
+ if (!opt) {
+ len = strcspn(str, "&");
+ str += len;
+ } else if (*str == '&' || *str == '\0') {
+ /* Check for bool options without value, e.g. "?verify".
+ * Unfortunately "listen" is a tri-state INT for some protocols so
+ * we also have to allow that for backward compatibility. */
+ if (opt->type != AV_OPT_TYPE_BOOL && strcmp(opt->name, "listen")) {
+ av_log(obj, AV_LOG_ERROR, "Non-bool query string option '%s' has no value\n", opt->name);
+ return AVERROR(EINVAL);
+ }
+ ret = av_opt_set_int(obj, opt->name, 1, 0);
+ if (ret < 0)
+ return ret;
+ } else {
+ av_assert2(*str == '=');
+ str++;
+ len = strcspn(str, "&");
+ if (ff_urldecode_len(optval, sizeof(optval), str, len, 1) < 0) {
+ av_log(obj, AV_LOG_ERROR, "Query string option '%s' value is too long\n", opt->name);
+ return AVERROR(EINVAL);
+ }
+ ret = av_opt_set(obj, opt->name, optval, 0);
+ if (ret < 0)
+ return ret;
+ str += len;
+ }
+ if (*str)
+ str++;
+ }
+ return 0;
+}
commit c5be4b70754d276e7370dd90e807e883c4bec627
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Tue Aug 26 23:03:40 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Tue Sep 30 23:48:14 2025 +0200
avformat: compile urldecode unconditionally
It will be used by the generic helper function to set options from URLs.
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 19ed1d4374..ed93458f03 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -28,6 +28,7 @@ OBJS = allformats.o \
sdp.o \
seek.o \
url.o \
+ urldecode.o \
utils.o \
version.o \
@@ -537,10 +538,8 @@ OBJS-$(CONFIG_RTP_MUXER) += rtp.o \
rtpenc_vp8.o \
rtpenc_vp9.o \
rtpenc_xiph.o
-OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o rtspdec.o httpauth.o \
- urldecode.o
-OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o httpauth.o \
- urldecode.o
+OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o rtspdec.o httpauth.o
+OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o httpauth.o
OBJS-$(CONFIG_S337M_DEMUXER) += s337m.o spdif.o
OBJS-$(CONFIG_SAMI_DEMUXER) += samidec.o subtitles.o
OBJS-$(CONFIG_SAP_DEMUXER) += sapdec.o
@@ -685,13 +684,13 @@ OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdigest.o rtmpdh.o
OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o
OBJS-$(CONFIG_FILE_PROTOCOL) += file.o
OBJS-$(CONFIG_FD_PROTOCOL) += file.o
-OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o urldecode.o
+OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o
OBJS-$(CONFIG_GOPHER_PROTOCOL) += gopher.o
OBJS-$(CONFIG_GOPHERS_PROTOCOL) += gopher.o
OBJS-$(CONFIG_HLS_PROTOCOL) += hlsproto.o
-OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o httpauth.o urldecode.o
-OBJS-$(CONFIG_HTTPPROXY_PROTOCOL) += http.o httpauth.o urldecode.o
-OBJS-$(CONFIG_HTTPS_PROTOCOL) += http.o httpauth.o urldecode.o
+OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o httpauth.o
+OBJS-$(CONFIG_HTTPPROXY_PROTOCOL) += http.o httpauth.o
+OBJS-$(CONFIG_HTTPS_PROTOCOL) += http.o httpauth.o
OBJS-$(CONFIG_ICECAST_PROTOCOL) += icecast.o
OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o
OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf_tags.o
@@ -725,7 +724,7 @@ OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o ip.o
OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o
# external library protocols
-OBJS-$(CONFIG_LIBAMQP_PROTOCOL) += libamqp.o urldecode.o
+OBJS-$(CONFIG_LIBAMQP_PROTOCOL) += libamqp.o
OBJS-$(CONFIG_LIBRIST_PROTOCOL) += librist.o
OBJS-$(CONFIG_LIBRTMP_PROTOCOL) += librtmp.o
OBJS-$(CONFIG_LIBRTMPE_PROTOCOL) += librtmp.o
@@ -733,7 +732,7 @@ OBJS-$(CONFIG_LIBRTMPS_PROTOCOL) += librtmp.o
OBJS-$(CONFIG_LIBRTMPT_PROTOCOL) += librtmp.o
OBJS-$(CONFIG_LIBRTMPTE_PROTOCOL) += librtmp.o
OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o
-OBJS-$(CONFIG_LIBSRT_PROTOCOL) += libsrt.o urldecode.o
+OBJS-$(CONFIG_LIBSRT_PROTOCOL) += libsrt.o
OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o
OBJS-$(CONFIG_LIBZMQ_PROTOCOL) += libzmq.o
commit 6f17053e6c75e5c44eaee9d4da0a4c80470274d0
Author: Marton Balint <cus(a)passwd.hu>
AuthorDate: Tue Aug 26 22:57:40 2025 +0200
Commit: Marton Balint <cus(a)passwd.hu>
CommitDate: Tue Sep 30 23:48:14 2025 +0200
avformat/urldecode: add ff_urldecode_len function
This will be used later to decode partial strings.
Signed-off-by: Marton Balint <cus(a)passwd.hu>
diff --git a/libavformat/urldecode.c b/libavformat/urldecode.c
index e7fa27b3fa..fdaa41784f 100644
--- a/libavformat/urldecode.c
+++ b/libavformat/urldecode.c
@@ -28,6 +28,8 @@
#include <string.h>
+#include "libavutil/error.h"
+#include "libavutil/macros.h"
#include "libavutil/mem.h"
#include "libavutil/avstring.h"
#include "urldecode.h"
@@ -93,3 +95,19 @@ char *ff_urldecode(const char *url, int decode_plus_sign)
return dest;
}
+
+int ff_urldecode_len(char *dest, size_t dest_len, const char *url, size_t url_max_len, int decode_plus_sign)
+{
+ size_t written_bytes;
+ size_t url_len = strlen(url);
+
+ url_len = FFMIN(url_len, url_max_len);
+
+ if (dest_len <= url_len)
+ return AVERROR(EINVAL);
+
+ written_bytes = urldecode(dest, url, url_len, decode_plus_sign);
+ dest[written_bytes] = '\0';
+
+ return written_bytes;
+}
diff --git a/libavformat/urldecode.h b/libavformat/urldecode.h
index 80b11c3428..246d9c9fda 100644
--- a/libavformat/urldecode.h
+++ b/libavformat/urldecode.h
@@ -19,6 +19,8 @@
#ifndef AVFORMAT_URLDECODE_H
#define AVFORMAT_URLDECODE_H
+#include <stddef.h>
+
/**
* Decodes an URL from its percent-encoded form back into normal
* representation. This function returns the decoded URL in a string.
@@ -33,4 +35,20 @@
*/
char *ff_urldecode(const char *url, int decode_plus_sign);
+/**
+ * Decodes an URL from its percent-encoded form back into normal
+ * representation. This function returns the decoded URL in a string.
+ * The URL to be decoded does not necessarily have to be encoded but
+ * in that case the original string is duplicated.
+ *
+ * @param dest the destination buffer.
+ * @param dest_len the maximum available space in the destination buffer.
+ * Must be bigger than FFMIN(strlen(url), url_max_len) to avoid
+ * an AVERROR(EINVAL) result
+ * @param url_max_len the maximum number of chars to read from url
+ * @param decode_plus_sign if nonzero plus sign is decoded to space
+ * @return the number of written bytes to dest excluding the zero terminator,
+ * negative on error
+ */
+int ff_urldecode_len(char *dest, size_t dest_len, const char *url, size_t url_max_len, int decode_plus_sign);
#endif /* AVFORMAT_URLDECODE_H */
-----------------------------------------------------------------------
Summary of changes:
doc/protocols.texi | 69 +++++++++++++++-------
libavformat/Makefile | 19 +++----
libavformat/internal.h | 12 ++++
libavformat/libsrt.c | 142 +---------------------------------------------
libavformat/rtpproto.c | 69 +++++-----------------
libavformat/sctp.c | 8 +--
libavformat/tcp.c | 36 ++----------
libavformat/tls.c | 46 ++-------------
libavformat/tls_mbedtls.c | 14 -----
libavformat/tls_openssl.c | 15 ++---
libavformat/udp.c | 93 +++++-------------------------
libavformat/urldecode.c | 18 ++++++
libavformat/urldecode.h | 18 ++++++
libavformat/utils.c | 66 +++++++++++++++++++++
14 files changed, 224 insertions(+), 401 deletions(-)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. 8cb1ff78ac avformat/dhav: Factorize some code in get_duration()
by ffmpeg-git@ffmpeg.org 30 Sep '25
by ffmpeg-git@ffmpeg.org 30 Sep '25
30 Sep '25
The branch, master has been updated
via 8cb1ff78ac62ff0f652b0cb06369ba50d5e946c6 (commit)
from b80f28fcbcedbf48b760921e85c5f2ae4f2f802a (commit)
- Log -----------------------------------------------------------------
commit 8cb1ff78ac62ff0f652b0cb06369ba50d5e946c6
Author: Michael Niedermayer <michael(a)niedermayer.cc>
AuthorDate: Sat Sep 20 01:56:20 2025 +0200
Commit: michaelni <michael(a)niedermayer.cc>
CommitDate: Tue Sep 30 21:13:56 2025 +0000
avformat/dhav: Factorize some code in get_duration()
Signed-off-by: Michael Niedermayer <michael(a)niedermayer.cc>
diff --git a/libavformat/dhav.c b/libavformat/dhav.c
index b3fa612ab3..614934dc68 100644
--- a/libavformat/dhav.c
+++ b/libavformat/dhav.c
@@ -242,7 +242,7 @@ static int64_t get_duration(AVFormatContext *s)
int64_t start_pos = avio_tell(s->pb);
int64_t pos = -1;
- int64_t start = 0, end = 0;
+ int64_t start = 0;
struct tm timeinfo;
uint8_t *buffer;
int64_t buffer_size;
@@ -250,6 +250,7 @@ static int64_t get_duration(AVFormatContext *s)
int64_t offset;
unsigned date;
int64_t size = avio_size(s->pb);
+ int64_t ret = 0;
if (start_pos + 20 > size)
return 0;
@@ -284,17 +285,12 @@ static int64_t get_duration(AVFormatContext *s)
date = AV_RL32(buffer + (pos - buffer_pos) + 16);
get_timeinfo(date, &timeinfo);
- end = av_timegm(&timeinfo) * 1000LL;
-
- av_freep(&buffer);
- avio_seek(s->pb, start_pos, SEEK_SET);
-
- return end - start;
+ ret = av_timegm(&timeinfo) * 1000LL - start;
fail:
av_freep(&buffer);
avio_seek(s->pb, start_pos, SEEK_SET);
- return 0;
+ return ret;
}
static int dhav_read_header(AVFormatContext *s)
-----------------------------------------------------------------------
Summary of changes:
libavformat/dhav.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. b80f28fcbc avfilter/vf_libplacebo: introduce `fit_sense` option
by ffmpeg-git@ffmpeg.org 30 Sep '25
by ffmpeg-git@ffmpeg.org 30 Sep '25
30 Sep '25
The branch, master has been updated
via b80f28fcbcedbf48b760921e85c5f2ae4f2f802a (commit)
via 12d696cff4eeaccb8610c02056fd5f7342d51ac3 (commit)
via 6ad839ff2e1ac36b6ab9ad6f687208a57731df7e (commit)
from 74115b017c3038b717162bb56346afb4ad937be3 (commit)
- Log -----------------------------------------------------------------
commit b80f28fcbcedbf48b760921e85c5f2ae4f2f802a
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Tue Sep 23 20:49:07 2025 +0200
Commit: Niklas Haas <ffmpeg(a)haasn.dev>
CommitDate: Tue Sep 30 15:39:39 2025 +0000
avfilter/vf_libplacebo: introduce `fit_sense` option
This allows choosing whether the `fit_mode` merely controls the placement
of the image within the output resolution, or whether the output resolution
is also adjusted according to the given `fit_mode`.
diff --git a/doc/filters.texi b/doc/filters.texi
index bb96e75d2a..262e7ad009 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -16449,7 +16449,8 @@ will be performed.
@item force_original_aspect_ratio
@item force_divisible_by
-Work the same as the identical @ref{scale} filter options.
+Work the same as the identical @ref{scale} filter options. Note that
+@option{force_divisible_by} also works with @code{fit_sense=constraint}.
@item reset_sar
If enabled, output frames will always have a pixel aspect ratio of 1:1. If
@@ -16503,6 +16504,22 @@ to either @code{contain} or @code{none}, depending on whether the input is
larger than the output or not.
@end table
+@item fit_sense
+When @option{fit_mode} is in use, this option controls how the fit strategy
+is applied against the specified output resolution. Mutually exclusive with
+@option{force_original_aspect_ratio}. Valid values are:
+
+@table @samp
+@item target
+The computed output resolution is taken as the exact size of the output frame.
+This is the default behavior.
+
+@item constraint
+The computed output resolution is a size reference against which the fit mode
+is applied, enlarging or decreasing the true frame size as needed to fit the
+content.
+@end table
+
@item fillcolor
Set the color used to fill the output area not covered by the output image, for
example as a result of @option{normalize_sar}. For the general syntax of this
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index 2cf58b1f8d..2b3738c8e0 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -161,6 +161,12 @@ enum fit_mode {
FIT_MODE_NB,
};
+enum fit_sense {
+ FIT_TARGET,
+ FIT_CONSTRAINT,
+ FIT_SENSE_NB,
+};
+
typedef struct LibplaceboContext {
/* lavfi vulkan*/
FFVulkanContext vkctx;
@@ -206,6 +212,7 @@ typedef struct LibplaceboContext {
int reset_sar;
int normalize_sar;
int fit_mode;
+ int fit_sense;
int apply_filmgrain;
int apply_dovi;
int colorspace;
@@ -1452,11 +1459,24 @@ static int libplacebo_config_output(AVFilterLink *outlink)
double sar_in = inlink->sample_aspect_ratio.num ?
av_q2d(inlink->sample_aspect_ratio) : 1.0;
+ int force_oar = s->force_original_aspect_ratio;
+ if (!force_oar && s->fit_sense == FIT_CONSTRAINT) {
+ if (s->fit_mode == FIT_CONTAIN || s->fit_mode == FIT_SCALE_DOWN) {
+ force_oar = SCALE_FORCE_OAR_DECREASE;
+ } else if (s->fit_mode == FIT_COVER) {
+ force_oar = SCALE_FORCE_OAR_INCREASE;
+ }
+ }
+
ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
- s->force_original_aspect_ratio,
- s->force_divisible_by,
+ force_oar, s->force_divisible_by,
s->reset_sar ? sar_in : 1.0);
+ if (s->fit_mode == FIT_SCALE_DOWN && s->fit_sense == FIT_CONSTRAINT) {
+ int w_adj = s->reset_sar ? sar_in * inlink->w : inlink->w;
+ outlink->w = FFMIN(outlink->w, w_adj);
+ outlink->h = FFMIN(outlink->h, inlink->h);
+ }
if (s->nb_inputs > 1 && !s->disable_fbos) {
/* Create a separate renderer and composition texture */
@@ -1586,6 +1606,9 @@ static const AVOption libplacebo_options[] = {
{ "none", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" },
{ "place", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" },
{ "scale_down", "Downscale only if larger, padding to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_SCALE_DOWN }, 0, 0, STATIC, .unit = "fit_mode" },
+ { "fit_sense", "Output size strategy (for the base layer only)", OFFSET(fit_sense), AV_OPT_TYPE_INT, {.i64 = FIT_TARGET }, 0, FIT_SENSE_NB - 1, STATIC, .unit = "fit_sense" },
+ { "target", "Computed resolution is the exact output size", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_TARGET }, 0, 0, STATIC, .unit = "fit_sense" },
+ { "constraint", "Computed resolution constrains the output size", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_CONSTRAINT }, 0, 0, STATIC, .unit = "fit_sense" },
{ "fillcolor", "Background fill color", OFFSET(fillcolor), AV_OPT_TYPE_COLOR, {.str = "black@0"}, .flags = DYNAMIC },
{ "corner_rounding", "Corner rounding radius", OFFSET(corner_rounding), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 1.0, .flags = DYNAMIC },
{ "lut", "Path to custom LUT file to apply", OFFSET(lut_filename), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = STATIC },
commit 12d696cff4eeaccb8610c02056fd5f7342d51ac3
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Mon Sep 8 18:28:19 2025 +0200
Commit: Niklas Haas <ffmpeg(a)haasn.dev>
CommitDate: Tue Sep 30 15:39:39 2025 +0000
avfilter/vf_libplacebo: introduce `fit_mode` option
The semantics of these keywords are well-defined by the CSS 'object-fit'
property. This is arguably more user-friendly and less obtuse than the
existing `normalize_sar` and `pad_crop_ratio` options. Additionally, this
comes with two new (useful) behaviors, `none` and `scale_down`, neither of
which map elegantly to the existing options.
One additional benefit of this option is that, unlike `normalize_sar`, it
does *not* also imply `reset_sar`; meaning that users can now choose to
have an anamorphic base layer and still have the overlay images scaled to fit
on top of it according to the chosen strategy.
See-Also: https://drafts.csswg.org/css-images/#the-object-fit
diff --git a/doc/filters.texi b/doc/filters.texi
index 8224574220..bb96e75d2a 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -16459,7 +16459,7 @@ e.g. anamorphic video sources, are forwarded to the output pixel aspect ratio.
@item normalize_sar
Like @option{reset_sar}, but instead of stretching the video content to fill
the new output aspect ratio, the content is instead padded or cropped as
-necessary.
+necessary. Mutually exclusive with @option{fit_mode}. Disabled by default.
@item pad_crop_ratio
Specifies a ratio (between @code{0.0} and @code{1.0}) between padding and
@@ -16469,6 +16469,40 @@ content with black borders, while a value of @code{1.0} always crops off parts
of the content. Intermediate values are possible, leading to a mix of the two
approaches.
+@item fit_mode
+Specify the content fit strategy according to a list of predefined modes.
+Determines how the input image is to be placed inside the destination crop
+rectangle (as defined by @code{pos_x/y} and @code{pos_w/h}). The names and
+their implementations are taken from the CSS 'object-fit' property. Note that
+this option is mutually exclusive with @option{normalize_sar}. Defaults to
+@code{fill}. Valid values are:
+
+@table @samp
+@item fill
+Stretch the input to the output rectangle, ignoring aspect ratio mismatches.
+Note that unless @option{reset_sar} is also enabled, the output will still
+have the correct pixel aspect ratio tagged.
+
+@item contain
+Scale the input to fit inside the output, preserving aspect ratio by padding.
+Equivalent to @option{normalize_sar} with @option{pad_crop_ratio} set to
+(a)code{0.0}.
+
+@item cover
+Scale the input to fill the output, preserving aspect ratio by cropping.
+Equivalent to @option{normalize_sar} with @option{pad_crop_ratio} set to
+(a)code{1.0}.
+
+@item none, place
+Don't scale the input. The input will be placed inside the output rectangle at
+its natural size; which may result in additional padding or cropping.
+
+@item scale_down
+Scale the input down as much as needed to fit inside the output. Equivalent
+to either @code{contain} or @code{none}, depending on whether the input is
+larger than the output or not.
+@end table
+
@item fillcolor
Set the color used to fill the output area not covered by the output image, for
example as a result of @option{normalize_sar}. For the general syntax of this
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index 1454f364e4..2cf58b1f8d 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -152,6 +152,15 @@ typedef struct LibplaceboInput {
int status;
} LibplaceboInput;
+enum fit_mode {
+ FIT_FILL,
+ FIT_CONTAIN,
+ FIT_COVER,
+ FIT_NONE,
+ FIT_SCALE_DOWN,
+ FIT_MODE_NB,
+};
+
typedef struct LibplaceboContext {
/* lavfi vulkan*/
FFVulkanContext vkctx;
@@ -196,6 +205,7 @@ typedef struct LibplaceboContext {
int force_divisible_by;
int reset_sar;
int normalize_sar;
+ int fit_mode;
int apply_filmgrain;
int apply_dovi;
int colorspace;
@@ -543,6 +553,11 @@ static int libplacebo_init(AVFilterContext *avctx)
LibplaceboContext *s = avctx->priv;
const AVVulkanDeviceContext *vkhwctx = NULL;
+ if (s->normalize_sar && s->fit_mode != FIT_FILL) {
+ av_log(avctx, AV_LOG_WARNING, "normalize_sar has no effect when using "
+ "a fit mode other than 'fill'\n");
+ }
+
/* Create libplacebo log context */
s->log = pl_log_create(PL_API_VER, pl_log_params(
.log_level = get_log_level(),
@@ -841,6 +856,7 @@ static void update_crops(AVFilterContext *ctx, LibplaceboInput *in,
{
FilterLink *outl = ff_filter_link(ctx->outputs[0]);
LibplaceboContext *s = ctx->priv;
+ const AVFilterLink *outlink = ctx->outputs[0];
const AVFilterLink *inlink = ctx->inputs[in->idx];
const AVFrame *ref = ref_frame(&in->mix);
@@ -900,10 +916,33 @@ static void update_crops(AVFilterContext *ctx, LibplaceboInput *in,
target->crop.y0 = av_expr_eval(s->pos_y_pexpr, s->var_values, NULL);
target->crop.x1 = target->crop.x0 + s->var_values[VAR_POS_W];
target->crop.y1 = target->crop.y0 + s->var_values[VAR_POS_H];
- if (s->normalize_sar) {
- float aspect = pl_rect2df_aspect(&image->crop);
- aspect *= av_q2d(inlink->sample_aspect_ratio);
- pl_rect2df_aspect_set(&target->crop, aspect, s->pad_crop_ratio);
+
+ /* Effective visual crop */
+ const float w_adj = av_q2d(inlink->sample_aspect_ratio) /
+ av_q2d(outlink->sample_aspect_ratio);
+
+ pl_rect2df fixed = image->crop;
+ pl_rect2df_stretch(&fixed, w_adj, 1.0);
+
+ switch (s->fit_mode) {
+ case FIT_FILL:
+ if (s->normalize_sar)
+ pl_rect2df_aspect_copy(&target->crop, &fixed, s->pad_crop_ratio);
+ break;
+ case FIT_CONTAIN:
+ pl_rect2df_aspect_copy(&target->crop, &fixed, 0.0);
+ break;
+ case FIT_COVER:
+ pl_rect2df_aspect_copy(&target->crop, &fixed, 1.0);
+ break;
+ case FIT_NONE: {
+ const float sx = fabsf(pl_rect_w(fixed)) / pl_rect_w(target->crop);
+ const float sy = fabsf(pl_rect_h(fixed)) / pl_rect_h(target->crop);
+ pl_rect2df_stretch(&target->crop, sx, sy);
+ break;
+ }
+ case FIT_SCALE_DOWN:
+ pl_rect2df_aspect_fit(&target->crop, &fixed, 0.0);
}
}
}
@@ -1446,7 +1485,7 @@ static int libplacebo_config_output(AVFilterLink *outlink)
if (s->reset_sar) {
/* SAR is normalized, or we have multiple inputs, set out to 1:1 */
outlink->sample_aspect_ratio = (AVRational){ 1, 1 };
- } else if (inlink->sample_aspect_ratio.num) {
+ } else if (inlink->sample_aspect_ratio.num && s->fit_mode == FIT_FILL) {
/* This is consistent with other scale_* filters, which only
* set the outlink SAR to be equal to the scale SAR iff the input SAR
* was set to something nonzero */
@@ -1540,6 +1579,13 @@ static const AVOption libplacebo_options[] = {
{ "reset_sar", "force SAR normalization to 1:1 by adjusting pos_x/y/w/h", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, STATIC },
{ "normalize_sar", "like reset_sar, but pad/crop instead of stretching the video", OFFSET(normalize_sar), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, STATIC },
{ "pad_crop_ratio", "ratio between padding and cropping when normalizing SAR (0=pad, 1=crop)", OFFSET(pad_crop_ratio), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, 1.0, DYNAMIC },
+ { "fit_mode", "Content fit strategy for placing input layers in the output", OFFSET(fit_mode), AV_OPT_TYPE_INT, {.i64 = FIT_FILL }, 0, FIT_MODE_NB - 1, STATIC, .unit = "fit_mode" },
+ { "fill", "Stretch content, ignoring aspect ratio", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_FILL }, 0, 0, STATIC, .unit = "fit_mode" },
+ { "contain", "Stretch content, padding to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_CONTAIN }, 0, 0, STATIC, .unit = "fit_mode" },
+ { "cover", "Stretch content, cropping to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_COVER }, 0, 0, STATIC, .unit = "fit_mode" },
+ { "none", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" },
+ { "place", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" },
+ { "scale_down", "Downscale only if larger, padding to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_SCALE_DOWN }, 0, 0, STATIC, .unit = "fit_mode" },
{ "fillcolor", "Background fill color", OFFSET(fillcolor), AV_OPT_TYPE_COLOR, {.str = "black@0"}, .flags = DYNAMIC },
{ "corner_rounding", "Corner rounding radius", OFFSET(corner_rounding), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 1.0, .flags = DYNAMIC },
{ "lut", "Path to custom LUT file to apply", OFFSET(lut_filename), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = STATIC },
commit 6ad839ff2e1ac36b6ab9ad6f687208a57731df7e
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Tue Sep 23 16:17:12 2025 +0200
Commit: Niklas Haas <ffmpeg(a)haasn.dev>
CommitDate: Tue Sep 30 15:39:39 2025 +0000
avfilter/vf_scale_*: add enum names for force_oar magic values
diff --git a/libavfilter/scale_eval.c b/libavfilter/scale_eval.c
index 53f5e22b0e..ad65610992 100644
--- a/libavfilter/scale_eval.c
+++ b/libavfilter/scale_eval.c
@@ -148,14 +148,14 @@ int ff_scale_adjust_dimensions(AVFilterLink *inlink,
/* Note that force_original_aspect_ratio may overwrite the previous set
* dimensions so that it is not divisible by the set factors anymore
* unless force_divisible_by is defined as well */
- if (force_original_aspect_ratio) {
+ if (force_original_aspect_ratio != SCALE_FORCE_OAR_DISABLE) {
// Including force_divisible_by here rounds to the nearest multiple of it.
int64_t tmp_w = av_rescale(h, inlink->w * w_adj, inlink->h * (int64_t)force_divisible_by)
* force_divisible_by;
int64_t tmp_h = av_rescale(w, inlink->h, inlink->w * w_adj * (int64_t)force_divisible_by)
* force_divisible_by;
- if (force_original_aspect_ratio == 1) {
+ if (force_original_aspect_ratio == SCALE_FORCE_OAR_DECREASE) {
w = FFMIN(tmp_w, w);
h = FFMIN(tmp_h, h);
if (force_divisible_by > 1) {
@@ -163,7 +163,7 @@ int ff_scale_adjust_dimensions(AVFilterLink *inlink,
w = w / force_divisible_by * force_divisible_by;
h = h / force_divisible_by * force_divisible_by;
}
- } else {
+ } else { // SCALE_FORCE_OAR_INCREASE
w = FFMAX(tmp_w, w);
h = FFMAX(tmp_h, h);
if (force_divisible_by > 1) {
diff --git a/libavfilter/scale_eval.h b/libavfilter/scale_eval.h
index 6cab623e1c..067703df21 100644
--- a/libavfilter/scale_eval.h
+++ b/libavfilter/scale_eval.h
@@ -21,6 +21,13 @@
#include "avfilter.h"
+enum {
+ SCALE_FORCE_OAR_DISABLE,
+ SCALE_FORCE_OAR_DECREASE,
+ SCALE_FORCE_OAR_INCREASE,
+ SCALE_FORCE_OAR_NB,
+};
+
/**
* Parse and evaluate string expressions for width and height. Upon success,
* ff_scale_adjust_dimensions must be called with evaluated width and height
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index 80d3b273bb..1454f364e4 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -1532,10 +1532,10 @@ static const AVOption libplacebo_options[] = {
{ "pos_w", "Output video placement w", OFFSET(pos_w_expr), AV_OPT_TYPE_STRING, {.str = "ow"}, .flags = DYNAMIC },
{ "pos_h", "Output video placement h", OFFSET(pos_h_expr), AV_OPT_TYPE_STRING, {.str = "oh"}, .flags = DYNAMIC },
{ "format", "Output video format", OFFSET(out_format_string), AV_OPT_TYPE_STRING, .flags = STATIC },
- { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, STATIC, .unit = "force_oar" },
- { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, STATIC, .unit = "force_oar" },
- { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, STATIC, .unit = "force_oar" },
- { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, STATIC, .unit = "force_oar" },
+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, SCALE_FORCE_OAR_NB-1, STATIC, .unit = "force_oar" },
+ { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, STATIC, .unit = "force_oar" },
+ { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, STATIC, .unit = "force_oar" },
+ { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, STATIC, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, STATIC },
{ "reset_sar", "force SAR normalization to 1:1 by adjusting pos_x/y/w/h", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, STATIC },
{ "normalize_sar", "like reset_sar, but pad/crop instead of stretching the video", OFFSET(normalize_sar), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, STATIC },
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 1ef1de8419..61d3ee0a0f 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -1148,10 +1148,10 @@ static const AVOption scale_options[] = {
{ "in_h_chr_pos", "input horizontal chroma position in luma grid/256", OFFSET(in_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
{ "out_v_chr_pos", "output vertical chroma position in luma grid/256" , OFFSET(out_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
{ "out_h_chr_pos", "output horizontal chroma position in luma grid/256", OFFSET(out_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
- { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, .unit = "force_oar" },
- { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, .unit = "force_oar" },
- { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
- { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, SCALE_FORCE_OAR_NB-1, FLAGS, .unit = "force_oar" },
+ { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, FLAGS, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
{ "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
{ "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c
index 44eef207ca..88a6e20610 100644
--- a/libavfilter/vf_scale_cuda.c
+++ b/libavfilter/vf_scale_cuda.c
@@ -621,10 +621,10 @@ static const AVOption options[] = {
{ "format", "Output video pixel format", OFFSET(format), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, INT_MIN, INT_MAX, .flags=FLAGS },
{ "passthrough", "Do not process frames at all if parameters match", OFFSET(passthrough), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
{ "param", "Algorithm-Specific parameter", OFFSET(param), AV_OPT_TYPE_FLOAT, { .dbl = SCALE_CUDA_PARAM_DEFAULT }, -FLT_MAX, FLT_MAX, FLAGS },
- { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, FLAGS, .unit = "force_oar" },
- { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, .unit = "force_oar" },
- { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
- { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, SCALE_FORCE_OAR_NB-1, FLAGS, .unit = "force_oar" },
+ { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, FLAGS, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
{ "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
{ NULL },
diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
index 0529db3a29..8e9113521c 100644
--- a/libavfilter/vf_scale_npp.c
+++ b/libavfilter/vf_scale_npp.c
@@ -978,10 +978,10 @@ static const AVOption options[] = {
{ "cubic2p_b05c03", "2-parameter cubic (B=1/2, C=3/10)", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_CUBIC2P_B05C03 }, 0, 0, FLAGS, .unit = "interp_algo" },
{ "super", "supersampling", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_SUPER }, 0, 0, FLAGS, .unit = "interp_algo" },
{ "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_LANCZOS }, 0, 0, FLAGS, .unit = "interp_algo" },
- { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, FLAGS, .unit = "force_oar" },
- { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, .unit = "force_oar" },
- { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
- { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, SCALE_FORCE_OAR_NB-1, FLAGS, .unit = "force_oar" },
+ { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, FLAGS, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
{ "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
{ "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, { .i64 = EVAL_MODE_INIT }, 0, EVAL_MODE_NB-1, FLAGS, .unit = "eval" },
diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c
index 547142d425..1ba925afa5 100644
--- a/libavfilter/vf_scale_vaapi.c
+++ b/libavfilter/vf_scale_vaapi.c
@@ -277,10 +277,10 @@ static const AVOption scale_vaapi_options[] = {
{ "out_chroma_location", "Output chroma sample location",
OFFSET(chroma_location_string), AV_OPT_TYPE_STRING,
{ .str = NULL }, .flags = FLAGS },
- { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, .unit = "force_oar" },
- { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, .unit = "force_oar" },
- { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
- { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, SCALE_FORCE_OAR_NB-1, FLAGS, .unit = "force_oar" },
+ { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, FLAGS, .unit = "force_oar" },
+ { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, FLAGS, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
{ "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
diff --git a/libavfilter/vf_scale_vt.c b/libavfilter/vf_scale_vt.c
index c024717bc2..3d4ba44dc6 100644
--- a/libavfilter/vf_scale_vt.c
+++ b/libavfilter/vf_scale_vt.c
@@ -248,7 +248,8 @@ static int scale_vt_config_output(AVFilterLink *outlink)
if (err < 0)
return err;
- ff_scale_adjust_dimensions(inlink, &s->output_width, &s->output_height, 0, 1, 1.f);
+ ff_scale_adjust_dimensions(inlink, &s->output_width, &s->output_height,
+ SCALE_FORCE_OAR_DISABLE, 1, 1.f);
outlink->w = s->output_width;
outlink->h = s->output_height;
diff --git a/libavfilter/vf_scale_vulkan.c b/libavfilter/vf_scale_vulkan.c
index c23cfe262f..f8e069f4a4 100644
--- a/libavfilter/vf_scale_vulkan.c
+++ b/libavfilter/vf_scale_vulkan.c
@@ -389,7 +389,8 @@ static int scale_vulkan_config_output(AVFilterLink *outlink)
if (err < 0)
return err;
- ff_scale_adjust_dimensions(inlink, &vkctx->output_width, &vkctx->output_height, 0, 1, 1.f);
+ ff_scale_adjust_dimensions(inlink, &vkctx->output_width, &vkctx->output_height,
+ SCALE_FORCE_OAR_DISABLE, 1, 1.f);
outlink->w = vkctx->output_width;
outlink->h = vkctx->output_height;
diff --git a/libavfilter/vf_vpp_amf.c b/libavfilter/vf_vpp_amf.c
index 92923a4757..78815551be 100644
--- a/libavfilter/vf_vpp_amf.c
+++ b/libavfilter/vf_vpp_amf.c
@@ -216,10 +216,10 @@ static const AVOption vpp_amf_options[] = {
{ "smpte428", "SMPTE428", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE428 }, 0, 0, FLAGS, "trc" },
{ "arib-std-b67", "ARIB_STD_B67", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_COLOR_TRANSFER_CHARACTERISTIC_ARIB_STD_B67 }, 0, 0, FLAGS, "trc" },
- { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, "force_oar" },
- { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" },
- { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" },
- { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" },
+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, SCALE_FORCE_OAR_NB-1, FLAGS, "force_oar" },
+ { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, FLAGS, "force_oar" },
+ { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, FLAGS, "force_oar" },
+ { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, FLAGS, "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
{ "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
-----------------------------------------------------------------------
Summary of changes:
doc/filters.texi | 55 +++++++++++++++++++++++++-
libavfilter/scale_eval.c | 6 +--
libavfilter/scale_eval.h | 7 ++++
libavfilter/vf_libplacebo.c | 91 +++++++++++++++++++++++++++++++++++++------
libavfilter/vf_scale.c | 8 ++--
libavfilter/vf_scale_cuda.c | 8 ++--
libavfilter/vf_scale_npp.c | 8 ++--
libavfilter/vf_scale_vaapi.c | 8 ++--
libavfilter/vf_scale_vt.c | 3 +-
libavfilter/vf_scale_vulkan.c | 3 +-
libavfilter/vf_vpp_amf.c | 8 ++--
11 files changed, 167 insertions(+), 38 deletions(-)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. 74115b017c doc: indicate libmpeghdec is non-free
by ffmpeg-git@ffmpeg.org 30 Sep '25
by ffmpeg-git@ffmpeg.org 30 Sep '25
30 Sep '25
The branch, master has been updated
via 74115b017c3038b717162bb56346afb4ad937be3 (commit)
from fd1fd5850de4f3beb240422b67889bb776b26c77 (commit)
- Log -----------------------------------------------------------------
commit 74115b017c3038b717162bb56346afb4ad937be3
Author: Gyan Doshi <ffmpeg(a)gyani.pro>
AuthorDate: Tue Sep 30 14:34:18 2025 +0530
Commit: Gyan Doshi <gyan(a)gyan.dev>
CommitDate: Tue Sep 30 11:55:02 2025 +0000
doc: indicate libmpeghdec is non-free
diff --git a/doc/decoders.texi b/doc/decoders.texi
index 9248e2283a..1db297f42f 100644
--- a/doc/decoders.texi
+++ b/doc/decoders.texi
@@ -353,7 +353,7 @@ libmpeghdec decoder wrapper.
libmpeghdec allows libmpeghdec to decode the MPEG-H 3D audio codec.
Requires the presence of the libmpeghdec headers and library during
configuration. You need to explicitly configure the build with
-@code{--enable-libmpeghdec}.
+@code{--enable-libmpeghdec --enable-nonfree}.
@section libopencore-amrnb
diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index 9608ce219a..98e35c0e8e 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -256,7 +256,7 @@ FFmpeg can make use of the Fraunhofer MPEG-H decoder library for MPEG-H 3DA deco
Go to @url{https://github.com/Fraunhofer-IIS/mpeghdec} and follow the
instructions for installing the library.
-Then pass @code{--enable-libmpeghdec} to configure to enable it.
+Then pass @code{--enable-libmpeghdec --enable-nonfree} to configure to enable it.
@subsection LC3 library
-----------------------------------------------------------------------
Summary of changes:
doc/decoders.texi | 2 +-
doc/general_contents.texi | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. fd1fd5850d fftools/ffmpeg_sched: unchoke upstream nodes on recv-closed filter inputs
by ffmpeg-git@ffmpeg.org 30 Sep '25
by ffmpeg-git@ffmpeg.org 30 Sep '25
30 Sep '25
The branch, master has been updated
via fd1fd5850de4f3beb240422b67889bb776b26c77 (commit)
via d43fd5b3321cc1ece25835e2b44936880ee05328 (commit)
via 56d9ca69d7f229dccee6ad47c67a37f558196fb7 (commit)
via 9d0b88feb17dabfebcb10b801045c1285fa5e4bc (commit)
via 59a847a23718a87a2bd1e2eae893d9784ed34b0f (commit)
via 5f4cbb5617ba52fb0b5bce36eb36e4cd7bdaec70 (commit)
via 23f1f094f854bdeaae4225c1876fd2b985e977f4 (commit)
via fd4b5b24cedac1f7bae6792cbe4216f3e30a2cae (commit)
via 15407cf90bb4fd9f47f85f078e5689b2593ccbc3 (commit)
from 1608aa38a2ca9bd49debc5577ee38e2726303eda (commit)
- Log -----------------------------------------------------------------
commit fd1fd5850de4f3beb240422b67889bb776b26c77
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Mon Sep 8 19:11:29 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/ffmpeg_sched: unchoke upstream nodes on recv-closed filter inputs
This allows upstream filters to observe EOF on their corresponding outputs
and terminate early, which is particularly useful for decoders and demuxers
that may then gracefully release their resources.
Prevents "leaking" memory for previously used, but now unused, filter inputs.
diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c
index dbe337ca16..d08f4a061d 100644
--- a/fftools/ffmpeg_sched.c
+++ b/fftools/ffmpeg_sched.c
@@ -1368,6 +1368,18 @@ static void schedule_update_locked(Scheduler *sch)
}
}
+ // also unchoke any sources feeding into closed filter graph inputs, so
+ // that they can observe the downstream EOF
+ for (unsigned i = 0; i < sch->nb_filters; i++) {
+ SchFilterGraph *fg = &sch->filters[i];
+
+ for (unsigned j = 0; j < fg->nb_inputs; j++) {
+ SchFilterIn *fi = &fg->inputs[j];
+ if (fi->receive_finished && !fi->send_finished)
+ unchoke_for_stream(sch, fi->src);
+ }
+ }
+
// make sure to unchoke at least one source, if still available
for (unsigned type = 0; !have_unchoked && type < 2; type++)
for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) {
@@ -2478,6 +2490,8 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx)
av_assert0(in_idx < fg->nb_inputs);
fi = &fg->inputs[in_idx];
+ pthread_mutex_lock(&sch->schedule_lock);
+
if (!fi->receive_finished) {
fi->receive_finished = 1;
tq_receive_finish(fg->queue, in_idx);
@@ -2485,7 +2499,11 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx)
// close the control stream when all actual inputs are done
if (++fg->nb_inputs_finished_receive == fg->nb_inputs)
tq_receive_finish(fg->queue, fg->nb_inputs);
+
+ schedule_update_locked(sch);
}
+
+ pthread_mutex_unlock(&sch->schedule_lock);
}
int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame *frame)
commit d43fd5b3321cc1ece25835e2b44936880ee05328
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Tue Sep 9 13:10:53 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/ffmpeg_sched: close stream when sch_filter_send receives EOF
THis is currently done by sch_demux_send() (via demux_stream_send_to_dst()),
sch_enc_send() (via enc_send_to_dst()), and sch_dec_send() (via
dec_send_to_dst()), but not by sch_filter_send().
Implement the same queue-closing logic for them. The main benefit here is that
this will allow them to mark downstream inputs as send-done (in addition
to received-done), which is useful for a following commit.
diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c
index 589f5360f2..dbe337ca16 100644
--- a/fftools/ffmpeg_sched.c
+++ b/fftools/ffmpeg_sched.c
@@ -2492,6 +2492,7 @@ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame *
{
SchFilterGraph *fg;
SchedulerNode dst;
+ int ret;
av_assert0(fg_idx < sch->nb_filters);
fg = &sch->filters[fg_idx];
@@ -2499,9 +2500,16 @@ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame *
av_assert0(out_idx < fg->nb_outputs);
dst = fg->outputs[out_idx].dst;
- return (dst.type == SCH_NODE_TYPE_ENC) ?
- send_to_enc (sch, &sch->enc[dst.idx], frame) :
- send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, frame);
+ if (dst.type == SCH_NODE_TYPE_ENC) {
+ ret = send_to_enc(sch, &sch->enc[dst.idx], frame);
+ if (ret == AVERROR_EOF)
+ send_to_enc(sch, &sch->enc[dst.idx], NULL);
+ } else {
+ ret = send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, frame);
+ if (ret == AVERROR_EOF)
+ send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, NULL);
+ }
+ return ret;
}
static int filter_done(Scheduler *sch, unsigned fg_idx)
commit 56d9ca69d7f229dccee6ad47c67a37f558196fb7
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Mon Sep 8 14:00:53 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/ffmpeg_dec: free decoder ctx after EOF
The codec context is no longer used after the decoder thread exits, but
still idly sticks around until program exit, wasting memory.
diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 521bd657f3..66c58c1c3c 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -1018,6 +1018,7 @@ static int decoder_thread(void *arg)
finish:
dec_thread_uninit(&dt);
+ avcodec_free_context(&dp->dec_ctx);
return ret;
}
commit 9d0b88feb17dabfebcb10b801045c1285fa5e4bc
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Thu Sep 4 18:22:27 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/ffmpeg_sched: forward demuxer choke status to dst queues
Cut off a choked demuxer's output codec/filter queues, effectively preventing
them from processing packets while the demuxer is choked. Avoids downstream
nodes from piling up extra input that a demuxer shouldn't currently be
sending.
The main benefit of this is to avoid queuing up excess packets that don't want
to be decoded yet, reducing memory consumption for idle inputs by preventing
them from being read earlier than needed.
diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c
index 039cd1c9aa..589f5360f2 100644
--- a/fftools/ffmpeg_sched.c
+++ b/fftools/ffmpeg_sched.c
@@ -1294,6 +1294,36 @@ static void unchoke_for_stream(Scheduler *sch, SchedulerNode src)
}
}
+static void choke_demux(const Scheduler *sch, int demux_id, int choked)
+{
+ av_assert1(demux_id < sch->nb_demux);
+ SchDemux *demux = &sch->demux[demux_id];
+
+ for (int i = 0; i < demux->nb_streams; i++) {
+ SchedulerNode *dst = demux->streams[i].dst;
+ SchFilterGraph *fg;
+
+ switch (dst->type) {
+ case SCH_NODE_TYPE_DEC:
+ tq_choke(sch->dec[dst->idx].queue, choked);
+ break;
+ case SCH_NODE_TYPE_ENC:
+ tq_choke(sch->enc[dst->idx].queue, choked);
+ break;
+ case SCH_NODE_TYPE_MUX:
+ break;
+ case SCH_NODE_TYPE_FILTER_IN:
+ fg = &sch->filters[dst->idx];
+ if (fg->nb_inputs == 1)
+ tq_choke(fg->queue, choked);
+ break;
+ default:
+ av_unreachable("Invalid destination node type?");
+ break;
+ }
+ }
+}
+
static void schedule_update_locked(Scheduler *sch)
{
int64_t dts;
@@ -1350,13 +1380,16 @@ static void schedule_update_locked(Scheduler *sch)
}
}
-
- for (unsigned type = 0; type < 2; type++)
+ for (unsigned type = 0; type < 2; type++) {
for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) {
SchWaiter *w = type ? &sch->filters[i].waiter : &sch->demux[i].waiter;
- if (w->choked_prev != w->choked_next)
+ if (w->choked_prev != w->choked_next) {
waiter_set(w, w->choked_next);
+ if (!type)
+ choke_demux(sch, i, w->choked_next);
+ }
}
+ }
}
@@ -2595,6 +2628,8 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts)
for (unsigned i = 0; i < (type ? sch->nb_demux : sch->nb_filters); i++) {
SchWaiter *w = type ? &sch->demux[i].waiter : &sch->filters[i].waiter;
waiter_set(w, 1);
+ if (type)
+ choke_demux(sch, i, 0); // unfreeze to allow draining
}
for (unsigned i = 0; i < sch->nb_demux; i++) {
commit 59a847a23718a87a2bd1e2eae893d9784ed34b0f
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Thu Sep 4 18:09:31 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/thread_queue: allow choking thread queues directly
Currently, when a demuxer thread is choked, it will avoid queuing more
packets, but any packets already present on the thread queue will still be
processed.
This can be quite wasteful if the choke is due to e.g. decoder not being
needed yet, such as in a filter graph involving concatenation-style filters.
Adding the ability to propagate the choke status to the thread queue directly
allows downstream decoders and filter graphs to avoid unnecessary work and
buffering.
Reduces the effective latency between scheduler updates and changes in the
thread workfload.
diff --git a/fftools/thread_queue.c b/fftools/thread_queue.c
index b035ffe11d..eb33431c98 100644
--- a/fftools/thread_queue.c
+++ b/fftools/thread_queue.c
@@ -38,6 +38,7 @@ enum {
};
struct ThreadQueue {
+ int choked;
int *finished;
unsigned int nb_streams;
@@ -157,6 +158,9 @@ static int receive_locked(ThreadQueue *tq, int *stream_idx,
{
unsigned int nb_finished = 0;
+ if (tq->choked)
+ return AVERROR(EAGAIN);
+
while (av_container_fifo_read(tq->fifo, data, 0) >= 0) {
unsigned idx;
int ret;
@@ -230,6 +234,7 @@ void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx)
* next time the consumer thread tries to read this stream it will get
* an EOF and recv-finished flag will be set */
tq->finished[stream_idx] |= FINISHED_SEND;
+ tq->choked = 0;
pthread_cond_broadcast(&tq->cond);
pthread_mutex_unlock(&tq->lock);
@@ -249,3 +254,15 @@ void tq_receive_finish(ThreadQueue *tq, unsigned int stream_idx)
pthread_mutex_unlock(&tq->lock);
}
+
+void tq_choke(ThreadQueue *tq, int choked)
+{
+ pthread_mutex_lock(&tq->lock);
+
+ int prev_choked = tq->choked;
+ tq->choked = choked;
+ if (choked != prev_choked)
+ pthread_cond_broadcast(&tq->cond);
+
+ pthread_mutex_unlock(&tq->lock);
+}
diff --git a/fftools/thread_queue.h b/fftools/thread_queue.h
index cc01c8a2c9..ad7669f131 100644
--- a/fftools/thread_queue.h
+++ b/fftools/thread_queue.h
@@ -58,6 +58,15 @@ int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data);
*/
void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx);
+/**
+ * Prevent further reads from the thread queue until it is unchoked. Threads
+ * attempting to read from the queue will block, similar to when the queue is
+ * empty.
+ *
+ * @param choked 1 to choke, 0 to unchoke
+ */
+void tq_choke(ThreadQueue *tq, int choked);
+
/**
* Read the next item from the queue.
*
commit 5f4cbb5617ba52fb0b5bce36eb36e4cd7bdaec70
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Thu Sep 4 15:11:46 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/ffmpeg_sched: choke inputs during filtergraph configuration
Currently, while the filter graph is being initially created, the scheduler
continues demuxing frames on the last input that happened to be active before
the filter graph was complete.
This can lead to an excess number of decoded frames "piling" up on this input,
regardless of whether or not it will actually be requested by the configured
filter graph. Suspending the filter graph during this initialization phase
reduces the amount of wasted memory.
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 2dae6400c8..c1c8eeb2d8 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -2878,6 +2878,7 @@ static const char *unknown_if_null(const char *str)
static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
InputFilter *ifilter, AVFrame *frame)
{
+ FilterGraphPriv *fgp = fgp_from_fg(fg);
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
FrameData *fd;
AVFrameSideData *sd;
@@ -2986,6 +2987,11 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
if (reason.len > 1)
reason.str[reason.len - 2] = '\0'; // remove last comma
av_log(fg, AV_LOG_INFO, "Reconfiguring filter graph%s%s\n", reason.len ? " because " : "", reason.str);
+ } else {
+ /* Choke all input to avoid buffering excessive frames while the
+ * initial filter graph is being configured, and before we have a
+ * preferred input */
+ sch_filter_choke_inputs(fgp->sch, fgp->sch_idx);
}
ret = configure_filtergraph(fg, fgt);
diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c
index 3c5cffa594..039cd1c9aa 100644
--- a/fftools/ffmpeg_sched.c
+++ b/fftools/ffmpeg_sched.c
@@ -2510,6 +2510,18 @@ int sch_filter_command(Scheduler *sch, unsigned fg_idx, AVFrame *frame)
return send_to_filter(sch, fg, fg->nb_inputs, frame);
}
+void sch_filter_choke_inputs(Scheduler *sch, unsigned fg_idx)
+{
+ SchFilterGraph *fg;
+ av_assert0(fg_idx < sch->nb_filters);
+ fg = &sch->filters[fg_idx];
+
+ pthread_mutex_lock(&sch->schedule_lock);
+ fg->best_input = fg->nb_inputs;
+ schedule_update_locked(sch);
+ pthread_mutex_unlock(&sch->schedule_lock);
+}
+
static int task_cleanup(Scheduler *sch, SchedulerNode node)
{
switch (node.type) {
diff --git a/fftools/ffmpeg_sched.h b/fftools/ffmpeg_sched.h
index 24ad37b778..0c01f558e4 100644
--- a/fftools/ffmpeg_sched.h
+++ b/fftools/ffmpeg_sched.h
@@ -443,6 +443,13 @@ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx,
int sch_filter_command(Scheduler *sch, unsigned fg_idx, struct AVFrame *frame);
+/**
+ * Called by filtergraph tasks to choke all filter inputs, preventing them from
+ * receiving more frames until woken up again by the scheduler. Used during
+ * initial graph configuration to avoid unnecessary buffering.
+ */
+void sch_filter_choke_inputs(Scheduler *sch, unsigned fg_idx);
+
/**
* Called by encoder tasks to obtain frames for encoding. Will wait for a frame
* to become available and return it in frame.
commit 23f1f094f854bdeaae4225c1876fd2b985e977f4
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Thu Sep 4 16:53:28 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/ffmpeg_sched: get rid of src_sched
This field is just saving (typically) a single pointer indirection; and IMO
makes the logic and graph relations unnecessarily complicated. I am also
considering adding choking logic to decoders and encoders as well, which this
field would get in the way of.
Apart from the unchoking logic in unchoke_for_input(), the only other place
that uses this field is the (cold) function check_acyclic(), which can be
served just as well with a simple function to do the graph traversal there.
diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c
index 4f0d446007..3c5cffa594 100644
--- a/fftools/ffmpeg_sched.c
+++ b/fftools/ffmpeg_sched.c
@@ -189,7 +189,6 @@ typedef struct PreMuxQueue {
typedef struct SchMuxStream {
SchedulerNode src;
- SchedulerNode src_sched;
unsigned *sub_heartbeat_dst;
unsigned nb_sub_heartbeat_dst;
@@ -235,7 +234,6 @@ typedef struct SchMux {
typedef struct SchFilterIn {
SchedulerNode src;
- SchedulerNode src_sched;
int send_finished;
int receive_finished;
} SchFilterIn;
@@ -1268,24 +1266,31 @@ static void unchoke_for_stream(Scheduler *sch, SchedulerNode src)
{
while (1) {
SchFilterGraph *fg;
-
- // fed directly by a demuxer (i.e. not through a filtergraph)
- if (src.type == SCH_NODE_TYPE_DEMUX) {
+ switch (src.type) {
+ case SCH_NODE_TYPE_DEMUX:
+ // fed directly by a demuxer (i.e. not through a filtergraph)
sch->demux[src.idx].waiter.choked_next = 0;
return;
- }
-
- av_assert0(src.type == SCH_NODE_TYPE_FILTER_OUT);
- fg = &sch->filters[src.idx];
-
- // the filtergraph contains internal sources and
- // requested to be scheduled directly
- if (fg->best_input == fg->nb_inputs) {
- fg->waiter.choked_next = 0;
+ case SCH_NODE_TYPE_DEC:
+ src = sch->dec[src.idx].src;
+ continue;
+ case SCH_NODE_TYPE_ENC:
+ src = sch->enc[src.idx].src;
+ continue;
+ case SCH_NODE_TYPE_FILTER_OUT:
+ fg = &sch->filters[src.idx];
+ // the filtergraph contains internal sources and
+ // requested to be scheduled directly
+ if (fg->best_input == fg->nb_inputs) {
+ fg->waiter.choked_next = 0;
+ return;
+ }
+ src = fg->inputs[fg->best_input].src;
+ continue;
+ default:
+ av_unreachable("Invalid source node type?");
return;
}
-
- src = fg->inputs[fg->best_input].src_sched;
}
}
@@ -1328,7 +1333,7 @@ static void schedule_update_locked(Scheduler *sch)
continue;
// resolve the source to unchoke
- unchoke_for_stream(sch, ms->src_sched);
+ unchoke_for_stream(sch, ms->src);
have_unchoked = 1;
}
}
@@ -1361,6 +1366,27 @@ enum {
CYCLE_NODE_DONE,
};
+// Finds the filtergraph or muxer upstream of a scheduler node
+static SchedulerNode src_filtergraph(const Scheduler *sch, SchedulerNode src)
+{
+ while (1) {
+ switch (src.type) {
+ case SCH_NODE_TYPE_DEMUX:
+ case SCH_NODE_TYPE_FILTER_OUT:
+ return src;
+ case SCH_NODE_TYPE_DEC:
+ src = sch->dec[src.idx].src;
+ continue;
+ case SCH_NODE_TYPE_ENC:
+ src = sch->enc[src.idx].src;
+ continue;
+ default:
+ av_unreachable("Invalid source node type?");
+ return (SchedulerNode) {0};
+ }
+ }
+}
+
static int
check_acyclic_for_output(const Scheduler *sch, SchedulerNode src,
uint8_t *filters_visited, SchedulerNode *filters_stack)
@@ -1377,22 +1403,23 @@ check_acyclic_for_output(const Scheduler *sch, SchedulerNode src,
// descend into every input, depth first
if (src.idx_stream < fg->nb_inputs) {
const SchFilterIn *fi = &fg->inputs[src.idx_stream++];
+ SchedulerNode node = src_filtergraph(sch, fi->src);
// connected to demuxer, no cycles possible
- if (fi->src_sched.type == SCH_NODE_TYPE_DEMUX)
+ if (node.type == SCH_NODE_TYPE_DEMUX)
continue;
// otherwise connected to another filtergraph
- av_assert0(fi->src_sched.type == SCH_NODE_TYPE_FILTER_OUT);
+ av_assert0(node.type == SCH_NODE_TYPE_FILTER_OUT);
// found a cycle
- if (filters_visited[fi->src_sched.idx] == CYCLE_NODE_STARTED)
+ if (filters_visited[node.idx] == CYCLE_NODE_STARTED)
return AVERROR(EINVAL);
// place current position on stack and descend
av_assert0(nb_filters_stack < sch->nb_filters);
filters_stack[nb_filters_stack++] = src;
- src = (SchedulerNode){ .idx = fi->src_sched.idx, .idx_stream = 0 };
+ src = (SchedulerNode){ .idx = node.idx, .idx_stream = 0 };
continue;
}
@@ -1514,22 +1541,7 @@ static int start_prepare(Scheduler *sch)
for (unsigned j = 0; j < mux->nb_streams; j++) {
SchMuxStream *ms = &mux->streams[j];
- switch (ms->src.type) {
- case SCH_NODE_TYPE_ENC: {
- SchEnc *enc = &sch->enc[ms->src.idx];
- if (enc->src.type == SCH_NODE_TYPE_DEC) {
- ms->src_sched = sch->dec[enc->src.idx].src;
- av_assert0(ms->src_sched.type == SCH_NODE_TYPE_DEMUX);
- } else {
- ms->src_sched = enc->src;
- av_assert0(ms->src_sched.type == SCH_NODE_TYPE_FILTER_OUT);
- }
- break;
- }
- case SCH_NODE_TYPE_DEMUX:
- ms->src_sched = ms->src;
- break;
- default:
+ if (!ms->src.type) {
av_log(mux, AV_LOG_ERROR,
"Muxer stream #%u not connected to a source\n", j);
return AVERROR(EINVAL);
@@ -1547,26 +1559,12 @@ static int start_prepare(Scheduler *sch)
for (unsigned j = 0; j < fg->nb_inputs; j++) {
SchFilterIn *fi = &fg->inputs[j];
- SchDec *dec;
if (!fi->src.type) {
av_log(fg, AV_LOG_ERROR,
"Filtergraph input %u not connected to a source\n", j);
return AVERROR(EINVAL);
}
-
- if (fi->src.type == SCH_NODE_TYPE_FILTER_OUT)
- fi->src_sched = fi->src;
- else {
- av_assert0(fi->src.type == SCH_NODE_TYPE_DEC);
- dec = &sch->dec[fi->src.idx];
-
- switch (dec->src.type) {
- case SCH_NODE_TYPE_DEMUX: fi->src_sched = dec->src; break;
- case SCH_NODE_TYPE_ENC: fi->src_sched = sch->enc[dec->src.idx].src; break;
- default: av_assert0(0);
- }
- }
}
for (unsigned j = 0; j < fg->nb_outputs; j++) {
commit fd4b5b24cedac1f7bae6792cbe4216f3e30a2cae
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Wed Sep 3 14:38:38 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/ffmpeg_sched: lower default frame queue size
I tested this extensively under different conditions and could not come up
with any scenario where using a larger queue size was actually beneficial.
Moreover, having such a large default queue is very wasteful especially
for larger frame sizes; and can in the worst case lead to an extra ~50% memory
footprint per input (with the default 16 threads), regardless of whether that
input is currently in use or not.
My methodology was to add logging in the event of a queue underrun/overrun,
and then observe and then observe the frequency of such events in practice,
as well as the impact on performance. I came up with an example filter graph
involving decoding, filtering and encoding with several input files and
various changes to move the bottleneck around.
I found that, in all configurations I tested, with all thread counts and
bottlenecks, using a queue size of 2 frames yielded practically identical
performance to a queue size of 8 frames. I was only able to consistently
measure a slowdown when restricting the queue to a single frame, where the
underruns ended up making up almost 1.1% of frame events in the worst case.
A summary of my test log follows:
= Bottleneck in decoder =
ffmpeg -i A -i B -i C -filter_complex "concat=n=3" -f null -
== 16 threads ==
=== Queue statistics (dec -> filtergraph) ===
- 8 frames = 91355 underruns, 1 overrun
- 4 frames = 91381 underruns, 2 overruns
- 2 frames = 91326 underruns, 21 overruns
- 1 frame = 91284 underruns, 102 overruns
=== Time elapsed ===
- 8 frames = 14.37s
- 4 frames = 14.28s
- 2 frames = 14.27s
- 1 frame = 14.35s
== 1 thread ==
=== Queue statistics (dec -> filtergraph) ===
- 8 frames = 91801 underruns, 0 overruns
- 4 frames = 91929 underruns, 1 overrun
- 2 frames = 91854 underruns, 7 overruns
- 1 frame = 91745 underrons, 83 overruns
=== Time elapsed ===
- 8 frames = 39.51s
- 4 frames = 39.94s
- 2 frames = 39.91s
- 1 frame = 41.69s
= Bottleneck in filter graph: =
ffmpeg -i A -i B -i C -filter_complex "concat=n=3,scale=3840x2160" -f null -
== 16 threads ==
=== Queue statistics (dec -> filtergraph) ===
- 8 frames = 277 underruns, 84673 overruns
- 4 frames = 640 underruns, 86523 overruns
- 2 frames = 850 underruns, 88751 overruns
- 1 frame = 1028 underruns, 89957 overruns
=== Time elapsed ===
- 8 frames = 26.35s
- 4 frames = 26.31s
- 2 frames = 26.38s
- 1 frame = 26.55s
== 1 thread ==
=== Queue statistics (dec -> filtergraph) ===
- 8 frames = 29746 underruns, 57033 overruns
- 4 frames = 29940 underruns, 58948 overruns
- 2 frames = 30160 underruns, 60185 overruns
- 1 frame = 30259 underruns, 61126 overruns
=== Time elapsed ===
- 8 frames = 52.08s
- 4 frames = 52.49s
- 2 frames = 52.25s
- 1 frame = 52.69s
= Bottleneck in encoder: =
ffmpeg -i A -i B -i C -filter_complex "concat=n=3" -c:v libx264 -preset veryfast -f null -
== 1 thread ==
== Queue statistics (filtergraph -> enc) ==
- 8 frames = 26763 underruns, 63535 overruns
- 4 frames = 26863 underruns, 63810 overruns
- 2 frames = 27243 underruns, 63839 overruns
- 1 frame = 27670 underruns, 63953 overruns
== Time elapsed ==
- 8 frames = 89.45s
- 4 frames = 89.04s
- 2 frames = 89.24s
- 1 frame = 90.26s
diff --git a/fftools/ffmpeg_sched.h b/fftools/ffmpeg_sched.h
index fb7a77ddfc..24ad37b778 100644
--- a/fftools/ffmpeg_sched.h
+++ b/fftools/ffmpeg_sched.h
@@ -257,7 +257,7 @@ int sch_add_mux(Scheduler *sch, SchThreadFunc func, int (*init)(void *),
/**
* Default size of a frame thread queue.
*/
-#define DEFAULT_FRAME_THREAD_QUEUE_SIZE 8
+#define DEFAULT_FRAME_THREAD_QUEUE_SIZE 2
/**
* Add a muxed stream for a previously added muxer.
commit 15407cf90bb4fd9f47f85f078e5689b2593ccbc3
Author: Niklas Haas <git(a)haasn.dev>
AuthorDate: Wed Sep 3 14:10:55 2025 +0200
Commit: Niklas Haas <git(a)haasn.dev>
CommitDate: Tue Sep 30 13:16:59 2025 +0200
fftools/ffmpeg_sched: relax queue size assertion
The code in the decoder just cares about allocating enough extra hw frames
to cover the size of the queue; but there's no reason we actually *have* to
use this many. We can safely relax the assertion to a <= check.
diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c
index 3180367576..4f0d446007 100644
--- a/fftools/ffmpeg_sched.c
+++ b/fftools/ffmpeg_sched.c
@@ -389,7 +389,7 @@ static int queue_alloc(ThreadQueue **ptq, unsigned nb_streams, unsigned queue_si
// for frames held in queues inside the ffmpeg utility. If this
// can ever dynamically change then the corresponding decode
// code needs to be updated as well.
- av_assert0(queue_size == DEFAULT_FRAME_THREAD_QUEUE_SIZE);
+ av_assert0(queue_size <= DEFAULT_FRAME_THREAD_QUEUE_SIZE);
}
tq = tq_alloc(nb_streams, queue_size,
-----------------------------------------------------------------------
Summary of changes:
fftools/ffmpeg_dec.c | 1 +
fftools/ffmpeg_filter.c | 6 ++
fftools/ffmpeg_sched.c | 183 +++++++++++++++++++++++++++++++++---------------
fftools/ffmpeg_sched.h | 9 ++-
fftools/thread_queue.c | 17 +++++
fftools/thread_queue.h | 9 +++
6 files changed, 168 insertions(+), 57 deletions(-)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. 1608aa38a2 doc/infra: More details about hosting and security
by ffmpeg-git@ffmpeg.org 30 Sep '25
by ffmpeg-git@ffmpeg.org 30 Sep '25
30 Sep '25
The branch, master has been updated
via 1608aa38a2ca9bd49debc5577ee38e2726303eda (commit)
from fd136a4d826d9eb2509dbb8d2869575ff8e74434 (commit)
- Log -----------------------------------------------------------------
commit 1608aa38a2ca9bd49debc5577ee38e2726303eda
Author: Nikolay Aleksandrov <razor(a)blackwall.org>
AuthorDate: Mon Nov 25 17:26:53 2024 +0100
Commit: Michael Niedermayer <michael(a)niedermayer.cc>
CommitDate: Tue Sep 30 13:14:03 2025 +0200
doc/infra: More details about hosting and security
Signed-off-by: Michael Niedermayer <michael(a)niedermayer.cc>
I have redacted the exact location of the FFmpeg server as writing
that in public seems just a bad idea
diff --git a/doc/infra.txt b/doc/infra.txt
index 490c6cdbd9..b5546aedd4 100644
--- a/doc/infra.txt
+++ b/doc/infra.txt
@@ -24,6 +24,26 @@ Our Main server is hosted at telepoint.bg
for more details see: https://www.ffmpeg.org/#thanks_sponsor_0001
Nothing runs on our main server directly, instead several VMs run on it.
+Main server security:
+---------------------
+Telepoint is one of the largest Bulgarian DC providers with multiple sibling companies offering
+Internet, SDH, DWDM, peering exchange and hosting. They have multiple DC buildings in Sofia and
+FFmpeg is hosted in XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. The building is locked down and accessible
+only with personal key cards that are registered. People who are granted access to a rack have
+to go through the access center with their ID to get logged and receive a one-time access card
+that can open the service elevator and only the hall where the destination rack is. All racks are
+locked, once access is granted to someone they will get a key for the rack for the duration of
+their visit. There are security cameras everywhere and personnel in the access center 24/7. As for
+software security, our BIOS and IPMI are protected by password and encrypted connection, and
+the machines can be accessed only by root administrators with their SSH keys. They're using
+a Ubuntu LTS release and get regular security updates as they are released. We also get
+notified by email for various security related events (e.g. failed sudo).
+
+Side note - Telepoint provides the rack and physical infrastructure, their sibling company called
+ Telehouse which is an ISP provides the connectivity, they are directly connected with
+ over 15 tier-1 service providers and have over 100 PoPs (points of presence)
+ in various cities. You can see more on www.telehouse.bg
+
ffmpeg.org VM:
--------------
-----------------------------------------------------------------------
Summary of changes:
doc/infra.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. fd136a4d82 ffv1enc_vulkan: fix empty struct build error on msvc
by ffmpeg-git@ffmpeg.org 30 Sep '25
by ffmpeg-git@ffmpeg.org 30 Sep '25
30 Sep '25
The branch, master has been updated
via fd136a4d826d9eb2509dbb8d2869575ff8e74434 (commit)
from bc561013c9a809a90c0d1b84413814ba612f7c44 (commit)
- Log -----------------------------------------------------------------
commit fd136a4d826d9eb2509dbb8d2869575ff8e74434
Author: Koushik Dutta via ffmpeg-devel <ffmpeg-devel(a)ffmpeg.org>
AuthorDate: Mon Sep 29 11:44:49 2025 -0700
Commit: Lynne <dev(a)lynne.ee>
CommitDate: Tue Sep 30 19:36:56 2025 +0900
ffv1enc_vulkan: fix empty struct build error on msvc
Signed-off-by: Koushik Dutta <koushd(a)gmail.com>
diff --git a/libavcodec/ffv1enc_vulkan.c b/libavcodec/ffv1enc_vulkan.c
index 259bc75d4c..a54180a98b 100644
--- a/libavcodec/ffv1enc_vulkan.c
+++ b/libavcodec/ffv1enc_vulkan.c
@@ -1367,6 +1367,7 @@ static int init_encode_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv)
.buf_content = "uint64_t slice_results[2048];",
},
{ /* place holder for desc_set[3] */
+ .name = "placeholder",
},
};
if (fv->is_rgb) {
-----------------------------------------------------------------------
Summary of changes:
libavcodec/ffv1enc_vulkan.c | 1 +
1 file changed, 1 insertion(+)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. bc561013c9 avformat/whip: add RTX initial support
by ffmpeg-git@ffmpeg.org 30 Sep '25
by ffmpeg-git@ffmpeg.org 30 Sep '25
30 Sep '25
The branch, master has been updated
via bc561013c9a809a90c0d1b84413814ba612f7c44 (commit)
from f1e9032a2000b8b885cffd6fed8eacd47b37673f (commit)
- Log -----------------------------------------------------------------
commit bc561013c9a809a90c0d1b84413814ba612f7c44
Author: Jack Lau <jacklau1222(a)qq.com>
AuthorDate: Thu Sep 18 09:23:31 2025 +0800
Commit: stevenliu <lingjiujianke(a)gmail.com>
CommitDate: Tue Sep 30 05:42:40 2025 +0000
avformat/whip: add RTX initial support
Refer to RFC 4588.
Add and set the basic param of RTX like
ssrc, payload_type, srtp.
Modify the SDP to add RTX info so that
the peer be able to parse the RTX packet.
There are more pateches to make RTX really
work.
Signed-off-by: Jack Lau <jacklau1222(a)qq.com>
diff --git a/libavformat/whip.c b/libavformat/whip.c
index cfdc861c5b..472c6dbf16 100644
--- a/libavformat/whip.c
+++ b/libavformat/whip.c
@@ -122,6 +122,7 @@
/* Referring to Chrome's definition of RTP payload types. */
#define WHIP_RTP_PAYLOAD_TYPE_H264 106
#define WHIP_RTP_PAYLOAD_TYPE_OPUS 111
+#define WHIP_RTP_PAYLOAD_TYPE_VIDEO_RTX 105
/**
* The STUN message header, which is 20 bytes long, comprises the
@@ -229,12 +230,14 @@ typedef struct WHIPContext {
/* The SSRC of the audio and video stream, generated by the muxer. */
uint32_t audio_ssrc;
uint32_t video_ssrc;
+ uint32_t video_rtx_ssrc;
uint16_t audio_first_seq;
uint16_t video_first_seq;
/* The PT(Payload Type) of stream, generated by the muxer. */
uint8_t audio_payload_type;
uint8_t video_payload_type;
+ uint8_t video_rtx_payload_type;
/**
* This is the SDP offer generated by the muxer based on the codec parameters,
* DTLS, and ICE information.
@@ -290,6 +293,7 @@ typedef struct WHIPContext {
/* The SRTP send context, to encrypt outgoing packets. */
SRTPContext srtp_audio_send;
SRTPContext srtp_video_send;
+ SRTPContext srtp_video_rtx_send;
SRTPContext srtp_rtcp_send;
/* The SRTP receive context, to decrypt incoming packets. */
SRTPContext srtp_recv;
@@ -602,9 +606,11 @@ static int generate_sdp_offer(AVFormatContext *s)
whip->audio_ssrc = av_lfg_get(&whip->rnd);
whip->video_ssrc = whip->audio_ssrc + 1;
+ whip->video_rtx_ssrc = whip->video_ssrc + 1;
whip->audio_payload_type = WHIP_RTP_PAYLOAD_TYPE_OPUS;
whip->video_payload_type = WHIP_RTP_PAYLOAD_TYPE_H264;
+ whip->video_rtx_payload_type = WHIP_RTP_PAYLOAD_TYPE_VIDEO_RTX;
av_bprintf(&bp, ""
"v=0\r\n"
@@ -657,7 +663,7 @@ static int generate_sdp_offer(AVFormatContext *s)
}
av_bprintf(&bp, ""
- "m=video 9 UDP/TLS/RTP/SAVPF %u\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF %u %u\r\n"
"c=IN IP4 0.0.0.0\r\n"
"a=ice-ufrag:%s\r\n"
"a=ice-pwd:%s\r\n"
@@ -671,9 +677,13 @@ static int generate_sdp_offer(AVFormatContext *s)
"a=rtpmap:%u %s/90000\r\n"
"a=fmtp:%u level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=%02x%02x%02x\r\n"
"a=rtcp-fb%u nack\r\n"
+ "a=rtpmap:%u rtx/90000\r\n"
+ "a=fmtp:%u apt=%u\r\n"
+ "a=ssrc-group:FID %u %u\r\n"
"a=ssrc:%u cname:FFmpeg\r\n"
"a=ssrc:%u msid:FFmpeg video\r\n",
whip->video_payload_type,
+ whip->video_rtx_payload_type,
whip->ice_ufrag_local,
whip->ice_pwd_local,
whip->dtls_fingerprint,
@@ -684,6 +694,11 @@ static int generate_sdp_offer(AVFormatContext *s)
profile_iop,
level,
whip->video_payload_type,
+ whip->video_rtx_payload_type,
+ whip->video_rtx_payload_type,
+ whip->video_payload_type,
+ whip->video_ssrc,
+ whip->video_rtx_ssrc,
whip->video_ssrc,
whip->video_ssrc);
}
@@ -1408,6 +1423,12 @@ static int setup_srtp(AVFormatContext *s)
goto end;
}
+ ret = ff_srtp_set_crypto(&whip->srtp_video_rtx_send, suite, buf);
+ if (ret < 0) {
+ av_log(whip, AV_LOG_ERROR, "Failed to set crypto for video rtx send\n");
+ goto end;
+ }
+
ret = ff_srtp_set_crypto(&whip->srtp_rtcp_send, suite, buf);
if (ret < 0) {
av_log(whip, AV_LOG_ERROR, "Failed to set crypto for rtcp send\n");
@@ -1924,6 +1945,7 @@ static av_cold void whip_deinit(AVFormatContext *s)
av_freep(&whip->key_file);
ff_srtp_free(&whip->srtp_audio_send);
ff_srtp_free(&whip->srtp_video_send);
+ ff_srtp_free(&whip->srtp_video_rtx_send);
ff_srtp_free(&whip->srtp_rtcp_send);
ff_srtp_free(&whip->srtp_recv);
ffurl_close(whip->dtls_uc);
-----------------------------------------------------------------------
Summary of changes:
libavformat/whip.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. f1e9032a20 configure: unbreak glslang build
by ffmpeg-git@ffmpeg.org 30 Sep '25
by ffmpeg-git@ffmpeg.org 30 Sep '25
30 Sep '25
The branch, master has been updated
via f1e9032a2000b8b885cffd6fed8eacd47b37673f (commit)
from d975dbd7b70e0b2f3f3b2950e5513c299b838810 (commit)
- Log -----------------------------------------------------------------
commit f1e9032a2000b8b885cffd6fed8eacd47b37673f
Author: Gyan Doshi <ffmpeg(a)gyani.pro>
AuthorDate: Sun Sep 28 13:20:23 2025 +0530
Commit: Gyan Doshi <gyan(a)gyan.dev>
CommitDate: Tue Sep 30 04:26:18 2025 +0000
configure: unbreak glslang build
Don't unconditionally link to libSPVRemapper which was removed in 16.0 in 3a7f787
diff --git a/configure b/configure
index aaa72c9f93..399b1ce128 100755
--- a/configure
+++ b/configure
@@ -7132,12 +7132,16 @@ enabled libfontconfig && require_pkg_config libfontconfig fontconfig "fontco
enabled libfreetype && require_pkg_config libfreetype freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType
enabled libfribidi && require_pkg_config libfribidi fribidi fribidi.h fribidi_version_info
enabled libharfbuzz && require_pkg_config libharfbuzz harfbuzz hb.h hb_buffer_create
-enabled libglslang && { check_lib spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
+if enabled libglslang; then
+ spvremap="-lSPVRemapper"
+ require_headers "glslang/build_info.h" && { test_cpp_condition glslang/build_info.h "GLSLANG_VERSION_MAJOR >= 16" && spvremap="" ; }
+ check_lib spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
-lglslang -lMachineIndependent -lGenericCodeGen \
- -lSPVRemapper -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ||
+ ${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ||
require spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
-lglslang -lMachineIndependent -lOSDependent -lHLSL -lOGLCompiler -lGenericCodeGen \
- -lSPVRemapper -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ; }
+ ${spvremap} -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ;
+fi
enabled libgme && { check_pkg_config libgme libgme gme/gme.h gme_new_emu ||
require libgme gme/gme.h gme_new_emu -lgme -lstdc++; }
enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do
-----------------------------------------------------------------------
Summary of changes:
configure | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
hooks/post-receive
--
1
0
[ffmpeg] branch master updated. d975dbd7b7 avcodec/libdav1d: bump minimum supported version to 1.0.0
by ffmpeg-git@ffmpeg.org 29 Sep '25
by ffmpeg-git@ffmpeg.org 29 Sep '25
29 Sep '25
The branch, master has been updated
via d975dbd7b70e0b2f3f3b2950e5513c299b838810 (commit)
from 0fdb5829e38dabea9cbe4073a35b6c6315e7508e (commit)
- Log -----------------------------------------------------------------
commit d975dbd7b70e0b2f3f3b2950e5513c299b838810
Author: James Almer <jamrial(a)gmail.com>
AuthorDate: Sun Sep 28 23:51:19 2025 -0300
Commit: James Almer <jamrial(a)gmail.com>
CommitDate: Sun Sep 28 23:53:27 2025 -0300
avcodec/libdav1d: bump minimum supported version to 1.0.0
This allows us to remove old deprecated options.
Signed-off-by: James Almer <jamrial(a)gmail.com>
diff --git a/configure b/configure
index 2cb39cbd57..aaa72c9f93 100755
--- a/configure
+++ b/configure
@@ -7116,7 +7116,7 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 &&
die "ERROR: libcelt must be installed and version must be >= 0.11.0."; }
enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas
enabled libcodec2 && require libcodec2 codec2/codec2.h codec2_create -lcodec2
-enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.5.0" "dav1d/dav1d.h" dav1d_version
+enabled libdav1d && require_pkg_config libdav1d "dav1d >= 1.0.0" "dav1d/dav1d.h" dav1d_version
enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open
enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new
enabled libdrm && check_pkg_config libdrm libdrm xf86drm.h drmGetVersion
diff --git a/doc/decoders.texi b/doc/decoders.texi
index b7d80ca3d7..9248e2283a 100644
--- a/doc/decoders.texi
+++ b/doc/decoders.texi
@@ -119,16 +119,6 @@ The following options are supported by the libdav1d wrapper.
@table @option
-@item framethreads
-Set amount of frame threads to use during decoding. The default value is 0 (autodetect).
-This option is deprecated for libdav1d >= 1.0 and will be removed in the future. Use the
-option @code{max_frame_delay} and the global option @code{threads} instead.
-
-@item tilethreads
-Set amount of tile threads to use during decoding. The default value is 0 (autodetect).
-This option is deprecated for libdav1d >= 1.0 and will be removed in the future. Use the
-global option @code{threads} instead.
-
@item max_frame_delay
Set max amount of frames the decoder may buffer internally. The default value is 0
(autodetect).
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index bd3050b881..01fe2c415f 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -50,8 +50,6 @@ typedef struct Libdav1dContext {
int pool_size;
Dav1dData data;
- int tile_threads;
- int frame_threads;
int max_frame_delay;
int apply_grain;
int operating_point;
@@ -215,11 +213,7 @@ static av_cold int libdav1d_init(AVCodecContext *c)
{
Libdav1dContext *dav1d = c->priv_data;
Dav1dSettings s;
-#if FF_DAV1D_VERSION_AT_LEAST(6,0)
int threads = c->thread_count;
-#else
- int threads = (c->thread_count ? c->thread_count : av_cpu_count()) * 3 / 2;
-#endif
const AVPacketSideData *sd;
int res;
@@ -240,32 +234,14 @@ static av_cold int libdav1d_init(AVCodecContext *c)
s.all_layers = dav1d->all_layers;
if (dav1d->operating_point >= 0)
s.operating_point = dav1d->operating_point;
-#if FF_DAV1D_VERSION_AT_LEAST(6,2)
s.strict_std_compliance = c->strict_std_compliance > 0;
-#endif
-#if FF_DAV1D_VERSION_AT_LEAST(6,0)
- if (dav1d->frame_threads || dav1d->tile_threads)
- s.n_threads = FFMAX(dav1d->frame_threads, dav1d->tile_threads);
- else
- s.n_threads = FFMIN(threads, DAV1D_MAX_THREADS);
+ s.n_threads = FFMIN(threads, DAV1D_MAX_THREADS);
if (dav1d->max_frame_delay > 0 && (c->flags & AV_CODEC_FLAG_LOW_DELAY))
av_log(c, AV_LOG_WARNING, "Low delay mode requested, forcing max_frame_delay 1\n");
s.max_frame_delay = (c->flags & AV_CODEC_FLAG_LOW_DELAY) ? 1 : dav1d->max_frame_delay;
av_log(c, AV_LOG_DEBUG, "Using %d threads, %d max_frame_delay\n",
s.n_threads, s.max_frame_delay);
-#else
- s.n_tile_threads = dav1d->tile_threads
- ? dav1d->tile_threads
- : FFMIN(floor(sqrt(threads)), DAV1D_MAX_TILE_THREADS);
- s.n_frame_threads = dav1d->frame_threads
- ? dav1d->frame_threads
- : FFMIN(ceil(threads / s.n_tile_threads), DAV1D_MAX_FRAME_THREADS);
- if (dav1d->max_frame_delay > 0)
- s.n_frame_threads = FFMIN(s.n_frame_threads, dav1d->max_frame_delay);
- av_log(c, AV_LOG_DEBUG, "Using %d frame threads, %d tile threads\n",
- s.n_frame_threads, s.n_tile_threads);
-#endif
#if FF_DAV1D_VERSION_AT_LEAST(6,8)
if (c->skip_frame >= AVDISCARD_NONKEY)
@@ -465,9 +441,7 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame)
Libdav1dContext *dav1d = c->priv_data;
Dav1dPicture pic = { 0 }, *p = &pic;
const AVPacket *pkt;
-#if FF_DAV1D_VERSION_AT_LEAST(5,1)
enum Dav1dEventFlags event_flags = 0;
-#endif
int res;
do {
@@ -493,12 +467,10 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame)
frame->linesize[1] = p->stride[1];
frame->linesize[2] = p->stride[1];
-#if FF_DAV1D_VERSION_AT_LEAST(5,1)
dav1d_get_event_flags(dav1d->c, &event_flags);
- if (c->pix_fmt == AV_PIX_FMT_NONE ||
- event_flags & DAV1D_EVENT_FLAG_NEW_SEQUENCE)
-#endif
- libdav1d_init_params(c, p->seq_hdr);
+ if (c->pix_fmt == AV_PIX_FMT_NONE || event_flags & DAV1D_EVENT_FLAG_NEW_SEQUENCE)
+ libdav1d_init_params(c, p->seq_hdr);
+
res = ff_decode_frame_props(c, frame);
if (res < 0)
goto fail;
@@ -677,8 +649,6 @@ static av_cold int libdav1d_close(AVCodecContext *c)
#define OFFSET(x) offsetof(Libdav1dContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption libdav1d_options[] = {
- { "tilethreads", "Tile threads", OFFSET(tile_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_TILE_THREADS, VD | AV_OPT_FLAG_DEPRECATED },
- { "framethreads", "Frame threads", OFFSET(frame_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_FRAME_THREADS, VD | AV_OPT_FLAG_DEPRECATED },
{ "max_frame_delay", "Max frame delay", OFFSET(max_frame_delay), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_FRAME_DELAY, VD },
{ "filmgrain", "Apply Film Grain", OFFSET(apply_grain), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD | AV_OPT_FLAG_DEPRECATED },
{ "oppoint", "Select an operating point of the scalable bitstream", OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 31, VD },
-----------------------------------------------------------------------
Summary of changes:
configure | 2 +-
doc/decoders.texi | 10 ----------
libavcodec/libdav1d.c | 38 ++++----------------------------------
3 files changed, 5 insertions(+), 45 deletions(-)
hooks/post-receive
--
1
0