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