Skip to content

기술 스택

권영언 edited this page Dec 20, 2020 · 3 revisions

🌠 Frontend

WAVE의 UI는 react로 구성하였으며, 상태 관리에는 redux와 공식 바인딩 라이브러리인 react-redux를 사용하였습니다. UI의 상태와 캔버스의 편집 상태를 동기화하기, 서버와 통신하기 등의 side-effect를 관리하기 위해 redux-saga도 도입하여 Component와 Reducer의 코드를 순수하게 유지하였습니다. 또한, atomic design을 벤치마킹하여 Button과 Modal 등 공통적인 요소가 뚜렷한 경우 컴포넌트를 재사용하였습니다.

📹 Video

🎆 WebGL

편집 중인 영상은 HTML5 의 WebGL context를 통해 보여집니다. 직각삼각형 2개로 구성된 직사각형 modelViewMatrix에 각 영상 효과를 행렬 연산 또는 shader로 적용하고, 여기에 원본 영상을 texture로 그리는 방식입니다. 서명이 있는 경우 사용자의 마우스 이벤트에서 위치를 받아 비슷한 방식으로 적용합니다.

🎞 Web Codecs

Web Codecs는 Chrome 브라우저에서 실험 중인 기능으로, 코덱이 이미 브라우저에 내장되어 있음에도 이를 JavaScript로 사용할 수 없어 미디어 인코딩/디코딩을 위해 Web Assembly 등의 다른 API를 도입해야 하는 필요성을 없애는 것이 목적입니다. 이는 MediaStreamTrack을 디코딩하여 ImageBitmap으로 전환이 가능한 VideoFrame을 제공하는 VideoTrackReader와, VideoFrame을 인코딩하여 EncodedVideoChunk를 제공하는 VideoEncoder로 구성되어 있습니다.

VideoTrackReader로 재생 중인 영상으로부터 VideoFrame을 받아 이를 ImageBitmap으로 전환 후 WebGL로 편집하고자 했지만, 영상의 화질이 좋거나 사용자의 브라우저 상황/컴퓨터 성능이 좋지 못한 경우 심각한 framerate 드랍이 일어나서 사용을 포기하고 HTMLVideoElement.currentTime을 직접 조작, onseeked 콜백에서 인코딩을 진행하였습니다.

⛓ Web Assembly

VideoEncoder로 인코딩을 해서 EncodedVideoChunk를 얻었지만, 이를 mp4 등의 컨테이너 포맷에 담는 과정을 직접 구현하거나 이를 수행하는 라이브러리를 찾을 수 없어 VideoEncoder 사용도 포기하였습니다. 결과적으로, Web Codecs를 프로젝트에서 사용하지 않고, Web Assembly를 사용하는 라이브러리(mp4-h264, ffmpeg.wasm)를 통해 인코딩과 오디오 추출, mux를 하게 되었습니다.

📑 Summary

영상 추출 과정을 요약하면, HTMLVideoElement.currentTime을 1/30초(30fps)씩 이동하며 onseeked 콜백에서 createImageBitmap()을 통해 각 프레임을 지정한 해상도의 ImageBitmap으로 받고, 이를 WebGL로 편집한 후, mp4-h264 라이브러리를 통해 인코딩하여 비디오 트랙만 있는 mp4 파일을 생성합니다. ffmpeg.wasm 라이브러리로는 원본 영상에서 해당 구간의 오디오 트랙을 추출하고, 위 mp4와 합쳐서 오디오 트랙과 비디오 트랙이 모두 있는 mp4 파일을 생성합니다.

🛢 Backend

nodejsexpress 서버를 구성하였으며, 영상 목록 관리를 위해 MySQL 데이터베이스를 사용하였습니다.

📜 Common

Webpack을 통해 bundling, Babel을 통해 polyfill/transpiling을 적용하였고, prettierESlint를 사용하여 코드 스타일을 깔끔하게 관리하였습니다. TypeScript 사용을 통해 컴파일 단계에서 타입 오류를 잡아낼 수 있었습니다.

☁ Deploy

Web Codecs를 사용하기 위해서는 secure domain을 포함하여 사용 신청을 해야 하는 관계로, https 배포를 하고자 Naver Cloud Platform에서 서버와 공인 IP, freenom에서 도메인, sslforfree에서 SSL 발급을 받았습니다.

Backend의 API 서버로는 express를 사용하였고, pm2를 통해 항상 동작하도록 했습니다. Frontend의 웹 서버로는 nginx를 사용하였고, API를 하나의 도메인에서 이용하기 위해 프록시 설정을 추가하였습니다.

Jenkins를 활용하여 master 브랜치로 merge할 때마다 서버에서도 자동으로 업데이트가 되도록 했습니다.

Clone this wiki locally