WWDC Quick Look 💓 By SwiftGGTeam
Edit and play back HDR video with AVFoundation

Edit and play back HDR video with AVFoundation

观看原视频

Highlight

Apple 在 AVFoundation 的 AVVideoComposition 中加入 HDR 编辑支持:内建 compositor 和内建 Core Image filter 可以处理 HDR,自定义 compositor 需要声明 10-bit 像素格式、HDR source frames 和 Wide Color source frames。

核心内容

视频编辑 App 以前把主要精力放在剪切、拼接、变换和混合上。进入 HDR 之后,问题变得更细:像素可能超过 SDR 的 0 到 1 范围,常见分发格式会使用 10-bit,传输函数可能是 HLG 或 PQ。一个已有的转场、滤镜或自定义合成器,如果仍按 SDR 假设处理颜色,就可能把高亮压掉,或把滤镜结果算成负值。

这场 session 把风险收敛到一个核心对象:AVVideoCompositionAVComposition 主要描述时间线上的素材对齐,基本不关心 HDR;AVVideoComposition 负责几何变换、混合和滤镜处理,必须知道输入和输出的颜色特性。Apple 的更新让两条常见路径变得简单:使用内建 compositor,或用 AVMutableVideoComposition(asset:applyingCIFiltersWithHandler:) 调用内建 Core Image filter 时,框架会替你处理 HDR 帧。

真正需要开发者改代码的地方是自定义逻辑。自定义 Metal Core Image kernel 要接受扩展动态范围,不能假设最大亮度就是 1。自定义 compositor 还要告诉 AVFoundation:它支持 10-bit 或更高位深的 pixel buffer,愿意接收 HDR source frames,并且能处理 Wide Color。播放端再用 AVPlayer.eligibleForHDRPlayback 判断当前硬件和显示器是否适合 HDR 预览。

详细内容

