자바스크립트로 m3u8 파일 하나의 mp4 변환 방법과 한계 분석
HLS 구조와 브라우저 다운로드의 기술적 모순
.m3u8과 .ts 세그먼트의 분리 구조
m3u8 파일은 영상 데이터 자체가 아니라 재생 목록(Playlist)일 뿐이다. 실제 화상과 음성 데이터는 수많은 .ts 파일 조각으로 분산되어 웹 서버에 존재한다. 일반적인 웹 브라우저의 HTML 태그와 download 속성은 단일 파일 URL만 처리할 수 있는 명백한 한계를 지닌다.
따라서 브라우저 주소창에 m3u8 링크를 입력하면 텍스트로 작성된 플레이리스트만 저장되거나 브라우저 내장 플레이어가 실행될 뿐이다. 사용자가 원하는 통합된 MP4 형태의 다운로드는 일어나지 않는다.
멀티미디어 컨테이너 변환의 브라우저 내부 한계
크롬이나 사파리 같은 최신 브라우저는 m3u8 포맷을 인식하고 끊김 없이 재생할 수 있다. 하지만 이를 '다운로드 가능한 단일 MP4 컨테이너'로 변환하는 기능은 내장하지 않았다. 단순한 스크립트만으로는 세그먼트를 하나로 병합하여 데이터를 순차적으로 나열할 수는 있다.
그러나 MP4 파일 시스템 구조인 FTYP, MOOV Atom 등을 생성하여 메타데이터를 정렬하는 패키징 과정이 철저히 결여되어 있다. 이로 인해 미디어 플레이어가 정상적으로 인식할 수 있는 완전한 파일이 생성되지 않는다.
WebAssembly를 활용한 클라이언트 사이드 트랜스코딩
ffmpeg.wasm을 이용한 브라우저 내 변환
'No ffmpeg'라는 요청의 핵심이 별도의 서버 구축이나 데스크톱 소프트웨어 설치 배제라면, WebAssembly 기반의 ffmpeg.wasm 라이브러리가 가장 강력한 대안이다. 이 기술은 C나 C++ 언어로 작성된 원본 ffmpeg 코어를 웹 어셈블리로 컴파일하여 브라우저 메모리 상에서 직접 구동하는 방식이다.
웹 워커(Worker)를 통해 조각난 세그먼트를 순차적으로 다운로드한 뒤, 브라우저 내부에서 직접 MP4로 결합(Muxing)한다. 이후 Uint8Array 형태로 변환하고 URL.createObjectURL 함수를 통해 즉시 다운로드할 수 있는 스트림을 생성한다.
SharedArrayBuffer와 CORS 헤더의 필수 조건
ffmpeg.wasm이 고성능으로 동작하려면 연산을 위한 멀티 스레딩이 필수적이다. 이를 위해서는 SharedArrayBuffer 객체가 필요하며, 이는 엄격한 브라우저 보안 정책상 서버의 제어가 동반되어야 한다. 웹 서버는 Cross-Origin-Opener-Policy를 same-origin으로 설정해야 한다.
추가로 Cross-Origin-Embedder-Policy를 require-corp으로 설정해야만 해당 객체가 활성화된다. 만약 대상 m3u8 서버가 CORS를 지원하지 않거나 해당 보안 헤더가 존재하지 않으면 브라우저에서의 직접 변환은 강제로 차단된다. 이는 사용자가 임의의 사이트에서 자유롭게 영상을 다운로드하고자 할 때 마주하는 가장 거대한 기술적 장벽이다.
CORS 우회 없는 원시 데이터 병합 방식
MP4 Box 구조 무시와 단순 바이트 결합
대상 비디오 서버와 동일한 도메인을 사용하지 않거나 프록시 서버를 거치지 않아 CORS 문제를 해결할 수 없는 상황이 존재한다. 이 때는 인코딩 연산을 포기하고 .ts 파일들의 원시 바이트 데이터를 단순 이어 붙이는 방식을 사용한다.
자바스크립트의 Blob 객체를 이용해 조각난 파일들을 순차적으로 읽어 들인 뒤 하나의 거대한 덩어리로 합치는 구조다. 복잡한 영상 압축이나 변환 연산 비용이 전혀 들지 않아 처리 속도가 매우 빠르며 서버 자원 소모도 제로(0)에 가깝다.
미디어 플레이어 호환성 저하와 부가 데이터 누락
치명적인 단점은 이 단순 병합 방식이 MP4 컨테이너 포맷의 규격을 생성하지 않는다는 점이다. 결괏값은 확장자명만 .mp4로 강제 변경된 변형된 TS 파일에 불과하다. 윈도우 미디어 플레이어나 모바일 기본 갤러리 앱과 같은 엄격한 플레이어에서는 코덱 인식 실패로 아예 재생이 거부된다.
영상은 출력되더라도 오디오가 누락되는 증상도 빈번하게 발생한다. 또한 스트리밍 특성상 파일 끝부분에 위치해야 할 메타데이터가 철저히 손실된다. 이로 인해 영상 재생 중 특정 시간대로 넘기는 탐색(Seeking) 기능이 작동하지 않아 처음부터 끝까지 순차적으로만 시청해야 하는 제약이 발생한다.
기술적 타협점과 선택 가이드
서버 구동 가능 여부에 따른 라이브러리 선택
Cloudflare Pages나 GitHub Pages 같은 정적 호스팅 환경에서 Cross-Origin-Embedder-Policy 헤더 설정이 가능하다면 ffmpeg.wasm을 도입하는 것이 기술적인 정석이다. 이를 통해 손실 없는 완전한 형태의 MP4 파일을 추출할 수 있다.
반면 헤더 설정이 물리적으로 불가능한 환경이거나 대상 미디어 서버가 타 도메인에 속해 있다면 전략을 수정해야 한다. MP4 인코딩 자체를 포기하고 앞서 언급한 단순 병합 방식을 사용하거나 AWS Lambda 같은 서버리스 함수를 이용해 다운로드 및 변환 과정을 백엔드로 완전히 분리해야만 한다.
다운로드 크기와 메모리 관리의 트레드오프
m3u8 영상의 재생 시간이 길어질수록 브라우저가 처리해야 할 데이터의 무게는 기하급수적으로 증가한다. 웹 어셈블리를 이용한 완전한 MP4 변환 로직은 모든 원시 데이터를 브라우저의 RAM에 적재해야만 작동하므로, 수천 개에 달하는 세그먼트를 동시에 처리해야 하는 위험을 안고 있다.
이 과정에서 브라우저 탭이 먹통이 되거나 강제 종료(Crash)될 확률이 지속적으로 상승한다. 1시간 분량 이상의 장시간 영상이나 고해상도 4K 스트리밍 처리에는 기존의 데스크탑용 ffmpeg 프로그램을 사용하는 것이 데이터 손실 방지 차원에서 안전하다. 현재의 웹 기반 다운로드 방식은 재생 시간이 10분 내외인 짧은 클립이나 프리뷰 영상 처리에만 국한하여 적용하는 것이 바람직하다.
쿠팡 파트너스 활동의 일환으로 일정 수수료를 제공받습니다
데일리 브리핑 구독
매일 아침 핵심 뉴스를 이메일로 받아보세요. 무료
