Commit b8249f73a7 for ffmpeg

commit b8249f73a7c74c28d84c080978ac264ec3eb70b0
Author: Michael Niedermayer <michael@niedermayer.cc>
Date:   Sun Oct 4 03:34:44 2026 +0200

    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

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, \