티스토리 뷰
[WillBe 화상 면접 커뮤니티] WebRTC, codec 조사 및 적용 (+Trouble Shooting)
AlgoRoot 2022. 5. 18. 10:29
지난 포스팅에서 프로젝트 주제와 기술 챌린지에 대한 간략한 내용을 담았다. 지난 포스팅을 토대로 오늘은 영상을 다루는 프로젝트를 시작하면서 처음 진행한 리서치에 대해 써보도록 하겠다.
오늘 다룰 내용은 크게 세 가지이다.
1. HTML5 video
2. WebRTC API, Library찾기
3. 모든 브라우저에 호환 가능한 코덱 찾기
웹캠, HTML5의 getUserMedia()의 역사
영상 쪽은 처음 공부하는 거라 몰랐던 부분이었는데 사실 영상을 촬영하는 것은 html5를 사용하는 것만으로도 가능하다는 것을 알았다.
html5rocks.com에서 소개하는 튜토리얼을 통해 어떻게 우리가 영상을 브라우저에서 간단히 다룰 수 있게 되었는지의 역사를 알 수 있게 되었다. 오래된 포스팅이지만, 역사는 변하지 않으니 참고할만하다.(여기서navigator.getUserMedia() 는 MediaDevices.getUserMedia()로 대체되었다.)
먼저 자료를 참고해 간단히 왜 우리가 최종적으로 MediaStream과 같은 API를 쓸 수 있게 되었는지 설명해보고자 한다.
1단계 : HTML Media Capture
<input type="file" accept="video/*;capture=camcorder">
비디오는 html5에서 input 태그를 잘 활용하면 카메라에 접근이 가능하다. 그럴싸해 보이지만 이는 단지 미디어 파일을 녹화하거나 그 순간 캡처를 하는 것만 가능했을 뿐 실시간 웹캠 데이터를 <canvas>에 그리는 것과 같은 실시간 효과를 처리하기에는 부족했다.
2단계 : device element
많은 제한이 있었던 HTML Media Capture을 보완하는 새로운 스펙이 등장했다. 이는 <device> tag형태로 호기롭게 등장했지만 정확히 같은 날 바로 나온 지금의 JavaScript API인 getUserMedia()의 등장으로 순식간에 폐기가 되었다. 폐기되었으므로 당연히 어떤 브라우저에서도 지원하지 않는 tag이다.
<device type="media" onchange="update(this.data)"></device>
<video autoplay></video>
<script>
function update(stream) {
document.querySelector('video').src = stream.url;
}
</script>
3단계 : (Old ver.) navigator.getUserMedia() > (New ver.) MediaDevices.getUserMedia()
그렇게 <device>가 폐기되고 같은 시기에 나온 getUserMedia()는 HTML5 및 JavaScript를 기반으로 만들어진 WebRTC 산하의 API로 현재에도 활발히 사용하고 있는 API가 되었다. 카메라 접근을 위해 플러그인을 설치하지 않고 브라우저에서 호출만 하면 가능하게 되게 된 것이다.
WebRTC
WebRTC(Web Real-Time Communication)는 웹 브라우저 간에 플러그인의 도움 없이 서로 통신할 수 있도록 설계된 API이다.
- 일반 JavaScript API로 제공되며 Apple, Google, Microsoft, Mozilla 등이 지원한다.
- 우리가 잘 알고 있는 화상통화, 화상 공유 등을 구현할 수 있는 오픈 소스이다.
- 비디오, 음성 및 일반 데이터가 P2P 방식으로 피어 간의 전송되도록 지원한다.
Web RTC에는 자바스크립트로 이용될 수 있는 세 가지 API가 구현되어 있다.
- MediaStream (aka getUserMedia)
- 사용자 단말기의 미디어 장치(마이크와 웹캠)를 액세스 할 수 있는 방법을 제공한다. getUserMedia를 통해 미디어 장치를 액세스 하게 되면 미디어 스트림 객체를 얻을 수 있으며 이를 PeerConnection에 전달하여 미디어 스트림을 전송하게 된다.
- RTCPeerConnection
- Peer 간의 화상과 음성 등을 교환하기 위한 거의 모든 작업을 수행하는 API이다. 기본적인 기능은 Singal Processing, Security, 비디오 encode/decode, 네트워크와 관련된 NAT Traversal, Packet send/receive, bandwidth estimation 등이 있다.
- RTCDataChannel
- Peer 간에 텍스트나 파일을 주고받을 수 있는 메시징 API이다. 설정에 따라 SCTP 또는 RTP로 전송할 수 있다. DataChannel 은 WebSocket과 같은 수준의 API를 제공하며 이는 Row Level API 라 할 수 있다. 대용량 파일을 주고받기 위해서는 이 API 를 활용한 애플리케이션 단의 테크닉이 필요하다.
이 중에서 우리 프로젝트에 필요한 기능은 영상 촬영과 녹화, 캡처이었으므로 모든 조건이 MediaStram API만 이용해서 구현 가능하였다. PeerConnection이나 DataChannel은 실시간 통신을 할 때 주로 Web socket과 결합하여 사용하는 기능이다. 서버 간 통신을 하지 않고 브라우저간 실시간 통신이 가능하다는 점이 무척 흥미로웠고, 이 번 프로젝트에서는 필요 없는 기능이지만 향후 혼자서라도 구현해보면 재밌을 것 같다는 생각을 했다.
Record RTC : WebRTC 라이브러리 찾기
MediaStream을 통해 만들어지는 라이브러리를 서치 해보았다. 총 세 가지가 나왔는데 npm trends를 통해 react-webcam과 reactRTC 두 가지가 추려졌고, 문서화나 예제의 다양성으로 보아 RecordRTC가 더 접근이 용이해 보여 최종적으로 선택하게 되었다.
1. RecordRTC
2. React-webcam
3. React-record-webcam
코덱 및 컨테이너 선정
Record RTC에서 지원하는 코덱 정보이다. 모든 브라우저에서 지원하는 VP8 codec을 사용하기로 했다.
Chrome | VP8, VP9, H264, MKV | OPUS/VORBIS, PCM |
Opera | VP8, VP9, H264, MKV | OPUS/VORBIS, PCM |
Firefox | VP8, H264 | OPUS/VORBIS, PCM |
Safari | VP8 | OPUS/VORBIS, PCM |
Edge (new) | VP8, VP9, H264, MKV | OPUS/VORBIS, PCM |
VP8 codec에서는 3GP, Ogg, WebM 세 가지 확장자를 지원한다.
Video processor 8 | 3GP , Ogg , WebM |
mdn사이트에서 Ogg보다 WebM을 사용하기를 권장하고 있고, 3GP는 네트워크 통신 속도가 느리던 시절 고안된 모바일용 확장자이며, 현재 사용하는 추세는 아니므로 최종적으로 WebM을 사용하게 되었다.
적용 :
recorderRef.current = new RecordRTC(stream, {
type: "video",
mimeType: "video/webm;codecs=vp8,opus",
});
Trouble shooting
프로젝트를 진행하는 중간 IOS에서는 WebM확장자를 지원하지 않는다는 것을 알게 되었다. 웹뷰에 집중하고 있던 터라 IOS환경에서 미처 확인하지 못했는데 이 때문에 WebM을 mp4로 변환하는 과정이 필요했다.
프론트 쪽에서 mp4로 변환하여 보내게 되는 것도 고려해 보았지만 이 부분에서 두 가지의 문제점이 있다고 판단되었다.
1. 확장자 변환 과정에서 유저의 대기시간이 길어진다.
2. 작업 도중 브라우저를 종료하게 되면 변환 과정이 날아가게 된다.
두 가지의 이유로 서버 쪽에서 바꿔주기로 하였고, 다행히 사용하고 있던 Record RTC에서도 WebM 에서 mp4로 변환하는 ffmfeg을 친절하게 소개(링크)해주고 있어 오랜 시간 걸리지 않고 서버쪽에서 성공적으로 확장자 변환을 하게 되었다.
서버에서의 변환 과정
1. s3에 저장된 WebM 파일을 가져와 H.264 코덱을 이용하여 mp4로 변환한다.
2. 변환이 완료되기 전까지 video의 값을 null로 응답해 주어 프런트에서 인코딩 중이라는 썸네일을 대체할 수 있도록 하였다.
적용 모습
짧은 회고
영상을 처리하는 것은 나에겐 너무 어려운 챌린지이다.. 하지만 밤을 새우기도 하며 부딪힌 과정들이 헛된 시간들이 아님을 믿고 있다. 더불어 점점 구글링 실력이 늘어가는 것 같다...하하.. 다음 포스팅에서는 우리의 프로젝트에서 서버, S3 클라이언트간에 영상을 어떤식으로 주고 받는지에 대한 포스팅을 해보겠다.
Willbe 프로젝트 진행과정 보기
Reference
'항해99 > 실전프로젝트' 카테고리의 다른 글
[WillBe 화상 면접 커뮤니티] React Player를 통한 custom player만들기 (2) (0) | 2022.05.24 |
---|---|
[WillBe 화상 면접 커뮤니티] React Player를 통한 custom player만들기 (1) (0) | 2022.05.23 |
[WillBe 화상 면접 커뮤니티] S3 Pre-signed URL 를 통한 비디오 주고받기 (0) | 2022.05.20 |
[WillBe 화상 면접 커뮤니티] 프로젝트 주제, 컨셉, 기술챌린지 소개 (0) | 2022.05.15 |
- Total
- Today
- Yesterday
- html
- javascript
- 무한스크롤
- React
- 모두를 위한 컴퓨터 과학
- 프로그래머스 베스트앨범 자바스크립트
- github
- 프로그래머스 자바스크립트
- 리액트네이티브
- 실전프로젝트
- 알고리즘자바스크립트
- python
- 네트워크
- css
- 자바스크립트 비동기 처리
- 자바스크립트알고리즘
- network
- cs50
- 프로그래머스
- 자바스크립트
- 타입스크립트
- 항해99
- 모두를위한컴퓨터과학
- React Query
- reactquery
- 백준
- 리액트
- 클로저
- 자바스크립트 클로저
- GIT
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |