ffmpeg-encoder/nvenc: Add minimum bitrate, fix target quality and more

Adds support for specifying Minimum Bitrate directly in the UI instead of requiring custom settings to do so. Additionally Adaptive I/B-Frames are now only shown if Look-Ahead is a value greater than 0 frames.

Quality Minimum can also now be left at a default value of -1, the Quality group is no longer toggleable and Quality Target moved into the group. Settings options on the context is now searching children too (if there are any).

Finally, some C++17 formatting was done.

Fixes #101
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2020-01-15 05:50:31 +01:00
parent 5d5a104819
commit 34b2859dac
2 changed files with 111 additions and 94 deletions

View file

@ -352,11 +352,13 @@ Codec.HEVC.Profile="Profile"
Codec.HEVC.Profile.main="Main" Codec.HEVC.Profile.main="Main"
Codec.HEVC.Profile.main10="Main 10-bit" Codec.HEVC.Profile.main10="Main 10-bit"
Codec.HEVC.Profile.rext="Range Extended" Codec.HEVC.Profile.rext="Range Extended"
Codec.HEVC.Profile.Description="H.265 profile determines which features of the codec can be used."
Codec.HEVC.Tier="Tier" Codec.HEVC.Tier="Tier"
Codec.HEVC.Tier.main="Main" Codec.HEVC.Tier.main="Main"
Codec.HEVC.Tier.high="High" Codec.HEVC.Tier.high="High"
Codec.HEVC.Tier.Description="H.265 tier determines the bitrate guidelines used for the video."
Codec.HEVC.Level="Level" Codec.HEVC.Level="Level"
Codec.HEVC.Level.Description="Level determines the upper limits of resolution, frame rate and bitrate for the video." Codec.HEVC.Level.Description="Level determines the upper limits of resolution and frame rate."
# Codec: Apple ProRes # Codec: Apple ProRes
Codec.ProRes.Profile="Profile" Codec.ProRes.Profile="Profile"
@ -422,42 +424,38 @@ FFmpegEncoder.NVENC.RateControl.Mode.CBR_HQ="High Quality Constant Bitrate"
FFmpegEncoder.NVENC.RateControl.Mode.CBR_HQ.Description="Constant Bitrate with two-pass encoding enabled by default." FFmpegEncoder.NVENC.RateControl.Mode.CBR_HQ.Description="Constant Bitrate with two-pass encoding enabled by default."
FFmpegEncoder.NVENC.RateControl.Mode.CBR_LD_HQ="Low Delay High Quality Constant Bitrate" FFmpegEncoder.NVENC.RateControl.Mode.CBR_LD_HQ="Low Delay High Quality Constant Bitrate"
FFmpegEncoder.NVENC.RateControl.Mode.CBR_LD_HQ.Description="Constant Bitrate optimized for lowest encoding latency." FFmpegEncoder.NVENC.RateControl.Mode.CBR_LD_HQ.Description="Constant Bitrate optimized for lowest encoding latency."
FFmpegEncoder.NVENC.RateControl.TwoPass="Two Pass"
FFmpegEncoder.NVENC.RateControl.TwoPass.Description="Enable a secondary pass for encoding, which can help with quality and bitrate stability.\nImproves quality slightly at the cost of some GPU time.\nNvidia Turing hardware might actually see a quality degrade from this."
FFmpegEncoder.NVENC.RateControl.LookAhead="Look Ahead" FFmpegEncoder.NVENC.RateControl.LookAhead="Look Ahead"
FFmpegEncoder.NVENC.RateControl.LookAhead.Description="Look ahead this many frames while encoding to better distribute bitrate.\nImproves quality slightly at the cost of some GPU time.\nSet to 0 to disable." FFmpegEncoder.NVENC.RateControl.LookAhead.Description="Look ahead this many frames while encoding to better distribute bitrate.\nImproves quality slightly at the cost of some GPU time.\nSet to 0 to disable."
FFmpegEncoder.NVENC.RateControl.AdaptiveI="Adaptive I-Frames" FFmpegEncoder.NVENC.RateControl.AdaptiveI="Adaptive I-Frames"
FFmpegEncoder.NVENC.RateControl.AdaptiveI.Description="Enables adaptive I-Frame insertion.\nOnly has an effect when look ahead is set to a value other than 0." FFmpegEncoder.NVENC.RateControl.AdaptiveI.Description="Enables adaptive I-Frame insertion.\nOnly has an effect when look ahead is set to a value other than 0."
FFmpegEncoder.NVENC.RateControl.AdaptiveB="Adaptive B-Frames" FFmpegEncoder.NVENC.RateControl.AdaptiveB="Adaptive B-Frames"
FFmpegEncoder.NVENC.RateControl.AdaptiveB.Description="Enables adaptive B-Frame insertion.\nOnly has an effect when look ahead is set to a value other than 0." FFmpegEncoder.NVENC.RateControl.AdaptiveB.Description="Enables adaptive B-Frame insertion.\nOnly has an effect when look ahead is set to a value other than 0."
FFmpegEncoder.NVENC.RateControl.TwoPass="Two Pass" FFmpegEncoder.NVENC.RateControl.BufferSize="Buffer Size"
FFmpegEncoder.NVENC.RateControl.TwoPass.Description="Enable a secondary pass for encoding, which can help with quality and bitrate stability.\nImproves quality slightly at the cost of some GPU time.\nNvidia Turing hardware might actually see a quality degrade from this." FFmpegEncoder.NVENC.RateControl.BufferSize.Description="Specifies the buffer size used for bitrate constrained modes.\nIdeally set to (KeyFrame Interval In Seconds * Bitrate Target), so at 2 seconds and 6000 kbit it should be 12000."
FFmpegEncoder.NVENC.RateControl.Bitrate="Bitrate Limits" FFmpegEncoder.NVENC.RateControl.Bitrate="Bitrate Limits"
FFmpegEncoder.NVENC.RateControl.Bitrate.Target="Target Bitrate" FFmpegEncoder.NVENC.RateControl.Bitrate.Target="Target Bitrate"
FFmpegEncoder.NVENC.RateControl.Bitrate.Maximum="Minimum Bitrate"
FFmpegEncoder.NVENC.RateControl.Bitrate.Maximum="Maximum Bitrate" FFmpegEncoder.NVENC.RateControl.Bitrate.Maximum="Maximum Bitrate"
FFmpegEncoder.NVENC.RateControl.BufferSize="Buffer Size" FFmpegEncoder.NVENC.RateControl.Quality="Quality Limits"
FFmpegEncoder.NVENC.RateControl.Quality="Enable Quality Limits" FFmpegEncoder.NVENC.RateControl.Quality.Target="Target Quality"
FFmpegEncoder.NVENC.RateControl.Quality.Target.Description="Target quality to achieve, with values closer to 0 being better quality.\nSet to 0 to disable the target quality restriction."
FFmpegEncoder.NVENC.RateControl.Quality.Minimum="Minimum Quality" FFmpegEncoder.NVENC.RateControl.Quality.Minimum="Minimum Quality"
FFmpegEncoder.NVENC.RateControl.Quality.Minimum.Description="Minimum quality to achieve, with values closer to 0 being better quality." FFmpegEncoder.NVENC.RateControl.Quality.Minimum.Description="Minimum quality to achieve, with values closer to 0 being better quality.\nSet to -1 to disable the maximum restriction."
FFmpegEncoder.NVENC.RateControl.Quality.Maximum="Maximum Quality" FFmpegEncoder.NVENC.RateControl.Quality.Maximum="Maximum Quality"
FFmpegEncoder.NVENC.RateControl.Quality.Maximum.Description="Maximum quality to achieve, with values closer to 0 being better quality.\nSet to -1 to disable the maximum restriction." FFmpegEncoder.NVENC.RateControl.Quality.Maximum.Description="Maximum quality to achieve, with values closer to 0 being better quality.\nSet to -1 to disable the maximum restriction."
FFmpegEncoder.NVENC.RateControl.Quality.Target="Target Quality"
FFmpegEncoder.NVENC.RateControl.Quality.Target.Description="Target quality to achieve, with values closer to 0 being better quality.\nSet to 0 to disable the maximum restriction."
FFmpegEncoder.NVENC.RateControl.QP="Quantization Parameters" FFmpegEncoder.NVENC.RateControl.QP="Quantization Parameters"
FFmpegEncoder.NVENC.RateControl.QP.I="I-Frame QP" FFmpegEncoder.NVENC.RateControl.QP.I="I-Frame QP"
FFmpegEncoder.NVENC.RateControl.QP.I.Description="Quantization parameter for I-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality." FFmpegEncoder.NVENC.RateControl.QP.I.Description="Quantization parameter for I-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality."
FFmpegEncoder.NVENC.RateControl.QP.I.Initial="Initial I-Frame QP"
FFmpegEncoder.NVENC.RateControl.QP.I.Initial.Description="Initial B-Frame quantization parameter.\nSet to -1 to use the automatically detected value instead."
FFmpegEncoder.NVENC.RateControl.QP.P="P-Frame QP" FFmpegEncoder.NVENC.RateControl.QP.P="P-Frame QP"
FFmpegEncoder.NVENC.RateControl.QP.P.Description="Quantization parameter for P-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality." FFmpegEncoder.NVENC.RateControl.QP.P.Description="Quantization parameter for P-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality."
FFmpegEncoder.NVENC.RateControl.QP.P.Initial="Initial P-Frame QP"
FFmpegEncoder.NVENC.RateControl.QP.P.Initial.Description="Initial P-Frame quantization parameter.\nSet to -1 to use the automatically detected value instead."
FFmpegEncoder.NVENC.RateControl.QP.B="B-Frame QP" FFmpegEncoder.NVENC.RateControl.QP.B="B-Frame QP"
FFmpegEncoder.NVENC.RateControl.QP.B.Description="Quantization parameter for B-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality." FFmpegEncoder.NVENC.RateControl.QP.B.Description="Quantization parameter for B-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality."
FFmpegEncoder.NVENC.RateControl.QP.B.Initial="Initial B-Frame QP"
FFmpegEncoder.NVENC.RateControl.QP.B.Initial.Description="Initial B-Frame quantization parameter.\nSet to -1 to use the automatically detected value instead."
FFmpegEncoder.NVENC.AQ="Adaptive Quantization" FFmpegEncoder.NVENC.AQ="Adaptive Quantization"
FFmpegEncoder.NVENC.AQ.Spatial="Spatial Adaptive Quantization" FFmpegEncoder.NVENC.AQ.Spatial="Spatial Adaptive Quantization"
FFmpegEncoder.NVENC.AQ.Spatial.Description="Enable spatial adaptive quantization, also sometimes referred to as Psychovisual Adaptive Quantization." FFmpegEncoder.NVENC.AQ.Spatial.Description="Enable spatial adaptive quantization, also sometimes referred to as Psychovisual Adaptive Quantization."
FFmpegEncoder.NVENC.AQ.Strength="Spatial AQ Strength" FFmpegEncoder.NVENC.AQ.Strength="Spatial Adaptive Quantization Strength"
FFmpegEncoder.NVENC.AQ.Strength.Description="Strength of the spatial adaptive quantization.\nValues closer to 15 mean more aggressive, while values closer to 1 mean more relaxed." FFmpegEncoder.NVENC.AQ.Strength.Description="Strength of the spatial adaptive quantization.\nValues closer to 15 mean more aggressive, while values closer to 1 mean more relaxed."
FFmpegEncoder.NVENC.AQ.Temporal="Temporal Adaptive Quantization" FFmpegEncoder.NVENC.AQ.Temporal="Temporal Adaptive Quantization"
FFmpegEncoder.NVENC.AQ.Temporal.Description="Enable temporal adaptive quantization." FFmpegEncoder.NVENC.AQ.Temporal.Description="Enable temporal adaptive quantization."

