Skip to content

Commit

Permalink
AV profile and tier selection fix.
Browse files Browse the repository at this point in the history
Signed-off-by: Raju Konda <kraju@nvidia.com>
  • Loading branch information
krajunv authored and zlatinski committed Mar 11, 2025
1 parent 84b2703 commit 445200d
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 48 deletions.
86 changes: 50 additions & 36 deletions vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ int EncoderConfigAV1::DoParseArguments(int argc, char* argv[])
return 0;
}

bool EncoderConfigAV1::InitSequenceHeader(StdVideoAV1SequenceHeader *seqHdr)
bool EncoderConfigAV1::InitSequenceHeader(StdVideoAV1SequenceHeader *seqHdr,
StdVideoEncodeAV1OperatingPointInfo* opInfo)
{
memset(seqHdr, 0, sizeof(StdVideoAV1SequenceHeader));

Expand All @@ -180,6 +181,9 @@ bool EncoderConfigAV1::InitSequenceHeader(StdVideoAV1SequenceHeader *seqHdr)
seqHdr->flags.enable_cdef = enableCdef ? 1 : 0;
seqHdr->flags.enable_restoration = enableLr ? 1 : 0;

opInfo->seq_level_idx = level;
opInfo->seq_tier = tier;

return true;
}

Expand Down Expand Up @@ -260,49 +264,59 @@ int8_t EncoderConfigAV1::InitDpbCount()
return dpbCount;
}

bool EncoderConfigAV1::DetermineLevelTier()
bool EncoderConfigAV1::ValidateLevel(uint32_t lvl, uint32_t lvlTier)
{
uint32_t frameRateNum = (frameRateNumerator > 0) ? frameRateNumerator : (uint32_t)FRAME_RATE_NUM_DEFAULT;
uint32_t frameRateDenom = (frameRateDenominator > 0) ? frameRateDenominator : (uint32_t)FRAME_RATE_DEN_DEFAULT;
uint32_t picSize = encodeWidth * encodeHeight;
uint64_t displayRate = (frameRateNum * picSize) / frameRateDenom;
uint64_t decodeRate = ((frameRateNum + 0) * picSize) / frameRateDenom;
uint64_t displayRate = ((uint64_t)frameRateNum * picSize) / frameRateDenom;
uint64_t decodeRate = (((uint64_t)frameRateNum + 0) * picSize) / frameRateDenom;
uint32_t headerRate = (frameRateNum + 0) / frameRateDenom;

uint32_t lvl = STD_VIDEO_AV1_LEVEL_2_0;
if (levelLimits[lvl].level == STD_VIDEO_AV1_LEVEL_INVALID) return false;

if (picSize > levelLimits[lvl].maxPicSize) return false;
if (encodeWidth > levelLimits[lvl].maxHSize) return false;
if (encodeHeight > levelLimits[lvl].maxVSize) return false;
if (displayRate > levelLimits[lvl].maxDisplayRate) return false;
if (decodeRate > levelLimits[lvl].maxDecodeRate) return false;
if (headerRate > levelLimits[lvl].maxHeaderRate) return false;

if ((hrdBitrate != 0) || (averageBitrate != 0)) {
uint32_t _maxBitrate = std::max(hrdBitrate, averageBitrate);
uint32_t picSizeProfileFactor = (profile == STD_VIDEO_AV1_PROFILE_MAIN) ? 15 : ((profile == STD_VIDEO_AV1_PROFILE_HIGH ? 30 : 26));
// Estimate max compressed size to be up to 16 frames at average rate
uint32_t maxCompressedSize = std::max(1u, ((_maxBitrate << 4) / frameRateNum) * frameRateDenom);
double minCR = ((double)picSize * picSizeProfileFactor) / maxCompressedSize;

if (minCR < GetLevelMinCR(lvl, lvlTier, (double)decodeRate)) return false;
// Add a safety margin of 1.5x
if (((3 * _maxBitrate) >> 1) > GetLevelMaxBitrate(lvl, lvlTier)) return false;
}

return true;
}

