![[실전 미디어 11] 동영상 용량을 잡는 법](https://img.thenullpage.com/posts/5784/5784_1_057e0d.webp)
지난 편에서 동영상 썸네일 문제를 서버사이드 프레임 추출로 해결했다. 이제 동영상 자체의 무게, 즉 용량 문제가 남았다. 요즘 스마트폰으로 찍은 동영상은 짧아도 수십 메가를 우습게 넘겼고, 이걸 원본 그대로 저장하고 서빙하면 스토리지도 대역폭도 감당이 안 됐다. 이번 편은 동영상 용량을 어떻게 잡는지, 특히 흔한 오해인 코덱 교체가 아니라 해상도와 비트레이트에 상한을 거는 것이 진짜 해법이라는 이야기를 다룬다.
1. 원본을 두면 눈덩이가 된다
동영상은 이미지와 비교가 안 되게 무거웠다. 사진 한 장이 몇 메가라면 동영상은 짧은 것도 수십 메가였고, 고화질 긴 영상은 수백 메가에 달했다. 이걸 원본 그대로 저장하면 스토리지 사용량이 순식간에 불어났다. 이미지 편에서 다룬 용량 문제가 동영상에서는 열 배, 백 배로 증폭됐다.
대역폭도 문제였다. 원본 고화질 동영상을 그대로 내려주면, 작은 화면으로 보는 사용자에게도 불필요하게 큰 데이터가 전송됐다. 모바일 사용자가 대다수인데, 이들에게 과분한 화질의 원본을 밀어 넣는 건 데이터 요금과 로딩 시간을 낭비하는 짓이었다. 화면 크기에 비해 과한 화질은 그냥 버려지는 비용이었다. 사용자는 자기가 본 것보다 훨씬 많은 데이터를 내려받고도 그 차이를 화면에서 느끼지 못했으니, 그 격차만큼이 순수한 낭비였다. 보이지 않는 화질을 위해 요금과 시간을 지불하게 하는 셈이었다.
그래서 업계가 어떻게 하는지 다시 조사했다. 결론은 이미지 때와 같았다. 원본 동영상을 그대로 서빙하는 큰 서비스는 없었다. 거의 전부가 업로드 즉시 서버에서 표준 코덱으로 재인코딩하고, 해상도와 비트레이트에 상한을 걸어 표준본을 만들고, 원본은 폐기하거나 값싼 보관으로 내렸다. 사용자가 올린 원본과 서빙되는 표준본은 다른 물건이었다.
규모가 큰 곳만 긴 영상에 적응형 스트리밍을 붙였고, 짧은 영상은 그냥 표준본을 프로그레시브로 내려줬다. 내 커뮤니티는 짧은 동영상이 대부분이었으니 복잡한 스트리밍까지 갈 필요는 없었다. 핵심은 원본을 표준본으로 눌러 저장한다는 원칙, 그리고 그 눌러 담는 방법이 무엇이냐였다. 방법을 잘못 알면 오히려 용량이 늘 수도 있었다.
2. 용량은 코덱이 아니라 상한으로 잡는다
가장 흔한 오해가 여기 있었다. 용량을 줄이려면 더 효율 좋은 최신 코덱으로 바꾸면 된다는 생각이다. 물론 최신 코덱은 같은 화질을 더 작게 담지만, 웹 호환성 문제로 아무 코덱이나 쓸 수는 없었다. 결국 웹에서 가장 널리 재생되는 표준 코덱을 써야 했고, 그러면 코덱 교체로 얻을 이득은 제한적이었다.
진짜 지렛대는 다른 데 있었다. 용량은 코덱보다 해상도와 비트레이트에 훨씬 크게 좌우된다. 해상도는 화면의 픽셀 수이고 비트레이트는 초당 데이터 양인데, 이 둘에 상한을 걸면 원본이 아무리 커도 결과물의 크기가 일정 범위로 수렴했다. 코덱을 바꾸는 것보다 이 상한을 거는 것이 용량에 미치는 영향이 압도적이었다.
구체적으로는 표준 해상도로 낮추고 비트레이트를 적정 수준으로 제한하는 것이었다. 원본이 아주 높은 해상도에 고비트레이트여도, 표준 해상도의 적정 비트레이트로 다시 인코딩하면 대개 훨씬 작은 크기로 떨어졌다. 화면에서 보기에는 큰 차이가 없으면서 용량만 크게 줄었다. 과한 화질을 적정 화질로 깎는 것이 낭비 제거의 핵심이었다.
여기서 중요한 함정이 하나 있었다. 코덱을 효율 좋은 것에서 호환성 좋은 표준으로 바꾸면, 같은 화질을 유지할 경우 오히려 용량이 늘 수 있다는 것이다. 그래서 코덱을 바꾸면서 용량까지 잡으려면 반드시 해상도나 비트레이트를 함께 낮춰야 했다. 이 원리를 모르면 재인코딩했는데 용량이 더 커지는 황당한 일이 벌어졌다. 실제로 이건 다음 편의 아이폰 문제와 직결됐다.
3. 표준본으로 눌러 담기
실제 처리는 원본을 표준 코덱, 표준 해상도, 적정 비트레이트로 다시 인코딩하는 것이었다. 이렇게 하면 원본이 어디서 어떻게 찍혔든 결과물은 일정한 규격의 표준본으로 수렴했다. 수십 메가, 수백 메가짜리 원본도 재인코딩을 거치면 대개 몇 메가에서 십몇 메가 범위로 떨어졌다. 크기가 예측 가능한 범위로 들어온다는 게 운영에 큰 안정감을 줬다.
화질 손실은 걱정보다 크지 않았다. 애초에 원본의 과한 화질은 작은 화면에서 체감되지 않는 부분이 많았기 때문이다. 표준 해상도로 낮춰도 모바일 화면에서는 거의 차이를 못 느꼈고, 오히려 로딩이 빨라져 체감은 나아졌다. 눈에 안 보이는 화질을 덜어내고 속도를 얻는, 남는 장사였다.
표준본으로 통일하니 재생 호환성도 좋아졌다. 원본은 기기마다 제각각 코덱이라 일부 브라우저에서 재생이 안 되기도 했는데, 표준 코덱으로 통일하니 어디서나 재생됐다. 이미지에서 포맷을 webp로 통일한 것과 똑같은 이점이 동영상에서는 코덱 통일로 나타났다. 통일이 주는 단순함은 미디어 종류를 가리지 않았다.
다만 원본을 완전히 버리진 않고 신중하게 다뤘다. 재인코딩 결과가 원본보다 확실히 작을 때만 교체하고, 어떤 이유로 결과가 더 커지면 원본을 유지했다. 무조건 재인코딩본으로 바꾸는 게 아니라, 실제로 이득이 있을 때만 바꾸는 안전장치를 뒀다. 최적화한다면서 오히려 더 나빠지는 일은 없어야 했다.
4. 어디서 인코딩할 것인가
문제는 이 재인코딩을 어디서 돌리냐였다. 앞서 여러 번 말했듯 엣지 함수 안에서는 무거운 동영상 인코딩 도구를 돌릴 수 없었다. 실행 시간과 메모리 한도, 네이티브 도구 사용 불가라는 제약이 여기서도 그대로 걸렸다. 함수 안에서 트랜스코딩을 시도하는 건 절대 하지 말아야 할 일 목록의 맨 위에 있었다.
그래서 현실적인 방법은 큐 기반 지연 처리였다. 업로드된 동영상은 일단 원본으로 저장하고, 재인코딩이 필요하다는 표시를 남겨 대기열에 넣는다. 그러면 함수는 무거운 일 없이 표시만 남기고 빠르게 끝났다. 실제 무거운 인코딩은 이 대기열을 소비하는 별도의 처리가 나중에 맡았다. 업로드 경로와 인코딩 경로를 시간적으로 분리한 것이다.
그 별도의 처리를 현재는 내 PC에서 도구로 일괄 실행하고 있었다. 대기열에 쌓인 동영상을 내려받아 재인코딩하고, 결과가 더 작으면 스토리지의 파일을 교체한 뒤 표시를 지우는 식이다. 애니메이션 이미지 때와 완전히 같은 반자동 패턴이었다. 감지와 대기열 관리는 자동, 무거운 변환만 사람이 주기적으로 실행하는 구조다.
더 근본적인 방향은 이 사람 자리를 자동화하는 것이었다. 인프라가 제공하는 컨테이너 환경에서 인코딩 도구를 띄워, 대기열을 자동으로 소비하게 만들면 사람이 개입할 필요가 없어진다. 큐 구조는 이미 있으니 수동 실행을 자동 실행으로 바꾸는 성격의 확장이었다. 당장은 반자동으로 굴리되, 영상이 늘면 이 자동화로 넘어가는 게 자연스러운 로드맵이었다.
5. 큐 기반 흐름의 이점
큐 기반으로 설계하니 여러 이점이 따라왔다. 우선 업로드가 빨랐다. 무거운 인코딩을 업로드 시점에 하지 않으니, 사용자는 원본만 올리면 즉시 글이 발행됐다. 인코딩은 뒤에서 조용히 진행되고, 끝나면 표준본으로 교체됐다. 사용자를 인코딩이 끝날 때까지 기다리게 하지 않는다는 게 경험상 컸다.
대기열 처리는 중단되어도 안전했다. 처리가 도중에 멈춰도 대기열의 표시는 남아 있으니, 다음번에 이어서 처리하면 됐다. 이미 처리한 건 표시가 지워져 건너뛰고, 남은 것만 다시 집으니 중복도 누락도 없었다. 이 이어서 하기 성질 덕분에 한 번에 다 처리하지 못해도 부담이 없었다. 큰 작업을 조금씩 나눠 소화할 수 있었다.
표시를 기반으로 하니 무엇이 처리됐고 안 됐는지도 투명했다. 대기열에 남은 항목을 세어보면 밀린 작업량이 바로 보였고, 처리가 잘 도는지도 확인할 수 있었다. 실패한 항목은 표시가 남아 다시 시도되니, 일시적 오류로 빠지는 것도 없었다. 상태가 데이터로 드러나는 구조가 운영을 편하게 했다.
이렇게 동영상 용량을 잡는 큰 틀이 갖춰졌다. 그런데 이 모든 논의를 뒤흔드는 특수한 사례가 있었다. 바로 아이폰에서 올라오는 동영상이었다. 아이폰 영상은 업로드하는 순간 오히려 용량이 몇 배로 불어나 곧바로 거부되는 기이한 일이 벌어졌다. 다음 편에서는 그 원인이 아이폰의 코덱 정책과 브라우저의 실시간 재인코딩에 있음을 파헤친다.