diff --git a/docs/configuration.md b/docs/configuration.md index 2b282d1c7a1..d4e3354045b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2303,6 +2303,33 @@ editing the `conf` file in a text editor. Use the examples as reference. +## VA-API Encoder + +### vaapi_strict_rc_buffer + + + + + + + + + + + + + + +
Description + 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.} +
Default@code{} + disabled + @endcode
Example@code{} + vaapi_strict_rc_buffer = enabled + @endcode
+ ## Software Encoder ### sw_preset diff --git a/src/config.cpp b/src/config.cpp index 8475a5e3370..a61b69b96f1 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -377,6 +377,10 @@ namespace config { -1, }, // vt + { + false, // strict_rc_buffer + }, // vaapi + {}, // capture {}, // encoder {}, // adapter_name @@ -1014,6 +1018,8 @@ 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); + bool_f(vars, "vaapi_strict_rc_buffer", video.vaapi.strict_rc_buffer); + string_f(vars, "capture", video.capture); string_f(vars, "encoder", video.encoder); string_f(vars, "adapter_name", video.adapter_name); diff --git a/src/config.h b/src/config.h index e599afae454..891a4079772 100644 --- a/src/config.h +++ b/src/config.h @@ -71,6 +71,10 @@ namespace config { int vt_coder; } vt; + struct { + bool strict_rc_buffer; + } vaapi; + std::string capture; std::string encoder; std::string adapter_name; diff --git a/src/platform/common.h b/src/platform/common.h index 368bc733b19..ee48ed3909a 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -418,7 +418,7 @@ namespace platf { * @note Implementations may set or modify codec options prior to codec initialization. */ virtual void - init_codec_options(AVCodecContext *ctx, AVDictionary *options) {}; + init_codec_options(AVCodecContext *ctx, AVDictionary **options) {}; /** * @brief Prepare to derive a context. diff --git a/src/platform/linux/vaapi.cpp b/src/platform/linux/vaapi.cpp index ada6370034a..909ade10548 100644 --- a/src/platform/linux/vaapi.cpp +++ b/src/platform/linux/vaapi.cpp @@ -9,6 +9,7 @@ extern "C" { #include +#include #include #include #if !VA_CHECK_VERSION(1, 9, 0) @@ -129,13 +130,173 @@ namespace va { return 0; } + /** + * @brief Finds a supported VA entrypoint for the given VA profile. + * @param profile The profile to match. + * @return A valid encoding entrypoint or 0 on failure. + */ + VAEntrypoint + select_va_entrypoint(VAProfile profile) { + std::vector entrypoints(vaMaxNumEntrypoints(va_display)); + int num_eps; + auto status = vaQueryConfigEntrypoints(va_display, profile, entrypoints.data(), &num_eps); + if (status != VA_STATUS_SUCCESS) { + BOOST_LOG(error) << "Failed to query VA entrypoints: "sv << vaErrorStr(status); + return (VAEntrypoint) 0; + } + entrypoints.resize(num_eps); + + // Sorted in order of descending preference + VAEntrypoint ep_preferences[] = { + VAEntrypointEncSliceLP, + VAEntrypointEncSlice, + VAEntrypointEncPicture + }; + for (auto ep_pref : ep_preferences) { + if (std::find(entrypoints.begin(), entrypoints.end(), ep_pref) != entrypoints.end()) { + return ep_pref; + } + } + + return (VAEntrypoint) 0; + } + + /** + * @brief Determines if a given VA profile is supported. + * @param profile The profile to match. + * @return Boolean value indicating if the profile is supported. + */ + bool + is_va_profile_supported(VAProfile profile) { + std::vector profiles(vaMaxNumProfiles(va_display)); + int num_profs; + auto status = vaQueryConfigProfiles(va_display, profiles.data(), &num_profs); + if (status != VA_STATUS_SUCCESS) { + BOOST_LOG(error) << "Failed to query VA profiles: "sv << vaErrorStr(status); + return false; + } + profiles.resize(num_profs); + + return std::find(profiles.begin(), profiles.end(), profile) != profiles.end(); + } + + /** + * @brief Determines the matching VA profile for the codec configuration. + * @param ctx The FFmpeg codec context. + * @return The matching VA profile or `VAProfileNone` on failure. + */ + VAProfile + get_va_profile(AVCodecContext *ctx) { + if (ctx->codec_id == AV_CODEC_ID_H264) { + // There's no VAAPI profile for H.264 4:4:4 + return VAProfileH264High; + } + else if (ctx->codec_id == AV_CODEC_ID_HEVC) { + switch (ctx->profile) { + case FF_PROFILE_HEVC_REXT: + switch (av_pix_fmt_desc_get(ctx->sw_pix_fmt)->comp[0].depth) { + case 10: + return VAProfileHEVCMain444_10; + case 8: + return VAProfileHEVCMain444; + } + break; + case FF_PROFILE_HEVC_MAIN_10: + return VAProfileHEVCMain10; + case FF_PROFILE_HEVC_MAIN: + return VAProfileHEVCMain; + } + } + else if (ctx->codec_id == AV_CODEC_ID_AV1) { + switch (ctx->profile) { + case FF_PROFILE_AV1_HIGH: + return VAProfileAV1Profile1; + case FF_PROFILE_AV1_MAIN: + return VAProfileAV1Profile0; + } + } + + BOOST_LOG(error) << "Unknown encoder profile: "sv << ctx->profile; + return VAProfileNone; + } + void - init_codec_options(AVCodecContext *ctx, AVDictionary *options) override { - // Don't set the RC buffer size when using H.264 on Intel GPUs. It causes - // major encoding quality degradation. + init_codec_options(AVCodecContext *ctx, AVDictionary **options) override { + auto va_profile = get_va_profile(ctx); + if (va_profile == VAProfileNone || !is_va_profile_supported(va_profile)) { + // Don't bother doing anything if the profile isn't supported + return; + } + + auto va_entrypoint = select_va_entrypoint(va_profile); + if (va_entrypoint == 0) { + // It's possible that only decoding is supported for this profile + return; + } + auto vendor = vaQueryVendorString(va_display); - if (ctx->codec_id != AV_CODEC_ID_H264 || (vendor && !strstr(vendor, "Intel"))) { + + if (va_entrypoint == VAEntrypointEncSliceLP) { + BOOST_LOG(info) << "Using LP encoding mode"sv; + av_dict_set_int(options, "low_power", 1, 0); + } + else { + BOOST_LOG(info) << "Using normal encoding mode"sv; + } + + VAConfigAttrib rc_attr = { VAConfigAttribRateControl }; + 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; + } + + VAConfigAttrib slice_attr = { VAConfigAttribEncMaxSlices }; + status = vaGetConfigAttributes(va_display, va_profile, va_entrypoint, &slice_attr, 1); + if (status != VA_STATUS_SUCCESS) { + // Assume only a single slice is supported + slice_attr.value = 1; + } + if (ctx->slices > slice_attr.value) { + BOOST_LOG(info) << "Limiting slice count to encoder maximum: "sv << slice_attr.value; + ctx->slices = slice_attr.value; + } + + // Use VBR with a single frame VBV when the user forces it and for known good cases: + // - Intel GPUs + // - AV1 + // + // VBR ensures the bitstream isn't full of filler data for bitrate undershoots and + // single frame VBV ensures that we don't have large bitrate overshoots (at least + // as much as they can be avoided without pre-analysis). + // + // 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 (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; } } diff --git a/src/video.cpp b/src/video.cpp index ecd92e2504a..20d22385353 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -462,7 +462,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "av1_nvenc"s, }, { @@ -472,7 +471,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "hevc_nvenc"s, }, { @@ -482,7 +480,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "h264_nvenc"s, }, PARALLEL_ENCODING | REF_FRAMES_INVALIDATION | YUV444_SUPPORT // flags @@ -525,7 +522,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "av1_nvenc"s, }, { @@ -552,7 +548,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "hevc_nvenc"s, }, { @@ -576,7 +571,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "h264_nvenc"s, }, PARALLEL_ENCODING @@ -618,7 +612,6 @@ namespace video { { "profile"s, (int) qsv::profile_av1_e::high }, }, {}, // Fallback options - std::nullopt, // QP rate control fallback "av1_qsv"s, }, { @@ -652,7 +645,6 @@ namespace video { // Fallback options { "low_power"s, []() { return config::video.qsv.qsv_slow_hevc ? 0 : 1; } }, }, - std::nullopt, // QP rate control fallback "hevc_qsv"s, }, { @@ -683,7 +675,6 @@ namespace video { // Fallback options { "low_power"s, 0 }, // Some old/low-end Intel GPUs don't support low power encoding }, - std::nullopt, // QP rate control fallback "h264_qsv"s, }, PARALLEL_ENCODING | CBR_WITH_VBR | RELAXED_COMPLIANCE | NO_RC_BUF_LIMIT | YUV444_SUPPORT @@ -716,7 +707,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "av1_amf"s, }, { @@ -741,7 +731,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "hevc_amf"s, }, { @@ -767,7 +756,6 @@ namespace video { // Fallback options { "usage"s, 2 /* AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY */ }, // Workaround for https://github.com/GPUOpen-LibrariesAndSDKs/AMF/issues/410 }, - std::nullopt, // QP rate control fallback "h264_amf"s, }, PARALLEL_ENCODING @@ -797,13 +785,10 @@ namespace video { {}, // YUV444 HDR-specific options {}, // Fallback options - // QP rate control fallback - std::nullopt, - #ifdef ENABLE_BROKEN_AV1_ENCODER - // Due to bugs preventing on-demand IDR frames from working and very poor - // real-time encoding performance, we do not enable libsvtav1 by default. - // It is only suitable for testing AV1 until the IDR frame issue is fixed. + // Due to bugs preventing on-demand IDR frames from working and very poor + // real-time encoding performance, we do not enable libsvtav1 by default. + // It is only suitable for testing AV1 until the IDR frame issue is fixed. "libsvtav1"s, #else {}, @@ -825,7 +810,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "libx265"s, }, { @@ -839,7 +823,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, // QP rate control fallback "libx264"s, }, H264_ONLY | PARALLEL_ENCODING | ALWAYS_REPROBE | YUV444_SUPPORT @@ -857,7 +840,6 @@ namespace video { { // Common options { - { "low_power"s, 1 }, { "async_depth"s, 1 }, { "idr_interval"s, std::numeric_limits::max() }, }, @@ -865,17 +847,12 @@ namespace video { {}, // HDR-specific options {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options - { - // Fallback options - { "low_power"s, 0 }, // Not all VAAPI drivers expose LP entrypoints - }, - std::make_optional("qp"s, &config::video.qp), + {}, // Fallback options "av1_vaapi"s, }, { // Common options { - { "low_power"s, 1 }, { "async_depth"s, 1 }, { "sei"s, 0 }, { "idr_interval"s, std::numeric_limits::max() }, @@ -884,17 +861,12 @@ namespace video { {}, // HDR-specific options {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options - { - // Fallback options - { "low_power"s, 0 }, // Not all VAAPI drivers expose LP entrypoints - }, - std::make_optional("qp"s, &config::video.qp), + {}, // Fallback options "hevc_vaapi"s, }, { // Common options { - { "low_power"s, 1 }, { "async_depth"s, 1 }, { "sei"s, 0 }, { "idr_interval"s, std::numeric_limits::max() }, @@ -903,15 +875,11 @@ namespace video { {}, // HDR-specific options {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options - { - // Fallback options - { "low_power"s, 0 }, // Not all VAAPI drivers expose LP entrypoints - }, - std::make_optional("qp"s, &config::video.qp), + {}, // Fallback options "h264_vaapi"s, }, // RC buffer size will be set in platform code if supported - LIMITED_GOP_SIZE | PARALLEL_ENCODING | SINGLE_SLICE_ONLY | NO_RC_BUF_LIMIT + LIMITED_GOP_SIZE | PARALLEL_ENCODING | NO_RC_BUF_LIMIT }; #endif @@ -938,7 +906,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, "av1_videotoolbox"s, }, { @@ -955,7 +922,6 @@ namespace video { {}, // YUV444 SDR-specific options {}, // YUV444 HDR-specific options {}, // Fallback options - std::nullopt, "hevc_videotoolbox"s, }, { @@ -975,7 +941,6 @@ namespace video { // Fallback options { "flags"s, "-low_delay" }, }, - std::nullopt, "h264_videotoolbox"s, }, DEFAULT @@ -1651,52 +1616,43 @@ namespace video { } } - if (video_format[encoder_t::CBR]) { - auto bitrate = config.bitrate * 1000; - ctx->rc_max_rate = bitrate; - ctx->bit_rate = bitrate; + auto bitrate = config.bitrate * 1000; + ctx->rc_max_rate = bitrate; + ctx->bit_rate = bitrate; - if (encoder.flags & CBR_WITH_VBR) { - // Ensure rc_max_bitrate != bit_rate to force VBR mode - ctx->bit_rate--; - } - else { - ctx->rc_min_rate = bitrate; - } + if (encoder.flags & CBR_WITH_VBR) { + // Ensure rc_max_bitrate != bit_rate to force VBR mode + ctx->bit_rate--; + } + else { + ctx->rc_min_rate = bitrate; + } - if (encoder.flags & RELAXED_COMPLIANCE) { - ctx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL; - } + if (encoder.flags & RELAXED_COMPLIANCE) { + ctx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL; + } - if (!(encoder.flags & NO_RC_BUF_LIMIT)) { - if (!hardware && (ctx->slices > 1 || config.videoFormat == 1)) { - // Use a larger rc_buffer_size for software encoding when slices are enabled, - // because libx264 can severely degrade quality if the buffer is too small. - // libx265 encounters this issue more frequently, so always scale the - // buffer by 1.5x for software HEVC encoding. - ctx->rc_buffer_size = bitrate / ((config.framerate * 10) / 15); - } - else { - ctx->rc_buffer_size = bitrate / config.framerate; + if (!(encoder.flags & NO_RC_BUF_LIMIT)) { + if (!hardware && (ctx->slices > 1 || config.videoFormat == 1)) { + // Use a larger rc_buffer_size for software encoding when slices are enabled, + // because libx264 can severely degrade quality if the buffer is too small. + // libx265 encounters this issue more frequently, so always scale the + // buffer by 1.5x for software HEVC encoding. + ctx->rc_buffer_size = bitrate / ((config.framerate * 10) / 15); + } + else { + ctx->rc_buffer_size = bitrate / config.framerate; #ifndef __APPLE__ - if (encoder.name == "nvenc" && config::video.nv_legacy.vbv_percentage_increase > 0) { - ctx->rc_buffer_size += ctx->rc_buffer_size * config::video.nv_legacy.vbv_percentage_increase / 100; - } -#endif + if (encoder.name == "nvenc" && config::video.nv_legacy.vbv_percentage_increase > 0) { + ctx->rc_buffer_size += ctx->rc_buffer_size * config::video.nv_legacy.vbv_percentage_increase / 100; } +#endif } } - else if (video_format.qp) { - handle_option(*video_format.qp); - } - else { - BOOST_LOG(error) << "Couldn't set video quality: encoder "sv << encoder.name << " doesn't support qp"sv; - return nullptr; - } // Allow the encoding device a final opportunity to set/unset or override any options - encode_device->init_codec_options(ctx.get(), options); + encode_device->init_codec_options(ctx.get(), &options); if (auto status = avcodec_open2(ctx.get(), codec, &options)) { char err_str[AV_ERROR_MAX_STRING_SIZE] { 0 }; @@ -2419,18 +2375,11 @@ namespace video { return false; } - retry: // If we're expecting failure, use the autoselect ref config first since that will always succeed // if the encoder is available. auto max_ref_frames_h264 = expect_failure ? -1 : validate_config(disp, encoder, config_max_ref_frames); auto autoselect_h264 = max_ref_frames_h264 >= 0 ? max_ref_frames_h264 : validate_config(disp, encoder, config_autoselect); if (autoselect_h264 < 0) { - if (encoder.h264.qp && encoder.h264[encoder_t::CBR]) { - // It's possible the encoder isn't accepting Constant Bit Rate. Turn off CBR and make another attempt - encoder.h264.capabilities.set(); - encoder.h264[encoder_t::CBR] = false; - goto retry; - } return false; } else if (expect_failure) { @@ -2454,7 +2403,6 @@ namespace video { config_autoselect.videoFormat = 1; if (disp->is_codec_supported(encoder.hevc.name, config_autoselect)) { - retry_hevc: auto max_ref_frames_hevc = validate_config(disp, encoder, config_max_ref_frames); // If H.264 succeeded with max ref frames specified, assume that we can count on @@ -2463,13 +2411,6 @@ namespace video { max_ref_frames_hevc : validate_config(disp, encoder, config_autoselect); - if (autoselect_hevc < 0 && encoder.hevc.qp && encoder.hevc[encoder_t::CBR]) { - // It's possible the encoder isn't accepting Constant Bit Rate. Turn off CBR and make another attempt - encoder.hevc.capabilities.set(); - encoder.hevc[encoder_t::CBR] = false; - goto retry_hevc; - } - for (auto [validate_flag, encoder_flag] : packet_deficiencies) { encoder.hevc[encoder_flag] = (max_ref_frames_hevc & validate_flag && autoselect_hevc & validate_flag); } @@ -2492,7 +2433,6 @@ namespace video { config_autoselect.videoFormat = 2; if (disp->is_codec_supported(encoder.av1.name, config_autoselect)) { - retry_av1: auto max_ref_frames_av1 = validate_config(disp, encoder, config_max_ref_frames); // If H.264 succeeded with max ref frames specified, assume that we can count on @@ -2501,13 +2441,6 @@ namespace video { max_ref_frames_av1 : validate_config(disp, encoder, config_autoselect); - if (autoselect_av1 < 0 && encoder.av1.qp && encoder.av1[encoder_t::CBR]) { - // It's possible the encoder isn't accepting Constant Bit Rate. Turn off CBR and make another attempt - encoder.av1.capabilities.set(); - encoder.av1[encoder_t::CBR] = false; - goto retry_av1; - } - for (auto [validate_flag, encoder_flag] : packet_deficiencies) { encoder.av1[encoder_flag] = (max_ref_frames_av1 & validate_flag && autoselect_av1 & validate_flag); } diff --git a/src/video.h b/src/video.h index 6a50b2e3832..1f39764820d 100644 --- a/src/video.h +++ b/src/video.h @@ -120,7 +120,6 @@ namespace video { enum flag_e { PASSED, ///< Indicates the encoder is supported. REF_FRAMES_RESTRICT, ///< Set maximum reference frames. - CBR, ///< Some encoders don't support CBR, if not supported attempt constant quantization parameter instead. DYNAMIC_RANGE, ///< HDR support. YUV444, ///< YUV 4:4:4 support. VUI_PARAMETERS, ///< AMD encoder with VAAPI doesn't add VUI parameters to SPS. @@ -135,7 +134,6 @@ namespace video { switch (flag) { _CONVERT(PASSED); _CONVERT(REF_FRAMES_RESTRICT); - _CONVERT(CBR); _CONVERT(DYNAMIC_RANGE); _CONVERT(YUV444); _CONVERT(VUI_PARAMETERS); @@ -167,11 +165,6 @@ namespace video { std::vector hdr444_options; std::vector fallback_options; - // QP option to set in the case that CBR/VBR is not supported - // by the encoder. If CBR/VBR is guaranteed to be supported, - // don't specify this option to avoid wasteful encoder probing. - std::optional qp; - std::string name; std::bitset capabilities; diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index c9c0a6ddf71..a7681fdde02 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -257,6 +257,13 @@

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

