What's new in AVFoundation
Audio & Video 进阶 31m

AVFoundation 新特性

What's new in AVFoundation

2021年6月7日

在 Apple 官方观看视频

一句话判断

AVFoundation 今年的更新虽然没有单一的”炸裂”特性,但累积起来改变了视频应用的开发方式——async/await 整合、Spatial Audio 支持、以及 HDR 管线的完善,每一个都值得跟进。

这场 Session 讲了什么

Session 全面介绍了 AVFoundation 在 iOS 15、macOS Monterey 和 tvOS 15 中的更新。涵盖了播放、录制、编辑三个维度的改进,重点包括:async/await API 的全面引入、Spatial Audio(空间音频)的录制与播放支持、ProRes 视频在 iPhone 13 Pro 上的录制能力、以及 HDR 视频管线在各环节的增强。

在播放侧,AVPlayerAVAsset 的许多异步操作现在都有了原生的 async 接口——加载 track 信息、查询 duration、获取 metadata 都不再需要 callback。录制侧,AVCaptureSession 支持了 Apple ProRAW 和 ProRes 格式,配合新的 AVCaptureDevice API 可以更精细地控制摄像头参数。编辑侧,AVComposition 的编辑操作现在可以导出为符合 HLS 规范的 fMP4 格式,方便直接用于流媒体分发。

值得深挖的点

AVAsset 的 async/await 接口设计

AVAsset 以前的异步加载模式是 loadValuesAsynchronously(forKeys:) 加回调,或者用 AVAsynchronousKeyValueLoading 协议。新 API 直接把每个属性变成了 async 计算属性。比如 asset.tracks 变成了 try await asset.load(.tracks)。更实用的是批量加载:try await asset.load(.tracks, .duration, .metadata) 一次加载多个属性,只触发一次 I/O 操作。这比之前每个属性单独加载高效得多,尤其是远程 URL 的 asset。

Spatial Audio 在 AVFoundation 中的实现

Spatial Audio 需要 iOS 15 的 AVFoundation 配合 AirPods Pro/Max 使用。AVAudioSession 新增了 isEligibleForSpatialization 属性来标记你的音频内容支持空间化。AVAudioMixing 协议新增了 renderingAlgorithm 属性,可以选择 renderingAlgorithm.equalPowerPanningrenderingAlgorithm.auto 来控制空间音频的渲染策略。对于视频播放,只要音频流包含 Dolby Atmos metadata,AVPlayer 会自动启用 Spatial Audio——开发者不需要额外代码。

代码片段

// AVAsset 的 async/await 加载方式
func analyzeVideo(at url: URL) async throws {
    let asset = AVURLAsset(url: url)
    
    // 批量异步加载多个属性,只触发一次 I/O
    let (tracks, duration, metadata) = try await asset.load(
        .tracks, .duration, .commonMetadata
    )
    
    print("时长: \(CMTimeGetSeconds(duration)) 秒")
    print("轨道数: \(tracks.count)")
    
    for item in metadata {
        if let title = item.stringValue {
            print("元数据: \(item.commonKey?.rawValue ?? "") = \(title)")
        }
    }
}
// Spatial Audio 配置
func configureSpatialAudio() {
    let session = AVAudioSession.sharedInstance()
    
    do {
        // 标记音频内容适合空间化处理
        try session.setCategory(.playback, 
                                mode: .moviePlayback,
                                policy: .longForm,
                                options: .allowAirPlay)
        
        // 检查当前输出设备是否支持空间音频
        if session.currentRoute.outputs.contains(where: { 
            $0.portType == .airPlay || $0.portType == .bluetooth 
        }) {
            print("当前输出支持 Spatial Audio")
        }
        
        try session.setActive(true)
    } catch {
        print("音频会话配置失败: \(error)")
    }
}
// AVCaptureSession 支持 async/await 的配置
func setupCamera() async throws {
    let session = AVCaptureSession()
    session.beginConfiguration()
    session.sessionPreset = .photo
    
    // 使用新的异步查询 API 检查设备能力
    let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera,
                                              for: .video, position: .back)
    guard let device = videoDevice else { return }
    
    let input = try AVCaptureDeviceInput(device: device)
    if session.canAddInput(input) {
        session.addInput(input)
    }
    
    session.commitConfiguration()
    // 在后台启动 session 不再阻塞当前线程
    await session.startRunning()  // iOS 15 新增的 async 版本
}

最佳实践

  • 立即将 loadValuesAsynchronously 的调用替换为 asset.load(.property) 的 async 版本。旧的 callback 方式不是立刻废弃,但新 API 在性能和可读性上都更好。
  • 如果你的 App 播放包含多语言音轨的视频,检查 AVMediaSelection 的 async API,按需加载音频轨道而不是全部预加载。
  • 在支持 ProRes 录制的设备上(iPhone 13 Pro 及以上),为用户提供格式选择选项——ProRes 文件体积是 HEVC 的 5-10 倍,不是所有用户都需要。

还有什么值得关注

  • AVAssetImageGenerator 现在支持 async 生成缩略图,配合 for await 可以逐帧遍历视频。
  • AVPlayerwaitingForCoordinatedPlayback 状态在 Group Activities 场景下有特殊用途,详见 SharePlay 相关 Session。
  • iOS 15 的 AVRoutePickerView 支持了 AirPlay 到 Mac,macOS Monterey 可以作为 AirPlay 接收端。
WWDC 2021