nvenc: new config page

This commit is contained in:
ns6089 2023-08-22 13:05:15 +03:00 committed by Cameron Gutman
parent 11ebb47b3e
commit 8b40fa6dd5
6 changed files with 113 additions and 154 deletions

View File

@ -24,6 +24,11 @@
#include <shellapi.h>
#endif
#ifndef __APPLE__
// For NVENC legacy constants
#include <ffnvcodec/nvEncodeAPI.h>
#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 <ffnvcodec/nvEncodeAPI.h>
#endif
enum preset_e : int {
p1 = 12, // PRESET_P1, // must be kept in sync with <libavcodec/nvenc.h>
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_e>
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_e>
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_e>
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 <typename T, typename F>
void
generic_f(std::unordered_map<std::string, std::string> &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<std::string, std::string> &vars, const std::string &name, std::string &input, const std::vector<std::string_view> &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);

View File

@ -11,6 +11,8 @@
#include <unordered_map>
#include <vector>
#include "nvenc/nvenc_config.h"
namespace config {
struct video_t {
// ffmpeg params
@ -26,12 +28,13 @@ namespace config {
std::optional<int> svtav1_preset;
} sw;
nvenc::nvenc_config nv;
struct {
std::optional<int> nv_preset;
std::optional<int> nv_tune;
std::optional<int> nv_rc;
int nv_coder;
} nv;
int preset;
int multipass;
int h264_coder;
} nv_legacy;
struct {
std::optional<int> qsv_preset;

View File

@ -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;

View File

@ -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;

View File

@ -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<encoder_platform_formats_avcodec>(
@ -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
{

View File

@ -872,41 +872,60 @@
<div v-if="currentTab === 'nv'" class="config-page">
<!--NVENC SETTINGS-->
<div class="mb-3">
<label for="nv_preset" class="form-label">NVENC Preset</label>
<select id="nv_preset" class="form-select" v-model="config.nv_preset">
<option value="p1">p1 -- fastest (lowest quality)</option>
<option value="p2">p2 -- faster (lower quality)</option>
<option value="p3">p3 -- fast (low quality)</option>
<option value="p4">p4 -- medium (default)</option>
<option value="p5">p5 -- slow (good quality)</option>
<option value="p6">p6 -- slower (better quality)</option>
<option value="p7">p7 -- slowest (best quality)</option>
<label for="nvenc_preset" class="form-label">Performance preset</label>
<select id="nvenc_preset" class="form-select" v-model="config.nvenc_preset">
<option value="1">P1 (fastest, default)</option>
<option value="2">P2</option>
<option value="3">P3</option>
<option value="4">P4</option>
<option value="5">P5</option>
<option value="6">P6</option>
<option value="7">P7 (slowest)</option>
</select>
<div class="form-text">Higher numbers improve compression (quality at given bitrate) at the cost of
<strong>increased encoding latency</strong>.<br>
Recommended to change only when limited by network or decoder, otherwise similar effect can be accomplished by
increasing bitrate.
</div>
</div>
<div class="mb-3">
<label for="nv_tune" class="form-label">NVENC Tune</label>
<select id="nv_tune" class="form-select" v-model="config.nv_tune">
<option value="hq">hq -- high quality</option>
<option value="ll">ll -- low latency</option>
<option value="ull">ull -- ultra low latency (default)</option>
<option value="lossless">lossless -- lossless</option>
<label for="nvenc_twopass" class="form-label">Two-pass mode</label>
<select id="nvenc_twopass" class="form-select" v-model="config.nvenc_twopass">
<option value="disabled">Disabled (fastest, not recommended)</option>
<option value="quarter_res">Quarter resolution (faster, default)</option>
<option value="full_res">Full resolution (slower)</option>
</select>
<div class="form-text">Adds preliminary encoding pass.<br>
This allows to detect more motion vectors, better distribute bitrate across the frame and more strictly adhere to
bitrate limits.<br>
Disabling it is not recommended since this can lead to occasional bitrate overshoot and subsequent packet loss.
</div>
</div>
<div class="mb-3">
<label for="nv_rc" class="form-label">NVENC Rate Control</label>
<select id="nv_rc" class="form-select" v-model="config.nv_rc">
<option value="constqp">constqp -- constant qp mode</option>
<option value="vbr">vbr -- variable bitrate</option>
<option value="cbr">cbr -- constant bitrate (default)</option>
</select>
</div>
<div class="mb-3">
<label for="nv_coder" class="form-label">NVENC Coder (H264)</label>
<select id="nv_coder" class="form-select" v-model="config.nv_coder">
<option value="auto">auto -- let ffmpeg decide (default)</option>
<option value="cabac">cabac -- context adaptive binary arithmetic coding - higher quality</option>
<option value="cavlc">cavlc -- context adaptive variable-length coding - faster decode</option>
</select>
<div class="accordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button" type="button" data-bs-toggle="collapse"
data-bs-target="#panelsStayOpen-collapseOne">
Miscellaneous options
</button>
</h2>
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse show"
aria-labelledby="panelsStayOpen-headingOne">
<div class="accordion-body">
<div>
<label for="nvenc_h264_cavlc" class="form-label">Prefer CAVLC over CABAC in H.264</label>
<select id="nvenc_h264_cavlc" class="form-select" v-model="config.nvenc_h264_cavlc">
<option value="disabled">Disabled (default)</option>
<option value="enabled">Enabled</option>
</select>
<div class="form-text">Simpler form of entropy coding.<br>
CAVLC needs around 10% more bitrate for same quality.<br>
Only relevant for really old decoding devices.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Intel Encoder Settings-->
@ -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",