feat(linux/vaapi): VAAPI encoder improvements (#5388)

This commit is contained in:
Conn O'Griofa
2026-07-15 15:41:22 +01:00
committed by GitHub
parent 1621100a85
commit 71acfc57ec
8 changed files with 393 additions and 28 deletions

View File

@@ -308,8 +308,33 @@ namespace va {
BOOST_LOG(info) << "Using normal encoding mode"sv;
}
// When the compression_level AVOption is set, vaapi_encode.c assigns the value to VAEncMiscParameterBufferQualityLevel
VAConfigAttrib quality_attr = {VAConfigAttribEncQualityRange};
auto status = vaGetConfigAttributes(va_display, va_profile, va_entrypoint, &quality_attr, 1);
if (status != VA_STATUS_SUCCESS || quality_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
quality_attr.value = 0;
}
auto vaapi_quality = config::video.vaapi.vaapi_quality.value_or(0);
auto target_quality = 0;
switch (vaapi_quality) {
default:
case 0: // auto or unset
break;
case 1: // low quality (highest value in range)
case 2: // med quality (middle value in range)
target_quality = quality_attr.value / vaapi_quality;
break;
case 3: // high quality (1)
target_quality = 1;
break;
}
if (quality_attr.value > 0) {
ctx->compression_level = target_quality;
BOOST_LOG(info) << "[VAAPI] Quality level set to "sv << ctx->compression_level << " (fastest level: "sv << quality_attr.value << ")"sv;
}
VAConfigAttrib rc_attr = {VAConfigAttribRateControl};
auto status = vaGetConfigAttributes(va_display, va_profile, va_entrypoint, &rc_attr, 1);
status = vaGetConfigAttributes(va_display, va_profile, va_entrypoint, &rc_attr, 1);
if (status != VA_STATUS_SUCCESS) {
// Stick to the default rate control (CQP)
rc_attr.value = 0;
@@ -337,27 +362,52 @@ namespace va {
// When we have to resort to the default 1 second VBV for encoding quality reasons,
// we stick to CBR in order to avoid encoding huge frames after bitrate undershoots
// leave headroom available in the RC window.
if (config::video.vaapi.strict_rc_buffer ||
(vendor && strstr(vendor, "Intel")) ||
ctx->codec_id == AV_CODEC_ID_AV1) {
ctx->rc_buffer_size = ctx->bit_rate * ctx->framerate.den / ctx->framerate.num;
//
// If a user-supplied rate control is detected, override the whitelist logic to allow
// full user control of both the rate control and strict VBV settings.
auto auto_whitelist = false;
auto rc_mode = config::video.vaapi.vaapi_rc_str;
auto rc_vbv = "with standard VBV size";
auto rc_whitelist = "";
auto rc_val = config::video.vaapi.vaapi_rc.value_or(0);
if (rc_attr.value & VA_RC_VBR) {
BOOST_LOG(info) << "Using VBR with single frame VBV size"sv;
av_dict_set(options, "rc_mode", "VBR", 0);
} else if (rc_attr.value & VA_RC_CBR) {
BOOST_LOG(info) << "Using CBR with single frame VBV size"sv;
av_dict_set(options, "rc_mode", "CBR", 0);
} else {
BOOST_LOG(warning) << "Using CQP with single frame VBV size"sv;
av_dict_set_int(options, "qp", config::video.qp, 0);
}
} else if (!(rc_attr.value & (VA_RC_CBR | VA_RC_VBR))) {
BOOST_LOG(warning) << "Using CQP rate control"sv;
av_dict_set_int(options, "qp", config::video.qp, 0);
} else {
BOOST_LOG(info) << "Using default rate control"sv;
// Detect whitelisted configurations
if ((vendor && std::string_view(vendor).contains("Intel") == true) || ctx->codec_id == AV_CODEC_ID_AV1) {
auto_whitelist = true;
rc_whitelist = " (whitelist override)";
}
// First try user config, else fall back to auto-detection that respects whitelist
if (rc_val > 0 && rc_attr.value & rc_val) {
// override whitelist if the user-specified RC is supported
auto_whitelist = false;
rc_whitelist = "";
} else if (rc_attr.value & VA_RC_VBR && auto_whitelist) {
rc_mode = "vbr";
rc_val = VA_RC_VBR;
} else if (rc_attr.value & VA_RC_CBR) {
rc_mode = "cbr";
rc_val = VA_RC_CBR;
} else {
rc_mode = "cqp";
rc_val = VA_RC_CQP;
}
if (config::video.vaapi.strict_rc_buffer || auto_whitelist) {
ctx->rc_buffer_size = ctx->bit_rate * ctx->framerate.den / ctx->framerate.num;
rc_vbv = "with single frame VBV size";
}
// ffmpeg's rc_mode values don't align with VAAPI's rc_val values, so transform string to uppercase
std::transform(rc_mode.begin(), rc_mode.end(), rc_mode.begin(), [](unsigned char c) {
return std::toupper(c);
});
av_dict_set(options, "rc_mode", rc_mode.c_str(), 0);
if (rc_val == VA_RC_CQP || rc_val == VA_RC_ICQ || rc_val == VA_RC_QVBR) {
BOOST_LOG(warning) << "[VAAPI] Applying QP for compatible rate control method (QP value: "sv << config::video.qp << ")"sv;
av_dict_set_int(options, "qp", config::video.qp, 0);
}
BOOST_LOG(info) << "[VAAPI] Using "sv << rc_mode << " rate control "sv << rc_vbv << rc_whitelist;
}
/**