1. 内建 compositor 的 HDR 路径(06:43

常见剪辑工作流会先创建 AVCompositionAVVideoComposition,再把它们交给 AVPlayerItem 预览,或交给 AVAssetExportSession 导出。session 明确说,HDR 的关键在 AVVideoComposition,因为它负责混合和变换。

let videoComposition = AVMutableVideoComposition()

videoComposition.instructions = [videoCompositionInstruction]
videoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
videoComposition.renderSize = assetSize

关键点:

  • instructions 描述每段时间线里如何混合或变换视频层;多条 instruction 不能重叠,也不能留下时间空洞。
  • frameDuration 决定合成输出帧率,示例用 1/30 秒。
  • renderSize 决定输出画面尺寸。
  • 这段代码没有设置 customVideoCompositorClass,AVFoundation 会使用内建 compositor;transcript 中说明,已有 App 在这种路径上输入 HDR video,通常可以得到按同一组 instruction 合成后的 HDR 输出。

2. 用 Core Image filter 创建 AVVideoComposition(09:55

第二条路径适合单视频层滤镜。AVMutableVideoComposition 会把第一条 enabled video track 的当前帧传给 handler,开发者拿到 request.sourceImage 后送进 CIFilter,最后调用 request.finish 返回结果。

let videoComposition =
    AVMutableVideoComposition(asset: asset,
    applyingCIFiltersWithHandler: {
        (request: AVAsynchronousCIImageFilteringRequest) -> Void in

        let ciFilter = CIFilter(name: "CIZoomBlur")

        ciFilter!.setValue(request.sourceImage, forKey: kCIInputImageKey)

        request.finish(with: ciFilter!.outputImage!, context: nil)
    })

关键点:

  • applyingCIFiltersWithHandler 省掉了手写 composition instruction 的工作,把焦点放到每帧滤镜处理上。
  • request.sourceImage 是当前输入帧,对应 transcript 中的 CIImage
  • CIZoomBlur 是 Core Image 内建 filter;session 说明 Core Image 的内建 filter 能处理 HDR source。
  • request.finish(with:context:) 把滤镜输出交回 AVFoundation,后续仍由 video composition 管线处理。

3. 自定义 Core Image kernel 要接受扩展动态范围(10:57

如果 handler 调用的是自定义 Metal Core Image kernel,代码就要理解 HDR 帧的像素范围。session 给了一个高亮检查 kernel:只要任一 RGB 通道超过 1,就把该像素涂成超亮红色。

#include <metal_stdlib>
#include <CoreImage/CoreImage.h>
using namespace metal;

extern "C" float4 HDRHighlight(coreimage::sample_t s, coreimage::destination dest) {
    if (s.r > 1.0 || s.g > 1.0 || s.b > 1.0)
        return float4(2.0, 0.0, 0.0, 1.0);
    else
        return s;
}

关键点:

  • CoreImage/CoreImage.h 引入 Metal Core Image kernel 需要的类型。
  • coreimage::sample_t s 是输入像素;HDR 内容里 s.rs.gs.b 可能大于 1。
  • float4(2.0, 0.0, 0.0, 1.0) 故意输出超过 SDR 白点的红色,用来标记 HDR 高亮区域。
  • session 随后用 color inverter 举反例:如果继续按 SDR 写 1.0 - s.r,HDR 像素大于 1 时结果会变成负值。

4. 自定义 compositor 必须声明 HDR 能力(13:58

自定义 compositor 的自由度最高,可以混合多个视频层,对每一层做几何变换和滤镜处理。代价是框架不会自动假定它能处理 HDR。开发者要同时处理真实合成逻辑和能力声明。

class SampleCustomCompositor: NSObject, AVVideoCompositing {
    var sourcePixelBufferAttributes: [String : Any]? =
        [kCVPixelBufferPixelFormatTypeKey as String:
            [kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange]]

    var requiredPixelBufferAttributesForRenderContext: [String : Any] =
        [kCVPixelBufferPixelFormatTypeKey as String:
            [kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange]]

    var supportsHDRSourceFrames = true
    var supportsWideColorSourceFrames = true

    func startRequest(_ request: AVAsynchronousVideoCompositionRequest) {
        ...
    }

    func renderContextChanged(_ newRenderContext: AVVideoCompositionRenderContext) {
    }
}

关键点:

  • sourcePixelBufferAttributes 告诉框架 compositor 支持哪些输入 pixel buffer 格式。
  • requiredPixelBufferAttributesForRenderContext 告诉框架输出 render context 需要哪些格式。
  • kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange 是示例中的 10-bit pixel format;实际项目要填自己真正支持的格式。
  • supportsHDRSourceFrames = true 是新字段。没有设置,或设置成 false,框架会在交给 compositor 前把 HDR source 转成 SDR。
  • supportsWideColorSourceFrames = true 对应 HDR 常伴随 Wide Color 的事实;transcript 说明,框架会假设能处理 HDR 的 compositor 也能处理 Wide Color。

5. 颜色属性和播放资格检查(17:4921:01

不指定 composition color properties 时,框架会按 HLG、PQ、SDR 的优先级选择输出格式。需要固定输出到 HLG、PQ 或 SDR 时,要显式设置 colorPrimariescolorTransferFunctioncolorYCbCrMatrix。播放预览还要检查当前系统是否能显示 HDR。

extension AVPlayer {
    @available(macOS 10.15, *)
    open class var eligibleForHDRPlayback: Bool { get }
}

if AVPlayer.eligibleForHDRPlayback {
    videoComposition.colorPrimaries = AVVideoColorPrimaries_ITU_R_2020
    videoComposition.colorTransferFunction = AVVideoTransferFunction_ITU_R_2100_HLG
    videoComposition.colorYCbCrMatrix = AVVideoYCbCrMatrix_ITU_R_2020
}
else {
    videoComposition.colorPrimaries = AVVideoColorPrimaries_ITU_R_709_2
    videoComposition.colorTransferFunction = AVVideoTransferFunction_ITU_R_709_2
    videoComposition.colorYCbCrMatrix = AVVideoYCbCrMatrix_ITU_R_709_2
}

关键点:

  • AVPlayer.eligibleForHDRPlayback 是 class var,不需要创建 AVPlayer 实例就能查询。
  • 返回 true 表示系统能消费 HDR video,并且至少有一个内建或外接显示器能显示 HDR。
  • HLG 示例使用 ITU_R_2020 color primaries、ITU_R_2100_HLG transfer function 和 ITU_R_2020 YCbCr matrix。
  • 不具备 HDR 播放能力时,示例把 composition color properties 设为 SDR,避免为无法显示的 HDR 预览花处理资源。
  • transcript 额外提醒:这个属性只描述播放能力。不能播放 HDR 的系统,仍可能可以走 HDR export path。

核心启发

  • HDR 剪辑预览器:做一个 macOS 视频剪辑预览窗口。为什么值得做:内建 compositor 可沿用现有 AVVideoComposition instruction 处理 HDR。怎么开始:先保持现有 AVMutableVideoComposition 结构不变,检查是否显式把 color properties 固定到了 SDR。
  • HDR 高光检查滤镜:做一个把超过 SDR 白点区域标红的诊断 filter。为什么值得做:session 的 HDRHighlight kernel 直接用 s.r > 1.0 等条件识别 HDR 高亮。怎么开始:把 kernel 放进 Metal Core Image 文件,再用 applyingCIFiltersWithHandler 接入预览。
  • 自定义 compositor HDR 升级:给多图层转场或画中画编辑器补上 HDR 能力。为什么值得做:自定义 compositor 可以同时做多层混合、几何变换和每层滤镜。怎么开始:先支持 10-bit pixel buffer,再设置 supportsHDRSourceFramessupportsWideColorSourceFrames
  • HDR/SDR 自动预览切换:根据设备能力给用户显示 HDR 或 SDR 预览。为什么值得做:eligibleForHDRPlayback 同时检查系统消费 HDR 的能力和显示器条件。怎么开始:播放路径读取该 class var,true 时设置 HLG color properties,false 时设置 ITU_R_709_2。
  • 分享用 SDR 副本:在剪辑 App 中提供“导出给普通显示设备”的选项。为什么值得做:transcript 明确给出邮件分享场景,接收方可能没有 HDR 播放系统。怎么开始:在该导出或预览路径上把 video composition 的三项 color properties 设置为 SDR。

关联 Session

评论

GitHub Issues · utterances