My-world 개발 보고서 : 거울앱, webcam on/off

강원지·2023년 5월 24일
0

react-webcam

설치

npm install react-webcam

사용법

기본 사용법은 다음과 같다.

import React from "react";
import Webcam from "react-webcam";

const WebcamComponent = () => <Webcam />;

이렇게 사용하면 거울 모달창을 닫아도 webcam은 켜져있다. webcam을 끄는 기능을 추가해주겠다.

webcam 끄기

MediaStreamTrack: stop() method

react-webcam 라이브러리에서는 끄는 기능을 제공하지 않아 따로 기능을 추가하였다.

우선 모질라에서 MediaStream의 상속을 받는 객체 videoElem의 소스 스트림을 정지시키고 해제하는 코드를 찾을 수 있었다.

function stopStreamedVideo(videoElem) {
  const stream = videoElem.srcObject;
  const tracks = stream.getTracks();

  tracks.forEach((track) => {
    track.stop();
  });

  videoElem.srcObject = null;
}

MediaStream이란

오디오, 비디오 같은 미디어 스트림을 다루는 객체이다.

소스스트림이란

미디어 요소(예: 비디오 요소, 오디오 요소)의 입력 소스로 사용되는 데이터 스트림입니다. 일반적으로 웹캠, 마이크, 화면 공유 등과 같은 입력 장치에서 제공되는 실시간 비디오 또는 오디오 스트림을 의미합니다.

react-Webcam 끄기

위의 두 코드를 합치고 기타 설정을 적용해보았다.

Mirror.tsx*

export const Mirror = () => {
  const webcamRef = useRef<Webcam | null>(null);
  
  const stopWebCam = () => {
    if (webcamRef.current?.video) {
      const stream = webcamRef.current?.video.srcObject as MediaStream;
      const tracks = stream.getTracks();
      tracks.forEach((track) => track.stop());
      webcamRef.current.video.srcObject = null;
    }
  };

  return (
    <>
      <button onClick={stopWebCam}>끄기</button>
      <Webcam
        ref={webcamRef}
        audio={false}
        mirrored={true}
        screenshotFormat="image/jpeg"
      ></Webcam>
    </>
  );
};

버튼으로 webcam을 끄는 과정이 불필요한 것 같아 모달창을 닫음과 동시에 webcam이 꺼지도록 코드를 수정해보겠다.

모달창 닫으면서 webcam 끄기

webcamRef는 useRef로 관리하는 변수로 외부로 export가 되지 않기 때문에 webcamRef를 외부에서 접근할 방법을 찾아야 한다.

해결방법

  1. setWebcamRef()을 통해 기존 Webcam 모듈에서 webcamRef에 해당하는 변수를 전달받아 저장하고
  2. 모달창의 layout을 관리하는 모듈에서 stopWebCam()을 호출하여 Webcam을 종료한다.

WebcamUtils.ts

type WebcamRefType = React.MutableRefObject<Webcam | null>;

let webcamRef: WebcamRefType = { current: null };

export const setWebcamRef = (ref: WebcamRefType) => {
  webcamRef = ref;
};

export const stopWebCam = () => {
  if (webcamRef?.current?.video) {
    const stream = webcamRef.current.video.srcObject as MediaStream;
    const tracks = stream.getTracks();
    tracks.forEach((track) => track.stop());

    webcamRef.current.video.srcObject = null;
  }
};

Mirror.tsx

export const Mirror = () => {
  const webcamRef = useRef(null);

  useEffect(() => {
    setWebcamRef(webcamRef);
  }, []);

  const videoConstraints = {
    width: 2480,
    height: 1440,
    facingMode: "user",
  };
  return (
    <>
      <Webcam
        audio={false}
        ref={webcamRef}
        mirrored={true}
        screenshotFormat="image/jpeg"
        style={{
          position: "absolute",
          textAlign: "center",
          height: "100%",
          width: "100%",
          objectFit: "cover",
        }}
        videoConstraints={videoConstraints}
      ></Webcam>
    </>
  );
};

ModalLayout.tsx

현재 모달의 name이 mirror일 때 stopWebCam()을 수행한다.

...
  const handleModal = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    e.preventDefault();
    dispatch(closeModal(""));
    if (modal?.name === "mirror") {
      stopWebCam();
    }
  };
...
  <button onClick={handleModal}>X</button>
...

결과물 캡처

0개의 댓글