PR #21183 opened by Lynne
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21183
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21183.patch
The issue is that .flush gets called asynchronously, and modifies the video
session state while its being used for decoding. This did not result in issues
since all known implementation do not keep important state there, but its not
compliant with the specs.
Its not necessary to flush the decoder when seeking, so simply don't.
>From c9299de723a42e2ec8b6fb53b898a79b68d7ffd7 Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sat, 13 Dec 2025 02:40:43 +0100
Subject: [PATCH 1/2] vulkan_decode: do not reset the decoder when flushing
The issue is that .flush gets called asynchronously, and modifies the
video session state while its being used for decoding. This did not
result in issues since all known vendors do not keep important state
there, but its not compliant with the specs.
Its not necessary to flush the decoder at all when seeking,
so simply don't.
---
libavcodec/vulkan_av1.c | 1 -
libavcodec/vulkan_dpx.c | 1 -
libavcodec/vulkan_ffv1.c | 1 -
libavcodec/vulkan_h264.c | 1 -
libavcodec/vulkan_hevc.c | 1 -
libavcodec/vulkan_prores.c | 1 -
libavcodec/vulkan_prores_raw.c | 1 -
libavcodec/vulkan_vp9.c | 1 -
8 files changed, 8 deletions(-)
diff --git a/libavcodec/vulkan_av1.c b/libavcodec/vulkan_av1.c
index 3a52d1f33a..3bee784a4f 100644
--- a/libavcodec/vulkan_av1.c
+++ b/libavcodec/vulkan_av1.c
@@ -662,7 +662,6 @@ const FFHWAccel ff_av1_vulkan_hwaccel = {
.init = &ff_vk_decode_init,
.update_thread_context = &ff_vk_update_thread_context,
.decode_params = &ff_vk_params_invalidate,
- .flush = &ff_vk_decode_flush,
.uninit = &ff_vk_decode_uninit,
.frame_params = &ff_vk_frame_params,
.priv_data_size = sizeof(FFVulkanDecodeContext),
diff --git a/libavcodec/vulkan_dpx.c b/libavcodec/vulkan_dpx.c
index 16ac10c5b8..d0466891fa 100644
--- a/libavcodec/vulkan_dpx.c
+++ b/libavcodec/vulkan_dpx.c
@@ -466,7 +466,6 @@ const FFHWAccel ff_dpx_vulkan_hwaccel = {
.init = &vk_decode_dpx_init,
.update_thread_context = &ff_vk_update_thread_context,
.decode_params = &ff_vk_params_invalidate,
- .flush = &ff_vk_decode_flush,
.uninit = &ff_vk_decode_uninit,
.frame_params = &ff_vk_frame_params,
.priv_data_size = sizeof(FFVulkanDecodeContext),
diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c
index 7d1e0c9ba7..643da9c551 100644
--- a/libavcodec/vulkan_ffv1.c
+++ b/libavcodec/vulkan_ffv1.c
@@ -1147,7 +1147,6 @@ const FFHWAccel ff_ffv1_vulkan_hwaccel = {
.init = &vk_decode_ffv1_init,
.update_thread_context = &ff_vk_update_thread_context,
.decode_params = &ff_vk_params_invalidate,
- .flush = &ff_vk_decode_flush,
.uninit = &ff_vk_decode_uninit,
.frame_params = &ff_vk_frame_params,
.priv_data_size = sizeof(FFVulkanDecodeContext),
diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c
index 8293f7ece9..5fc0f4c4cf 100644
--- a/libavcodec/vulkan_h264.c
+++ b/libavcodec/vulkan_h264.c
@@ -584,7 +584,6 @@ const FFHWAccel ff_h264_vulkan_hwaccel = {
.init = &ff_vk_decode_init,
.update_thread_context = &ff_vk_update_thread_context,
.decode_params = &ff_vk_params_invalidate,
- .flush = &ff_vk_decode_flush,
.uninit = &ff_vk_decode_uninit,
.frame_params = &ff_vk_frame_params,
.priv_data_size = sizeof(FFVulkanDecodeContext),
diff --git a/libavcodec/vulkan_hevc.c b/libavcodec/vulkan_hevc.c
index f609c4301f..8f0d1f6636 100644
--- a/libavcodec/vulkan_hevc.c
+++ b/libavcodec/vulkan_hevc.c
@@ -949,7 +949,6 @@ const FFHWAccel ff_hevc_vulkan_hwaccel = {
.init = &ff_vk_decode_init,
.update_thread_context = &ff_vk_update_thread_context,
.decode_params = &ff_vk_params_invalidate,
- .flush = &ff_vk_decode_flush,
.uninit = &ff_vk_decode_uninit,
.frame_params = &ff_vk_frame_params,
.priv_data_size = sizeof(FFVulkanDecodeContext),
diff --git a/libavcodec/vulkan_prores.c b/libavcodec/vulkan_prores.c
index 12e66876f2..e8c74b7863 100644
--- a/libavcodec/vulkan_prores.c
+++ b/libavcodec/vulkan_prores.c
@@ -567,7 +567,6 @@ const FFHWAccel ff_prores_vulkan_hwaccel = {
.init = &vk_decode_prores_init,
.update_thread_context = &ff_vk_update_thread_context,
.decode_params = &ff_vk_params_invalidate,
- .flush = &ff_vk_decode_flush,
.uninit = &ff_vk_decode_uninit,
.frame_params = &ff_vk_frame_params,
.priv_data_size = sizeof(FFVulkanDecodeContext),
diff --git a/libavcodec/vulkan_prores_raw.c b/libavcodec/vulkan_prores_raw.c
index cd025d25e6..0c7a97fa60 100644
--- a/libavcodec/vulkan_prores_raw.c
+++ b/libavcodec/vulkan_prores_raw.c
@@ -474,7 +474,6 @@ const FFHWAccel ff_prores_raw_vulkan_hwaccel = {
.init = &vk_decode_prores_raw_init,
.update_thread_context = &ff_vk_update_thread_context,
.decode_params = &ff_vk_params_invalidate,
- .flush = &ff_vk_decode_flush,
.uninit = &ff_vk_decode_uninit,
.frame_params = &ff_vk_frame_params,
.priv_data_size = sizeof(FFVulkanDecodeContext),
diff --git a/libavcodec/vulkan_vp9.c b/libavcodec/vulkan_vp9.c
index 6d0a5ce46f..5aeec3fb21 100644
--- a/libavcodec/vulkan_vp9.c
+++ b/libavcodec/vulkan_vp9.c
@@ -365,7 +365,6 @@ const FFHWAccel ff_vp9_vulkan_hwaccel = {
.frame_priv_data_size = sizeof(VP9VulkanDecodePicture),
.init = &ff_vk_decode_init,
.update_thread_context = &ff_vk_update_thread_context,
- .flush = &ff_vk_decode_flush,
.uninit = &ff_vk_decode_uninit,
.frame_params = &ff_vk_frame_params,
.priv_data_size = sizeof(FFVulkanDecodeContext),
--
2.49.1
>From 9da2129a992551ff19d9fb1df1cb3532c56eb7c9 Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sat, 13 Dec 2025 02:53:23 +0100
Subject: [PATCH 2/2] vulkan_decode: clean up decoder initialization
Now that we don't reset on every seek, we can simplify it.
---
libavcodec/vulkan_decode.c | 149 +++++++++++++++++++------------------
libavcodec/vulkan_decode.h | 7 --
2 files changed, 76 insertions(+), 80 deletions(-)
diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c
index 654149851d..b1e4b989ce 100644
--- a/libavcodec/vulkan_decode.c
+++ b/libavcodec/vulkan_decode.c
@@ -372,17 +372,66 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx,
FFVulkanDecodePicture *vp,
return 0;
}
-void ff_vk_decode_flush(AVCodecContext *avctx)
+static int create_empty_session_parameters(AVCodecContext *avctx,
+ FFVulkanDecodeShared *ctx,
+ VkVideoSessionParametersKHR
*empty_session_params)
{
- FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
- FFVulkanDecodeShared *ctx = dec->shared_ctx;
+ VkResult ret;
+ FFVulkanContext *s = &ctx->s;
+ FFVulkanFunctions *vk = &s->vkfn;
+
+ VkVideoDecodeH264SessionParametersCreateInfoKHR h264_params = {
+ .sType =
VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR,
+ };
+ VkVideoDecodeH265SessionParametersCreateInfoKHR h265_params = {
+ .sType =
VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR,
+ };
+ StdVideoAV1SequenceHeader av1_empty_seq = { 0 };
+ VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params = {
+ .sType =
VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR,
+ .pStdSequenceHeader = &av1_empty_seq,
+ };
+ VkVideoSessionParametersCreateInfoKHR session_params_create = {
+ .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR,
+ .pNext = avctx->codec_id == AV_CODEC_ID_H264 ? (void *)&h264_params :
+ avctx->codec_id == AV_CODEC_ID_HEVC ? (void *)&h265_params :
+ avctx->codec_id == AV_CODEC_ID_AV1 ? (void *)&av1_params :
+ NULL,
+ .videoSession = ctx->common.session,
+ };
+
+ if (avctx->codec_id == AV_CODEC_ID_VP9)
+ return 0;
+
+ ret = vk->CreateVideoSessionParametersKHR(s->hwctx->act_dev,
&session_params_create,
+ s->hwctx->alloc,
empty_session_params);
+ if (ret != VK_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to create empty Vulkan video
session parameters: %s!\n",
+ ff_vk_ret2str(ret));
+ return AVERROR_EXTERNAL;
+ }
+
+ return 0;
+}
+
+static int decode_reset(AVCodecContext *avctx, FFVulkanDecodeShared *ctx)
+{
+ int err;
+ FFVulkanContext *s = &ctx->s;
+ FFVulkanFunctions *vk = &s->vkfn;
- FFVulkanFunctions *vk = &ctx->s.vkfn;
VkVideoBeginCodingInfoKHR decode_start = {
.sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR,
.videoSession = ctx->common.session,
- .videoSessionParameters = ctx->empty_session_params,
};
+
+ if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) {
+ err = create_empty_session_parameters(avctx, ctx,
+
&decode_start.videoSessionParameters);
+ if (err < 0)
+ return err;
+ }
+
VkVideoCodingControlInfoKHR decode_ctrl = {
.sType = VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR,
.flags = VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR,
@@ -391,21 +440,25 @@ void ff_vk_decode_flush(AVCodecContext *avctx)
.sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR,
};
- VkCommandBuffer cmd_buf;
- FFVkExecContext *exec;
-
- /* Non-video queues do not need to be reset */
- if (!(get_codecdesc(avctx->codec_id)->decode_op))
- return;
-
- exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool);
+ FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool);
ff_vk_exec_start(&ctx->s, exec);
- cmd_buf = exec->buf;
- vk->CmdBeginVideoCodingKHR(cmd_buf, &decode_start);
- vk->CmdControlVideoCodingKHR(cmd_buf, &decode_ctrl);
- vk->CmdEndVideoCodingKHR(cmd_buf, &decode_end);
- ff_vk_exec_submit(&ctx->s, exec);
+ vk->CmdBeginVideoCodingKHR(exec->buf, &decode_start);
+ vk->CmdControlVideoCodingKHR(exec->buf, &decode_ctrl);
+ vk->CmdEndVideoCodingKHR(exec->buf, &decode_end);
+
+ err = ff_vk_exec_submit(&ctx->s, exec);
+
+ if (decode_start.videoSessionParameters) {
+ /* Wait to complete to delete the temporary session parameters */
+ if (err >= 0)
+ ff_vk_exec_wait(&ctx->s, exec);
+ vk->DestroyVideoSessionParametersKHR(s->hwctx->act_dev,
+
decode_start.videoSessionParameters,
+ s->hwctx->alloc);
+ }
+
+ return err;
}
int ff_vk_decode_frame(AVCodecContext *avctx,
@@ -651,7 +704,6 @@ static void free_common(AVRefStructOpaque unused, void *obj)
{
FFVulkanDecodeShared *ctx = obj;
FFVulkanContext *s = &ctx->s;
- FFVulkanFunctions *vk = &ctx->s.vkfn;
/* Wait on and free execution pool */
ff_vk_exec_pool_free(&ctx->s, &ctx->exec_pool);
@@ -659,12 +711,6 @@ static void free_common(AVRefStructOpaque unused, void
*obj)
/* This also frees all references from this pool */
av_frame_free(&ctx->common.layered_frame);
- /* Destroy parameters */
- if (ctx->empty_session_params)
- vk->DestroyVideoSessionParametersKHR(s->hwctx->act_dev,
- ctx->empty_session_params,
- s->hwctx->alloc);
-
av_buffer_pool_uninit(&ctx->buf_pool);
ff_vk_video_common_uninit(s, &ctx->common);
@@ -1237,47 +1283,6 @@ int ff_vk_decode_uninit(AVCodecContext *avctx)
return 0;
}
-static int create_empty_session_parameters(AVCodecContext *avctx,
- FFVulkanDecodeShared *ctx)
-{
- VkResult ret;
- FFVulkanContext *s = &ctx->s;
- FFVulkanFunctions *vk = &s->vkfn;
-
- VkVideoDecodeH264SessionParametersCreateInfoKHR h264_params = {
- .sType =
VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR,
- };
- VkVideoDecodeH265SessionParametersCreateInfoKHR h265_params = {
- .sType =
VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR,
- };
- StdVideoAV1SequenceHeader av1_empty_seq = { 0 };
- VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params = {
- .sType =
VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR,
- .pStdSequenceHeader = &av1_empty_seq,
- };
- VkVideoSessionParametersCreateInfoKHR session_params_create = {
- .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR,
- .pNext = avctx->codec_id == AV_CODEC_ID_H264 ? (void *)&h264_params :
- avctx->codec_id == AV_CODEC_ID_HEVC ? (void *)&h265_params :
- avctx->codec_id == AV_CODEC_ID_AV1 ? (void *)&av1_params :
- NULL,
- .videoSession = ctx->common.session,
- };
-
- if (avctx->codec_id == AV_CODEC_ID_VP9)
- return 0;
-
- ret = vk->CreateVideoSessionParametersKHR(s->hwctx->act_dev,
&session_params_create,
- s->hwctx->alloc,
&ctx->empty_session_params);
- if (ret != VK_SUCCESS) {
- av_log(avctx, AV_LOG_ERROR, "Unable to create empty Vulkan video
session parameters: %s!\n",
- ff_vk_ret2str(ret));
- return AVERROR_EXTERNAL;
- }
-
- return 0;
-}
-
int ff_vk_decode_init(AVCodecContext *avctx)
{
int err;
@@ -1405,11 +1410,11 @@ int ff_vk_decode_init(AVCodecContext *avctx)
}
if (!DECODER_IS_SDR(avctx->codec_id)) {
- if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) {
- err = create_empty_session_parameters(avctx, ctx);
- if (err < 0)
- return err;
- }
+ err = decode_reset(avctx, ctx);
+ if (err < 0)
+ return err;
+
+
} else {
/* For SDR decoders, this alignment value will be 0. Since this will
make
* add_slice() malfunction, set it to a sane default value. */
@@ -1424,8 +1429,6 @@ int ff_vk_decode_init(AVCodecContext *avctx)
driver_props->conformanceVersion.patch < 3)
dec->quirk_av1_offset = 1;
- ff_vk_decode_flush(avctx);
-
av_log(avctx, AV_LOG_VERBOSE, "Vulkan decoder initialization
successful\n");
return 0;
diff --git a/libavcodec/vulkan_decode.h b/libavcodec/vulkan_decode.h
index e32468f317..c75f0710db 100644
--- a/libavcodec/vulkan_decode.h
+++ b/libavcodec/vulkan_decode.h
@@ -46,8 +46,6 @@ typedef struct FFVulkanDecodeShared {
VkVideoCapabilitiesKHR caps;
VkVideoDecodeCapabilitiesKHR dec_caps;
- VkVideoSessionParametersKHR empty_session_params;
-
/* Software-defined decoder context */
void *sd_ctx;
void (*sd_ctx_free)(struct FFVulkanDecodeShared *ctx);
@@ -176,11 +174,6 @@ int ff_vk_get_decode_buffer(FFVulkanDecodeContext *ctx,
AVBufferRef **buf,
int ff_vk_decode_create_params(AVBufferRef **par_ref, void *logctx,
FFVulkanDecodeShared *ctx,
const VkVideoSessionParametersCreateInfoKHR
*session_params_create);
-/**
- * Flush decoder.
- */
-void ff_vk_decode_flush(AVCodecContext *avctx);
-
/**
* Free decoder.
*/
--
2.49.1
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]