From 37ab751e94df9a988ef9995bb6b621ddb0113ec2 Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Wed, 26 Nov 2025 16:04:37 +0530 Subject: [PATCH 1/9] encode: make H.264 level limits table readable This makes it easier to read and compare these limits against the data from table A-1 of the H.264 specification (from where these limits have been copied), and to add new entries if required in the future. Signed-off-by: Srinath Kumarapuram --- .../libs/VkVideoEncoder/VkEncoderConfigH264.h | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h index 6d8865a5..77ee1bd1 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h @@ -90,23 +90,23 @@ struct EncoderConfigH264 : public EncoderConfig { { // Level limits (Table A-1) static const LevelLimits levelLimitsTbl[] = { - // level_idc, maxMBPS, maxFS, maxDPB, maxBR, maxCPB, maxVmvR, prog, level - {10, 1485, 99, 148.5, 64, 175, 64, 1, STD_VIDEO_H264_LEVEL_IDC_1_0}, - {11, 3000, 396, 337.5, 192, 500, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_1}, - {12, 6000, 396, 891.0, 384, 1000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_2}, - {13, 11880, 396, 891.0, 768, 2000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_3}, - {20, 11880, 396, 891.0, 2000, 2000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_2_0}, - {21, 19800, 792, 1782.0, 4000, 4000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_2_1}, - {22, 20250, 1620, 3037.5, 4000, 4000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_2_2}, - {30, 40500, 1620, 3037.5, 10000, 10000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_3_0}, - {31, 108000, 3600, 6750.0, 14000, 14000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_3_1}, - {32, 216000, 5120, 7680.0, 20000, 20000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_3_2}, - {40, 245760, 8192, 12288.0, 20000, 25000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_0}, - {41, 245760, 8192, 12288.0, 50000, 62500, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_1}, - {42, 522240, 8704, 13056.0, 50000, 62500, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_2}, - {50, 589824, 22080, 41400.0, 135000, 135000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_0}, - {51, 983040, 36864, 69120.0, 240000, 240000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_1}, - {52, 2073600, 36864, 69120.0, 240000, 240000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_2}, + // level_idc, maxMBPS, maxFS, maxDPB, maxBR, maxCPB, maxVmvR, prog, level + {10, 1485, 99, 148.5, 64, 175, 64, 1, STD_VIDEO_H264_LEVEL_IDC_1_0}, + {11, 3000, 396, 337.5, 192, 500, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_1}, + {12, 6000, 396, 891.0, 384, 1000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_2}, + {13, 11880, 396, 891.0, 768, 2000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_3}, + {20, 11880, 396, 891.0, 2000, 2000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_2_0}, + {21, 19800, 792, 1782.0, 4000, 4000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_2_1}, + {22, 20250, 1620, 3037.5, 4000, 4000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_2_2}, + {30, 40500, 1620, 3037.5, 10000, 10000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_3_0}, + {31, 108000, 3600, 6750.0, 14000, 14000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_3_1}, + {32, 216000, 5120, 7680.0, 20000, 20000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_3_2}, + {40, 245760, 8192, 12288.0, 20000, 25000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_0}, + {41, 245760, 8192, 12288.0, 50000, 62500, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_1}, + {42, 522240, 8704, 13056.0, 50000, 62500, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_2}, + {50, 589824, 22080, 41400.0, 135000, 135000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_0}, + {51, 983040, 36864, 69120.0, 240000, 240000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_1}, + {52, 2073600, 36864, 69120.0, 240000, 240000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_2}, }; levelLimits = levelLimitsTbl; From 6e2dab3fdd0a20d04b1d1f09c9da4c037d59f792 Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Wed, 26 Nov 2025 16:37:37 +0530 Subject: [PATCH 2/9] encode: remove "prog" column from H.264 level limits table The values in this column have been taken from table A-4 of the H.264 specification and specify the value to be used for the SPS frame_mbs_only_flag syntax element for a given level. These values are not used anywhere in the code as interlaced encoding is not supported (and therefore frame_mbs_only_flag = 1 always). Signed-off-by: Srinath Kumarapuram --- .../libs/VkVideoEncoder/VkEncoderConfigH264.h | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h index 77ee1bd1..e0e027cd 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h @@ -54,7 +54,6 @@ struct EncoderConfigH264 : public EncoderConfig { uint32_t maxBR; // 1200 bits/s uint32_t maxCPB; // 1200 bits uint32_t maxVmvR; // [-MaxVmvR..+MaxVmvR-0.25] - uint32_t prog; // frame_mbs_only_flag = 1 StdVideoH264LevelIdc level; }; @@ -90,23 +89,23 @@ struct EncoderConfigH264 : public EncoderConfig { { // Level limits (Table A-1) static const LevelLimits levelLimitsTbl[] = { - // level_idc, maxMBPS, maxFS, maxDPB, maxBR, maxCPB, maxVmvR, prog, level - {10, 1485, 99, 148.5, 64, 175, 64, 1, STD_VIDEO_H264_LEVEL_IDC_1_0}, - {11, 3000, 396, 337.5, 192, 500, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_1}, - {12, 6000, 396, 891.0, 384, 1000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_2}, - {13, 11880, 396, 891.0, 768, 2000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_1_3}, - {20, 11880, 396, 891.0, 2000, 2000, 128, 1, STD_VIDEO_H264_LEVEL_IDC_2_0}, - {21, 19800, 792, 1782.0, 4000, 4000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_2_1}, - {22, 20250, 1620, 3037.5, 4000, 4000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_2_2}, - {30, 40500, 1620, 3037.5, 10000, 10000, 256, 0, STD_VIDEO_H264_LEVEL_IDC_3_0}, - {31, 108000, 3600, 6750.0, 14000, 14000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_3_1}, - {32, 216000, 5120, 7680.0, 20000, 20000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_3_2}, - {40, 245760, 8192, 12288.0, 20000, 25000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_0}, - {41, 245760, 8192, 12288.0, 50000, 62500, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_1}, - {42, 522240, 8704, 13056.0, 50000, 62500, 512, 0, STD_VIDEO_H264_LEVEL_IDC_4_2}, - {50, 589824, 22080, 41400.0, 135000, 135000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_0}, - {51, 983040, 36864, 69120.0, 240000, 240000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_1}, - {52, 2073600, 36864, 69120.0, 240000, 240000, 512, 0, STD_VIDEO_H264_LEVEL_IDC_5_2}, + // level_idc, maxMBPS, maxFS, maxDPB, maxBR, maxCPB, maxVmvR, level + {10, 1485, 99, 148.5, 64, 175, 64, STD_VIDEO_H264_LEVEL_IDC_1_0}, + {11, 3000, 396, 337.5, 192, 500, 128, STD_VIDEO_H264_LEVEL_IDC_1_1}, + {12, 6000, 396, 891.0, 384, 1000, 128, STD_VIDEO_H264_LEVEL_IDC_1_2}, + {13, 11880, 396, 891.0, 768, 2000, 128, STD_VIDEO_H264_LEVEL_IDC_1_3}, + {20, 11880, 396, 891.0, 2000, 2000, 128, STD_VIDEO_H264_LEVEL_IDC_2_0}, + {21, 19800, 792, 1782.0, 4000, 4000, 256, STD_VIDEO_H264_LEVEL_IDC_2_1}, + {22, 20250, 1620, 3037.5, 4000, 4000, 256, STD_VIDEO_H264_LEVEL_IDC_2_2}, + {30, 40500, 1620, 3037.5, 10000, 10000, 256, STD_VIDEO_H264_LEVEL_IDC_3_0}, + {31, 108000, 3600, 6750.0, 14000, 14000, 512, STD_VIDEO_H264_LEVEL_IDC_3_1}, + {32, 216000, 5120, 7680.0, 20000, 20000, 512, STD_VIDEO_H264_LEVEL_IDC_3_2}, + {40, 245760, 8192, 12288.0, 20000, 25000, 512, STD_VIDEO_H264_LEVEL_IDC_4_0}, + {41, 245760, 8192, 12288.0, 50000, 62500, 512, STD_VIDEO_H264_LEVEL_IDC_4_1}, + {42, 522240, 8704, 13056.0, 50000, 62500, 512, STD_VIDEO_H264_LEVEL_IDC_4_2}, + {50, 589824, 22080, 41400.0, 135000, 135000, 512, STD_VIDEO_H264_LEVEL_IDC_5_0}, + {51, 983040, 36864, 69120.0, 240000, 240000, 512, STD_VIDEO_H264_LEVEL_IDC_5_1}, + {52, 2073600, 36864, 69120.0, 240000, 240000, 512, STD_VIDEO_H264_LEVEL_IDC_5_2}, }; levelLimits = levelLimitsTbl; From fe29120c296f426a2e14590655b7c6570e5ab607 Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Wed, 26 Nov 2025 16:40:36 +0530 Subject: [PATCH 3/9] encode: add H.264 level limits for levels 6.0, 6.1, 6.2 These are defined in table A-1 of the H.264 specification but were missing from the level limits table defined in our code. These new entries also allow removing some workarounds where the level was previously artifically limited to level 5.2 as the maximum supported level. Signed-off-by: Srinath Kumarapuram --- .../libs/VkVideoEncoder/VkEncoderConfigH264.cpp | 16 +++------------- .../libs/VkVideoEncoder/VkEncoderConfigH264.h | 3 +++ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp index e9c94bed..062998b6 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp @@ -505,28 +505,18 @@ int8_t EncoderConfigH264::InitDpbCount() assert(pic_width_in_mbs > 0); assert(pic_height_in_map_units > 0); - uint32_t frameSizeInMbs = pic_width_in_mbs * pic_height_in_map_units; double frameRate = ((frameRateNumerator > 0) && (frameRateDenominator > 0)) ? (double)frameRateNumerator / frameRateDenominator : (double)FRAME_RATE_NUM_DEFAULT / (double)FRAME_RATE_DEN_DEFAULT; - // WAR for super HD resolution (bypass H264 level check for frame mode and use level 5.2) - if ((frameSizeInMbs > ((uint32_t)levelLimits[levelLimitsSize - 1].maxFS) || - ((frameSizeInMbs * frameRate) > ((uint32_t)levelLimits[levelLimitsSize - 1].maxMBPS)))) { - levelIdc = STD_VIDEO_H264_LEVEL_IDC_5_2; - } else { - // find lowest possible level - levelIdc = DetermineLevel(dpbCount, levelBitRate, vbvBufferSize, frameRate); - } + // find lowest possible level + levelIdc = DetermineLevel(dpbCount, levelBitRate, vbvBufferSize, frameRate); uint8_t levelDpbSize = (uint8_t)(((1024 * levelLimits[levelIdc].maxDPB)) / ((pic_width_in_mbs * pic_height_in_map_units) * 384)); - // XXX: If the level is 5.2, it is highly likely that we forced it to that - // value as a WAR for super HD. In that case, force the DPB size to - // DEFAULT_MAX_NUM_REF_FRAMES. Otherwise, clamp the computed DPB size to DEFAULT_MAX_NUM_REF_FRAMES. - levelDpbSize = (levelIdc == STD_VIDEO_H264_LEVEL_IDC_5_2) ? (uint8_t)DEFAULT_MAX_NUM_REF_FRAMES : std::min(uint8_t(DEFAULT_MAX_NUM_REF_FRAMES), levelDpbSize); + levelDpbSize = std::min(uint8_t(DEFAULT_MAX_NUM_REF_FRAMES), levelDpbSize); uint8_t dpbSize = (uint8_t)((dpbCount < 1) ? levelDpbSize : (uint8_t)(std::min((uint8_t)dpbCount, levelDpbSize))) + 1; diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h index e0e027cd..f1e9d061 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h @@ -106,6 +106,9 @@ struct EncoderConfigH264 : public EncoderConfig { {50, 589824, 22080, 41400.0, 135000, 135000, 512, STD_VIDEO_H264_LEVEL_IDC_5_0}, {51, 983040, 36864, 69120.0, 240000, 240000, 512, STD_VIDEO_H264_LEVEL_IDC_5_1}, {52, 2073600, 36864, 69120.0, 240000, 240000, 512, STD_VIDEO_H264_LEVEL_IDC_5_2}, + {60, 4177920, 139264, 261120.0, 240000, 240000, 8192, STD_VIDEO_H264_LEVEL_IDC_6_0}, + {61, 8355840, 139264, 261120.0, 480000, 480000, 8192, STD_VIDEO_H264_LEVEL_IDC_6_1}, + {62, 16711680, 139264, 261120.0, 800000, 800000, 8192, STD_VIDEO_H264_LEVEL_IDC_6_2}, }; levelLimits = levelLimitsTbl; From a8bb6ac6034c0add43f93eb31ac2b60be779bf03 Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Mon, 16 Feb 2026 16:36:53 +0530 Subject: [PATCH 4/9] EncoderConfigH264: Add InitProfileLevel for common profile and level init The codec profile and level are currently set in the following places: - level in EncoderConfigH264::InitDpbCount() - profile in EncoderConfigH264::InitSpsPpsParameters() The profile and level are fairly basic encoding parameters and it is desirable to set these as early as possible. This commit adds a method to the EncoderConfigH264 class which sets the profile and level at an early stage in the encoder configuration. This also provides the opportunity to use the codec profile in the construction of the video profile which will be used in physical device queries (currently, this video profile uses a default codec profile). This method gets called from EncoderConfigH264::InitializeParameters(), immediately after the command line parameters have been parsed and is part of the overall encoder config structure initialization process. The profile is more important than the level, so it is essential to set these values in this order, as done within this change. Also, certain level limits are profile-specific, and this ordering makes it possible for a subsequent change to use the profile in the level determination code. This commit also removes a check on the rate control mode when lossless encoding is requested, as the rate control mode may not have been specified by the user (and it will be determined later when querying the quality level properties). This change works as lossless encoding inherently requires the HIGH_444_PREDICTIVE profile regardless of rate control settings. Signed-off-by: Srinath Kumarapuram --- .../VkVideoEncoder/VkEncoderConfigH264.cpp | 83 ++++++++++--------- .../libs/VkVideoEncoder/VkEncoderConfigH264.h | 4 + 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp index 062998b6..35b408fa 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp @@ -310,11 +310,6 @@ bool EncoderConfigH264::InitSpsPpsParameters(StdVideoH264SequenceParameterSet *s sps->pic_order_cnt_type = STD_VIDEO_H264_POC_TYPE_2; } - // FIXME: Check if the HW supports transform_8x8_mode_is_supported - // based on capabilities or profiles supported - const bool transform_8x8_mode_is_supported = true; - const bool bIsFastestPreset = false; - if (adaptiveTransformMode == ADAPTIVE_TRANSFORM_ENABLE) { pps->flags.transform_8x8_mode_flag = true; if ((profileIdc == STD_VIDEO_H264_PROFILE_IDC_BASELINE) || @@ -326,12 +321,9 @@ bool EncoderConfigH264::InitSpsPpsParameters(StdVideoH264SequenceParameterSet *s pps->flags.transform_8x8_mode_flag = false; } else { // Autoselect - if (!bIsFastestPreset || transform_8x8_mode_is_supported) { - if ((profileIdc == STD_VIDEO_H264_PROFILE_IDC_INVALID) || - (profileIdc >= STD_VIDEO_H264_PROFILE_IDC_HIGH)) { - // Unconditionally enable 8x8 transform - pps->flags.transform_8x8_mode_flag = true; - } + if (profileIdc >= STD_VIDEO_H264_PROFILE_IDC_HIGH) { + // Unconditionally enable 8x8 transform + pps->flags.transform_8x8_mode_flag = true; } } @@ -348,28 +340,6 @@ bool EncoderConfigH264::InitSpsPpsParameters(StdVideoH264SequenceParameterSet *s pps->flags.constrained_intra_pred_flag = true; } - // If the profileIdc hasn't been specified, force set it now. - if (profileIdc == STD_VIDEO_H264_PROFILE_IDC_INVALID) { - profileIdc = STD_VIDEO_H264_PROFILE_IDC_BASELINE; - - if (entropyCodingMode == ENTROPY_CODING_MODE_CABAC) { - profileIdc = STD_VIDEO_H264_PROFILE_IDC_MAIN; - } - - if ((gopStructure.GetConsecutiveBFrameCount() > 0) || pps->flags.entropy_coding_mode_flag || !sps->flags.frame_mbs_only_flag) - profileIdc = STD_VIDEO_H264_PROFILE_IDC_MAIN; - - if (pps->flags.transform_8x8_mode_flag) { - profileIdc = STD_VIDEO_H264_PROFILE_IDC_HIGH; - } - - if ((sps->flags.qpprime_y_zero_transform_bypass_flag && - (rateControlMode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR)) || - (sps->chroma_format_idc == STD_VIDEO_H264_CHROMA_FORMAT_IDC_444)) { - profileIdc = STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE; - } - } - sps->profile_idc = profileIdc; sps->level_idc = levelIdc; @@ -491,14 +461,44 @@ VkResult EncoderConfigH264::InitDeviceCapabilities(const VulkanDeviceContext* vk return VK_SUCCESS; } -int8_t EncoderConfigH264::InitDpbCount() +void EncoderConfigH264::InitProfileLevel() { - dpbCount = 0; // TODO: What is the need for this? + // FIXME: Check if the HW supports transform_8x8_mode_is_supported + // based on capabilities or profiles supported + bool use8x8Transform = true; + + if (adaptiveTransformMode == ADAPTIVE_TRANSFORM_ENABLE) { + use8x8Transform = true; + } else if (adaptiveTransformMode == ADAPTIVE_TRANSFORM_DISABLE) { + use8x8Transform = false; + } else { + // Autoselect + if ((profileIdc == STD_VIDEO_H264_PROFILE_IDC_INVALID) || + (profileIdc >= STD_VIDEO_H264_PROFILE_IDC_HIGH)) { + // Unconditionally enable 8x8 transform + use8x8Transform = true; + } + } + + // If the profileIdc hasn't been specified, force set it now. + if (profileIdc == STD_VIDEO_H264_PROFILE_IDC_INVALID) { + profileIdc = STD_VIDEO_H264_PROFILE_IDC_BASELINE; + + // Upgrade to MAIN profile if using B-frames or CABAC entropy coding + if ((gopStructure.GetConsecutiveBFrameCount() > 0) || (entropyCodingMode == ENTROPY_CODING_MODE_CABAC)) + profileIdc = STD_VIDEO_H264_PROFILE_IDC_MAIN; + + if (use8x8Transform) { + profileIdc = STD_VIDEO_H264_PROFILE_IDC_HIGH; + } + + // Upgrade to HIGH_444_PREDICTIVE for lossless encoding or 4:4:4 chroma + if ((tuningMode == VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR) || + (input.chromaSubsampling == VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR)) { + profileIdc = STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE; + } + } - // spsInfo->level represents the smallest level that we require for the - // given stream. This level constrains the maximum size (in terms of - // number of frames) that the DPB can have. levelDpbSize is this maximum - // value. uint32_t levelBitRate = ((rateControlMode != VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) && hrdBitrate == 0) ? averageBitrate // constrained by avg bitrate : hrdBitrate; // constrained by max bitrate @@ -512,6 +512,11 @@ int8_t EncoderConfigH264::InitDpbCount() // find lowest possible level levelIdc = DetermineLevel(dpbCount, levelBitRate, vbvBufferSize, frameRate); +} + +int8_t EncoderConfigH264::InitDpbCount() +{ + dpbCount = 0; // TODO: What is the need for this? uint8_t levelDpbSize = (uint8_t)(((1024 * levelLimits[levelIdc].maxDPB)) / ((pic_width_in_mbs * pic_height_in_map_units) * 384)); diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h index f1e9d061..4e692c21 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h @@ -180,6 +180,8 @@ struct EncoderConfigH264 : public EncoderConfig { pic_height_in_map_units = DivUp(encodeHeight, 16); if ((pic_width_in_mbs > 0) && (pic_height_in_map_units > 0)) { + // Initialize codec profile and level based on encoder configuration + InitProfileLevel(); return VK_SUCCESS; } @@ -187,6 +189,8 @@ struct EncoderConfigH264 : public EncoderConfig { return VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR; } + void InitProfileLevel(); + virtual VkResult InitDeviceCapabilities(const VulkanDeviceContext* vkDevCtx) override; virtual uint32_t GetDefaultVideoProfileIdc() override { return STD_VIDEO_H264_PROFILE_IDC_HIGH; }; From f341c6be4b270edc11ff8a5a61e2906977702fa2 Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Tue, 25 Nov 2025 14:57:04 +0530 Subject: [PATCH 5/9] encode: update H.264 level limits based on the profile The level determination code in EncoderConfigH264::DetermineLevel() uses a multipler of 1200 for the MaxBR and MaxCPB entries in the level limits table, taken from table A-1 of the H.264 specification. However, this multipler is to be used only for the Baseline, Constrained Baseline, Main and Extended profiles. Profiles greater than these use a different (larger) multipler, as specified in table A-2 of the H.264 specification. Due to the use of a smaller multipler, this code selects a greater level than is strictly necessary in some situations, based on the input settings. This commit updates this code to use a multipler dependent on the codec profile. Signed-off-by: Srinath Kumarapuram --- .../libs/VkVideoEncoder/VkEncoderConfigH264.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp index 35b408fa..07a623e7 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.cpp @@ -63,6 +63,13 @@ StdVideoH264LevelIdc EncoderConfigH264::DetermineLevel(uint8_t dpbSize, uint32_t _vbvBufferSize, double frameRate) { + uint32_t cpbBrNalFactor = 1200; + + // Adjust cpbBrNalFactor depending on whether the High (or greater) profile + // is being used + if (profileIdc >= STD_VIDEO_H264_PROFILE_IDC_HIGH) { + cpbBrNalFactor = (profileIdc >= STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE) ? 4800 : 1500; + } uint32_t frameSizeInMbs = pic_width_in_mbs * pic_height_in_map_units; for (uint32_t idx = 0; idx < levelLimitsSize; idx++) { @@ -71,8 +78,8 @@ StdVideoH264LevelIdc EncoderConfigH264::DetermineLevel(uint8_t dpbSize, if ((frameSizeInMbs) > ((uint32_t)levelLimits[idx].maxFS)) continue; if ((frameSizeInMbs * numRefFrames * 384) > levelLimits[idx].maxDPB * 1024) continue; - if ((bitrate != 0) && (bitrate > ((uint32_t)levelLimits[idx].maxBR * 1200))) continue; - if ((_vbvBufferSize != 0) && (_vbvBufferSize > ((uint32_t)levelLimits[idx].maxCPB * 1200))) continue; + if ((bitrate != 0) && (bitrate > ((uint32_t)levelLimits[idx].maxBR * cpbBrNalFactor))) continue; + if ((_vbvBufferSize != 0) && (_vbvBufferSize > ((uint32_t)levelLimits[idx].maxCPB * cpbBrNalFactor))) continue; return levelLimits[idx].level; } From b02b0772043fa9db52b06024184f21323c28b175 Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Mon, 16 Feb 2026 17:28:35 +0530 Subject: [PATCH 6/9] EncoderConfigH265: Add InitProfileLevel for common profile, level, tier init This commit adds an InitProfileLevel() method similar to what EncoderConfigH264 contains, for common initialization of the codec profile, level and tier. This makes use of the preexisting profile and levelIdc members defined in EncoderConfigH265 but not used otherwise. With this addition, the InitParamameters() and InitRateControl() methods have been changed to remove the redundant and repetitive initialization of the profile and level. The codec profile and level determined earlier in the encoder config initialization are now used directly instead. Signed-off-by: Srinath Kumarapuram --- .../VkVideoEncoder/VkEncoderConfigH265.cpp | 56 ++++++++++--------- .../libs/VkVideoEncoder/VkEncoderConfigH265.h | 10 +++- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.cpp b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.cpp index 33bcc53e..89cfe7e6 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.cpp +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.cpp @@ -513,15 +513,34 @@ StdVideoH265ProfileTierLevel EncoderConfigH265::GetLevelTier() return profileTierLevel; } -bool EncoderConfigH265::InitRateControl() +void EncoderConfigH265::InitProfileLevel() { - StdVideoH265ProfileTierLevel profileTierLevel = GetLevelTier(); - // Assigning default main profile if invalid. - if (profileTierLevel.general_profile_idc == STD_VIDEO_H265_PROFILE_IDC_INVALID) { - profileTierLevel.general_profile_idc = STD_VIDEO_H265_PROFILE_IDC_MAIN; + // If profile hasn't been specified, determine it based on bit depth and chroma + if (profile == STD_VIDEO_H265_PROFILE_IDC_INVALID) { + if (encodeChromaSubsampling == VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR) { + if (input.bpp == 8) { + profile = STD_VIDEO_H265_PROFILE_IDC_MAIN; + } else if (input.bpp <= 10) { + profile = STD_VIDEO_H265_PROFILE_IDC_MAIN_10; + } else { + profile = STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS; + } + } else { + // 4:2:2 or 4:4:4 requires Range Extensions profile + profile = STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS; + } } - uint32_t level = profileTierLevel.general_level_idc; - if (level >= levelLimitsTblSize) { + + // Determine level and tier based on resolution, bitrate, etc. + StdVideoH265ProfileTierLevel profileTierLevel = GetLevelTier(); + levelIdc = profileTierLevel.general_level_idc; + general_tier_flag = profileTierLevel.flags.general_tier_flag; +} + +bool EncoderConfigH265::InitRateControl() +{ + // Level is already initialized by InitProfileLevel() + if (levelIdc >= levelLimitsTblSize) { assert(!"The h.265 level index is invalid"); return false; } @@ -529,7 +548,7 @@ bool EncoderConfigH265::InitRateControl() // Safe default maximum bitrate uint32_t levelBitRate = std::max(averageBitrate, hrdBitrate); - levelBitRate = std::max(levelBitRate, std::min(levelLimits[level].maxBitRateMainTier * 800u, 120000000u)); + levelBitRate = std::max(levelBitRate, std::min(levelLimits[levelIdc].maxBitRateMainTier * 800u, 120000000u)); // If no bitrate is specified, use the level limit if (averageBitrate == 0) { @@ -553,7 +572,7 @@ bool EncoderConfigH265::InitRateControl() // Use the main tier level limit for the max VBV buffer size, and no more than 8 seconds at peak rate if (vbvBufferSize == 0) { - vbvBufferSize = std::min(levelLimits[level].maxCPBSizeMainTier * cpbVclFactor, 100000000u); + vbvBufferSize = std::min(levelLimits[levelIdc].maxCPBSizeMainTier * cpbVclFactor, 100000000u); if (rateControlMode != VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { if ((vbvBufferSize >> 3) > hrdBitrate) { vbvBufferSize = hrdBitrate << 3; @@ -626,7 +645,9 @@ bool EncoderConfigH265::InitParamameters(VpsH265 *vpsInfo, SpsH265 *spsInfo, spsInfo->decPicBufMgr.max_num_reorder_pics[i] = gopStructure.GetConsecutiveBFrameCount() ? 1 : 0; } - spsInfo->profileTierLevel = GetLevelTier(); + // Use pre-initialized profile, level, and tier from InitProfileLevel() + spsInfo->profileTierLevel.general_profile_idc = profile; + spsInfo->profileTierLevel.general_level_idc = levelIdc; spsInfo->profileTierLevel.flags.general_tier_flag = general_tier_flag; // Always insert profile tier flags assuming frame mode @@ -636,21 +657,6 @@ bool EncoderConfigH265::InitParamameters(VpsH265 *vpsInfo, SpsH265 *spsInfo, spsInfo->profileTierLevel.flags.general_non_packed_constraint_flag = 0; spsInfo->profileTierLevel.flags.general_frame_only_constraint_flag = 1; - // Assigning default main profile if invalid. - if (spsInfo->profileTierLevel.general_profile_idc == STD_VIDEO_H265_PROFILE_IDC_INVALID) { - if (encodeChromaSubsampling == VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR) { - if (input.bpp == 8) { - spsInfo->profileTierLevel.general_profile_idc = STD_VIDEO_H265_PROFILE_IDC_MAIN; - } else if (input.bpp == 10) { - spsInfo->profileTierLevel.general_profile_idc = STD_VIDEO_H265_PROFILE_IDC_MAIN_10; - } else { - spsInfo->profileTierLevel.general_profile_idc = STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS; - } - } else { - spsInfo->profileTierLevel.general_profile_idc = STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS; - } - } - const uint32_t ctbLog2SizeY = cuSize + 3; const uint32_t minCbLog2SizeY = cuMinSize + 3; const uint32_t log2MinTransformBlockSize = std::min(minCbLog2SizeY, minTransformUnitSize + 2U); diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h index 774bf1a9..2149d88d 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h @@ -83,8 +83,8 @@ struct EncoderConfigH265 : public EncoderConfig { size_t levelLimitsTblSize; EncoderConfigH265() - : profile(STD_VIDEO_H265_PROFILE_IDC_MAIN) - , levelIdc(STD_VIDEO_H265_LEVEL_IDC_5_2) + : profile(STD_VIDEO_H265_PROFILE_IDC_INVALID) + , levelIdc(STD_VIDEO_H265_LEVEL_IDC_INVALID) , h265EncodeCapabilities() , general_tier_flag(false) , numRefL0(1) @@ -147,10 +147,16 @@ struct EncoderConfigH265 : public EncoderConfig { if (result != VK_SUCCESS) { return result; } + + // Initialize profile, level, and tier based on encoder configuration + InitProfileLevel(); + // TODO: more h.265 parameters init ... return VK_SUCCESS; } + void InitProfileLevel(); + virtual VkResult InitDeviceCapabilities(const VulkanDeviceContext* vkDevCtx) override; virtual uint32_t GetDefaultVideoProfileIdc() override { return STD_VIDEO_H265_PROFILE_IDC_MAIN; }; From b8e01efffd6319dfffeffc35cb25e05e24dfb51f Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Fri, 6 Feb 2026 12:12:16 +0530 Subject: [PATCH 7/9] EncoderConfigH265: rename GetLevelTier to DetermineLevelTier This change is not a plain renaming, as it also modifies the method to directly set the level and tier members in the class instead of initializing and returning a StdVideoH265ProfileTierLevel structure. The method name is also now consistent with that for the other codecs. Signed-off-by: Srinath Kumarapuram --- .../VkVideoEncoder/VkEncoderConfigH265.cpp | 21 +++++++------------ .../libs/VkVideoEncoder/VkEncoderConfigH265.h | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.cpp b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.cpp index 89cfe7e6..8b041b9d 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.cpp +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.cpp @@ -483,25 +483,24 @@ void EncoderConfigH265::InitializeSpsRefPicSet(SpsH265 *pSps) memset(&pSps->longTermRefPicsSps.lt_ref_pic_poc_lsb_sps, 0, sizeof(pSps->longTermRefPicsSps.lt_ref_pic_poc_lsb_sps)); } -StdVideoH265ProfileTierLevel EncoderConfigH265::GetLevelTier() +void EncoderConfigH265::DetermineLevelTier() { - StdVideoH265ProfileTierLevel profileTierLevel{}; - profileTierLevel.general_profile_idc = STD_VIDEO_H265_PROFILE_IDC_INVALID; - profileTierLevel.general_level_idc = STD_VIDEO_H265_LEVEL_IDC_INVALID; + levelIdc = STD_VIDEO_H265_LEVEL_IDC_INVALID; + general_tier_flag = 0; uint32_t levelIdx = 0; for (; levelIdx < levelLimitsTblSize; levelIdx++) { if (IsSuitableLevel(levelIdx, 0)) { - profileTierLevel.general_level_idc = levelLimits[levelIdx].stdLevel; - profileTierLevel.flags.general_tier_flag = 0; // Main tier + levelIdc = levelLimits[levelIdx].stdLevel; + general_tier_flag = 0; // Main tier break; } if ((levelLimits[levelIdx].levelIdc >= 120) && // level 4.0 and above IsSuitableLevel(levelIdx, 1)) { - profileTierLevel.general_level_idc = levelLimits[levelIdx].stdLevel; - profileTierLevel.flags.general_tier_flag = 1; // Main tier + levelIdc = levelLimits[levelIdx].stdLevel; + general_tier_flag = 1; // High tier break; } } @@ -509,8 +508,6 @@ StdVideoH265ProfileTierLevel EncoderConfigH265::GetLevelTier() if (levelIdx >= levelLimitsTblSize) { assert(!"No suitable level selected"); } - - return profileTierLevel; } void EncoderConfigH265::InitProfileLevel() @@ -532,9 +529,7 @@ void EncoderConfigH265::InitProfileLevel() } // Determine level and tier based on resolution, bitrate, etc. - StdVideoH265ProfileTierLevel profileTierLevel = GetLevelTier(); - levelIdc = profileTierLevel.general_level_idc; - general_tier_flag = profileTierLevel.flags.general_tier_flag; + DetermineLevelTier(); } bool EncoderConfigH265::InitRateControl() diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h index 2149d88d..4eae0069 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h @@ -197,7 +197,7 @@ struct EncoderConfigH265 : public EncoderConfig { StdVideoH265SequenceParameterSetVui* vui = nullptr); bool IsSuitableLevel(uint32_t levelIdx, bool highTier); - StdVideoH265ProfileTierLevel GetLevelTier(); + void DetermineLevelTier(); void InitializeSpsRefPicSet(SpsH265 *pSps); }; From deaad4d4e6f78901e59796c245f6e2ad3414813c Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Mon, 16 Feb 2026 17:34:38 +0530 Subject: [PATCH 8/9] EncoderConfigAV1: Add InitProfileLevel for common profile, level, tier init This commit adds an InitProfileLevel() method similar to what EncoderConfigH264 and EncoderConfigH265 contain, for common initialization of the codec profile, level and tier. With this addition, the InitRateControl() method have been changed to remove the redundant and repetitive initialization of the level and tier. The codec profile and level determined earlier in the encoder config initialization are now used directly instead. Signed-off-by: Srinath Kumarapuram --- .../VkVideoEncoder/VkEncoderConfigAV1.cpp | 26 +++++++++++++++++-- .../libs/VkVideoEncoder/VkEncoderConfigAV1.h | 8 ++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.cpp b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.cpp index c3ba67c1..24cee2ef 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.cpp +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.cpp @@ -285,6 +285,29 @@ VkResult EncoderConfigAV1::InitDeviceCapabilities(const VulkanDeviceContext* vkD return VK_SUCCESS; } +void EncoderConfigAV1::InitProfileLevel() +{ + // If profile hasn't been specified, determine it based on bit depth and chroma + if (profile == STD_VIDEO_AV1_PROFILE_INVALID) { + // PROFESSIONAL is required for 12-bit or 422 + if ((input.bpp > 10) || + (encodeChromaSubsampling == VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR)) { + profile = STD_VIDEO_AV1_PROFILE_PROFESSIONAL; + } + // HIGH is required for 444 chroma + else if (encodeChromaSubsampling == VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR) { + profile = STD_VIDEO_AV1_PROFILE_HIGH; + } + // MAIN supports 8-bit and 10-bit with 420 + else { + profile = STD_VIDEO_AV1_PROFILE_MAIN; + } + } + + // Determine level and tier based on encoder configuration + DetermineLevelTier(); +} + int8_t EncoderConfigAV1::InitDpbCount() { dpbCount = STD_VIDEO_AV1_NUM_REF_FRAMES + 1; // BUFFER_POOL_MAX_SIZE = Number of frames in buffer pool = 10 @@ -351,8 +374,7 @@ bool EncoderConfigAV1::DetermineLevelTier() bool EncoderConfigAV1::InitRateControl() { - DetermineLevelTier(); - + // Level and tier are already initialized by InitProfileLevel() // use level max values for now. Limit it to 120Mbits/sec uint32_t levelBitrate = std::min(GetLevelBitrate(level, tier), 120000000u); diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h index 622977d6..54c9ce8e 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h @@ -102,6 +102,8 @@ struct EncoderConfigAV1 : public EncoderConfig { pic_height_in_sbs = DivUp(encodeHeight, 16); if ((pic_width_in_sbs > 0) && (pic_height_in_sbs > 0)) { + // Initialize profile, level, and tier based on encoder configuration + InitProfileLevel(); return VK_SUCCESS; } @@ -111,6 +113,8 @@ struct EncoderConfigAV1 : public EncoderConfig { virtual VkResult InitDeviceCapabilities(const VulkanDeviceContext* vkDevCtx) override; + void InitProfileLevel(); + virtual uint32_t GetDefaultVideoProfileIdc() override { return STD_VIDEO_AV1_PROFILE_MAIN; } virtual int8_t InitDpbCount() override; @@ -185,8 +189,8 @@ struct EncoderConfigAV1 : public EncoderConfig { return ((encodeWidth * encodeHeight * picSizeProfileFactor) >> 3); } - StdVideoAV1Profile profile{ STD_VIDEO_AV1_PROFILE_MAIN }; - StdVideoAV1Level level{ STD_VIDEO_AV1_LEVEL_5_0 }; + StdVideoAV1Profile profile{ STD_VIDEO_AV1_PROFILE_INVALID }; + StdVideoAV1Level level{ STD_VIDEO_AV1_LEVEL_INVALID }; uint8_t tier{}; VkVideoEncodeAV1CapabilitiesKHR av1EncodeCapabilities{ VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR }; VkVideoEncodeAV1QualityLevelPropertiesKHR av1QualityLevelProperties{ VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_QUALITY_LEVEL_PROPERTIES_KHR }; From 4fba129e2ced9bd4645c65e94ca508d9abacbd84 Mon Sep 17 00:00:00 2001 From: Srinath Kumarapuram Date: Mon, 16 Feb 2026 17:43:42 +0530 Subject: [PATCH 9/9] encode: remove videoProfileIdc and GetDefaultVideoProfileIdc() Currently, the video profile constructed for querying capabilities or quality level properties uses the videoProfileIdc member from the encoder config for the codec profile, or calls GetDefaultVideoProfileIdc() if that member is not initialized. No code initializes videoProfileIdc to a proper value, so GetDefaultVideoProfileIdc() gets called always and returns a fixed value for each codec. However, this fixed codec profile may not support all of the coding tools requested by the user when encoding, or may even be incompatible with the codec profile actually needed for encoding. We already have code in the InitProfileLevel() method to determine the codec profile based on various encoding features (B-frames, CABAC, bit depth, chroma format, etc.). This change makes the video profile construction code use this codec profile, thereby eliminating redundant profile storage and computation. The main changes in this refactoring are: - Remove videoProfileIdc member variable from EncoderConfig base class - Replace GetDefaultVideoProfileIdc() virtual method with GetCodecProfile() - Add GetCodecProfile() implementations in H.264/H.265/AV1 that return the already-initialized codec-specific profile members - Update InitVideoProfile() to call GetCodecProfile() instead of using videoProfileIdc - Add an assertion in each GetCodecProfile() implementation to ensure that the profile is initialized With this change, the codec profile is determined once and used everywhere else in the codebase. Signed-off-by: Srinath Kumarapuram --- vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.cpp | 6 ++++-- vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.h | 5 ++--- vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h | 5 ++++- vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h | 5 ++++- vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h | 5 ++++- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.cpp b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.cpp index 9918d573..56d4d804 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.cpp +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.cpp @@ -823,13 +823,15 @@ void EncoderConfig::InitVideoProfile() encodeBitDepthChroma = encodeBitDepthLuma; } + // Get the codec-specific profile (already set by InitProfileLevel) + uint32_t codecProfile = GetCodecProfile(); + // update the video profile videoCoreProfile = VkVideoCoreProfile::CreateEncodeProfile( codec, encodeChromaSubsampling, GetComponentBitDepthFlagBits(encodeBitDepthLuma), GetComponentBitDepthFlagBits(encodeBitDepthChroma), - (videoProfileIdc != (uint32_t)-1) ? videoProfileIdc : - GetDefaultVideoProfileIdc(), + codecProfile, tuningMode); } diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.h index 8ad4b161..35e0727f 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfig.h @@ -685,7 +685,6 @@ struct EncoderConfig : public VkVideoRefCountBase { bool noDeviceFallback; VkVideoCodecOperationFlagBitsKHR codec; bool useDpbArray; - uint32_t videoProfileIdc; uint32_t numInputImages; EncoderInputImageParameters input; uint8_t encodeBitDepthLuma; @@ -793,7 +792,6 @@ struct EncoderConfig : public VkVideoRefCountBase { , noDeviceFallback(false) , codec(VK_VIDEO_CODEC_OPERATION_NONE_KHR) , useDpbArray(false) - , videoProfileIdc((uint32_t)-1) , numInputImages(DEFAULT_NUM_INPUT_IMAGES) , input() , encodeBitDepthLuma(0) @@ -961,7 +959,8 @@ struct EncoderConfig : public VkVideoRefCountBase { // These functions should be overwritten from the codec-specific classes virtual VkResult InitDeviceCapabilities(const VulkanDeviceContext* vkDevCtx) { return VK_ERROR_INITIALIZATION_FAILED; }; - virtual uint32_t GetDefaultVideoProfileIdc() { return 0; }; + // Returns the codec-specific profile identifier (must be set by InitProfileLevel first) + virtual uint32_t GetCodecProfile() = 0; virtual int8_t InitDpbCount() { return 16; }; diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h index 54c9ce8e..58168822 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h @@ -115,7 +115,10 @@ struct EncoderConfigAV1 : public EncoderConfig { void InitProfileLevel(); - virtual uint32_t GetDefaultVideoProfileIdc() override { return STD_VIDEO_AV1_PROFILE_MAIN; } + virtual uint32_t GetCodecProfile() override { + assert(profile != STD_VIDEO_AV1_PROFILE_INVALID); + return static_cast(profile); + } virtual int8_t InitDpbCount() override; diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h index 4e692c21..32546503 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH264.h @@ -193,7 +193,10 @@ struct EncoderConfigH264 : public EncoderConfig { virtual VkResult InitDeviceCapabilities(const VulkanDeviceContext* vkDevCtx) override; - virtual uint32_t GetDefaultVideoProfileIdc() override { return STD_VIDEO_H264_PROFILE_IDC_HIGH; }; + virtual uint32_t GetCodecProfile() override { + assert(profileIdc != STD_VIDEO_H264_PROFILE_IDC_INVALID); + return static_cast(profileIdc); + } // 1. First h.264 determine the number of the Dpb buffers required virtual int8_t InitDpbCount() override; diff --git a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h index 4eae0069..39fcf019 100644 --- a/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h +++ b/vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigH265.h @@ -159,7 +159,10 @@ struct EncoderConfigH265 : public EncoderConfig { virtual VkResult InitDeviceCapabilities(const VulkanDeviceContext* vkDevCtx) override; - virtual uint32_t GetDefaultVideoProfileIdc() override { return STD_VIDEO_H265_PROFILE_IDC_MAIN; }; + virtual uint32_t GetCodecProfile() override { + assert(profile != STD_VIDEO_H265_PROFILE_IDC_INVALID); + return static_cast(profile); + } // 1. First h.265 determine the number of the Dpb buffers required virtual int8_t InitDpbCount() override;