웹브라우저에서 동작하는 녹화앱 만들기

JUNGDU JANG (AboutJang)
WATCHA
Published in
9 min readAug 13, 2021

--

안녕하세요. 왓챠 FE팀에서 웹 프론트엔드 개발을 하는 프레드입니다.

최신 웹브라우저에서는 오디오, 이미지, 비디오 데이터를 저장하고 조작할 수 있는 API를 제공합니다. 이번 글에서는 웹브라우저에서 제공하는 API를 사용하여 간단하게( 100줄 이내의 자바스크립트 코드) 녹화 기능을 구현하는 방법을 소개합니다.

예제를 통해서 아래의 이미지와 같은 페이지를 작성합니다.

구현할 기능

  • 카메라에 찍히는 화면을 실시간으로 확인
  • 카메라에 찍히는 화면을 녹화 (녹화 시작, 녹화 종료)
  • 녹화된 영상 미리보기
  • 녹화된 영상을 다운로드

결과물이 궁금하시면 아래의 링크를 클릭해 주세요.

(카메라 사용 권한으로 얻는 데이터를 포함한 어떠한 사용자의 데이터도 외부 서버로 전송하지 않습니다.)

동작을 위해서는 내장된 카메라나 연결된 카메라가 필요합니다.
chrome, firefox, edge 최신 버전에서 동작하며 다른 브라우저나 낮은 버전에서 기능이 동작하지 않을 수 있습니다.

사용 방법

페이지로 접속하면 카메라의 사용 권한을 요청합니다. 권한을 수락하면 바로 카메라의 화면을 페이지 내에서 확인하실 수 있습니다. 녹화 시작 버튼을 누르면 녹화가 시작되고 녹화 종료 버튼을 누르면 녹화가 종료되면서 미리보기에 녹화된 영상을 설정합니다. 녹화된 영상을 확인하려면 미리보기에서 재생 버튼을 클릭합니다. 다운로드 버튼을 누르면 다운로드가 시작됩니다.

기능 구현

기능 구현 과정은 다음과 같은 순서로 이루어집니다.

  1. 카메라로 부터 입력 받기
  2. 카메라로 받은 입력을 HTMLVideoElement를 통해서 실시간으로 출력
  3. 카메라로 부터 받은 입력을 녹화
  4. 녹화된 영상 미리보기
  5. 녹화된 영상 다운로드

카메라로 부터 입력 받기

MediaDevie.getUserMedia 메서드를 통해서 유저의 카메라, 마이크와 같은 기기로부터 입력을 받을 수 있습니다. getUserMedia 함수를 호출하면 사용자에게 미디어 입력장치의 사용 권한을 요청합니다. 사용자가 권한 요청을 수락하면 비디오 트랙을 포함한 MeidaStream을 전달하는 Promise 객체를 리턴합니다.

전달받은 MediaStream을 활용하는 부분이 아직 구현되어있지 않기 때문에 아무 일도 일어나지 않습니다. 콘솔 창을 열어보면 전달받은 MediaStream객체의 정보를 확인할 수 있습니다.

카메라로 받은 입력 출력

녹화할 때 카메라의 화면을 바로 확인할 수 있도록 웹페이지에 출력하는 기능을 추가하겠습니다. HTMLVideoElement는 srcObject 속성을 통해서 MediaStream을 source 로 설정할 수 있습니다. 메타데이터가 로드되는 onloadmetadata 이벤트 호출 이후 HTMLVideoElement.play 메서드를 호출하여 MediaStream을 실시간으로 웹페이지에서 보여줍니다.

카메라로 부터 받은 입력을 녹화

이번 과정에서는 MediaStream의 데이터를 캡처하고 캡처한 영상을 녹화 미리보기 영상 재생, 녹화 영상 다운로드에 활용할 URL을 얻는 것이 목적입니다.

MediaStream Recording API는 MediaStream이나 HTMLMediaElement(HTMLCanvasElement, HTMLVideoElement, HTMLAudioElement가 이 인터페이스를 상속받습니다) 로 부터 전달되는 데이터를 캡쳐하는 기능을 제공합니다.

