이번주 실전프로젝트를 진행하면서 제일 힘들었던점은 영상을 녹화할때 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)으로 설정해두자