UNPKG

@azzapp/react-native-skia-video

Version:
95 lines (91 loc) 2.74 kB
"use strict"; import { runOnJS } from 'react-native-reanimated'; import { Platform } from 'react-native'; import { Skia, BlendMode } from '@shopify/react-native-skia'; import RNSkiaVideoModule from './RNSkiaVideoModule'; import { runOnNewThread } from './utils/thread'; const Promise = global.Promise; const OS = Platform.OS; /** * Exports a video composition to a video file. * * @returns A promise that resolves when the export is complete. */ export const exportVideoComposition = async ({ videoComposition, drawFrame, beforeDrawFrame, afterDrawFrame, onProgress, ...options }) => new Promise((resolve, reject) => { runOnNewThread(() => { 'worklet'; let surface = null; let frameExtractor = null; let encoder = null; const { width, height } = options; try { surface = Skia.Surface.MakeOffscreen(width, height); if (!surface) { throw new Error('Failed to create Skia surface'); } encoder = RNSkiaVideoModule.createVideoEncoder(options); encoder.prepare(); frameExtractor = RNSkiaVideoModule.createVideoCompositionFramesExtractorSync(videoComposition); frameExtractor.start(); const nbFrames = videoComposition.duration * options.frameRate; const canvas = surface.getCanvas(); const clearColor = Skia.Color('#00000000'); for (let i = 0; i < nbFrames; i++) { const currentTime = i / options.frameRate; const frames = frameExtractor.decodeCompositionFrames(currentTime); canvas.drawColor(clearColor, BlendMode.Clear); const context = beforeDrawFrame?.(); drawFrame({ context, canvas, videoComposition, currentTime, frames, width: options.width, height: options.height }); surface.flush(); // On iOS and macOS, the first flush is not synchronous, // so we need to wait for the next frame if (i === 0 && (OS === 'ios' || OS === 'macos')) { RNSkiaVideoModule.usleep?.(1000); } const texture = surface.getNativeTextureUnstable(); encoder.encodeFrame(texture, currentTime); afterDrawFrame?.(context); if (onProgress) { runOnJS(onProgress)({ framesCompleted: i + 1, nbFrames }); } } } catch (e) { runOnJS(reject)(e); return; } finally { frameExtractor?.dispose(); surface?.dispose(); } try { encoder.finishWriting(); } catch (e) { runOnJS(reject)(e); return; } finally { encoder?.dispose(); } runOnJS(resolve)(); }); }); //# sourceMappingURL=exportVideoComposition.js.map