mdejong / MetalBT709Decoder

Proper rendering of BT.709 encoded H.264 image using Metal
32 stars 5 forks source link

Use `CVImageBufferCreateColorSpaceFromAttachments` rather than hard-coding color space information #2

Closed fumoboy007 closed 5 years ago

fumoboy007 commented 5 years ago

Rather than hard-coding constants, you can use CVImageBufferCreateColorSpaceFromAttachments to get the Apple-custom color space corresponding to a (Y'CbCr matrix, color primaries, transfer function) triple. Then, use the methods described in #1 to convert from this color space to your destination color space.

This will always produce results equivalent to AVFoundation even if the implementation of the Apple-custom color profiles or the Apple CMM changes in the future.

mdejong commented 5 years ago

Actually, that does not work. You can see an example of that sort of call in H264Encoder.m and in BGRAToBT709Converter.m in the source code. One has to set attachments related to the BT.709 matrix but this will not actually use the correct gamma conversion. What I am doing to maintain compatibility with Apple 1.96 gamma it to invoke [H264Encoder createHDTVColorSpaceRef] to get access to the hidden HDTV colorspace ref which is then used to encode sRGB -> YCbCr with a gamma that exactly matches the Apple 1.96 gamma curve. To see this in action, run the encode_h264 target to go from sRGB -> m4v or use the srgb_to_bt709 target to encode sRGB -> Y4M and then encode with ffmpeg (with bt.709 flags) to generate a .m4v with the proper settings.

fumoboy007 commented 5 years ago

Your +[H264Encoder createHDTVColorSpaceRef] method does what I described above, but in an indirect way. I have already reverse-engineered the -[CIImage imageWithCVPixelBuffer:] method and internally, it calls CVImageBufferCreateColorSpaceFromAttachments.

In fact, here are the most popular Apple-custom color spaces that can be created by that function: Apple Video Color Spaces.zip.

mdejong commented 5 years ago

Ahh, interesting. I assume you grabbed these icc profiles via CGColorSpaceCopyICCData() ? The thing about this approach is that the ICC color profiles generated with these curves do not seem to include the near zero black level linear segments, see how "Red tone response curve" online lists 1.961 but it makes no mention of the linear segment. That seems to be handled by the Apple CMM. What is unclear to me is if one were to import one of these ICC files into AfterEffects, would it actually slope limit to 16 or would it use the slope limit of 32 which Adobe CMM seems to define.

fumoboy007 commented 5 years ago

Yes, I believe the slope limit is internal to the CMM. I noticed that these color spaces have a Preferred CMM: Apple field. I have a feeling that this Preferred CMM field can be used by CMMs to deal with the subtleties of other CMMs. Whether Adobe CMM uses that field or not, I don’t know.

cc @UliZappe who seems to be pretty knowledgeable about this topic. 😉

UliZappe commented 5 years ago

The thing about this approach is that the ICC color profiles generated with these curves do not seem to include the near zero black level linear segments, see how "Red tone response curve" online lists 1.961 but it makes no mention of the linear segment. That seems to be handled by the Apple CMM.

Yep. Slope Limiting is a CMM feature to ensure a minimum resolution in dark areas no matter how fine tuned or not the ICC profile is in this regard.

To see how this could be implemented in a CMM, take a look at my Little CMS patch.

If you want to reimplement the complete TRC without using a CMM, but emulate ICC color management behavior, you must add slope limiting (16 to emulate the Apple/Kodak CMM, 32 to emulate the Adobe CMM) to the TRC of the ICC profile.

What is unclear to me is if one were to import one of these ICC files into AfterEffects, would it actually slope limit to 16 or would it use the slope limit of 32 which Adobe CMM seems to define.

That simply depends on what CMM AfterEffects uses. I do not know this program, maybe you can select the CMM in its preferences, maybe it’s hard-coded to use the Adobe CMM, maybe it depends on the OS on which it is running. This should be documented somewhere in the AfterEffects docs.

UliZappe commented 5 years ago

Also note that adding slope limiting does not mean to always use the linear (16 or 32) segment, as if it was a 2 part TRC. Slope limiting, as its name suggests, limits the TRC; i.e. if the TRC of the ICC profile lies above the linear slope limiting segment, slope limiting has no effect at all. It just prevents the TRC from sinking below minimum values in the dark area.

fumoboy007 commented 5 years ago

@UliZappe Question: Is “black point compensation” the same thing as “slope limiting”?

UliZappe commented 5 years ago

It’s not the same thing, but it has the same goal.

For Black Point Compensation, the ICC profile creation software measures the near-black values and takes these measurements into account when the ICC profile is created. It’s an improved version of an ICC profile (with relative colorimetric intent), so to speak, taking into account the imperfections of technology where black is not necessarily 0. (ICC profiles with a true perceptual rendering intent have always done this.) Black Point Compensation is always specific to a specific color space and as such incorporated in the corresponding ICC profile.

Slope Limiting is a fall-back solution / a “last resort” within the CMM for ICC profiles with less-than-ideal behavior in the dark areas (e.g. ICC profiles with relative rendering intent without blackpoint compensation). It is much coarser by principle, as, being implemented in the CMM, it uses a “one size fits all” approach without using any data specific to the device the ICC profile describes.

With ICC profiles with a true perceptual rendering intent or a relative colorimetric rendering intent with blackpoint compensation, slope limiting rarely should have any effect at all. It’s the other, especially the “idealized” standard ICC profiles with a simple gamma curve where it matters.

mdejong commented 5 years ago

There is some interesting discussion here, but I am going to close this issue since the encoder process does not use hard coded values. Keeping discussion open on the other issue about encoding.