PR #23678 opened by felipdsa21 URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23678 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23678.patch
On Windows, CRT file descriptors cannot be reliably passed to child processes, so HANDLEs need to be used instead. This adds a handle protocol so ffmpeg.exe can accept a HANDLE directly as input or output. The new protocol duplicates the given handle, or falls back to the standard input or output handle, then converts it to a CRT fd, and reuses the existing fd/file protocol code for I/O. Used the fd protocol's own addition as reference: https://code.ffmpeg.org/FFmpeg/FFmpeg/compare/e9fe1634d4...195ccf7ea8 Also includes a small fix removing pipe and fd's `url_check` hook, since it treated the URL as a filesystem path, which is incorrect for these protocols and gave bogus results. From cc82b086e500947e69e184742136c7adc06300f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Ara=C3=BAjo?= <[email protected]> Date: Thu, 2 Jul 2026 02:05:58 -0300 Subject: [PATCH 1/3] avformat/file: remove broken url_check on pipe and fd protocols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit file_check treats the URL as a file path, which is incorrect for the pipe and fd protocols. Signed-off-by: Felipe Araújo <[email protected]> --- libavformat/file.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/libavformat/file.c b/libavformat/file.c index 71d30a25c4..e58f00a9e5 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -481,7 +481,6 @@ const URLProtocol ff_pipe_protocol = { .url_write = file_write, .url_close = file_close, .url_get_file_handle = file_get_handle, - .url_check = file_check, .priv_data_size = sizeof(FileContext), .priv_data_class = &pipe_class, .default_whitelist = "crypto,data" @@ -527,7 +526,6 @@ const URLProtocol ff_fd_protocol = { .url_seek = file_seek, .url_close = file_close, .url_get_file_handle = file_get_handle, - .url_check = file_check, .priv_data_size = sizeof(FileContext), .priv_data_class = &fd_class, .default_whitelist = "crypto,data" @@ -687,7 +685,6 @@ const URLProtocol ff_android_content_protocol = { .url_seek = file_seek, .url_close = file_close, .url_get_file_handle = file_get_handle, - .url_check = NULL, .priv_data_size = sizeof(FileContext), .priv_data_class = &android_content_class, }; -- 2.52.0 From 4700990c9bf56c299b3ae1f444e7afa627c1689b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Ara=C3=BAjo?= <[email protected]> Date: Thu, 2 Jul 2026 02:05:58 -0300 Subject: [PATCH 2/3] avformat/file: add Windows handle protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like the fd protocol, but takes a raw Windows HANDLE instead of a CRT file descriptor. Signed-off-by: Felipe Araújo <[email protected]> --- configure | 1 + doc/protocols.texi | 26 ++++++++++++++ libavformat/Makefile | 1 + libavformat/file.c | 79 +++++++++++++++++++++++++++++++++++++++++ libavformat/protocols.c | 1 + libavformat/version.h | 2 +- 6 files changed, 109 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 4573d69f28..3fa3011798 100755 --- a/configure +++ b/configure @@ -4124,6 +4124,7 @@ unix_protocol_deps="sys_un_h" unix_protocol_select="network" ipfs_gateway_protocol_select="https_protocol" ipns_gateway_protocol_select="https_protocol" +windows_handle_protocol_deps="windows_h" # external library protocols libamqp_protocol_deps="librabbitmq" diff --git a/doc/protocols.texi b/doc/protocols.texi index 5f8cc8094d..8ab61f4c08 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -419,6 +419,32 @@ Gophers protocol. The Gopher protocol with TLS encapsulation. +@section handle + +Windows handle access protocol. + +The accepted syntax is: +@example +handle: -handle @var{handle} +@end example + +If @option{handle} is not specified, by default the output handle will be +used for writing, input handle for reading. This protocol is only available +on Windows. It has seek support if the handle corresponds to a regular file. + +This protocol accepts the following options: + +@table @option +@item blocksize +Set I/O operation maximum block size, in bytes. Default value is +@code{INT_MAX}, which results in not limiting the requested block size. +Setting this value reasonably low improves user termination request reaction +time, which is valuable if data transmission is slow. + +@item handle +Set Windows handle. +@end table + @section http HTTP (Hyper Text Transfer Protocol). diff --git a/libavformat/Makefile b/libavformat/Makefile index b244eaabf9..d7d1046382 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -732,6 +732,7 @@ OBJS-$(CONFIG_DTLS_PROTOCOL) += tls.o $(TLS-OBJS-yes) OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o ip.o OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o ip.o OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o +OBJS-$(CONFIG_WINDOWS_HANDLE_PROTOCOL) += file.o # external library protocols OBJS-$(CONFIG_LIBAMQP_PROTOCOL) += libamqp.o diff --git a/libavformat/file.c b/libavformat/file.c index e58f00a9e5..6c80c4c815 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -103,6 +103,9 @@ typedef struct FileContext { #if HAVE_DIRENT_H DIR *dir; #endif +#if CONFIG_WINDOWS_HANDLE_PROTOCOL + int64_t handle; +#endif } FileContext; static const AVOption file_options[] = { @@ -533,6 +536,82 @@ const URLProtocol ff_fd_protocol = { #endif /* CONFIG_FD_PROTOCOL */ +#if CONFIG_WINDOWS_HANDLE_PROTOCOL + +#include <windows.h> + +static const AVOption windows_handle_options[] = { + { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + { "handle", "set Windows handle", offsetof(FileContext, handle), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + { NULL } +}; + +static const AVClass windows_handle_class = { + .class_name = "windows_handle", + .item_name = av_default_item_name, + .option = windows_handle_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static int windows_handle_open(URLContext *h, const char *filename, int flags) +{ + FileContext *c = h->priv_data; + HANDLE handle = (HANDLE)(intptr_t)c->handle; + HANDLE dup_handle; + int fd; + struct stat st; + + if (strcmp(filename, "handle:") != 0) { + av_log(h, AV_LOG_ERROR, "Doesn't support passing Windows handles via URL," + " please set it via -handle {num}\n"); + return AVERROR(EINVAL); + } + + if (handle == INVALID_HANDLE_VALUE || !handle) { + if (flags & AVIO_FLAG_WRITE) + handle = GetStdHandle(STD_OUTPUT_HANDLE); + else + handle = GetStdHandle(STD_INPUT_HANDLE); + } + + if (!DuplicateHandle(GetCurrentProcess(), handle, + GetCurrentProcess(), &dup_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + return AVERROR(EIO); + + fd = _open_osfhandle((intptr_t)dup_handle, O_BINARY | + ((flags & AVIO_FLAG_WRITE) ? O_RDWR : O_RDONLY)); + if (fd == -1) { + CloseHandle(dup_handle); + return AVERROR(errno); + } + + if (fstat(fd, &st) < 0) { + close(fd); + return AVERROR(errno); + } + + c->fd = fd; + h->is_streamed = !(S_ISREG(st.st_mode) || S_ISBLK(st.st_mode)); + + return 0; +} + +const URLProtocol ff_windows_handle_protocol = { + .name = "handle", + .url_open = windows_handle_open, + .url_read = file_read, + .url_write = file_write, + .url_seek = file_seek, + .url_close = file_close, + .url_get_file_handle = file_get_handle, + .priv_data_size = sizeof(FileContext), + .priv_data_class = &windows_handle_class, + .default_whitelist = "crypto,data" +}; + +#endif /* CONFIG_WINDOWS_HANDLE_PROTOCOL */ + #if CONFIG_ANDROID_CONTENT_PROTOCOL #include <jni.h> #include "libavcodec/ffjni.h" diff --git a/libavformat/protocols.c b/libavformat/protocols.c index 257b41970a..db5bc37aef 100644 --- a/libavformat/protocols.c +++ b/libavformat/protocols.c @@ -79,6 +79,7 @@ extern const URLProtocol ff_libsmbclient_protocol; extern const URLProtocol ff_libzmq_protocol; extern const URLProtocol ff_ipfs_gateway_protocol; extern const URLProtocol ff_ipns_gateway_protocol; +extern const URLProtocol ff_windows_handle_protocol; #include "libavformat/protocol_list.c" diff --git a/libavformat/version.h b/libavformat/version.h index 7ff1483912..af7d0a1024 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFORMAT_VERSION_MINOR 3 +#define LIBAVFORMAT_VERSION_MINOR 4 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ -- 2.52.0 From 725c210f2d7f01d5ae53999ca76f5acf0873b819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Ara=C3=BAjo?= <[email protected]> Date: Thu, 2 Jul 2026 02:05:59 -0300 Subject: [PATCH 3/3] fftools/ffmpeg_demux: disable stdin interaction for Windows handle protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Felipe Araújo <[email protected]> --- fftools/ffmpeg_demux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c index 38bd580bfc..cc98a0f8e0 100644 --- a/fftools/ffmpeg_demux.c +++ b/fftools/ffmpeg_demux.c @@ -2078,6 +2078,7 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) stdin_interaction &= strncmp(filename, "pipe:", 5) && strcmp(filename, "fd:") && + strcmp(filename, "handle:") && strcmp(filename, "/dev/stdin"); /* get default parameters from command line */ -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
