Skip to content

Commit

Permalink
obs-nvenc: Add SDK 13.0 features
Browse files Browse the repository at this point in the history
  • Loading branch information
derrod committed Jan 30, 2025
1 parent e6f13af commit ec5613c
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 3 deletions.
1 change: 1 addition & 0 deletions plugins/obs-nvenc/data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ SplitEncode.Auto="Auto"
SplitEncode.Disabled="Disabled"
SplitEncode.Enabled="Two-way split"
SplitEncode.ThreeWay="Three-way split"
SplitEncode.FourWay="Four-way split"

Opts="Custom Encoder Options"
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\""
Expand Down
2 changes: 2 additions & 0 deletions plugins/obs-nvenc/nvenc-helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ static void read_codec_caps(config_t *config, enum codec_type codec, const char
caps->temporal_aq = config_get_bool(config, section, "temporal_aq");
caps->ten_bit = config_get_bool(config, section, "10bit");
caps->four_four_four = config_get_bool(config, section, "yuv_444");
caps->four_two_two = config_get_bool(config, section, "yuv_422");
caps->uhq = config_get_bool(config, section, "uhq");
}

static bool nvenc_check(void)
Expand Down
6 changes: 6 additions & 0 deletions plugins/obs-nvenc/nvenc-helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#define NVENC_12_2_OR_LATER
#endif

#if NVENCAPI_MAJOR_VERSION >= 13
#define NVENC_13_0_OR_LATER
#endif

enum codec_type {
CODEC_H264,
CODEC_HEVC,
Expand Down Expand Up @@ -54,10 +58,12 @@ struct encoder_caps {
bool lookahead;
bool lossless;
bool temporal_aq;
bool uhq;

/* Yeah... */
bool ten_bit;
bool four_four_four;
bool four_two_two;
};

typedef NVENCSTATUS(NVENCAPI *NV_CREATE_INSTANCE_FUNC)(NV_ENCODE_API_FUNCTION_LIST *);
Expand Down
5 changes: 5 additions & 0 deletions plugins/obs-nvenc/nvenc-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ struct nvenc_data {
size_t roi_map_size;
uint32_t roi_increment;

#ifdef NVENC_13_0_OR_LATER
CONTENT_LIGHT_LEVEL *cll;
MASTERING_DISPLAY_INFO *mdi;
#endif

struct nvenc_properties props;

CUcontext cu_ctx;
Expand Down
6 changes: 6 additions & 0 deletions plugins/obs-nvenc/nvenc-opts-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ static bool apply_h264_opt(struct obs_option *opt, NV_ENC_CONFIG_H264 *nv_conf)

APPLY_INT_OPT(idrPeriod, uint32_t, PRIu32)
APPLY_INT_OPT(useBFramesAsRef, NV_ENC_BFRAME_REF_MODE, PRIu32)
#ifdef NVENC_13_0_OR_LATER
APPLY_INT_OPT(tfLevel, NV_ENC_TEMPORAL_FILTER_LEVEL, PRIu32)
#endif

APPLY_BIT_OPT(enableFillerDataInsertion, 1)

Expand Down Expand Up @@ -162,6 +165,9 @@ static bool apply_av1_opt(struct obs_option *opt, NV_ENC_CONFIG_AV1 *nv_conf)
APPLY_INT_OPT(numTileRows, uint32_t, PRIu32)
APPLY_INT_OPT(idrPeriod, uint32_t, PRIu32)
APPLY_INT_OPT(useBFramesAsRef, NV_ENC_BFRAME_REF_MODE, PRIu32)
#ifdef NVENC_13_0_OR_LATER
APPLY_INT_OPT(tfLevel, NV_ENC_TEMPORAL_FILTER_LEVEL, PRIu32)
#endif

APPLY_BIT_OPT(enableBitstreamPadding, 1)

Expand Down
15 changes: 13 additions & 2 deletions plugins/obs-nvenc/nvenc-properties.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"), 50, UINT32_MAX / 1000, 50);
obs_property_int_set_suffix(p, " Kbps");

obs_properties_add_int(props, "target_quality", obs_module_text("TargetQuality"), 1, 51, 1);
obs_properties_add_int(props, "target_quality", obs_module_text("TargetQuality"), 1,
codec == CODEC_AV1 ? 63 : 51, 1);

p = obs_properties_add_int(props, "max_bitrate", obs_module_text("MaxBitrate"), 0, UINT32_MAX / 1000, 50);
obs_property_int_set_suffix(p, " Kbps");
Expand Down Expand Up @@ -160,7 +161,7 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
/* The UHQ tune is only supported on Turing or later.
* It uses the temporal filtering feature, so we can use its
* availability as an indicator that we are on a supported GPU. */
if (codec == CODEC_HEVC && caps->temporal_filter)
if (caps->uhq)
add_tune("uhq");
#endif
add_tune("hq");
Expand Down Expand Up @@ -188,6 +189,10 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
} else if (codec == CODEC_AV1) {
add_profile("main");
} else {
#ifdef NVENC_13_0_OR_LATER
if (caps->ten_bit)
add_profile("high10");
#endif
add_profile("high");
add_profile("main");
add_profile("baseline");
Expand Down Expand Up @@ -243,6 +248,12 @@ obs_properties_t *nvenc_properties_internal(enum codec_type codec)
obs_property_list_add_int(p, obs_module_text("SplitEncode.ThreeWay"),
NV_ENC_SPLIT_THREE_FORCED_MODE);
}
#ifdef NVENC_13_0_OR_LATER
if (caps->engines > 3) {
obs_property_list_add_int(p, obs_module_text("SplitEncode.FourWay"),
NV_ENC_SPLIT_FOUR_FORCED_MODE);
}
#endif
}
#endif

