Skip to main content

Playback

useVideoCompositionPlayer plays a composition in real time: it drives the decoders, calls your drawFrame into an offscreen GPU surface every vsync, and returns the resulting SkImage as a Reanimated derived value.

import { Canvas, Image } from '@shopify/react-native-skia';
import { useVideoCompositionPlayer } from '@azzapp/react-native-skia-video';

const CompositionPlayer = ({ composition, width, height }) => {
const { currentFrame, player } = useVideoCompositionPlayer({
composition,
drawFrame,
width,
height,
autoPlay: true,
isLooping: true,
onError: (error, retry) => {
console.warn(error);
retry();
},
});

return (
<Canvas style={{ width, height }}>
<Image image={currentFrame} x={0} y={0} width={width} height={height} />
</Canvas>
);
};

Options

OptionTypeDescription
compositionVideoComposition | nullThe composition to play; null skips creating the player.
drawFrameFrameDrawerWorklet that draws each frame (concepts).
width / heightnumberOutput size in density-independent points (the backing surface is scaled by the device pixel ratio).
autoPlaybooleanStart as soon as the composition is ready.
isLoopingbooleanLoop when the end is reached.
beforeDrawFrame / afterDrawFrame() => T / (context: T) => voidRun around every frame; the returned context is passed to drawFrame. Handy for allocating/releasing per-frame resources.
onReadyToPlay() => voidThe composition is prepared.
onComplete() => voidPlayback reached the end.
onError(error, retry) => voidDecoding failed; call retry() to re-create the player.

Returns

  • currentFrameDerivedValue<SkImage | null>: the freshly rendered frame. Pass it straight to a Skia <Image> component.
  • player — a controller with play(), pause(), seekTo(seconds), currentTime and isPlaying.

Performance notes

  • Give video items a resolution no larger than what you display: decoding 1080p to show a 300pt preview wastes decoder bandwidth and memory.
  • drawFrame runs on the UI thread — keep per-frame allocations low and cache expensive Skia objects (paragraphs, runtime effects) between frames.
  • The player owns the frame textures; don't hold on to VideoFrames across frames. Dispose any SkImage wrappers you create once drawn.
  • Re-creating the player (new composition object identity) is not free: memoize the composition and only rebuild it when playback inputs actually change.