React 웹캠 - 2. getUserMedia
React 웹캠 시리즈입니다.
- React 웹캠 - 1. Promise 비동기 함수의 이해
- React 웹캠 - 2. getUserMedia
- React 웹캠 - 3. Canvas
- React 웹캠 - 4. Select webcam
오늘은 웹캠을 통해 영상을 보여주는 간단한 React 앱을 만들어보겠습니다.
예제 코드: Sample Code
소스 위치: src/tutorial/Tutorial03-Webcam.js
navigator.mediaDevices.getUserMedia()
단순히 navigator.mediaDevices.getUserMedia()만 호출하면 웹캠을 사용할 수 있습니다. 함수 인자로는 video를 쓸 것인지 audio를 쓸 것인지 true/false 값을 넣어주는 게 전부입니다.
Tip. 좀 더 자세히 알아보자면, 이 구문에서 navigator란 브라우저에서 기본으로 제공되는 Web API 인터페이스 객체인데요, 브라우저를 사용하는 user agent의 상태와 신원 정보를 나타냅니다. 뒤이어 나오는 mediaDevices은 카메라, 마이크 등과 같이 현재 연결된 미디어 장치에 접근할 수 있는 객체입니다. getUserMedia()는 미디어 접근을 요청하는 함수로 Promise(비동기 작업의 미래 결과)를 리턴합니다.
getUserMedia()를 사용하여 카메라를 불러오는 간단한 React 앱을 만들어봅시다.
import React from 'react';
import { Button } from 'reactstrap';
const getWebcam = (callback) => {
try {
const constraints = {
'video': true,
'audio': false
}
navigator.mediaDevices.getUserMedia(constraints)
.then(callback);
} catch (err) {
console.log(err);
return undefined;
}
}
const Styles = {
Video: { width: "100%", height: "100%", background: 'rgba(245, 240, 215, 0.5)' },
None: { display: 'none' },
}
웹캠을 가져오는 부분은 React와는 무관하게 javascript 코드이므로 별도 함수로 정의하는 것이 깔끔하겠죠? constraints는 좀 더 많은 옵션이 있지만, 기본적으로 video, audio만 이해하고 넘어갑시다. 말 그대로 위 코드는 audio를 닫겠다는 의미입니다. 주의! 마이크 입력을 사용할 경우(audio : true), PC 마이크 입력때문에 하울링이 생길 수 있으니 볼륨을 작게 해두세요.
Styles는 video 엘리먼트의 크기 속성을 나타내려고 편의상 정의한 함수입니다. CSS 스타일을 적용하는 방법은 다양한데, 지금 이 컴포넌트에서만 사용하는 스타일이 몇 개 있는 경우라면 이런 방법도 좋겠지요. 이제 나머지 React 컴포넌트 TestOverlay 코드 부분을 보겠습니다.
function TestOverlay() {
const [playing, setPlaying] = React.useState(undefined);
const videoRef = React.useRef(null);
React.useEffect(() => {
getWebcam((stream => {
setPlaying(true);
videoRef.current.srcObject = stream;
}));
}, []);
const startOrStop = () => {
if (playing) {
const s = videoRef.current.srcObject;
s.getTracks().forEach((track) => {
track.stop();
});
} else {
getWebcam((stream => {
setPlaying(true);
videoRef.current.srcObject = stream;
}));
}
setPlaying(!playing);
}
return (<>
<div style={{ width: '100vw', height: '100vh', padding: '3em' }}>
<video ref={videoRef} autoPlay style={Styles.Video} />
<Button color="warning" onClick={() => startOrStop()}>{playing ? 'Stop' : 'Start'} </Button>
</div >
</>);
}
export default TestOverlay;
코드 순서대로 설명하자면, 우선 playing이라는 state를 사용해서 웹캠 입력을 토글링합니다. useEffect(..., [ ]) 구문은 클래스의 componentDidMount()에 해당, 즉 컴포넌트가 올라왔을 때 최초 1회 호출되는 부분으로, getWebcam()을 이 안에서 호출했습니다. getWebcam(callback) 인자로 넘겨준 콜백은 playing state를 true로 하고 스트림을 이 컴포넌트의 <video> 태그 소스로 넣어주는 구문입니다.
useRef()를 사용하면 return()으로 렌더링하는 엘리먼트들을 참조할 수 있고 이때 참조된 객체의 .current. 속성을 이용해서 사용합니다. startOrStop()이라는 함수를 만들어 웹캠을 켜고 끌 수 있도록 했으며, 이를 버튼에 연동했습니다. playing state를 이용해서 버튼 텍스트가 바뀌도록 했고요.
쉽죠? 실행해 봅시다. 결과 화면에는 제 얼굴이 나오기 때문에 스크린샷은 매너스킵합니다.