Expand Down
82 changes: 81 additions & 1 deletion plugins/obs-nvenc/nvenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ static bool is_10_bit(const struct nvenc_data *enc)
: obs_encoder_video_tex_active(enc->encoder, VIDEO_FORMAT_P010);
}

static bool is_hdr(const enum video_colorspace space)
{
return space == VIDEO_CS_2100_HLG || space == VIDEO_CS_2100_PQ;
}

static bool init_encoder_base(struct nvenc_data *enc, obs_data_t *settings)
{
UNUSED_PARAMETER(settings);
Expand Down Expand Up @@ -479,6 +484,13 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
if (enc->in_format == VIDEO_FORMAT_I444) {
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID;
h264_config->chromaFormatIDC = 3;
#ifdef NVENC_13_0_OR_LATER
} else if (astrcmpi(enc->props.profile, "high10") == 0) {
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID;
} else if (is_10_bit(enc)) {
warn("Forcing high10 for P010");
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_10_GUID;
#endif
} else if (astrcmpi(enc->props.profile, "main") == 0) {
config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
} else if (astrcmpi(enc->props.profile, "baseline") == 0) {
Expand All @@ -487,6 +499,13 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
}

#ifdef NVENC_13_0_OR_LATER
/* Note: Only supported on Blackwell! */
h264_config->inputBitDepth = is_10_bit(enc) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8;
h264_config->outputBitDepth = config->profileGUID == NV_ENC_H264_PROFILE_HIGH_10_GUID ? NV_ENC_BIT_DEPTH_10
: NV_ENC_BIT_DEPTH_8;
#endif

if (!apply_user_args(enc)) {
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
return false;
Expand Down Expand Up @@ -585,7 +604,7 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
config->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
profile_is_10bpc = true;
} else if (is_10_bit(enc)) {
blog(LOG_WARNING, "[obs-nvenc] Forcing main10 for P010");
warn("Forcing main10 for P010");
config->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
profile_is_10bpc = true;
} else {
Expand All @@ -599,6 +618,13 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
hevc_config->outputBitDepth = profile_is_10bpc ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8;
#endif

#ifdef NVENC_13_0_OR_LATER
if (is_10_bit(enc) && is_hdr(voi->colorspace)) {
hevc_config->outputMasteringDisplay = 1;
hevc_config->outputMaxCll = 1;
}
#endif

if (!apply_user_args(enc)) {
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
return false;
Expand Down Expand Up @@ -686,6 +712,13 @@ static bool init_encoder_av1(struct nvenc_data *enc, obs_data_t *settings)
av1_config->numBwdRefs = 1;
av1_config->repeatSeqHdr = 1;

#ifdef NVENC_13_0_OR_LATER
if (is_10_bit(enc) && is_hdr(voi->colorspace)) {
av1_config->outputMasteringDisplay = 1;
av1_config->outputMaxCll = 1;
}
#endif

if (!apply_user_args(enc)) {
obs_encoder_set_last_error(enc->encoder, obs_module_text("Opts.Invalid"));
return false;
Expand Down Expand Up @@ -772,6 +805,31 @@ static bool init_encoder(struct nvenc_data *enc, enum codec_type codec, obs_data
}
}

#ifdef NVENC_13_0_OR_LATER
const bool pq = voi->colorspace == VIDEO_CS_2100_PQ;
const bool hlg = voi->colorspace == VIDEO_CS_2100_HLG;
if (pq || hlg) {
enc->cll = bzalloc(sizeof(CONTENT_LIGHT_LEVEL));
enc->mdi = bzalloc(sizeof(MASTERING_DISPLAY_INFO));
const uint16_t hdr_nominal_peak_level = pq ? (uint16_t)obs_get_video_hdr_nominal_peak_level()
: (hlg ? 1000 : 0);
/* Currently these are hardcoded across all encoders. */
enc->mdi->r.x = 13250;
enc->mdi->r.y = 34500;
enc->mdi->g.x = 7500;
enc->mdi->g.y = 3000;
enc->mdi->b.x = 34000;
enc->mdi->b.y = 16000;
enc->mdi->whitePoint.x = 15635;
enc->mdi->whitePoint.y = 16450;
enc->mdi->maxLuma = hdr_nominal_peak_level * 10000;
enc->mdi->minLuma = 0;

enc->cll->maxContentLightLevel = hdr_nominal_peak_level;
enc->cll->maxPicAverageLightLevel = hdr_nominal_peak_level;
}
#endif

switch (enc->codec) {
case CODEC_HEVC:
return init_encoder_hevc(enc, settings);
Expand Down Expand Up @@ -984,6 +1042,13 @@ static void nvenc_destroy(void *data)
bfree(enc->sei);
bfree(enc->roi_map);

#ifdef NVENC_13_0_OR_LATER
if (enc->mdi)
bfree(enc->mdi);
if (enc->cll)
bfree(enc->cll);
#endif

deque_free(&enc->dts_list);

da_free(enc->surfaces);
Expand Down Expand Up @@ -1203,6 +1268,21 @@ bool nvenc_encode_base(struct nvenc_data *enc, struct nv_bitstream *bs, void *pi
: NV_ENC_BUFFER_FORMAT_NV12;
}

#ifdef NVENC_13_0_OR_LATER
if (enc->cll) {
if (enc->codec == CODEC_AV1)
params.codecPicParams.av1PicParams.pMaxCll = enc->cll;
else if (enc->codec == CODEC_HEVC)
params.codecPicParams.hevcPicParams.pMaxCll = enc->cll;
}
if (enc->mdi) {
if (enc->codec == CODEC_AV1)
params.codecPicParams.av1PicParams.pMasteringDisplay = enc->mdi;
else if (enc->codec == CODEC_HEVC)
params.codecPicParams.hevcPicParams.pMasteringDisplay = enc->mdi;
}
#endif

/* Add ROI map if enabled */
if (obs_encoder_has_roi(enc->encoder))
add_roi(enc, &params);
Expand Down

0 comments on commit ec5613c

Please sign in to comment.