diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 11de3fc0..2fce7d46 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -352,11 +352,13 @@ Codec.HEVC.Profile="Profile" Codec.HEVC.Profile.main="Main" Codec.HEVC.Profile.main10="Main 10-bit" 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.main="Main" 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.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.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_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.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.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.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.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.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="Buffer Size" +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.Target="Target Bitrate" +FFmpegEncoder.NVENC.RateControl.Bitrate.Maximum="Minimum Bitrate" FFmpegEncoder.NVENC.RateControl.Bitrate.Maximum="Maximum Bitrate" -FFmpegEncoder.NVENC.RateControl.BufferSize="Buffer Size" -FFmpegEncoder.NVENC.RateControl.Quality="Enable Quality Limits" +FFmpegEncoder.NVENC.RateControl.Quality="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.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.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.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.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.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.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.Spatial="Spatial 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.Temporal="Temporal Adaptive Quantization" FFmpegEncoder.NVENC.AQ.Temporal.Description="Enable temporal adaptive quantization." diff --git a/source/encoders/handlers/nvenc_shared.cpp b/source/encoders/handlers/nvenc_shared.cpp index 76e7d313..fc57faa8 100644 --- a/source/encoders/handlers/nvenc_shared.cpp +++ b/source/encoders/handlers/nvenc_shared.cpp @@ -47,6 +47,7 @@ extern "C" { #define ST_RATECONTROL_ADAPTIVEB ST_RATECONTROL ".AdaptiveB" #define ST_RATECONTROL_BITRATE ST_RATECONTROL ".Bitrate" #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_BUFFERSIZE ST_RATECONTROL ".BufferSize" #define ST_RATECONTROL_QUALITY ST_RATECONTROL ".Quality" @@ -75,6 +76,7 @@ extern "C" { #define KEY_RATECONTROL_ADAPTIVEI "RateControl.AdaptiveI" #define KEY_RATECONTROL_ADAPTIVEB "RateControl.AdaptiveB" #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_BUFFERSIZE "RateControl.BufferSize" #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_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_bool(settings, KEY_RATECONTROL_QUALITY, false); - obs_data_set_default_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM, 51); + obs_data_set_default_double(settings, KEY_RATECONTROL_QUALITY_TARGET, 0); + 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_TARGET, 0); obs_data_set_default_int(settings, KEY_RATECONTROL_QP_I, 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, 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_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; } +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 { 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); obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_LOOKAHEAD))); obs_property_int_set_suffix(p, " frames"); + obs_property_set_modified_callback(p, modified_lookahead); } + { - auto p = - util::obs_properties_add_tristate(grp, ST_RATECONTROL_ADAPTIVEI, D_TRANSLATE(ST_RATECONTROL_ADAPTIVEI)); + auto p = util::obs_properties_add_tristate(grp, KEY_RATECONTROL_ADAPTIVEI, + D_TRANSLATE(ST_RATECONTROL_ADAPTIVEI)); obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_ADAPTIVEI))); } + if (strcmp(codec->name, "h264_nvenc") == 0) { - auto p = - util::obs_properties_add_tristate(grp, ST_RATECONTROL_ADAPTIVEB, D_TRANSLATE(ST_RATECONTROL_ADAPTIVEB)); + auto p = util::obs_properties_add_tristate(grp, KEY_RATECONTROL_ADAPTIVEB, + D_TRANSLATE(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::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 = - 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::max(), 1); - obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_BITRATE_TARGET))); obs_property_int_set_suffix(p, " kbit/s"); } { - auto p = - obs_properties_add_int(grp, ST_RATECONTROL_BITRATE_MAXIMUM, D_TRANSLATE(ST_RATECONTROL_BITRATE_MAXIMUM), - 0, std::numeric_limits::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, + auto p = obs_properties_add_int(grp, KEY_RATECONTROL_BITRATE_MINIMUM, + D_TRANSLATE(ST_RATECONTROL_BITRATE_MINIMUM), 0, std::numeric_limits::max(), 1); - obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_BUFFERSIZE))); - obs_property_int_set_suffix(p, " kbit"); + obs_property_int_set_suffix(p, " kbit/s"); + } + { + auto p = obs_properties_add_int(grp, KEY_RATECONTROL_BITRATE_MAXIMUM, + D_TRANSLATE(ST_RATECONTROL_BITRATE_MAXIMUM), 0, + std::numeric_limits::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()) { grp = obs_properties_create(); auto p = obs_properties_add_group(props, ST_RATECONTROL_QUALITY, D_TRANSLATE(ST_RATECONTROL_QUALITY), - OBS_GROUP_CHECKABLE, 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_GROUP_NORMAL, grp); 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, - 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))); } { @@ -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; if (!util::are_property_groups_broken()) { @@ -460,7 +476,6 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec) auto p = obs_properties_add_list(grp, KEY_OTHER_BFRAMEREFERENCEMODE, D_TRANSLATE(ST_OTHER_BFRAMEREFERENCEMODE), 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) { obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast(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_ADAPTIVEI), 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, 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_BUFFERSIZE), true); 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_MAXIMUM), false); @@ -540,10 +555,10 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c ratecontrolmode rc = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_MODE)); auto rcopt = ratecontrolmode_to_opt.find(rc); 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) { case ratecontrolmode::CQP: 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_LD_HQ: 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; case ratecontrolmode::VBR: case ratecontrolmode::VBR_HQ: @@ -564,59 +579,65 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c break; } - int tp = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_TWOPASS)); - if (tp >= 0) { - av_opt_set_int(context->priv_data, "2pass", tp ? 1 : 0, 0); + if (int tp = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_TWOPASS)); tp >= 0) { + av_opt_set_int(context->priv_data, "2pass", tp ? 1 : 0, AV_OPT_SEARCH_CHILDREN); } int la = static_cast(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) { - int64_t adapt_i = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEI); - if (!util::is_tristate_default(adapt_i)) { + if (int64_t adapt_i = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEI); + !util::is_tristate_default(adapt_i)) { av_opt_set_int(context->priv_data, "no-scenecut", adapt_i, AV_OPT_SEARCH_CHILDREN); } if (strcmp(codec->name, "h264_nvenc")) { - int64_t adapt_b = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEB); - if (!util::is_tristate_default(adapt_b)) { + if (int64_t adapt_b = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEB); + !util::is_tristate_default(adapt_b)) { av_opt_set_int(context->priv_data, "b_adapt", adapt_b, AV_OPT_SEARCH_CHILDREN); } } } if (have_bitrate) { - context->bit_rate = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_TARGET) * 1000); - // Support for Replay Buffer - obs_data_set_int(settings, "bitrate", obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_TARGET)); - } - if (have_bitrate_max) - context->rc_max_rate = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM) * 1000); - if (have_bitrate || have_bitrate_max) - context->rc_buffer_size = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_BUFFERSIZE) * 1000); + int64_t v = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_TARGET); + if (v >= 0) + context->bit_rate = static_cast(v * 1000); - if (have_quality && obs_data_get_bool(settings, KEY_RATECONTROL_QUALITY)) { - int qmin = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM)); - context->qmin = qmin; - if (qmin >= 0) { - context->qmax = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MAXIMUM)); - } + // Support for Replay Buffer + obs_data_set_int(settings, "bitrate", v); + } + 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(min * 1000); + if (int64_t max = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM); max >= 0) + context->rc_max_rate = static_cast(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(v * 1000); + } + + if (have_quality) { + if (int qmin = static_cast(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM)); qmin >= 0) + context->qmin = qmin; + if (int qmax = static_cast(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 (v > 0) { - av_opt_set_double(context->priv_data, "cq", v, 0); + if (double_t v = obs_data_get_double(settings, KEY_RATECONTROL_QUALITY_TARGET) / 100.0 * 51.0; > 0) { + av_opt_set_double(context->priv_data, "cq", v, AV_OPT_SEARCH_CHILDREN); } } if (have_qp) { av_opt_set_int(context->priv_data, "init_qpI", - static_cast(obs_data_get_int(settings, KEY_RATECONTROL_QP_I)), 0); + static_cast(obs_data_get_int(settings, KEY_RATECONTROL_QP_I)), AV_OPT_SEARCH_CHILDREN); av_opt_set_int(context->priv_data, "init_qpP", - static_cast(obs_data_get_int(settings, KEY_RATECONTROL_QP_P)), 0); + static_cast(obs_data_get_int(settings, KEY_RATECONTROL_QP_P)), AV_OPT_SEARCH_CHILDREN); av_opt_set_int(context->priv_data, "init_qpB", - static_cast(obs_data_get_int(settings, KEY_RATECONTROL_QP_B)), 0); + static_cast(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 (!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)) - 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 { 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)) - 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)) av_opt_set_int(context->priv_data, "aq-strength", - static_cast(obs_data_get_int(settings, KEY_AQ_STRENGTH)), 0); + static_cast(obs_data_get_int(settings, KEY_AQ_STRENGTH)), AV_OPT_SEARCH_CHILDREN); } { // 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 nrp = obs_data_get_int(settings, KEY_OTHER_NONREFERENCEPFRAMES); + int64_t wp = obs_data_get_int(settings, KEY_OTHER_WEIGHTEDPREDICTION); context->max_b_frames = static_cast(obs_data_get_int(settings, KEY_OTHER_BFRAMES)); - if (!util::is_tristate_default(zl)) - av_opt_set_int(context->priv_data, "zerolatency", zl, 0); - if (!util::is_tristate_default(nrp)) - av_opt_set_int(context->priv_data, "nonref_p", nrp, 0); + 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, AV_OPT_SEARCH_CHILDREN); + 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, AV_OPT_SEARCH_CHILDREN); 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); - 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)) { - 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( static_cast(obs_data_get_int(settings, KEY_OTHER_BFRAMEREFERENCEMODE))); 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); } } }