브라우저 안에서 파일을 변환한다는 것

파일이 왜 서버로 안 가는지, 그래서 무엇이 빠르고 무엇이 느린지, 상한이 어디서 나왔는지 순서대로 적었습니다.

파일을 안 올린다는 것의 뜻

흔한 변환 사이트는 파일을 그쪽 서버에 올려 처리하고 결과를 돌려줍니다. 그래서 무료 한도가 있고, 줄을 서고, 파일이 얼마간 그쪽에 남습니다. 회의 녹음, 강의 영상, 가족 영상처럼 남의 서버에 두기 싫은 파일은 그 구조 자체가 걸립니다.

이 도구는 반대로 갑니다. 처음 한 번 변환 엔진(ffmpeg 을 WebAssembly 로 옮긴 것, 31MB)을 받아 브라우저 안에서 돌립니다. 고른 파일은 브라우저 메모리에만 올라가고, 결과도 거기서 만들어져 바로 내려받습니다. 우리 서버가 받는 것은 화면을 열었는지 변환을 눌렀는지 같은 단계 이름뿐입니다.

그 대신 처리하는 컴퓨터는 이 기기입니다. 빠르기도, 다룰 수 있는 크기도 이 기기 성능에 달려 있습니다. 이 안내의 나머지는 그 한계를 숫자로 적은 것입니다.

다시 그리는 일과 안 그리는 일

영상 파일은 그릇(mp4, mkv, mov, webm)과 그 안의 영상 줄기(H.264 같은 코덱), 소리 줄기(AAC, mp3)로 되어 있습니다. 그릇만 바꾸거나, 소리 줄기만 꺼내거나, 시간으로 잘라 내는 일은 줄기를 풀지 않고 옮겨 담기만 하면 됩니다. 이런 일은 파일 크기만큼 읽고 쓰는 시간이면 끝납니다.

용량을 줄이거나 GIF 를 만드는 일은 다릅니다. 영상 줄기를 한 장 한 장 풀어서 다시 압축해야 합니다. 이것을 재인코딩이라고 하고, 컴퓨터가 가장 오래 일하는 자리입니다.

여기 엔진은 한 코어로 돕니다. 여러 코어를 쓰는 빌드도 있지만 그것은 브라우저에 특별한 보안 헤더를 요구하고, 그 헤더가 켜지면 이 사이트의 광고 자리가 막힙니다. 광고가 이 사이트의 운영비라, 한 코어짜리를 골랐습니다. 그래서 재인코딩은 느리고, 느리다는 것을 시작 전에 화면에 적어 둡니다.

이 도구가 실제로 하는 일

여기는 코드가 실제로 하는 일을 순서대로 적은 것입니다. 소리만 뽑기는 영상 줄기를 버리고 소리 줄기를 고른 형식으로 씁니다. mp3 는 LAME 192kbps, m4a 는 AAC 160kbps, wav 는 16비트 무손실입니다. 원본이 이미 mp3 여도 다시 인코딩합니다.

자르기는 시작과 끝 시간을 받아 그 구간을 옮겨 담습니다. 줄기를 풀지 않으므로 키프레임 단위로만 잘립니다. 시작이 최대 몇 초 앞으로 당겨질 수 있고, 화질은 그대로입니다.

용량 줄이기는 목표 용량(MB)과 파일 길이로 영상 비트레이트를 셈합니다. 목표 용량의 95% 에서 소리 몫 96kbps 를 빼고 길이로 나눕니다. 그 값이 150kbps 아래면 150 으로 올리고 목표를 넘길 수 있다고 적습니다. 세로는 720 이하로 줄이고 H.264 로 한 번에 다시 그립니다.

GIF 는 구간과 너비, 초당 장수를 받아 만듭니다. 팔레트를 따로 만드는 두 단계 방식은 시간이 곱절이라 쓰지 않았고, 대신 색이 조금 거칠 수 있습니다.

형식만 바꾸기는 줄기를 그대로 다른 그릇에 담습니다. mp4 그릇은 H.264, H.265, AAC 정도만 받아서, 안 맞는 줄기면 ffmpeg 이 거절하고 그 메시지를 그대로 보여 줍니다.

자막 변환은 엔진 없이 글자만 다룹니다. UTF-8 로 읽어 깨지지 않으면 UTF-8, 깨지면 EUC-KR 로 다시 읽습니다. smi 는 SYNC 마다 시작 시각을 읽고 다음 SYNC 를 끝으로 삼습니다. 언어 구분(클래스)이 여럿이면 첫 번째만 옮기고 그렇게 했다고 적습니다.

