2025 Audio & VideoSpatial Computing
WWDC25 · 15 min · Audio & Video / Spatial Computing
Learn about Apple Immersive Video technologies
Explore the capabilities of Apple Immersive Video and Apple Spatial Audio Format technologies to create truly immersive experiences. Meet the new ImmersiveMediaSupport framework, which offers functionality to read and write the necessary metadata for enabling Apple Immersive Video. Learn guidelines for encoding and publishing Apple Immersive Video content in standalone files for playback or streaming via HLS. To get the most out of this session, we recommend first watching “Explore video experiences for visionOS.”
Watch at developer.apple.com ↗Chapters
- 0:00 — Introduction
- 0:48 — Apple Immersive Video overview
- 2:36 — Apple Immersive Video metadata
- 5:13 — Read AIVU files
- 7:16 — Write AIVU files
- 8:43 — Publish Apple Immersive Video content
- 10:29 — Preview Apple Immersive Video content
- 11:21 — Apple Spatial Audio Format
- 12:39 — Apple Positional Audio Codec
Code shown on screen · 6 snippets
Read VenueDescriptor from AIVU file
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
} Read PresentationDescriptor from AIVU playback
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
} Create AVMetadataItem from VenueDescriptor
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
} Create timed AVMetadataItem from PresentationDescriptorReader
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
} Validate AIVU file
func validAIVU(file aivuFile: URL) async throws -> Bool {
return try await AIVUValidator.validate(url: aivuFile)
} Save AIME file
let aimeFile = FileManager.default.temporaryDirectory.appendingPathComponent("primary.aime")
try? await venueDescriptor.save(to: aimeFile) Resources
Related sessions
-
26 min -
20 min -
26 min -
29 min