04 — CMAF (Common Media Application Format)
이 문서가 답하는 질문: HLS와 DASH가 같은 segment 파일을 쓸 수 있는가? 그리고 그 합의를 누가 만들었는가? 표준: ISO/IEC 23000-19 (MPEG, 2017). 핵심 한 줄: CMAF는 *fMP4 컨테이너 표준 + 공통 암호화(CENC/CBCS)*를 정해서 한 segment를 HLS와 DASH가 동시에 참조하게 만드는 합의다.
한 줄 답 (Pyramid Top)
CMAF는 새로운 프로토콜이 아니다. **“같은 fMP4 segment를 만들면 HLS 매니페스트와 DASH 매니페스트 둘 다에서 가리킬 수 있다”**는 합의다. 인코딩 1번 → 매니페스트 2종 → 인프라 비용 약 절반.
Why — 왜 통합이 필요했나
CMAF 이전(2016 이전)에는 HLS와 DASH를 둘 다 지원하려면:
| 자원 | HLS-only | DASH-only | 둘 다 |
|---|---|---|---|
| 인코딩 | TS variant 5개 | fMP4 5개 | TS 5개 + fMP4 5개 = 10개 |
| 저장 (1시간 영상 예) | 5GB | 5GB | 10GB |
| CDN 캐시 | TS만 | fMP4만 | 둘 다 따로 캐시 |
| DRM 패키징 | SAMPLE-AES | CENC | 별도 작업 |
→ 저장·인코딩·CDN 비용 모두 2배. 그리고 두 segment가 내용은 같은데 헤더만 다른 낭비.
CMAF는 두 진영이 모인 워크숍(Microsoft + Apple, 2015)에서 시작 → 2017년 ISO/IEC 23000-19 표준화. 합의 핵심:
- 같은 fMP4 컨테이너로 만든다.
- 같은 CENC 암호화 스킴을 쓴다 (CBCS와 CTR 둘 다 정의).
- 매니페스트(m3u8 / MPD)만 다르게 만든다.
→ 저장은 1번, 매니페스트는 2번. 이 합의가 차세대 OTT 인프라의 표준이 되었다 (Netflix, Disney+, Apple TV+, Amazon Prime Video).
How — fMP4의 구조
CMAF의 컨테이너는 fragmented MP4다. 일반 MP4와의 차이는 시간 분할.
일반 MP4 (Progressive)
[ftyp][moov][mdat ]
↑ ↑
전체 메타데이터 전체 미디어moov(Movie Box)가 모든 sample의 위치/시간을 한 곳에 가진다.- 영상이 길면
moov가 거대해지고, 받기 전엔 재생 시작 못함.
fMP4 (Fragmented)
[ftyp][moov] [moof][mdat] [moof][mdat] [moof][mdat] ...
init segment ─┬──────── fragment 1 ── fragment 2 ── ...
각 fragment가 자기 시간 정보를 들고 있음moov는 *변환표(decoder config)*만, sample 위치는 각moof(Movie Fragment Box)에.moof + mdat한 쌍 = 한 fragment = 한 segment.- 한 fragment가 자기 시작 시간/duration을 알아 어디서든 시작 가능.
박스 구조 (실제 dump 흐름)
| 박스 | 의미 | 핵심 필드 |
|---|---|---|
ftyp | 파일 타입 식별 | cmfc, iso6 등 |
moov | 글로벌 메타데이터 | track 목록, 코덱 config |
styp | segment 타입 (옵션) | msdh(media segment), msix(indexed) |
moof | fragment 헤더 | sequence number |
tfdt | decode time | 영상 전체에서의 누적 시작 시간 (timescale 단위) |
trun | sample 정보 | duration, size, offset, flags |
mdat | 실제 미디어 | H.264 NAL units, AAC frames 등 |
sidx | segment index | seek table (선택) |
What — CMAF Brand와 호환성 시그널
ftyp 박스의 brand 코드가 이 fMP4가 어떤 표준을 따르는가를 표시한다.
| Brand | 의미 |
|---|---|
iso6 | ISO Base Media File Format v6 (fMP4 일반) |
cmfc | CMAF compliant (CMAF 호환 필수 마커) |
cmf2 | CMAF + WebM 호환 (드뭄) |
cmfl | CMAF Low-Latency profile |
dash | DASH 호환 (legacy) |
hlsf | HLS fMP4 호환 (legacy) |
표준 dump (mp4dump):
[ftyp] size=8+24
major_brand = cmfc
minor_version = 0
compatible_brands = cmfc iso6 dash hlsf→ 보통 cmfc, iso6, dash, hlsf를 모두 박아 어떤 매니페스트에서든 통과. 플레이어는 지원하는 brand 중 하나라도 있으면 받아들인다.
What — Common Encryption (CENC) — 두 가지 모드
CMAF의 진짜 가치는 컨테이너 통일보다 암호화 통일이다.
CTR mode (cenc) — Counter mode AES-128
sample 평문 ──XOR── AES-CTR(key, counter) ──→ 암호문
counter = IV ‖ block_index- Block 단위로 키를 streaming처럼 적용. 부분 복호화 가능.
- 역사적으로 DASH/Widevine/PlayReady가 CENC CTR을 채택.
CBCS mode (cbcs) — CBC + sample-level 패턴 (Pattern Encryption)
한 sample을 N개 block으로 나누고:
처음 1 block 암호화 → 9 block 평문 → 1 block 암호화 → ...
(1:9 패턴이 Apple의 default)- 부분만 암호화 → CPU 부담 ↓.
- 키는 전체 sample에 동일.
- 역사적으로 FairPlay가 CBCS를 요구.
통합 모드 (cbcs로 합의)
CMAF 후기 표준은 CBCS를 공통 모드로 권장한다 — Apple이 CBCS만 받기 때문.
- Widevine과 PlayReady도 CBCS 지원 (2018년부터).
- 즉 한 번 CBCS로 암호화하면 세 DRM이 모두 풀 수 있다.
| DRM | CTR (cenc) | CBCS (cbcs) |
|---|---|---|
| Widevine | ✅ (legacy) | ✅ (modern) |
| PlayReady | ✅ (legacy) | ✅ (modern) |
| FairPlay | ❌ | ✅ |
→ 이 한 줄이 CMAF의 존재 이유. 자세한 DRM은 07-drm.md.
What — 같은 segment를 가리키는 HLS와 DASH
디렉터리 (one source of truth)
cdn.example.com/movies/abc/
├── video/
│ ├── 1080p/
│ │ ├── init.mp4
│ │ ├── seg_00001.m4s
│ │ ├── seg_00002.m4s
│ │ └── ...
│ ├── 720p/
│ │ └── ...
│ └── 360p/
├── audio/
│ ├── ko/init.mp4 + seg_*.m4s
│ └── en/init.mp4 + seg_*.m4s
├── subs/
│ ├── ko.vtt
│ └── en.vtt
├── master.m3u8 ← HLS 매니페스트
├── manifest.mpd ← DASH 매니페스트
└── 1080p/index.m3u8 ... ← variant 매니페스트들HLS variant playlist (fMP4)
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:6
#EXT-X-MAP:URI="../video/1080p/init.mp4"
#EXTINF:6.006,
../video/1080p/seg_00001.m4s
#EXTINF:6.006,
../video/1080p/seg_00002.m4s
...
#EXT-X-ENDLISTDASH MPD (같은 segment)
<Representation id="v1080" bandwidth="5300000" width="1920" height="1080">
<SegmentTemplate timescale="90000"
initialization="video/1080p/init.mp4"
media="video/1080p/seg_$Number%05d$.m4s"
startNumber="1">
<SegmentTimeline>
<S t="0" d="540540" r="299"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>→ 같은 init.mp4와 같은 seg_NNNNN.m4s를 가리킨다. 다른 점은 매니페스트 형식뿐.
What — chunk-level (LL-CMAF)
CMAF는 low-latency 확장도 정의한다. 한 segment를 더 작은 chunk로 쪼개 생성 즉시 푸시.
seg_00001.m4s (6초 길이) =
[moof][mdat] ← chunk 1 (200ms)
[moof][mdat] ← chunk 2 (200ms)
[moof][mdat] ← chunk 3 (200ms)
...
[moof][mdat] ← chunk 30 (200ms)- 인코더는 chunk 1을 만든 즉시 HTTP/1.1 chunked transfer로 내보낸다.
- 플레이어는 segment가 끝나기 전에 일부를 받아 디코딩 시작 → 글래스-투-글래스 지연 ↓.
- HLS의 partial segment(
05-low-latency.md)와 같은 메커니즘. CMAF에서 통일.
What-if — 잘못 쓰면 어떻게 깨지는가
| 증상 | 원인 | 처방 |
|---|---|---|
| iOS는 안 되고 Chrome만 됨 | CTR(cenc) 암호화 사용 | CBCS로 재패키징 |
init.mp4가 매번 바뀜 | 인코더가 매 segment마다 init 재생성 | init은 한 번 고정 — moov가 segment 사이에 변경되면 안 됨 |
cmfc brand 누락 | 일부 플레이어가 거부 | ftyp의 compatible_brands에 cmfc 추가 |
| Widevine은 풀고 FairPlay는 못 풂 | default_KID만 있고 PSSH가 FairPlay용으로 없음 | EXT-X-KEY로 FairPlay skd:// URI 추가 |
| HLS는 재생 OK, DASH는 깨짐 | timescale이 90000이 아니라 변칙(예: 25000) | 90000으로 통일 또는 timescale 명시 일관 |
| audio가 silent | audio init segment의 esds가 변칙 | AAC config 검증 (sample rate / channel) |
| seek가 frame 아닌 segment 단위 | tfdt의 decode time 부정확 | 인코더 설정에서 frag_keyframe/movflags +cmaf |
Insight — 흥미로운 이야기
“CMAF는 사실 Microsoft와 Apple의 화해다”
CMAF 워크숍(2015) 직전, Apple은 HLS+TS, Microsoft는 Smooth Streaming (PIFF, fMP4 변종). 두 회사가 공통 컨테이너에 합의한 게 CMAF의 시작이었다. ISO/IEC가 인증해서 표준이 되었지만, 제안서는 이 두 회사에서 나왔다. Adobe Flash가 죽고, RTMP가 식고, HTML5 비디오가 모두를 통일하는 시기에 마지막 분열을 봉합한 합의.
“CBCS가 결국 이긴 이유는 Apple”
CTR이 더 학술적으로 깔끔하다. 그런데 FairPlay가 CBCS만 받는다 → iOS를 포기할 수 없으니 모두가 CBCS로 갔다. 시장 점유율이 표준을 끈 사례.
“인코딩 1번이 인프라 30~50% 절감”
Netflix 같은 거대 OTT는 한 영화에 수천 가지 변형(언어/HDR/codec/해상도)을 만든다. HLS와 DASH를 따로 만들면 이 모든 게 2배. CMAF로 통합한 결과 Petabyte 수준의 저장 절감을 보고했다 (Netflix Tech Blog, 2016). 비용 외에도 origin 캐시 hit ratio가 올라간다 — CDN이 같은 파일에 두 매니페스트 트래픽이 모두 hit하므로.
“CMAF는 LL의 전제다”
Low-latency를 하려면 chunk-level transfer가 필요한데, 그건 fMP4의 fragment 단위가 있어야 가능하다. MPEG-TS는 패킷이 188 byte 단위라 chunk 개념이 다르다. 그래서 LL-HLS도 fMP4 기반이다. 즉 CMAF가 없으면 LL도 없다.
한 단락 요약 + Mermaid
CMAF는 fMP4 컨테이너와 CENC/CBCS 암호화를 표준화해서 같은 segment를 HLS와 DASH가 동시에 참조하게 만드는 합의다. 새 프로토콜이 아니라 공통 contract. 결과: 인코딩·저장·CDN·DRM 패키징이 모두 절반. 그리고 이게 LL 스트리밍의 전제 조건이다.
→ 다음 파일 05-low-latency.md: 같은 CMAF segment를 더 잘게 쪼개 라이브 지연을 30초 → 3초로 줄이는 기법.