Skip to content

Commit 86f98be

Browse files
derrodRytoEX
authored andcommitted
obs-nvenc: Add SDK 13.0 features
1 parent c6650e2 commit 86f98be

7 files changed

Lines changed: 117 additions & 10 deletions

File tree

plugins/obs-nvenc/data/locale/en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ SplitEncode.Auto="Auto"
5050
SplitEncode.Disabled="Disabled"
5151
SplitEncode.Enabled="Two-way split"
5252
SplitEncode.ThreeWay="Three-way split"
53+
SplitEncode.FourWay="Four-way split"
5354

5455
Opts="Custom Encoder Options"
5556
Opts.TT="Space-separated list of options to apply to the rate control and codec settings,\nbased their names in the nvEncodeAPI header.\ne.g. \"lookaheadDepth=16 aqStrength=4\""

plugins/obs-nvenc/nvenc-helpers.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ static void read_codec_caps(config_t *config, enum codec_type codec, const char
281281
caps->temporal_aq = config_get_bool(config, section, "temporal_aq");
282282
caps->ten_bit = config_get_bool(config, section, "10bit");
283283
caps->four_four_four = config_get_bool(config, section, "yuv_444");
284+
caps->four_two_two = config_get_bool(config, section, "yuv_422");
285+
caps->uhq = config_get_bool(config, section, "uhq");
284286
}
285287

286288
static bool nvenc_check(void)

plugins/obs-nvenc/nvenc-helpers.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#define NVENC_12_2_OR_LATER
1919
#endif
2020

21+
#if NVENCAPI_MAJOR_VERSION >= 13
22+
#define NVENC_13_0_OR_LATER
23+
#endif
24+
2125
enum codec_type {
2226
CODEC_H264,
2327
CODEC_HEVC,
@@ -46,18 +50,19 @@ struct encoder_caps {
4650
int max_width;
4751
int max_height;
4852

49-
/* These don't seem to work correctly, thanks NVIDIA. */
50-
int temporal_filter;
51-
int lookahead_level;
53+
int temporal_filter; /* Broken prior to the 551.21 driver. */
54+
int lookahead_level; /* Broken prior to the 570.20 driver. */
5255

5356
bool dyn_bitrate;
5457
bool lookahead;
5558
bool lossless;
5659
bool temporal_aq;
60+
bool uhq;
5761

5862
/* Yeah... */
5963
bool ten_bit;
6064
bool four_four_four;
65+
bool four_two_two;
6166
};
6267

6368
typedef NVENCSTATUS(NVENCAPI *NV_CREATE_INSTANCE_FUNC)(NV_ENCODE_API_FUNCTION_LIST *);

plugins/obs-nvenc/nvenc-internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ struct nvenc_data {
108108
size_t roi_map_size;
109109
uint32_t roi_increment;
110110

111+
#ifdef NVENC_13_0_OR_LATER
112+
CONTENT_LIGHT_LEVEL *cll;
113+
MASTERING_DISPLAY_INFO *mdi;
114+
#endif
115+
111116
struct nvenc_properties props;
112117

113118
CUcontext cu_ctx;

plugins/obs-nvenc/nvenc-opts-parser.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ static bool apply_h264_opt(struct obs_option *opt, NV_ENC_CONFIG_H264 *nv_conf)
129129

130130
APPLY_INT_OPT(idrPeriod, uint32_t, PRIu32)
131131
APPLY_INT_OPT(useBFramesAsRef, NV_ENC_BFRAME_REF_MODE, PRIu32)
132+
#ifdef NVENC_13_0_OR_LATER
133+
APPLY_INT_OPT(tfLevel, NV_ENC_TEMPORAL_FILTER_LEVEL, PRIu32)
134+
#endif
132135

133136
APPLY_BIT_OPT(enableFillerDataInsertion, 1)
134137

@@ -162,6 +165,9 @@ static bool apply_av1_opt(struct obs_option *opt, NV_ENC_CONFIG_AV1 *nv_conf)
162165
APPLY_INT_OPT(numTileRows, uint32_t, PRIu32)
163166
APPLY_INT_OPT(idrPeriod, uint32_t, PRIu32)
164167
APPLY_INT_OPT(useBFramesAsRef, NV_ENC_BFRAME_REF_MODE, PRIu32)
168+
#ifdef NVENC_13_0_OR_LATER
169+
APPLY_INT_OPT(tfLevel, NV_ENC_TEMPORAL_FILTER_LEVEL, PRIu32)
170+
#endif
165171

166172
APPLY_BIT_OPT(enableBitstreamPadding, 1)
167173

plugins/obs-nvenc/nvenc-properties.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,10 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
157157
OBS_COMBO_FORMAT_STRING);
158158

159159
#define add_tune(val) obs_property_list_add_string(p, obs_module_text("Tuning." val), val)
160-
#ifdef NVENC_12_2_OR_LATER
161-
/* The UHQ tune is only supported on Turing or later.
162-
* It uses the temporal filtering feature, so we can use its
163-
* availability as an indicator that we are on a supported GPU. */
164-
if (codec == CODEC_HEVC && caps->temporal_filter)
160+
/* The UHQ tune is only supported on Turing or later. */
161+
if (caps->uhq)
165162
add_tune("uhq");
166-
#endif
163+
167164
add_tune("hq");
168165
add_tune("ll");
169166
add_tune("ull");
@@ -189,6 +186,10 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
189186
} else if (codec == CODEC_AV1) {
190187
add_profile("main");
191188
} else {
189+
#ifdef NVENC_13_0_OR_LATER
190+
if (caps->ten_bit)
191+
add_profile("high10");
192+
#endif
192193
add_profile("high");
193194
add_profile("main");
194195
add_profile("baseline");
@@ -244,6 +245,12 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
244245
obs_property_list_add_int(p, obs_module_text("SplitEncode.ThreeWay"),
245246
NV_ENC_SPLIT_THREE_FORCED_MODE);
246247
}
248+
#ifdef NVENC_13_0_OR_LATER
249+
if (caps->engines > 3) {
250+
obs_property_list_add_int(p, obs_module_text("SplitEncode.FourWay"),
251+
NV_ENC_SPLIT_FOUR_FORCED_MODE);
252+
}
253+
#endif
247254
}
248255
#endif
249256