// TODO: how to choose tier
tier = 0;
bool EncoderConfigAV1::DetermineLevelTier()
{
uint32_t lvl = STD_VIDEO_AV1_LEVEL_2_0;

for (; lvl <= STD_VIDEO_AV1_LEVEL_7_3; lvl++) {
if (levelLimits[lvl].level == STD_VIDEO_AV1_LEVEL_INVALID) continue;

level = (StdVideoAV1Level)lvl;

if (picSize > levelLimits[lvl].maxPicSize) continue;
if (encodeWidth > levelLimits[lvl].maxHSize) continue;
if (encodeHeight > levelLimits[lvl].maxVSize) continue;
if (displayRate > levelLimits[lvl].maxDisplayRate) continue;
if (decodeRate > levelLimits[lvl].maxDecodeRate) continue;
if (headerRate > levelLimits[lvl].maxHeaderRate) continue;

// TODO: if ratecontrol params are specified at the command line use the below code
// otherwise, use level max values.
//if (hrdBitrate != 0) {
// if (lvl > STD_VIDEO_AV1_LEVEL_4_0) {
// tier = 1;
// }
// uint32_t lvlBitrate = GetLevelBitrate();
// if (hrdBitrate > lvlBitrate) continue;
//}

// double minCompressRatio = GetMinCompressRatio(decodeRate);
// uint32_t compressedSize = 0; // TODO: How to estimate?
// uint32_t uncompressedSize = GetUncompressedSize();
// uint32_t compressedRatio = uncompressedSize / compressedSize;
// if (compressedRatio < minCompressRatio) continue;

break;
if (ValidateLevel(lvl, 0)) { // validate with tier 0
level = (StdVideoAV1Level)lvl;
tier = 0;
break;
}

if ((lvl >= STD_VIDEO_AV1_LEVEL_4_0) && ValidateLevel(lvl, 1)) { // validate with tier 1
level = (StdVideoAV1Level)lvl;
tier = 1;
break;
}
}
if (lvl > STD_VIDEO_AV1_LEVEL_7_3) {
level = STD_VIDEO_AV1_LEVEL_7_3;
tier = 0;
}

return true;
Expand All @@ -313,7 +327,7 @@ bool EncoderConfigAV1::InitRateControl()
DetermineLevelTier();

// use level max values for now. Limit it to 120Mbits/sec
uint32_t levelBitrate = std::min(GetLevelBitrate(), 120000000u);
uint32_t levelBitrate = std::min(GetLevelBitrate(level, tier), 120000000u);

// If no bitrate is specified, use the level limit
if (averageBitrate == 0) {
Expand Down
42 changes: 32 additions & 10 deletions vk_video_encoder/libs/VkVideoEncoder/VkEncoderConfigAV1.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,29 +124,53 @@ struct EncoderConfigAV1 : public EncoderConfig {
VkVideoEncodeAV1RateControlInfoKHR* rcInfoAV1,
VkVideoEncodeAV1RateControlLayerInfoKHR* rcLayerInfoAV1);

bool InitSequenceHeader(StdVideoAV1SequenceHeader* seqHeader);
bool InitSequenceHeader(StdVideoAV1SequenceHeader* seqHeader,
StdVideoEncodeAV1OperatingPointInfo* opInfo);

virtual EncoderConfigAV1* GetEncoderConfigAV1() override {
return this;
}

bool ValidateLevel(uint32_t lLevel, uint32_t lTier);

bool DetermineLevelTier();

uint32_t GetLevelMaxBitrate() {
return (tier == 0) ? levelLimits[level].mainBps : levelLimits[level].highBps;
uint32_t GetLevelMaxBitrate(uint32_t lLevel, uint32_t lTier) {
if (lLevel < STD_VIDEO_AV1_LEVEL_4_0) {
lTier = 0;
}

uint32_t _maxBitrate = lTier ? levelLimits[lLevel].highBps : levelLimits[lLevel].mainBps;
uint32_t bitrateProfileFactor = (profile == STD_VIDEO_AV1_PROFILE_MAIN) ? 1 :
((profile == STD_VIDEO_AV1_PROFILE_HIGH) ? 1 : 3);

return _maxBitrate * bitrateProfileFactor;
}

uint32_t GetLevelBitrate() {
double GetLevelMinCR(uint32_t lLevel, uint32_t lTier, double decodeRate) {
if (lLevel < STD_VIDEO_AV1_LEVEL_4_0) {
lTier = 0;
}

uint32_t minCRBase = lTier ? levelLimits[lLevel].highCR : levelLimits[lLevel].mainCR;
double speedAdj = decodeRate / levelLimits[lLevel].maxDisplayRate;

return std::max(minCRBase * speedAdj, 0.8);
}

uint32_t GetLevelBitrate(uint32_t lLevel, uint32_t lTier) {
if (lLevel < STD_VIDEO_AV1_LEVEL_4_0) {
lTier = 0;
}
uint32_t bitrateProfileFactor = (profile == STD_VIDEO_AV1_PROFILE_MAIN) ? 1 :
((profile == STD_VIDEO_AV1_PROFILE_HIGH) ? 2 : 3);
uint32_t _maxBitrate = (tier == 0) ? levelLimits[level].mainBps : levelLimits[level].highBps;
uint32_t _maxBitrate = (lTier == 0) ? levelLimits[lLevel].mainBps : levelLimits[lLevel].highBps;
return _maxBitrate * bitrateProfileFactor;
}

double GetMinCompressRatio(uint32_t decodeRate) {
double speedAdj = (double)decodeRate / (double)levelLimits[level].maxDisplayRate;
double minCompBasis = (tier == 0) ? levelLimits[level].mainCR : levelLimits[level].highCR;
double GetMinCompressRatio(uint32_t lLevel, uint32_t lTier, uint32_t decodeRate) {
double speedAdj = (double)decodeRate / (double)levelLimits[lLevel].maxDisplayRate;
double minCompBasis = (lTier == 0) ? levelLimits[lLevel].mainCR : levelLimits[lLevel].highCR;
return std::max(0.8, minCompBasis * speedAdj);
}

Expand All @@ -162,8 +186,6 @@ struct EncoderConfigAV1 : public EncoderConfig {
VkVideoEncodeAV1CapabilitiesKHR av1EncodeCapabilities{ VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR };
VkVideoEncodeAV1QualityLevelPropertiesKHR av1QualityLevelProperties{ VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_QUALITY_LEVEL_PROPERTIES_KHR };
VkVideoEncodeAV1QuantizationMapCapabilitiesKHR av1QuantizationMapCapabilities { VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_QUANTIZATION_MAP_CAPABILITIES_KHR };
uint32_t maxBitrate{};
uint32_t hrdBitrate{};
uint32_t vbvBufferSize{};
uint32_t vbvInitialDelay{};
uint32_t pic_width_in_sbs{};
Expand Down
4 changes: 2 additions & 2 deletions vk_video_encoder/libs/VkVideoEncoder/VkVideoEncoderAV1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ VkResult VkVideoEncoderAV1::InitEncoderCodec(VkSharedBaseObj<EncoderConfig>& enc

m_encoderConfig->GetRateControlParameters(&m_rateControlInfo, m_rateControlLayersInfo, &m_stateAV1.m_rateControlInfoAV1, m_stateAV1.m_rateControlLayersInfoAV1);

m_encoderConfig->InitSequenceHeader(&m_stateAV1.m_sequenceHeader);
m_encoderConfig->InitSequenceHeader(&m_stateAV1.m_sequenceHeader, m_stateAV1.m_operatingPointsInfo);

VideoSessionParametersInfoAV1 videoSessionParametersInfo(*m_videoSession, &m_stateAV1.m_sequenceHeader,
nullptr/*decoderModelInfo*/,
1, nullptr /*operatingPointsInfo*/,
1, m_stateAV1.m_operatingPointsInfo /*operatingPointsInfo*/,
encoderConfig->enableQpMap, m_qpMapTexelSize);
VkVideoSessionParametersCreateInfoKHR* encodeSessionParametersCreateInfo = videoSessionParametersInfo.getVideoSessionParametersInfo();
VkVideoSessionParametersKHR sessionParameters;
Expand Down

0 comments on commit 445200d

Please sign in to comment.