Commit cb032dc37b for ffmpeg
commit cb032dc37b394dc21f31f03942604cbdc40ecf81
Author: lusoris <lusoris@proton.me>
Date: Fri Oct 30 14:38:31 2026 +0100
avutil/hwcontext_vulkan: keep frame internals after failed CUDA imports
A failure while importing a frame's memory or semaphores into CUDA freed
all of its internal state. The frame stays in its pool, so the next
transfer on it crashed locking the freed update_mutex, and every other
use of the frame would have done the same.
Release only the partial CUDA import, clear the handles so the next
transfer imports again, and take the image back from the external queue.
Signed-off-by: lusoris <lusoris@proton.me>
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index 43baef0cef..023b11224e 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -2403,6 +2403,51 @@ static int alloc_mem(AVHWDeviceContext *ctx, VkMemoryRequirements *req,
return 0;
}
+#if CONFIG_CUDA
+static void vulkan_free_internal_cuda(AVVkFrameInternal *internal)
+{
+ AVHWFramesContext *cuda_fc;
+ AVHWDeviceContext *cuda_cu;
+ AVCUDADeviceContext *cuda_dev;
+ AVCUDADeviceContextInternal *cu_internal;
+ CudaFunctions *cu;
+ int planes;
+
+ if (!internal->cuda_fc_ref)
+ return;
+
+ cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
+ planes = av_pix_fmt_count_planes(cuda_fc->sw_format);
+ cuda_cu = cuda_fc->device_ctx;
+ cuda_dev = cuda_cu->hwctx;
+ cu_internal = cuda_dev->internal;
+ cu = cu_internal->cuda_dl;
+
+ for (int i = 0; i < planes; i++) {
+ if (internal->cu_sem[i])
+ CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
+ if (internal->cu_mma[i])
+ CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
+ if (internal->ext_mem[i])
+ CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
+ internal->cu_sem[i] = NULL;
+ internal->cu_mma[i] = NULL;
+ internal->cu_array[i] = NULL;
+ internal->ext_mem[i] = NULL;
+#ifdef _WIN32
+ if (internal->ext_sem_handle[i])
+ CloseHandle(internal->ext_sem_handle[i]);
+ if (internal->ext_mem_handle[i])
+ CloseHandle(internal->ext_mem_handle[i]);
+ internal->ext_sem_handle[i] = NULL;
+ internal->ext_mem_handle[i] = NULL;
+#endif
+ }
+
+ av_buffer_unref(&internal->cuda_fc_ref);
+}
+#endif
+
static void vulkan_free_internal(VulkanDevicePriv *p, AVVkFrame *f)
{
av_unused AVVkFrameInternal *internal = f->internal;
@@ -2412,31 +2457,7 @@ static void vulkan_free_internal(VulkanDevicePriv *p, AVVkFrame *f)
return;
#if CONFIG_CUDA
- if (internal->cuda_fc_ref) {
- AVHWFramesContext *cuda_fc = (AVHWFramesContext *)internal->cuda_fc_ref->data;
- int planes = av_pix_fmt_count_planes(cuda_fc->sw_format);
- AVHWDeviceContext *cuda_cu = cuda_fc->device_ctx;
- AVCUDADeviceContext *cuda_dev = cuda_cu->hwctx;
- AVCUDADeviceContextInternal *cu_internal = cuda_dev->internal;
- CudaFunctions *cu = cu_internal->cuda_dl;
-
- for (int i = 0; i < planes; i++) {
- if (internal->cu_sem[i])
- CHECK_CU(cu->cuDestroyExternalSemaphore(internal->cu_sem[i]));
- if (internal->cu_mma[i])
- CHECK_CU(cu->cuMipmappedArrayDestroy(internal->cu_mma[i]));
- if (internal->ext_mem[i])
- CHECK_CU(cu->cuDestroyExternalMemory(internal->ext_mem[i]));
-#ifdef _WIN32
- if (internal->ext_sem_handle[i])
- CloseHandle(internal->ext_sem_handle[i]);
- if (internal->ext_mem_handle[i])
- CloseHandle(internal->ext_mem_handle[i]);
-#endif
- }
-
- av_buffer_unref(&internal->cuda_fc_ref);
- }
+ vulkan_free_internal_cuda(internal);
#endif
if (internal->drm_sync_sem != VK_NULL_HANDLE)
@@ -4275,7 +4296,9 @@ static int vulkan_export_to_cuda(AVHWFramesContext *hwfc,
return 0;
fail:
- vulkan_free_internal(p, dst_f);
+ /* Only the import failed: the frame is still valid and stays in its pool,
+ * and the next transfer starts the import over. */
+ vulkan_free_internal_cuda(dst_int);
return err;
}
@@ -4311,10 +4334,8 @@ static int vulkan_transfer_data_from_cuda(AVHWFramesContext *hwfc,
return err;
err = vulkan_export_to_cuda(hwfc, src->hw_frames_ctx, dst);
- if (err < 0) {
- CHECK_CU(cu->cuCtxPopCurrent(&dummy));
- return err;
- }
+ if (err < 0)
+ goto fail;
dst_int = dst_f->internal;
@@ -5240,10 +5261,8 @@ static int vulkan_transfer_data_to_cuda(AVHWFramesContext *hwfc, AVFrame *dst,
return err;
err = vulkan_export_to_cuda(hwfc, dst->hw_frames_ctx, src);
- if (err < 0) {
- CHECK_CU(cu->cuCtxPopCurrent(&dummy));
- return err;
- }
+ if (err < 0)
+ goto fail;
dst_int = dst_f->internal;