Blob(Binary Large Object)은 미가공 데이터를 처리하거나 간접 참조하는 객체입니다. 텍스트와 이진 데이터의 형태로 읽을 수 있으며, Blob은 이진 데이터를 활용하는 다양한 자바스크립트 API에서는 데이터 교환 메커니즘의 중요한 매체로 제공됩니다. 생성한 영상 파일의 Blob을 URL로 참조합니다.

녹화 기능 구현 과정

  1. MediaStream을 매개변수로 MediaRecorder 생성자를 호출합니다. 생성자의 다른 매개변수로 mimeType을 설정하는데, 브라우저마다 지원하는 mimeType에는 차이가 있습니다. mimeType을 설정하기 전에 MediaRecorder.isTypeSupported로 브라우저가 녹화를 지원하는 MIME type인지 확인할 수 있습니다.
  2. MediaRecorder.ondataavailable 이벤트가 호출될 때마다 전달받는 영상 데이터를 배열에 쌓도록 핸들러를 작성하여 등록합니다. ondataavailable 이벤트는 데이터가 준비될 때마다 호출되며, 이벤트는 미디어 데이터를 data 속성으로 가집니다.
  3. 녹화를 중지하면 MediaRecorder.onstop 이벤트가 호출됩니다. 이벤트가 호출되었을 때 2번 과정에서 모인 영상 데이터로 Blob을 생성하는 핸들러를 onstop 이벤트에 등록합니다. 생성된 Blob을 매개변수로 URL.createObjectURL 메서드를 호출하면 URL로 활용할 수 있도록 string을 반환합니다. 반환받은 값은 이후 과정에서 다운로드, 미리보기 기능에 사용됩니다.
  4. MediaRecorder.start() 를 호출하여 녹화 시작
  5. 녹화 중지 버튼을 누르면 MediaRecorder.stop()을 호출하여 녹화 중지

녹화를 중지하면 recordedMediaUrl에 녹화된 영상을 참조하는 url이 할당됩니다.

예제에서 추가하지 않았지만 위의 코드에서 주의해야 할 점은 createObjectURL 메서드를 호출로 생성한 url을 더 이상 사용하지 않을 때 revokeObjectURL메소드를 호출하여 생성된 url이 참조하는 object가 할당된 메모리를 해제해야 합니다. 그렇지 않으면 메모리 누수 문제가 발생할 수 있습니다.

녹화된 영상 미리보기

이전 과정에서 recordedMediaUrl을 얻었으니 일반적인 동영상 파일의 url을 사용하는 방식과 같은 방식으로 사용할 수 있습니다. 할당된 recordedMediaUrl 을 녹화 영상 미리보기 용도로 추가한HTMLVideoElement의 src 속성으로 설정합니다. 미리보기 비디오의 재생 버튼을 누르면 미리보기 영상이 재생됩니다.

녹화된 영상 다운로드

다운로드 버튼 클릭 시 recordedMediaUrl로 다운로드를 요청하는 기능을 추가합니다. 다운로드 버튼을 누르면 video.webm이라는 파일명으로 다운로드를 시작합니다.

다양한 입력의 MediaStream

카메라의 입력 뿐만 아니라 마이크, PC의 화면, 웹페이지 내 Canvas에 렌더링되는 콘텐츠와 같은 다양한 입력도 MediaStream으로 얻을 수 있습니다.

스크린은 MediaDevices.getDisplayMedia() 메서드를 통해서, HTMLCanvas에 렌더링 되는 콘텐츠는 HTMLMediaElement.captureStream() 메서드를 통해서 MediaStream을 얻습니다. 얻어진 MediaStream은 녹화 기능을 추가할 때 썼던 방식과 동일한 방식으로 기능을 추가할 수 있습니다.

마치며

요즘 화상으로 회의가 진행되는 경우가 많은데 Google Meets 화상 회의 서비스를 주로 사용하고 있습니다. Google Meets에서 녹화 기능을 제공하는 것을 보고 “어떻게 한 거지?”라는 궁금증이 생겼고 궁금증을 해소하기 위해 다시 구글의 힘을 빌렸습니다. 구글링하면서 그동안 몰랐던 그리고 개인적으로 흥미로웠던 브라우저의 API를 주제로 글을 쓰게 되었습니다. 브라우저에 또 어떤 기능들이 추가될지 앞으로의 발전이 기대됩니다.

Resources

  • 자바스크립트 완벽 가이드(코뿔소 책)

--

--