Skip to content

Commit b7bc77d

Browse files
committed
obs-nvenc: Add SDK 13.0 features
1 parent 6b7b759 commit b7bc77d

File tree

7 files changed

+117
-10
lines changed

7 files changed

+117
-10
lines changed

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

+1
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

+2
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

+8-3
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

+5
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ struct nvenc_data {
107107
size_t roi_map_size;
108108
uint32_t roi_increment;
109109

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

112117
CUcontext cu_ctx;

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

+6
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

+13-6
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

+82-1
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ static bool is_10_bit(const struct nvenc_data *enc)
213213
: obs_encoder_video_tex_active(enc->encoder, VIDEO_FORMAT_P010);
214214
}
215215

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

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

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

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

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

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

9901056
da_free(enc->surfaces);
@@ -1204,6 +1270,21 @@ bool nvenc_encode_base(struct nvenc_data *enc, struct nv_bitstream *bs, void *pi
12041270
: NV_ENC_BUFFER_FORMAT_NV12;
12051271
}
12061272

1273+
#ifdef NVENC_13_0_OR_LATER
1274+
if (enc->cll) {
1275+
if (enc->codec == CODEC_AV1)
1276+
params.codecPicParams.av1PicParams.pMaxCll = enc->cll;
1277+
else if (enc->codec == CODEC_HEVC)
1278+
params.codecPicParams.hevcPicParams.pMaxCll = enc->cll;
1279+
}
1280+
if (enc->mdi) {
1281+
if (enc->codec == CODEC_AV1)
1282+
params.codecPicParams.av1PicParams.pMasteringDisplay = enc->mdi;
1283+
else if (enc->codec == CODEC_HEVC)
1284+
params.codecPicParams.hevcPicParams.pMasteringDisplay = enc->mdi;
1285+
}
1286+
#endif
1287+
12071288
/* Add ROI map if enabled */
12081289
if (obs_encoder_has_roi(enc->encoder))
12091290
add_roi(enc, &params);

0 commit comments

Comments
 (0)