A component that supports general video-playback experience with an AV player.
To streamline and enhance video playback controls, a video player component empowers an app to support
captions, subtitles, light spill, and passthrough tinting (visionOS only). Attach a `VideoPlayerComponent`
to an entity to start configuring playback controls.
The example below shows an entity with a ``VideoPlayerComponent`` attached:
@Video(
source: videoplayercomponent-videoplaying,
alt: "A screen recording of an entity with a video player component playing in a living room scene.",
poster: videoplayercomponent-videoplaying-poster
)
The following code example shows the basic setup for initializing a `VideoPlayerComponent` with an
<doc://com.apple.documentation/documentation/avfoundation/avplayer>:
```swift
// Create an entity for display.
let videoEntity = Entity()
// Create an AV player with a URL.
let player = AVPlayer(url: "PLACEMENT_URL")
// Create a video player component with the AV player.
let videoPlayerComponent = VideoPlayerComponent(avPlayer: player)
// Attach the video player component to the entity.
videoEntity.components.set(videoPlayerComponent)
```
Here are some common usage scenarios before attaching the video player component to the entity:
```swift
// Set the desired viewing mode to stereo to enable
// stereoscopic playback of the video, if available.
videoPlayerComponent.desiredViewingMode = VideoPlaybackController.ViewingMode.stereo
// Enable passthrough tinting during video playback.
videoPlayerComponent.isPassthroughTintingEnabled = true
```
Here are a few event subscription examples for ``VideoPlayerEvents``:
```swift
RealityView { content in
// Set up a video player component with an AV player.
let entity = Entity()
let player = AVPlayer(url: "PLACEMENT_URL")
let videoPlayerComponent = VideoPlayerComponent(avPlayer: player)
player.play()
entity.components.set(videoPlayerComponent)
var subscription: EventSubscription?
// Subscribe to the video screen size change event.
subscription = content.subscribe(to:
VideoPlayerEvents.VideoSizeDidChange.self) { event in
print("video size did change: \(event.videoDimension)")
}
// Subscribe to the current viewing mode change event.
subscription = content.subscribe(to:
VideoPlayerEvents.ViewingModeDidChange.self) { event in
print("viewing mode did change: \(event.currentViewingMode)")
}
// Subscribe to the content type change event.
subscription = content.subscribe(to:
VideoPlayerEvents.ContentTypeDidChange.self) { event in
print("content type did change: \(event.contentType.rawValue)")
}
content.add(entity)
}
```
### Playing immersive video
On visionOS, you can also use `VideoPlayerComponent` to play immersive media with RealityKit.
Watch videos in a window alongside other Shared Space apps, or watch immersive video
with a 180-degree field of view in a fully immersive space, or watch immersive video with a progressive view
in a progressive immersive space
### Playing immersive video with a 180-degree field of view
To play the immersive media with a 180-degree field of view, first set up a fully immersive space,
and then set ``desiredImmersiveViewingMode`` to ``ImmersiveViewingMode-swift.enum/full``.
If you want to switch the immersive-viewing mode to `full` while immersive-media playback
is in ``ImmersiveViewingMode-swift.enum/portal`` mode,
wait for the scene event named ``VideoPlayerEvents/ImmersiveViewingModeDidChange``
to trigger after you set ``desiredImmersiveViewingMode`` to `full`.
Then, dismiss the window scene and open up a fully immersive space scene.
### Playing immersive video with a progressive view
To play the immersive media with a progressive view, first set up a progressive immersive space,
and then set ``desiredImmersiveViewingMode`` to ``ImmersiveViewingMode-swift.enum/progressive``.
If you want to switch the immersive-viewing mode to `progressive` while immersive-media playback
is in ``ImmersiveViewingMode-swift.enum/portal`` mode,
wait for the scene event named ``VideoPlayerEvents/ImmersiveViewingModeDidChange``
to trigger after you set ``desiredImmersiveViewingMode`` to `progressive`.
Then, dismiss the window scene and open up a progressive immersive space scene.
### Playing immersive video in a portal window
To play the immersive video in a portal window, set up a window scene in the Shared Space,
and then set ``desiredImmersiveViewingMode`` to ``ImmersiveViewingMode-swift.enum/portal``.
If you want to switch the immersive-viewing mode to `portal` while immersive-media playback
is in `full` or is in `progressive` mode, wait for the scene event named
``VideoPlayerEvents/ImmersiveViewingModeDidChange`` to trigger
after you set ``desiredImmersiveViewingMode`` to `portal`.
Then, dismiss the fully/progressive immersive space and open up a window scene.
### Updating the UI during transitions
The system triggers scene events named
``VideoPlayerEvents/ImmersiveViewingModeWillTransition`` and
``VideoPlayerEvents/ImmersiveViewingModeDidTransition``
at the start and end of the immersive-viewing mode transitions, respectively.
Apps can listen to these scene events to turn playback controls or other UI items on or off during transitions.
Creates a video player component from an AV player object.
- Note: You can't use the same `AVPlayer` object with more than one `VideoPlayerComponent`.
Here's an example of setting up a video player component:
```swift
// Create an entity for display.
let videoEntity = Entity()
// Create an AV player with a URL.
let player = AVPlayer(url: "PLACEMENT_URL")
// Create a video player component with the AV player.
let videoPlayerComponent = VideoPlayerComponent(avPlayer: player)
// Attach the video player component to the entity.
videoEntity.components.set(videoPlayerComponent)
```
- Parameters:
- avPlayer: An
<doc://com.apple.documentation/documentation/avfoundation/avplayer>
instance.
get · iOS 18.0+
avPlayer
TypeScript
get avPlayer(): (_AVFoundation_AVPlayer) | null
Swift declaration
var avPlayer: AVPlayer? { get }
The AV player that the component plays.
Pass this player to the component as a parameter
in the initializer; you can't replace it afterward.
get · iOS 18.0+
screenVideoDimension
TypeScript
get screenVideoDimension(): SDKHandle
Swift declaration
var screenVideoDimension: SIMD2<Float> { get }
The video resolution size.
This property has the format `[width, height]`, for example, `[1920, 1080]`.
get · iOS 18.0+
viewingMode
TypeScript
get viewingMode(): (VideoPlaybackController_ViewingMode) | null
Swift declaration
var viewingMode: VideoPlaybackController.ViewingMode? { get }
The current content-viewing mode for video playback.
Creates a video player component from a sample buffer video renderer object.
To create a `VideoPlayerComponent`, first create an
<doc://com.apple.documentation/documentation/avfoundation/avsamplebuffervideorenderer>
instance with no parameters and then pass that to the `VideoPlayerComponent` initializer.
After creating the `VideoPlayerComponent`, create an
<doc://com.apple.documentation/documentation/avfoundation/avassetreader>
with the <doc://com.apple.documentation/documentation/avfoundation/avurlasset>
and load the media (video), which you need to track as the
<doc://com.apple.documentation/documentation/avfoundation/avassettrack>.
Feed this `AVAssetTrack` to the
<doc://com.apple.documentation/documentation/avfoundation/avassetreadertrackoutput>
and add this output tracker to the `AVAssetReader`.
Wait for setup to finish and start reading.
Read the sample buffers from the reader and enqueue it into the
`AVSampleBufferVideoRenderer` object.
`AVSampleBufferVideoRenderer` uses a push model, so feed the video sample buffers until
the queue is full, and then resume feeding it when it's ready for more.
You can use `isReadyForMoreMediaData` on the `AVSampleBufferVideoRenderer`
object in a while-loop to check whether you need to enqueue more sample buffers.
You can't use the same `AVSampleBufferVideoRenderer` object with more than one
`VideoPlayerComponent`.
You need to synchronize the audio, captions, and playback rate separately in your app.
The following code example demonstrates how to synchronize video with audio:
```swift
// Create an `AVSampleBufferVideoRenderer` instance to control playback of a movie.
let videoRenderer = AVSampleBufferVideoRenderer()
// Create an `AVSampleBufferAudioRenderer` instance to control audio of the playback.
let audioRenderer = AVSampleBufferAudioRenderer()
// Create a `AVSampleBufferRenderSynchronizer` instance to synchronize video and audio.
let synchronizer = AVSampleBufferRenderSynchronizer()
// Add both videoRenderer and audioRenderer to the synchronizer.
synchronizer.addRenderer(videoRenderer)
synchronizer.addRenderer(audioRenderer)
// Create an entity for display.
let videoEntity = Entity()
// Create a `VideoPlayerComponent` object that supplies the `AVSampleBufferVideoRenderer` object.
let videoPlayerComponent = VideoPlayerComponent(videoRenderer: videoRenderer)
videoEntity.components[VideoPlayerComponent.self] = videoPlayerComponent
// Create a URL that points to the movie file.
if let url = Bundle.main.url(forResource: "MyMovie", withExtension: "mp4") {
let sourceAsset = AVURLAsset(url: url)
let sourceAssetReader = AVAssetReader(asset: sourceAsset)
let sourceAssetVideoTrack = sourceAsset.loadTracks(withMediaType: .video).first
let sourceAssetAudioTrack = sourceAsset.loadTracks(withMediaType: .audio).first
let sourceAssetReaderVideoTrackOutput = AVAssetReaderTrackOutput(track: sourceAssetVideoTrack!, outputSettings: nil)
let sourceAssetReaderAudioTrackOutput = AVAssetReaderTrackOutput(track: sourceAssetAudioTrack!, outputSettings: nil)
sourceAssetReader.add(sourceAssetReaderVideoTrackOutput!)
sourceAssetReader.add(sourceAssetReaderAudioTrackOutput!)
sourceAssetReader.startReading()
videoRenderer.requestMediaDataWhenReady(on: DispatchQueue.global()) {
while videoRenderer.isReadyForMoreMediaData {
if let sampleBuffer = sourceAssetReaderVideoTrackOutput!.copyNextSampleBuffer() {
videoRenderer.enqueue(sampleBuffer)
} else {
videoRenderer.stopRequestingMediaData()
return
}
}
}
audioRenderer.requestMediaDataWhenReady(on: DispatchQueue.global()) {
while audioRenderer.isReadyForMoreMediaData {
if let sampleBuffer = sourceAssetReaderAudioTrackOutput!.copyNextSampleBuffer() {
audioRenderer.enqueue(sampleBuffer)
} else {
audioRenderer.stopRequestingMediaData()
return
}
}
}
// Start the playback immediately.
synchronizer.setRate(1, time: .zero)
}
```
- Parameters:
- videoRenderer: The sample buffer video renderer with the visual contents the component
presents.
get · iOS 18.0+
videoRenderer
TypeScript
get videoRenderer(): (_AVFoundation_AVSampleBufferVideoRenderer) | null
Swift declaration
var videoRenderer: AVSampleBufferVideoRenderer? { get }
The component's video renderer.
Pass this renderer to the component as a parameter
in the initializer; you can't replace it afterward.
You can't use the same `AVSampleBufferVideoRenderer`
object with more than one `VideoPlayerComponent`.
get · iOS 18.0+
playerScreenSize
TypeScript
get playerScreenSize(): SDKHandle
Swift declaration
var playerScreenSize: SIMD2<Float> { get }
The screen entity size of the current video player in meters.
This property has the format `[width, height]`.
get · iOS 18.0+
desiredViewingMode
TypeScript
get desiredViewingMode(): VideoPlaybackController_ViewingMode
Swift declaration
var desiredViewingMode: VideoPlaybackController.ViewingMode { get set }
The viewer's selected content-viewing mode.
This is the content-viewing mode that the current content-viewing mode transitions to.
set · iOS 18.0+
desiredViewingMode
TypeScript
set desiredViewingMode(value: VideoPlaybackController_ViewingMode)
Swift declaration
var desiredViewingMode: VideoPlaybackController.ViewingMode { get set }
The viewer's selected content-viewing mode.
This is the content-viewing mode that the current content-viewing mode transitions to.
get · iOS 18.0+
currentRenderingStatus
TypeScript
get currentRenderingStatus(): VideoPlayerComponent_RenderingStatus
Swift declaration
var currentRenderingStatus: VideoPlayerComponent.RenderingStatus { get }