@@ -213,6 +213,11 @@ static bool is_10_bit(const struct nvenc_data *enc)
213
213
: obs_encoder_video_tex_active (enc -> encoder , VIDEO_FORMAT_P010 );
214
214
}
215
215
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
+
216
221
static bool init_encoder_base (struct nvenc_data * enc , obs_data_t * settings )
217
222
{
218
223
UNUSED_PARAMETER (settings );
@@ -479,6 +484,13 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
479
484
if (enc -> in_format == VIDEO_FORMAT_I444 ) {
480
485
config -> profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID ;
481
486
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
482
494
} else if (astrcmpi (enc -> props .profile , "main" ) == 0 ) {
483
495
config -> profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID ;
484
496
} 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)
487
499
config -> profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID ;
488
500
}
489
501
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
+
490
509
if (!apply_user_args (enc )) {
491
510
obs_encoder_set_last_error (enc -> encoder , obs_module_text ("Opts.Invalid" ));
492
511
return false;
@@ -585,7 +604,7 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
585
604
config -> profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID ;
586
605
profile_is_10bpc = true;
587
606
} else if (is_10_bit (enc )) {
588
- blog ( LOG_WARNING , "[obs-nvenc] Forcing main10 for P010" );
607
+ warn ( " Forcing main10 for P010" );
589
608
config -> profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID ;
590
609
profile_is_10bpc = true;
591
610
} else {
@@ -599,6 +618,13 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
599
618
hevc_config -> outputBitDepth = profile_is_10bpc ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8 ;
600
619
#endif
601
620
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
+
602
628
if (!apply_user_args (enc )) {
603
629
obs_encoder_set_last_error (enc -> encoder , obs_module_text ("Opts.Invalid" ));
604
630
return false;
@@ -686,6 +712,13 @@ static bool init_encoder_av1(struct nvenc_data *enc, obs_data_t *settings)
686
712
av1_config -> numBwdRefs = 1 ;
687
713
av1_config -> repeatSeqHdr = 1 ;
688
714
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
+
689
722
if (!apply_user_args (enc )) {
690
723
obs_encoder_set_last_error (enc -> encoder , obs_module_text ("Opts.Invalid" ));
691
724
return false;
@@ -772,6 +805,31 @@ static bool init_encoder(struct nvenc_data *enc, enum codec_type codec, obs_data
772
805
}
773
806
}
774
807
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
+
775
833
switch (enc -> codec ) {
776
834
case CODEC_HEVC :
777
835
return init_encoder_hevc (enc , settings );
@@ -984,6 +1042,13 @@ static void nvenc_destroy(void *data)
984
1042
bfree (enc -> sei );
985
1043
bfree (enc -> roi_map );
986
1044
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
+
987
1052
deque_free (& enc -> dts_list );
988
1053
989
1054
da_free (enc -> surfaces );
@@ -1203,6 +1268,21 @@ bool nvenc_encode_base(struct nvenc_data *enc, struct nv_bitstream *bs, void *pi
1203
1268
: NV_ENC_BUFFER_FORMAT_NV12 ;
1204
1269
}
1205
1270
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
+
1206
1286
/* Add ROI map if enabled */
1207
1287
if (obs_encoder_has_roi (enc -> encoder ))
1208
1288
add_roi (enc , & params );
0 commit comments