PR #23860 opened by David Rosca (nowrep) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23860 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23860.patch
# Summary of changes Fixes auto detect of level when not specified. Also fixes using level and tier options, which were previously ignored. <!-- If this PR requires new FATE test samples, attach them to the PR and list their target paths below (relative to the fate-suite root). Attached filenames must match the sample's filename: ```fate-samples # e.g. vorbis/new-sample.ogg ``` --> >From df174aa52764330786197b95d72e79cdfb51c17e Mon Sep 17 00:00:00 2001 From: David Rosca <[email protected]> Date: Mon, 20 Jul 2026 15:39:40 +0200 Subject: [PATCH 1/2] avcodec/vulkan_encode_av1: fix level auto-detection using zero dimensions Move level guessing from init_profile() to init_sequence_headers(), where base_ctx->surface_width/height are already initialized. init_profile() is called from ff_vulkan_encode_init() before the surface dimensions are set, so ff_av1_guess_level() always received zeros and selected the lowest level (2.0). init_sequence_headers() runs after ff_vulkan_encode_init() returns, matching how H.264 and H.265 Vulkan encoders handle level detection. Co-Authored-By: Claude Opus 4 --- libavcodec/vulkan_encode_av1.c | 50 ++++++++++++++++------------------ 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/libavcodec/vulkan_encode_av1.c b/libavcodec/vulkan_encode_av1.c index 1f38e691f1..994fc33cc1 100644 --- a/libavcodec/vulkan_encode_av1.c +++ b/libavcodec/vulkan_encode_av1.c @@ -593,7 +593,6 @@ static int init_profile(AVCodecContext *avctx, FFVulkanEncodeContext *ctx = &enc->common; FFVulkanContext *s = &ctx->s; FFVulkanFunctions *vk = &ctx->s.vkfn; - FFHWBaseEncodeContext *base_ctx = &ctx->base; VkVideoEncodeAV1CapabilitiesKHR av1_caps = { .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR, @@ -631,31 +630,6 @@ static int init_profile(AVCodecContext *avctx, }; profile->pNext = &enc->profile; - /* Set level */ - if (avctx->level == AV_LEVEL_UNKNOWN) { - const AV1LevelDescriptor *level; - float framerate = 0.0; - - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) - framerate = av_q2d(avctx->framerate); - - level = ff_av1_guess_level(avctx->bit_rate, enc->seq_tier, - base_ctx->surface_width, base_ctx->surface_height, - enc->tile_rows * enc->tile_cols, - enc->tile_cols, framerate); - if (level) { - av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); - enc->seq_level_idx = level->level_idx; - } else { - av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " - "any normal level, using level 7.3 by default.\n"); - enc->seq_level_idx = STD_VIDEO_AV1_LEVEL_7_3; - enc->seq_tier = 1; - } - } else { - enc->seq_level_idx = ff_vk_av1_level_to_vk(avctx->level); - } - /* User has explicitly specified a profile. */ if (avctx->profile != AV_PROFILE_UNKNOWN) return 0; @@ -750,6 +724,30 @@ static av_cold int init_sequence_headers(AVCodecContext *avctx) if (!desc) return AVERROR(EINVAL); + if (avctx->level == AV_LEVEL_UNKNOWN) { + const AV1LevelDescriptor *level; + float framerate = 0.0; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + framerate = av_q2d(avctx->framerate); + + level = ff_av1_guess_level(avctx->bit_rate, enc->seq_tier, + base_ctx->surface_width, base_ctx->surface_height, + enc->tile_rows * enc->tile_cols, + enc->tile_cols, framerate); + if (level) { + av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); + enc->seq_level_idx = level->level_idx; + } else { + av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " + "any normal level, using level 7.3 by default.\n"); + enc->seq_level_idx = STD_VIDEO_AV1_LEVEL_7_3; + enc->seq_tier = 1; + } + } else { + enc->seq_level_idx = ff_vk_av1_level_to_vk(avctx->level); + } + seq_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER; *seq = (AV1RawSequenceHeader) { .seq_profile = avctx->profile, -- 2.52.0 >From 4daca1c115abfbe551240403d2b4c4f001ce76f2 Mon Sep 17 00:00:00 2001 From: David Rosca <[email protected]> Date: Mon, 20 Jul 2026 15:45:52 +0200 Subject: [PATCH 2/2] avcodec/vulkan_encode_av1: fix level and tier option handling Copy opts.level into avctx->level (matching H.264/H.265 encoders), so the -level command line option is actually used. Also initialize enc->seq_tier from opts.tier so the -tier option takes effect. The -level option values (0-23) already match the StdVideoAV1Level enum directly, so assign avctx->level to seq_level_idx without going through ff_vk_av1_level_to_vk() which expects AV1 spec-style level numbers (20, 21, 30, ...). Co-Authored-By: Claude Opus 4 --- libavcodec/vulkan_encode_av1.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libavcodec/vulkan_encode_av1.c b/libavcodec/vulkan_encode_av1.c index 994fc33cc1..bb6a1ae04d 100644 --- a/libavcodec/vulkan_encode_av1.c +++ b/libavcodec/vulkan_encode_av1.c @@ -724,6 +724,8 @@ static av_cold int init_sequence_headers(AVCodecContext *avctx) if (!desc) return AVERROR(EINVAL); + enc->seq_tier = enc->common.opts.tier; + if (avctx->level == AV_LEVEL_UNKNOWN) { const AV1LevelDescriptor *level; float framerate = 0.0; @@ -745,7 +747,7 @@ static av_cold int init_sequence_headers(AVCodecContext *avctx) enc->seq_tier = 1; } } else { - enc->seq_level_idx = ff_vk_av1_level_to_vk(avctx->level); + enc->seq_level_idx = avctx->level; } seq_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER; @@ -1229,6 +1231,8 @@ static av_cold int vulkan_encode_av1_init(AVCodecContext *avctx) if (avctx->profile == AV_PROFILE_UNKNOWN) avctx->profile = enc->common.opts.profile; + if (avctx->level == AV_LEVEL_UNKNOWN) + avctx->level = enc->common.opts.level; enc->caps = (VkVideoEncodeAV1CapabilitiesKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR, -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
