Search code examples
javascriptreactjsvideo-reactjs

How to play video till one point and move to another frame in React


I have a React project where I'm having a slider between 0 and 700 and depending on which step is chosen it gets value between 1 and 8 (so 700 is obviously 8).

 <div className={styles.slider_container}>
                    <input type='range' className={styles.slider} step={100} min={0} max={700} value={value} onChange={(e) => setValue(parseInt(e.target.value))} />
                </div>

I also have an frames array which consists of bunch of objects which look like:

    const [frames, setFrames] = useState([
        {
            id: 1,
            title: 'Touch',
            start: 0,
            idle: 5.82,
            end: 7.10,
        },
        {
            id: 2,
            title: 'Display',
            start: 7.11,
            idle: 8.5,
            end: 10.12,
        },
        ...
    ];

and I call my VideoPlayer component as:

<div className={styles.content}>
                <VideoPlayer frames={frames} currentComponent={selectedComponent} prevComponent={prevComponent} startTime={frames.find((item) => item.id === selectedComponent).start} endTime={frames.find((item) => item.id === selectedComponent).end} idleTime={frames.find((item) => item.id === selectedComponent).idle} />
            </div>

VideoPlayer component is just using react-video library to display the video and play/pause/seek through it. and it is just like:


 const [currentTime, setCurrentTime] = useState(startTime);
    const playerRef = useRef(null);

    useEffect(() => {
        if (currentTime >= idleTime) {
            playerRef.current.pause();
        }
    }, [currentTime]);

    useEffect(() => {
        if (prevComponent) {

            if (prevComponent < currentComponent) {
                const time = (frames.find(item => item.id === prevComponent).end); // endTime of previous component;
                if (currentTime <= time) {
                    playerRef.current.play();
                    if (time - currentTime <= 0.3) {
                        playerRef.current.pause();
                        playerRef.current.seek(startTime);
                        playerRef.current.play();
                    }
                }
            }
        }
    }, [currentTime, currentComponent]);


    useEffect(() => {
        if (prevComponent > currentComponent) {
            playerRef.current.seek(startTime);
            playerRef.current.play();
        }
    }, [currentComponent]);

    return (
        <Player
            ref={playerRef}
            autoPlay
            startTime={0}
            muted={true}
            onTimeUpdate={(e) => {
                setCurrentTime(parseFloat(e.target.currentTime));
            }}
        >
            <source src="./video.mp4" style={{ height: '100vh' }} />
            <ControlBar autoHide={false} disableCompletely={true} disableDefaultControls={true} />
        </Player>

It works fine with going forward (I mean from step 2 to step 3 or step 4), but I have a problem in

    useEffect(() => {
        if (prevComponent > currentComponent) {
            playerRef.current.seek(startTime);
            playerRef.current.play();
        }
    }, [currentComponent]);

where if I select a component (or step) 2 after step 3 (if we go back), it should play the video till endTime of the prevComponent and then just back to startTime of currentComponent and continue playing till idleTime of the currentComponent.


Solution

  • I would apply the while loop to if (prevComponent > currentComponent) condition, so it would just play the video till the difference between time and currentTime is less or equal to zero, if so, just break out from the loop and then use seek() function to jump to another frame/time you want.

        useEffect(() => {
            if (prevComponent > currentComponent) {
                while(time - currentTime > 0) {
                    playerRef.current.play();
                }
                playerRef.current.seek(startTime);
            }
        }, [currentTime, currentComponent]);