如何在自定义 Metal Core Image Kernel 中正确处理 HDR10?

问题描述

我有一个自定义Metal Core Image 内核(用 CIImageProcessorKernel 编写),我正在尝试使其与 HDR 视频(HDR10 PQ 启动)一起正常工作。

我知道对于 HDR 视频,进入着色器的 rgb 值可以低于 0.0 或高于 1.0。但是,我不明白视频中的 10 位整数值(即 0-1023)是如何映射到浮点数的。

浮点数的最小值和最大值是多少? IE。 1023(纯白色)像素在着色器中的浮点数是多少。

在 WWDC20 session 10009, 的 11:32 使用 AVFoundation 编辑和播放 HDR 视频时,有一个 Core Image Metal 内核的示例,它不支持 HDR,因此无法工作。它通过从 1.0 中减去它们来反转传入的值,当 1.0 不是最大可能值时,这显然会崩溃。应如何实施以实现 HDR 感知?

extern “C” float4 ColorInverter(coreimage::sample_t s,coreimage::destination dest) {  
    return float4(1.0 - s.r,1.0 - s.g,1.0 - s.b,1.0);
}

解决方法

在您的内核中,颜色通常被标准化为 [0.0 ... 1.0]基于底层颜色空间。因此,即使值存储在纹理中的 10 位中间值中,您的着色器也会将它们作为标准化浮点数获取。

我强调了上面的颜色空间,因为在将颜色从源转换为那些标准化值时会用到它。当您使用默认的 sRGB 色彩空间时,来自 HDR 源的宽色域不适合 sRGB [0.0 ... 1.0] 光谱。这就是为什么您可能会在内核中获得该范围之外的值。这在大多数情况下实际上很有用,因为大多数为 sRGB 设计的过滤器操作仍然可以工作。然而,上面的颜色反转示例不是。

我知道你在这里有两个选择:

您可以将您正在使用的 workingColorSpaceCIContext 更改为输入的 HDR 色彩空间:

let ciContext = CIContext(options: [.workingColorSpace: CGColorSpace(name: CGColorSpace.itur_2020)!])

然后,内核中的所有颜色值都应限制为 [0.0 ... 1.0],其中 0.0 是最暗的 HDR 颜色值,1.0 是最亮的。然后您可以安全地使用 1.0 - x 执行反演。但是,请记住,其他一些过滤器将不会产生正确的结果,因为它们假设输入为(线性)sRGB——Core Image 的默认值。

第二个选项是将输入转换(“颜色匹配”)到正确的色彩空间之前将其传递到内核并再次返回到工作空间之前返回:

let colorSpace = CGColorSpace(name: CGColorSpace.itur_2020)!
let colorMatchedInput = inputImage.matchedFromWorkingSpace(to: colorSpace)
let kernelOutput = myKernel.apply(...,[colorMatchedInput,...])
return kernelOutput.matchedToWorkingSpace(from: colorSpace)