plugins/obs-nvenc/nvenc.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ static bool is_10_bit(const struct nvenc_data *enc)
214214
: obs_encoder_video_tex_active(enc->encoder, VIDEO_FORMAT_P010);
215215
}
216216

217+
static bool is_hdr(const enum video_colorspace space)
218+
{
219+
return space == VIDEO_CS_2100_HLG || space == VIDEO_CS_2100_PQ;
220+
}
221+
217222
static bool init_encoder_base(struct nvenc_data *enc, obs_data_t *settings)
218223
{
219224
UNUSED_PARAMETER(settings);
@@ -481,6 +486,13 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
481486
if (enc->in_format == VIDEO_FORMAT_I444) {
482487
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID;
483488
h264_config->chromaFormatIDC = 3;
489+
#ifdef NVENC_13_0_OR_LATER
490+
} else if (astrcmpi(enc->props.profile, "high10") == 0) {
491+
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID;
492+
} else if (is_10_bit(enc)) {
493+
warn("Forcing high10 for P010");
494+
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID;
495+
#endif
484496
} else if (astrcmpi(enc->props.profile, "main") == 0) {
485497
config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
486498
} else if (astrcmpi(enc->props.profile, "baseline") == 0) {
@@ -489,6 +501,14 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
489501
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
490502
}
491503

504+
#ifdef NVENC_13_0_OR_LATER
505+
/* Note: Only supported on Blackwell! */
506+
h264_config->inputBitDepth = is_10_bit(enc) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8;
507+
h264_config->outputBitDepth = memcmp(&config->profileGUID, &NV_ENC_H264_PROFILE_HIGH_10_GUID, sizeof(GUID)) == 0
508+
? NV_ENC_BIT_DEPTH_10
509+
: NV_ENC_BIT_DEPTH_8;
510+
#endif
511+
492512
if (!apply_user_args(enc)) {
493513
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
494514
return false;
@@ -587,7 +607,7 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
587607
config->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
588608
profile_is_10bpc = true;
589609
} else if (is_10_bit(enc)) {
590-
blog(LOG_WARNING, "[obs-nvenc] Forcing main10 for P010");
610+
warn("Forcing main10 for P010");
591611
config->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
592612
profile_is_10bpc = true;
593613
} else {
@@ -601,6 +621,13 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
601621
hevc_config->outputBitDepth = profile_is_10bpc ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8;
602622
#endif
603623

624+
#ifdef NVENC_13_0_OR_LATER
625+
if (is_10_bit(enc) && is_hdr(voi->colorspace)) {
626+
hevc_config->outputMasteringDisplay = 1;
627+
hevc_config->outputMaxCll = 1;
628+
}
629+
#endif
630+
604631
if (!apply_user_args(enc)) {
605632
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
606633
return false;
@@ -688,6 +715,13 @@ static bool init_encoder_av1(struct nvenc_data *enc, obs_data_t *settings)
688715
av1_config->numBwdRefs = 1;
689716
av1_config->repeatSeqHdr = 1;
690717

718+
#ifdef NVENC_13_0_OR_LATER
719+
if (is_10_bit(enc) && is_hdr(voi->colorspace)) {
720+
av1_config->outputMasteringDisplay = 1;
721+
av1_config->outputMaxCll = 1;
722+
}
723+
#endif
724+
691725
if (!apply_user_args(enc)) {
692726
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
693727
return false;
@@ -774,6 +808,31 @@ static bool init_encoder(struct nvenc_data *enc, enum codec_type codec, obs_data
774808
}
775809
}
776810

811+
#ifdef NVENC_13_0_OR_LATER
812+
const bool pq = voi->colorspace == VIDEO_CS_2100_PQ;
813+
const bool hlg = voi->colorspace == VIDEO_CS_2100_HLG;
814+
if (pq || hlg) {
815+
enc->cll = bzalloc(sizeof(CONTENT_LIGHT_LEVEL));
816+
enc->mdi = bzalloc(sizeof(MASTERING_DISPLAY_INFO));
817+
const uint16_t hdr_nominal_peak_level = pq ? (uint16_t)obs_get_video_hdr_nominal_peak_level()
818+
: (hlg ? 1000 : 0);
819+
/* Currently these are hardcoded across all encoders. */
820+
enc->mdi->r.x = 13250;
821+
enc->mdi->r.y = 34500;
822+
enc->mdi->g.x = 7500;
823+
enc->mdi->g.y = 3000;
824+
enc->mdi->b.x = 34000;
825+
enc->mdi->b.y = 16000;
826+
enc->mdi->whitePoint.x = 15635;
827+
enc->mdi->whitePoint.y = 16450;
828+
enc->mdi->maxLuma = hdr_nominal_peak_level * 10000;
829+
enc->mdi->minLuma = 0;
830+
831+
enc->cll->maxContentLightLevel = hdr_nominal_peak_level;
832+
enc->cll->maxPicAverageLightLevel = hdr_nominal_peak_level;
833+
}
834+
#endif
835+
777836
switch (enc->codec) {
778837
case CODEC_HEVC:
779838
return init_encoder_hevc(enc, settings);
@@ -986,6 +1045,13 @@ static void nvenc_destroy(void *data)
9861045
bfree(enc->sei);
9871046
bfree(enc->roi_map);
9881047

1048+
#ifdef NVENC_13_0_OR_LATER
1049+
if (enc->mdi)
1050+
bfree(enc->mdi);
1051+
if (enc->cll)
1052+
bfree(enc->cll);
1053+
#endif
1054+
9891055
deque_free(&enc->dts_list);
9901056

9911057
da_free(enc->surfaces);
@@ -1225,6 +1291,21 @@ bool nvenc_encode_base(struct nvenc_data *enc, struct nv_bitstream *bs, void *pi
12251291
: NV_ENC_BUFFER_FORMAT_NV12;
12261292
}
12271293

1294+
#ifdef NVENC_13_0_OR_LATER
1295+
if (enc->cll) {
1296+
if (enc->codec == CODEC_AV1)
1297+
params.codecPicParams.av1PicParams.pMaxCll = enc->cll;
1298+
else if (enc->codec == CODEC_HEVC)
1299+
params.codecPicParams.hevcPicParams.pMaxCll = enc->cll;
1300+
}
1301+
if (enc->mdi) {
1302+
if (enc->codec == CODEC_AV1)
1303+
params.codecPicParams.av1PicParams.pMasteringDisplay = enc->mdi;
1304+
else if (enc->codec == CODEC_HEVC)
1305+
params.codecPicParams.hevcPicParams.pMasteringDisplay = enc->mdi;
1306+
}
1307+
#endif
1308+
12281309
/* Add ROI map if enabled */
12291310
if (obs_encoder_has_roi(enc->encoder))
12301311
add_roi(enc, &params);

0 commit comments

Comments
 (0)