@@ -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+
217222static 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