ffmpeg.wasm이 큰 파일을 다룰 수 있게 하려고 한 개고생 정리(1)

김준성·2022년 6월 20일

주의

본인은 전문가가 아닙니다. 글에서 전문성을 기대하지 말아주세요. 내가 한 일을 정리도 하고 누군가에게 도움이 될 수도? 있지 않을까 하는 생각에서 글을 적어봅니다.


주말에 쉬고 있다가 브라우저에서 WebAssembly를 이용해서 ffmpeg를 쓸 수 있으면 재미있지 않을까?란 생각이 갑자기 들어서 이 고생은 시작됐다.

찾아보니 이미 어떤 분이 ffmpeg.wasm 레포지토리를 통해서 웹어셈블리 버전 ffmpeg를 배포하고 있었다.

ffmpeg.wasm 프로젝트 페이지

그런데 한계가 있었는데... 이 프로젝트는 emscripten이 제공하는 인메모리 파일 시스템을 사용해서 큰 파일을 넣으면 브라우저가 죽어버린다는 거였다.

그걸 확인하고 든 생각.

내가 직접 고쳐보지 뭐

그거 아니야

목표

내가 목표로 삼은 건 두가지였다.

  1. emscripten의 인메모리 파일 시스템인 MEMFS 대신 큰 파일을 다룰 수 있는 WORKERFS를 적용시켜서 큰 파일을 입력받을 수 있도록 하자.
  2. File System Access API를 이용해 출력을 메모리 대신 바로 디스크에 쓰자.

이 글에서는 1의 일부분만 다룹니다.

Emscripten의 File System API

Emscripten은 웹 어셈블리 프로젝트 개발을 위해서 개발된 툴체인이라고 한다. 가장 큰 특징은 기존 C, C++ 툴체인의 Drop-in replacement라는 거다. 그러니깐 기존 프로젝트에서 gcc쓰듯 emcc 컴파일러를 쓰면 된다는건데... 솔직히 이쪽은 잘 모르니깐 일단 넘어가자.

기존의 ffmpeg같은 프로젝트가 브라우저에서 정상적으로 돌아가려면 파일 시스템이 브라우저상에서 구현되어야 한다. 문서를 읽어보면 MEMFS, IDBFS, WORKERFS등 다양한 파일 시스템 구현이 존재한다는 걸 확인할 수 있다. 이중 아무런 설정도 안하면 기본으로 포함되는 MEMFS는 인메모리 파일 시스템이다. 그러니깐 마치 메모리를 디스크 쓰듯이 쓰게 되는 것이다. 가장 간단하지만, 메모리에다가 바로 파일을 써버리기 때문에 큰 파일을 쓰려고 하면 메모리가 나가버린다.

WORKERFS는 파일을 모두 메모리에 저장하지 않는 대신 처음에 받는 File 오브젝트를 이용해서 필요한 데이터만 가져오는거로 추정된다. (확인해보지는 않았지만 아마 그럴듯...) 그래서 이걸 이용하면 큰 파일을 지원할 수 있을거라고 생각하고, 이걸 적용해보기로 했다.

문제는 이 파일 시스템은 웹 워커 환경에서만 동작하며, 읽기만 지원하고(그러니깐 쓰기가 안된다!), 별도로 설정을 해주어야 했다는 것이다. 웹 워커는 쓰기 쉬우니깐 별 문제가 안되지만 읽기만 지원한다는 게 문제였다. 일단 이 부분은 나중에 생각해보기로 해보고 읽기라도 되게 해보기 위해서 WORKERFS를 적용시킬 방법을 찾아보았다.

ffmpeg.wasm 레포지토리에서 관련 이슈를 찾아보니 어떤 사람이 이미 설정을 다 해 놓은 레포지토리를 찾을 수 있었다. 이걸 clone하고 도커에서 컴파일 돌리면 되겠지?라고 생각했는데...

컴파일해보자!

일단 컴파일을 위해서 레포지토리를 클론했다. 참고로 본인은 개발용으로 윈도우 10 컴퓨터에서 WSL2를 올려서 쓰고 있다.

