@@ -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 );
@@ -480,6 +485,13 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
480
485
if (enc -> in_format == VIDEO_FORMAT_I444 ) {
481
486
config -> profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID ;
482
487
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
483
495
} else if (astrcmpi (enc -> props .profile , "main" ) == 0 ) {
484
496
config -> profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID ;
485
497
} else if (astrcmpi (enc -> props .profile , "baseline" ) == 0 ) {
@@ -488,6 +500,13 @@ static bool init_encoder_h264(struct nvenc_data *enc, obs_data_t *settings)
488
500
config -> profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID ;
489
501
}
490
502
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 = config -> profileGUID == NV_ENC_H264_PROFILE_HIGH_10_GUID ? NV_ENC_BIT_DEPTH_10
507
+ : NV_ENC_BIT_DEPTH_8 ;
508
+ #endif
509
+
491
510
if (!apply_user_args (enc )) {
492
511
obs_encoder_set_last_error (enc -> encoder , obs_module_text ("Opts.Invalid" ));
493
512
return false;
@@ -586,7 +605,7 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
586
605
config -> profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID ;
587
606
profile_is_10bpc = true;
588
607
} else if (is_10_bit (enc )) {
589
- blog ( LOG_WARNING , "[obs-nvenc] Forcing main10 for P010" );
608
+ warn ( " Forcing main10 for P010" );
590
609
config -> profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID ;
591
610
profile_is_10bpc = true;
592
611
} else {
@@ -600,6 +619,13 @@ static bool init_encoder_hevc(struct nvenc_data *enc, obs_data_t *settings)
600
619
hevc_config -> outputBitDepth = profile_is_10bpc ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8 ;
601
620
#endif
602
621
622
+ #ifdef NVENC_13_0_OR_LATER
623
+ if (is_10_bit (enc ) && is_hdr (voi -> colorspace )) {
624
+ hevc_config -> outputMasteringDisplay = 1 ;
625
+ hevc_config -> outputMaxCll = 1 ;
626
+ }
627
+ #endif
628
+
603
629
if (!apply_user_args (enc )) {
604
630
obs_encoder_set_last_error (enc -> encoder , obs_module_text ("Opts.Invalid" ));
605
631
return false;
@@ -687,6 +713,13 @@ static bool init_encoder_av1(struct nvenc_data *enc, obs_data_t *settings)
687
713
av1_config -> numBwdRefs = 1 ;
688
714
av1_config -> repeatSeqHdr = 1 ;
689
715
716
+ #ifdef NVENC_13_0_OR_LATER
717
+ if (is_10_bit (enc ) && is_hdr (voi -> colorspace )) {
718
+ av1_config -> outputMasteringDisplay = 1 ;
719
+ av1_config -> outputMaxCll = 1 ;
720
+ }
721
+ #endif
722
+
690
723
if (!apply_user_args (enc )) {
691
724
obs_encoder_set_last_error (enc -> encoder , obs_module_text ("Opts.Invalid" ));
692
725
return false;
@@ -773,6 +806,31 @@ static bool init_encoder(struct nvenc_data *enc, enum codec_type codec, obs_data
773
806
}
774
807
}
775
808
809
+ #ifdef NVENC_13_0_OR_LATER
810
+ const bool pq = voi -> colorspace == VIDEO_CS_2100_PQ ;
811
+ const bool hlg = voi -> colorspace == VIDEO_CS_2100_HLG ;
812
+ if (pq || hlg ) {
813
+ enc -> cll = bzalloc (sizeof (CONTENT_LIGHT_LEVEL ));
814
+ enc -> mdi = bzalloc (sizeof (MASTERING_DISPLAY_INFO ));
815
+ const uint16_t hdr_nominal_peak_level = pq ? (uint16_t )obs_get_video_hdr_nominal_peak_level ()
816
+ : (hlg ? 1000 : 0 );
817
+ /* Currently these are hardcoded across all encoders. */
818
+ enc -> mdi -> r .x = 13250 ;
819
+ enc -> mdi -> r .y = 34500 ;
820
+ enc -> mdi -> g .x = 7500 ;
821
+ enc -> mdi -> g .y = 3000 ;
822
+ enc -> mdi -> b .x = 34000 ;
823
+ enc -> mdi -> b .y = 16000 ;
824
+ enc -> mdi -> whitePoint .x = 15635 ;
825
+ enc -> mdi -> whitePoint .y = 16450 ;
826
+ enc -> mdi -> maxLuma = hdr_nominal_peak_level * 10000 ;
827
+ enc -> mdi -> minLuma = 0 ;
828
+
829
+ enc -> cll -> maxContentLightLevel = hdr_nominal_peak_level ;
830
+ enc -> cll -> maxPicAverageLightLevel = hdr_nominal_peak_level ;
831
+ }
832
+ #endif
833
+
776
834
switch (enc -> codec ) {
777
835
case CODEC_HEVC :
778
836
return init_encoder_hevc (enc , settings );
@@ -985,6 +1043,13 @@ static void nvenc_destroy(void *data)
985
1043
bfree (enc -> sei );
986
1044
bfree (enc -> roi_map );
987
1045
1046
+ #ifdef NVENC_13_0_OR_LATER
1047
+ if (enc -> mdi )
1048
+ bfree (enc -> mdi );
1049
+ if (enc -> cll )
1050
+ bfree (enc -> cll );
1051
+ #endif
1052
+
988
1053
deque_free (& enc -> dts_list );
989
1054
990
1055
da_free (enc -> surfaces );
@@ -1204,6 +1269,21 @@ bool nvenc_encode_base(struct nvenc_data *enc, struct nv_bitstream *bs, void *pi
1204
1269
: NV_ENC_BUFFER_FORMAT_NV12 ;
1205
1270
}
1206
1271
1272
+ #ifdef NVENC_13_0_OR_LATER
1273
+ if (enc -> cll ) {
1274
+ if (enc -> codec == CODEC_AV1 )
1275
+ params .codecPicParams .av1PicParams .pMaxCll = enc -> cll ;
1276
+ else if (enc -> codec == CODEC_HEVC )
1277
+ params .codecPicParams .hevcPicParams .pMaxCll = enc -> cll ;
1278
+ }
1279
+ if (enc -> mdi ) {
1280
+ if (enc -> codec == CODEC_AV1 )
1281
+ params .codecPicParams .av1PicParams .pMasteringDisplay = enc -> mdi ;
1282
+ else if (enc -> codec == CODEC_HEVC )
1283
+ params .codecPicParams .hevcPicParams .pMasteringDisplay = enc -> mdi ;
1284
+ }
1285
+ #endif
1286
+
1207
1287
/* Add ROI map if enabled */
1208
1288
if (obs_encoder_has_roi (enc -> encoder ))
1209
1289
add_roi (enc , & params );
0 commit comments