diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c index 9cfad8902..c8dbc7c12 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 @@ -41,15 +42,16 @@ 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; bool first_packet; bool can_change_bitrate; - bool bframes; + int32_t bframes; DARRAY(struct nv_bitstream) bitstreams; DARRAY(struct nv_texture) textures; @@ -408,21 +410,22 @@ 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; 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; @@ -434,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; @@ -457,19 +465,45 @@ 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)) { - config->rcParams.lookaheadDepth = 8; + const bool use_profile_lookahead = config->rcParams.enableLookahead; + lookahead = nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD) && + (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) { + 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; - } else { - lookahead = false; + config->rcParams.lookaheadDepth = + max(enc->rc_lookahead, lkd_bound); + config->rcParams.disableIadapt = 0; + config->rcParams.disableBadapt = 0; } /* 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; } @@ -506,6 +540,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 */ @@ -525,10 +560,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" @@ -904,8 +935,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; diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c index cc17b25a1..5361b8916 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); @@ -220,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; } @@ -229,8 +231,12 @@ 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); - enc->context->bit_rate = bitrate * 1000; - enc->context->rc_buffer_size = bitrate * 1000; + 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); + + 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}; @@ -291,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;