• 综述

苹果用 EDR 这个词是为了跟 HDR 区分开,因为 HDR 在不同的场景可能对应着不同的理解:

  1. HDR 显示:更生动的显示亮色和暗色
  2. HDR 格式:HDR10、Dolby Vision
  3. HDR 转换函数:PQ、HLG
  4. 色调映射(Tone Mapping):HDR → SDR

而 EDR(Extended Dynamic Range)是苹果推出的一套渲染管线技术,以支持在不同的屏幕上同时正确显示 SDR 和 HDR 内容。当显示 HDR 的内容时,EDR 并不会直接将 HDR 区域变得更亮,而是识别到 HDR 内容后提高整体屏幕亮度的同时,降低非 HDR 区域的白点值,使得其看起来没有那么亮。

  • EDR 的技术方案

SDR 的像素浮点数表示范围为 [0.0, 1.0],其中 0.0 表示黑色,1.0 表示白色。在 EDR 的像素浮点数表示中,SDR 的部分映射到 [0.0, 1.0],而大于 1.0 的部分就是比 SDR 更亮的 HDR 部分。

不像其他的 HDR 格式那样,EDR 不会做 Tone Mapping 将像素值都映射到 [0.0, 1.0] 的范围。这就意味着在渲染时,它有一套新的机制。当渲染时,像素浮点值范围为 [0.0, 1.0] 的 SDR 内容是始终会正常渲染的。(1.0, EDR headroom] 范围的 HDR 内容也是可以渲染的。但是,超过了 EDR headroom 的部分就会被丢掉。

EDR headroom 的存在支持了亮度更高的 HDR 内容,但是它具体是多少呢?其实,EDR headroom 是动态的,它的值受到多种因素的影响,比如:设备的显示技术、当前的显示亮度等等。

我们通常可以使用下面这个公式粗略估计 EDR headroom:

Headroom ≈ Display Peak / SDR

Pro Display XDR显示器可手动/自动调节的最大亮度等级是500nits(用于光线好的环境),所以把它作为1.0EDR预设值,这个范围就是SDR的范围,EDR值=1600nits/500nits=3.2;如果昏暗环境,手动/自动把显示器亮度调到4nits, EDR值就是1600nits/4nits=400。

  • 代码讲解

1. 以首选的EDR框架CAMetalLayer为示范。首先看以下4个步骤:选择使用EDR-》设置扩展范围色域-》将metaLayer的像素格式调整为浮点格式,如RGBA16Float-》实际生成EDR像素

前三个步骤代码示例如下:

有关第四个步骤,我们用ImageIO导入HDR静态图像内容,并将其渲染成EDR纹理,这个过程可以概括为: 先通过HDR图片建立CGImage-》绘制浮点bitmap-》创建浮点纹理-》将EDR位图导入到texture中-》将texture渲染成EDR可用的metal管线

1)读取HDR原图片,保存成CGImageRef格式。

CGImageRef ,这个结构用来创建像素位图,可以通过操作存储的像素位来编辑图片。其参数解释如下:

sizt_t是定义的一个可移植性的单位,在64位机器中为8字节,32位位4字节。
width:图片宽度像素
height:图片高度像素
bitsPerComponent:每个颜色的比特数,例如在rgba-32模式下为8
bitsPerPixel:每个像素的总比特数
bytesPerRow:每一行占用的字节数,注意这里的单位是字节
space:颜色空间模式,例如const CFStringRef kCGColorSpaceGenericRGB 这个函数可以返回一个颜色空间对象。
bitmapInfo:位图像素布局,这是个枚举
provider:数据源提供者
decode[]:解码渲染数组
shouldInterpolate:是否抗锯齿
intent:图片相关参数

2)绘制浮点位图

先读取像素位图的宽度、高度,再根据位图组成信息和色彩空间(之前设置过的Display-P3),调用CGBitmapContextCreate创建绘图上下文(相当于一个画布),然后调用CGContextDrawImage方法在当前上下文画图。

CGContextRef (Quartz 2D绘图的核心API是CGContextRef,该API专门用于绘制各种图形。)

CGContextRef CGBitmapContextCreate (
void *data,
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bytesPerRow,
CGColorSpaceRef colorspace,
CGBitmapInfo bitmapInfo
);
/**
参数:
data                    指向要渲染的绘制内存的地址。这个内存块的大小至少是(bytesPerRow*height)个字节。使用时可填NULL或unsigned char类型的指针。
width                   bitmap的宽度,单位为像素
height                  bitmap的高度,单位为像素
bitsPerComponent        内存中像素的每个组件的位数.例如,对于32位像素格式和RGB 颜色空间,你应该将这个值设为8。
bytesPerRow             bitmap的每一行在内存所占的比特数,一个像素一个byte。
colorspace              bitmap上下文使用的颜色空间。
bitmapInfo              指定bitmap是否包含alpha通道,像素中alpha通道的相对位置,像素组件是整形还是浮点型等信息的字符串。
*/
  • CGBitmapInfo讲解

CGBitmapInfo由两部分取或运算组成,一部分是指定 cpu使用的大小端模式,另一部分指定的是颜色空间中每个 bule green red alpha 的排列顺序。

