diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 4e1965da..9b9454ce 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -166,27 +166,40 @@ Encoder.FFmpeg.AMF.Other.AccessUnitDelimiter="Access Unit Delimiter" # Encoder/FFmpeg/NVENC Encoder.FFmpeg.NVENC.Preset="Preset" -Encoder.FFmpeg.NVENC.Preset.Default="Default" -Encoder.FFmpeg.NVENC.Preset.Slow="Slow" -Encoder.FFmpeg.NVENC.Preset.Medium="Medium" -Encoder.FFmpeg.NVENC.Preset.Fast="Fast" -Encoder.FFmpeg.NVENC.Preset.HighPerformance="High Performance" -Encoder.FFmpeg.NVENC.Preset.HighQuality="High Quality" -Encoder.FFmpeg.NVENC.Preset.BluRayDisc="BluRay Disc" -Encoder.FFmpeg.NVENC.Preset.LowLatency="Low Latency" -Encoder.FFmpeg.NVENC.Preset.LowLatencyHighPerformance="Low Latency High Performance" -Encoder.FFmpeg.NVENC.Preset.LowLatencyHighQuality="Low Latency High Quality" -Encoder.FFmpeg.NVENC.Preset.Lossless="Lossless" -Encoder.FFmpeg.NVENC.Preset.LosslessHighPerformance="Lossless High Performance" +Encoder.FFmpeg.NVENC.Preset.default="Default" +Encoder.FFmpeg.NVENC.Preset.slow="Slow" +Encoder.FFmpeg.NVENC.Preset.medium="Medium" +Encoder.FFmpeg.NVENC.Preset.fast="Fast" +Encoder.FFmpeg.NVENC.Preset.hp="High Performance" +Encoder.FFmpeg.NVENC.Preset.hq="High Quality" +Encoder.FFmpeg.NVENC.Preset.bd="BluRay Disc" +Encoder.FFmpeg.NVENC.Preset.ll="Low Latency" +Encoder.FFmpeg.NVENC.Preset.llhq="Low Latency High Quality" +Encoder.FFmpeg.NVENC.Preset.llhp="Low Latency High Performance" +Encoder.FFmpeg.NVENC.Preset.lossless="Lossless" +Encoder.FFmpeg.NVENC.Preset.losslesshp="Lossless High Performance" +Encoder.FFmpeg.NVENC.Preset.p1="Fastest (P1)" +Encoder.FFmpeg.NVENC.Preset.p2="Faster (P2)" +Encoder.FFmpeg.NVENC.Preset.p3="Fast (P3)" +Encoder.FFmpeg.NVENC.Preset.p4="Medium (P4)" +Encoder.FFmpeg.NVENC.Preset.p5="Slow (P5)" +Encoder.FFmpeg.NVENC.Preset.p6="Slower (P6)" +Encoder.FFmpeg.NVENC.Preset.p7="Slowest (P7)" +Encoder.FFmpeg.NVENC.Tune="Tune" +Encoder.FFmpeg.NVENC.Tune.hq="High Quality" +Encoder.FFmpeg.NVENC.Tune.ll="Low Latency" +Encoder.FFmpeg.NVENC.Tune.ull="Ultra Low Latency" +Encoder.FFmpeg.NVENC.Tune.lossless="Lossless" Encoder.FFmpeg.NVENC.RateControl="Rate Control Options" Encoder.FFmpeg.NVENC.RateControl.Mode="Mode" -Encoder.FFmpeg.NVENC.RateControl.Mode.CQP="Constant Quantization Parameter" -Encoder.FFmpeg.NVENC.RateControl.Mode.VBR="Variable Bitrate" -Encoder.FFmpeg.NVENC.RateControl.Mode.VBR_HQ="High Quality Variable Bitrate" -Encoder.FFmpeg.NVENC.RateControl.Mode.CBR="Constant Bitrate" -Encoder.FFmpeg.NVENC.RateControl.Mode.CBR_HQ="High Quality Constant Bitrate" -Encoder.FFmpeg.NVENC.RateControl.Mode.CBR_LD_HQ="Low Delay High Quality Constant Bitrate" +Encoder.FFmpeg.NVENC.RateControl.Mode.constqp="Constant Quantization Parameter" +Encoder.FFmpeg.NVENC.RateControl.Mode.vbr="Variable Bitrate" +Encoder.FFmpeg.NVENC.RateControl.Mode.cbr="Constant Bitrate" Encoder.FFmpeg.NVENC.RateControl.TwoPass="Two Pass" +Encoder.FFmpeg.NVENC.RateControl.MultiPass="Multi-Pass" +Encoder.FFmpeg.NVENC.RateControl.MultiPass.disabled="Single Pass" +Encoder.FFmpeg.NVENC.RateControl.MultiPass.qres="Two Pass at Quarter Resolution" +Encoder.FFmpeg.NVENC.RateControl.MultiPass.fullres="Two Pass at Full Resolution" Encoder.FFmpeg.NVENC.RateControl.LookAhead="Look Ahead" Encoder.FFmpeg.NVENC.RateControl.AdaptiveI="Adaptive I-Frames" Encoder.FFmpeg.NVENC.RateControl.AdaptiveB="Adaptive B-Frames" @@ -208,12 +221,14 @@ Encoder.FFmpeg.NVENC.AQ.Temporal="Temporal Adaptive Quantization" Encoder.FFmpeg.NVENC.Other="Other Options" Encoder.FFmpeg.NVENC.Other.BFrames="Maximum B-Frames" Encoder.FFmpeg.NVENC.Other.BFrameReferenceMode="B-Frame Reference Mode" -Encoder.FFmpeg.NVENC.Other.BFrameReferenceMode.Middle="Use only middle B-Frames as reference" -Encoder.FFmpeg.NVENC.Other.BFrameReferenceMode.Each="Use all B-Frames as reference" +Encoder.FFmpeg.NVENC.Other.BFrameReferenceMode.disabled="No B-Frames will be used as Reference" +Encoder.FFmpeg.NVENC.Other.BFrameReferenceMode.middle="Only B-Frames/2 will be used as Reference" +Encoder.FFmpeg.NVENC.Other.BFrameReferenceMode.each="Each B-Frame will be used as Reference" Encoder.FFmpeg.NVENC.Other.ZeroLatency="Zero Latency" Encoder.FFmpeg.NVENC.Other.WeightedPrediction="Weighted Prediction" Encoder.FFmpeg.NVENC.Other.NonReferencePFrames="Non-reference P-Frames" Encoder.FFmpeg.NVENC.Other.ReferenceFrames="Reference Frames" +Encoder.FFmpeg.NVENC.Other.LowDelayKeyFrameScale="Low Delay Key-Frame Scale" # Blur Blur.Type.Box="Box" diff --git a/source/encoders/handlers/nvenc_h264_handler.cpp b/source/encoders/handlers/nvenc_h264_handler.cpp index 24d11d58..3eeedecd 100644 --- a/source/encoders/handlers/nvenc_h264_handler.cpp +++ b/source/encoders/handlers/nvenc_h264_handler.cpp @@ -45,20 +45,6 @@ extern "C" { using namespace streamfx::encoder::ffmpeg::handler; using namespace streamfx::encoder::codec::h264; -static std::map profiles{ - {profile::BASELINE, "baseline"}, - {profile::MAIN, "main"}, - {profile::HIGH, "high"}, - {profile::HIGH444_PREDICTIVE, "high444p"}, -}; - -static std::map levels{ - {level::L1_0, "1.0"}, {level::L1_0b, "1.0b"}, {level::L1_1, "1.1"}, {level::L1_2, "1.2"}, - {level::L1_3, "1.3"}, {level::L2_0, "2.0"}, {level::L2_1, "2.1"}, {level::L2_2, "2.2"}, - {level::L3_0, "3.0"}, {level::L3_1, "3.1"}, {level::L3_2, "3.2"}, {level::L4_0, "4.0"}, - {level::L4_1, "4.1"}, {level::L4_2, "4.2"}, {level::L5_0, "5.0"}, {level::L5_1, "5.1"}, -}; - void nvenc_h264_handler::adjust_info(ffmpeg_factory* fac, const AVCodec*, std::string&, std::string& name, std::string&) { name = "NVIDIA NVENC H.264/AVC (via FFmpeg)"; @@ -108,19 +94,13 @@ void nvenc_h264_handler::update(obs_data_t* settings, const AVCodec* codec, AVCo nvenc::update(settings, codec, context); if (!context->internal) { - { - auto found = profiles.find(static_cast(obs_data_get_int(settings, ST_KEY_PROFILE))); - if (found != profiles.end()) { - av_opt_set(context->priv_data, "profile", found->second.c_str(), 0); - } + if (auto value = obs_data_get_int(settings, ST_KEY_PROFILE); value > -1) { + av_opt_set_int(context->priv_data, "profile", value, AV_OPT_SEARCH_CHILDREN); } - { - auto found = levels.find(static_cast(obs_data_get_int(settings, ST_KEY_LEVEL))); - if (found != levels.end()) { - av_opt_set(context->priv_data, "level", found->second.c_str(), 0); - } else { - av_opt_set(context->priv_data, "level", "auto", 0); - } + if (auto value = obs_data_get_int(settings, ST_KEY_LEVEL); value > -1) { + av_opt_set_int(context->priv_data, "level", value, AV_OPT_SEARCH_CHILDREN); + } else { + av_opt_set(context->priv_data, "level", "auto", AV_OPT_SEARCH_CHILDREN); } } } @@ -143,7 +123,13 @@ void nvenc_h264_handler::log_options(obs_data_t* settings, const AVCodec* codec, void nvenc_h264_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec) { - nvenc::get_properties_pre(props, codec); + AVCodecContext* context = avcodec_alloc_context3(codec); + if (!context->priv_data) { + avcodec_free_context(&context); + return; + } + + nvenc::get_properties_pre(props, codec, context); { obs_properties_t* grp = props; @@ -155,23 +141,27 @@ void nvenc_h264_handler::get_encoder_properties(obs_properties_t* props, const A { auto p = obs_properties_add_list(grp, ST_KEY_PROFILE, D_TRANSLATE(S_CODEC_H264_PROFILE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), static_cast(profile::UNKNOWN)); - for (auto const kv : profiles) { - std::string trans = std::string(S_CODEC_H264_PROFILE) + "." + kv.second; - obs_property_list_add_int(p, D_TRANSLATE(trans.c_str()), static_cast(kv.first)); - } + obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1); + streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "profile", p, S_CODEC_H264_PROFILE); } { auto p = obs_properties_add_list(grp, ST_KEY_LEVEL, D_TRANSLATE(S_CODEC_H264_LEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_AUTOMATIC), static_cast(level::UNKNOWN)); - for (auto const kv : levels) { - obs_property_list_add_int(p, kv.second.c_str(), static_cast(kv.first)); - } + obs_property_list_add_int(p, D_TRANSLATE(S_STATE_AUTOMATIC), 0); + streamfx::ffmpeg::tools::avoption_list_add_entries_unnamed(context->priv_data, "level", p, + [](const AVOption* opt) { + if (opt->default_val.i64 == 0) + return true; + return false; + }); } } - nvenc::get_properties_post(props, codec); + nvenc::get_properties_post(props, codec, context); + + if (context) { + avcodec_free_context(&context); + } } void nvenc_h264_handler::get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context) diff --git a/source/encoders/handlers/nvenc_hevc_handler.cpp b/source/encoders/handlers/nvenc_hevc_handler.cpp index 0b1a253c..5c3cb7ba 100644 --- a/source/encoders/handlers/nvenc_hevc_handler.cpp +++ b/source/encoders/handlers/nvenc_hevc_handler.cpp @@ -42,23 +42,6 @@ extern "C" { using namespace streamfx::encoder::ffmpeg::handler; using namespace streamfx::encoder::codec::hevc; -static std::map profiles{ - {profile::MAIN, "main"}, - {profile::MAIN10, "main10"}, - {profile::RANGE_EXTENDED, "rext"}, -}; - -static std::map tiers{ - {tier::MAIN, "main"}, - {tier::HIGH, "high"}, -}; - -static std::map levels{ - {level::L1_0, "1.0"}, {level::L2_0, "2.0"}, {level::L2_1, "2.1"}, {level::L3_0, "3.0"}, {level::L3_1, "3.1"}, - {level::L4_0, "4.0"}, {level::L4_1, "4.1"}, {level::L5_0, "5.0"}, {level::L5_1, "5.1"}, {level::L5_2, "5.2"}, - {level::L6_0, "6.0"}, {level::L6_1, "6.1"}, {level::L6_2, "6.2"}, -}; - void nvenc_hevc_handler::adjust_info(ffmpeg_factory* fac, const AVCodec*, std::string&, std::string& name, std::string&) { name = "NVIDIA NVENC H.265/HEVC (via FFmpeg)"; @@ -109,25 +92,16 @@ void nvenc_hevc_handler::update(obs_data_t* settings, const AVCodec* codec, AVCo nvenc::update(settings, codec, context); if (!context->internal) { - { // HEVC Options - auto found = profiles.find(static_cast(obs_data_get_int(settings, ST_KEY_PROFILE))); - if (found != profiles.end()) { - av_opt_set(context->priv_data, "profile", found->second.c_str(), 0); - } + if (auto v = obs_data_get_int(settings, ST_KEY_PROFILE); v > -1) { + av_opt_set_int(context->priv_data, "profile", v, AV_OPT_SEARCH_CHILDREN); } - { - auto found = tiers.find(static_cast(obs_data_get_int(settings, ST_KEY_TIER))); - if (found != tiers.end()) { - av_opt_set(context->priv_data, "tier", found->second.c_str(), 0); - } + if (auto v = obs_data_get_int(settings, ST_KEY_TIER); v > -1) { + av_opt_set_int(context->priv_data, "tier", v, AV_OPT_SEARCH_CHILDREN); } - { - auto found = levels.find(static_cast(obs_data_get_int(settings, ST_KEY_LEVEL))); - if (found != levels.end()) { - av_opt_set(context->priv_data, "level", found->second.c_str(), 0); - } else { - av_opt_set(context->priv_data, "level", "auto", 0); - } + if (auto v = obs_data_get_int(settings, ST_KEY_LEVEL); v > -1) { + av_opt_set_int(context->priv_data, "level", v, AV_OPT_SEARCH_CHILDREN); + } else { + av_opt_set(context->priv_data, "level", "auto", AV_OPT_SEARCH_CHILDREN); } } } @@ -152,7 +126,13 @@ void nvenc_hevc_handler::log_options(obs_data_t* settings, const AVCodec* codec, void nvenc_hevc_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec) { - nvenc::get_properties_pre(props, codec); + AVCodecContext* context = avcodec_alloc_context3(codec); + if (!context->priv_data) { + avcodec_free_context(&context); + return; + } + + nvenc::get_properties_pre(props, codec, context); { obs_properties_t* grp = props; @@ -164,32 +144,33 @@ void nvenc_hevc_handler::get_encoder_properties(obs_properties_t* props, const A { auto p = obs_properties_add_list(grp, ST_KEY_PROFILE, D_TRANSLATE(S_CODEC_HEVC_PROFILE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), static_cast(profile::UNKNOWN)); - for (auto const kv : profiles) { - std::string trans = std::string(S_CODEC_HEVC_PROFILE) + "." + kv.second; - obs_property_list_add_int(p, D_TRANSLATE(trans.c_str()), static_cast(kv.first)); - } + obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1); + streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "profile", p, S_CODEC_HEVC_PROFILE); } { auto p = obs_properties_add_list(grp, ST_KEY_TIER, D_TRANSLATE(S_CODEC_HEVC_TIER), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), static_cast(tier::UNKNOWN)); - for (auto const kv : tiers) { - std::string trans = std::string(S_CODEC_HEVC_TIER) + "." + kv.second; - obs_property_list_add_int(p, D_TRANSLATE(trans.c_str()), static_cast(kv.first)); - } + obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1); + streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "tier", p, S_CODEC_HEVC_TIER); } { auto p = obs_properties_add_list(grp, ST_KEY_LEVEL, D_TRANSLATE(S_CODEC_HEVC_LEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_AUTOMATIC), static_cast(level::UNKNOWN)); - for (auto const kv : levels) { - obs_property_list_add_int(p, kv.second.c_str(), static_cast(kv.first)); - } + obs_property_list_add_int(p, D_TRANSLATE(S_STATE_AUTOMATIC), 0); + streamfx::ffmpeg::tools::avoption_list_add_entries_unnamed(context->priv_data, "level", p, + [](const AVOption* opt) { + if (opt->default_val.i64 == 0) + return true; + return false; + }); } } - nvenc::get_properties_post(props, codec); + nvenc::get_properties_post(props, codec, context); + + if (context) { + avcodec_free_context(&context); + } } void nvenc_hevc_handler::get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context) diff --git a/source/encoders/handlers/nvenc_shared.cpp b/source/encoders/handlers/nvenc_shared.cpp index 7dcafe60..4426ac8f 100644 --- a/source/encoders/handlers/nvenc_shared.cpp +++ b/source/encoders/handlers/nvenc_shared.cpp @@ -33,12 +33,17 @@ extern "C" { #define ST_I18N_PRESET "Encoder.FFmpeg.NVENC.Preset" #define ST_I18N_PRESET_(x) ST_I18N_PRESET "." D_VSTR(x) #define ST_KEY_PRESET "Preset" +#define ST_I18N_TUNE "Encoder.FFmpeg.NVENC.Tune" +#define ST_I18N_TUNE_(x) ST_I18N_TUNE "." D_VSTR(x) +#define ST_KEY_TUNE "Tune" #define ST_I18N_RATECONTROL "Encoder.FFmpeg.NVENC.RateControl" #define ST_I18N_RATECONTROL_MODE ST_I18N_RATECONTROL ".Mode" #define ST_I18N_RATECONTROL_MODE_(x) ST_I18N_RATECONTROL_MODE "." D_VSTR(x) #define ST_KEY_RATECONTROL_MODE "RateControl.Mode" #define ST_I18N_RATECONTROL_TWOPASS ST_I18N_RATECONTROL ".TwoPass" #define ST_KEY_RATECONTROL_TWOPASS "RateControl.TwoPass" +#define ST_I18N_RATECONTROL_MULTIPASS ST_I18N_RATECONTROL ".MultiPass" +#define ST_KEY_RATECONTROL_MULTIPASS "RateControl.MultiPass" #define ST_I18N_RATECONTROL_LOOKAHEAD ST_I18N_RATECONTROL ".LookAhead" #define ST_KEY_RATECONTROL_LOOKAHEAD "RateControl.LookAhead" #define ST_I18N_RATECONTROL_ADAPTIVEI ST_I18N_RATECONTROL ".AdaptiveI" @@ -86,66 +91,25 @@ extern "C" { #define ST_KEY_OTHER_NONREFERENCEPFRAMES "Other.NonReferencePFrames" #define ST_I18N_OTHER_REFERENCEFRAMES ST_I18N_OTHER ".ReferenceFrames" #define ST_KEY_OTHER_REFERENCEFRAMES "Other.ReferenceFrames" +#define ST_I18N_OTHER_LOWDELAYKEYFRAMESCALE ST_I18N_OTHER ".LowDelayKeyFrameScale" +#define ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE "Other.LowDelayKeyFrameScale" using namespace streamfx::encoder::ffmpeg::handler; -std::map nvenc::presets{ - {nvenc::preset::DEFAULT, ST_I18N_PRESET_(Default)}, - {nvenc::preset::SLOW, ST_I18N_PRESET_(Slow)}, - {nvenc::preset::MEDIUM, ST_I18N_PRESET_(Medium)}, - {nvenc::preset::FAST, ST_I18N_PRESET_(Fast)}, - {nvenc::preset::HIGH_PERFORMANCE, ST_I18N_PRESET_(HighPerformance)}, - {nvenc::preset::HIGH_QUALITY, ST_I18N_PRESET_(HighQuality)}, - {nvenc::preset::BLURAYDISC, ST_I18N_PRESET_(BluRayDisc)}, - {nvenc::preset::LOW_LATENCY, ST_I18N_PRESET_(LowLatency)}, - {nvenc::preset::LOW_LATENCY_HIGH_PERFORMANCE, ST_I18N_PRESET_(LowLatencyHighPerformance)}, - {nvenc::preset::LOW_LATENCY_HIGH_QUALITY, ST_I18N_PRESET_(LowLatencyHighQuality)}, - {nvenc::preset::LOSSLESS, ST_I18N_PRESET_(Lossless)}, - {nvenc::preset::LOSSLESS_HIGH_PERFORMANCE, ST_I18N_PRESET_(LosslessHighPerformance)}, -}; +inline bool is_cqp(std::string_view rc) +{ + return std::string_view("constqp") == rc; +} -std::map nvenc::preset_to_opt{ - {nvenc::preset::DEFAULT, "default"}, - {nvenc::preset::SLOW, "slow"}, - {nvenc::preset::MEDIUM, "medium"}, - {nvenc::preset::FAST, "fast"}, - {nvenc::preset::HIGH_PERFORMANCE, "hp"}, - {nvenc::preset::HIGH_QUALITY, "hq"}, - {nvenc::preset::BLURAYDISC, "bd"}, - {nvenc::preset::LOW_LATENCY, "ll"}, - {nvenc::preset::LOW_LATENCY_HIGH_PERFORMANCE, "llhp"}, - {nvenc::preset::LOW_LATENCY_HIGH_QUALITY, "llhq"}, - {nvenc::preset::LOSSLESS, "lossless"}, - {nvenc::preset::LOSSLESS_HIGH_PERFORMANCE, "losslesshp"}, -}; +inline bool is_cbr(std::string_view rc) +{ + return std::string_view("cbr") == rc; +} -std::map nvenc::ratecontrolmodes{ - {nvenc::ratecontrolmode::CQP, ST_I18N_RATECONTROL_MODE_(CQP)}, - {nvenc::ratecontrolmode::VBR, ST_I18N_RATECONTROL_MODE_(VBR)}, - {nvenc::ratecontrolmode::VBR_HQ, ST_I18N_RATECONTROL_MODE_(VBR_HQ)}, - {nvenc::ratecontrolmode::CBR, ST_I18N_RATECONTROL_MODE_(CBR)}, - {nvenc::ratecontrolmode::CBR_HQ, ST_I18N_RATECONTROL_MODE_(CBR_HQ)}, - {nvenc::ratecontrolmode::CBR_LD_HQ, ST_I18N_RATECONTROL_MODE_(CBR_LD_HQ)}, -}; - -std::map nvenc::ratecontrolmode_to_opt{ - {nvenc::ratecontrolmode::CQP, "constqp"}, {nvenc::ratecontrolmode::VBR, "vbr"}, - {nvenc::ratecontrolmode::VBR_HQ, "vbr_hq"}, {nvenc::ratecontrolmode::CBR, "cbr"}, - {nvenc::ratecontrolmode::CBR_HQ, "cbr_hq"}, {nvenc::ratecontrolmode::CBR_LD_HQ, "cbr_ld_hq"}, -}; - -std::map nvenc::b_ref_modes{ - {nvenc::b_ref_mode::INVALID, S_STATE_DEFAULT}, - {nvenc::b_ref_mode::DISABLED, S_STATE_DISABLED}, - {nvenc::b_ref_mode::EACH, ST_I18N_OTHER_BFRAMEREFERENCEMODE ".Each"}, - {nvenc::b_ref_mode::MIDDLE, ST_I18N_OTHER_BFRAMEREFERENCEMODE ".Middle"}, -}; - -std::map nvenc::b_ref_mode_to_opt{ - {nvenc::b_ref_mode::DISABLED, "disabled"}, - {nvenc::b_ref_mode::EACH, "each"}, - {nvenc::b_ref_mode::MIDDLE, "middle"}, -}; +inline bool is_vbr(std::string_view rc) +{ + return std::string_view("vbr") == rc; +} bool streamfx::encoder::ffmpeg::handler::nvenc::is_available() { @@ -198,9 +162,9 @@ void nvenc::override_update(ffmpeg_instance* instance, obs_data_t*) void nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*) { - obs_data_set_default_int(settings, ST_KEY_PRESET, static_cast(nvenc::preset::DEFAULT)); + obs_data_set_default_int(settings, ST_KEY_PRESET, -1); - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_MODE, static_cast(ratecontrolmode::CBR_HQ)); + obs_data_set_default_int(settings, ST_KEY_RATECONTROL_MODE, -1); obs_data_set_default_int(settings, ST_KEY_RATECONTROL_TWOPASS, -1); obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LOOKAHEAD, -1); obs_data_set_default_int(settings, ST_KEY_RATECONTROL_ADAPTIVEI, -1); @@ -222,11 +186,12 @@ void nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*) obs_data_set_default_int(settings, ST_KEY_AQ_TEMPORAL, -1); obs_data_set_default_int(settings, ST_KEY_OTHER_BFRAMES, -1); - obs_data_set_default_int(settings, ST_KEY_OTHER_BFRAMEREFERENCEMODE, static_cast(b_ref_mode::INVALID)); + obs_data_set_default_int(settings, ST_KEY_OTHER_BFRAMEREFERENCEMODE, -1); obs_data_set_default_int(settings, ST_KEY_OTHER_ZEROLATENCY, -1); obs_data_set_default_int(settings, ST_KEY_OTHER_WEIGHTEDPREDICTION, -1); obs_data_set_default_int(settings, ST_KEY_OTHER_NONREFERENCEPFRAMES, -1); obs_data_set_default_int(settings, ST_KEY_OTHER_REFERENCEFRAMES, -1); + obs_data_set_default_int(settings, ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE, -1); // Replay Buffer obs_data_set_default_int(settings, "bitrate", 0); @@ -234,33 +199,29 @@ void nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*) static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept { + // Decode the name into useful flags. + auto value = obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE); bool have_bitrate = false; bool have_bitrate_range = false; bool have_quality = false; bool have_qp_limits = false; bool have_qp = false; - - nvenc::ratecontrolmode rc = - static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE)); - switch (rc) { - case nvenc::ratecontrolmode::CQP: - have_qp = true; - break; - case nvenc::ratecontrolmode::INVALID: - case nvenc::ratecontrolmode::CBR: - case nvenc::ratecontrolmode::CBR_HQ: - case nvenc::ratecontrolmode::CBR_LD_HQ: - have_bitrate = true; - have_qp_limits = true; - break; - case nvenc::ratecontrolmode::VBR: - case nvenc::ratecontrolmode::VBR_HQ: + if (value == 2) { + have_bitrate = true; + } else if (value == 1) { + have_bitrate = true; + have_bitrate_range = true; + have_quality = true; + have_qp_limits = true; + have_qp = true; + } else if (value == 0) { + have_qp = true; + } else { have_bitrate = true; have_bitrate_range = true; have_quality = true; have_qp_limits = true; have_qp = true; - break; } obs_property_set_visible(obs_properties_get(props, ST_I18N_RATECONTROL_LIMITS), have_bitrate || have_quality); @@ -286,16 +247,22 @@ static bool modified_aq(obs_properties_t* props, obs_property_t*, obs_data_t* se return true; } -void nvenc::get_properties_pre(obs_properties_t* props, const AVCodec*) +void nvenc::get_properties_pre(obs_properties_t* props, const AVCodec*, const AVCodecContext* context) { - auto p = obs_properties_add_list(props, ST_KEY_PRESET, D_TRANSLATE(ST_I18N_PRESET), OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_INT); - for (auto kv : presets) { - obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast(kv.first)); + { + auto p = obs_properties_add_list(props, ST_KEY_PRESET, D_TRANSLATE(ST_I18N_PRESET), OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_INT); + streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "preset", p, ST_I18N_PRESET); + } + + if (streamfx::ffmpeg::tools::avoption_exists(context->priv_data, "tune")) { + auto p = obs_properties_add_list(props, ST_KEY_TUNE, D_TRANSLATE(ST_I18N_TUNE), OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_INT); + streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "tune", p, ST_I18N_TUNE); } } -void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec) +void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec, const AVCodecContext* context) { { // Rate Control obs_properties_t* grp = props; @@ -309,12 +276,23 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec) auto p = obs_properties_add_list(grp, ST_KEY_RATECONTROL_MODE, D_TRANSLATE(ST_I18N_RATECONTROL_MODE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_modified_callback(p, modified_ratecontrol); - for (auto kv : ratecontrolmodes) { - obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast(kv.first)); - } + auto filter = [](const AVOption* opt) { + if (opt->default_val.i64 & (1 << 23)) + return true; + return false; + }; + streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "rc", p, ST_I18N_RATECONTROL_MODE, + filter); } - { + if (streamfx::ffmpeg::tools::avoption_exists(context->priv_data, "multipass")) { + auto p = + obs_properties_add_list(grp, ST_KEY_RATECONTROL_MULTIPASS, D_TRANSLATE(ST_I18N_RATECONTROL_MULTIPASS), + OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1); + streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "multipass", p, + ST_I18N_RATECONTROL_MULTIPASS); + } else { auto p = streamfx::util::obs_properties_add_tristate(grp, ST_KEY_RATECONTROL_TWOPASS, D_TRANSLATE(ST_I18N_RATECONTROL_TWOPASS)); } @@ -347,7 +325,7 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec) { auto p = obs_properties_add_float_slider(grp, ST_KEY_RATECONTROL_LIMITS_QUALITY, - D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_QUALITY), 0, 100, 0.01); + D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_QUALITY), 0, 51, 0.01); } { @@ -442,13 +420,9 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec) auto p = obs_properties_add_list(grp, ST_KEY_OTHER_BFRAMEREFERENCEMODE, D_TRANSLATE(ST_I18N_OTHER_BFRAMEREFERENCEMODE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - for (auto kv : b_ref_modes) { - if (kv.first == nvenc::b_ref_mode::EACH && (std::string_view("h264_nvenc") == codec->name)) { - // H.264 does not support using all B-Frames as reference. - continue; - } - obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast(kv.first)); - } + obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1); + streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "b_ref_mode", p, + ST_I18N_OTHER_BFRAMEREFERENCEMODE); } { @@ -472,15 +446,22 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec) (strcmp(codec->name, "h264_nvenc") == 0) ? 16 : 4, 1); obs_property_int_set_suffix(p, " frames"); } + + if (streamfx::ffmpeg::tools::avoption_exists(context->priv_data, "ldkfs")) { + auto p = obs_properties_add_int_slider(grp, ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE, + D_TRANSLATE(ST_I18N_OTHER_LOWDELAYKEYFRAMESCALE), -1, 255, 1); + } } } void nvenc::get_runtime_properties(obs_properties_t* props, const AVCodec*, AVCodecContext*) { obs_property_set_enabled(obs_properties_get(props, ST_KEY_PRESET), false); + obs_property_set_enabled(obs_properties_get(props, ST_KEY_TUNE), false); obs_property_set_enabled(obs_properties_get(props, ST_I18N_RATECONTROL), false); obs_property_set_enabled(obs_properties_get(props, ST_KEY_RATECONTROL_MODE), false); obs_property_set_enabled(obs_properties_get(props, ST_KEY_RATECONTROL_TWOPASS), false); + obs_property_set_enabled(obs_properties_get(props, ST_KEY_RATECONTROL_MULTIPASS), false); obs_property_set_enabled(obs_properties_get(props, ST_KEY_RATECONTROL_LOOKAHEAD), false); obs_property_set_enabled(obs_properties_get(props, ST_KEY_RATECONTROL_ADAPTIVEI), false); obs_property_set_enabled(obs_properties_get(props, ST_KEY_RATECONTROL_ADAPTIVEB), false); @@ -506,84 +487,91 @@ void nvenc::get_runtime_properties(obs_properties_t* props, const AVCodec*, AVCo obs_property_set_enabled(obs_properties_get(props, ST_KEY_OTHER_WEIGHTEDPREDICTION), false); obs_property_set_enabled(obs_properties_get(props, ST_KEY_OTHER_NONREFERENCEPFRAMES), false); obs_property_set_enabled(obs_properties_get(props, ST_KEY_OTHER_REFERENCEFRAMES), false); + obs_property_set_enabled(obs_properties_get(props, ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE), false); } void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) { if (!context->internal) { - preset c_preset = static_cast(obs_data_get_int(settings, ST_KEY_PRESET)); - auto found = preset_to_opt.find(c_preset); - if (found != preset_to_opt.end()) { - av_opt_set(context->priv_data, "preset", found->second.c_str(), 0); - } else { - av_opt_set(context->priv_data, "preset", nullptr, 0); + auto value = obs_data_get_int(settings, ST_KEY_PRESET); + if (value != -1) { + auto name = streamfx::ffmpeg::tools::avoption_name_from_unit_value(context->priv_data, "preset", value); + if (name) { + av_opt_set(context->priv_data, "preset", name, AV_OPT_SEARCH_CHILDREN); + } else { + av_opt_set_int(context->priv_data, "preset", value, AV_OPT_SEARCH_CHILDREN); + } } } { // Rate Control + auto value = obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE); + auto name = streamfx::ffmpeg::tools::avoption_name_from_unit_value(context->priv_data, "rc", value); + if (value != -1) { + if (name && !context->internal) { + av_opt_set(context->priv_data, "rc", name, AV_OPT_SEARCH_CHILDREN); + } else { + av_opt_set_int(context->priv_data, "rc", value, AV_OPT_SEARCH_CHILDREN); + } + } + + // Decode the name into useful flags. bool have_bitrate = false; bool have_bitrate_range = false; bool have_quality = false; bool have_qp_limits = false; bool have_qp = false; + if (is_cbr(name)) { + have_bitrate = true; - ratecontrolmode rc = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE)); - auto rcopt = ratecontrolmode_to_opt.find(rc); - if (rcopt != ratecontrolmode_to_opt.end()) { - if (!context->internal) { - av_opt_set(context->priv_data, "rc", rcopt->second.c_str(), AV_OPT_SEARCH_CHILDREN); - } + if (!context->internal) + av_opt_set_int(context->priv_data, "cbr", 1, AV_OPT_SEARCH_CHILDREN); + + // Support for OBS Studio + obs_data_set_string(settings, "rate_control", "CBR"); + } else if (is_vbr(name)) { + have_bitrate = true; + have_bitrate_range = true; + have_quality = true; + have_qp_limits = true; + have_qp = true; + + if (!context->internal) + av_opt_set_int(context->priv_data, "cbr", 0, AV_OPT_SEARCH_CHILDREN); + + // Support for OBS Studio + obs_data_set_string(settings, "rate_control", "VBR"); + } else if (is_cqp(name)) { + have_qp = true; + + if (!context->internal) + av_opt_set_int(context->priv_data, "cbr", 0, AV_OPT_SEARCH_CHILDREN); + + // Support for OBS Studio + obs_data_set_string(settings, "rate_control", "CQP"); } else { have_bitrate = true; have_bitrate_range = true; have_quality = true; have_qp_limits = true; have_qp = true; + + if (!context->internal) + av_opt_set_int(context->priv_data, "cbr", 0, AV_OPT_SEARCH_CHILDREN); } if (!context->internal) { - av_opt_set_int(context->priv_data, "cbr", 0, AV_OPT_SEARCH_CHILDREN); - } - switch (rc) { - case ratecontrolmode::CQP: - have_qp = true; - - { // Support for OBS Studio - obs_data_set_string(settings, "rate_control", "CQP"); - } - break; - case ratecontrolmode::INVALID: - case ratecontrolmode::CBR: - case ratecontrolmode::CBR_HQ: - case ratecontrolmode::CBR_LD_HQ: - have_bitrate = true; - have_qp_limits = true; - if (!context->internal) { - av_opt_set_int(context->priv_data, "cbr", 1, AV_OPT_SEARCH_CHILDREN); - } - - { // Support for OBS Studio - obs_data_set_string(settings, "rate_control", "CBR"); - } - break; - case ratecontrolmode::VBR: - case ratecontrolmode::VBR_HQ: - have_bitrate_range = true; - have_bitrate = true; - have_quality = true; - have_qp = true; - have_qp_limits = true; - - { // Support for OBS Studio - obs_data_set_string(settings, "rate_control", "VBR"); - } - break; - } - - if (!context->internal) { - // Two Pass - if (int tp = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_TWOPASS)); tp > -1) { - av_opt_set_int(context->priv_data, "2pass", tp ? 1 : 0, AV_OPT_SEARCH_CHILDREN); + if (streamfx::ffmpeg::tools::avoption_exists(context->priv_data, "multipass")) { + // Multi-Pass + if (int tp = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_MULTIPASS)); tp > -1) { + av_opt_set_int(context->priv_data, "multipass", tp, AV_OPT_SEARCH_CHILDREN); + av_opt_set_int(context->priv_data, "2pass", 0, AV_OPT_SEARCH_CHILDREN); + } + } else { + // Two-Pass + if (int tp = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_TWOPASS)); tp > -1) { + av_opt_set_int(context->priv_data, "2pass", tp ? 1 : 0, AV_OPT_SEARCH_CHILDREN); + } } // Look Ahead # of Frames @@ -600,8 +588,7 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c } // Adaptive B-Frames - constexpr std::string_view h264_encoder_name = "h264_nvenc"; - if (h264_encoder_name == codec->name) { + if (std::string_view("h264_nvenc") == codec->name) { if (int64_t adapt_b = obs_data_get_int(settings, ST_KEY_RATECONTROL_ADAPTIVEB); !streamfx::util::is_tristate_default(adapt_b) && (la != 0)) { av_opt_set_int(context->priv_data, "b_adapt", adapt_b, AV_OPT_SEARCH_CHILDREN); @@ -661,8 +648,7 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c // Quality Target if (have_quality) { - if (double_t v = obs_data_get_double(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY) / 100.0 * 51.0; - v > 0) { + if (double_t v = obs_data_get_double(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY); v > 0) { av_opt_set_double(context->priv_data, "cq", v, AV_OPT_SEARCH_CHILDREN); } } else { @@ -703,7 +689,7 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c if (!context->internal) { // Other if (int64_t bf = obs_data_get_int(settings, ST_KEY_OTHER_BFRAMES); bf > -1) - context->max_b_frames = static_cast(bf); + av_opt_set_int(context, "bf", bf, AV_OPT_SEARCH_CHILDREN); if (int64_t zl = obs_data_get_int(settings, ST_KEY_OTHER_ZEROLATENCY); !streamfx::util::is_tristate_default(zl)) av_opt_set_int(context->priv_data, "zerolatency", zl, AV_OPT_SEARCH_CHILDREN); @@ -711,7 +697,7 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c !streamfx::util::is_tristate_default(nrp)) av_opt_set_int(context->priv_data, "nonref_p", nrp, AV_OPT_SEARCH_CHILDREN); if (int64_t v = obs_data_get_int(settings, ST_KEY_OTHER_REFERENCEFRAMES); v > -1) - context->refs = v; + av_opt_set_int(context, "refs", v, AV_OPT_SEARCH_CHILDREN); int64_t wp = obs_data_get_int(settings, ST_KEY_OTHER_WEIGHTEDPREDICTION); if ((context->max_b_frames > 0) && streamfx::util::is_tristate_enabled(wp)) { @@ -721,12 +707,12 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c 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, ST_KEY_OTHER_BFRAMEREFERENCEMODE))); - if (found != b_ref_mode_to_opt.end()) { - av_opt_set(context->priv_data, "b_ref_mode", found->second.c_str(), AV_OPT_SEARCH_CHILDREN); - } + if (auto v = obs_data_get_int(settings, ST_KEY_OTHER_BFRAMEREFERENCEMODE); v > -1) { + av_opt_set_int(context->priv_data, "b_ref_mode", v, AV_OPT_SEARCH_CHILDREN); + } + + if (auto v = obs_data_get_int(settings, ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE); v > -1) { + av_opt_set_int(context->priv_data, "ldkfs", v, AV_OPT_SEARCH_CHILDREN); } } } @@ -741,6 +727,8 @@ void nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* conte tools::print_av_option_string2(context, "rc", " Rate Control", [](int64_t v, std::string_view o) { return std::string(o); }); tools::print_av_option_bool(context, "2pass", " Two Pass"); + tools::print_av_option_string2(context, "multipass", " Multi-Pass", + [](int64_t v, std::string_view o) { return std::string(o); }); tools::print_av_option_int(context, "rc-lookahead", " Look-Ahead", "Frames"); tools::print_av_option_bool(context, "no-scenecut", " Adaptive I-Frames", true); if (strcmp(codec->name, "h264_nvenc") == 0) @@ -759,6 +747,8 @@ void nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* conte tools::print_av_option_int(context, "init_qpI", " I-Frame", ""); tools::print_av_option_int(context, "init_qpP", " P-Frame", ""); tools::print_av_option_int(context, "init_qpB", " B-Frame", ""); + tools::print_av_option_int(context, "qp_cb_offset", " CB Offset", ""); + tools::print_av_option_int(context, "qp_cr_offset", " CR Offset", ""); tools::print_av_option_int(context, "bf", " B-Frames", "Frames"); tools::print_av_option_string2(context, "b_ref_mode", " Reference Mode", @@ -783,9 +773,14 @@ void nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* conte tools::print_av_option_bool(context, "strict_gop", " Strict GOP"); tools::print_av_option_bool(context, "aud", " Access Unit Delimiters"); tools::print_av_option_bool(context, "bluray-compat", " Bluray Compatibility"); - if (strcmp(codec->name, "h264_nvenc") == 0) - tools::print_av_option_bool(context, "a53cc", " A53 Closed Captions"); + tools::print_av_option_bool(context, "a53cc", " A53 Closed Captions"); tools::print_av_option_int(context, "dpb_size", " DPB Size", "Frames"); + tools::print_av_option_int(context, "ldkfs", " DPB Size", "Frames"); + tools::print_av_option_bool(context, "extra_sei", " Extra SEI Data"); + tools::print_av_option_bool(context, "udu_sei", " User SEI Data"); + tools::print_av_option_bool(context, "intra-refresh", " Intra-Refresh"); + tools::print_av_option_bool(context, "single-slice-intra-refresh", " Single Slice Intra-Refresh"); + tools::print_av_option_bool(context, "constrained-encoding", " Constrained Encoding"); } void streamfx::encoder::ffmpeg::handler::nvenc::migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec, @@ -814,5 +809,31 @@ void streamfx::encoder::ffmpeg::handler::nvenc::migrate(obs_data_t* settings, ui obs_data_unset_user_value(settings, "Other.DecodedPictureBufferSize"); } + if (version < STREAMFX_MAKE_VERSION(0, 11, 1, 0)) { + if (auto v = obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE); v != -1) { + switch (v) { + case 0: // CQP + break; + case 2: // VBR_HQ + obs_data_set_int(settings, ST_KEY_RATECONTROL_MODE, 1); + obs_data_set_int(settings, ST_KEY_RATECONTROL_TWOPASS, 1); + obs_data_set_int(settings, ST_KEY_RATECONTROL_MULTIPASS, 1); + case 1: // VBR + break; + case 5: // CBR_LD_HQ + obs_data_set_int(settings, ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE, 1); + case 4: // CBR_HQ + obs_data_set_int(settings, ST_KEY_RATECONTROL_MODE, 2); + obs_data_set_int(settings, ST_KEY_RATECONTROL_TWOPASS, 1); + obs_data_set_int(settings, ST_KEY_RATECONTROL_MULTIPASS, 1); + case 3: // CBR + break; + } + } + if (auto v = obs_data_get_double(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY); v > 0) { + obs_data_set_double(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY, (v / 100.) * 51.); + } + } + #undef COPY_UNSET } diff --git a/source/encoders/handlers/nvenc_shared.hpp b/source/encoders/handlers/nvenc_shared.hpp index cea4d385..08288b27 100644 --- a/source/encoders/handlers/nvenc_shared.hpp +++ b/source/encoders/handlers/nvenc_shared.hpp @@ -42,63 +42,15 @@ extern "C" { */ namespace streamfx::encoder::ffmpeg::handler::nvenc { - enum class preset : int64_t { - DEFAULT, - SLOW, - MEDIUM, - FAST, - HIGH_PERFORMANCE, - HIGH_QUALITY, - BLURAYDISC, - LOW_LATENCY, - LOW_LATENCY_HIGH_PERFORMANCE, - LOW_LATENCY_HIGH_QUALITY, - LOSSLESS, - LOSSLESS_HIGH_PERFORMANCE, - // Append things before this. - INVALID = -1, - }; - - enum class ratecontrolmode : int64_t { - CQP, - VBR, - VBR_HQ, - 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; - - extern std::map preset_to_opt; - - extern std::map ratecontrolmodes; - - extern std::map ratecontrolmode_to_opt; - - extern std::map b_ref_modes; - - extern std::map b_ref_mode_to_opt; - bool is_available(); void override_update(ffmpeg_instance* instance, obs_data_t* settings); void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context); - void get_properties_pre(obs_properties_t* props, const AVCodec* codec); + void get_properties_pre(obs_properties_t* props, const AVCodec* codec, const AVCodecContext* context); - void get_properties_post(obs_properties_t* props, const AVCodec* codec); + void get_properties_post(obs_properties_t* props, const AVCodec* codec, const AVCodecContext* context); void get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context);