📁 File6. 스트리밍04 — CMAF (Common Media Application Format)

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-onlyDASH-only둘 다
인코딩TS variant 5개fMP4 5개TS 5개 + fMP4 5개 = 10개
저장 (1시간 영상 예)5GB5GB10GB
CDN 캐시TS만fMP4만둘 다 따로 캐시
DRM 패키징SAMPLE-AESCENC별도 작업

저장·인코딩·CDN 비용 모두 2배. 그리고 두 segment가 내용은 같은데 헤더만 다른 낭비.

CMAF는 두 진영이 모인 워크숍(Microsoft + Apple, 2015)에서 시작 → 2017년 ISO/IEC 23000-19 표준화. 합의 핵심:

  1. 같은 fMP4 컨테이너로 만든다.
  2. 같은 CENC 암호화 스킴을 쓴다 (CBCS와 CTR 둘 다 정의).
  3. 매니페스트(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
stypsegment 타입 (옵션)msdh(media segment), msix(indexed)
mooffragment 헤더sequence number
tfdtdecode time영상 전체에서의 누적 시작 시간 (timescale 단위)
trunsample 정보duration, size, offset, flags
mdat실제 미디어H.264 NAL units, AAC frames 등
sidxsegment indexseek table (선택)

What — CMAF Brand와 호환성 시그널

ftyp 박스의 brand 코드가 이 fMP4가 어떤 표준을 따르는가를 표시한다.

Brand의미
iso6ISO Base Media File Format v6 (fMP4 일반)
cmfcCMAF compliant (CMAF 호환 필수 마커)
cmf2CMAF + WebM 호환 (드뭄)
cmflCMAF Low-Latency profile
dashDASH 호환 (legacy)
hlsfHLS 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이 모두 풀 수 있다.
DRMCTR (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-ENDLIST

DASH 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가 silentaudio 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초로 줄이는 기법.