typedef CF_ENUM(uint32_t, CGImageByteOrderInfo) {kCGImageByteOrderMask     = 0x7000,kCGImageByteOrderDefault  = (0 << 12),kCGImageByteOrder16Little = (1 << 12),kCGImageByteOrder32Little = (2 << 12),kCGImageByteOrder16Big    = (3 << 12),kCGImageByteOrder32Big    = (4 << 12)
} CG_AVAILABLE_STARTING(10.0, 2.0);typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {kCGImageAlphaNone,               /* For example, RGB. */kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */kCGImageAlphaOnly                /* No color data, alpha data only */
};typedef CF_OPTIONS(uint32_t, CGBitmapInfo) {kCGBitmapAlphaInfoMask = 0x1F,kCGBitmapFloatInfoMask = 0xF00, kCGBitmapFloatComponents = (1 << 8), // 浮点型表示kCGBitmapByteOrderMask     = kCGImageByteOrderMask,kCGBitmapByteOrderDefault  = kCGImageByteOrderDefault,  // 默认kCGBitmapByteOrder16Little = kCGImageByteOrder16Little, // 16 位小端kCGBitmapByteOrder32Little = kCGImageByteOrder32Little, // 32 位小端kCGBitmapByteOrder16Big    = kCGImageByteOrder16Big, // 16 位大端kCGBitmapByteOrder32Big    = kCGImageByteOrder32Big // 32 位大端
} CG_AVAILABLE_STARTING(10.0, 2.0);
// Big、Little 大端和小端分别
// 大端表示低字节放在高地址,高字节放在低地址
// 小端表示高字节放在高地址,低字节放在低地址

颜色空间的格式 RGB肯定要连续排序,唯一可能的变化是A的存放位置,A存放位置有两种可能:

情况一:A放在RGB之后RGBA 对应iOS的CGImageAlphaInfo为AlphaLast.

(对于32位图像,4个字节表示一个像素,每8位表示一个颜色。)

情况二:A放在RGB前面ARGB 对应iOS的CGImageAlphaInfo为AlphaFirst

再联系上大小端,那么

对于情况一:A放在RGB之后RGBA

对于大端对齐的cpu其像素存储格式是 0xRGBA

对于小端对齐的cpu其像素存储格式是 0xABGR

对于情况二:A放在RGB前面ARGB

对于大端对齐的cpu其像素存储格式是 0xARGB

对于小端对齐的cpu其像素存储格式是 0xBGRA

另外:Alpha通道的作用

IOS是小端序,所以kCGBitmapByteOrder16Host就是 kCGBitmapByteOrder16Little。

3)创建RGBA16Float类型的纹理对象(MTLTexture)

通过newTextureWithDescriptor方法使用一块新的用于存放texture image data的内存来创建 MTLTexture纹理对象,该api中通过 MTLTextureDescriptor 来描述texture的属性

创建 MTLTexture的时候 MTLTextureDescriptor 被用于定义属性,包括图像尺寸(宽、高、深度)、pixel format、arrangement(array、cubemap)以及mipmap的数量。MTLTextureDescriptor 值在创建 MTLTexture 的时候有用,当创建完毕后, 改变 MTLTextureDescriptor 的属性将对已经创建的 texture 没有任何影响。也就是说,当纹理对象创建完成后,它的大多数属性,比如大小,新类型,像素格式都是不能改变的,但是纹理的像素数据是可以改变。

  • 创建一个包含 texture 属性的 MTLTextureDescriptor :

    • textureType 表示 texture的dimensionality 和 arrangement(array or cube)
    • width、height、depth用于表明 texture base level mipmap中每一个dimension的pixel size
    • pixelFormat表明 texture中的像素存储方式
    • arrayLength 表明 MTLTextureType1DArray or MTLTextureType2DArray 类型 texture的数组元素的数量
    • mipmapLevelCount 表明texture mipmap的数量
    • sampleCount 表明每个pixel的对应的sample数量
    • resourceOptions 表明内存分配的方式
  • 通过 MTLDevice 的 newTextureWithDescriptor: 方法根据 MTLTextureDescriptor 创建一个texture。创建完毕后,如果要复制内存的像素数据到纹理中,调用 replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage: 方法来加载texture image data

4)将EDR的像素数据加到纹理中。

利用CGBitmapContextGetData获取EDR图像数据,并用replaceRegion设置EDR纹理。

5)使用metal管线渲染EDR

【相关链接】

bilibili讲解的文字版描述: WWDC 2022 音视频相关 Session 概览(EDR 相关)丨音视频工程示例 - 掘金

bilibili讲解:【中文字幕】Apple:EDR是如何工作的?HDR渲染之道 | Explore HDR rendering with EDR_哔哩哔哩_bilibili

w3讲解EDR:http://3ms.huawei.com/hi/group/1004055/wiki_6221842.html

Apple’s “EDR” Brings High Dynamic Range to Non-HDR Displays — Prolost

微信公众号讲解: https://mp.weixin.qq.com/s/EgJkGimBs5AF1n3O4KqYog

