From 369bf509c603559abcaff6f1ddddcd1da92be290 Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Thu, 24 Sep 2026 22:22:15 +0100 Subject: [PATCH 1/4] fix(linux/vaapi): validate quality configuration, add Intel quirk * Validate quality levels against driver before committing to AVOptions dict. * Add quirk for intermediate quality value on Intel cards. --- src/platform/linux/vaapi.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/platform/linux/vaapi.cpp b/src/platform/linux/vaapi.cpp index c98f0b82ba6..5cc28791404 100644 --- a/src/platform/linux/vaapi.cpp +++ b/src/platform/linux/vaapi.cpp @@ -280,6 +280,26 @@ namespace va { return VAProfileNone; } + /** + * @brief Determines if a specific VA quality level is supported. + * + * @return True if supported. + */ + + bool is_quality_level_supported(VADisplay dpy, VAProfile profile, VAEntrypoint entrypoint, int quality_level) { + VAConfigAttrib attrib = { + .type = VAConfigAttribEncQualityRange, + .value = static_cast(quality_level) + }; + VAConfigID config_id; + + if (VAStatus status = vaCreateConfig(dpy, profile, entrypoint, &attrib, 1, &config_id); status == VA_STATUS_SUCCESS) { + vaDestroyConfig(dpy, config_id); + return true; + } + return false; + } + /** * @brief Initialize codec options. * @@ -322,15 +342,19 @@ namespace va { break; case 1: // low quality (highest value in range) case 2: // med quality (middle value in range) - target_quality = quality_attr.value / vaapi_quality; + // Calculate the true midpoint between 1 and max quality range. + // For an odd max like 7, (1 + 7) / 2 = 4. For even like 6, (1 + 6) / 2 = 3. + target_quality = (1 + quality_attr.value / vaapi_quality); break; case 3: // high quality (1) target_quality = 1; break; } - if (quality_attr.value > 0) { + if (is_quality_level_supported(va_display, va_profile, va_entrypoint, target_quality)) { ctx->compression_level = target_quality; BOOST_LOG(info) << "[VAAPI] Quality level set to "sv << ctx->compression_level << " (fastest level: "sv << quality_attr.value << ")"sv; + } else { + BOOST_LOG(warning) << "[VAAPI] Quality level "sv << target_quality << " is not supported."sv; } VAConfigAttrib rc_attr = {.type = VAConfigAttribRateControl}; From 23b992e42178baa4dc2b702a3aa1c7c933d6ef48 Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Thu, 24 Sep 2026 23:48:07 +0100 Subject: [PATCH 2/4] fixup: refactor to reduce CC --- src/platform/linux/vaapi.cpp | 77 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/platform/linux/vaapi.cpp b/src/platform/linux/vaapi.cpp index 5cc28791404..93f0447a0fb 100644 --- a/src/platform/linux/vaapi.cpp +++ b/src/platform/linux/vaapi.cpp @@ -281,23 +281,52 @@ namespace va { } /** - * @brief Determines if a specific VA quality level is supported. - * - * @return True if supported. + * @brief Probes driver support for a specific VA quality level via vaCreateConfig, + * then sets compression_level to the validated value. Note: vaGetConfigAttributes only + * reports whether the QualityRange attribute is supported and its max value — it does not + * validate individual levels within that range, so vaCreateConfig is used as the actual check. */ + void set_quality_level(AVCodecContext *va_ctx, VADisplay dpy, VAProfile va_profile, VAEntrypoint va_entrypoint, int quality_level) { + // When the compression_level value is set, vaapi_encode.c assigns the value to VAEncMiscParameterBufferQualityLevel + VAConfigAttrib quality_attr = {.type = VAConfigAttribEncQualityRange}; + auto quality_status = vaGetConfigAttributes(dpy, va_profile, va_entrypoint, &quality_attr, 1); + if (quality_status != VA_STATUS_SUCCESS || quality_attr.value == VA_ATTRIB_NOT_SUPPORTED) { + quality_attr.value = 0; + } + auto target_quality = 0; + switch (quality_level) { + case 0: // auto or unset + break; + case 1: // low quality (highest value in range) + target_quality = quality_attr.value; + break; + case 2: // med quality (middle value in range) + // Calculate the true midpoint between 1 and max quality range. + // For an odd max like 7, (1 + 7) / 2 = 4. For even like 6, (1 + 6) / 2 = 3. + target_quality = (1 + quality_attr.value) / 2; + break; + case 3: // high quality (1) + target_quality = 1; + break; + default: + break; + } - bool is_quality_level_supported(VADisplay dpy, VAProfile profile, VAEntrypoint entrypoint, int quality_level) { VAConfigAttrib attrib = { .type = VAConfigAttribEncQualityRange, - .value = static_cast(quality_level) + .value = static_cast(target_quality) }; VAConfigID config_id; - if (VAStatus status = vaCreateConfig(dpy, profile, entrypoint, &attrib, 1, &config_id); status == VA_STATUS_SUCCESS) { + if (VAStatus status = vaCreateConfig(dpy, va_profile, va_entrypoint, &attrib, 1, &config_id); status == VA_STATUS_SUCCESS) { vaDestroyConfig(dpy, config_id); - return true; + va_ctx->compression_level = target_quality; + BOOST_LOG(info) << "[VAAPI] Quality level set to "sv << va_ctx->compression_level + << " (fastest level: "sv << quality_attr.value << ")"sv; + } else { + BOOST_LOG(warning) << "[VAAPI] Quality level "sv << target_quality + << " is not supported by the driver; using default."sv; } - return false; } /** @@ -328,37 +357,11 @@ 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 = {.type = 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) - // Calculate the true midpoint between 1 and max quality range. - // For an odd max like 7, (1 + 7) / 2 = 4. For even like 6, (1 + 6) / 2 = 3. - target_quality = (1 + quality_attr.value / vaapi_quality); - break; - case 3: // high quality (1) - target_quality = 1; - break; - } - if (is_quality_level_supported(va_display, va_profile, va_entrypoint, target_quality)) { - ctx->compression_level = target_quality; - BOOST_LOG(info) << "[VAAPI] Quality level set to "sv << ctx->compression_level << " (fastest level: "sv << quality_attr.value << ")"sv; - } else { - BOOST_LOG(warning) << "[VAAPI] Quality level "sv << target_quality << " is not supported."sv; - } + // Validate and set quality level + set_quality_level(ctx, va_display, va_profile, va_entrypoint, config::video.vaapi.vaapi_quality.value_or(0)); VAConfigAttrib rc_attr = {.type = VAConfigAttribRateControl}; - status = vaGetConfigAttributes(va_display, va_profile, va_entrypoint, &rc_attr, 1); + auto 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; From 1a952d3e400b5f4aeffb992bcbc06ad979fc6d4a Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Fri, 25 Sep 2026 02:24:10 +0100 Subject: [PATCH 3/4] fixup: doxygen errors --- src/platform/linux/vaapi.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/platform/linux/vaapi.cpp b/src/platform/linux/vaapi.cpp index 93f0447a0fb..b77857cafd2 100644 --- a/src/platform/linux/vaapi.cpp +++ b/src/platform/linux/vaapi.cpp @@ -285,6 +285,12 @@ namespace va { * then sets compression_level to the validated value. Note: vaGetConfigAttributes only * reports whether the QualityRange attribute is supported and its max value — it does not * validate individual levels within that range, so vaCreateConfig is used as the actual check. + * + * @param va_ctx AVCodecContext context. + * @param dpy VA display. + * @param va_profile VA profile. + * @param va_profile VA entrypoint. + * @param quality_level Requested quality level to be translated into equivalent per-driver VA quality value. */ void set_quality_level(AVCodecContext *va_ctx, VADisplay dpy, VAProfile va_profile, VAEntrypoint va_entrypoint, int quality_level) { // When the compression_level value is set, vaapi_encode.c assigns the value to VAEncMiscParameterBufferQualityLevel From f92302532c4ae646ff8f055c0961be503f201d6b Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Fri, 25 Sep 2026 02:41:29 +0100 Subject: [PATCH 4/4] fixup: doxygen fix --- src/platform/linux/vaapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/linux/vaapi.cpp b/src/platform/linux/vaapi.cpp index b77857cafd2..6fafc9fd6ec 100644 --- a/src/platform/linux/vaapi.cpp +++ b/src/platform/linux/vaapi.cpp @@ -289,7 +289,7 @@ namespace va { * @param va_ctx AVCodecContext context. * @param dpy VA display. * @param va_profile VA profile. - * @param va_profile VA entrypoint. + * @param va_entrypoint VA entrypoint. * @param quality_level Requested quality level to be translated into equivalent per-driver VA quality value. */ void set_quality_level(AVCodecContext *va_ctx, VADisplay dpy, VAProfile va_profile, VAEntrypoint va_entrypoint, int quality_level) {