# 윈도우 10에서 실행
git clone https://github.com/animebook/ffmpeg.wasm-core
cd ffmpeg.wasm-core

그다음 다음 명령어를 실행해서 도커에서 컴파일을 돌렸다.

# WSL2로 환경 바꿈
./build-with-docker.sh

그러면 도커가 알아서 적절한 이미지를 다운받고 격리된 환경에서 완벽하게 컴파일을 해줘야...하는데... 오류가 나네????

./configure: 1: eval: aac_adtstoasc_bsf
=yes: not found

구글링을 해봐도 나오지도 않는 오류다... 도대체 왜???????

?????????

디버깅 지옥

본인은 bash 언어를 다룰줄 모른다. 그런데 저 오류를 낸 ./configure이란 스크립트는 확인해보니 무려 7000라인짜리 bash 스크립트였다. 현실을 부정하며 명령어를 몇번을 다시 돌려봐도 결과는 똑같았다.

그다음으로 든 생각은 디버깅을 해보자는 거였다. 그런데 bash에도 디버거가 있나? 찾아보니 정말 다행이도 bashdb라는 디버깅 프로그램과 대응되는 vscode 확장도 있었다. 이유는 모르겠는데 최신 버전의 우분투에는 이 프로그램이 빠져있어서 공식 사이트에서 파일을 받아 패키지를 직접 설치하고 vscode로 도커 컨테이너에 연결해 디버깅을 시작했다.

맨땅에 해딩하듯이 bash 언어를 stackoverflow의 도움을 받아서 조금씩 배워나가면서 스크립트를 돌려나갔다. 한줄 돌리고 모르는거 찾아보고를 계속하면서 약 2시간쯤이 지났을때쯤 스크립트에서 이상한 점을 하나 발견할 수 있었다.


이 부분을 디버거로 돌려보니 볼 수 없었던 오류 메시지를 볼 수 있었다. 정확한 메시지는 기억나지 않지만 분명 위에서는 eval $var=$value였는데 디버깅 콘솔에는 eval $val=\r$value라고 출력되어 있었던 것 같다.

\r이 뭐였지...? 바로 폭풍검색을 해본 결과... 마침내 문제의 원인을 찾을 수 있었다!! (아래는 검색의 흔적이다) 새벽 3시에 폭풍검색

사람 잘못

문제의 원인
\r은 Carriage Return이란 문자로 윈도우 환경에서 개행문자로 \n(line feed)와 함께 사용된다. 그건 원래 알고 있었는데... 도대체 왜 이게 스크립트 중간에 끼어있는 거지??? 기억을 되돌려본 결과 진짜 원인을 발견할 수 있었다. 바로 나는 프로젝트를 윈도우 10 환경에서 클론했던 것이었다!

git에는 autocrlf라는 기능이 있어서 서로 다른 운영 체제 간 개행 문자의 차이를 신경써도 되지 않게 해 준다. 윈도우에서 git을 설치하면 기본적으로 autocrlf 기능이 활성화되어 있으며, 이 기능이 켜져있으면 git은 프로젝트를 clone등으로 불러올 때 lf를 몽땅 crlf로 바꾸고 반대로 커밋할때는 crlflf로 바꿔서 커밋시킨다.

나는 이 autocrlf 기능이 켜져있는 윈도우 10 환경에서 clone을 해서 git이 정말 고맙게도 프로젝트의 개행문자를 crlf로 죄다 바꿔버렸는데 이 과정에서 알 수 없는 오류로 인해 저 위치에 \r이 끼어들어간 것이었다.

고치기

원인을 알아내자 정말 어이가 날아갔지만 일단 고치는게 최우선이니 고칠 방법을 찾아봤다. 정말 고맙게도 누군가 dos2unix라는 좋은 프로그램을 만들어둬서 이걸 이용해서 프로젝트의 모든 파일의 개행 문자를 바꿨다.

dos2unix **/*

그리고 컴파일해보니 다행이도 정상적으로 컴파일이 되었다.

교훈

다음부터는 WSL에서 클론해야겠다.

profile
학생

0개의 댓글