1. 우리 서비스 MediaCAT의 신규 가입 유저가 오류가 났다며 문의를 보냈다. 데이터독 세션 리플레이를 확인해보니 1.5GB짜리 동영상 파일을 올려서 전사 작업을 하려고 했다.
2. 우리는 <video>
태그를 임시로 생성해서 URL.createObjectURL
로 영상을 불러오고, 메타데이터의 duration
을 이용하여 동영상 길이를 얻어 가격을 추산하고, 유저가 가진 크레딧이 작업하기에 충분하지 않으면 작업을 돌리지 못하게 하는 로직이 있었다.
3. MediaCAT 신규 가입시 주는 $10 크레딧으로는 1.5GB를 돌릴 수 없는 게 당연하다. 그래서 실패했어야 했는데 그냥 작업이 돌아갔고, 돈 부족으로 실패가 떴다.
4. 가격을 추산하고 작업을 방지하는 로직은 영상의 길이가 0이면 작동하지 않게 되어 있다. 알고 보니, 서버에서는 ffmpeg
이 지원하는 영상 포맷을 다 허용하지만 브라우저에서는 <video>
태그가 지원하는 포맷 형태가 상당히 제한적이었다. 예를 들어 avi
, mpeg
, flv
는 <video>
태그에서 재생할 수 없으므로 길이도 알 수 없었다. 우리가 개발하고 테스트할 때는 mp4
, mov
를 비롯해 재생되는 포맷으로만 했기 때문에 몰랐던 것이다.
5. Vercel 서버든 우리 서버든 기본적으로 대용량의 파일을 네트워크에 태우고 싶지 않았다. 그래서 어떻게든 브라우저 안에서 해결하고 싶었다. 검색해보니, 누군가가 avi 포맷의 스펙을 해석하여 길이를 알아내는 코드를 올려둔 걸 찾았다. 무슨 언어인지는 이해를 못해서, ChatGPT에게 상황을 설명하고 자바스크립트로 바꿔달라고 하니 잘 바꿔주었고, 샘플 avi
파일로 테스트해보니 실제로 영상 길이를 얻을 수 있었다.
6. 이번에는 ChatGPT에게 비슷하게 flv
와 mpeg
를 처리할 수 있을지 물어봤는데, 굉장히 조심스러워하며 "내가 코드를 주긴 주는데 이거 작동 안할 확률 높음" 이라고 하더라. 그러면서 ffmpeg.js
를 써보는 건 어떠냐 제안했다.
7. 그 제안을 보고 문득 생각이 나서 찾아보니, ffmpeg
을 웹어셈블리로 브라우저에서 돌릴 수 있게 하는 라이브러리가 있었다. 한번쯤 웹어셈블리를 써보고 싶기도 했어서 PoC를 시작했다.
8. 우리가 사용하는 NextJS 12에서 온갖 삽질을 해가며 결국 성공했다. 그런데 여러가지 문제가 있었다.
- 웹어셈블리에는 올릴 수 있는 파일의 용량 크기가 2GB로 제한된다. 우리는 지금까지 5GB까지 파일을 받았다.
- 구현방식의 문제일 수도 있지만, 이게 결국
avi
파일을mp4
같은 걸로 transcode해서 길이를 알아내는 거였는데 transcode가 너무 오래 걸렸다. (1.5MB짜리 파일이 체감상 10초 가까이 걸림) - 가장 중요한 건, 웹어셈블리를 멀티쓰레드로 사용하려고 하면 cross-origin isolated 환경에서만 돌 수 있다. SharedArrayBuffer를 써야 하기 때문이다. (그런데 wasm을 싱글쓰레드로 쓰면 메인쓰레드를 블록하기 때문에 멀티쓰레드 안하면 뭔 의미인가 싶다.)
- 이를 위해
Cross-Origin-Opener-Policy: same-origin
,Cross-Origin-Embedder-Policy: require-corp
를 지정하는데, 이렇게 하면 Stripe, Freshdesk 등 우리가 사용하고 있던 origin이 다른 js 파일들을 아예 실행할 수 없게 된다. (젠데스크에서도 비슷한 문제가 리포트된 바 있다)
9. 결론적으로 지금 우리 환경에서는 웹어셈블리를 쓰기 어렵다는 결론에 도달했다. 비록 이번에는 엣지케이스를 다루기 위한 것이었으나 한번 쓸 수 있게 되면 여러모로 유용할 것 같아 아주 아쉬웠다. wasm을 운영환경에서 쓰는 프로젝트들 코드가 궁금해졌다.
10. 결국 avi
파일은 5번으로 해결하고, 나머지 불가능한 포맷 (또는 어떤 이유로든 미디어 길이 계산을 못한 경우) 은 폴백 메시지를 표시하는 걸로 결정했다.