"vt_realtime": "enabled", }, }, + { + id: "vaapi", + name: "VA-API Encoder", + options: { + "vaapi_strict_rc_buffer": "disabled", + }, + }, { id: "sw", name: "Software Encoder", @@ -283,7 +290,7 @@

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

var app = document.getElementById("app"); if (this.platform === "windows") { this.tabs = this.tabs.filter((el) => { - return el.id !== "vt"; + return el.id !== "vt" && el.id !== "vaapi"; }); } if (this.platform === "linux") { @@ -293,7 +300,7 @@

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

} if (this.platform === "macos") { this.tabs = this.tabs.filter((el) => { - return el.id !== "amd" && el.id !== "nv" && el.id !== "qsv"; + return el.id !== "amd" && el.id !== "nv" && el.id !== "qsv" && el.id !== "vaapi"; }); } diff --git a/src_assets/common/assets/web/configs/tabs/ContainerEncoders.vue b/src_assets/common/assets/web/configs/tabs/ContainerEncoders.vue index 084c3001f57..1dce1403adf 100644 --- a/src_assets/common/assets/web/configs/tabs/ContainerEncoders.vue +++ b/src_assets/common/assets/web/configs/tabs/ContainerEncoders.vue @@ -5,6 +5,7 @@ import IntelQuickSyncEncoder from './encoders/IntelQuickSyncEncoder.vue' import AmdAmfEncoder from './encoders/AmdAmfEncoder.vue' import VideotoolboxEncoder from './encoders/VideotoolboxEncoder.vue' import SoftwareEncoder from './encoders/SoftwareEncoder.vue' +import VAAPIEncoder from './encoders/VAAPIEncoder.vue' const props = defineProps([ 'platform', @@ -45,6 +46,13 @@ const config = ref(props.config) :config="config" /> + + + +import { ref } from 'vue' + +const props = defineProps([ + 'platform', + 'config', +]) + +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 12844fcf874..a41617fe682 100644 --- a/src_assets/common/assets/web/public/assets/locale/en.json +++ b/src_assets/common/assets/web/public/assets/locale/en.json @@ -310,6 +310,8 @@ "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_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.", "virtual_sink": "Virtual Sink", "virtual_sink_desc": "Manually specify a virtual audio device to use. If unset, the device is chosen automatically. We strongly recommend leaving this field blank to use automatic device selection!", "virtual_sink_placeholder": "Steam Streaming Speakers",