skip to Main Content

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.

2

Answers


  1. To achieve the behavior you described where the video should play from the end of the previous component to the start of the current component when moving backward, you can make some modifications to your VideoPlayer component. Specifically, you need to update the logic in the useEffect that handles moving from a higher component to a lower one.

    You can do this by calculating the time to play from the end of the previous component to the start of the current component and then continue playing from there. Here’s the modified code:

    const VideoPlayer = ({ frames, currentComponent, prevComponent, startTime, endTime, idleTime }) => {
      const [currentTime, setCurrentTime] = useState(startTime);
      const playerRef = useRef(null);
    
      useEffect(() => {
        if (currentTime >= idleTime) {
          playerRef.current.pause();
        }
      }, [currentTime]);
    
      useEffect(() => {
        if (prevComponent && prevComponent > currentComponent) {
          // Calculate the time to play from the end of the previous component to the start of the current component.
          const previousEnd = frames.find((item) => item.id === prevComponent).end;
          const currentStart = startTime;
          const timeToPlay = currentStart - previousEnd;
    
          // Play from the calculated time.
          if (timeToPlay > 0) {
            playerRef.current.play();
            playerRef.current.seek(previousEnd);
            setTimeout(() => {
              playerRef.current.pause();
              playerRef.current.seek(currentStart);
              playerRef.current.play();
            }, timeToPlay * 1000);
          }
        }
      }, [currentTime, currentComponent, prevComponent, frames, startTime]);
    
      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>
      );
    };
    
    Login or Signup to reply.
  2. 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]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search