상한은 실측입니다. 메모리 16GB 컴퓨터의 Chromium 에서 1.5GB wav 파일을 넣고 그대로 복사해 꺼내는 데 성공했고, 2GB 는 브라우저가 메모리를 잡지 못해 실패했습니다. 다른 기기의 값은 다릅니다. 실패하면 엔진을 다시 준비하고 그 사실을 알려 줍니다.

속도도 같은 날 같은 PC 에서 쟀습니다. 60초 wav 를 mp3 로 바꾸는 데 0.6초, 10초 720p 영상을 480p 로 다시 그리는 데 11.0초였습니다. 그릇 바꾸기와 자르기는 0.1초가 안 걸렸습니다. 재인코딩은 대략 영상 길이만큼 걸린다고 보시면 됩니다.

결과는 내려받기 버튼을 누를 때 브라우저가 파일로 저장합니다. 화면을 떠나면 결과는 사라집니다. 서버에는 아무것도 남지 않으므로 다시 받으려면 다시 변환해야 합니다.

넣을 때 요령

긴 영상에서 일부만 필요하면 자르기를 먼저 하고 그 결과를 다시 넣으세요. 자르기는 빠르고, 짧아진 파일은 용량 줄이기와 GIF 가 그만큼 덜 걸립니다.

시간은 초 또는 분:초 로 넣습니다. 30 은 30초, 1:05 는 1분 5초, 0:02:10 은 2분 10초입니다. 끝은 시작보다 뒤여야 하고, 파일 길이를 넘기면 길이까지만 잘립니다.

소리만 필요한 강의 영상은 소리만 뽑기가 답입니다. 다시 그리지 않으니 한 시간짜리도 파일을 읽는 시간이면 끝나고, mp3 하나가 영상의 십분의 일도 안 됩니다.

스마트폰에서 큰 영상을 넣으면 메모리가 먼저 바닥납니다. 그러면 브라우저가 탭을 닫거나 엔진이 멈춥니다. 수백 MB 를 넘는 파일은 PC 에서 하는 편이 낫습니다.

용량 목표와 자막 인코딩

용량 목표는 세 프리셋과 직접 입력이 있습니다. 지메일 25MB 는 구글 고객센터 원문에서 확인한 값입니다. 카카오톡 300MB 와 네이버 메일 10MB 는 공식 문서에서 숫자를 찾지 못해 사용자 글에서 반복되는 값을 옮겼고, 화면에 확인 못 함이라고 적어 두었습니다. 실제 상한은 그 서비스 화면이 정본입니다.

비트레이트가 낮아질수록 화면이 뭉개집니다. 10분 영상을 10MB 에 맞추면 영상에 남는 것이 초당 40kbit 정도라 글자가 안 보입니다. 그럴 때는 목표를 키우거나 길이를 줄이는 것 말고 방법이 없고, 이 도구는 그 사실을 셈해서 미리 적습니다.

옛 smi 자막은 EUC-KR 로 저장된 것이 많습니다. 그대로 srt 로 저장하면 플레이어에서 글자가 깨집니다. 이 도구는 읽을 때 인코딩을 판정하고 결과는 언제나 UTF-8 로 씁니다. 반대로 UTF-8 smi 를 옛 플레이어에 넣으면 그쪽이 못 읽을 수 있는데, 그것은 플레이어 설정의 일입니다.

srt 와 vtt 는 거의 같은 형식입니다. 시간의 구분자가 쉼표와 점으로 다르고, vtt 는 머리에 WEBVTT 한 줄이 붙습니다. 웹 페이지의 video 태그는 vtt 만 받습니다.

자주 막히는 부분

변환 엔진을 받는 데 오래 걸린다면 회선이 느린 것이지 파일 문제가 아닙니다. 한 번 받으면 브라우저가 기억해서 다음에는 바로 시작합니다. 시크릿 창은 기억하지 않습니다.

형식만 바꾸기에서 안 된다고 나오면 코덱이 그 그릇에 못 들어가는 것입니다. 예를 들어 webm 안의 VP9 는 mp4 에 넣지 못합니다. 용량 줄이기로 H.264 로 다시 그리면 mp4 가 됩니다.

자르기 결과가 넣은 시작보다 앞에서 시작한다면 키프레임 때문입니다. 정확한 자리가 꼭 필요하면 용량 줄이기로 다시 그리면서 자르는 것이 맞는데, 이 도구는 그 조합을 두지 않았습니다. 대신 자르기 결과를 용량 줄이기에 다시 넣으면 됩니다.

메모리가 모자라 멈췄다는 안내가 나오면 파일이 이 기기에 너무 큽니다. 자르기로 나눠서 하거나 PC 에서 해 보세요. 이 도구는 파일을 서버로 보내 대신 처리하는 길이 없습니다.

결과 파일 이름은 원본 이름 뒤에 무엇을 했는지 한 낱말이 붙습니다. 영어 화면에서는 영어 낱말이 붙습니다.

출처와 실측