본문 바로가기
React

리액트에서 카메라 사용법

by 붕어사랑 티스토리 2022. 12. 2.
반응형

https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia

 

MediaDevices.getUserMedia() - Web APIs | MDN

The MediaDevices.getUserMedia() method prompts the user for permission to use a media input which produces a MediaStream with tracks containing the requested types of media.

developer.mozilla.org

1. 개요

React에서 카메라를 사용하려면 getUserMedia() 함수를 사용하면 됩니다 허나 이 함수는 단순히 카메라만 사용하는것이 아닌 마이크 등 기기 내에 모든 Media 디바이스 정보들을 사용할 수 있습니다.

 

 

 

 

2. 카메라 열기

아래 코드는 카메라를 여는 예제입니다.

// Prefer camera resolution nearest to 1280x720.
const constraints = {
  audio: true,
  video: { width: 1280, height: 720 }
};

navigator.mediaDevices.getUserMedia(constraints)
  .then((mediaStream) => {
    const video = document.querySelector('video');
    video.srcObject = mediaStream;
    video.onloadedmetadata = () => {
      video.play();
    };
  })
  .catch((err) => {
    // always check for errors at the end.
    console.error(`${err.name}: ${err.message}`);
  });

 

여기서 주목할것은 getUserMeida에 들어가는 config 정보입니다.

 

 

 

 

 

width height 값 설정법

카메라를 열 때 width와 height값은 다음과 같이 주면됩니다. 이 값은 임으로 정할 수 없고 인풋을 주면 알아서 결정되어 올라옵니다.

 video: {
          width: { min: 720, max: 1440, ideal: 1440 },
          height: { min: 960, max: 1920, ideal: 1920 },
        },

 

 

 

 

3. 모바일에서 카메라 사용과 https 적용

모바일에서 카메라를 오픈할 경우 getUserMedia함수가 없다고 에러가 납니다. 이를 해결하기 위해서는 카메라를 여는 페이지가 https가 적용되어 있어야 합니다.

 

https를 적용하는 방법은 아주 다양합니다. 배포를 하는 경우라면 인증서를 사거나, AWS의 API Gateway나 로드밸런서를 이용하는 방법이 있습니다.

 

만약에 그냥 개발서버에서 간단하게 적용하고 싶다면 mkcert라는 프로그램을 이용하여 key.pem과 cert.pem을 만든 후 아래와 같이 리액트 .env 파일에 환경변수로 경로를 지정해주면 됩니다.

 

mkcert 사용법은 구글에 검색하면 많이 나오니 참고 부탁드립니다.

HTTPS=true
SSL_KEY_FILE=key.pem
SSL_CRT_FILE=cert.pem

 

 

 

 

후면 카메라 사용법

모바일 디바이스의 경우 기본적으로 카메라를 open하면 전면카메라가 실행됩니다. 후면카메라를 open하고 싶으면 다음과 같이 facingMode를 environment로 주면 됩니다.( 전면카메라의 경우 user로 값을 준다)

 

video: {
          width: { min: 720, max: 1440, ideal: 1440 },
          height: { min: 960, max: 1920, ideal: 1920 },
          facingMode: "environment",
        },

 

 

FrameRate 설정법

카메라에서 올라오는 프리뷰의 frame rate로 설정할 수 있습니다.

const constraints = {
  video: { frameRate: { ideal: 10, max: 15 } }
};

 

 

다른 디바이스 정보도 얻어오기

한 기기에 카메라가 여러개 달려있는데 그걸 사용하고 싶다면? enumerateDevices 함수를 이용합니다.

아래 코드 예제는 모든 카메라 정보를 가져와 그중에서 1번 카메라를 선택하는 예제입니다.

 

기기마다 카메라를 허용해주는 정도가 다르며, 아이폰12의 경우 광각카메라, 전면카메라만 지원하고 초광각은 지원 안하네요.

 

출저: https://stackoverflow.com/questions/16807133/select-the-camera-while-using-navigate-getusermedia

navigator.mediaDevices.enumerateDevices()
.then(devices => {
    var videoDevices = [0,0];
    var videoDeviceIndex = 0;
    devices.forEach(function(device) {
    console.log(device.kind + ": " + device.label +
        " id = " + device.deviceId);
    if (device.kind == "videoinput") {  
        videoDevices[videoDeviceIndex++] =  device.deviceId;    
    }
    });


    var constraints =  {width: { min: 1024, ideal: 1280, max: 1920 },
    height: { min: 776, ideal: 720, max: 1080 },
    deviceId: { exact: videoDevices[1]  } 
};
return navigator.mediaDevices.getUserMedia({ video: constraints });

})
.then(stream => {
    if (window.webkitURL) {
    video.src = window.webkitURL.createObjectURL(stream);
    localMediaStream = stream;
    } else if (video.mozSrcObject !== undefined) {
    video.mozSrcObject = stream;
    } else if (video.srcObject !== undefined) {
    video.srcObject = stream;
    } else {
    video.src = stream;
    }})
.catch(e => console.error(e));

 

 

4. 카메라 프레임에 콜백 달아주기

 

카메라 프레임이 렌더링 될 때 마다 callback을 달아 줄 수 있습니다. 이 콜백은 oneShot으로 동작하며, 계속해서 다음프레임에 콜백을 달아주고 싶으면 재귀 형태로 다시 콜백을 달아주어야 합니다.

const videoCallback = (now, meta)=>{
      console.log(now);
      video.requestVideoFrameCallback(videoCallback)
    }
video.requestVideoFrameCallback(videoCallback);

 

허나 이건 video 엘리먼트에 렌더링 되기 이전이 아닌, 렌더링 되기 이후로 추정되며, 렌더링 되기 이전에 전처리를 해주고 싶으면 다른방법을 찾아야 할 것으로 보입니다.

 

 

 

MediaStreamTrackProcessor & MediaStreamTrackGenerator

프레임을 전처리해주는 방법을 찾아보니 위 API를 발견하였습니다. 허나 사파리에서는 지원하지 않고 예제코드 적용해 보았는데 잘 동작하지 않네요...

 

아래는 그 예시코드 입니다.

https://webrtc.github.io/samples/src/content/insertable-streams/video-processing/

 

const stream = await getUserMedia({ video: true });
const videoTrack = stream.getVideoTracks()[0];

const trackProcessor = new MediaStreamTrackProcessor({ track: videoTrack });
const trackGenerator = new MediaStreamTrackGenerator({ kind: 'video' });

const transformer = new TransformStream({
  async transform(videoFrame, controller) {
    const barcodes = await detectBarcodes(videoFrame);
    const newFrame = highlightBarcodes(videoFrame, barcodes);
    videoFrame.close();
    controller.enqueue(newFrame);
  },
});

trackProcessor.readable.pipeThrough(transformer).pipeTo(trackGenerator.writable);

const videoBefore = document.getElementById('video-before');
const videoAfter = document.getElementById('video-after');
videoBefore.srcObject = stream;
const streamAfter = new MediaStream([trackGenerator]);
videoAfter.srcObject = streamAfter;

 

반응형

댓글