From 6ee7725c03639971f932e2cf04a49861374b69d0 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 18:53:28 -0700 Subject: [PATCH 01/11] obs-ffmpeg: Use av_reduce on NVENC aspect ratio For example, 1920:1080 becomes 16:9. --- plugins/obs-ffmpeg/jim-nvenc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index 9cfad8902..48edc6e0b 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -3,6 +3,7 @@ #include #include #include +#include #define INITGUID #include #include @@ -408,14 +409,17 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui_params = &h264_config->h264VUIParameters; + int darWidth, darHeight; + av_reduce(&darWidth, &darHeight, voi->width, voi->height, 1024 * 1024); + memset(params, 0, sizeof(*params)); params->version = NV_ENC_INITIALIZE_PARAMS_VER; params->encodeGUID = NV_ENC_CODEC_H264_GUID; params->presetGUID = nv_preset; params->encodeWidth = voi->width; params->encodeHeight = voi->height; - params->darWidth = voi->width; - params->darHeight = voi->height; + params->darWidth = darWidth; + params->darHeight = darHeight; params->frameRateNum = voi->fps_num; params->frameRateDen = voi->fps_den; params->enableEncodeAsync = 1; From b150e4fd39788a1f5d41493ba0f84208b644d637 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 18:58:11 -0700 Subject: [PATCH 02/11] obs-ffmpeg: Align NVENC dts math Multiply by number of bframes like FFmpeg does. --- plugins/obs-ffmpeg/jim-nvenc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index 48edc6e0b..1620664c1 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -50,7 +50,7 @@ struct nvenc_data { bool encode_started; bool first_packet; bool can_change_bitrate; - bool bframes; + int32_t bframes; DARRAY(struct nv_bitstream) bitstreams; DARRAY(struct nv_texture) textures; @@ -461,7 +461,7 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) break; } - enc->bframes = bf > 0; + enc->bframes = bf; /* lookahead */ if (lookahead && nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD)) { @@ -908,8 +908,7 @@ static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts, circlebuf_pop_front(&enc->dts_list, &dts, sizeof(dts)); /* subtract bframe delay from dts */ - if (enc->bframes) - dts -= packet->timebase_num; + dts -= (int64_t)enc->bframes * packet->timebase_num; *received_packet = true; packet->data = enc->packet_data.array; From 0c971276aec6e0f1f98452f0bcdcdc6357f8a6de Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:01:00 -0700 Subject: [PATCH 03/11] obs-ffmpeg: Don't set NVENC max dimensions Don't set maxEncodeWidth/maxEncodeHeight since FFmpeg doesn't, and we don't support resolution changes. --- plugins/obs-ffmpeg/jim-nvenc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index 1620664c1..e5dc732ca 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -425,8 +425,6 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) params->enableEncodeAsync = 1; params->enablePTD = 1; params->encodeConfig = &enc->config; - params->maxEncodeWidth = voi->width; - params->maxEncodeHeight = voi->height; config->gopLength = gop_size; config->frameIntervalP = 1 + bf; h264_config->idrPeriod = gop_size; From f253c6dcb3f55fe8e6e3235b6593d6f4d025c3cc Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:02:50 -0700 Subject: [PATCH 04/11] obs-ffmpeg: Align NVENC aqStrength If Psycho Visual Tuning is on, switch aqStrength to from 0 to 8 to match FFmpeg default. --- plugins/obs-ffmpeg/jim-nvenc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index e5dc732ca..ed48bc593 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -472,6 +472,7 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) /* psycho aq */ if (nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ)) { config->rcParams.enableAQ = psycho_aq; + config->rcParams.aqStrength = 8; config->rcParams.enableTemporalAQ = psycho_aq; } From aa7e579f8773f8ca301fc0102db6733ede5ee5d2 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:04:00 -0700 Subject: [PATCH 05/11] obs-ffmpeg: Align NVENC vbvBufferSize Set vbvBufferSize to match FFmpeg behavior. --- plugins/obs-ffmpeg/jim-nvenc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index ed48bc593..a0fc0ee90 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -509,6 +509,7 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) h264_config->outputPictureTimingSEI = 1; config->rcParams.averageBitRate = bitrate * 1000; config->rcParams.maxBitRate = vbr ? max_bitrate * 1000 : bitrate * 1000; + config->rcParams.vbvBufferSize = bitrate * 1000; /* -------------------------- */ /* profile */ From eca916527d80308bd6f443baddd3991786d1ca32 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:05:36 -0700 Subject: [PATCH 06/11] obs-ffmpeg: PVT for NVENC fallback Plumb Psycho Visual Tuning setting into fallback encoder. --- plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c index cc17b25a1..fb0acaa56 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c @@ -173,6 +173,7 @@ static bool nvenc_update(void *data, obs_data_t *settings) int gpu = (int)obs_data_get_int(settings, "gpu"); bool cbr_override = obs_data_get_bool(settings, "cbr"); int bf = (int)obs_data_get_int(settings, "bf"); + bool psycho_aq = obs_data_get_bool(settings, "psycho_aq"); video_t *video = obs_encoder_video(enc->encoder); const struct video_output_info *voi = video_output_get_info(video); @@ -229,6 +230,9 @@ static bool nvenc_update(void *data, obs_data_t *settings) av_opt_set_int(enc->context->priv_data, "2pass", twopass, 0); av_opt_set_int(enc->context->priv_data, "gpu", gpu, 0); + av_opt_set_int(enc->context->priv_data, "spatial-aq", psycho_aq, 0); + av_opt_set_int(enc->context->priv_data, "temporal-aq", psycho_aq, 0); + enc->context->bit_rate = bitrate * 1000; enc->context->rc_buffer_size = bitrate * 1000; enc->context->width = obs_encoder_get_width(enc->encoder); From 7e8a04bbea1cadcea5ac3ec7f96a4b9390b021dc Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:15:04 -0700 Subject: [PATCH 07/11] obs-ffmpeg: Align NVENC lookahead logic Force-enable lookahead if nvEncGetEncodePresetConfig says to. --- plugins/obs-ffmpeg/jim-nvenc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index a0fc0ee90..9a911a683 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -462,11 +462,11 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) enc->bframes = bf; /* lookahead */ - if (lookahead && nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD)) { + lookahead = nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD) && + (lookahead || config->rcParams.enableLookahead); + if (lookahead) { config->rcParams.lookaheadDepth = 8; config->rcParams.enableLookahead = 1; - } else { - lookahead = false; } /* psycho aq */ From 3ddab3ca3e0566125ffbd9fa10fbe23ea14d0676 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:24:05 -0700 Subject: [PATCH 08/11] obs-ffmpeg: Align NVENC buffer length Compute buffer count according to FFmpeg logic. --- plugins/obs-ffmpeg/jim-nvenc.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index 9a911a683..d449a755f 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -42,9 +42,10 @@ struct nvenc_data { void *session; NV_ENC_INITIALIZE_PARAMS params; NV_ENC_CONFIG config; - size_t buf_count; - size_t output_delay; - size_t buffers_queued; + int rc_lookahead; + int buf_count; + int output_delay; + int buffers_queued; size_t next_bitstream; size_t cur_bitstream; bool encode_started; @@ -464,9 +465,28 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) /* lookahead */ lookahead = nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD) && (lookahead || config->rcParams.enableLookahead); + if (lookahead) + enc->rc_lookahead = 8; + + int buf_count = max(4, config->frameIntervalP * 2 * 2); if (lookahead) { - config->rcParams.lookaheadDepth = 8; + buf_count = max(buf_count, config->frameIntervalP + + enc->rc_lookahead + + EXTRA_BUFFERS); + } + + buf_count = min(64, buf_count); + enc->buf_count = buf_count; + + const int output_delay = buf_count - 1; + enc->output_delay = output_delay; + + if (lookahead) { + int lkd_bound = output_delay - config->frameIntervalP - 4; + config->rcParams.enableLookahead = 1; + config->rcParams.lookaheadDepth = + max(enc->rc_lookahead, lkd_bound); } /* psycho aq */ @@ -529,10 +549,6 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) return false; } - enc->buf_count = config->frameIntervalP + - config->rcParams.lookaheadDepth + EXTRA_BUFFERS; - enc->output_delay = enc->buf_count - 1; - info("settings:\n" "\trate_control: %s\n" "\tbitrate: %d\n" From 68262859214707214455565066289175202edc98 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:09:13 -0700 Subject: [PATCH 09/11] obs-ffmpeg: Align NVENC config values Hard-code various config values as they appear in FFmpeg. --- plugins/obs-ffmpeg/jim-nvenc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index d449a755f..b16958336 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -437,6 +437,11 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) h264_config->outputAUD = 1; } + h264_config->sliceMode = 3; + h264_config->sliceModeData = 1; + + h264_config->useBFramesAsRef = NV_ENC_BFRAME_REF_MODE_DISABLED; + vui_params->videoSignalTypePresentFlag = 1; vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL); vui_params->colourDescriptionPresentFlag = 1; @@ -487,6 +492,8 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) config->rcParams.enableLookahead = 1; config->rcParams.lookaheadDepth = max(enc->rc_lookahead, lkd_bound); + config->rcParams.disableIadapt = 0; + config->rcParams.disableBadapt = 0; } /* psycho aq */ From f35e37a963270443e4c31d809367b2222d9e8ddc Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:29:45 -0700 Subject: [PATCH 10/11] obs-ffmpeg: Use NVENC preset lookahead length If the preset specifies the lookahead length, use it. Force to previous setting of 8 otherwise. --- plugins/obs-ffmpeg/jim-nvenc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index b16958336..c8dbc7c12 100644 --- a/plugins/obs-ffmpeg/jim-nvenc.c +++ b/plugins/obs-ffmpeg/jim-nvenc.c @@ -468,10 +468,14 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings) enc->bframes = bf; /* lookahead */ + const bool use_profile_lookahead = config->rcParams.enableLookahead; lookahead = nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD) && - (lookahead || config->rcParams.enableLookahead); - if (lookahead) - enc->rc_lookahead = 8; + (lookahead || use_profile_lookahead); + if (lookahead) { + enc->rc_lookahead = use_profile_lookahead + ? config->rcParams.lookaheadDepth + : 8; + } int buf_count = max(4, config->frameIntervalP * 2 * 2); if (lookahead) { From 7b983f00e31309f5cefd237773a70e4f5195700f Mon Sep 17 00:00:00 2001 From: jpark37 Date: Tue, 16 Mar 2021 19:31:26 -0700 Subject: [PATCH 11/11] obs-ffmpeg: Static analysis warnings Fix various warnings about variable size. --- plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c index fb0acaa56..5361b8916 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c @@ -221,8 +221,9 @@ static bool nvenc_update(void *data, obs_data_t *settings) } else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */ av_opt_set_int(enc->context->priv_data, "cbr", true, 0); - enc->context->rc_max_rate = bitrate * 1000; - enc->context->rc_min_rate = bitrate * 1000; + const int64_t rate = (int64_t)bitrate * 1000; + enc->context->rc_max_rate = rate; + enc->context->rc_min_rate = rate; cqp = 0; } @@ -233,8 +234,9 @@ static bool nvenc_update(void *data, obs_data_t *settings) av_opt_set_int(enc->context->priv_data, "spatial-aq", psycho_aq, 0); av_opt_set_int(enc->context->priv_data, "temporal-aq", psycho_aq, 0); - enc->context->bit_rate = bitrate * 1000; - enc->context->rc_buffer_size = bitrate * 1000; + const int rate = bitrate * 1000; + enc->context->bit_rate = rate; + enc->context->rc_buffer_size = rate; enc->context->width = obs_encoder_get_width(enc->encoder); enc->context->height = obs_encoder_get_height(enc->encoder); enc->context->time_base = (AVRational){voi->fps_den, voi->fps_num}; @@ -295,13 +297,14 @@ static bool nvenc_reconfigure(void *data, obs_data_t *settings) #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 19, 101) struct nvenc_encoder *enc = data; - int bitrate = (int)obs_data_get_int(settings, "bitrate"); + const int64_t bitrate = obs_data_get_int(settings, "bitrate"); const char *rc = obs_data_get_string(settings, "rate_control"); bool cbr = astrcmpi(rc, "CBR") == 0; bool vbr = astrcmpi(rc, "VBR") == 0; if (cbr || vbr) { - enc->context->bit_rate = bitrate * 1000; - enc->context->rc_max_rate = bitrate * 1000; + const int64_t rate = bitrate * 1000; + enc->context->bit_rate = rate; + enc->context->rc_max_rate = rate; } #endif return true;