From b8249f73a7c74c28d84c080978ac264ec3eb70b0 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Sun, 4 Oct 2026 03:34:44 +0200 Subject: [PATCH] avutil/hwcontext: add av_hwframe_get_transfer_buffer() It allocates the buffers of a software frame used for a transfer to or from a hardware frames context out of a pool kept by that context. Assisted-by: Claude --- doc/APIchanges | 3 +++ libavutil/hwcontext.c | 34 ++++++++++++++++++++++++++++++++++ libavutil/hwcontext.h | 15 +++++++++++++++ libavutil/hwcontext_internal.h | 9 +++++++++ libavutil/version.h | 2 +- 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index 42d539990f..323b88af8f 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2026-06-23. API changes, most recent first: +2026-10-xx - xxxxxxxxxx - lavu 61.16.100 - hwcontext.h + Add av_hwframe_get_transfer_buffer(). + 2026-10-xx - xxxxxxxxxx - lavu 61.15.100 - encryption_info.h Add av_encryption_init_info_append_side_data(). diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c index c9e7d99f1d..2c3bd2eeaa 100644 --- a/libavutil/hwcontext.c +++ b/libavutil/hwcontext.c @@ -21,6 +21,7 @@ #include "avassert.h" #include "buffer.h" #include "common.h" +#include "frame_internal.h" #include "hwcontext.h" #include "hwcontext_internal.h" #include "imgutils.h" @@ -246,6 +247,9 @@ static void hwframe_ctx_free(void *opaque, uint8_t *data) if (ctxi->pool_internal) av_buffer_pool_uninit(&ctxi->pool_internal); + av_buffer_pool_uninit(&ctxi->transfer_pool); + ff_mutex_destroy(&ctxi->transfer_pool_lock); + if (ctxi->hw_type->frames_uninit) ctxi->hw_type->frames_uninit(ctx); @@ -273,6 +277,11 @@ AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in) return NULL; ctx = &ctxi->p; + if (ff_mutex_init(&ctxi->transfer_pool_lock, NULL)) { + av_free(ctxi); + return NULL; + } + if (hw_type->frames_hwctx_size) { ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size); if (!ctx->hwctx) @@ -301,6 +310,7 @@ AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in) fail: av_buffer_unref(&device_ref); + ff_mutex_destroy(&ctxi->transfer_pool_lock); av_freep(&ctx->hwctx); av_freep(&ctx); return NULL; @@ -395,6 +405,30 @@ int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref, return ctxi->hw_type->transfer_get_formats(&ctxi->p, dir, formats); } +static AVBufferRef *transfer_buffer_alloc(void *opaque, size_t size) +{ + FFHWFramesContext *ctxi = opaque; + AVBufferRef *buf = NULL; + + ff_mutex_lock(&ctxi->transfer_pool_lock); + if (ctxi->transfer_pool_size != size) { + av_buffer_pool_uninit(&ctxi->transfer_pool); + ctxi->transfer_pool = av_buffer_pool_init(size, NULL); + ctxi->transfer_pool_size = ctxi->transfer_pool ? size : 0; + } + if (ctxi->transfer_pool) + buf = av_buffer_pool_get(ctxi->transfer_pool); + ff_mutex_unlock(&ctxi->transfer_pool_lock); + + return buf; +} + +int av_hwframe_get_transfer_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame) +{ + return ff_frame_get_video_buffer(frame, 0, transfer_buffer_alloc, + hwframe_ctx->data); +} + static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags) { AVHWFramesContext *ctx; diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h index 29374cf0a7..5a73f368a1 100644 --- a/libavutil/hwcontext.h +++ b/libavutil/hwcontext.h @@ -372,6 +372,21 @@ int av_hwframe_ctx_init(AVBufferRef *ref); */ int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame, int flags); +/** + * Allocate the buffers of a software frame that data is transferred to or + * from frames of the given AVHWFramesContext. + * + * Frames allocated otherwise can be transferred as well, as described for + * av_hwframe_transfer_data(). The buffers allocated here are pooled, and may be + * in memory that the device transfers faster. + * + * @param hwframe_ctx a reference to an AVHWFramesContext + * @param frame a video frame with format, width and height set and no + * data buffers + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwframe_get_transfer_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame); + /** * Copy data to or from a hw surface. At least one of dst/src must have an * AVHWFramesContext attached. diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h index dcfdc2016a..33e34b9d65 100644 --- a/libavutil/hwcontext_internal.h +++ b/libavutil/hwcontext_internal.h @@ -23,6 +23,7 @@ #include "buffer.h" #include "hwcontext.h" +#include "thread.h" #include "frame.h" #include "pixfmt.h" @@ -100,6 +101,14 @@ typedef struct FFHWFramesContext { AVBufferPool *pool_internal; + /** + * Buffers of transfer_pool_size bytes for av_hwframe_get_transfer_buffer(), + * both guarded by transfer_pool_lock. + */ + AVBufferPool *transfer_pool; + size_t transfer_pool_size; + AVMutex transfer_pool_lock; + /** * For a derived context, a reference to the original frames * context it was derived from. diff --git a/libavutil/version.h b/libavutil/version.h index 9f1429987a..812815937b 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 61 -#define LIBAVUTIL_VERSION_MINOR 15 +#define LIBAVUTIL_VERSION_MINOR 16 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \