diff --git a/docs/configuration.md b/docs/configuration.md index e9fe004ddde..7d61b0c455f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -3006,6 +3006,125 @@ editing the `conf` file in a text editor. Use the examples as reference. ## VA-API Encoder +### vaapi_blbrc + + + + + + + + + + + + + + +
Description + Block level based bitrate control (BLBRC) can assign different bitrate on a per-block basis. May improve quality on supported devices. + @note{This option only applies when using the VA-API [encoder](#encoder).} +
Default@code{} + disabled + @endcode
Example@code{} + vaapi_blbrc = enabled + @endcode
+ +### vaapi_quality + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Description + The quality profile controls the tradeoff between speed and quality of encoding. + @note{This option only applies when using the VA-API [encoder](#encoder).} +
Default@code{} + auto + @endcode
Example@code{} + vaapi_quality = auto + @endcode
Choicesautodriver default quality
speedprefer speed
balancedbalanced
qualityprefer quality
+ +### vaapi_rc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Description + The encoder rate control. + @note{This option only applies when using the VA-API [encoder](#encoder).} + @warning{The automatic setting may override the driver-default rate control method to VBR and force [vaapi_strict_rc_buffer](#vaapi_strict_rc_buffer) enabled on certain configurations. Selecting another rate control manually will override this behaviour.} +
Default@code{} + auto + @endcode
Example@code{} + vaapi_rc = vbr + @endcode
Choicesautodriver default (or whitelisted override)
avbraverage variable bitrate
cbrconstant bitrate
cqpconstant qp mode
icqintelligent qp mode
qvbrquality-defined variable bitrate
vbrvariable bitrate
+ ### vaapi_strict_rc_buffer @@ -3014,7 +3133,7 @@ editing the `conf` file in a text editor. Use the examples as reference. diff --git a/src/config.cpp b/src/config.cpp index e1dab3516fb..7d8f01459a2 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -38,6 +38,11 @@ #include #endif +#if (defined(linux) || defined(__FreeBSD__) && !defined(DOXYGEN)) + // For VAAPI rate control types + #include +#endif + namespace fs = std::filesystem; using namespace std::literals; @@ -397,6 +402,89 @@ namespace config { } // namespace qsv + namespace vaapi { +#if !(defined(linux) || defined(__FreeBSD__) || defined(DOXYGEN)) + constexpr int VA_RC_CBR = 0x00000002; + constexpr int VA_RC_VBR = 0x00000004; + constexpr int VA_RC_CQP = 0x00000010; + constexpr int VA_RC_ICQ = 0x00000040; + constexpr int VA_RC_QVBR = 0x00000400; + constexpr int VA_RC_AVBR = 0x00000800; +#endif + /** + * @brief Enumerates supported VA-API quality options. + */ + enum class quality_e : int { + _auto = 0, ///< Auto quality level + speed = 1, ///< Speed level + balanced = 2, ///< Balanced level + quality = 3 ///< Quality level + }; + + /** + * @brief Enumerates supported VA-API rc options. + */ + enum class rc_e : int { + _auto = 0, ///< Auto rate control + avbr = VA_RC_AVBR, ///< AVBR - average variable bitrate + cbr = VA_RC_CBR, ///< CBR - constant bitrate + cqp = VA_RC_CQP, ///< CQP - constant QP + icq = VA_RC_ICQ, ///< ICQ - intelligent QP + qvbr = VA_RC_QVBR, ///< QVBR - quality-defined variable bitrate + vbr = VA_RC_VBR ///< VBR - variable bitrate + }; + + /** + * @brief Parse a VA-API quality preset while preserving the current value on invalid input. + * + * @param quality_type Configuration text naming the VA-API quality preset. + * @param original Original text value used when reporting a parsing failure. + * @return Parsed enum value, or the setting-specific default when the text is unknown. + */ + template + ::std::optional quality_from_view(const ::std::string_view &quality_type, const ::std::optional(&original)) { +#ifndef DOXYGEN + #define _CONVERT_(x) \ + if (quality_type == #x##sv) \ + return (int) T::x +#endif + _CONVERT_(balanced); + _CONVERT_(quality); + _CONVERT_(speed); +#ifdef _CONVERT_ + #undef _CONVERT_ +#endif + return original; + } + + /** + * @brief Parse a VA-API rate-control mode while preserving the current value on invalid input. + * + * @param rc Rate-control mode selected in the configuration. + * @param original Original text value used when reporting a parsing failure. + * @return Parsed enum value, or the setting-specific default when the text is unknown. + */ + template + ::std::optional rc_from_view(const ::std::string_view &rc, const ::std::optional(&original)) { +#ifndef DOXYGEN + #define _CONVERT_(x) \ + if (rc == #x##sv) \ + return (int) T::x +#endif + _CONVERT_(avbr); + _CONVERT_(cbr); + _CONVERT_(cqp); + _CONVERT_(icq); + _CONVERT_(qvbr); + _CONVERT_(vbr); +#ifdef _CONVERT_ + #undef _CONVERT_ +#endif + return original; + } + + } // namespace vaapi + namespace vt { /** @@ -669,6 +757,10 @@ namespace config { }, // vt { + 0, // blbrc + std::to_underlying(vaapi::quality_e::_auto), // quality + std::to_underlying(vaapi::rc_e::_auto), // rate control + {}, // rate control string false, // strict_rc_buffer }, // vaapi @@ -1551,6 +1643,16 @@ namespace config { int_f(vars, "vt_software", video.vt.vt_require_sw, vt::force_software_from_view); int_f(vars, "vt_realtime", video.vt.vt_realtime, vt::rt_from_view); + std::string vaapi_quality; + string_f(vars, "vaapi_quality", vaapi_quality); + if (!vaapi_quality.empty()) { + video.vaapi.vaapi_quality = vaapi::quality_from_view(vaapi_quality, video.vaapi.vaapi_quality); + } + string_f(vars, "vaapi_rc", video.vaapi.vaapi_rc_str); + if (!video.vaapi.vaapi_rc_str.empty()) { + video.vaapi.vaapi_rc = vaapi::rc_from_view(video.vaapi.vaapi_rc_str, video.vaapi.vaapi_rc); + } + bool_f(vars, "vaapi_blbrc", (bool &) video.vaapi.blbrc); bool_f(vars, "vaapi_strict_rc_buffer", video.vaapi.strict_rc_buffer); int_f(vars, "vk_tune", video.vk.tune); diff --git a/src/config.h b/src/config.h index cbe0978ede4..2795cf17958 100644 --- a/src/config.h +++ b/src/config.h @@ -105,6 +105,10 @@ namespace config { } vt; ///< VideoToolbox encoder options. struct { + std::optional blbrc; + std::optional vaapi_quality; + std::optional vaapi_rc; + std::string vaapi_rc_str; bool strict_rc_buffer; } vaapi; ///< VA-API encoder options. diff --git a/src/platform/linux/vaapi.cpp b/src/platform/linux/vaapi.cpp index 22843fe2007..767967fa222 100644 --- a/src/platform/linux/vaapi.cpp +++ b/src/platform/linux/vaapi.cpp @@ -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) { + // + // 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); + + // 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"; + } - 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; + // 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); - } else { - BOOST_LOG(info) << "Using default rate control"sv; } + BOOST_LOG(info) << "[VAAPI] Using "sv << rc_mode << " rate control "sv << rc_vbv << rc_whitelist; } /** diff --git a/src/video.cpp b/src/video.cpp index c34751aa4f0..2abc1eb4504 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -1191,6 +1191,7 @@ namespace video { // Common options { {"async_depth"s, 1}, + {"blbrc"s, &config::video.vaapi.blbrc}, {"idr_interval"s, std::numeric_limits::max()}, }, {}, // SDR-specific options @@ -1204,6 +1205,7 @@ namespace video { // Common options { {"async_depth"s, 1}, + {"blbrc"s, &config::video.vaapi.blbrc}, {"sei"s, 0}, {"idr_interval"s, std::numeric_limits::max()}, }, @@ -1218,6 +1220,7 @@ namespace video { // Common options { {"async_depth"s, 1}, + {"blbrc"s, &config::video.vaapi.blbrc}, {"sei"s, 0}, {"idr_interval"s, std::numeric_limits::max()}, }, diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index a9476ea02bf..e62c61ed838 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -356,6 +356,9 @@

{{ $t('config.configuration') }}

id: "vaapi", name: "VA-API Encoder", options: { + "vaapi_blbrc": "disabled", + "vaapi_quality": "auto", + "vaapi_rc": "auto", "vaapi_strict_rc_buffer": "disabled", }, }, diff --git a/src_assets/common/assets/web/configs/tabs/encoders/VAAPIEncoder.vue b/src_assets/common/assets/web/configs/tabs/encoders/VAAPIEncoder.vue index 063bba45b50..df5a6b69404 100644 --- a/src_assets/common/assets/web/configs/tabs/encoders/VAAPIEncoder.vue +++ b/src_assets/common/assets/web/configs/tabs/encoders/VAAPIEncoder.vue @@ -12,13 +12,80 @@ const config = ref(props.config) diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json index 397abb4a32e..137b202bb38 100644 --- a/src_assets/common/assets/web/public/assets/locale/en.json +++ b/src_assets/common/assets/web/public/assets/locale/en.json @@ -397,6 +397,23 @@ "touchpad_as_ds4_desc": "If disabled, touchpad presence will not be taken into account during gamepad type selection.", "upnp": "UPnP", "upnp_desc": "Automatically configure port forwarding for streaming over the Internet", + "vaapi_blbrc": "Block level based bitrate control (BLBRC)", + "vaapi_blbrc_desc": "Enable block level rate control, which assigns different bitrate block by block. Can be combined with CBR/VBR-type rate control methods on supported encoders.", + "vaapi_quality": "VA-API Quality", + "vaapi_quality_balanced": "balanced -- balanced", + "vaapi_quality_desc": "Determines encoder tradeoff between quality and speed/power consumption.", + "vaapi_quality_group": "VA-API Quality Settings", + "vaapi_quality_quality": "quality -- prefer quality", + "vaapi_quality_speed": "speed -- prefer speed", + "vaapi_rc": "VA-API Rate Control", + "vaapi_rc_avbr": "avbr -- average variable bitrate", + "vaapi_rc_cbr": "cbr -- constant bitrate", + "vaapi_rc_cqp": "cqp -- constant qp mode", + "vaapi_rc_desc": "This controls the rate control method to ensure we are not exceeding the client bitrate target. Note that supported rate control methods varies by vendor, and automatic may force-enable strict bitrate enforcement on certain devices.", + "vaapi_rc_group": "VA-API Rate Control Settings", + "vaapi_rc_icq": "icq -- intelligent constant qp mode", + "vaapi_rc_qvbr": "qvbr -- quality-defined variable bitrate", + "vaapi_rc_vbr": "vbr -- variable bitrate", "vaapi_strict_rc_buffer": "Strictly enforce frame bitrate limits for H.264/HEVC on AMD GPUs", "vaapi_strict_rc_buffer_desc": "Enabling this option can avoid dropped frames over the network during scene changes, but video quality may be reduced during motion.", "vk_rc_cbr": "CBR (Constant Bitrate) (default)",
Enabling this option can avoid dropped frames over the network during scene changes, but video quality may be reduced during motion. - @note{This option only applies for H.264 and HEVC when using VA-API [encoder](#encoder) on AMD GPUs.} + @note{This option only applies for H.264 and HEVC when using VA-API [encoder](#encoder) on AMD GPUs (or when overriding the default rate control on other devices).}