大多数浏览器和
Developer App 均支持流媒体播放。
-
探索 iOS 上的 EDR
EDR 是 Apple 的高动态范围表示和渲染管道。探索如何借助 App 中的 EDR 渲染 HDR 内容,并在 iPhone 和 iPad 上充分挖掘 HDR 显示屏的动态范围功能。我们将介绍如何利用 iOS 上的原生 EDR API,提供最佳实践以帮助您确定使用 HDR 的正确时机,以及分享有关色调映射和 HDR 内容渲染的技巧。我们还将讨论参考模式,重点说明它会如何提供参考响应以启用颜色关键型工作流程,如调色、编辑和内容审核等。
资源
相关视频
WWDC23
WWDC22
Tech Talks
-
下载
♪ 柔和乐器演奏的嘻哈音乐 ♪ ♪ 嗨 我是 Denis 我是 Apple 显示和色彩技术 团队的一员 今天我将探讨一些 令人兴奋的 EDR 更新 以及它们对 iOS 开发者的影响 您可能已经通过去年的展示 对 EDR 有所了解 但还是简单地回顾一下 EDR 全称扩展动态范围 是 Apple 的 HDR 技术 EDR 既是一种渲染技术 也是一种像素表示法 EDR 的像素表示法尤为重要 因为它统一代表了标准 和高动态范围两种内容 在曝光良好的内容中 画面主体 在这个例子中是露营的人 应当处于图像的标准动态范围内 而反射和自发光高光 比如篝火 会处于更高的范围内 在标准范围表示法中 这些元素最终会被裁剪 但在 EDR 中 它们仍然可以表示 虽然还有其他像素表示法 用于表示固定范围的亮度值 EDR 的表示法是真正动态的 可以描述任意值 此外 通过利用一切未使用的背光 EDR 允许所有显示器 渲染高动态范围内容 不管显示器的峰值水平如何 随着 HDR 内容 变得更加普遍和易于获得 macOS 上采用 EDR 的 App 的选择也变得多样化 《博德之门 3》 《神界:原罪 2》 和《古墓丽影》 这些在 macOS 上 使用 EDR 的游戏已经发售 通过采用 EDR 游戏能够渲染 更明亮、更饱和的色彩 以及生成更逼真的光照效果 反射效果 以及更丰富多彩的内容 明亮元素会 受到 SDR 白色峰值的限制 但通过 EDR 它们 可以重新获得鲜艳度和深度 正如创作者所希望的那样 EDR 集成 在整个 Apple 生态系统中 Safari 浏览器和 QuickTime Player 均支持使用 因此 视频点播 App 和服务 例如 Apple TV 和 Netflix 都具备了为 用户提供不断 增加的 HDR10、杜比视界、 和 ProRes 内容的能力 采用 EDR 的专业 App 让用户可以 创建惊艳的 HDR 内容 通过提供各类专业工作流程 实现 HDR 静帧及视频的准确剪辑 调色、制作和查看 在大家都为能在 macOS 上 采用 EDR 而兴奋不已时 我们很高兴为 EDR 带来几项更新 首先 我们很高兴地 告知大家 EDR API 现在将可以在 iOS 和 iPadOS 上使用 此外 作为 Apple 对支持 专业用户承诺的一环 今年我们将推出 12.9 英寸 配备 Liquid Retina XDR 显示屏的 iPad Pro 上 两项新的专业色彩功能 参考模式 和“随航”中的 EDR 渲染 参考模式是一种新的显示模式 通过向各类常见 视频格式提供参考响应 实现对色彩要求很高的工作流程 例如调色、剪辑和内容检查 类似 macOS 上的参考预设 为此 参考模式将 SDR 峰值亮度固定为 100 尼特 将 HDR 的峰值亮度 固定为 1000 尼特 从而留出 10 倍的 EDR 净空 参考模式还提供一种 一对一的传输介质做显示映射 并禁用所有针对环境的动态显示调整 例如原彩显示 自动亮度和夜间模式 无需用户 手动对白点进行精细校准 这样一来 显示器就会生成 与各自规格所描述的 完全一致的色彩 这张表格中列出了 参考模式支持的格式 需要注意的是 与 macOS 上的参考预设不同 参考模式通过一个切换按键 来支持五种最常见的 HDR 和 SDR 视频格式 为各媒体类型提供一致的参考响应 如果您需要的内容格式并未 在表格中列出 也请不必担心 任何不受支持的格式 都将进行颜色管理 和在默认显示模式下一样 举例来说 让我们看看 参考模式下的 LumaFusion 通过在 iOS 上启用参考模式 LumaFusion 将成为 视频后期制作中的 更强大的工具 显示 HDR 视频时 P3 色域内 高达 1000 尼特峰值的颜色 可以准确进行渲染 因此用户可以确信 他们的视频的显示始终 正确且一致 将参考模式与 和 LumaFusion 全新的“视频域”功能相结合 现在就可以在 iPad Pro 上 执行对色彩要求很高的工作流程 如果我们禁用参考模式 EDR 将会发生动态变更 在 iOS 调整视频亮度时 可以在这里看到 用户可以将他们的 LumaFusion 项目导出为 XML 然后导入 其他常见的 Mac 后期制作 App 让内容创作者团队在两个平台上 轻松地进行协作 LumaFusion 对参考模式的采用 以及它为专业内容创作者带来的 价值和灵活性都很让人激动 但参考模式并不是唯一的新功能 早在 2019 年 我们就推出了“随航” 这种技术让 Mac 用户可以将 他们的 iPad 用作辅助显示器 现在 随着参考模式的引入 我们开始为“随航” 添加对 EDR 渲染的支持 这大大扩展了“随航”的功能 在启用参考模式 支持调色参考的 SDR 和 HDR 内容时 专业内容创作者 将可以把 iPad Pro 用作搭载 Apple 芯片的 Mac 的辅助参考显示器 当然 通过“随航”渲染的内容 也将在参考模式中 为所有相同的视频格式 提供与原生 iOS 一致的参考响应 比如说 让我们来看看这个在 Mac 上 以 HDR 视频预设 渲染的 HDR10 测试图案 并将其与 iPad Pro 上 “随航”的再现进行比较 在此配置中 两个设备都是 具有 P3 色域和 D65 白点的参考显示 因为这恰好符合两个显示器的规格 从 P3 主色条 和副色条可以看出 Mac 和 iPad 都 产生了符合我们预期的响应 此外 两者的配置 都支持 1000 尼特的峰值亮度 从梯度渐变中可以看出 这些值将得到如实的渲染 而超过 1000 尼特的值 则会被剪除 “随航”上的 EDR 渲染为我们的 专业用户带来的 前景和新机遇让人感到兴奋 我们也期待看到更多的开发者 通过在自己的 App 中采用 EDR 来充分使用这些功能 说到这里 就来看看如何将 EDR 渲染 集成到您自己的 iOS 和 iPadOS App 中 我们将首先来看看 EDR 的 像素表示法和渲染管线 可能产生的影响 传统上 SDR 的浮点表示法 使用的是 0 到 1 范围内的值 0 代表黑色 1 代表 SDR 白色 使用 EDR 时 SDR 内容 仍然由 0 到 1 的范围来表示 而大于 1 的值则用于 表示比 SDR 亮度更高的内容 请注意 EDR 的表述 是在线性空间中进行的 这意味着如果 EDR 为 2.0 并不会明显是 1.0 亮度的两倍 与其他 HDR 格式不同 EDR 不会将值 色调映射到 0 到 1 的范围中 这会对渲染产生一些影响 考虑到这一点 EDR 会确保始终渲染 SDR 内容 也就是从 0 到 1 的值 并且 它会对任何大于 1 且小于最高 EDR 净空的值 进行无色调映射的正确渲染 但是 亮度超过 此范围的值都将被剪除 乍看之下 这种行为可能显得不够理想 但这意味着 以 HDR 创作的所有内容 将尽可能忠实于原本意图进行呈现 任何过亮的高光 也都会像在通常的表示法中那样 进行移除 很显然 有了更高的净空 您的内容就可以变得更明亮、更动态 但我们的净空有多大呢? 其实 需要注意的是 瞬时 EDR 净空是一个动态值 由许多因素决定 包括但不仅限于 设备自身的显示技术 以及当前的显示亮度 非常简化地来看 您当前的 EDR 净空大致等于 显示器的最大亮度 除以当前 SDR 亮度 所以之前 我提到参考模式可以提供 10 倍 EDR 净空 那是因为我们将 EDR 1.0 也就是 SDR 亮度 设置为 100 尼特 同时将 HDR 峰值亮度 设置为 1000 尼特 因此 用 1000 尼特 除以 100 尼特 就得到 10 倍的 EDR 恒定净空 这张表格列出了几种设备示例 和他们的最大潜在净空 请注意 这只是潜在的净空 真正的净空将取决于 其他各种因素 包括当前的显示亮度 在演讲的后段 我们将详细介绍净空 并举例说明如何查询和使用净空 来为渲染做出合理的决策 不过 现在您应该 已经对 EDR 的功能 以及何时需要使用它 有了很好的了解 现在 让我们来实际渲染 一些 EDR 内容 在本节中 我们将介绍 如何将您的 HDR 内容 读取为可渲染的格式 我们将要详细介绍的案例 是一个 Image I/O 工作流程 但如果您想了解其他框架 请查看今年其他的 EDR 相关演讲 在处理静态媒体时 第一步是找到要加载的图像 这个图像通常会在 双平面 YUV 空间中进行编码 一开始加载它时 图像和它的缓冲都将使用其原始格式 很遗憾 如果用了这种格式 可能会很难以任何有意义的方式 对图像进行解译和处理 所以在 CGBitmapContext 的帮助下 我们将对图像解码和转换为 更可用的格式 此时 我们可以 从上下文支持的像素数据 创建一个 MTLTexture 然后用 Metal 引擎进行渲染 更具体地来说 为了实现这一目标 我们需要经过四个步骤 首先为我们的 HDR 静帧创建 CGImage 将该 CGImage 绘制到位图上下文中 创建 Metal 纹理 最后再将 位图数据加载到新创建的纹理中 在第一步中 我们将读取图像 并进行一些设置 首先 我们将图像从 URL 读取到 CGImageSource 中 然后从这个源创建 CGImage 在这种情况下 我们通过传递 nil 选项字典 来创建图像 但是 如果您想要通过浮点缓冲 使用某些 HDR 格式 就应该考虑设置新的选项 kCGImageSourceShouldAllowFloat 现在 我们将 实例化 CGBitmapInfo 在这里 我们创建的是一个 16 位 带预乘 alpha 的浮点上下文 请记住这一点 因为我们需要 Metal 纹理 也使用相同的格式 接下来 我们将使用 刚刚创建的位图信息 以及 CGImage 的宽度和高度 构建 CGBitmapContext 请注意 您需要将上下文的色彩空间 与您将要 渲染到的 CAMetalLayer 的 色彩空间相匹配 否则就需要自己进行 相应的色彩管理 最后 我们将把 CGImage 绘制到位图上下文中 此时 我们可以继续从上下文 创建 Metal 纹理 要创建 Metal 纹理 我们需要首先 实例化 MTLTextureDescriptor 请回想一下 我们之前选择为位图上下文 使用半浮点格式 但在渲染 EDR 时 您也可以 将 2D 纹理压缩为 10 位蓝、绿和红 及 2 位 alpha 的 32 位像素格式 稍后我们将更详细地介绍 但是现在 知道纹理像素格式 应该与内容像素格式 相匹配就已经足够了 在我们的案例中 就是半浮点 现在 我们将对纹理进行实例化 使用 Metal 层级设备 和新创建的纹理描述符 最后 我们将从位图上下文中抓取数据 并将其复制到纹理中 这样 我们就得到了 一个包含 EDR 值的 Metal 纹理 可以发送到 Metal 管线中进行渲染 本节介绍了一个从 URL 开始 获取 HDR 静止图像 并继续完成 Metal 纹理的工作流程案例 接下来 我们将介绍 在 iOS 和 iPadOS 上 渲染这样的纹理所需的 最低限度代码更改 将 EDR 纳入 新 iOS 和 iPadOS API 的流程 与 macOS 上的完全一致 因此 如果您 macOS 版本的 App 已经有了 EDR 支持 您就无需进行任何更改 要选择使用 EDR 您需要确保使用的 是 CAMetalLayer 在该层上设置了恰当的标识和标签 并且您的明亮内容 是 EDR 支持的格式 首先选用 CAMetalLayer 您将要通过它渲染你的内容 在该层上 您需要启用 wantsExtendedDynamicRangeContent 标识 然后 在同一个层上 您需要设置 受支持的像素格式 和 CGColorSpace 组合 取决于您拥有的内容类型 以及获取它的方式 具体的像素格式 和色彩空间会有所不同 在我们的案例中 我们将图像加载进了 一个 16 位浮点缓冲 现在我们选择将它与 扩展的线性 Display P3 色彩空间进行匹配 iOS 支持在 16 位浮点缓冲与 与线性色彩空间的组合中 渲染 EDR 但如果您选择这样一种组合 请务必使用色彩空间的扩展变体 否则 您的内容将被剪切为 SDR iOS 也支持 10 位压缩 BGRA 像素缓冲 我们在前面简单提到过 此类缓冲支持 使用 PQ 或 HLG 色彩空间 进行渲染 比如表格中所列的这些 在本节中 我们讲解了支持 EDR 渲染 所需要在渲染层进行的 最低限度代码更改 包括 wantExtendedDynamicRangeContent 标识 以及各种支持 EDR 的像素格式 和色彩空间 此时 如果您准备将我们在 前一节获取的 Metal 纹理 渲染到本节中的 CAMetalLayer 上 就是在使用 EDR 进行渲染 但还有一些我们可以掌握的诀窍 正如概述中提到的 EDR 的默认行为 是根据当前的 EDR 净空进行剪切 在有些情况下 您或许会认为 净空还没有高到 让渲染 EDR 内容显得合情合理 于是就选择了使用 SDR 还有些情况下 您可能想使用当前净空 在显示之前对 您的内容进行色调映射 无论哪种情况 iOS 现在都有了新 API 用于支持查询净空 在本节中 我们将介绍这些调用 以及这些调用 与 macOS 的区别 方便您更好地做出此类决定 在 macOS 上 您可以 在 NSScreen 上找到净空查询 在 NSScreen 上 我们配备了以下查询 显示器可以支持的最大 EDR 净空 当前参考预设的最大 EDR 净空 和当前的 EDR 净空 此外 macOS 还为每次 EDR 净空变化 提供通知提醒 在 iOS 上 净空查询 可以在 UIScreen 上找到 和 NSScreen 不同 在这里我们可以查询的是 显示器支持的最大 EDR 净空 和当前的 EDR 净空 此外 UIScreen 提供 参考显示模式状态 用来表示 是否支持和启用了参考模式 请注意 UIScreen 不会为 EDR 净空变化 提供通知 但在参考模式的 状态发生变化时会发送通知 您可能也注意到最大参考净空查询 并不在列表当中 不需要使用专门的查询 您可以在参考模式状态显示 参考模式已启用的情况下 通过查询潜在的最大净空 来确定它的值 让我们来看一些示例代码 更好地了解如何查询净空 在 UIScreen 上 您可以 查询 potentialEDRHeadroom 来看到显示的 最大可能净空 如果您认为这个值太低 就可以改为渲染 SDR 路径 以节约一些处理能力 不过 如果您决定使用 EDR 您可能会用一个渲染委托 或定期安排的绘制调用 在此调用中 我们可以 查询 currentEDRHeadroom 并用它来对内容进行色调映 这样它就不会 超过净空 也就不会被剪除 如果您想了解参考模式的状态 可以通过注册代码 在每次状态变动时收到通知 需要使用 UIScreen.referenceDisplay ModeStatusDidChangeNotification 以后 每当状态发生变化时 您都可以获知新的状态 和新的潜在 EDR 净空 并使用它们来为渲染做进一步决策 关于参考模式状态 您应该留意以下四种状态表述 StatusEnabled 表示 已启用参考模式 并且它正在按预期进行渲染 StatusLimited 表示 已启用参考模式 但由于某种原因我们暂时无法 实现参考响应 请注意 如果这种状态出现了 还将出现“缺少参考”的 UI 通知 告知用户参考响应 出现了问题 StatusNotEnabled 表示参考模式 受此设备支持 但尚未启用 最后 StatusNotSupported 表示此设备不支持参考模式 这些新 API 应当使开发人员对 当前显示的状态有了更深入的理解 并为他们提供了所需的工具 来就如何渲染 EDR 内容 做出明智的决定 在上一节中 我们介绍了如何查询各种净空参数 包括当前的 EDR 净空 您可以使用它来对内容 进行色调映射 避免遭到剪除 但是 如果您不想深入或实施 自己的色调映射算法该怎么办呢? 如果是处理视频内容 您可以使用 Apple 内置的色调映射 如果您想对内容启用 Apple 的色调映射 可以通过 CAEDR 元数据接口 其中包括 适用于 HDR10 和 HLG 的 元数据构造函数 请注意 并非所有 平台都支持色调映射 但您可以使用一个查询来确认 您的平台是否支持 要确认您的平台是否支持色调映射 可以查询 CAEDRMetadata.isAvailable 如果色调映射可用的话 您接下来 需要实例化 CAEDRMetadata 稍后我们将讨论具体的构造函数 但我们先跳过这一步 获得 EDR 元数据后 您可以将其应用于正在渲染的层 这将使您的层开始由 系统色调映射器 根据提供的元数据进行处理 正如之前所提到的 可用的 EDR 元数据 构造函数很多 分别针对不同的 HDR 视频格式 这是 HLG 元数据的构造函数 它不需要参数 接下来 是两个可用的 HDR10 构造函数之一 它需要三个参数 母版显示的最小亮度 以尼特为单位 以尼特为单位的母版显示最大亮度 和光学输出刻度 它用来表示 映射到以尼特为单位的 亮度值的 EDR 1.0 内容 通常 我们将其设置为 100 最后 还有一个 HDR10 构造函数 它使用的参数为 MasterDisplayColourVolume SEI 信息 ContentLightLevelInformation SEI 信息 和 opticalOutputScale 像之前提到的那样 它通常设置为 100 尼特 在使用其中的某个构造函数 创建您的 CAEDRMetadata 对象之后 可以将其设置在 您 App 的 CAMetalLayer 上 这将使该层上所有渲染内容 由系统色调映射器处理 既避免了剪除的风险 又无需自己执行映射 使用哪个构造函数完全取决于 您内容的来源或创建方式 但通常情况下 如果 您的内容在 HLG 色彩空间中 您需要使用 HLG 构造函数 如果它在 PQ 色彩空间中 则需要使用 HDR10 构造函数 如果您的内容 已经附带了 SEI 信息 那么我们建议使用 第二种 HDR10 构造函数 以忠实遵循创作者的意图 不然的话 您将需要使用第一个构造函数 如果您使用的是线性色彩空间 那么选择构造函数完全取决于 内容是如何创建方式 因此 如果您打算将其 与 Apple 的色调映射一起使用 我强烈建议您 阅读我们的开发者文档中 关于 HDR10 和 HLG 元数据的部分 现在让我们来看看 Pixelmator 以及它对 EDR 的采用 因为有了 EDR 我们可以将图像 以更生动、更逼真的方式进行渲染 举例来说 如果我们 打开一张 RAW 照片 增加曝光和高光 最亮区域的细节无法使用显示器的 标准动态范围 即 SDR 进行渲染 现在 如果我们打开 EDR 所有超出 SDR 白色的部分 都变得可见了 请注意 EDR 内容相对于画布的 SDR 颜色而言显得多么鲜艳 关闭 EDR 会使 SDR 和 EDR 之间的视觉差异更加明显 到这里 今天的讲座就要结束了 在讲座中 我们讲解了一些 iOS 和 iPadOS 即将推出的 令人兴奋的功能 我们快速温习了 EDR 的概念 介绍了示例工作流程 关于如何 读取带图像 I/O 的 HDR 图像 并将其转换为 Metal 纹理 还查看了如何选择使用 EDR 在不裁剪到 SDR 的情况下渲染该纹理 我们还简略谈到了净空查询 API 以及它对合理的 EDR 渲染决策 产生的作用 还介绍了如何选择使用 Apple 系统为常见 HDR 格式 提供的色调映射功能 我希望您在本次讲座结束时 已经更好地了解 EDR 以及如何 在您的 iOS 和 iPadOS App 中使用它 如果您想进一步了解如何运用 HDR 或是其他 EDR 相关内容 我推荐您查看往届和 之后的几场讲座 说了这么多 感谢您参加今天的讲座 “在 iOS 上探索 EDR” 祝您拥有精彩的 WWDC 之旅! ♪
-
-
9:23 - Create CGImage and Draw
// Create CGImage from HDR Image let isr = CGImageSourceCreateWithURL(HDRImageURL, nil) let img = CGImageSourceCreateImageAtIndex(isr, 0, nil) // Draw into floating point bitmap context let width = img.width let height = img.height let info = CGBitmapInfo(rawValue: kCGBitmapByteOrder16Host |CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.floatComponents.rawValue) let ctx = CGContext(data: nil, width: width, height: height, bitsPerComponent: 16, bytesPerRow: 0, space: layer.colorspace, bitmapInfo: info.rawValue) ctx?.draw(in: img, image: CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height)))
-
10:30 - Create floating point texture and Load EDR bitmap
// Create floating point texture let desc = MTLTextureDescriptor() desc.pixelFormat = .rgba16Float desc.textureType = .type2D let texture = layer.device.makeTexture(descriptor: desc) // Load EDR bitmap into texture let data = ctx.data texture.replace(region: MTLRegionMake2D(0, 0, width, height), mipmapLevel: 0, withBytes: &data, bytesPerRow: ctx.bytesPerRow)
-
11:55 - CAMetalLayer properties
// Opt into using EDR var layer = CAMetalLayer() layer?.wantsExtendedDynamicRangeContent = true // Use supported pixel format and color spaces layer.pixelFormat = MTLPixelFormatRGBA16Float layer.colorspace = CGColorSpace(name: kCGColorSpaceExtendedLinearDisplayP3)
-
14:42 - UIScreen headroom
// Query potential headroom let screen = windowScene.screen let maxPotentialEDR = screen.potentialEDRHeadroom if (maxPotentialEDR < 1.5) { // SDR path } // Query current headroom func draw(_ rect: CGRect) { let maxEDR = screen.currentEDRHeadroom // Tone-map to maxEDR } // Register for Reference Mode notifications let notification = NotificationCenter.default notification.addObserver(self, selector: #selector(screenChangedEvent(_:)), name: UIScreen.referenceDisplayModeStatusDidChangeNotification, object: nil) // Query for latest status and headroom func screenChangedEvent(_ notification: Notification?) { let status = screen.referenceDisplayModeStatus let maxPotentialEDR = screen.potentialEDRHeadroom }
-
16:54 - CAEDRMetadata and CAMetalLayer
// Check if EDR metadata is available let isAvailable = CAEDRMetadata.isAvailable // Instantiate EDR metadata // ... // Apply EDR metadata to layer let layer: CAMetalLayer? = nil layer?.edrMetadata = metadata
-
17:22 - Instantiating CAEDRMetadata
// HLG let edrMetadata = CAEDRMetadata.hlg // HDR10 (Mastering Display luminance) let edrMetaData = CAEDRMetadata.hdr10(minLuminance: minLuminance, maxLuminance: maxContentMasteringDisplayBrightness, opticalOutputScale: outputScale) // HDR10 (Supplemental Enhancement Information) let edrMetaData = CAEDRMetadata.hdr10(displayInfo: displayData, contentInfo: contentInfo, opticalOutputScale: outputScale)
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。