1
0
Эх сурвалжийг харах

Merge pull request #4344 from jpark37/nvenc-ffmpeg-alignment

obs-ffmpeg: Align both NVENC implementations
Jim 4 жил өмнө
parent
commit
011adc4e29

+ 49 - 19
plugins/obs-ffmpeg/jim-nvenc.c

@@ -3,6 +3,7 @@
 #include <util/darray.h>
 #include <util/dstr.h>
 #include <obs-avc.h>
+#include <libavutil/rational.h>
 #define INITGUID
 #include <dxgi.h>
 #include <d3d11.h>
@@ -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;

+ 14 - 7
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;