Commit 6930ddb3dc for ffmpeg

commit 6930ddb3dc312e7d38f51c5aa35a7c63590ec21d
Author: lusoris <lusoris@proton.me>
Date:   Fri Oct 30 14:37:41 2026 +0100

    avutil/hwcontext_vulkan: keep frames after failed CUDA transfers

    When cuWaitExternalSemaphoresAsync, cuMemcpy2DAsync or
    cuSignalExternalSemaphoresAsync failed, the transfer freed the internal
    state of the Vulkan frame and unreferenced the destination's first
    buffer. The caller still owns the destination, and the Vulkan frame
    stays in its pool, so the next transfer on that frame crashed locking
    the freed update_mutex in ff_vk_exec_add_dep_frame().

    Return the error and leave both frames alone. Wait for commands queued
    before the failure and take the image back from the external queue,
    as a successful transfer does.

    Signed-off-by: lusoris <lusoris@proton.me>

diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index 0ddfafb1b8..43baef0cef 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -4286,7 +4286,6 @@ static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
     CUcontext dummy;
     AVVkFrame *dst_f;
     AVVkFrameInternal *dst_int;
-    VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
     VulkanFramesPriv *fp = hwfc->hwctx;
     const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
@@ -4366,9 +4365,11 @@ static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
     return err = prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);

 fail:
+    /* Commands queued before the failure may still use the image, and the
+     * frame stays usable, so return it the way a successful transfer does. */
+    CHECK_CU(cu->cuStreamSynchronize(cuda_dev->stream));
     CHECK_CU(cu->cuCtxPopCurrent(&dummy));
-    vulkan_free_internal(p, dst_f);
-    av_buffer_unref(&dst->buf[0]);
+    prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
     return err;
 }
 #endif
@@ -5214,7 +5215,6 @@ static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
     CUcontext dummy;
     AVVkFrame *dst_f;
     AVVkFrameInternal *dst_int;
-    VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
     VulkanFramesPriv *fp = hwfc->hwctx;
     const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
@@ -5294,9 +5294,11 @@ static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
     return prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);

 fail:
+    /* Commands queued before the failure may still use the image, and the
+     * frame stays usable, so return it the way a successful transfer does. */
+    CHECK_CU(cu->cuStreamSynchronize(cuda_dev->stream));
     CHECK_CU(cu->cuCtxPopCurrent(&dummy));
-    vulkan_free_internal(p, dst_f);
-    av_buffer_unref(&dst->buf[0]);
+    prepare_frame(hwfc, &fp->upload_exec, dst_f, PREP_MODE_EXTERNAL_IMPORT);
     return err;
 }
 #endif