항해99-WIL-react-실전-webcam

장산·2022년 7월 4일
0

React

목록 보기
9/12

이번주 실전프로젝트를 진행하면서 제일 힘들었던점은 영상을 녹화할때 30초타이머를 설정해서 자동 녹화 종료가 되게 해야했다. 비디오 라이브러리는 recordrtc,video-react를 사용했다.

const WebCam: FC = () => {
  const navigate = useNavigate();
  const videoRef = useRef<HTMLVideoElement>(null);
  //take picture
  const photoRef = useRef<any>(null);
  const [hasPhoto, setHasPhoto] = useState(false);
  //recordrtc
  const [stream, setStream] = useState<MediaStream | null>();
  const [recorder, setRecorder] = useState<RecordRTC.RecordRTCPromisesHandler | null>();
  const [videoBlob, setVideoUrlBlob] = useState<Blob | null>();
  //30초 타이머
  const [timeLeft, setTimeLeft] = React.useState<number>(30);
  const minutes: any = padTime(Math.floor(timeLeft / 60));
  const seconds = padTime(timeLeft - minutes * 60);
  const intervalRef: any = React.useRef(null);
  //화면에 틀자마자 webcam 호출
  useEffect(() => {
    getVideo();
  }, [videoRef]);
  const getVideo = () => {
    navigator.mediaDevices
      .getUserMedia({
        video: { width: 600, height: 600 },
      })
      .then((stream) => {
        const video: any = videoRef.current;
        video.srcObject = stream;
        video.play();
      })
      .catch((err) => {
        console.error(err);
      });
  };
  //사진 촬영
  const takePhoto = () => {
    const width = 600;
    const height = width / (16 / 9);

    const video = videoRef.current;
    const photo: any = photoRef.current;
    photo.width = width;
    photo.height = height;

    const ctx = photo.getContext("2d");
    ctx.drawImage(video, 0, 0, width, height);
    setHasPhoto(true);
  };
  //비디오 녹화 시작버튼
  const startRecoding = async () => {
    const mediaDevices = navigator.mediaDevices;
    const stream: MediaStream = await mediaDevices.getUserMedia({ video: true, audio: true });
    const recorder: RecordRTCPromisesHandler = new RecordRTCPromisesHandler(stream, {
      type: "video",
    });
    await recorder.startRecording();
    setRecorder(recorder);
    setStream(stream);
    setVideoUrlBlob(null);
    // 시작버튼 누르면 30초 타이머
    intervalRef.current = setInterval(() => {
      setTimeLeft((timeLeft: number) => {
        if (timeLeft >= 1) {
          return timeLeft - 1;
        } else {
          return 0;
        }
      });
    }, 1000);
  };
  //비디오 녹화 종료
  const stopRecording: any = async () => {
    if (recorder) {
      await recorder.stopRecording();
      const blob: Blob = await recorder.getBlob();
      (stream as any).stop();
      setVideoUrlBlob(blob);
      setStream(null);
      setRecorder(null);
      //정지버튼 누르면 타이머 초기화 및 다시 30초 세팅
      clearInterval(intervalRef.current);
      setTimeLeft(30);
    }
  };
  //녹화 시작 후 30초뒤에 자동 종료
  useEffect(() => {
    const timeOut = setTimeout(stopRecording, 2000);
    return () => {
      clearTimeout(timeOut);
    };
  });

녹화 시작 버튼을 누르면 30초가 카운트 다운되는데 이때 setTimeout(stopRecording, 30000)만 입력하니 녹화 종료가 30초동안 반복되는 리렌더링 현상을 겪었다.그래서 useEffect를 사용하니 녹화시간이 1분이 되어버렸다.
이틀동안 찾은결과 settimout하고 setInterval이 합쳐져서 30초+30초=1분 되었다는걸 알고 settimeout을 2초로 바꾸어주고 cleartimerdout을 사용해서 타이머를 초기화 시켰더니 해결되었다.
참고로 settimeout 시간을 타이머가 끝나고 1초뒤로 수정해두면 타이머 시간이 되기전에 자동종료되는 버그가 생긴다. 그래서 settimeout를 1.1초(1100)으로 설정해두자

profile
신입 개발자

0개의 댓글