This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 1ae485ba98381cbb2505e75a0666c40c77f3d8de Author: Felipe Araújo <[email protected]> AuthorDate: Sat Oct 10 03:16:05 2026 -0300 Commit: michaelni <[email protected]> CommitDate: Sun Oct 11 23:10:44 2026 +0000 avformat/file: add Windows handle protocol Like the fd protocol, but takes a raw Windows HANDLE instead of a CRT file descriptor. On Windows, CRT file descriptors cannot be reliably passed to child processes, so HANDLEs need to be used instead. Signed-off-by: Felipe Araújo <[email protected]> --- configure | 3 ++ doc/protocols.texi | 34 ++++++++++++++++++++ libavformat/Makefile | 1 + libavformat/file.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++- libavformat/protocols.c | 1 + libavformat/version.h | 2 +- 6 files changed, 123 insertions(+), 2 deletions(-) diff --git a/configure b/configure index f542d4e0d6..f316113785 100755 --- a/configure +++ b/configure @@ -2534,6 +2534,7 @@ SYSTEM_FUNCS=" mmap mprotect nanosleep + open_osfhandle PeekNamedPipe posix_memalign prctl @@ -4097,6 +4098,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 open_osfhandle GetStdHandle" # external library protocols libamqp_protocol_deps="librabbitmq" @@ -6899,6 +6901,7 @@ check_func usleep check_func_headers conio.h kbhit check_func_headers io.h setmode +check_func_headers io.h _open_osfhandle && enable open_osfhandle check_func_headers lzo/lzo1x.h lzo1x_999_compress check_func_headers mach/mach_time.h mach_absolute_time check_func_headers setjmp.h siglongjmp diff --git a/doc/protocols.texi b/doc/protocols.texi index dbb1f166c7..1d43fa6327 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -419,6 +419,40 @@ 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. +It doesn't support passing the handle via URL. + +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. + +The supplied handle must already be valid in the calling process. +When launching @command{ffmpeg}, arrange for the child process to +inherit the handle before passing its numeric value with +@option{handle}. Handles opened with @code{FILE_FLAG_OVERLAPPED} +are not supported. Closing the protocol does not close the +caller's original handle. +@end table + @section http HTTP (Hyper Text Transfer Protocol). diff --git a/libavformat/Makefile b/libavformat/Makefile index 512e7ec214..02fb2b92f6 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -738,6 +738,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 fb344aef93..bb99198a6a 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[] = { @@ -223,7 +226,7 @@ static int fd_dup(URLContext *h, int oldfd) } #endif -#if CONFIG_FD_PROTOCOL || CONFIG_PIPE_PROTOCOL +#if CONFIG_FD_PROTOCOL || CONFIG_PIPE_PROTOCOL || CONFIG_WINDOWS_HANDLE_PROTOCOL /* Without a check, avio_check() would open the descriptor, rewinding seekable * output. It cannot pass the option selecting the descriptor, so just fail. */ static int fd_check(URLContext *h, int mask) @@ -544,6 +547,85 @@ 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 (handle == INVALID_HANDLE_VALUE || !handle) + return AVERROR(EBADF); + } + + if (!DuplicateHandle(GetCurrentProcess(), handle, + GetCurrentProcess(), &dup_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + return GetLastError() == ERROR_INVALID_HANDLE ? AVERROR(EBADF) + : AVERROR(EIO); + + fd = _open_osfhandle((intptr_t)dup_handle, O_BINARY); + 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, + .url_check = fd_check, + .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 367b40ee2c..aea09da498 100644 --- a/libavformat/protocols.c +++ b/libavformat/protocols.c @@ -80,6 +80,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 35d796d318..1b079ebce8 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFORMAT_VERSION_MINOR 8 +#define LIBAVFORMAT_VERSION_MINOR 9 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