【HDR学习】苹果EDR技术洞察(二)相关推荐

  1. 从零开始学习音视频编程技术(二) 音频格式讲解

    从零开始学习音视频编程技术(二) 音频格式讲解 原文地址:http://blog.yundiantech.com/?log=blog&id=5 1. 音频简介 前面我们说过视频有一个每秒钟采集 ...

  2. 大型机学习之具体技术之-JCL练习(二)

             <大型机学习之具体技术之-JCL练习二> 由于种种原因,在前天结束了培训的昨天又安排了一次补课,内容是PL/I,可是基础本来不好,多做一天练习用处其实不大.当时需要的一个 ...

  3. 深度学习模型压缩与加速技术(二):参数量化

    目录 总结 参数量化 参数量化定义 参数量化特点 1.二值化 二值化权重 二值化权重与激活函数 2.三值化 3.聚类量化 4.混合位宽 手工固定 自主确定 训练技巧 参考文献 深度学习模型的压缩和加速 ...

  4. 非计算机专业买几寸电脑好,学习计算机网路技术专业,是不是需要买电脑啊

    学习计算机网路技术专业,是不是需要买电脑啊以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 学习计算机网路技术专业,是不是 ...

  5. 要凉?46%开发者表示短期内不考虑学习区块链技术,拿什么拯救你我的区块链人才荒...

    程序员应该选择什么技术领域才能获得最高的回报? 本文详细解读了 2018 年最热门的五大领域,对行业现状.薪资概况及具体的技能要求给出了深入的分析,希望给担心"入错行"的你提供些指 ...

  6. 个人学习笔记 ——【技术美术百人计划】图形 2.1 色彩空间介绍

    个人学习笔记 --[技术美术百人计划]图形 2.1 色彩空间介绍 图形 2.1 色彩空间介绍 个人学习笔记 --[技术美术百人计划]图形 2.1 色彩空间介绍 图形 2.1 色彩空间介绍 一.色彩发送 ...

  7. 大数据怎么学习:大数据学习的关键技术知识体系、学习路径和误区

    由于大数据技术涉及内容太庞杂,大数据应用领域广泛,而且各领域和方向采用的关键技术差异性也会较大,难以三言两语说清楚,本文从数据科学和大数据关键技术体系角度,来说说大数据的核心技术什么,到底要怎么学习它 ...

  8. 2021-春季学习-智能车技术创新与实践-Lesson2

    课程内容 ▌01 课程背景 1.课程简介 2.[课程预告] 3.Linux以及ROS自学简介 4. ROS相关资料 (1)ROS-WiKi ▌02 课程设计 1.机器人操作系统ROS简介:SC21 S ...

  9. 2021-春季学习-智能车技术创新与实践-Lesson 1

    ▌01 课程背景 1.课程简介: 具体内容参见: 智能车技术创新与实践(01510422-90)课程简介 上课时间地点: 星期六第1节(前八周),六教6A211: 星期六第2节(前八周),六教6A21 ...

最新文章

  1. Single Image Dehazing via Conditional Generative Adversarial Network(CVPR2018-图像去雾)
  2. ​北京大学吴华君组诚聘医学/生信助理研究员和博士后
  3. web移动端_移动端的轮播
  4. 杭电oj1176,2084java实现
  5. aspx隐藏前台控件div_c# – 代码隐藏页面无法“查看”aspx页面中声明的任何项目/控件...
  6. android模拟器上传,电脑文件怎么传到夜神android模拟器 文件上传夜神模拟器
  7. 自定义ClassLoader
  8. 移动平台深度神经网络实战
  9. python做线性回归统计推断提取参数_概率分析方法与推断统计(来自我写的python书)...
  10. U盘FAT32转换NTFS格式
  11. [地图SkyLine二次开发]框架(2)
  12. UVA 10341 Solve It
  13. webstorm破解方法
  14. mdx 医学词典_Mdict的mdx词典文件如何解析,有相关的开源代码可以参考吗?
  15. 复习Python爬取必应的壁纸
  16. 【Qt】边学边写之Qt教程(零基础)
  17. 2018c与语言程序设计形成性考核册,最新版中央广播电视大学C语言程序设计形成性考核册及答案.docx...
  18. amd显卡测试大风车软件md,知之实验室 篇三:大家好才是真的好!免费显卡升级工具AMD FSR技术研究测试...
  19. 苹果macOS Big Sur 11.2 RC 修复蓝牙和显示连接问题
  20. SQL:请用sql实现学生表中出现的学生姓名次数最多的学生姓名?

热门文章

  1. systemd wsl 测试笔记
  2. ionic开发记账软件《易跟金》
  3. 加密和杂凑(Hashing)有什么不一样?
  4. python菜鸟教程mac安装_Python菜鸟教程 | 多平台安装
  5. iOS 边学边记 升级ios14 Xcode真机调试启动非常慢的问题解决
  6. U大师U盘启动盘克隆制作工具
  7. 想要报考华为技术认证,你一定要了解这些
  8. 跨境电商的9大运营模式
  9. esc pos命令 java使用_18、ESC/POS指令集在android设备上使用实例(通过socket)
  10. 不忘初心,能偷懒就偷懒:C#操作Word文件