Build compelling spatial photo and video experiences
Spatial Computing 进阶 20m

在 App 中构建空间照片和空间视频体验

Build compelling spatial photo and video experiences

2024年6月10日

在 Apple 官方观看视频

一句话判断

visionOS 2 和 iOS 18 让空间视频的录制、检测和播放全部融入现有框架(AVFoundation、PhotoKit、QuickLook),iPhone 15 Pro 上只需三行代码改动就能录制空间视频。

这场 Session 讲了什么

空间媒体(Spatial Media)在 Vision Pro 上有三种形态:3D Video(在平面屏幕上有深度效果)、Spatial Video(通过窗口播放,沉浸模式时与真实世界融合)、Apple Immersive Video(180 度 8K + Spatial Audio 的专业级内容)。三种形态各有适用场景——3D 适合电影,Spatial Video 适合日常记录,Immersive 适合专业制作。

今年最大的变化是把空间媒体能力开放给了开发者,而且没有引入新框架。所有 API 都集成在 AVFoundation、PhotoKit、QuickLook 等已有框架中。

录制方面,iPhone 15 Pro 的广角和超广角摄像头在横屏时处于同一水平基线,类似人眼布局。API 现在公开了空间视频录制能力——切换摄像头、选择支持空间视频的格式、开启录制标志,三步完成。播放方面,Vision Pro 上的窗口模式和沉浸模式可以自由切换。检测方面,可以通过文件元数据判断是否为空间内容。

值得深挖的点

空间视频录制的三个关键改动

从普通视频录制迁移到空间视频录制只需要改三处。第一处是把摄像头从 systemPreferredCamera 改为 builtInDualWideCamera,因为空间视频需要广角和超广角同时工作。第二处是遍历 videoDevice.formats 找到 isSpatialVideoCaptureSupported == true 的格式并设为活跃格式。第三处是在输出上设置 isSpatialVideoCaptureEnabled = true

看似简单,但背后的含义值得注意。广角和超广角同时工作意味着更高的功耗和发热。Apple 选择在 iPhone 15 Pro 上开放这个能力,是因为它的摄像头物理布局经过专门调整。如果你需要在不同设备上做兼容处理,一定要检查 isSpatialVideoCaptureSupported 而不是硬编码设备型号。

空间视频播放的窗口模式与沉浸模式

空间视频在 Vision Pro 上有两种呈现方式。窗口模式下通过一个带柔和光晕的窗口播放,用户可以同时操作其他 App。点击沉浸按钮后,内容扩展到与真实物体等大的尺寸,画面边缘消失,与真实世界无缝融合——不是”看视频”,而是”身处其中”。

对于开发者来说,QuickLook 框架可以直接预览空间照片和视频,WebKit 也可以渲染空间内容。你不需要自己实现沉浸模式的切换逻辑,系统提供了标准的交互方式。

代码片段

在 iPhone 上录制空间视频

import AVFoundation

let session = AVCaptureSession()

// 改动 1:使用双广角摄像头(广角+超广角同时工作)
guard let videoDevice = AVCaptureDevice.default(.builtInDualWideCamera, for: .video, position: .back) else {
    print("设备不支持双广角摄像头")
    return
}

let deviceInput = try AVCaptureDeviceInput(device: videoDevice)
session.addInput(deviceInput)

// 改动 2:找到支持空间视频的格式
var spatialFormatFound = false
do {
    try videoDevice.lockForConfiguration()
    for format in videoDevice.formats {
        if format.isSpatialVideoCaptureSupported {
            videoDevice.activeFormat = format
            spatialFormatFound = true
            break
        }
    }
    videoDevice.unlockForConfiguration()
} catch {
    print("配置格式失败: \(error)")
}

guard spatialFormatFound else {
    print("未找到支持空间视频的格式")
    return
}

let movieOutput = AVCaptureMovieFileOutput()
session.addOutput(movieOutput)

// 改动 3:开启空间视频录制
if movieOutput.isSpatialVideoCaptureSupported {
    movieOutput.isSpatialVideoCaptureEnabled = true
}

session.commitConfiguration()
session.startRunning()

场景:社交类 App 想让用户拍摄空间视频并分享。三处改动从普通视频录制切换到空间视频。

坑点isSpatialVideoCaptureSupported 在非 iPhone 15 Pro 设备上返回 false,需要做好降级处理。录制过程中广角和超广角同时工作会增加发热,长时间录制需要注意。

使用 QuickLook 预览空间照片

import QuickLook

class SpatialPreviewController: QLPreviewControllerDataSource {
    
    func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
        return 1
    }
    
    func previewController(_ controller: QLPreviewController, 
                           previewItemAt index: Int) -> QLPreviewItem {
        // 空间照片/视频文件 URL
        return spatialMediaURL as QLPreviewItem
    }
}

// QuickLook 自动识别空间媒体并以正确方式呈现
let previewController = QLPreviewController()
previewController.dataSource = dataSource
present(previewController, animated: true)

场景:用户从相册选择了一张空间照片,用 QuickLook 在 Vision Pro 上预览。系统自动处理窗口/沉浸模式切换。

最佳实践

  • 录制空间视频时,为获得最佳防抖效果,设置 preferredVideoStabilizationMode
  • 不要硬编码设备型号检查,始终使用 isSpatialVideoCaptureSupported 做兼容判断
  • QuickLook 是最简单的空间媒体预览方案,优先考虑而非自己实现播放器
  • 空间视频的同步、校准、编码和元数据写入都由系统处理,不要尝试手动操作这些步骤

还有什么值得关注

  • Vision 框架提供了检测文件是否为空间媒体的 API,可用于内容过滤
  • AVFoundation 也支持构建自定义的空间视频播放体验,适合需要特殊 UI 的场景
  • 实时 3D 内容在 Vision Pro 上也可以呈现立体效果,参考 “Bring your iOS or iPadOS game to visionOS”
WWDC 2024