diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 717f37a..6ca994a 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -117,11 +117,11 @@ NVENC.RateControl.Mode.CBR_LD_HQ="Low Delay High Quality Constant Bitrate" NVENC.RateControl.Mode.CBR_LD_HQ.Description="Constant Bitrate optimized for lowest encoding latency." NVENC.RateControl.LookAhead="Look Ahead" 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." -NVENC.RateControl.AdaptiveI="Enable adaptive I-Frame insertion" +NVENC.RateControl.AdaptiveI="Adaptive I-Frames" NVENC.RateControl.AdaptiveI.Description="Enables adaptive I-Frame insertion.\nOnly has an effect when look ahead is set to a value other than 0." -NVENC.RateControl.AdaptiveB="Enable adaptive B-Frame insertion" +NVENC.RateControl.AdaptiveB="Adaptive B-Frames" NVENC.RateControl.AdaptiveB.Description="Enables adaptive B-Frame insertion.\nOnly has an effect when look ahead is set to a value other than 0." -NVENC.RateControl.TwoPass="Enable Two Pass" +NVENC.RateControl.TwoPass="Two Pass" 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." NVENC.RateControl.Bitrate="Bitrate Limits" NVENC.RateControl.Bitrate.Target="Target Bitrate" @@ -147,11 +147,11 @@ NVENC.RateControl.QP.B.Description="Quantization parameter for B-Frames.\nSmalle NVENC.RateControl.QP.B.Initial="Initial B-Frame QP" NVENC.RateControl.QP.B.Initial.Description="Initial B-Frame quantization parameter.\nSet to -1 to use the automatically detected value instead." NVENC.AQ="Adaptive Quantization" -NVENC.AQ.Spatial="Enable Spatial Adaptive Quantization" +NVENC.AQ.Spatial="Spatial Adaptive Quantization" NVENC.AQ.Spatial.Description="Enable spatial adaptive quantization, also sometimes referred to as Psychovisual Adaptive Quantization." NVENC.AQ.Strength="Spatial AQ Strength" 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." -NVENC.AQ.Temporal="Enable Temporal Adaptive Quantization" +NVENC.AQ.Temporal="Temporal Adaptive Quantization" NVENC.AQ.Temporal.Description="Enable temporal adaptive quantization." NVENC.Other="Other Options" NVENC.Other.BFrames="Maximum B-Frames" @@ -159,9 +159,9 @@ NVENC.Other.BFrames.Description="Maximum number of B-Frames to insert into the e NVENC.Other.BFrameReferenceMode="B-Frame Reference Mode" NVENC.Other.BFrameReferenceMode.Each="Each B-Frame will be used for references" NVENC.Other.BFrameReferenceMode.Middle="Only (# of B-Frames)/2 will be used for references" -NVENC.Other.ZeroLatency="Enable Zero Latency" +NVENC.Other.ZeroLatency="Zero Latency" NVENC.Other.ZeroLatency.Description="Enable zero latency operation, which ensures that there is no reordering delay." -NVENC.Other.WeightedPrediction="Enable Weighted Prediction" +NVENC.Other.WeightedPrediction="Weighted Prediction" NVENC.Other.WeightedPrediction.Description="Enable weighted prediction for encoding.\nCan't be used with B-Frames." -NVENC.Other.NonReferencePFrames="Enable non-reference P-Frames" +NVENC.Other.NonReferencePFrames="Non-reference P-Frames" NVENC.Other.NonReferencePFrames.Description="Enable the automatic insertion of non-reference P-Frames." diff --git a/source/ui/nvenc_h264_handler.cpp b/source/ui/nvenc_h264_handler.cpp index 0917735..e79a701 100644 --- a/source/ui/nvenc_h264_handler.cpp +++ b/source/ui/nvenc_h264_handler.cpp @@ -22,6 +22,7 @@ #include "nvenc_h264_handler.hpp" #include "codecs/h264.hpp" #include "encoder.hpp" +#include "ffmpeg/tools.hpp" #include "nvenc_shared.hpp" #include "plugin.hpp" #include "strings.hpp" @@ -35,30 +36,7 @@ extern "C" { #pragma warning(pop) } -/* Missing Options: - -Seem to be covered by initQP_* instead. -- [obs-ffmpeg-encoder] Option 'cq' with help 'Set target quality level (0 to 51, 0 means automatic) for constant quality mode in VBR rate control' of type 'Float' with default value '0.000000', minimum '0.000000' and maximum '51.000000'. -- [obs-ffmpeg-encoder] Option 'qp' with help 'Constant quantization parameter rate control method' of type 'Int' with default value '-1', minimum '-1.000000' and maximum '51.000000'. - -Not sure what there are useful for. -[obs-ffmpeg-encoder] Option 'aud' with help 'Use access unit delimiters' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'. -[obs-ffmpeg-encoder] Option 'surfaces' with help 'Number of concurrent surfaces' of type 'Int' with default value '0', minimum '0.000000' and maximum '64.000000'. -[obs-ffmpeg-encoder] Option 'delay' with help 'Delay frame output by the given amount of frames' of type 'Int' with default value '2147483647', minimum '0.000000' and maximum '2147483647.000000'. - -Should probably add this. -[obs-ffmpeg-encoder] Option 'gpu' with unit (gpu) with help 'Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on.' of type 'Int' with default value '-1', minimum '-2.000000' and maximum '2147483647.000000'. -[obs-ffmpeg-encoder] [gpu] Constant 'any' and help text 'Pick the first device available' with value '-1'. -[obs-ffmpeg-encoder] [gpu] Constant 'list' and help text 'List the available devices' with value '-2'. - -Useless except for strict_gop maybe? -[obs-ffmpeg-encoder] Option 'forced-idr' with help 'If forcing keyframes, force them as IDR frames.' of type 'Bool' with default value 'false', minimum '-1.000000' and maximum '1.000000'. -[obs-ffmpeg-encoder] Option 'strict_gop' with help 'Set 1 to minimize GOP-to-GOP rate fluctuations' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'. -[obs-ffmpeg-encoder] Option 'bluray-compat' with help 'Bluray compatibility workarounds' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'. -*/ - using namespace obsffmpeg::codecs::h264; -using namespace obsffmpeg::nvenc; std::map profiles{ {profile::BASELINE, "baseline"}, @@ -143,16 +121,21 @@ void obsffmpeg::ui::nvenc_h264_handler::log_options(obs_data_t* settings, const { nvenc::log_options(settings, codec, context); - profile cfg_profile = static_cast(obs_data_get_int(settings, P_H264_PROFILE)); - level cfg_level = static_cast(obs_data_get_int(settings, P_H264_LEVEL)); - - auto found1 = profiles.find(cfg_profile); - if (found1 != profiles.end()) - PLOG_INFO("[%s] H.264 Profile: %s", codec->name, found1->second.c_str()); - - auto found2 = levels.find(cfg_level); - if (found2 != levels.end()) - PLOG_INFO("[%s] H.264 Level: %s", codec->name, found2->second.c_str()); + PLOG_INFO("[%s] H.265/HEVC:", codec->name); + ffmpeg::tools::print_av_option_string(context, "profile", " Profile", [](int64_t v) { + profile val = static_cast(v); + auto index = profiles.find(val); + if (index != profiles.end()) + return index->second; + return std::string(""); + }); + ffmpeg::tools::print_av_option_string(context, "level", " Level", [](int64_t v) { + level val = static_cast(v); + auto index = levels.find(val); + if (index != levels.end()) + return index->second; + return std::string(""); + }); } void obsffmpeg::ui::nvenc_h264_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec) diff --git a/source/ui/nvenc_hevc_handler.cpp b/source/ui/nvenc_hevc_handler.cpp index 99b8a33..6754799 100644 --- a/source/ui/nvenc_hevc_handler.cpp +++ b/source/ui/nvenc_hevc_handler.cpp @@ -22,6 +22,7 @@ #include "nvenc_hevc_handler.hpp" #include "codecs/hevc.hpp" #include "encoder.hpp" +#include "ffmpeg/tools.hpp" #include "nvenc_shared.hpp" #include "plugin.hpp" #include "strings.hpp" @@ -35,28 +36,6 @@ extern "C" { #pragma warning(pop) } -/* Missing Options: - -Seem to be covered by initQP_* instead. -- [obs-ffmpeg-encoder] Option 'cq' with help 'Set target quality level (0 to 51, 0 means automatic) for constant quality mode in VBR rate control' of type 'Float' with default value '0.000000', minimum '0.000000' and maximum '51.000000'. -- [obs-ffmpeg-encoder] Option 'qp' with help 'Constant quantization parameter rate control method' of type 'Int' with default value '-1', minimum '-1.000000' and maximum '51.000000'. - -Not sure what there are useful for. -[obs-ffmpeg-encoder] Option 'aud' with help 'Use access unit delimiters' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'. -[obs-ffmpeg-encoder] Option 'surfaces' with help 'Number of concurrent surfaces' of type 'Int' with default value '0', minimum '0.000000' and maximum '64.000000'. -[obs-ffmpeg-encoder] Option 'delay' with help 'Delay frame output by the given amount of frames' of type 'Int' with default value '2147483647', minimum '0.000000' and maximum '2147483647.000000'. - -Should probably add this. -[obs-ffmpeg-encoder] Option 'gpu' with unit (gpu) with help 'Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on.' of type 'Int' with default value '-1', minimum '-2.000000' and maximum '2147483647.000000'. -[obs-ffmpeg-encoder] [gpu] Constant 'any' and help text 'Pick the first device available' with value '-1'. -[obs-ffmpeg-encoder] [gpu] Constant 'list' and help text 'List the available devices' with value '-2'. - -Useless except for strict_gop maybe? -[obs-ffmpeg-encoder] Option 'forced-idr' with help 'If forcing keyframes, force them as IDR frames.' of type 'Bool' with default value 'false', minimum '-1.000000' and maximum '1.000000'. -[obs-ffmpeg-encoder] Option 'strict_gop' with help 'Set 1 to minimize GOP-to-GOP rate fluctuations' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'. -[obs-ffmpeg-encoder] Option 'bluray-compat' with help 'Bluray compatibility workarounds' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'. -*/ - using namespace obsffmpeg::codecs::hevc; std::map profiles{ @@ -150,21 +129,28 @@ void obsffmpeg::ui::nvenc_hevc_handler::log_options(obs_data_t* settings, const { nvenc::log_options(settings, codec, context); - profile cfg_profile = static_cast(obs_data_get_int(settings, P_HEVC_PROFILE)); - tier cfg_tier = static_cast(obs_data_get_int(settings, P_HEVC_TIER)); - level cfg_level = static_cast(obs_data_get_int(settings, P_HEVC_LEVEL)); - - auto found1 = profiles.find(cfg_profile); - if (found1 != profiles.end()) - PLOG_INFO("[%s] H.265 Profile: %s", codec->name, found1->second.c_str()); - - auto found2 = levels.find(cfg_level); - if (found2 != levels.end()) - PLOG_INFO("[%s] H.265 Level: %s", codec->name, found2->second.c_str()); - - auto found3 = tiers.find(cfg_tier); - if (found3 != tiers.end()) - PLOG_INFO("[%s] H.265 Tier: %s", codec->name, found3->second.c_str()); + PLOG_INFO("[%s] H.265/HEVC:", codec->name); + ffmpeg::tools::print_av_option_string(context, "profile", " Profile", [](int64_t v) { + profile val = static_cast(v); + auto index = profiles.find(val); + if (index != profiles.end()) + return index->second; + return std::string(""); + }); + ffmpeg::tools::print_av_option_string(context, "level", " Level", [](int64_t v) { + level val = static_cast(v); + auto index = levels.find(val); + if (index != levels.end()) + return index->second; + return std::string(""); + }); + ffmpeg::tools::print_av_option_string(context, "tier", " Tier", [](int64_t v) { + tier val = static_cast(v); + auto index = tiers.find(val); + if (index != tiers.end()) + return index->second; + return std::string(""); + }); } void obsffmpeg::ui::nvenc_hevc_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec) diff --git a/source/ui/nvenc_shared.cpp b/source/ui/nvenc_shared.cpp index 8e2e1f8..84d7e43 100644 --- a/source/ui/nvenc_shared.cpp +++ b/source/ui/nvenc_shared.cpp @@ -23,6 +23,7 @@ #include #include "codecs/hevc.hpp" #include "encoder.hpp" +#include "ffmpeg/tools.hpp" #include "plugin.hpp" #include "strings.hpp" #include "utility.hpp" @@ -138,7 +139,7 @@ void obsffmpeg::nvenc::override_update(obsffmpeg::encoder* instance, obs_data_t* AVCodecContext* context = const_cast(instance->get_avcodeccontext()); int64_t rclookahead = 0; - int64_t surfaces = 0; + int64_t surfaces = 0; int64_t async_depth = 0; av_opt_get_int(context, "rc-lookahead", AV_OPT_SEARCH_CHILDREN, &rclookahead); @@ -170,8 +171,8 @@ void obsffmpeg::nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCode obs_data_set_default_int(settings, ST_RATECONTROL_MODE, static_cast(ratecontrolmode::CBR_HQ)); obs_data_set_default_int(settings, ST_RATECONTROL_TWOPASS, -1); obs_data_set_default_int(settings, ST_RATECONTROL_LOOKAHEAD, 0); - obs_data_set_default_bool(settings, ST_RATECONTROL_ADAPTIVEI, true); - obs_data_set_default_bool(settings, ST_RATECONTROL_ADAPTIVEB, true); + obs_data_set_default_int(settings, ST_RATECONTROL_ADAPTIVEI, -1); + obs_data_set_default_int(settings, ST_RATECONTROL_ADAPTIVEB, -1); obs_data_set_default_int(settings, ST_RATECONTROL_BITRATE_TARGET, 6000); obs_data_set_default_int(settings, ST_RATECONTROL_BITRATE_MAXIMUM, 6000); @@ -188,15 +189,15 @@ void obsffmpeg::nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCode obs_data_set_default_int(settings, ST_RATECONTROL_QP_B, 21); obs_data_set_default_int(settings, ST_RATECONTROL_QP_B_INITIAL, -1); - obs_data_set_default_bool(settings, ST_AQ_SPATIAL, true); + obs_data_set_default_int(settings, ST_AQ_SPATIAL, -1); obs_data_set_default_int(settings, ST_AQ_STRENGTH, 8); - obs_data_set_default_bool(settings, ST_AQ_TEMPORAL, true); + obs_data_set_default_int(settings, ST_AQ_TEMPORAL, -1); obs_data_set_default_int(settings, ST_OTHER_BFRAMES, 2); obs_data_set_default_int(settings, ST_OTHER_BFRAME_REFERENCEMODE, static_cast(b_ref_mode::DISABLED)); - obs_data_set_default_bool(settings, ST_OTHER_ZEROLATENCY, false); - obs_data_set_default_bool(settings, ST_OTHER_WEIGHTED_PREDICTION, false); - obs_data_set_default_bool(settings, ST_OTHER_NONREFERENCE_PFRAMES, false); + obs_data_set_default_int(settings, ST_OTHER_ZEROLATENCY, -1); + obs_data_set_default_int(settings, ST_OTHER_WEIGHTED_PREDICTION, -1); + obs_data_set_default_int(settings, ST_OTHER_NONREFERENCE_PFRAMES, -1); } static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_data_t* settings) @@ -259,7 +260,7 @@ static bool modified_quality(obs_properties_t* props, obs_property_t*, obs_data_ static bool modified_aq(obs_properties_t* props, obs_property_t*, obs_data_t* settings) { - bool spatial_aq = obs_data_get_bool(settings, ST_AQ_SPATIAL); + bool spatial_aq = obs_data_get_int(settings, ST_AQ_SPATIAL) == 1; obs_property_set_visible(obs_properties_get(props, ST_AQ_STRENGTH), spatial_aq); return true; } @@ -298,12 +299,9 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode } { - auto p = obs_properties_add_list(grp, ST_RATECONTROL_TWOPASS, TRANSLATE(ST_RATECONTROL_TWOPASS), - OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_RATECONTROL_TWOPASS, + TRANSLATE(ST_RATECONTROL_TWOPASS)); obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_TWOPASS))); - obs_property_list_add_int(p, TRANSLATE(S_STATE_DEFAULT), -1); - obs_property_list_add_int(p, TRANSLATE(S_STATE_DISABLED), 0); - obs_property_list_add_int(p, TRANSLATE(S_STATE_ENABLED), 1); } { @@ -313,13 +311,13 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode obs_property_int_set_suffix(p, " frames"); } { - auto p = - obs_properties_add_bool(grp, ST_RATECONTROL_ADAPTIVEI, TRANSLATE(ST_RATECONTROL_ADAPTIVEI)); + auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_RATECONTROL_ADAPTIVEI, + TRANSLATE(ST_RATECONTROL_ADAPTIVEI)); obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_ADAPTIVEI))); } if (strcmp(codec->name, "h264_nvenc") == 0) { - auto p = - obs_properties_add_bool(grp, ST_RATECONTROL_ADAPTIVEB, TRANSLATE(ST_RATECONTROL_ADAPTIVEB)); + auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_RATECONTROL_ADAPTIVEB, + TRANSLATE(ST_RATECONTROL_ADAPTIVEB)); obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_ADAPTIVEB))); } } @@ -435,7 +433,7 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode } { - auto p = obs_properties_add_bool(grp, ST_AQ_SPATIAL, TRANSLATE(ST_AQ_SPATIAL)); + auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_AQ_SPATIAL, TRANSLATE(ST_AQ_SPATIAL)); obs_property_set_long_description(p, TRANSLATE(DESC(ST_AQ_SPATIAL))); obs_property_set_modified_callback(p, modified_aq); } @@ -445,7 +443,7 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode obs_property_set_long_description(p, TRANSLATE(DESC(ST_AQ_STRENGTH))); } { - auto p = obs_properties_add_bool(grp, ST_AQ_TEMPORAL, TRANSLATE(ST_AQ_TEMPORAL)); + auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_AQ_TEMPORAL, TRANSLATE(ST_AQ_TEMPORAL)); obs_property_set_long_description(p, TRANSLATE(DESC(ST_AQ_TEMPORAL))); } } @@ -476,19 +474,20 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode } { - auto p = obs_properties_add_bool(grp, ST_OTHER_ZEROLATENCY, TRANSLATE(ST_OTHER_ZEROLATENCY)); + auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_OTHER_ZEROLATENCY, + TRANSLATE(ST_OTHER_ZEROLATENCY)); obs_property_set_long_description(p, TRANSLATE(DESC(ST_OTHER_ZEROLATENCY))); } { - auto p = obs_properties_add_bool(grp, ST_OTHER_WEIGHTED_PREDICTION, - TRANSLATE(ST_OTHER_WEIGHTED_PREDICTION)); + auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_OTHER_WEIGHTED_PREDICTION, + TRANSLATE(ST_OTHER_WEIGHTED_PREDICTION)); obs_property_set_long_description(p, TRANSLATE(DESC(ST_OTHER_WEIGHTED_PREDICTION))); } { - auto p = obs_properties_add_bool(grp, ST_OTHER_NONREFERENCE_PFRAMES, - TRANSLATE(ST_OTHER_NONREFERENCE_PFRAMES)); + auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_OTHER_NONREFERENCE_PFRAMES, + TRANSLATE(ST_OTHER_NONREFERENCE_PFRAMES)); obs_property_set_long_description(p, TRANSLATE(DESC(ST_OTHER_NONREFERENCE_PFRAMES))); } } @@ -555,6 +554,7 @@ void obsffmpeg::nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCode av_opt_set(context->priv_data, "rc", rcopt->second.c_str(), 0); } + av_opt_set_int(context->priv_data, "cbr", 0, 0); switch (rc) { case ratecontrolmode::CQP: have_qp = true; @@ -580,14 +580,18 @@ void obsffmpeg::nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCode } int la = static_cast(obs_data_get_int(settings, ST_RATECONTROL_LOOKAHEAD)); - av_opt_set_int(context->priv_data, "lookahead", la, 0); + av_opt_set_int(context->priv_data, "rc-lookahead", la, 0); if (la > 0) { - bool adapt_i = obs_data_get_bool(settings, ST_RATECONTROL_ADAPTIVEI); - av_opt_set_int(context->priv_data, "no-scenecut", !adapt_i ? 1 : 0, 0); + int64_t adapt_i = obs_data_get_int(settings, ST_RATECONTROL_ADAPTIVEI); + if (!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")) { - bool adapt_b = obs_data_get_bool(settings, ST_RATECONTROL_ADAPTIVEB); - av_opt_set_int(context->priv_data, "b_adapt", adapt_b ? 1 : 0, 0); + int64_t adapt_b = obs_data_get_int(settings, ST_RATECONTROL_ADAPTIVEB); + if (!is_tristate_default(adapt_b)) { + av_opt_set_int(context->priv_data, "b_adapt", adapt_b, AV_OPT_SEARCH_CHILDREN); + } } } @@ -636,37 +640,42 @@ void obsffmpeg::nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCode } { // AQ - bool saq = obs_data_get_bool(settings, ST_AQ_SPATIAL); - bool taq = obs_data_get_bool(settings, ST_AQ_TEMPORAL); + int64_t saq = obs_data_get_int(settings, ST_AQ_SPATIAL); + int64_t taq = obs_data_get_int(settings, ST_AQ_TEMPORAL); - if (strcmp(codec->name, "h264_nvenc")) { - av_opt_set_int(context->priv_data, "spatial-aq", saq ? 1 : 0, 0); - av_opt_set_int(context->priv_data, "temporal-aq", taq ? 1 : 0, 0); + if (strcmp(codec->name, "h264_nvenc") == 0) { + if (!is_tristate_default(saq)) + av_opt_set_int(context->priv_data, "spatial-aq", saq, 0); + if (!is_tristate_default(taq)) + av_opt_set_int(context->priv_data, "temporal-aq", taq, 0); } else { - av_opt_set_int(context->priv_data, "spatial_aq", saq ? 1 : 0, 0); - av_opt_set_int(context->priv_data, "temporal_aq", taq ? 1 : 0, 0); + if (!is_tristate_default(saq)) + av_opt_set_int(context->priv_data, "spatial_aq", saq, 0); + if (!is_tristate_default(taq)) + av_opt_set_int(context->priv_data, "temporal_aq", taq, 0); } - if (saq) { + if (is_tristate_enabled(saq)) av_opt_set_int(context->priv_data, "aq-strength", static_cast(obs_data_get_int(settings, ST_AQ_STRENGTH)), 0); - } } { // Other - bool zl = obs_data_get_bool(settings, ST_OTHER_ZEROLATENCY); - bool wp = obs_data_get_bool(settings, ST_OTHER_WEIGHTED_PREDICTION); - bool nrp = obs_data_get_bool(settings, ST_OTHER_NONREFERENCE_PFRAMES); + int64_t zl = obs_data_get_int(settings, ST_OTHER_ZEROLATENCY); + int64_t wp = obs_data_get_int(settings, ST_OTHER_WEIGHTED_PREDICTION); + int64_t nrp = obs_data_get_int(settings, ST_OTHER_NONREFERENCE_PFRAMES); context->max_b_frames = static_cast(obs_data_get_int(settings, ST_OTHER_BFRAMES)); - av_opt_set_int(context->priv_data, "zerolatency", zl ? 1 : 0, 0); - av_opt_set_int(context->priv_data, "nonref_p", nrp ? 1 : 0, 0); + if (!is_tristate_default(zl)) + av_opt_set_int(context->priv_data, "zerolatency", zl, 0); + if (!is_tristate_default(nrp)) + av_opt_set_int(context->priv_data, "nonref_p", nrp, 0); - if ((context->max_b_frames != 0) && wp) { - PLOG_WARNING( - "Automatically disabled weighted prediction due to being incompatible with B-Frames."); - } else { - av_opt_set_int(context->priv_data, "weighted_pred", wp ? 1 : 0, 0); + if ((context->max_b_frames != 0) && is_tristate_enabled(wp)) { + PLOG_WARNING("[%s] Weighted Prediction disabled because of B-Frames being used.", codec->name); + av_opt_set_int(context->priv_data, "weighted_pred", 0, 0); + } else if (!is_tristate_default(wp)) { + av_opt_set_int(context->priv_data, "weighted_pred", wp, 0); } { @@ -679,112 +688,73 @@ void obsffmpeg::nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCode } } -void obsffmpeg::nvenc::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) +void obsffmpeg::nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* context) { - preset cfg_preset = static_cast(obs_data_get_int(settings, ST_PRESET)); + PLOG_INFO("[%s] Nvidia NVENC:", codec->name); + ffmpeg::tools::print_av_option_string(context, "preset", " Preset", [](int64_t v) { + preset val = static_cast(v); + std::string name = ""; + auto index = preset_to_opt.find(val); + if (index != preset_to_opt.end()) + name = index->second; + return name; + }); + ffmpeg::tools::print_av_option_string(context, "rc", " Rate Control", [](int64_t v) { + ratecontrolmode val = static_cast(v); + std::string name = ""; + auto index = ratecontrolmode_to_opt.find(val); + if (index != ratecontrolmode_to_opt.end()) + name = index->second; + return name; + }); + ffmpeg::tools::print_av_option_bool(context, "2pass", " Two Pass"); + ffmpeg::tools::print_av_option_int(context, "rc-lookahead", " Look-Ahead", "Frames"); + ffmpeg::tools::print_av_option_bool(context, "no-scenecut", " Adaptive I-Frames"); + if (strcmp(codec->name, "h264_nvenc") == 0) + ffmpeg::tools::print_av_option_bool(context, "b_adapt", " Adaptive B-Frames"); - auto found1 = preset_to_opt.find(cfg_preset); - if (found1 != preset_to_opt.end()) - PLOG_INFO("[%s] Preset: %s", codec->name, found1->second.c_str()); + PLOG_INFO("[%s] Bitrate:", codec->name); + ffmpeg::tools::print_av_option_int(context, "bitrate", " Target", "bits/sec"); + ffmpeg::tools::print_av_option_int(context, "rc_max_rate", " Maximum", "bits/sec"); + ffmpeg::tools::print_av_option_int(context, "rc_buffer_size", " Buffer", "bits"); + PLOG_INFO("[%s] Quality:", codec->name); + ffmpeg::tools::print_av_option_int(context, "qmin", " Minimum", ""); + ffmpeg::tools::print_av_option_int(context, "cq", " Target", ""); + ffmpeg::tools::print_av_option_int(context, "qmax", " Maximum", ""); + PLOG_INFO("[%s] Quantization Parameters:", codec->name); + ffmpeg::tools::print_av_option_int(context, "init_qpI", " I-Frame", ""); + ffmpeg::tools::print_av_option_int(context, "init_qpP", " P-Frame", ""); + ffmpeg::tools::print_av_option_int(context, "init_qpB", " B-Frame", ""); - ratecontrolmode cfg_rc_mode = static_cast(obs_data_get_int(settings, ST_RATECONTROL_MODE)); - int64_t cfg_rc_2pass = obs_data_get_int(settings, ST_RATECONTROL_TWOPASS); - int64_t cfg_rc_lahead = obs_data_get_int(settings, ST_RATECONTROL_LOOKAHEAD); - bool cfg_rc_adapti = obs_data_get_bool(settings, ST_RATECONTROL_ADAPTIVEI); - bool cfg_rc_adaptb = obs_data_get_bool(settings, ST_RATECONTROL_ADAPTIVEB); + ffmpeg::tools::print_av_option_int(context, "max_b_frames", " B-Frames", "Frames"); + ffmpeg::tools::print_av_option_string(context, "b_ref_mode", " Reference Mode", [](int64_t v) { + b_ref_mode val = static_cast(v); + std::string name = ""; + auto index = b_ref_mode_to_opt.find(val); + if (index != b_ref_mode_to_opt.end()) + name = index->second; + return name; + }); - auto found2 = ratecontrolmode_to_opt.find(cfg_rc_mode); - if (found2 != ratecontrolmode_to_opt.end()) - PLOG_INFO("[%s] Rate Control: %s", codec->name, found2->second.c_str()); - PLOG_INFO("[%s] Two Pass: %s", codec->name, - cfg_rc_2pass == 1 ? "Enabled" : (cfg_rc_2pass == 0 ? "Disabled" : "Default")); - PLOG_INFO("[%s] Lookahead: %" PRId64 " Frames", codec->name, cfg_rc_lahead); - if (cfg_rc_adapti && cfg_rc_lahead > 0) - PLOG_INFO("[%s] Adaptive I-Frames Enabled", codec->name); - if (cfg_rc_adaptb && cfg_rc_lahead > 0) - PLOG_INFO("[%s] Adaptive B-Frames Enabled", codec->name); - - int64_t cfg_rc_bitrate = obs_data_get_int(settings, ST_RATECONTROL_BITRATE_TARGET); - int64_t cfg_rc_max_bitrate = obs_data_get_int(settings, ST_RATECONTROL_BITRATE_MAXIMUM); - int64_t cfg_rc_bufsize = obs_data_get_int(settings, S_RATECONTROL_BUFFERSIZE); - bool cfg_rc_quality = obs_data_get_bool(settings, ST_RATECONTROL_QUALITY); - int64_t cfg_rc_quality_min = obs_data_get_int(settings, ST_RATECONTROL_QUALITY_MINIMUM); - int64_t cfg_rc_quality_max = obs_data_get_int(settings, ST_RATECONTROL_QUALITY_MAXIMUM); - double_t cfg_rc_quality_tgt = obs_data_get_double(settings, ST_RATECONTROL_QUALITY_TARGET) / 100.0 * 51.0; - int64_t cfg_rc_qp_i = obs_data_get_int(settings, ST_RATECONTROL_QP_I); - int64_t cfg_rc_qp_p = obs_data_get_int(settings, ST_RATECONTROL_QP_P); - int64_t cfg_rc_qp_b = obs_data_get_int(settings, ST_RATECONTROL_QP_B); - int64_t cfg_rc_qp_i_init = obs_data_get_int(settings, ST_RATECONTROL_QP_I_INITIAL); - int64_t cfg_rc_qp_p_init = obs_data_get_int(settings, ST_RATECONTROL_QP_P_INITIAL); - int64_t cfg_rc_qp_b_init = obs_data_get_int(settings, ST_RATECONTROL_QP_B_INITIAL); - - { - bool have_bitrate = false; - bool have_bitrate_max = false; - bool have_quality = false; - bool have_qp = false; - bool have_qp_init = false; - - switch (cfg_rc_mode) { - case ratecontrolmode::CQP: - have_qp = true; - break; - case ratecontrolmode::CBR: - case ratecontrolmode::CBR_HQ: - case ratecontrolmode::CBR_LD_HQ: - have_bitrate = true; - av_opt_set_int(context->priv_data, "cbr", 1, 0); - break; - case ratecontrolmode::VBR: - case ratecontrolmode::VBR_HQ: - have_bitrate_max = true; - have_bitrate = true; - have_quality = true; - have_qp_init = true; - break; - } - - PLOG_INFO("[%s] Buffer Size: %" PRId64, codec->name, cfg_rc_bufsize); - if (have_bitrate) - PLOG_INFO("[%s] Bitrate Target: %" PRId64, codec->name, cfg_rc_bitrate); - if (have_bitrate_max) - PLOG_INFO("[%s] Bitrate Maximum: %" PRId64, codec->name, cfg_rc_max_bitrate); - if (have_quality && cfg_rc_quality) { - PLOG_INFO("[%s] Quality Limits:", codec->name); - PLOG_INFO("[%s] Minimum: %" PRId64, codec->name, cfg_rc_quality_min); - PLOG_INFO("[%s] Maximum: %" PRId64, codec->name, cfg_rc_quality_max); - PLOG_INFO("[%s] Target: %f", codec->name, cfg_rc_quality_tgt); - } - if (have_qp) - PLOG_INFO("[%s] QP Values: %" PRId64 "/%" PRId64 "/%" PRId64, codec->name, cfg_rc_qp_i, - cfg_rc_qp_p, cfg_rc_qp_b); - if (have_qp_init) - PLOG_INFO("[%s] Initial QP Values: %" PRId64 "/%" PRId64 "/%" PRId64, codec->name, - cfg_rc_qp_i_init, cfg_rc_qp_p_init, cfg_rc_qp_b_init); + PLOG_INFO("[%s] Adaptive Quantization:", codec->name); + if (strcmp(codec->name, "h264_nvenc") == 0) { + ffmpeg::tools::print_av_option_bool(context, "spatial-aq", " Spatial AQ"); + ffmpeg::tools::print_av_option_int(context, "aq-strength", " Strength", ""); + ffmpeg::tools::print_av_option_bool(context, "temporal-aq", " Temporal AQ"); + } else { + ffmpeg::tools::print_av_option_bool(context, "spatial_aq", " Spatial AQ"); + ffmpeg::tools::print_av_option_int(context, "aq-strength", " Strength", ""); + ffmpeg::tools::print_av_option_bool(context, "temporal_aq", " Temporal AQ"); } - bool cfg_aq_spatial = obs_data_get_bool(settings, ST_AQ_SPATIAL); - int64_t cfg_aq_strength = obs_data_get_int(settings, ST_AQ_STRENGTH); - bool cfg_aq_temporal = obs_data_get_bool(settings, ST_AQ_TEMPORAL); - if (cfg_aq_spatial) - PLOG_INFO("[%s] Spatial AQ Enabled: Strength %" PRId64, codec->name, cfg_aq_strength); - if (cfg_aq_temporal) - PLOG_INFO("[%s] Temporal AQ Enabled", codec->name); - - int64_t cfg_bf = obs_data_get_int(settings, ST_OTHER_BFRAMES); - b_ref_mode cfg_bf_mode = static_cast(obs_data_get_int(settings, ST_OTHER_BFRAME_REFERENCEMODE)); - bool cfg_zerolatency = obs_data_get_bool(settings, ST_OTHER_ZEROLATENCY); - bool cfg_weightp = obs_data_get_bool(settings, ST_OTHER_WEIGHTED_PREDICTION); - bool cfg_nonrefp = obs_data_get_bool(settings, ST_OTHER_NONREFERENCE_PFRAMES); - - PLOG_INFO("[%s] B-Frames: %" PRId64, codec->name, cfg_bf); - auto found3 = b_ref_mode_to_opt.find(cfg_bf_mode); - if (found3 != b_ref_mode_to_opt.end()) - PLOG_INFO("[%s] Reference Mode: %s", codec->name, found3->second.c_str()); - if (cfg_zerolatency) - PLOG_INFO("[%s] Zero Latency Enabled", codec->name); - if (cfg_weightp) - PLOG_INFO("[%s] Weighted Prediction Enabled", codec->name); - if (cfg_nonrefp) - PLOG_INFO("[%s] Non-Ref P-Frames Enabled", codec->name); + PLOG_INFO("[%s] Other:", codec->name); + ffmpeg::tools::print_av_option_bool(context, "zerolatency", " Zero Latency"); + ffmpeg::tools::print_av_option_bool(context, "weighted_pred", " Weighted Prediction"); + ffmpeg::tools::print_av_option_bool(context, "nonref_p", " Non-reference P-Frames"); + ffmpeg::tools::print_av_option_bool(context, "strict_gop", " Strict GOP"); + ffmpeg::tools::print_av_option_bool(context, "aud", " Access Unit Delimiters"); + ffmpeg::tools::print_av_option_bool(context, "bluray-compat", " Bluray Compatibility"); + if (strcmp(codec->name, "h264_nvenc") == 0) + ffmpeg::tools::print_av_option_bool(context, "a53cc", " A53 Closed Captions"); + ffmpeg::tools::print_av_option_int(context, "dpb_size", " DPB Size", ""); } diff --git a/source/ui/nvenc_shared.hpp b/source/ui/nvenc_shared.hpp index b800b5f..00f28d6 100644 --- a/source/ui/nvenc_shared.hpp +++ b/source/ui/nvenc_shared.hpp @@ -48,6 +48,8 @@ namespace obsffmpeg { LOW_LATENCY_HIGH_QUALITY, LOSSLESS, LOSSLESS_HIGH_PERFORMANCE, + // Append things before this. + INVALID = -1, }; enum class ratecontrolmode : int64_t { @@ -57,12 +59,16 @@ namespace obsffmpeg { CBR, CBR_HQ, CBR_LD_HQ, + // Append things before this. + INVALID = -1, }; enum class b_ref_mode : int64_t { DISABLED, EACH, MIDDLE, + // Append things before this. + INVALID = -1, }; extern std::map presets;