From 8b40fa6dd52f5f5b636a1d6e11b548ddd809dc86 Mon Sep 17 00:00:00 2001 From: ns6089 <61738816+ns6089@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:05:15 +0300 Subject: [PATCH] nvenc: new config page --- src/config.cpp | 133 ++++++----------------- src/config.h | 13 ++- src/nvenc/nvenc_config.h | 4 +- src/platform/windows/display_vram.cpp | 6 +- src/video.cpp | 25 +++-- src_assets/common/assets/web/config.html | 86 +++++++++------ 6 files changed, 113 insertions(+), 154 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index ecb3d232..8302ab67 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -24,6 +24,11 @@ #include #endif +#ifndef __APPLE__ + // For NVENC legacy constants + #include +#endif + namespace fs = std::filesystem; using namespace std::literals; @@ -35,96 +40,16 @@ using namespace std::literals; namespace config { namespace nv { -#ifdef __APPLE__ - // values accurate as of 27/12/2022, but aren't strictly necessary for MacOS build - #define NV_ENC_TUNING_INFO_HIGH_QUALITY 1 - #define NV_ENC_TUNING_INFO_LOW_LATENCY 2 - #define NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY 3 - #define NV_ENC_TUNING_INFO_LOSSLESS 4 - #define NV_ENC_PARAMS_RC_CONSTQP 0x0 - #define NV_ENC_PARAMS_RC_VBR 0x1 - #define NV_ENC_PARAMS_RC_CBR 0x2 - #define NV_ENC_H264_ENTROPY_CODING_MODE_CABAC 1 - #define NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC 2 -#else - #include -#endif - enum preset_e : int { - p1 = 12, // PRESET_P1, // must be kept in sync with - p2, // PRESET_P2, - p3, // PRESET_P3, - p4, // PRESET_P4, - p5, // PRESET_P5, - p6, // PRESET_P6, - p7 // PRESET_P7 - }; - - enum tune_e : int { - hq = NV_ENC_TUNING_INFO_HIGH_QUALITY, - ll = NV_ENC_TUNING_INFO_LOW_LATENCY, - ull = NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY, - lossless = NV_ENC_TUNING_INFO_LOSSLESS - }; - - enum rc_e : int { - constqp = NV_ENC_PARAMS_RC_CONSTQP, /**< Constant QP mode */ - vbr = NV_ENC_PARAMS_RC_VBR, /**< Variable bitrate mode */ - cbr = NV_ENC_PARAMS_RC_CBR /**< Constant bitrate mode */ - }; - - enum coder_e : int { - _auto = 0, - cabac = NV_ENC_H264_ENTROPY_CODING_MODE_CABAC, - cavlc = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC, - }; - - std::optional - preset_from_view(const std::string_view &preset) { -#define _CONVERT_(x) \ - if (preset == #x##sv) return x - _CONVERT_(p1); - _CONVERT_(p2); - _CONVERT_(p3); - _CONVERT_(p4); - _CONVERT_(p5); - _CONVERT_(p6); - _CONVERT_(p7); -#undef _CONVERT_ - return std::nullopt; + nvenc::nvenc_two_pass + twopass_from_view(const std::string_view &preset) { + if (preset == "disabled") return nvenc::nvenc_two_pass::disabled; + if (preset == "quarter_res") return nvenc::nvenc_two_pass::quarter_resolution; + if (preset == "full_res") return nvenc::nvenc_two_pass::full_resolution; + BOOST_LOG(warning) << "config: unknown nvenc_twopass value: " << preset; + return nvenc::nvenc_two_pass::quarter_resolution; } - std::optional - tune_from_view(const std::string_view &tune) { -#define _CONVERT_(x) \ - if (tune == #x##sv) return x - _CONVERT_(hq); - _CONVERT_(ll); - _CONVERT_(ull); - _CONVERT_(lossless); -#undef _CONVERT_ - return std::nullopt; - } - - std::optional - rc_from_view(const std::string_view &rc) { -#define _CONVERT_(x) \ - if (rc == #x##sv) return x - _CONVERT_(constqp); - _CONVERT_(vbr); - _CONVERT_(cbr); -#undef _CONVERT_ - return std::nullopt; - } - - int - coder_from_view(const std::string_view &coder) { - if (coder == "auto"sv) return _auto; - if (coder == "cabac"sv || coder == "ac"sv) return cabac; - if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc; - - return -1; - } } // namespace nv namespace amd { @@ -400,12 +325,8 @@ namespace config { 11, // superfast }, // software - { - nv::p4, // preset - nv::ull, // tune - nv::cbr, // rc - nv::_auto // coder - }, // nv + {}, // nv + {}, // nv_legacy { qsv::medium, // preset @@ -640,6 +561,16 @@ namespace config { vars.erase(it); } + template + void + generic_f(std::unordered_map &vars, const std::string &name, T &input, F &&f) { + std::string tmp; + string_f(vars, name, tmp); + if (!tmp.empty()) { + input = f(tmp); + } + } + void string_restricted_f(std::unordered_map &vars, const std::string &name, std::string &input, const std::vector &allowed_vals) { std::string temp; @@ -989,10 +920,18 @@ namespace config { video.sw.svtav1_preset = sw::svtav1_preset_from_view(video.sw.sw_preset); } string_f(vars, "sw_tune", video.sw.sw_tune); - int_f(vars, "nv_preset", video.nv.nv_preset, nv::preset_from_view); - int_f(vars, "nv_tune", video.nv.nv_tune, nv::tune_from_view); - int_f(vars, "nv_rc", video.nv.nv_rc, nv::rc_from_view); - int_f(vars, "nv_coder", video.nv.nv_coder, nv::coder_from_view); + + int_between_f(vars, "nvenc_preset", video.nv.quality_preset, { 1, 7 }); + generic_f(vars, "nvenc_twopass", video.nv.two_pass, nv::twopass_from_view); + bool_f(vars, "nvenc_h264_cavlc", video.nv.h264_cavlc); + +#ifndef __APPLE__ + video.nv_legacy.preset = video.nv.quality_preset + 11; + video.nv_legacy.multipass = video.nv.two_pass == nvenc::nvenc_two_pass::quarter_resolution ? NV_ENC_TWO_PASS_QUARTER_RESOLUTION : + video.nv.two_pass == nvenc::nvenc_two_pass::full_resolution ? NV_ENC_TWO_PASS_FULL_RESOLUTION : + NV_ENC_MULTI_PASS_DISABLED; + video.nv_legacy.h264_coder = video.nv.h264_cavlc ? NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC : NV_ENC_H264_ENTROPY_CODING_MODE_CABAC; +#endif int_f(vars, "qsv_preset", video.qsv.qsv_preset, qsv::preset_from_view); int_f(vars, "qsv_coder", video.qsv.qsv_cavlc, qsv::coder_from_view); diff --git a/src/config.h b/src/config.h index 23673e1e..8a6c1a2b 100644 --- a/src/config.h +++ b/src/config.h @@ -11,6 +11,8 @@ #include #include +#include "nvenc/nvenc_config.h" + namespace config { struct video_t { // ffmpeg params @@ -26,12 +28,13 @@ namespace config { std::optional svtav1_preset; } sw; + nvenc::nvenc_config nv; + struct { - std::optional nv_preset; - std::optional nv_tune; - std::optional nv_rc; - int nv_coder; - } nv; + int preset; + int multipass; + int h264_coder; + } nv_legacy; struct { std::optional qsv_preset; diff --git a/src/nvenc/nvenc_config.h b/src/nvenc/nvenc_config.h index a7e480c7..632146b7 100644 --- a/src/nvenc/nvenc_config.h +++ b/src/nvenc/nvenc_config.h @@ -15,10 +15,10 @@ namespace nvenc { struct nvenc_config { // Quality preset from 1 to 7, higher is slower - unsigned quality_preset = 1; + int quality_preset = 1; // Use optional preliminary pass for better motion vectors, bitrate distribution and stricter VBV(HRD), uses CUDA cores - nvenc_two_pass two_pass = nvenc_two_pass::disabled; + nvenc_two_pass two_pass = nvenc_two_pass::quarter_resolution; // Improves fades compression, uses CUDA cores bool weighted_prediction = false; diff --git a/src/platform/windows/display_vram.cpp b/src/platform/windows/display_vram.cpp index 5db0f0a2..5c0ead06 100644 --- a/src/platform/windows/display_vram.cpp +++ b/src/platform/windows/display_vram.cpp @@ -874,12 +874,8 @@ namespace platf::dxgi { init_encoder(const ::video::config_t &client_config, const ::video::sunshine_colorspace_t &colorspace) override { if (!nvenc_d3d) return false; - nvenc::nvenc_config nvenc_config; - nvenc_config.quality_preset = config::video.nv.nv_preset ? (*config::video.nv.nv_preset - 11) : 1; - nvenc_config.h264_cavlc = (config::video.nv.nv_coder == NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC); - auto nvenc_colorspace = nvenc::nvenc_colorspace_from_sunshine_colorspace(colorspace); - if (!nvenc_d3d->create_encoder(nvenc_config, client_config, nvenc_colorspace, buffer_format)) return false; + if (!nvenc_d3d->create_encoder(config::video.nv, client_config, nvenc_colorspace, buffer_format)) return false; base.apply_colorspace(colorspace); return base.init_output(nvenc_d3d->get_input_texture(), client_config.width, client_config.height) == 0; diff --git a/src/video.cpp b/src/video.cpp index 98c99357..421e58ff 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -601,7 +601,7 @@ namespace video { }, PARALLEL_ENCODING | REF_FRAMES_INVALIDATION // flags }; -#else +#elif !defined(__APPLE__) static encoder_t nvenc { "nvenc"sv, std::make_unique( @@ -625,9 +625,10 @@ namespace video { { "delay"s, 0 }, { "forced-idr"s, 1 }, { "zerolatency"s, 1 }, - { "preset"s, &config::video.nv.nv_preset }, - { "tune"s, &config::video.nv.nv_tune }, - { "rc"s, &config::video.nv.nv_rc }, + { "preset"s, &config::video.nv_legacy.preset }, + { "tune"s, NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY }, + { "rc"s, NV_ENC_PARAMS_RC_CBR }, + { "multipass"s, &config::video.nv_legacy.multipass }, }, // SDR-specific options {}, @@ -642,9 +643,10 @@ namespace video { { "delay"s, 0 }, { "forced-idr"s, 1 }, { "zerolatency"s, 1 }, - { "preset"s, &config::video.nv.nv_preset }, - { "tune"s, &config::video.nv.nv_tune }, - { "rc"s, &config::video.nv.nv_rc }, + { "preset"s, &config::video.nv_legacy.preset }, + { "tune"s, NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY }, + { "rc"s, NV_ENC_PARAMS_RC_CBR }, + { "multipass"s, &config::video.nv_legacy.multipass }, }, // SDR-specific options { @@ -662,10 +664,11 @@ namespace video { { "delay"s, 0 }, { "forced-idr"s, 1 }, { "zerolatency"s, 1 }, - { "preset"s, &config::video.nv.nv_preset }, - { "tune"s, &config::video.nv.nv_tune }, - { "rc"s, &config::video.nv.nv_rc }, - { "coder"s, &config::video.nv.nv_coder }, + { "preset"s, &config::video.nv_legacy.preset }, + { "tune"s, NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY }, + { "rc"s, NV_ENC_PARAMS_RC_CBR }, + { "coder"s, &config::video.nv_legacy.h264_coder }, + { "multipass"s, &config::video.nv_legacy.multipass }, }, // SDR-specific options { diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index b4fc94be..0ebc2e2e 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -872,41 +872,60 @@
- - + + + + + + + +
Higher numbers improve compression (quality at given bitrate) at the cost of + increased encoding latency.
+ Recommended to change only when limited by network or decoder, otherwise similar effect can be accomplished by + increasing bitrate. +
- - + + + +
Adds preliminary encoding pass.
+ This allows to detect more motion vectors, better distribute bitrate across the frame and more strictly adhere to + bitrate limits.
+ Disabling it is not recommended since this can lead to occasional bitrate overshoot and subsequent packet loss. +
-
- - -
-
- - +
+
+

+ +

+
+
+
+ + +
Simpler form of entropy coding.
+ CAVLC needs around 10% more bitrate for same quality.
+ Only relevant for really old decoding devices. +
+
+
+
+
@@ -1061,10 +1080,9 @@ "keyboard": "enabled", "min_log_level": 2, "mouse": "enabled", - "nv_coder": "auto", - "nv_preset": "p4", - "nv_rc": "cbr", - "nv_tune": "ull", + "nvenc_preset": "1", + "nvenc_twopass": "quarter_res", + "nvenc_h264_cavlc": "disabled", "origin_pin_allowed": "pc", "origin_web_ui_allowed": "lan", "qsv_coder": "auto",