-
-
Notifications
You must be signed in to change notification settings - Fork 350
Webcodecs: Handle limited range pixel values in NV12 data. #1606
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
base: webcodecs
Are you sure you want to change the base?
Conversation
NV12 data. "Full range" means that the pixel data ranges from 0 to 255. "Limited range" means that it's using a more constrained range, such as 16 to 235. Because the range is being clamped, it prevents images decoded with the VideoDecoder API from using the full range of color. Notably, this caused fully transparent backgrounds to be light gray due to the bottom end of the range starting at 16 instead of 0. Also, explicilty handle the mono image channel used to encode transparency information in HEIC images. Lastly, add the copyright header to decoder_webcodecs.h.
There are two different modes in video that rarely existed in images, but now that video and image share formats, they have become relevant. What's often called full-range, PC-mode, or JPEG-mode is from 0-255, while limited-range, TV-mode, or video-mode is from 16-235 (16-240 chroma), with those numbers scaled up for 10+ bit. The latter is by far the most common for any video you'll encounter, the former for images. Libheif supports both via the full_range_flag in nclx, and will flag an image as being in limited or full range -- the decoder should handle that. (Which decoders have been getting much better about actually doing.) I think you can override it to get the right color conversion even when decoding. That saves the hit of an extra color conversion step plus additional round-off errors from the scaling. |
I tried to use that information to update the approach, but wasn't able to get something fully working. Here's what I tried: Create the nclx color profile:
Implemented conversion functions to convert from the values returned by the browser's decoded VideoFrame:
It would also be possible to grab this data from the VUI section of the SPS data, but the SPS parsing function we've got in this file doesn't have code to parse the VUI info. I printed some debug output to make sure this was all getting set properly, and I saw primaries = smpte170m (6), transfer = bt709 (1), matrix = smpte170m (6), and full range = 0. All these values seem correct to me, so I'm not quite sure why it doesn't work. Is there anything special you have to do when using the image data, such as over in post.js? |
I've investigated this further and discovered two things that prevent setting of the nclx profile from working as expected.
After this investigation I can see that it doesn't make sense to do the limited range color conversion in the decoder plugin. So I will go ahead and update this PR just to properly set the nclx profile info on the decoded image. However, I still think both things I raised above should be addressed to make color conversion & preserve the alpha channel properly for data returned from the webcodecs plugin. If there's any direction on that and whether you'd like me to take either thing on let me know. Thanks! |
the decoded tiles. Remove custom limited range color remapping that was being done in the plugin.
NV12 data coming from the browser's VideoDecoder API may be using a different range of pixel values (instead of 0-255). The pixel ranges need to be re-mapped to use the full range expected by libheif.
In particular, this caused transparent backgrounds to be light gray due to the bottom end of the range starting at 16 instead of 0.
This PR also adds explicit handling of the mono alpha channel that's used to encode the transparency information in HEIC images when dealing with NV12 data.
P.S.: Not related to the changes in this PR, but I noticed that the alpha channel does not work properly when decode_with_browser_hevc returns RGBA data. I tried a few different ways to get it to work, but wasn't able to (the background is always black). I'm not sure if libheif is setup to handle the alpha channel mask when using RGBA data, or if there was an issue with my approach.
I was able to get it to work by converting RGBA data to NV12 and reusing that pathway. I know you didn't like that approach before, but it has a bit more meaning now to reuse the code b/c there's more custom code on each pathway for handling the mono/transparency mask. Let me know if you want a PR for that or if you want to try to work on getting alpha support to work with RGBA formatted data.
Note that from my perspective it is not that big of a problem, because I haven't yet seen any images with transparency that are using the code path that returns RGBA (I have to "force" it by modifying the code). But it might possibly be more likely on other hardware that I'm not testing on.
For my purposes, the webcodecs plugin is already very useful as it is, b/c HEIC with alpha channels are already somewhat rare to begin with.