Video Player
useVideoPlayer plays a single video file and exposes its current frame as a
Reanimated shared value. Each frame is a GPU texture — wrap it with
Skia.Image.MakeImageFromNativeTextureUnstable and draw it like any other
SkImage.
import { Canvas, Image, Skia } from '@shopify/react-native-skia';
import { useVideoPlayer } from '@azzapp/react-native-skia-video';
import { useDerivedValue } from 'react-native-reanimated';
const MyVideoPlayer = ({ uri, width, height }) => {
const { currentFrame, player } = useVideoPlayer({
uri,
autoPlay: true,
isLooping: true,
onReadyToPlay: ({ width, height, rotation }) =>
console.log(`video is ${width}x${height}, rotated ${rotation}°`),
});
const videoImage = useDerivedValue(() => {
const frame = currentFrame.value;
if (!frame) return null;
return Skia.Image.MakeImageFromNativeTextureUnstable(
frame.texture,
frame.width,
frame.height
);
});
return (
<Canvas style={{ width, height }}>
<Image image={videoImage} x={0} y={0} width={width} height={height} fit="cover" />
</Canvas>
);
};
Options
| Option | Type | Description |
|---|---|---|
uri | string | null | The video to play. Pass null to skip creating the player. |
resolution | { width, height } | Decode at a lower resolution — a big performance win when the display size is small. Changing it re-creates the player. |
autoPlay | boolean | Start playback as soon as the video is ready. |
isLooping | boolean | Restart from the beginning when playback completes. |
volume | number | Volume of the video's audio track (0–1). |
playbackSpeed | number | 1 is normal speed, 2 double, 0.5 half. |
Callbacks
| Callback | Fired when |
|---|---|
onReadyToPlay(dimensions) | The video is ready; receives { width, height, rotation }. |
onBufferingStart() / onBufferingEnd() | Network/disk buffering starts or ends. |
onBufferingUpdate(ranges) | Buffered ranges change ({ start, duration }[]). |
onComplete() | Playback reaches the end. |
onSeekComplete() | A seekTo finished. |
onPlayingStatusChange(playing) | Play/pause state changes. |
onError(error, retry) | Something failed; call retry() to re-create the player. |
Controlling playback
The hook also returns a player controller:
const { currentFrame, player } = useVideoPlayer({ uri });
player?.play();
player?.pause();
player?.seekTo(12.5); // seconds
player?.currentTime; // seconds
player?.duration; // seconds
player?.isPlaying;
Frame lifecycle
The frame textures are owned and recycled by the player. The SkImage
wrappers you create around them are cheap; create them per frame in a derived
value (as above) or in a frame callback.
For playing several videos on a shared clock — cuts, transitions, overlays — use a Video Composition instead of multiple players.