@azzapp/react-native-skia-video
Version:
video support for react-native-skia
106 lines (104 loc) • 3.15 kB
JavaScript
;
import { Skia } from '@shopify/react-native-skia';
import { useSharedValue, useFrameCallback, runOnUI } from 'react-native-reanimated';
import { useCallback, useEffect, useMemo, useState } from 'react';
import RNSkiaVideoModule from './RNSkiaVideoModule';
import useEventListener from './utils/useEventListener';
import { PixelRatio } from 'react-native';
/**
* A hook that creates a video composition player.
*/
export const useVideoCompositionPlayer = ({
composition,
drawFrame,
beforeDrawFrame,
afterDrawFrame,
width,
height,
autoPlay = false,
isLooping = false,
onReadyToPlay,
onComplete,
onError
}) => {
const [isErrored, setIsErrored] = useState(false);
const framesExtractor = useMemo(() => {
if (composition && !isErrored) {
return RNSkiaVideoModule.createVideoCompositionFramesExtractor(composition);
}
return null;
}, [isErrored, composition]);
useEffect(() => {
runOnUI(() => {
framesExtractor?.prepare();
})();
}, [framesExtractor]);
const currentFrame = useSharedValue(null);
useEffect(() => () => {
currentFrame.value = null;
framesExtractor?.dispose();
}, [currentFrame, framesExtractor]);
const retry = useCallback(() => {
setIsErrored(false);
}, []);
const errorHandler = useCallback(error => {
onError?.(error, retry);
setIsErrored(true);
}, [onError, retry]);
useEffect(() => {
if (framesExtractor) {
framesExtractor.isLooping = isLooping;
}
}, [framesExtractor, isLooping]);
useEventListener(framesExtractor, 'ready', onReadyToPlay);
useEventListener(framesExtractor, 'complete', onComplete);
useEventListener(framesExtractor, 'error', errorHandler);
useEffect(() => {
if (autoPlay) {
framesExtractor?.play();
}
}, [framesExtractor, autoPlay]);
const surfaceSharedValue = useSharedValue(null);
const pixelRatio = PixelRatio.get();
useFrameCallback(() => {
'worklet';
if (!framesExtractor) {
return;
}
let surface = surfaceSharedValue.value;
if (!surface) {
surface = Skia.Surface.MakeOffscreen(width * pixelRatio, height * pixelRatio);
surfaceSharedValue.value = surface;
}
if (!surface) {
console.warn('Failed to create surface');
return;
}
const canvas = surface.getCanvas();
const context = beforeDrawFrame?.();
drawFrame({
canvas,
context,
videoComposition: composition,
currentTime: framesExtractor.currentTime,
frames: framesExtractor.decodeCompositionFrames(),
width: width * pixelRatio,
height: height * pixelRatio
});
surface.flush();
const previousFrame = currentFrame.value;
try {
currentFrame.value = Skia.Image.MakeImageFromNativeTextureUnstable(surface.getNativeTextureUnstable(), width * pixelRatio, height * pixelRatio);
} catch (error) {
console.warn('Failed to create image from texture', error);
return;
}
previousFrame?.dispose();
afterDrawFrame?.(context);
}, true);
return {
currentFrame,
player: framesExtractor
};
};
//# sourceMappingURL=videoCompositionPlayer.js.map