View file

@ -47,6 +47,7 @@ extern "C" {
#define ST_RATECONTROL_ADAPTIVEB ST_RATECONTROL ".AdaptiveB" #define ST_RATECONTROL_ADAPTIVEB ST_RATECONTROL ".AdaptiveB"
#define ST_RATECONTROL_BITRATE ST_RATECONTROL ".Bitrate" #define ST_RATECONTROL_BITRATE ST_RATECONTROL ".Bitrate"
#define ST_RATECONTROL_BITRATE_TARGET ST_RATECONTROL_BITRATE ".Target" #define ST_RATECONTROL_BITRATE_TARGET ST_RATECONTROL_BITRATE ".Target"
#define ST_RATECONTROL_BITRATE_MINIMUM ST_RATECONTROL_BITRATE ".Minimum"
#define ST_RATECONTROL_BITRATE_MAXIMUM ST_RATECONTROL_BITRATE ".Maximum" #define ST_RATECONTROL_BITRATE_MAXIMUM ST_RATECONTROL_BITRATE ".Maximum"
#define ST_RATECONTROL_BUFFERSIZE ST_RATECONTROL ".BufferSize" #define ST_RATECONTROL_BUFFERSIZE ST_RATECONTROL ".BufferSize"
#define ST_RATECONTROL_QUALITY ST_RATECONTROL ".Quality" #define ST_RATECONTROL_QUALITY ST_RATECONTROL ".Quality"
@ -75,6 +76,7 @@ extern "C" {
#define KEY_RATECONTROL_ADAPTIVEI "RateControl.AdaptiveI" #define KEY_RATECONTROL_ADAPTIVEI "RateControl.AdaptiveI"
#define KEY_RATECONTROL_ADAPTIVEB "RateControl.AdaptiveB" #define KEY_RATECONTROL_ADAPTIVEB "RateControl.AdaptiveB"
#define KEY_RATECONTROL_BITRATE_TARGET "RateControl.Bitrate.Target" #define KEY_RATECONTROL_BITRATE_TARGET "RateControl.Bitrate.Target"
#define KEY_RATECONTROL_BITRATE_MINIMUM "RateControl.Bitrate.Minimum"
#define KEY_RATECONTROL_BITRATE_MAXIMUM "RateControl.Bitrate.Maximum" #define KEY_RATECONTROL_BITRATE_MAXIMUM "RateControl.Bitrate.Maximum"
#define KEY_RATECONTROL_BUFFERSIZE "RateControl.BufferSize" #define KEY_RATECONTROL_BUFFERSIZE "RateControl.BufferSize"
#define KEY_RATECONTROL_QUALITY "RateControl.Quality" #define KEY_RATECONTROL_QUALITY "RateControl.Quality"
@ -194,13 +196,13 @@ void nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*)
obs_data_set_default_int(settings, KEY_RATECONTROL_ADAPTIVEB, -1); obs_data_set_default_int(settings, KEY_RATECONTROL_ADAPTIVEB, -1);
obs_data_set_default_int(settings, KEY_RATECONTROL_BITRATE_TARGET, 6000); obs_data_set_default_int(settings, KEY_RATECONTROL_BITRATE_TARGET, 6000);
obs_data_set_default_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM, 6000); obs_data_set_default_int(settings, KEY_RATECONTROL_BITRATE_MINIMUM, 0);
obs_data_set_default_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM, 0);
obs_data_set_default_int(settings, KEY_RATECONTROL_BUFFERSIZE, 12000); obs_data_set_default_int(settings, KEY_RATECONTROL_BUFFERSIZE, 12000);
obs_data_set_default_bool(settings, KEY_RATECONTROL_QUALITY, false); obs_data_set_default_double(settings, KEY_RATECONTROL_QUALITY_TARGET, 0);
obs_data_set_default_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM, 51); obs_data_set_default_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM, -1);
obs_data_set_default_int(settings, KEY_RATECONTROL_QUALITY_MAXIMUM, -1); obs_data_set_default_int(settings, KEY_RATECONTROL_QUALITY_MAXIMUM, -1);
obs_data_set_default_int(settings, KEY_RATECONTROL_QUALITY_TARGET, 0);
obs_data_set_default_int(settings, KEY_RATECONTROL_QP_I, 21); obs_data_set_default_int(settings, KEY_RATECONTROL_QP_I, 21);
obs_data_set_default_int(settings, KEY_RATECONTROL_QP_P, 21); obs_data_set_default_int(settings, KEY_RATECONTROL_QP_P, 21);
@ -249,6 +251,7 @@ static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_d
obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_BITRATE), have_bitrate || have_bitrate_max); obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_BITRATE), have_bitrate || have_bitrate_max);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BITRATE_TARGET), have_bitrate); obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BITRATE_TARGET), have_bitrate);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BITRATE_MINIMUM), have_bitrate_max);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BITRATE_MAXIMUM), have_bitrate_max); obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BITRATE_MAXIMUM), have_bitrate_max);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BUFFERSIZE), have_bitrate || have_bitrate_max); obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BUFFERSIZE), have_bitrate || have_bitrate_max);
@ -265,6 +268,14 @@ static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_d
return true; return true;
} }
static bool modified_lookahead(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept
{
int64_t v = obs_data_get_int(settings, KEY_RATECONTROL_LOOKAHEAD);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_ADAPTIVEI), v > 0);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_ADAPTIVEB), v > 0);
return true;
}
static bool modified_quality(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept static bool modified_quality(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept
{ {
bool enabled = obs_data_get_bool(settings, ST_RATECONTROL_QUALITY); bool enabled = obs_data_get_bool(settings, ST_RATECONTROL_QUALITY);
@ -322,17 +333,27 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
0, 32, 1); 0, 32, 1);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_LOOKAHEAD))); obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_LOOKAHEAD)));
obs_property_int_set_suffix(p, " frames"); obs_property_int_set_suffix(p, " frames");
obs_property_set_modified_callback(p, modified_lookahead);
} }
{ {
auto p = auto p = util::obs_properties_add_tristate(grp, KEY_RATECONTROL_ADAPTIVEI,
util::obs_properties_add_tristate(grp, ST_RATECONTROL_ADAPTIVEI, D_TRANSLATE(ST_RATECONTROL_ADAPTIVEI)); D_TRANSLATE(ST_RATECONTROL_ADAPTIVEI));
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_ADAPTIVEI))); obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_ADAPTIVEI)));
} }
if (strcmp(codec->name, "h264_nvenc") == 0) { if (strcmp(codec->name, "h264_nvenc") == 0) {
auto p = auto p = util::obs_properties_add_tristate(grp, KEY_RATECONTROL_ADAPTIVEB,
util::obs_properties_add_tristate(grp, ST_RATECONTROL_ADAPTIVEB, D_TRANSLATE(ST_RATECONTROL_ADAPTIVEB)); D_TRANSLATE(ST_RATECONTROL_ADAPTIVEB));
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_ADAPTIVEB))); obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_ADAPTIVEB)));
} }
{
auto p = obs_properties_add_int(grp, KEY_RATECONTROL_BUFFERSIZE, D_TRANSLATE(ST_RATECONTROL_BUFFERSIZE), 0,
std::numeric_limits<int32_t>::max(), 1);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_BUFFERSIZE)));
obs_property_int_set_suffix(p, " kbit");
}
} }
{ {
@ -345,23 +366,21 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
{ {
auto p = auto p =
obs_properties_add_int(grp, ST_RATECONTROL_BITRATE_TARGET, D_TRANSLATE(ST_RATECONTROL_BITRATE_TARGET), obs_properties_add_int(grp, KEY_RATECONTROL_BITRATE_TARGET, D_TRANSLATE(ST_RATECONTROL_BITRATE_TARGET),
0, std::numeric_limits<int32_t>::max(), 1); 0, std::numeric_limits<int32_t>::max(), 1);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_BITRATE_TARGET)));
obs_property_int_set_suffix(p, " kbit/s"); obs_property_int_set_suffix(p, " kbit/s");
} }
{ {
auto p = auto p = obs_properties_add_int(grp, KEY_RATECONTROL_BITRATE_MINIMUM,
obs_properties_add_int(grp, ST_RATECONTROL_BITRATE_MAXIMUM, D_TRANSLATE(ST_RATECONTROL_BITRATE_MAXIMUM), D_TRANSLATE(ST_RATECONTROL_BITRATE_MINIMUM), 0,
0, std::numeric_limits<int32_t>::max(), 1);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_BITRATE_MAXIMUM)));
obs_property_int_set_suffix(p, " kbit/s");
}
{
auto p = obs_properties_add_int(grp, KEY_RATECONTROL_BUFFERSIZE, D_TRANSLATE(ST_RATECONTROL_BUFFERSIZE), 0,
std::numeric_limits<int32_t>::max(), 1); std::numeric_limits<int32_t>::max(), 1);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_BUFFERSIZE))); obs_property_int_set_suffix(p, " kbit/s");
obs_property_int_set_suffix(p, " kbit"); }
{
auto p = obs_properties_add_int(grp, KEY_RATECONTROL_BITRATE_MAXIMUM,
D_TRANSLATE(ST_RATECONTROL_BITRATE_MAXIMUM), 0,
std::numeric_limits<int32_t>::max(), 1);
obs_property_int_set_suffix(p, " kbit/s");
} }
} }
@ -370,16 +389,19 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
if (!util::are_property_groups_broken()) { if (!util::are_property_groups_broken()) {
grp = obs_properties_create(); grp = obs_properties_create();
auto p = obs_properties_add_group(props, ST_RATECONTROL_QUALITY, D_TRANSLATE(ST_RATECONTROL_QUALITY), auto p = obs_properties_add_group(props, ST_RATECONTROL_QUALITY, D_TRANSLATE(ST_RATECONTROL_QUALITY),
OBS_GROUP_CHECKABLE, grp); OBS_GROUP_NORMAL, grp);
obs_property_set_modified_callback(p, modified_quality);
} else {
auto p = obs_properties_add_bool(props, ST_RATECONTROL_QUALITY, D_TRANSLATE(ST_RATECONTROL_QUALITY));
obs_property_set_modified_callback(p, modified_quality); obs_property_set_modified_callback(p, modified_quality);
} }
{
auto p = obs_properties_add_float_slider(grp, KEY_RATECONTROL_QUALITY_TARGET,
D_TRANSLATE(ST_RATECONTROL_QUALITY_TARGET), 0, 100, 0.01);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_QUALITY_TARGET)));
}
{ {
auto p = obs_properties_add_int_slider(grp, KEY_RATECONTROL_QUALITY_MINIMUM, auto p = obs_properties_add_int_slider(grp, KEY_RATECONTROL_QUALITY_MINIMUM,
D_TRANSLATE(ST_RATECONTROL_QUALITY_MINIMUM), 0, 51, 1); D_TRANSLATE(ST_RATECONTROL_QUALITY_MINIMUM), -1, 51, 1);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_QUALITY_MINIMUM))); obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_QUALITY_MINIMUM)));
} }
{ {
@ -389,12 +411,6 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
} }
} }
{
auto p = obs_properties_add_float_slider(props, KEY_RATECONTROL_QUALITY_TARGET,
D_TRANSLATE(ST_RATECONTROL_QUALITY_TARGET), 0, 100, 0.01);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_QUALITY_TARGET)));
}
{ {
obs_properties_t* grp = props; obs_properties_t* grp = props;
if (!util::are_property_groups_broken()) { if (!util::are_property_groups_broken()) {
@ -460,7 +476,6 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
auto p = auto p =
obs_properties_add_list(grp, KEY_OTHER_BFRAMEREFERENCEMODE, D_TRANSLATE(ST_OTHER_BFRAMEREFERENCEMODE), obs_properties_add_list(grp, KEY_OTHER_BFRAMEREFERENCEMODE, D_TRANSLATE(ST_OTHER_BFRAMEREFERENCEMODE),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_OTHER_BFRAMEREFERENCEMODE)));
for (auto kv : b_ref_modes) { for (auto kv : b_ref_modes) {
obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast<int64_t>(kv.first)); obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast<int64_t>(kv.first));
} }
@ -494,10 +509,10 @@ void nvenc::get_runtime_properties(obs_properties_t* props, const AVCodec*, AVCo
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_LOOKAHEAD), false); obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_LOOKAHEAD), false);
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_ADAPTIVEI), false); obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_ADAPTIVEI), false);
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_ADAPTIVEB), false); obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_ADAPTIVEB), false);
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_BUFFERSIZE), true);
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_BITRATE), true); obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_BITRATE), true);
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_BITRATE_TARGET), true); obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_BITRATE_TARGET), true);
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_BITRATE_MAXIMUM), true); obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_BITRATE_MAXIMUM), true);
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_BUFFERSIZE), true);
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QUALITY), false); obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QUALITY), false);
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_QUALITY_MINIMUM), false); obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_QUALITY_MINIMUM), false);
obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_QUALITY_MAXIMUM), false); obs_property_set_enabled(obs_properties_get(props, KEY_RATECONTROL_QUALITY_MAXIMUM), false);
@ -540,10 +555,10 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
ratecontrolmode rc = static_cast<ratecontrolmode>(obs_data_get_int(settings, KEY_RATECONTROL_MODE)); ratecontrolmode rc = static_cast<ratecontrolmode>(obs_data_get_int(settings, KEY_RATECONTROL_MODE));
auto rcopt = ratecontrolmode_to_opt.find(rc); auto rcopt = ratecontrolmode_to_opt.find(rc);
if (rcopt != ratecontrolmode_to_opt.end()) { if (rcopt != ratecontrolmode_to_opt.end()) {
av_opt_set(context->priv_data, "rc", rcopt->second.c_str(), 0); av_opt_set(context->priv_data, "rc", rcopt->second.c_str(), AV_OPT_SEARCH_CHILDREN);
} }
av_opt_set_int(context->priv_data, "cbr", 0, 0); av_opt_set_int(context->priv_data, "cbr", 0, AV_OPT_SEARCH_CHILDREN);
switch (rc) { switch (rc) {
case ratecontrolmode::CQP: case ratecontrolmode::CQP:
have_qp = true; have_qp = true;
@ -553,7 +568,7 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
case ratecontrolmode::CBR_HQ: case ratecontrolmode::CBR_HQ:
case ratecontrolmode::CBR_LD_HQ: case ratecontrolmode::CBR_LD_HQ:
have_bitrate = true; have_bitrate = true;
av_opt_set_int(context->priv_data, "cbr", 1, 0); av_opt_set_int(context->priv_data, "cbr", 1, AV_OPT_SEARCH_CHILDREN);
break; break;
case ratecontrolmode::VBR: case ratecontrolmode::VBR:
case ratecontrolmode::VBR_HQ: case ratecontrolmode::VBR_HQ:
@ -564,59 +579,65 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
break; break;
} }
int tp = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_TWOPASS)); if (int tp = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_TWOPASS)); tp >= 0) {
if (tp >= 0) { av_opt_set_int(context->priv_data, "2pass", tp ? 1 : 0, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(context->priv_data, "2pass", tp ? 1 : 0, 0);
} }
int la = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_LOOKAHEAD)); int la = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_LOOKAHEAD));
av_opt_set_int(context->priv_data, "rc-lookahead", la, 0); av_opt_set_int(context->priv_data, "rc-lookahead", la, AV_OPT_SEARCH_CHILDREN);
if (la > 0) { if (la > 0) {
int64_t adapt_i = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEI); if (int64_t adapt_i = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEI);
if (!util::is_tristate_default(adapt_i)) { !util::is_tristate_default(adapt_i)) {
av_opt_set_int(context->priv_data, "no-scenecut", adapt_i, AV_OPT_SEARCH_CHILDREN); av_opt_set_int(context->priv_data, "no-scenecut", adapt_i, AV_OPT_SEARCH_CHILDREN);
} }
if (strcmp(codec->name, "h264_nvenc")) { if (strcmp(codec->name, "h264_nvenc")) {
int64_t adapt_b = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEB); if (int64_t adapt_b = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEB);
if (!util::is_tristate_default(adapt_b)) { !util::is_tristate_default(adapt_b)) {
av_opt_set_int(context->priv_data, "b_adapt", adapt_b, AV_OPT_SEARCH_CHILDREN); av_opt_set_int(context->priv_data, "b_adapt", adapt_b, AV_OPT_SEARCH_CHILDREN);
} }
} }
} }
if (have_bitrate) { if (have_bitrate) {
context->bit_rate = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_TARGET) * 1000); int64_t v = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_TARGET);
// Support for Replay Buffer if (v >= 0)
obs_data_set_int(settings, "bitrate", obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_TARGET)); context->bit_rate = static_cast<int>(v * 1000);
}
if (have_bitrate_max)
context->rc_max_rate = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM) * 1000);
if (have_bitrate || have_bitrate_max)
context->rc_buffer_size = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_BUFFERSIZE) * 1000);
if (have_quality && obs_data_get_bool(settings, KEY_RATECONTROL_QUALITY)) { // Support for Replay Buffer
int qmin = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM)); obs_data_set_int(settings, "bitrate", v);
context->qmin = qmin;
if (qmin >= 0) {
context->qmax = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MAXIMUM));
} }
if (have_bitrate_max) {
if (int64_t min = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_MINIMUM); min >= 0)
context->rc_min_rate = static_cast<int>(min * 1000);
if (int64_t max = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM); max >= 0)
context->rc_max_rate = static_cast<int>(max * 1000);
}
if (have_bitrate || have_bitrate_max) {
if (int64_t v = obs_data_get_int(settings, KEY_RATECONTROL_BUFFERSIZE); v >= 0)
context->rc_buffer_size = static_cast<int>(v * 1000);
}
if (have_quality) {
if (int qmin = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM)); qmin >= 0)
context->qmin = qmin;
if (int qmax = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MAXIMUM)); qmax >= 0)
context->qmax = qmax;
} }
{ {
double_t v = obs_data_get_double(settings, KEY_RATECONTROL_QUALITY_TARGET) / 100.0 * 51.0; if (double_t v = obs_data_get_double(settings, KEY_RATECONTROL_QUALITY_TARGET) / 100.0 * 51.0; > 0) {
if (v > 0) { av_opt_set_double(context->priv_data, "cq", v, AV_OPT_SEARCH_CHILDREN);
av_opt_set_double(context->priv_data, "cq", v, 0);
} }
} }
if (have_qp) { if (have_qp) {
av_opt_set_int(context->priv_data, "init_qpI", av_opt_set_int(context->priv_data, "init_qpI",
static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_I)), 0); static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_I)), AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(context->priv_data, "init_qpP", av_opt_set_int(context->priv_data, "init_qpP",
static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_P)), 0); static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_P)), AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(context->priv_data, "init_qpB", av_opt_set_int(context->priv_data, "init_qpB",
static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_B)), 0); static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_B)), AV_OPT_SEARCH_CHILDREN);
} }
} }
@ -626,44 +647,42 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
if (strcmp(codec->name, "h264_nvenc") == 0) { if (strcmp(codec->name, "h264_nvenc") == 0) {
if (!util::is_tristate_default(saq)) if (!util::is_tristate_default(saq))
av_opt_set_int(context->priv_data, "spatial-aq", saq, 0); av_opt_set_int(context->priv_data, "spatial-aq", saq, AV_OPT_SEARCH_CHILDREN);
if (!util::is_tristate_default(taq)) if (!util::is_tristate_default(taq))
av_opt_set_int(context->priv_data, "temporal-aq", taq, 0); av_opt_set_int(context->priv_data, "temporal-aq", taq, AV_OPT_SEARCH_CHILDREN);
} else { } else {
if (!util::is_tristate_default(saq)) if (!util::is_tristate_default(saq))
av_opt_set_int(context->priv_data, "spatial_aq", saq, 0); av_opt_set_int(context->priv_data, "spatial_aq", saq, AV_OPT_SEARCH_CHILDREN);
if (!util::is_tristate_default(taq)) if (!util::is_tristate_default(taq))
av_opt_set_int(context->priv_data, "temporal_aq", taq, 0); av_opt_set_int(context->priv_data, "temporal_aq", taq, AV_OPT_SEARCH_CHILDREN);
} }
if (util::is_tristate_enabled(saq)) if (util::is_tristate_enabled(saq))
av_opt_set_int(context->priv_data, "aq-strength", av_opt_set_int(context->priv_data, "aq-strength",
static_cast<int>(obs_data_get_int(settings, KEY_AQ_STRENGTH)), 0); static_cast<int>(obs_data_get_int(settings, KEY_AQ_STRENGTH)), AV_OPT_SEARCH_CHILDREN);
} }
{ // Other { // Other
int64_t zl = obs_data_get_int(settings, KEY_OTHER_ZEROLATENCY);
int64_t wp = obs_data_get_int(settings, KEY_OTHER_WEIGHTEDPREDICTION); int64_t wp = obs_data_get_int(settings, KEY_OTHER_WEIGHTEDPREDICTION);
int64_t nrp = obs_data_get_int(settings, KEY_OTHER_NONREFERENCEPFRAMES);
context->max_b_frames = static_cast<int>(obs_data_get_int(settings, KEY_OTHER_BFRAMES)); context->max_b_frames = static_cast<int>(obs_data_get_int(settings, KEY_OTHER_BFRAMES));
if (!util::is_tristate_default(zl)) if (int64_t zl = obs_data_get_int(settings, KEY_OTHER_ZEROLATENCY); !util::is_tristate_default(zl))
av_opt_set_int(context->priv_data, "zerolatency", zl, 0); av_opt_set_int(context->priv_data, "zerolatency", zl, AV_OPT_SEARCH_CHILDREN);
if (!util::is_tristate_default(nrp)) if (int64_t nrp = obs_data_get_int(settings, KEY_OTHER_NONREFERENCEPFRAMES); !util::is_tristate_default(nrp))
av_opt_set_int(context->priv_data, "nonref_p", nrp, 0); av_opt_set_int(context->priv_data, "nonref_p", nrp, AV_OPT_SEARCH_CHILDREN);
if ((context->max_b_frames != 0) && util::is_tristate_enabled(wp)) { if ((context->max_b_frames != 0) && util::is_tristate_enabled(wp)) {
LOG_WARNING("[%s] Weighted Prediction disabled because of B-Frames being used.", codec->name); LOG_WARNING("[%s] Weighted Prediction disabled because of B-Frames being used.", codec->name);
av_opt_set_int(context->priv_data, "weighted_pred", 0, 0); av_opt_set_int(context->priv_data, "weighted_pred", 0, AV_OPT_SEARCH_CHILDREN);
} else if (!util::is_tristate_default(wp)) { } else if (!util::is_tristate_default(wp)) {
av_opt_set_int(context->priv_data, "weighted_pred", wp, 0); av_opt_set_int(context->priv_data, "weighted_pred", wp, AV_OPT_SEARCH_CHILDREN);
} }
{ {
auto found = b_ref_mode_to_opt.find( auto found = b_ref_mode_to_opt.find(
static_cast<b_ref_mode>(obs_data_get_int(settings, KEY_OTHER_BFRAMEREFERENCEMODE))); static_cast<b_ref_mode>(obs_data_get_int(settings, KEY_OTHER_BFRAMEREFERENCEMODE)));
if (found != b_ref_mode_to_opt.end()) { if (found != b_ref_mode_to_opt.end()) {
av_opt_set(context->priv_data, "b_ref_mode", found->second.c_str(), 0); av_opt_set(context->priv_data, "b_ref_mode", found->second.c_str(), AV_OPT_SEARCH_CHILDREN);
} }
} }
} }