Skip to content

Commit

Permalink
encoders/ffmpeg/nvenc: Ensure compatibility with more than just FFmpe…
Browse files Browse the repository at this point in the history
…g 4.2

When FFmpeg Encoders was originally written, FFmpeg 4.2 was still new and OBS Studio did not seem to want to update to anything newer for a while. This led to code being fine-tuned for FFmpeg 4.2, which stops working the moment OBS Studio upgrades FFmpeg. This removes the dependency on FFmpeg 4.2 hopefully, and allows using newer FFmpeg versions - or perhaps even older versions.

Additionally the nonsensical behavior of the Target Quality slider was fixed. It is now from 0 to 51, instead of from 0 to 100, and as such matches FFmpeg exactly.
  • Loading branch information
Xaymar committed Feb 17, 2022
1 parent 736829a commit e9ea6c7
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 312 deletions.
55 changes: 35 additions & 20 deletions data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down
64 changes: 27 additions & 37 deletions source/encoders/handlers/nvenc_h264_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,6 @@ extern "C" {
using namespace streamfx::encoder::ffmpeg::handler;
using namespace streamfx::encoder::codec::h264;

static std::map<profile, std::string> profiles{
{profile::BASELINE, "baseline"},
{profile::MAIN, "main"},
{profile::HIGH, "high"},
{profile::HIGH444_PREDICTIVE, "high444p"},
};

static std::map<level, std::string> 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)";
Expand Down Expand Up @@ -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<profile>(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<level>(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);
}
}
}
Expand All @@ -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;
Expand All @@ -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<int64_t>(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<int64_t>(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<int64_t>(level::UNKNOWN));
for (auto const kv : levels) {
obs_property_list_add_int(p, kv.second.c_str(), static_cast<int64_t>(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)
Expand Down
81 changes: 31 additions & 50 deletions source/encoders/handlers/nvenc_hevc_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,6 @@ extern "C" {
using namespace streamfx::encoder::ffmpeg::handler;
using namespace streamfx::encoder::codec::hevc;

static std::map<profile, std::string> profiles{
{profile::MAIN, "main"},
{profile::MAIN10, "main10"},
{profile::RANGE_EXTENDED, "rext"},
};

static std::map<tier, std::string> tiers{
{tier::MAIN, "main"},
{tier::HIGH, "high"},
};

static std::map<level, std::string> 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)";
Expand Down Expand Up @@ -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<profile>(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<tier>(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<level>(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);
}
}
}
Expand All @@ -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;
Expand All @@ -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<int64_t>(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<int64_t>(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<int64_t>(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<int64_t>(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<int64_t>(level::UNKNOWN));
for (auto const kv : levels) {
obs_property_list_add_int(p, kv.second.c_str(), static_cast<int64_t>(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)
Expand Down
Loading

0 comments on commit e9ea6c7

Please # to comment.