瀏覽代碼

obs-ffmpeg: Refactor NVENC

There's a lot of duplicated code, so refactor it
jp9000 3 年之前
父節點
當前提交
5c9e620315
共有 1 個文件被更改,包括 164 次插入304 次删除
  1. 164 304
      plugins/obs-ffmpeg/jim-nvenc.c

+ 164 - 304
plugins/obs-ffmpeg/jim-nvenc.c

@@ -8,9 +8,7 @@
 #include <dxgi.h>
 #include <d3d11.h>
 #include <d3d11_1.h>
-#ifdef ENABLE_HEVC
 #include <obs-hevc.h>
-#endif
 
 /* TODO: Use new preset scheme */
 #pragma warning(disable : 4996)
@@ -42,11 +40,27 @@ struct handle_tex {
 /* ------------------------------------------------------------------------- */
 /* Main Implementation Structure                                             */
 
+enum codec_type {
+	CODEC_H264,
+	CODEC_HEVC,
+};
+
+static const char *get_codec_name(enum codec_type type)
+{
+	switch (type) {
+	case CODEC_H264:
+		return "H264";
+	case CODEC_HEVC:
+		return "HEVC";
+	}
+
+	return "Unknown";
+}
+
 struct nvenc_data {
 	obs_encoder_t *encoder;
-#ifdef ENABLE_HEVC
-	bool hevc;
-#endif
+	enum codec_type codec;
+	GUID codec_guid;
 
 	void *session;
 	NV_ENC_INITIALIZE_PARAMS params;
@@ -194,8 +208,7 @@ static const char *hevc_nvenc_get_name(void *type_data)
 }
 #endif
 
-static inline int nv_get_cap_internal(struct nvenc_data *enc, NV_ENC_CAPS cap,
-				      GUID encodeGUID)
+static inline int nv_get_cap(struct nvenc_data *enc, NV_ENC_CAPS cap)
 {
 	if (!enc->session)
 		return 0;
@@ -204,22 +217,10 @@ static inline int nv_get_cap_internal(struct nvenc_data *enc, NV_ENC_CAPS cap,
 	int v;
 
 	param.capsToQuery = cap;
-	nv.nvEncGetEncodeCaps(enc->session, encodeGUID, &param, &v);
+	nv.nvEncGetEncodeCaps(enc->session, enc->codec_guid, &param, &v);
 	return v;
 }
 
-static inline int nv_get_cap_h264(struct nvenc_data *enc, NV_ENC_CAPS cap)
-{
-	return nv_get_cap_internal(enc, cap, NV_ENC_CODEC_H264_GUID);
-}
-
-#ifdef ENABLE_HEVC
-static inline int nv_get_cap_hevc(struct nvenc_data *enc, NV_ENC_CAPS cap)
-{
-	return nv_get_cap_internal(enc, cap, NV_ENC_CODEC_HEVC_GUID);
-}
-#endif
-
 static bool nvenc_update(void *data, obs_data_t *settings)
 {
 	struct nvenc_data *enc = data;
@@ -349,8 +350,8 @@ static void initialize_params(NV_ENC_INITIALIZE_PARAMS *params,
 	params->encodeConfig = config;
 }
 
-static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
-			      int bf, bool psycho_aq)
+static bool init_encoder_base(struct nvenc_data *enc, obs_data_t *settings,
+			      int bf, bool psycho_aq, bool *lossless)
 {
 	const char *rc = obs_data_get_string(settings, "rate_control");
 	int bitrate = (int)obs_data_get_int(settings, "bitrate");
@@ -403,11 +404,11 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
 	}
 
 	const bool rc_lossless = astrcmpi(rc, "lossless") == 0;
-	bool lossless = rc_lossless;
+	*lossless = rc_lossless;
 	if (rc_lossless) {
-		lossless = nv_get_cap_h264(enc,
-					   NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE);
-		if (lossless) {
+		*lossless =
+			nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE);
+		if (*lossless) {
 			nv_preset = hp ? NV_ENC_PRESET_LOSSLESS_HP_GUID
 				       : NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
 		} else {
@@ -421,9 +422,8 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
 	NV_ENC_PRESET_CONFIG preset_config = {NV_ENC_PRESET_CONFIG_VER,
 					      {NV_ENC_CONFIG_VER}};
 
-	err = nv.nvEncGetEncodePresetConfig(enc->session,
-					    NV_ENC_CODEC_H264_GUID, nv_preset,
-					    &preset_config);
+	err = nv.nvEncGetEncodePresetConfig(enc->session, enc->codec_guid,
+					    nv_preset, &preset_config);
 	if (nv_failed(enc->encoder, err, __FUNCTION__,
 		      "nvEncGetEncodePresetConfig")) {
 		return false;
@@ -438,57 +438,19 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
 		(keyint_sec) ? keyint_sec * voi->fps_num / voi->fps_den : 250;
 
 	NV_ENC_CONFIG *config = &enc->config;
-	NV_ENC_CONFIG_H264 *h264_config = &config->encodeCodecConfig.h264Config;
-	NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui_params =
-		&h264_config->h264VUIParameters;
 
-	initialize_params(&enc->params, &NV_ENC_CODEC_H264_GUID, &nv_preset,
+	initialize_params(&enc->params, &enc->codec_guid, &nv_preset,
 			  voi->width, voi->height, voi->fps_num, voi->fps_den,
 			  &enc->config);
+
 	config->gopLength = gop_size;
 	config->frameIntervalP = 1 + bf;
-	h264_config->idrPeriod = gop_size;
-
-	bool repeat_headers = obs_data_get_bool(settings, "repeat_headers");
-	if (repeat_headers) {
-		h264_config->repeatSPSPPS = 1;
-		h264_config->disableSPSPPS = 0;
-		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;
-
-	switch (voi->colorspace) {
-	case VIDEO_CS_601:
-		vui_params->colourPrimaries = 6;
-		vui_params->transferCharacteristics = 6;
-		vui_params->colourMatrix = 6;
-		break;
-	case VIDEO_CS_DEFAULT:
-	case VIDEO_CS_709:
-		vui_params->colourPrimaries = 1;
-		vui_params->transferCharacteristics = 1;
-		vui_params->colourMatrix = 1;
-		break;
-	case VIDEO_CS_SRGB:
-		vui_params->colourPrimaries = 1;
-		vui_params->transferCharacteristics = 13;
-		vui_params->colourMatrix = 1;
-		break;
-	}
 
 	enc->bframes = bf;
 
 	/* lookahead */
 	const bool use_profile_lookahead = config->rcParams.enableLookahead;
-	lookahead = nv_get_cap_h264(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD) &&
+	lookahead = nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD) &&
 		    (lookahead || use_profile_lookahead);
 	if (lookahead) {
 		enc->rc_lookahead = use_profile_lookahead
@@ -523,7 +485,7 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
 	}
 
 	/* psycho aq */
-	if (nv_get_cap_h264(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_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;
@@ -535,17 +497,15 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
 	/* rate control               */
 
 	enc->can_change_bitrate =
-		nv_get_cap_h264(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE) &&
+		nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE) &&
 		!lookahead;
 
 	config->rcParams.rateControlMode = twopass ? NV_ENC_PARAMS_RC_VBR_HQ
 						   : NV_ENC_PARAMS_RC_VBR;
 
 	if (astrcmpi(rc, "cqp") == 0 || rc_lossless) {
-		if (lossless) {
-			h264_config->qpPrimeYZeroTransformBypassFlag = 1;
+		if (*lossless)
 			cqp = 0;
-		}
 
 		config->rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
 		config->rcParams.constQP.qpInterP = cqp;
@@ -557,37 +517,20 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
 		max_bitrate = 0;
 
 	} else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */
-		h264_config->outputBufferingPeriodSEI = 1;
 		config->rcParams.rateControlMode =
 			twopass ? NV_ENC_PARAMS_RC_2_PASS_QUALITY
 				: NV_ENC_PARAMS_RC_CBR;
 	}
 
-	h264_config->outputPictureTimingSEI = 1;
 	config->rcParams.averageBitRate = bitrate * 1000;
 	config->rcParams.maxBitRate = vbr ? max_bitrate * 1000 : bitrate * 1000;
 	config->rcParams.vbvBufferSize = bitrate * 1000;
 
-	/* -------------------------- */
-	/* profile                    */
-
-	if (astrcmpi(profile, "main") == 0) {
-		config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
-	} else if (astrcmpi(profile, "baseline") == 0) {
-		config->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
-	} else if (!lossless) {
-		config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
-	}
-
 	/* -------------------------- */
 	/* initialize                 */
 
-	if (NV_FAILED(nv.nvEncInitializeEncoder(enc->session, &enc->params))) {
-		return false;
-	}
-
 	info("settings:\n"
-	     "\tcodec:        H264\n"
+	     "\tcodec:        %s\n"
 	     "\trate_control: %s\n"
 	     "\tbitrate:      %d\n"
 	     "\tcqp:          %d\n"
@@ -600,112 +543,120 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
 	     "\tb-frames:     %d\n"
 	     "\tlookahead:    %s\n"
 	     "\tpsycho_aq:    %s\n",
-	     rc, bitrate, cqp, gop_size, preset, profile, enc->cx, enc->cy,
-	     twopass ? "true" : "false", bf, lookahead ? "true" : "false",
-	     psycho_aq ? "true" : "false");
+	     get_codec_name(enc->codec), rc, bitrate, cqp, gop_size, preset,
+	     profile, enc->cx, enc->cy, twopass ? "true" : "false", bf,
+	     lookahead ? "true" : "false", psycho_aq ? "true" : "false");
 
 	return true;
 }
 
-#ifdef ENABLE_HEVC
-static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings,
+static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings,
 			      int bf, bool psycho_aq)
 {
 	const char *rc = obs_data_get_string(settings, "rate_control");
-	int bitrate = (int)obs_data_get_int(settings, "bitrate");
-	int max_bitrate = (int)obs_data_get_int(settings, "max_bitrate");
-	int cqp = (int)obs_data_get_int(settings, "cqp");
 	int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
-	const char *preset = obs_data_get_string(settings, "preset");
 	const char *profile = obs_data_get_string(settings, "profile");
-	bool lookahead = obs_data_get_bool(settings, "lookahead");
-	bool vbr = astrcmpi(rc, "VBR") == 0;
-	NVENCSTATUS err;
-
-	video_t *video = obs_encoder_video(enc->encoder);
-	const struct video_output_info *voi = video_output_get_info(video);
+	bool lossless;
 
-	enc->cx = voi->width;
-	enc->cy = voi->height;
+	if (!init_encoder_base(enc, settings, bf, psycho_aq, &lossless)) {
+		return false;
+	}
 
-	/* -------------------------- */
-	/* get preset                 */
+	NV_ENC_CONFIG *config = &enc->config;
+	NV_ENC_CONFIG_H264 *h264_config = &config->encodeCodecConfig.h264Config;
+	NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui_params =
+		&h264_config->h264VUIParameters;
 
-	GUID nv_preset = NV_ENC_PRESET_DEFAULT_GUID;
-	bool twopass = false;
-	bool hp = false;
-	bool ll = false;
+	video_t *video = obs_encoder_video(enc->encoder);
+	const struct video_output_info *voi = video_output_get_info(video);
+	uint32_t gop_size =
+		(keyint_sec) ? keyint_sec * voi->fps_num / voi->fps_den : 250;
 
-	if (astrcmpi(preset, "hq") == 0) {
-		nv_preset = NV_ENC_PRESET_HQ_GUID;
+	h264_config->idrPeriod = gop_size;
 
-	} else if (astrcmpi(preset, "mq") == 0) {
-		nv_preset = NV_ENC_PRESET_HQ_GUID;
-		twopass = true;
+	bool repeat_headers = obs_data_get_bool(settings, "repeat_headers");
+	if (repeat_headers) {
+		h264_config->repeatSPSPPS = 1;
+		h264_config->disableSPSPPS = 0;
+		h264_config->outputAUD = 1;
+	}
 
-	} else if (astrcmpi(preset, "hp") == 0) {
-		nv_preset = NV_ENC_PRESET_HP_GUID;
-		hp = true;
+	h264_config->sliceMode = 3;
+	h264_config->sliceModeData = 1;
 
-	} else if (astrcmpi(preset, "ll") == 0) {
-		nv_preset = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
-		ll = true;
+	h264_config->useBFramesAsRef = NV_ENC_BFRAME_REF_MODE_DISABLED;
 
-	} else if (astrcmpi(preset, "llhq") == 0) {
-		nv_preset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
-		ll = true;
+	vui_params->videoSignalTypePresentFlag = 1;
+	vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL);
+	vui_params->colourDescriptionPresentFlag = 1;
 
-	} else if (astrcmpi(preset, "llhp") == 0) {
-		nv_preset = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
-		hp = true;
-		ll = true;
+	switch (voi->colorspace) {
+	case VIDEO_CS_601:
+		vui_params->colourPrimaries = 6;
+		vui_params->transferCharacteristics = 6;
+		vui_params->colourMatrix = 6;
+		break;
+	case VIDEO_CS_DEFAULT:
+	case VIDEO_CS_709:
+		vui_params->colourPrimaries = 1;
+		vui_params->transferCharacteristics = 1;
+		vui_params->colourMatrix = 1;
+		break;
+	case VIDEO_CS_SRGB:
+		vui_params->colourPrimaries = 1;
+		vui_params->transferCharacteristics = 13;
+		vui_params->colourMatrix = 1;
+		break;
 	}
 
-	const bool rc_lossless = astrcmpi(rc, "lossless") == 0;
-	bool lossless = rc_lossless;
-	if (rc_lossless) {
-		lossless = nv_get_cap_hevc(enc,
-					   NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE);
-		if (lossless) {
-			nv_preset = hp ? NV_ENC_PRESET_LOSSLESS_HP_GUID
-				       : NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
-		} else {
-			warn("lossless encode is not supported, ignoring");
-		}
+	if (astrcmpi(rc, "lossless") == 0) {
+		h264_config->qpPrimeYZeroTransformBypassFlag = 1;
+	} else if (astrcmpi(rc, "vbr") != 0) { /* CBR */
+		h264_config->outputBufferingPeriodSEI = 1;
 	}
 
+	h264_config->outputPictureTimingSEI = 1;
+
 	/* -------------------------- */
-	/* get preset default config  */
+	/* profile                    */
 
-	NV_ENC_PRESET_CONFIG preset_config = {NV_ENC_PRESET_CONFIG_VER,
-					      {NV_ENC_CONFIG_VER}};
+	if (astrcmpi(profile, "main") == 0) {
+		config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
+	} else if (astrcmpi(profile, "baseline") == 0) {
+		config->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
+	} else if (!lossless) {
+		config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
+	}
 
-	err = nv.nvEncGetEncodePresetConfig(enc->session,
-					    NV_ENC_CODEC_HEVC_GUID, nv_preset,
-					    &preset_config);
-	if (nv_failed(enc->encoder, err, __FUNCTION__,
-		      "nvEncGetEncodePresetConfig")) {
+	if (NV_FAILED(nv.nvEncInitializeEncoder(enc->session, &enc->params))) {
 		return false;
 	}
 
-	/* -------------------------- */
-	/* main configuration         */
+	return true;
+}
 
-	enc->config = preset_config.presetCfg;
+static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings,
+			      int bf, bool psycho_aq)
+{
+	const char *rc = obs_data_get_string(settings, "rate_control");
+	int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
+	const char *profile = obs_data_get_string(settings, "profile");
+	bool lossless;
 
-	uint32_t gop_size =
-		(keyint_sec) ? keyint_sec * voi->fps_num / voi->fps_den : 250;
+	if (!init_encoder_base(enc, settings, bf, psycho_aq, &lossless)) {
+		return false;
+	}
 
 	NV_ENC_CONFIG *config = &enc->config;
 	NV_ENC_CONFIG_HEVC *hevc_config = &config->encodeCodecConfig.hevcConfig;
 	NV_ENC_CONFIG_HEVC_VUI_PARAMETERS *vui_params =
 		&hevc_config->hevcVUIParameters;
 
-	initialize_params(&enc->params, &NV_ENC_CODEC_HEVC_GUID, &nv_preset,
-			  voi->width, voi->height, voi->fps_num, voi->fps_den,
-			  &enc->config);
-	config->gopLength = gop_size;
-	config->frameIntervalP = 1 + bf;
+	video_t *video = obs_encoder_video(enc->encoder);
+	const struct video_output_info *voi = video_output_get_info(video);
+	uint32_t gop_size =
+		(keyint_sec) ? keyint_sec * voi->fps_num / voi->fps_den : 250;
+
 	hevc_config->idrPeriod = gop_size;
 
 	bool repeat_headers = obs_data_get_bool(settings, "repeat_headers");
@@ -724,8 +675,6 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings,
 	vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL);
 	vui_params->colourDescriptionPresentFlag = 1;
 
-	hevc_config->pixelBitDepthMinus8 = obs_p010_tex_active() ? 2 : 0;
-
 	switch (voi->colorspace) {
 	case VIDEO_CS_601:
 		vui_params->colourPrimaries = 6;
@@ -760,87 +709,13 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings,
 		vui_params->chromaSampleLocationBot = 2;
 	}
 
-	enc->bframes = bf;
-
-	/* lookahead */
-	const bool use_profile_lookahead = config->rcParams.enableLookahead;
-	lookahead = nv_get_cap_hevc(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) {
-		const int lkd_bound = output_delay - config->frameIntervalP - 4;
-		if (lkd_bound >= 0) {
-			config->rcParams.enableLookahead = 1;
-			config->rcParams.lookaheadDepth =
-				max(enc->rc_lookahead, lkd_bound);
-			config->rcParams.disableIadapt = 0;
-			config->rcParams.disableBadapt = 0;
-		} else {
-			lookahead = false;
-		}
-	}
-
-	/* psycho aq */
-	if (nv_get_cap_hevc(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ)) {
-		config->rcParams.enableAQ = psycho_aq;
-		config->rcParams.aqStrength = 8;
-		config->rcParams.enableTemporalAQ = psycho_aq;
-	} else if (psycho_aq) {
-		warn("Ignoring Psycho Visual Tuning request since GPU is not capable");
-	}
-
-	/* -------------------------- */
-	/* rate control               */
-
-	enc->can_change_bitrate =
-		nv_get_cap_hevc(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE) &&
-		!lookahead;
-
-	config->rcParams.rateControlMode = twopass ? NV_ENC_PARAMS_RC_VBR_HQ
-						   : NV_ENC_PARAMS_RC_VBR;
-
-	if (astrcmpi(rc, "cqp") == 0 || rc_lossless) {
-		if (lossless)
-			cqp = 0;
-
-		config->rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
-		config->rcParams.constQP.qpInterP = cqp;
-		config->rcParams.constQP.qpInterB = cqp;
-		config->rcParams.constQP.qpIntra = cqp;
-		enc->can_change_bitrate = false;
-
-		bitrate = 0;
-		max_bitrate = 0;
+	hevc_config->pixelBitDepthMinus8 = obs_p010_tex_active() ? 2 : 0;
 
-	} else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */
+	if (astrcmpi(rc, "cbr") == 0) {
 		hevc_config->outputBufferingPeriodSEI = 1;
-		config->rcParams.rateControlMode =
-			twopass ? NV_ENC_PARAMS_RC_2_PASS_QUALITY
-				: NV_ENC_PARAMS_RC_CBR;
 	}
 
 	hevc_config->outputPictureTimingSEI = 1;
-	config->rcParams.averageBitRate = bitrate * 1000;
-	config->rcParams.maxBitRate = vbr ? max_bitrate * 1000 : bitrate * 1000;
-	config->rcParams.vbvBufferSize = bitrate * 1000;
 
 	/* -------------------------- */
 	/* profile                    */
@@ -854,34 +729,12 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings,
 		config->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID;
 	}
 
-	/* -------------------------- */
-	/* initialize                 */
-
 	if (NV_FAILED(nv.nvEncInitializeEncoder(enc->session, &enc->params))) {
 		return false;
 	}
 
-	info("settings:\n"
-	     "\tcodec:        HEVC\n"
-	     "\trate_control: %s\n"
-	     "\tbitrate:      %d\n"
-	     "\tcqp:          %d\n"
-	     "\tkeyint:       %d\n"
-	     "\tpreset:       %s\n"
-	     "\tprofile:      %s\n"
-	     "\twidth:        %d\n"
-	     "\theight:       %d\n"
-	     "\t2-pass:       %s\n"
-	     "\tb-frames:     %d\n"
-	     "\tlookahead:    %s\n"
-	     "\tpsycho_aq:    %s\n",
-	     rc, bitrate, cqp, gop_size, preset, profile, enc->cx, enc->cy,
-	     twopass ? "true" : "false", bf, lookahead ? "true" : "false",
-	     psycho_aq ? "true" : "false");
-
 	return true;
 }
-#endif
 
 static bool init_bitstreams(struct nvenc_data *enc)
 {
@@ -915,34 +768,27 @@ static bool init_textures(struct nvenc_data *enc)
 
 static void nvenc_destroy(void *data);
 
-static bool init_specific_encoder(struct nvenc_data *enc, bool hevc,
-				  obs_data_t *settings, int bf, bool psycho_aq)
+static bool init_specific_encoder(struct nvenc_data *enc, obs_data_t *settings,
+				  int bf, bool psycho_aq)
 {
-#ifdef ENABLE_HEVC
-	if (hevc)
+	switch (enc->codec) {
+	case CODEC_HEVC:
 		return init_encoder_hevc(enc, settings, bf, psycho_aq);
-#endif
+	case CODEC_H264:
+		return init_encoder_h264(enc, settings, bf, psycho_aq);
+	}
 
-	return init_encoder_h264(enc, settings, bf, psycho_aq);
+	return false;
 }
 
-static bool init_encoder(struct nvenc_data *enc, bool hevc,
-			 obs_data_t *settings)
+static bool init_encoder(struct nvenc_data *enc, enum codec_type codec,
+			 obs_data_t *settings, obs_encoder_t *encoder)
 {
 	const int bf = (int)obs_data_get_int(settings, "bf");
 	const bool psycho_aq = obs_data_get_bool(settings, "psycho_aq");
-#ifdef ENABLE_HEVC
 	const bool support_10bit =
-		hevc ? nv_get_cap_hevc(enc, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE)
-		     : nv_get_cap_h264(enc, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE);
-	const int bf_max =
-		hevc ? nv_get_cap_hevc(enc, NV_ENC_CAPS_NUM_MAX_BFRAMES)
-		     : nv_get_cap_h264(enc, NV_ENC_CAPS_NUM_MAX_BFRAMES);
-#else
-	const bool support_10bit =
-		nv_get_cap_h264(enc, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE);
-	const int bf_max = nv_get_cap_h264(enc, NV_ENC_CAPS_NUM_MAX_BFRAMES);
-#endif
+		nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE);
+	const int bf_max = nv_get_cap(enc, NV_ENC_CAPS_NUM_MAX_BFRAMES);
 
 	if (obs_p010_tex_active() && !support_10bit) {
 		NV_FAIL(obs_module_text("NVENC.10bitUnsupported"));
@@ -969,16 +815,17 @@ static bool init_encoder(struct nvenc_data *enc, bool hevc,
 		return false;
 	}
 
-	if (!init_specific_encoder(enc, hevc, settings, bf, psycho_aq)) {
+	if (!init_specific_encoder(enc, settings, bf, psycho_aq)) {
 		if (!psycho_aq)
 			return false;
 
 		blog(LOG_WARNING, "[jim-nvenc] init_specific_encoder failed, "
 				  "trying again without Psycho Visual Tuning");
+
 		nv.nvEncDestroyEncoder(enc->session);
 		enc->session = NULL;
-		if (!init_session(enc) ||
-		    !init_specific_encoder(enc, hevc, settings, bf, false)) {
+
+		if (!init_specific_encoder(enc, settings, bf, false)) {
 			return false;
 		}
 	}
@@ -986,14 +833,24 @@ static bool init_encoder(struct nvenc_data *enc, bool hevc,
 	return true;
 }
 
-static void *nvenc_create_internal(bool hevc, obs_data_t *settings,
+static void *nvenc_create_internal(enum codec_type codec, obs_data_t *settings,
 				   obs_encoder_t *encoder)
 {
 	NV_ENCODE_API_FUNCTION_LIST init = {NV_ENCODE_API_FUNCTION_LIST_VER};
 	struct nvenc_data *enc = bzalloc(sizeof(*enc));
 	enc->encoder = encoder;
+	enc->codec = codec;
 	enc->first_packet = true;
 
+	switch (enc->codec) {
+	case CODEC_H264:
+		enc->codec_guid = NV_ENC_CODEC_H264_GUID;
+		break;
+	case CODEC_HEVC:
+		enc->codec_guid = NV_ENC_CODEC_HEVC_GUID;
+		break;
+	}
+
 	if (!init_nvenc(encoder)) {
 		goto fail;
 	}
@@ -1006,7 +863,7 @@ static void *nvenc_create_internal(bool hevc, obs_data_t *settings,
 	if (!init_session(enc)) {
 		goto fail;
 	}
-	if (!init_encoder(enc, hevc, settings)) {
+	if (!init_encoder(enc, codec, settings, encoder)) {
 		goto fail;
 	}
 	if (!init_bitstreams(enc)) {
@@ -1017,7 +874,7 @@ static void *nvenc_create_internal(bool hevc, obs_data_t *settings,
 	}
 
 #ifdef ENABLE_HEVC
-	enc->hevc = hevc;
+	enc->codec = codec;
 #endif
 	return enc;
 
@@ -1026,8 +883,8 @@ fail:
 	return NULL;
 }
 
-static void *nvenc_create_h264_hevc(bool hevc, obs_data_t *settings,
-				    obs_encoder_t *encoder)
+static void *nvenc_create_base(enum codec_type codec, obs_data_t *settings,
+			       obs_encoder_t *encoder)
 {
 	/* this encoder requires shared textures, this cannot be used on a
 	 * gpu other than the one OBS is currently running on. */
@@ -1050,30 +907,34 @@ static void *nvenc_create_h264_hevc(bool hevc, obs_data_t *settings,
 		goto reroute;
 	}
 
-	struct nvenc_data *enc = nvenc_create_internal(hevc, settings, encoder);
+	struct nvenc_data *enc =
+		nvenc_create_internal(codec, settings, encoder);
 
 	if (enc) {
 		return enc;
 	}
 
 reroute:
-	const char *fallback_name = "ffmpeg_nvenc";
-#ifdef ENABLE_HEVC
-	if (hevc)
-		fallback_name = "ffmpeg_hevc_nvenc";
-#endif
-	return obs_encoder_create_rerouted(encoder, fallback_name);
+	switch (codec) {
+	case CODEC_H264:
+		return obs_encoder_create_rerouted(encoder, "ffmpeg_nvenc");
+	case CODEC_HEVC:
+		return obs_encoder_create_rerouted(encoder,
+						   "ffmpeg_hevc_nvenc");
+	}
+
+	return NULL;
 }
 
 static void *h264_nvenc_create(obs_data_t *settings, obs_encoder_t *encoder)
 {
-	return nvenc_create_h264_hevc(false, settings, encoder);
+	return nvenc_create_base(CODEC_H264, settings, encoder);
 }
 
 #ifdef ENABLE_HEVC
 static void *hevc_nvenc_create(obs_data_t *settings, obs_encoder_t *encoder)
 {
-	return nvenc_create_h264_hevc(true, settings, encoder);
+	return nvenc_create_base(CODEC_HEVC, settings, encoder);
 }
 #endif
 
@@ -1200,16 +1061,15 @@ static bool get_encoded_packet(struct nvenc_data *enc, bool finalize)
 			size_t size;
 
 			enc->first_packet = false;
-#ifdef ENABLE_HEVC
-			if (enc->hevc) {
+
+			if (enc->codec == CODEC_HEVC) {
 				obs_extract_hevc_headers(
 					lock.bitstreamBufferPtr,
 					lock.bitstreamSizeInBytes, &new_packet,
 					&size, &enc->header, &enc->header_size,
 					&enc->sei, &enc->sei_size);
-			} else
-#endif
-			{
+
+			} else if (enc->codec == CODEC_H264) {
 				obs_extract_avc_headers(
 					lock.bitstreamBufferPtr,
 					lock.bitstreamSizeInBytes, &new_packet,