Skip to content

Commit ec5613c

Browse files
committed
obs-nvenc: Add SDK 13.0 features
1 parent e6f13af commit ec5613c

File tree

7 files changed

+114
-3
lines changed

7 files changed

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

+6
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,
@@ -54,10 +58,12 @@ struct encoder_caps {
5458
bool lookahead;
5559
bool lossless;
5660
bool temporal_aq;
61+
bool uhq;
5762

5863
/* Yeah... */
5964
bool ten_bit;
6065
bool four_four_four;
66+
bool four_two_two;
6167
};
6268

6369
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-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
126126
p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"), 50, UINT32_MAX / 1000, 50);
127127
obs_property_int_set_suffix(p, " Kbps");
128128

129-
obs_properties_add_int(props, "target_quality", obs_module_text("TargetQuality"), 1, 51, 1);
129+
obs_properties_add_int(props, "target_quality", obs_module_text("TargetQuality"), 1,
130+
codec == CODEC_AV1 ? 63 : 51, 1);
130131

131132
p = obs_properties_add_int(props, "max_bitrate", obs_module_text("MaxBitrate"), 0, UINT32_MAX / 1000, 50);
132133
obs_property_int_set_suffix(p, " Kbps");
@@ -160,7 +161,7 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
160161
/* The UHQ tune is only supported on Turing or later.
161162
* It uses the temporal filtering feature, so we can use its
162163
* availability as an indicator that we are on a supported GPU. */
163-
if (codec == CODEC_HEVC && caps->temporal_filter)
164+
if (caps->uhq)
164165
add_tune("uhq");
165166
#endif
166167
add_tune("hq");
@@ -188,6 +189,10 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
188189
} else if (codec == CODEC_AV1) {
189190
add_profile("main");
190191
} else {
192+
#ifdef NVENC_13_0_OR_LATER
193+
if (caps->ten_bit)
194+
add_profile("high10");
195+
#endif
191196
add_profile("high");
192197
add_profile("main");
193198
add_profile("baseline");
@@ -243,6 +248,12 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
243248
obs_property_list_add_int(p, obs_module_text("SplitEncode.ThreeWay"),
244249
NV_ENC_SPLIT_THREE_FORCED_MODE);
245250
}
251+
#ifdef NVENC_13_0_OR_LATER
252+
if (caps->engines > 3) {
253+
obs_property_list_add_int(p, obs_module_text("SplitEncode.FourWay"),
254+
NV_ENC_SPLIT_FOUR_FORCED_MODE);
255+
}
256+
#endif
246257
}
247258
#endif
248259

plugins/obs-nvenc/nvenc.c

+81-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);
@@ -479,6 +484,13 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
479484
if (enc->in_format == VIDEO_FORMAT_I444) {
480485
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID;
481486
h264_config->chromaFormatIDC = 3;
487+
#ifdef NVENC_13_0_OR_LATER
488+
} else if (astrcmpi(enc->props.profile, "high10") == 0) {
489+
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID;
490+
} else if (is_10_bit(enc)) {
491+
warn("Forcing high10 for P010");
492+
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID;
493+
#endif
482494
} else if (astrcmpi(enc->props.profile, "main") == 0) {
483495
config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
484496
} else if (astrcmpi(enc->props.profile, "baseline") == 0) {
@@ -487,6 +499,13 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
487499
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
488500
}
489501

502+
#ifdef NVENC_13_0_OR_LATER
503+
/* Note: Only supported on Blackwell! */
504+
h264_config->inputBitDepth = is_10_bit(enc) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8;
505+
h264_config->outputBitDepth = config->profileGUID == NV_ENC_H264_PROFILE_HIGH_10_GUID ? NV_ENC_BIT_DEPTH_10
506+
: NV_ENC_BIT_DEPTH_8;
507+
#endif
508+
490509
if (!apply_user_args(enc)) {
491510
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
492511
return false;
@@ -585,7 +604,7 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
585604
config->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
586605
profile_is_10bpc = true;
587606
} else if (is_10_bit(enc)) {
588-
blog(LOG_WARNING, "[obs-nvenc] Forcing main10 for P010");
607+
warn("Forcing main10 for P010");
589608
config->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
590609
profile_is_10bpc = true;
591610
} else {
@@ -599,6 +618,13 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
599618
hevc_config->outputBitDepth = profile_is_10bpc ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8;
600619
#endif
601620

621+
#ifdef NVENC_13_0_OR_LATER
622+
if (is_10_bit(enc) && is_hdr(voi->colorspace)) {
623+
hevc_config->outputMasteringDisplay = 1;
624+
hevc_config->outputMaxCll = 1;
625+
}
626+
#endif
627+
602628
if (!apply_user_args(enc)) {
603629
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
604630
return false;
@@ -686,6 +712,13 @@ static bool init_encoder_av1(struct nvenc_data *enc, obs_data_t *settings)
686712
av1_config->numBwdRefs = 1;
687713
av1_config->repeatSeqHdr = 1;
688714

715+
#ifdef NVENC_13_0_OR_LATER
716+
if (is_10_bit(enc) && is_hdr(voi->colorspace)) {
717+
av1_config->outputMasteringDisplay = 1;
718+
av1_config->outputMaxCll = 1;
719+
}
720+
#endif
721+
689722
if (!apply_user_args(enc)) {
690723
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
691724
return false;
@@ -772,6 +805,31 @@ static bool init_encoder(struct nvenc_data *enc, enum codec_type codec, obs_data
772805
}
773806
}
774807

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

1045+
#ifdef NVENC_13_0_OR_LATER
1046+
if (enc->mdi)
1047+
bfree(enc->mdi);
1048+
if (enc->cll)
1049+
bfree(enc->cll);
1050+
#endif
1051+
9871052
deque_free(&enc->dts_list);
9881053

9891054
da_free(enc->surfaces);
@@ -1203,6 +1268,21 @@ bool nvenc_encode_base(struct nvenc_data *enc, struct nv_bitstream *bs, void *pi
12031268
: NV_ENC_BUFFER_FORMAT_NV12;
12041269
}
12051270

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

0 commit comments

Comments
 (0)