UNPKG

@remotion/player

Version:

React component for embedding a Remotion preview into your app

158 lines (157 loc) • 5.68 kB
import { useCallback, useContext, useMemo, useRef, useState } from 'react'; import { Internals } from 'remotion'; import { PlayerEventEmitterContext } from './emitter-context.js'; export const usePlayer = () => { var _a; const [playing, setPlaying, imperativePlaying] = Internals.Timeline.usePlayingState(); const [hasPlayed, setHasPlayed] = useState(false); const frame = Internals.Timeline.useTimelinePosition(); const playStart = useRef(frame); const setFrame = Internals.Timeline.useTimelineSetFrame(); const setTimelinePosition = Internals.Timeline.useTimelineSetFrame(); const audioContext = useContext(Internals.SharedAudioContext); const { audioAndVideoTags } = useContext(Internals.Timeline.TimelineContext); const frameRef = useRef(frame); frameRef.current = frame; const video = Internals.useVideo(); const config = Internals.useUnsafeVideoConfig(); const emitter = useContext(PlayerEventEmitterContext); const lastFrame = ((_a = config === null || config === void 0 ? void 0 : config.durationInFrames) !== null && _a !== void 0 ? _a : 1) - 1; const isLastFrame = frame === lastFrame; const isFirstFrame = frame === 0; if (!emitter) { throw new TypeError('Expected Player event emitter context'); } const bufferingContext = useContext(Internals.BufferingContextReact); if (!bufferingContext) { throw new Error('Missing the buffering context. Most likely you have a Remotion version mismatch.'); } const { buffering } = bufferingContext; const seek = useCallback((newFrame) => { if (video === null || video === void 0 ? void 0 : video.id) { setTimelinePosition((c) => ({ ...c, [video.id]: newFrame })); } frameRef.current = newFrame; emitter.dispatchSeek(newFrame); }, [emitter, setTimelinePosition, video === null || video === void 0 ? void 0 : video.id]); const play = useCallback((e) => { if (imperativePlaying.current) { return; } setHasPlayed(true); if (isLastFrame) { seek(0); } /** * Play silent audio tags to warm them up for autoplay */ if (audioContext && audioContext.numberOfAudioTags > 0 && e) { audioContext.playAllAudios(); } /** * Play audios and videos directly here so they can benefit from * being triggered by a click */ audioAndVideoTags.current.forEach((a) => a.play()); imperativePlaying.current = true; setPlaying(true); playStart.current = frameRef.current; emitter.dispatchPlay(); }, [ imperativePlaying, isLastFrame, audioContext, setPlaying, emitter, seek, audioAndVideoTags, ]); const pause = useCallback(() => { if (imperativePlaying.current) { imperativePlaying.current = false; setPlaying(false); emitter.dispatchPause(); } }, [emitter, imperativePlaying, setPlaying]); const pauseAndReturnToPlayStart = useCallback(() => { if (imperativePlaying.current) { imperativePlaying.current = false; frameRef.current = playStart.current; if (config) { setTimelinePosition((c) => ({ ...c, [config.id]: playStart.current, })); setPlaying(false); emitter.dispatchPause(); } } }, [config, emitter, imperativePlaying, setPlaying, setTimelinePosition]); const videoId = video === null || video === void 0 ? void 0 : video.id; const frameBack = useCallback((frames) => { if (!videoId) { return null; } if (imperativePlaying.current) { return; } setFrame((c) => { var _a, _b; const prev = (_b = (_a = c[videoId]) !== null && _a !== void 0 ? _a : window.remotion_initialFrame) !== null && _b !== void 0 ? _b : 0; return { ...c, [videoId]: Math.max(0, prev - frames), }; }); }, [imperativePlaying, setFrame, videoId]); const frameForward = useCallback((frames) => { if (!videoId) { return null; } if (imperativePlaying.current) { return; } setFrame((c) => { var _a, _b; const prev = (_b = (_a = c[videoId]) !== null && _a !== void 0 ? _a : window.remotion_initialFrame) !== null && _b !== void 0 ? _b : 0; return { ...c, [videoId]: Math.min(lastFrame, prev + frames), }; }); }, [videoId, imperativePlaying, lastFrame, setFrame]); const returnValue = useMemo(() => { return { frameBack, frameForward, isLastFrame, emitter, playing, play, pause, seek, isFirstFrame, getCurrentFrame: () => frameRef.current, isPlaying: () => imperativePlaying.current, isBuffering: () => buffering.current, pauseAndReturnToPlayStart, hasPlayed, remotionInternal_currentFrameRef: frameRef, }; }, [ frameBack, frameForward, isLastFrame, emitter, playing, play, pause, seek, isFirstFrame, pauseAndReturnToPlayStart, hasPlayed, imperativePlaying, buffering, ]); return returnValue; };