Highlight
macOS 与 visionOS 26 新增 ImmersiveMediaSupport 框架,配合 AIVU 文件容器和 ASAF/APAC 音频格式,让第三方工具也能读写 Apple Immersive Video 的元数据。
核心内容
Apple Immersive Video(AIV)是 Apple Vision Pro 上画质最高的沉浸式视频格式,专为 Blackmagic URSA Cine Immersive 这类相机设计。这种相机出厂时就经过逐机标定(factory calibration),把每只立体镜头的曲率参数写进视频文件,渲染时再根据这些参数做参数化投影。问题在于,过去这套元数据只能由 Apple 内部工具处理:第三方非线性编辑软件、转码工具、流媒体平台拿到 AIV 素材后,无法读写其中的相机标定、shot flop、淡入淡出等关键信息,整条生产链卡在中间。
Blake 在这场 session 里宣布了打通这条链路的方案。macOS 与 visionOS 26 新增 ImmersiveMediaSupport 框架,提供 VenueDescriptor(多相机组合 + 边缘混合 mask + 背景环境)和 PresentationDescriptor(每帧的标定切换、shot flop、fade 等动态指令)两套数据类型;同时定义 AIVU(Apple Immersive Video Universal)文件容器,把视频轨、PresentationDescriptor、VenueDescriptor 打包成单一文件,可在 visionOS 的 Files app 里通过 Quick Look 直接预览。读写都走 AVFoundation:用 quickTimeMetadataAIMEData 标识符过滤元数据拿到 VenueDescriptor,用 quickTimeMetadataPresentationImmersiveMedia 拿到 PresentationDescriptor。写入则把投影类型设为 AppleImmersiveVideo,再用 AVAssetWriter 把元数据 mux 进去。音频侧,Apple 新出 ASAF(Apple Spatial Audio Format)做制作格式,APAC(Apple Positional Audio Codec)做分发格式,APAC 是 AIV 体验的强制要求。
详细内容
读取 AIVU 文件中的 VenueDescriptor(06:23):
func readAIMEData(from aivuFile: URL) async throws -> VenueDescriptor? {
let avAsset = AVURLAsset(url: aivuFile)
let metadata = try await avAsset.load(.metadata)
let aimeData = metadata.filter({ $0.identifier == .quickTimeMetadataAIMEData }).first
if let dataValue = try await aimeData.load(.value) as? NSData {
return try await VenueDescriptor(aimeData: dataValue as Data)
}
return nil
}
关键点:
AVURLAsset(url:)把 AIVU 当成普通 QuickTime 资源加载。load(.metadata)异步取出整份资源级元数据。quickTimeMetadataAIMEData是 ImmersiveMediaSupport 新增的标识符,专门用来过滤 AIME(Apple Immersive Media Embedded)数据。VenueDescriptor(aimeData:)把原始Data反序列化为相机组合描述。
读取每帧的 PresentationDescriptor(06:50):
func presentation(timedMetadata: [AVTimedMetadataGroup]) async throws ->
[PresentationDescriptor] {
var presentations: [PresentationDescriptor] = []
for group in timedMetadata {
for metadata in group.items {
if metadata.identifier == .quickTimeMetadataPresentationImmersiveMedia {
let data = try await metadata.load(.dataValue) {
presentations.append(
try JSONDecoder().decode(PresentationDescriptor.self, from: data)
)
}
}
}
}
return presentations
}
关键点:
- 入参是
AVTimedMetadataGroup数组,每组对应一段视频帧的 PTS 区间。 - 通过
quickTimeMetadataPresentationImmersiveMedia标识符过滤 Presentation 命令。 - 命令以 JSON 编码,用
JSONDecoder解出PresentationDescriptor,里面带着该时间点的相机标定切换、shot flop、fade 等指令。 - 详细取 timed metadata 的方式参考
AVPlayerItemMetadataOutput。
写入 VenueDescriptor 到 AVMetadataItem(07:52):
func getMetadataItem(from metadata: VenueDescriptor) async throws -> AVMetadataItem {
let aimeData = try await metadata.aimeData
let aimeMetadataItem = AVMutableMetadataItem()
aimeMetadataItem.identifier = .quickTimeMetadataAIMEData
aimeMetadataItem.dataType = String(kCMMetadataBaseDataType_RawData)
aimeMetadataItem.value = aimeData as NSData
return aimeMetadataItem
}
关键点:
metadata.aimeData把 VenueDescriptor 序列化成原始字节。dataType = kCMMetadataBaseDataType_RawData告诉容器这是原始二进制,避免被误处理为字符串。- 这一项作为资源级元数据写入,配合 AVAssetWriter 即可生成可播放的 AIVU。
写入按帧时序的 PresentationDescriptor(08:02):
func getMetadataItem(reader: PresentationDescriptorReader,
time: CMTime, frameDuration: CMTime) -> AVMetadataItem? {
let commands = reader.outputPresentationCommands(for: time) ?? []
if commands.isEmpty { return nil }
let descriptor = PresentationDescriptor(commands: commands)
let encodedData = try JSONEncoder().encode(descriptor)
let presentationMetadata = AVMutableMetadataItem()
presentationMetadata.identifier = .quickTimeMetadataPresentationImmersiveMedia
presentationMetadata.dataType = String(kCMMetadataBaseDataType_RawData)
presentationMetadata.value = encodedData as NSData
presentationMetadata.time = time
presentationMetadata.duration = frameDuration
return presentationMetadata
}
关键点:
PresentationDescriptorReader.outputPresentationCommands(for:)按时间取出该帧需要执行的命令序列。- 命令为空时返回 nil,避免写入冗余的元数据条目。
time与duration必须对齐到视频帧 buffer 的 PTS 与帧长,播放器据此触发标定切换或 shot flop。- 编码沿用 JSON,写入侧与读取侧对称。
校验 AIVU 文件(08:20):
func validAIVU(file aivuFile: URL) async throws -> Bool {
return try await AIVUValidator.validate(url: aivuFile)
}
关键点:
AIVUValidator.validate(url:)在写入流水线尾部跑一次,提前发现元数据缺失或不一致。- 校验失败抛错;校验通过返回 true。
HLS 发布要点(09:31 起):
- 推荐参数:每只眼 4320×4320、90fps、P3-D65-PQ 色彩空间、MV-HEVC。
- 码率:平均 25–100 Mbps,峰值 50–150 Mbps,分层时保持分辨率与帧率一致,只在码率维度做取舍。
- 用
venueDescriptor.save(to:)单独导出一个.aime文件,放在 HLS playlist 旁边。 - multivariant playlist 需 HLS version ≥ 12,标注 venue description data ID、
content type=fully immersive、stereo video layout、AppleImmersiveVideo投影、APAC 音频。 - 切片时务必保留 PresentationDescriptor 所在的 timed metadata track,否则播放端无法在帧级别切换标定。
预览链路:ImmersiveMediaRemotePreviewSender 与 ImmersiveMediaRemotePreviewReceiver 把低码率帧从 Mac 推到 Vision Pro,配合自定义 compositor 在 visionOS app 里实时显示,专门服务编辑期。
音频部分(11:21 起):ASAF 基于 broadcast Wave + 线性 PCM + 元数据,渲染完全自适应,根据物体和听者位置实时计算,没有烘焙。APAC 是 ASAF 的 mp4 分发编码,64 kbps 起步,支持 Channels、Objects、HOA、Dialogue、Binaural、交互元素,watchOS 之外的全平台可播。制作工具是 Apple Pro Tools 插件和 DaVinci Resolve Studio Editor。HLS 侧需要在 media tag 里写音频通道信息,并在 stream info tag 里指定 APAC 编解码器。
核心启发
-
做什么:在自家相册或视频管理 app 里加一条 AIVU 直读管线。
- 为什么值得做:visionOS 26 起 AIVU 已是 Apple 官方推荐的单文件交付格式,Files + Quick Look 已原生支持。先把它当一等公民处理,用户从同事或 NLE 拿到 AIVU 就能直接消费。
- 怎么开始:
AVURLAsset加载 → 过滤quickTimeMetadataAIMEData取 VenueDescriptor → 监听 timed metadata group 取 PresentationDescriptor → 用系统播放栈渲染。读写代码大约百行内。
-
做什么:给 NLE/转码工具加一个 “Export as AIVU” 按钮。
- 为什么值得做:AIV 元数据一旦在中间环节丢失,下游就拿不到正确的相机标定,画面会扭曲。把 AIVU 作为统一的中间交付格式可以保住元数据。
- 怎么开始:用 AVAssetWriter,把投影类型设为
AppleImmersiveVideo,VenueDescriptor 走资源级 metadata,PresentationDescriptor 走 timed metadata,写完调用AIVUValidator.validate(url:)自检。
-
做什么:搭一条 Mac→Vision Pro 的实时预览链路。
- 为什么值得做:剪辑期的素材通常没经过完整压制,开发者过去只能导出再导入,反馈周期太长。
ImmersiveMediaRemotePreviewSender/Receiver把这一步压到帧级。 - 怎么开始:Mac 端用 Sender 推低码率帧,Vision Pro 端写一个带自定义 compositor 的 visionOS app 接 Receiver,预览质量牺牲换取低延迟。
- 为什么值得做:剪辑期的素材通常没经过完整压制,开发者过去只能导出再导入,反馈周期太长。
-
做什么:流媒体后端补齐 HLS 的 AIV 字段。
- 为什么值得做:Apple Vision Pro 对 AIV HLS 有硬要求(version 12、AIME 旁路文件、fully immersive content type、APAC 音频)。任何一项缺失播放器就会拒绝。
- 怎么开始:先按推荐 tier(25/50/100 Mbps 平均,50/100/150 Mbps 峰值)切片,保留 timed metadata track,把
venueDescriptor.save(to:)出的.aime文件放进 playlist 目录,再在 multivariant playlist 加好对应 tag。
-
做什么:声音侧补齐 ASAF→APAC 的工作流。
- 为什么值得做:APAC 是 AIV 体验的强制项,且 64 kbps 起就能跑出沉浸式空间音频,对带宽友好。
- 怎么开始:制作端选 Apple Pro Tools 插件或 DaVinci Resolve Studio Editor 输出 ASAF(broadcast Wave + 元数据),再编码为 mp4 APAC,HLS 端在 media tag 标注通道信息、stream info tag 指定 APAC 编码。
关联 Session
- Explore video experiences for visionOS — visionOS 26 视频 profile 总览,本场的前置知识
- Learn about the Apple Projected Media Profile — 180/360 度投影格式 APMP 详解
- Support immersive video playback in visionOS apps — 在自己的 visionOS app 里播放 AIVU/HLS 沉浸式视频
- Create a seamless multiview playback experience — 多视角播放体验的构建方式
评论
GitHub Issues · utterances