AVFoundation 新特性
What's new in AVFoundation
2021年6月7日
一句话判断
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 视频管线在各环节的增强。
在播放侧,AVPlayer 和 AVAsset 的许多异步操作现在都有了原生的 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.equalPowerPanning 或 renderingAlgorithm.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可以逐帧遍历视频。AVPlayer的waitingForCoordinatedPlayback状态在 Group Activities 场景下有特殊用途,详见 SharePlay 相关 Session。- iOS 15 的
AVRoutePickerView支持了 AirPlay 到 Mac,macOS Monterey 可以作为 AirPlay 接收端。