Display HDR video in EDR with AVFoundation and Metal
Graphics & Games 进阶 20m

用 AVFoundation 和 Metal 在 EDR 中展示 HDR 视频

Display HDR video in EDR with AVFoundation and Metal

2022年6月6日

在 Apple 官方观看视频

一句话判断

从 AVKit 一行代码播放 HDR 到 Metal 管线实时处理解码帧,这场 Session 是 EDR 视频渲染的全栈指南——尤其适合需要实时调色、色度键或自定义视频处理的应用。

这场 Session 讲了什么

Apple 显示与色彩技术团队的 Ken Greenebaum 深入讲解了如何在 Apple 平台上利用 EDR(Extended Dynamic Range)播放和处理 HDR 视频。Session 从高层框架到低层管线逐层展开,覆盖了 AVKit/AVFoundation 的简单播放、AVPlayerItemVideoOutput 逐帧输出、Core Image 滤镜实时处理、以及 CVMetalTextureCache + Metal 渲染的完整管线。

核心信息是:Apple 平台的视频框架形成了一个清晰的层级体系,从 AVKit(最简单)到 Core Media(最灵活),选择越高层框架越好,但如果需要逐帧处理,可以优雅地接入低层接口。

值得深挖的点

视频框架的层级关系。从上到下依次是 AVKit、AVFoundation、Core Video、Video Toolbox、Core Media。高层框架自动处理 HDR 到 EDR 的映射,低层框架提供逐帧访问和自定义处理能力。建议始终使用能满足需求的最高层框架。

三种 HDR 播放方式。AVPlayer + AVPlayerViewController(最简单,AVKit 管理一切)、AVPlayer + AVPlayerLayer(自定义视图中播放)、以及 AVPlayerItemVideoOutput + Core Image/Metal(逐帧处理后再渲染)。三种方式的复杂度递增,灵活度也递增。

逐帧处理管线的核心组件。AVPlayerItemVideoOutput 输出解码后的 CVPixelBuffer,通过 CADisplayLink 同步帧率,然后可以选择两条路径:送给 Core Image 的 CIFilter 做色彩处理,或通过 CVMetalTextureCache 转为 Metal 纹理在 shader 中处理。最终结果渲染到 EDR 显示。

EDR 的本质。EDR 让 HDR 内容在支持的显示器上以更高的亮度范围呈现,超出 SDR 的标准亮度。视频框架自动处理色调映射,开发者主要关注的是不要在处理管线中丢失 HDR 信息。

代码片段

// 方式一:AVKit 最简播放 HDR
let player = AVPlayer(url: mediaURL)
let controller = AVPlayerViewController()
controller.player = player
present(controller, animated: true) {
    player.play()
}

// 方式二:AVPlayerLayer 在自定义视图中播放
let player = AVPlayer(url: mediaURL)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = view.bounds
view.layer.addSublayer(playerLayer)
player.play()

// 方式三:逐帧处理管线核心
// 设置 AVPlayerItemVideoOutput 输出
let output = AVPlayerItemVideoOutput()
playerItem.add(output)

// 用 CADisplayLink 同步帧
let displayLink = CADisplayLink(target: self, selector: #selector(frameDidFire))
displayLink.add(to: .main, forMode: .common)

// 在回调中获取 CVPixelBuffer
@objc func frameDidFire() {
    let itemTime = playerItem.currentTime()
    guard let pixelBuffer = output.copyPixelBuffer(
        forItemTime: itemTime, itemTimeForDisplay: nil
    ) else { return }
    // 送给 Core Image 或 Metal 处理
    processFrame(pixelBuffer)
}

最佳实践

  • 简单播放场景优先使用 AVKit + AVPlayerViewController,它会自动处理 EDR 渲染
  • 需要自定义视图时用 AVPlayer + AVPlayerLayer,同样自动支持 EDR
  • 逐帧处理时确保整条管线保持 HDR/EDR 色彩空间,避免中途降级到 SDR
  • 使用 CADisplayLink 而非定时器来同步视频帧,确保与显示刷新率一致
  • Core Image 处理时注意色彩管理,确保 CIFilter 链正确处理 HDR 色彩空间
  • Metal shader 中使用合适的像素格式来接收 HDR 纹理数据

还有什么值得关注

  • AVQueuePlayer 可以管理连续的 HDR 视频队列播放
  • Video Toolbox 的 VTDecompressionSession 提供最低层的硬件解码器访问,适合高级场景
  • EDR API 在 iOS 上是今年新增的,之前仅限 macOS
  • 相关 Session “Explore EDR on iOS” 和 “Display EDR content with Core Image, Metal, and SwiftUI” 提供了更多背景知识
WWDC 2022