Getting Started with Video on visionOS
From flat to immersive: master video playback on Apple Vision Pro.
In this guide we’ll walk you through three options for video players on visionOS. Each of these can play a variety of video formats. The controls that appear on these players depend on the type of video that is being played. Make sure you download the code and try each option yourself. The repo is linked at the end of the article.
Video is one of the most common experiences built for Apple Vision Pro–whether it’s a flat 2D movie, a 3D clip, a 360° capture, a wide FOV + APMP video, or a fully immersive video.
The good news: starting in visionOS 26, Apple has simplified video workflows and improved quality through AIVU format and AIME metadata.
The better news: we’ve explored these tools for you and condensed the essentials into this guide.
VideoPlayer: Simple and SwiftUI-native
If you just want to display a 2D video inside a window, VideoPlayer from SwiftUI is the easiest way to start.
import AVKit
import SwiftUI
struct VideoPlayerView: View {
private let player = AVPlayer()
private let videoURL = URL(string: "https://devstreaming-cdn.apple.com/videos/streaming/examples/immersive-media/spatialLighthouseFlowersWaves/mvp.m3u8")!
var body: some View {
VideoPlayer(player: player)
.onAppear {
let item = AVPlayerItem(url: videoURL)
player.replaceCurrentItem(with: item)
player.play()
}
.onDisappear {
player.replaceCurrentItem(with: nil)
}
}
}AVPlayerViewController: the native video player
If you want something closer to the built-in Apple TV or Photos video player, use AVPlayerViewController.
It’s a UIKit component, so you’ll wrap it in UIViewControllerRepresentable to integrate it in SwiftUI.
import AVKit
import SwiftUI
struct AVPlayerControllerView: UIViewControllerRepresentable {
let player: AVPlayer
private let playerDelegate: PlayerDelegate
init(player: AVPlayer, exitExperience: @Sendable @MainActor @escaping () -> Void) {
self.player = player
self.playerDelegate = PlayerDelegate(exitExperience: exitExperience)
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
let controller = AVPlayerViewController()
controller.player = player
controller.delegate = playerDelegate
return controller
}
func updateUIViewController(_ vc: AVPlayerViewController, context: Context) { }
}When playback ends or the user exits, your custom delegate handles cleanup and exits the experience:
final class PlayerDelegate: NSObject, AVPlayerViewControllerDelegate {
let exitExperience: @Sendable @MainActor () -> Void
init(exitExperience: @MainActor @Sendable @escaping () -> Void) {
self.exitExperience = exitExperience
super.init()
}
func playerViewController(
_ playerViewController: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator coordinator: any UIViewControllerTransitionCoordinator
) {
exitExperience()
}
}You can host the player in your SwiftUI view:
struct AVPlayerView: View {
private let player = AVPlayer()
private let videoURL = URL(string: "https://devstreaming-cdn.apple.com/videos/streaming/examples/immersive-media/spatialLighthouseFlowersWaves/mvp.m3u8")!
var body: some View {
AVPlayerControllerView(player: player) {
appState.avPlayerVideoSource = nil
}
.onAppear {
let item = AVPlayerItem(url: videoURL)
player.replaceCurrentItem(with: item)
player.play()
}
.onDisappear {
player.replaceCurrentItem(with: nil)
}
}
}Place this view at the root of your window to guarantee solid playback:
struct ContentView: View {
@State private var presentVideo = false
var body: some View {
Group {
if presentVideo {
AVPlayerView()
} else {
HomeView()
}
}
}
}VideoPlayerComponent: bringing video into RealityKit
For a more immersive experience, visionOS 26 introduces VideoPlayerComponent. This is the option we choose when building an immersive media app or when integrating video into an immersive space.
This component builds a complete RealityKit Entity, automatically generating the mesh and video material from your AVPlayer and any AIME metadata.
Order matters: only attach the VideoPlayerComponent on new entities to avoid losing features like spatial audio.
let avPlayer = AVPlayer()
let videoEntity = Entity()
let videoURL = URL(string: "https://devstreaming-cdn.apple.com/videos/streaming/examples/immersive-media/spatialLighthouseFlowersWaves/mvp.m3u8")!
let item = AVPlayerItem(url: videoURL)
avPlayer.replaceCurrentItem(with: item)
let videoPlayerComponent = VideoPlayerComponent(avPlayer: avPlayer)
videoEntity.components.set(videoPlayerComponent)
rootEntity.addChild(videoEntity)
avPlayer.play()Full app source code
Download the complete and customizable Xcode project with this and many more video examples from STUDIO·84 + Step Into Vision.
Editors Note: I want to thank Florent Morin of STUDIO•84 for contributing this article to the Step Into Vision Community. Thank you for sharing your knowledge and expertise!
Make sure you download the app from the repo and try it yourself. We’ll explore these players and more media features in detail in our Example Code section.

Follow Step Into Vision