06 · 컨테이너 (MP4 · MOV · MKV · WebM · MPEG-TS · FLV)
이 문서가 답하는 질문: 코덱과 컨테이너는 어떻게 다르고, MP4와 MKV는 왜 둘 다 있는가? 선행:
01-pixel-resolution-aspect.md,04-yuv-and-chroma-subsampling.md
한 줄 답
코덱은 비디오/오디오를 압축하는 알고리즘이고, 컨테이너는 그 압축된 스트림과 메타·자막·챕터·DRM 정보를 한 파일에 묶는 포장 형식이다. 하나의 코덱은 여러 컨테이너에 들어갈 수 있고, 하나의 컨테이너는 여러 코덱을 담을 수 있다.
Why — 왜 컨테이너가 따로 필요한가
비디오 한 편에는 동영상 하나만 들어가는 게 아니다:
- 비디오 스트림 1개 (또는 여러 개 — angle, picture-in-picture)
- 오디오 스트림 N개 (다국어·5.1 서라운드)
- 자막 스트림 M개 (SRT·WebVTT·PGS)
- 챕터 마커
- 메타데이터 (제목·저작자·EXIF·Dolby Vision RPU·HDR mastering display)
- DRM 보호 정보
- 썸네일/포스터
이걸 한 파일에 어떻게 줄 세울지, 어떻게 빠르게 탐색할지(seek), 어떻게 스트리밍 단위로 쪼갤지 가 컨테이너의 일.
How — 컨테이너의 두 가지 모델
1) Atom/Box 모델 (ISO BMFF — MP4·MOV·HEIF)
전체 파일이 재귀적인 박스(box, atom) 트리.
[ftyp] ← File Type box (포맷 식별)
[moov] ← Movie box (메타 — 모든 트랙 정보)
[trak] ← Track box × N (비디오·오디오·자막)
[mdia]
[minf]
[stbl] ← Sample Table (어떤 sample이 어디 있나)
[stsd] ← codec configuration
[stts] ← time-to-sample (PTS)
[stss] ← sync sample (key frame index)
[stsz] ← sample size
[stco]/[co64] ← chunk offset (파일 안 위치)
[mdat] ← Media Data (실제 압축된 비디오/오디오 바이트)→ moov가 인덱스, mdat가 데이터. seek할 때 moov의 stbl을 읽어 mdat 안의 byte offset으로 점프.
2) Stream 모델 (MPEG-TS — 방송)
고정 188바이트 패킷의 무한 스트림. 인덱스가 따로 없고, 매 패킷에 Program Information 이 반복적으로 포함되어 있어 중간부터 받아도 디코드 가능.
[TS pkt 188B][TS pkt 188B][TS pkt 188B]...
↑ header(4B) + payload(184B)
header: sync(0x47) | flags | PID | …→ 방송·라이브 스트리밍에 최적. HLS는 MPEG-TS 세그먼트를 그대로 사용 (현재는 fMP4 세그먼트도 표준).
What — 컨테이너 비교
주요 컨테이너 요약 표
| 컨테이너 | 확장자 | 모델 | 비디오 코덱 | 오디오 코덱 | 자막 | DRM | 라이브 |
|---|---|---|---|---|---|---|---|
| MP4 (ISO BMFF) | .mp4 / .m4v | atom/box | H.264·HEVC·AV1·VP9·MPEG-4 | AAC·MP3·AC-3·Opus·ALAC | TX3G·WebVTT(fMP4) | CENC | fMP4 ✅ |
| MOV (QuickTime) | .mov | atom/box (MP4 조상) | ProRes·H.264·HEVC·DNxHD | AAC·PCM·ALAC | QT text | — | ❌ |
| MKV (Matroska) | .mkv | EBML | 거의 모든 코덱 | 모든 코덱 | SRT·SSA·VobSub·PGS | 자체 | ❌ |
| WebM | .webm | EBML (MKV 부분집합) | VP8·VP9·AV1 | Vorbis·Opus | WebVTT | EME 가능 | ❌ |
| MPEG-TS | .ts / .m2ts | stream (188B 패킷) | MPEG-2·H.264·HEVC | AAC·AC-3·DTS | DVB·CC | CENC | ✅ |
| FLV | .flv | RTMP 스트림 포장 | H.264·VP6·Sorenson | AAC·MP3·Speex | — | — | (RTMP) |
| AVI | .avi | RIFF chunk | (구식) DivX·Xvid·MJPEG | MP3·AC-3 | — | — | ❌ |
| 3GP | .3gp | atom/box (MP4 sub) | H.263·H.264·MPEG-4 | AMR·AAC | TX3G | — | ❌ |
| OGG | .ogv | Ogg page | Theora·Daala | Vorbis·Opus·FLAC | Kate | — | ❌ |
MP4 box 구조 깊이 보기
isom
└─ ftyp (major_brand="isom", compatible="iso2 avc1 mp41")
└─ moov
├─ mvhd (movie header — duration, timescale)
├─ trak (video)
│ ├─ tkhd (track header — width, height)
│ ├─ edts/elst (edit list — cut/offset)
│ └─ mdia/minf/stbl/...
├─ trak (audio)
├─ trak (subtitle)
├─ udta (user data — iTunes metadata, Dolby Vision config)
└─ mvex (movie extends — fragmented MP4 indicator)
└─ moof (fragment) × N ← Fragmented MP4의 경우
└─ traf (track fragment)
└─ mdat (media data) × NFragmented MP4 (fMP4) — 스트리밍의 표준
전통적 MP4는 moov(인덱스)가 파일 끝 또는 시작에 한 번. 라이브 스트리밍에는 부적합 — 끝나기 전엔 인덱스를 못 쓴다.
Fragmented MP4는 파일을 moof + mdat 쌍의 프래그먼트로 쪼갠다:
[ftyp][moov(empty placeholder)]
[moof][mdat] ← fragment 1 (예: 6초)
[moof][mdat] ← fragment 2
[moof][mdat] ← ...→ 각 fragment가 독립적으로 디코드 가능. HLS·DASH·LL-HLS의 세그먼트 가 fMP4 (CMAF).
# fMP4 fragment 길이를 6초로 나눠 인코딩 (HLS/DASH 공통)
ffmpeg -i in.mp4 -c copy \
-movflags +frag_keyframe+empty_moov+default_base_moof \
-frag_duration 6000000 fragmented.mp4faststart — moov를 앞으로
# moov를 파일 끝에서 앞으로 이동 (web 점진적 스트리밍 가능)
ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4
# 검증 (moov가 mdat보다 앞에 있어야 함)
mp4dump out.mp4 | head -20→ moov가 끝에 있으면 브라우저는 파일 전체를 받아야 재생 시작. 앞에 있으면 첫 청크만 받아도 재생.
MKV가 인기 있는 이유
MKV (Matroska)는 EBML(Extensible Binary Meta Language) 기반 — XML의 바이너리 친척. 모든 코덱·자막·다중 트랙·챕터를 자유롭게 담는다:
[EBML header]
[Segment]
[SeekHead] ← top-level element 위치 인덱스
[Info] ← timecode scale, duration
[Tracks] ← 트랙 메타 (비디오·오디오·자막 N개)
[Chapters]
[Attachments] ← 폰트·이미지 첨부
[Cluster] × N ← 실제 데이터 (블록 단위)
[Cues] ← seek index
[Tags] ← 메타데이터→ 사용자/팬섭(fansub) 커뮤니티의 사실상 표준. 영화에 5개 자막·3개 음성을 묶을 수 있다.
MIME 타입과 codecs 파라미터
video/mp4; codecs="avc1.640028,mp4a.40.2"
↑ H.264 High@4.0 ↑ AAC-LC
video/mp4; codecs="hvc1.1.6.L120.90,mp4a.40.2"
↑ HEVC Main 4.0
video/mp4; codecs="av01.0.05M.08,opus"
↑ AV1 Main Profile 5.0 ↑ Opus
video/webm; codecs="vp9,opus"
video/mp2t ← MPEG-TS
application/vnd.apple.mpegurl ← .m3u8 (HLS playlist)
application/dash+xml ← .mpd (DASH manifest)MediaSource.isTypeSupported() 가 이 문자열로 디코더 가용성을 확인한다.
What-if — 잘못 다루면 어떻게 깨지는가
❌ 함정 1 — moov 앞으로 안 옮긴 MP4를 웹 점진 다운로드
증상: 5분 영상에서 끝까지 다운로드된 뒤에야 재생 시작. 원인: moov가 mdat 뒤에 있어서 브라우저가 인덱스를 못 읽음.
ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4❌ 함정 2 — MOV를 그대로 웹에 올림
QuickTime MOV는 ProRes·DNxHD 같은 마스터링 코덱을 자주 담는다. 100MB/min 비트레이트. 브라우저는 ProRes 디코더가 없어서 재생 불가. 반드시 H.264/HEVC/AV1로 트랜스코드.
❌ 함정 3 — MKV를 iOS Safari로 송출
iOS Safari는 MKV/WebM 미지원 (Safari 16+에서 일부 WebM AV1 지원 시작).
<video src="movie.mkv"> 는 그냥 안 뜬다. MP4 또는 HLS 권장.
❌ 함정 4 — fMP4와 일반 MP4를 같은 endpoint에서 혼용
CDN 캐시 키가 같아 fMP4 fragment이 일반 MP4와 충돌. 잘못된 byte를 받아 디코더 깨짐. 별도 path 또는 별도 cache key로 분리.
❌ 함정 5 — codecs 파라미터 누락
<source src="video.mp4" type="video/mp4">는 통과되긴 하지만, 정확한 디코더 capability 확인이 안 된다 — 일부 브라우저는 fallback 결정에 codecs 파라미터를 본다.
<source src="video.mp4" type='video/mp4; codecs="avc1.640028,mp4a.40.2"'>
<source src="video.webm" type='video/webm; codecs="vp9,opus"'>❌ 함정 6 — MPEG-TS를 progressive download로 사용
TS는 stream-oriented. byte-range seek이 비효율적이고 인덱스가 없다. 파일 다운로드용은 MP4, 라이브/세그먼트 스트리밍용은 TS 또는 fMP4.
Insight — 흥미로운 이야기
“MP4는 MOV의 후손이다”
1991년 Apple QuickTime의 atom/box 모델 → 1998년 ISO/IEC 14496-12 (ISO BMFF) → 1999년 MPEG-4 Part 14 (MP4). ISO BMFF는 MOV의 atom 구조를 거의 그대로 표준화한 것이라, MP4와 MOV는 box 단위 호환 — ffmpeg는 두 포맷을 동일 코드 패스로 다룬다. HEIF·CMAF·Dolby Vision도 모두 ISO BMFF 위에 만들어졌다.
“FLV는 죽었지만 RTMP는 안 죽었다”
FLV 컨테이너는 Flash Player의 사망(2020)으로 사실상 죽었지만, RTMP 프로토콜 위의
tag구조는 OBS·Twitch·YouTube Live의 송출 측 표준으로 남아있다. “OBS → RTMP(FLV tags) → ingest server → HLS(fMP4) → viewer” 가 현대 라이브 파이프라인. 즉 FLV는 송출 와이어 프로토콜, MP4/HLS는 시청 측 포맷으로 갈렸다.
“MKV가 ISO 표준이 아닌 이유”
MKV는 1990년대 후반 러시아 개발자가 시작한 오픈 프로젝트(Matroska). ISO 표준에 들어가지 못한 건 너무 자유롭기 때문 — 어떤 코덱도 담을 수 있다 는 게 표준화 입장에선 약점. 그러나 그 자유로움이 팬섭·고화질 아카이브 커뮤니티의 마음을 잡았다. Google이 WebM(MKV 부분집합)을 만들면서 제한된 MKV가 다시 웹 표준에 합류.
“CMAF는 HLS와 DASH를 통일하려 했다”
2017년 Apple·MS·Netflix·Akamai가 CMAF (Common Media Application Format) 표준화. 같은 fMP4 세그먼트를 HLS와 DASH 둘 다 가리킬 수 있게 — 인코딩·CDN 비용을 한 번만 내자는 야심. 결과: CMAF는 기술적으로 잘 되지만 DRM 차이(FairPlay vs Widevine)와 manifest 차이로 완전 통일은 미완. 그래도 fMP4 세그먼트의 표준은 사실상 CMAF.
요약 + Mermaid
컨테이너는 코덱을 포장하는 형식이며, atom/box (MP4 계열)와 stream (MPEG-TS) 두 가지 모델이 있다. MP4는 웹·OTT의 표준, MKV는 자유도 챔피언이지만 iOS 비호환, MPEG-TS는 라이브, WebM은 Google 친화. faststart로 moov를 앞으로, fMP4로 fragment 쪼개기, codecs 파라미터로 capability 명시 — 이 셋이 모던 컨테이너 운용의 90%.