NVENC HEVC with full range colors?

I’m currently evaluating the video encoder od SDK 7.0 on a GTX1060.
As an input I use the testsrc generated by ffmpeg:

ffmpeg -f lavfi -i testsrc=duration=60:size=3840x2160:rate=60 -crf 0 -c:v libx264rgb -vf scale=dst_range=1 testsrc.mp4

I convert it to YUV444 before, of course.
Finally, I use such command to encode:

NvEncoderPerf -i testsrc_crf00.yuv -o testsrc_crf00.h265 -size 3840 2160 -inputFormat 1 -fps 60 -codec 1 -preset hq -rcmode 0 -qp 0

I want to do a lossless encoding, so I need to check that the decoded video has same color than the input, which isn’t the case.
IMHO it’s because the encoder consider the YCbCr to be in TV range, where Y is in [0…255], but Cb and Cr are scaled to [16…235].
I found in the

hevcVUIParameters

there are parameters that could do the full range job:

  • VideoSignalTypePresentFlag
  • videoFullRangeFlag
  • videoFormat
  • colourDescriptionPresentFlag
  • colourPrimaries
  • colourMatrix
  • transferCharacteristics

So in the Sample NvHWEncoder.cpp provided with the SDK, I added these lines at line 896.

m_stEncodeConfig.encodeCodecConfig.hevcConfig.hevcVUIParameters.videoSignalTypePresentFlag = 1;
m_stEncodeConfig.encodeCodecConfig.hevcConfig.hevcVUIParameters.videoFullRangeFlag = 1;
m_stEncodeConfig.encodeCodecConfig.hevcConfig.hevcVUIParameters.videoFormat = 5; // unspecified
m_stEncodeConfig.encodeCodecConfig.hevcConfig.hevcVUIParameters.colourDescriptionPresentFlag = 1;
m_stEncodeConfig.encodeCodecConfig.hevcConfig.hevcVUIParameters.colourPrimaries = 1; // AVCOL_SPC_BT709 = 1
m_stEncodeConfig.encodeCodecConfig.hevcConfig.hevcVUIParameters.colourMatrix = 1; //AVCOL_PRI_BT709 = 1
m_stEncodeConfig.encodeCodecConfig.hevcConfig.hevcVUIParameters.transferCharacteristics = 1; // AVCOL_TRC_BT709 = 1

Unfortunately it doesn’t produce a full range color video as I expected. Any idea why?

Seeing core NVENC SDK developers suddenly become active today…I am bumping this topic up for their attention

Hi.

Sorry for a slow response here. This thread was referenced in some other discussion, so I thought I should respond here.

For doing lossless encoding, you should use the Lossless preset.

NVENC does not care whether the input is full range or limited range. Full-range/limited-range is a RGB to YUV (or vice versa) color conversion issue. It is a job of client application to ensure that end-to-end color space conversion logic is maintained in a consistent manner. To do that, the client application needs to know what CSC matrix was used in converting from RGB to YUV, fill the VUI params correctly, and the decoder needs to honor the information given in the VUI params to decode and perform the color conversion correctly.

If the specified input surface format is ABGR or ARGB, full range is assumed inside the NVENCODEAPI for doing the CSC.

Thanks.

1 Like

“Unfortunately it doesn’t produce a full range color video as I expected”

And how did you check for this? You need to also tag mkv or mp4 container with full range. In case of mp4 you should also write a mp4 nclc chunk with -movflags +write_colr

YCbCr to be in TV range, where Y is in [0…255], but Cb and Cr are scaled to [16…235].

TV range is [1 … 254] in all three components. It always was. Also Chroma is not scaled between 16 and 235, but between 16 and 240. Wow.