ffmpeg-encoder/nvenc: See description

* Remove Minimum Bitrate as it is not supported by the encoder.
* Add several default states (-1 or Default) to options.
* Possibly fix bitrate lock with CQP and CQ mode.
* Fix log output for bitrate and B-Frames.
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2020-03-07 01:52:04 +01:00
parent 549e7c7437
commit f2913685ed
2 changed files with 48 additions and 54 deletions

View File

@ -78,10 +78,8 @@ 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"
#define KEY_RATECONTROL_QUALITY_TARGET "RateControl.Quality.Target"
#define KEY_RATECONTROL_QUALITY_MINIMUM "RateControl.Quality.Minimum"
#define KEY_RATECONTROL_QUALITY_MAXIMUM "RateControl.Quality.Maximum"
@ -133,7 +131,6 @@ std::map<nvenc::preset, std::string> nvenc::preset_to_opt{
};
std::map<nvenc::ratecontrolmode, std::string> nvenc::ratecontrolmodes{
{nvenc::ratecontrolmode::INVALID, S_STATE_DEFAULT},
{nvenc::ratecontrolmode::CQP, ST_RATECONTROL_MODE_(CQP)},
{nvenc::ratecontrolmode::VBR, ST_RATECONTROL_MODE_(VBR)},
{nvenc::ratecontrolmode::VBR_HQ, ST_RATECONTROL_MODE_(VBR_HQ)},
@ -197,12 +194,11 @@ void nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*)
obs_data_set_default_int(settings, KEY_RATECONTROL_MODE, static_cast<int64_t>(ratecontrolmode::CBR_HQ));
obs_data_set_default_int(settings, KEY_RATECONTROL_TWOPASS, -1);
obs_data_set_default_int(settings, KEY_RATECONTROL_LOOKAHEAD, 0);
obs_data_set_default_int(settings, KEY_RATECONTROL_LOOKAHEAD, -1);
obs_data_set_default_int(settings, KEY_RATECONTROL_ADAPTIVEI, -1);
obs_data_set_default_int(settings, KEY_RATECONTROL_ADAPTIVEB, -1);
obs_data_set_default_int(settings, KEY_RATECONTROL_BITRATE_TARGET, 6000);
obs_data_set_default_int(settings, KEY_RATECONTROL_BITRATE_MINIMUM, 0);
obs_data_set_default_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM, 0);
obs_data_set_default_int(settings, KEY_RATECONTROL_BUFFERSIZE, 12000);
@ -215,11 +211,11 @@ void nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*)
obs_data_set_default_int(settings, KEY_RATECONTROL_QP_B, 21);
obs_data_set_default_int(settings, KEY_AQ_SPATIAL, -1);
obs_data_set_default_int(settings, KEY_AQ_STRENGTH, 8);
obs_data_set_default_int(settings, KEY_AQ_STRENGTH, -1);
obs_data_set_default_int(settings, KEY_AQ_TEMPORAL, -1);
obs_data_set_default_int(settings, KEY_OTHER_BFRAMES, 2);
obs_data_set_default_int(settings, KEY_OTHER_BFRAMEREFERENCEMODE, static_cast<int64_t>(b_ref_mode::DISABLED));
obs_data_set_default_int(settings, KEY_OTHER_BFRAMES, -1);
obs_data_set_default_int(settings, KEY_OTHER_BFRAMEREFERENCEMODE, static_cast<int64_t>(b_ref_mode::INVALID));
obs_data_set_default_int(settings, KEY_OTHER_ZEROLATENCY, -1);
obs_data_set_default_int(settings, KEY_OTHER_WEIGHTEDPREDICTION, -1);
obs_data_set_default_int(settings, KEY_OTHER_NONREFERENCEPFRAMES, -1);
@ -237,7 +233,7 @@ static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_d
bool have_quality = false;
bool have_qp = false;
nvenc::ratecontrolmode rc = static_cast<nvenc::ratecontrolmode>(obs_data_get_int(settings, ST_RATECONTROL_MODE));
nvenc::ratecontrolmode rc = static_cast<nvenc::ratecontrolmode>(obs_data_get_int(settings, KEY_RATECONTROL_MODE));
switch (rc) {
case nvenc::ratecontrolmode::CQP:
have_qp = true;
@ -259,11 +255,10 @@ 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_range);
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_range);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BITRATE_MAXIMUM), have_bitrate_range);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_BUFFERSIZE), have_bitrate || have_bitrate_range);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_QUALITY), have_quality);
obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_QUALITY), have_quality);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_QUALITY_MINIMUM), have_quality);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_QUALITY_MAXIMUM), have_quality);
obs_property_set_visible(obs_properties_get(props, KEY_RATECONTROL_QUALITY_TARGET), have_quality);
@ -278,22 +273,20 @@ static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_d
static bool modified_aq(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept
{
bool spatial_aq = obs_data_get_int(settings, KEY_AQ_SPATIAL) == 1;
bool spatial_aq = util::is_tristate_enabled(obs_data_get_int(settings, KEY_AQ_SPATIAL));
obs_property_set_visible(obs_properties_get(props, KEY_AQ_STRENGTH), spatial_aq);
return true;
}
void nvenc::get_properties_pre(obs_properties_t* props, const AVCodec*)
{
{
auto p = obs_properties_add_list(props, KEY_PRESET, D_TRANSLATE(ST_PRESET), OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_INT);
auto p =
obs_properties_add_list(props, KEY_PRESET, D_TRANSLATE(ST_PRESET), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_PRESET)));
for (auto kv : presets) {
obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast<int64_t>(kv.first));
}
}
}
void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
{
@ -305,7 +298,7 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
}
{
auto p = obs_properties_add_list(grp, ST_RATECONTROL_MODE, D_TRANSLATE(ST_RATECONTROL_MODE),
auto p = obs_properties_add_list(grp, KEY_RATECONTROL_MODE, D_TRANSLATE(ST_RATECONTROL_MODE),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_MODE)));
obs_property_set_modified_callback(p, modified_ratecontrol);
@ -316,7 +309,7 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
{
auto p =
util::obs_properties_add_tristate(grp, ST_RATECONTROL_TWOPASS, D_TRANSLATE(ST_RATECONTROL_TWOPASS));
util::obs_properties_add_tristate(grp, KEY_RATECONTROL_TWOPASS, D_TRANSLATE(ST_RATECONTROL_TWOPASS));
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_RATECONTROL_TWOPASS)));
}
@ -359,18 +352,12 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec)
{
auto p =
obs_properties_add_int(grp, KEY_RATECONTROL_BITRATE_TARGET, D_TRANSLATE(ST_RATECONTROL_BITRATE_TARGET),
0, std::numeric_limits<int32_t>::max(), 1);
obs_property_int_set_suffix(p, " kbit/s");
}
{
auto p = obs_properties_add_int(grp, KEY_RATECONTROL_BITRATE_MINIMUM,
D_TRANSLATE(ST_RATECONTROL_BITRATE_MINIMUM), 0,
std::numeric_limits<int32_t>::max(), 1);
-1, std::numeric_limits<int32_t>::max(), 1);
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,
D_TRANSLATE(ST_RATECONTROL_BITRATE_MAXIMUM), -1,
std::numeric_limits<int32_t>::max(), 1);
obs_property_int_set_suffix(p, " kbit/s");
}
@ -588,12 +575,12 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
break;
}
if (int tp = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_TWOPASS)); tp >= 0) {
if (int tp = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_TWOPASS)); tp > -1) {
av_opt_set_int(context->priv_data, "2pass", tp ? 1 : 0, AV_OPT_SEARCH_CHILDREN);
}
int la = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_LOOKAHEAD));
if (la >= 0)
if (la > -1)
av_opt_set_int(context->priv_data, "rc-lookahead", la, AV_OPT_SEARCH_CHILDREN);
if (la > 0) {
if (int64_t adapt_i = obs_data_get_int(settings, KEY_RATECONTROL_ADAPTIVEI);
@ -611,28 +598,36 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
if (have_bitrate) {
int64_t v = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_TARGET);
if (v >= 0)
if (v > -1)
context->bit_rate = static_cast<int>(v * 1000);
// Support for Replay Buffer
obs_data_set_int(settings, "bitrate", v);
} else {
context->bit_rate = 0;
}
if (have_bitrate_range) {
if (int64_t min = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_MINIMUM); min >= 0)
context->rc_min_rate = static_cast<int>(min * 1000);
if (int64_t max = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM); max >= 0)
if (int64_t max = obs_data_get_int(settings, KEY_RATECONTROL_BITRATE_MAXIMUM); max > -1)
context->rc_max_rate = static_cast<int>(max * 1000);
} else {
//context->rc_min_rate = 0;
context->rc_max_rate = 0;
}
if (have_bitrate || have_bitrate_range) {
if (int64_t v = obs_data_get_int(settings, KEY_RATECONTROL_BUFFERSIZE); v >= 0)
if (int64_t v = obs_data_get_int(settings, KEY_RATECONTROL_BUFFERSIZE); v > -1)
context->rc_buffer_size = static_cast<int>(v * 1000);
} else {
context->rc_buffer_size = 0;
}
if (have_quality) {
if (int qmin = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM)); qmin >= 0)
if (int qmin = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MINIMUM)); qmin > -1)
context->qmin = qmin;
if (int qmax = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MAXIMUM)); qmax >= 0)
if (int qmax = static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QUALITY_MAXIMUM)); qmax > -1)
context->qmax = qmax;
} else {
context->qmin = -1;
context->qmax = -1;
}
{
@ -642,12 +637,12 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
}
if (have_qp) {
av_opt_set_int(context->priv_data, "init_qpI",
static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_I)), AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(context->priv_data, "init_qpP",
static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_P)), AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(context->priv_data, "init_qpB",
static_cast<int>(obs_data_get_int(settings, KEY_RATECONTROL_QP_B)), AV_OPT_SEARCH_CHILDREN);
if (int64_t qp = obs_data_get_int(settings, KEY_RATECONTROL_QP_I); qp > -1)
av_opt_set_int(context->priv_data, "init_qpI", static_cast<int>(qp), AV_OPT_SEARCH_CHILDREN);
if (int64_t qp = obs_data_get_int(settings, KEY_RATECONTROL_QP_P); qp > -1)
av_opt_set_int(context->priv_data, "init_qpP", static_cast<int>(qp), AV_OPT_SEARCH_CHILDREN);
if (int64_t qp = obs_data_get_int(settings, KEY_RATECONTROL_QP_B); qp > -1)
av_opt_set_int(context->priv_data, "init_qpB", static_cast<int>(qp), AV_OPT_SEARCH_CHILDREN);
}
}
@ -667,14 +662,12 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
av_opt_set_int(context->priv_data, "temporal_aq", taq, AV_OPT_SEARCH_CHILDREN);
}
if (util::is_tristate_enabled(saq))
if (int64_t aqs = obs_data_get_int(settings, KEY_AQ_STRENGTH); aqs >= 0)
if (int64_t aqs = obs_data_get_int(settings, KEY_AQ_STRENGTH); aqs > -1)
av_opt_set_int(context->priv_data, "aq-strength", static_cast<int>(aqs), AV_OPT_SEARCH_CHILDREN);
}
{ // Other
int64_t wp = obs_data_get_int(settings, KEY_OTHER_WEIGHTEDPREDICTION);
if (int64_t bf = obs_data_get_int(settings, KEY_OTHER_BFRAMES); bf >= 0)
if (int64_t bf = obs_data_get_int(settings, KEY_OTHER_BFRAMES); bf > -1)
context->max_b_frames = static_cast<int>(bf);
if (int64_t zl = obs_data_get_int(settings, KEY_OTHER_ZEROLATENCY); !util::is_tristate_default(zl))
@ -686,6 +679,7 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
if (int64_t v = obs_data_get_int(settings, KEY_OTHER_DECODEDPICTUREBUFFERSIZE); v > -1)
av_opt_set_int(context->priv_data, "dpb_size", v, AV_OPT_SEARCH_CHILDREN);
int64_t wp = obs_data_get_int(settings, KEY_OTHER_WEIGHTEDPREDICTION);
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, AV_OPT_SEARCH_CHILDREN);
@ -729,10 +723,10 @@ void nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* conte
tools::print_av_option_bool(context, "b_adapt", " Adaptive B-Frames");
LOG_INFO("[%s] Bitrate:", codec->name);
tools::print_av_option_int(context, "bitrate", " Target", "bits/sec");
tools::print_av_option_int(context, "rc_min_rate", " Minimum", "bits/sec");
tools::print_av_option_int(context, "rc_max_rate", " Maximum", "bits/sec");
tools::print_av_option_int(context, "rc_buffer_size", " Buffer", "bits");
tools::print_av_option_int(context, "b", " Target", "bits/sec");
tools::print_av_option_int(context, "minrate", " Minimum", "bits/sec");
tools::print_av_option_int(context, "maxrate", " Maximum", "bits/sec");
tools::print_av_option_int(context, "bufsize", " Buffer", "bits");
LOG_INFO("[%s] Quality:", codec->name);
tools::print_av_option_int(context, "cq", " Target", "");
tools::print_av_option_int(context, "qmin", " Minimum", "");
@ -742,7 +736,7 @@ void nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* conte
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, "max_b_frames", " B-Frames", "Frames");
tools::print_av_option_int(context, "bf", " B-Frames", "Frames");
tools::print_av_option_string(context, "b_ref_mode", " Reference Mode", [](int64_t v) {
b_ref_mode val = static_cast<b_ref_mode>(v);
std::string name = "<Default>";

View File

@ -37,7 +37,7 @@ extern "C" {
- CBR: Constant Bitrate (rc=cbr)
- VBR: Variable Bitrate (rc=vbr)
- CQP: Constant QP (rc=cqp)
- CQ: Constant Quality (rc=vbr b=0 minrate=0 maxrate=0 qmin=0 qmax=51 cq=qp), this is basically CRF in X264.
- CQ: Constant Quality (rc=vbr b=0 maxrate=0 qmin=0 qmax=51 cq=qp), this is basically CRF in X264.
*/
using namespace encoder::ffmpeg;