Repository navigation
Add ITU-R BT.709 YCbCr conversions to the color conversion kernels #6567
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jantonguirao
merged 9 commits into
NVIDIA:main
from
jantonguirao:janton/dali-4954-bt709-kernels
Oct 30, 2026
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
d5517da
Add ITU-R BT.709 YCbCr conversions to the color conversion kernels
jantonguirao e8755f9
Share the gray conversions of the ITU-R methods and test BT.709 with …
jantonguirao 98585c0
Share the YCbCr conversions of the ITU-R, JPEG and BT.709 methods
jantonguirao cd642d8
Derive the YCbCr matrices from the luma weights
jantonguirao bbc0e4c
Tidy the YCbCr conversion templates and pin the BT.709 full range
jantonguirao 896ebd4
Spell out the reference parameters of the BT.709 methods in the test
jantonguirao 6f8e4fa
Compute the BT.709 matrix rows at compile time, also in debug builds
jantonguirao eb660ab
Add braces around the conditional EXPECT in the BT.709 round-trip test
jantonguirao d72e2b5
Use the n-bit limited range for the integer types in the YCbCr conver…
jantonguirao File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Question] The limited-range offsets are fractions of
2^n(y_bias= 1/16, chroma offset 1/2), but the scales are fractions of the type maximum2^n - 1(219/255 and 224/255). For 8-bit types this gives exactly 16..235 / 16..240. For other types it does not match the published n-bit limited range (16 * 2^(n-8)to235 * 2^(n-8)for Y):For float it is the same issue with samples normalized by 255: the black level is 0.0625 here, but 16/255 = 0.0627 for 8-bit video, and the neutral chroma is 0.5, but 128/255 = 0.502.
color_space.cucallsycbcr_to_rgb<float>onyuv * (1 / 255). I computed that path with the BT.709 coefficients:itu_r_bt_601already behaves this way, so this is not a regression, and the typed tests cannot catch it because their reference uses the same convention (unit<Out>() * yscale + ybias). Butitu_r_bt_709is meant for the video decoders (follow-up PR), where 10-bit HEVC and float output are likely, so it seems worth deciding now.Is this convention intended? If not, the offsets could be
16 * 2^(n-8)with the scale219 * 2^(n-8), or the video path could convert touint8_tfirst. If it is intended, a sentence in the comment abovelimited_rangesaying that only 8-bit types match the published ranges would help.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, your numbers reproduce: uint16 white was 60379, the largest Cb was 61552, and the smallest was 3984, below the black level of 4096.
The convention was not intended. The offsets were already fractions of 2^n, but the spans were fractions of the type maximum, which matches the published ranges only for 8 bits.
itu_r_bt_601had it before this PR, so BT.709 inherited it.I fixed it for the integer types in d72e2b5, for all limited range methods (BT.601 too) and for the gray conversions: the spans are now 219 * 2^(n-8) and 224 * 2^(n-8), as in BT.601/709/2100 and H.273. uint8, float and the full range methods are bit-identical to before. For uint16 the range is now 4096..60160 for Y and 4096..61440 for Cb and Cr, with pinned values in the new tests. The reference of the typed tests follows the same definition now, so it can catch this.
Float is not changed. The recommendations do not define it, and the right black level depends on the bit depth of the source, which the kernel does not know (16/255 for 8-bit data normalized by 255, 4096/65535 for 16-bit data). The current values are within about 0.6% of both. I documented this in the comment above
limited_range. If you would prefer float to follow 8-bit data (offsets 16/255 and 128/255), let me know. It moves the float golden files, so I would do it in a separate PR.The (131.4, 130.1, 131.5) result you computed is a separate problem:
color_space.cunormalizes the 8-bit codes by 1/255 and then uses the float convention. The kernel change does not fix it, so it needs its own fix at the call site, which I am leaving out of this PR. As far as I can tell, only 8-bit NV12 reaches that kernel today.One side effect, described in the header comment: converting a YCbCr input directly and converting its type first now differ by up to about 2% of the full scale when the input and output types differ (YCbCr inputs only). I updated the tolerances of the tests, and I ran the CPU vs GPU convert tests on a Titan V: they pass.