CMAF(Common Media Application Format) 레퍼런스 — ISO 23000-19·fMP4·HLS+DASH·저지연
이 글의 핵심
CMAF는 ‘한 번 패키징한 fMP4’로 HLS와 MPEG-DASH를 동시에 서빙하도록 정렬된 미디어 컨테이너 프로파일입니다. ISO/IEC 23000-19의 트랙·헤더/프래그먼트·스위칭/셀렉션 개념, 마스터 인덱스(m3u8·MPD)와 미디어 바이트의 관계, LL-HLS·LL-DASH와의 결합, FFmpeg·Shaka Packager·Nginx·hls.js·dash.js로의 구현, 프래그먼트/청크·CDN 튜닝까지 참조서 형태로 정리합니다.
CMAF(Common Media Application Format)는 MPEG이 ISO/IEC 23000-19로 정의한 공통 미디어 프로파일입니다. 핵심은 하나의 fMP4(Fragmented MP4) 바이트 스트림을 HLS 플레이리스트와 MPEG-DASH 매니페스트(ISO/IEC 23009-1)가 함께 가리킬 수 있도록, 초기화 데이터와 세그먼트 경계(랜덤 액세스 지점), 타임스탬프를 ABR 전환에 맞게 정렬하는 것입니다.
상용 솔루션이나 CDN이 “CMAF 지원”을 내세우더라도 실제로는 Apple HLS 저작 가이드, DASH-IF 가이드라인, 그리고 Safari·Chrome·셋톱박스 같은 클라이언트의 지원 범위가 서로 다릅니다. 이 글의 명령과 설정은 구조를 설명하기 위한 예시이므로, 배포 전에는 반드시 대상 기기 목록을 정해 놓고 검증하십시오.
프로토콜 스펙 (ISO BMFF, CMAF)
ISO BMFF(ISO/IEC 14496-12)와 fMP4
ISO/IEC 14496-12 ISO Base Media File Format(ISO BMFF, 이하 BMFF)은 MP4와 fMP4의 기본 구조를 정의합니다. 일반(progressive) MP4는 하나의 moov에 모든 샘플 테이블을 담고 mdat에 미디어를 연속 배치합니다. 반면 fMP4는 moov에 트랙 설명만 두고, moof+mdat 쌍을 반복하면서 전송·재생에 알맞은 조각(fragment)을 쌓아 갑니다.
CMAF는 이 BMFF 구조 위에, 세그먼트 경계에서 비트레이트·해상도가 다른 트랙으로 전환할 수 있고 트랙 간 동기가 유지되도록 제약을 얹은 것입니다. 그래서 CMAF를 이해하려면 먼저 BMFF 수준에서 트랙, 트랙 프래그먼트, 무비 프래그먼트의 관계를 알고 있는 편이 좋습니다.
ftyp: 파일의 브랜드(isom,mp41, CMAF의cmfc등)를 밝혀, 파서가 이 파일을 어떤 규칙으로 읽을지 판단하는 기준이 됩니다.moov: 트랙 설명(trak, 샘플 엔트리가 담긴stsd등)을 담는 전역 메타데이터입니다. CMAF Header의 핵심입니다.moof+mdat: 미디어 프래그먼트입니다. CMAF Fragment로 주소를 지정하는 바이트 구간이 됩니다.
fMP4는 온디맨드용 파일일 수도 있고, 라이브처럼 HTTP로 조각을 연속으로 받아 이어 붙이는 형태일 수도 있습니다. CMAF는 후자를 염두에 두고, 같은 바이트 구간을 여러 인덱스(HLS 플레이리스트, DASH MPD)가 참조할 수 있도록 설계되었습니다.
CMAF Track(트랙) 구조
CMAF Track은 하나의 논리적 재생 단위(오디오, 비디오, 자막 트랙)로, DASH의 Representation이나 HLS의 렌디션과 거의 1:1로 대응합니다. 구현에서 중요한 점은 세 가지입니다. 각 트랙이 독립적으로 디코딩될 수 있도록 CMAF Header에 디코더 설정이 들어 있어야 하고, CMAF Fragment의 디코드 시간은 단조 증가해야 하며, 랜덤 액세스 지점(RAP) 배치가 ABR 전환 지점과 어긋나지 않아야 합니다.
비디오는 H.264/AVC, H.265/HEVC 등 CMAF 미디어 프로파일이 허용하는 코덱과 샘플 규칙을 따라야 합니다. 오디오 AAC는 fMP4 안에서 ADTS 헤더 없이 raw 액세스 유닛으로 저장되고 디코더 설정은 샘플 엔트리(esds)에 들어갑니다. TS 기반 HLS에서 쓰던 ADTS 스트림을 그대로 넣으면 안 되는 이유입니다. 실서비스에서는 DASH-IF 가이드와 Apple HLS Authoring Specification이 권장하는 코덱·프로파일을 함께 확인합니다.
CMAF Header vs CMAF Fragment
문헌과 도구에 따라 Initialization Segment, CMAF Header 같은 용어가 섞여 쓰이므로 역할을 기준으로 정리해 두는 것이 안전합니다.
| 구성 요소 | 일반적 내용(개념) | HLS(대응) | DASH(대응) |
|---|---|---|---|
| CMAF Header | 트랙·코덱·샘플 엔트리 등 초기화에 필요한 ftyp+moov | EXT-X-MAP가 가리키는 초기화 바이트 | Initialization sourceURL (Range 가능) |
| CMAF Fragment | moof+mdat로 이루어진 미디어 구간 | EXTINF + 세그먼트 URI (또는 같은 URI의 EXT-X-BYTERANGE) | SegmentURL / SegmentTemplate |
CMAF Header는 트랙마다 한 번 받아 캐싱해 두고 재사용하며, CMAF Fragment는 시간 순서대로 이어집니다. ABR이 다른 트랙으로 전환할 때 플레이어는 그 트랙의 Header로 디코더를 다시 설정합니다. 스위칭 세트 안의 트랙들이 같은 코덱 계열과 호환되는 설정을 쓰도록 제약하는 이유가 바로 이 재설정이 매끄럽게 되도록 하기 위해서입니다.
CMAF Switching Set(스위칭 세트)
Switching Set은 같은 콘텐츠를 비트레이트·해상도만 달리 인코딩한 트랙들의 집합으로, ABR이 세그먼트 경계에서 서로 바꿔 탈 수 있도록 프래그먼트 경계가 정렬되어 있어야 합니다. 트랙마다 프래그먼트 길이가 다르거나 경계에 RAP가 없으면 전환 시 화면이 끊기거나 버퍼가 요동칩니다. 그래서 인코딩 단계에서 GOP와 키프레임 위치를 맞추고 세그먼트 길이를 통일하는 것이 사실상 필수입니다.
정렬을 점검할 때는 다음 두 가지를 봅니다.
- 세그먼트 길이가 두 인덱스에서 같게 기술되는지(HLS
EXT-X-TARGETDURATION·EXTINF, DASHSegmentTemplate@duration또는SegmentTimeline) - 타임라인이 MPD의
Period와 HLS의EXT-X-PROGRAM-DATE-TIME(사용할 경우) 사이에서 어긋나지 않는지
CMAF Selection Set(셀렉션 세트)
Selection Set은 같은 미디어 유형에서 사용자가 하나를 고르는 대안들(예: 다국어 음성, 서로 다른 코덱의 비디오)을 묶습니다. ABR의 비트레이트 전환이 아니라 언어, 역할, 접근성 같은 콘텐츠 선택이 목적이라는 점에서 Switching Set과 개념적으로 구분됩니다. HLS의 EXT-X-MEDIA(TYPE=AUDIO/SUBTITLES)나 MPD의 AdaptationSet@lang / Role에 대응하는 경우가 많지만, 도구마다 그룹핑 표현이 다를 수 있으므로 패키저 출력을 검증해야 합니다.
HLS + DASH 통합(단일 CMAF 팩)
“단일 파일(세트)로 양쪽 지원”이란?
하나의 CMAF 미디어 바이트(Header + fMP4 프래그먼트)를 두고, 이를 가리키는 인덱스만 두 가지로 만든다는 뜻입니다.
- HLS 쪽: 마스터·미디어 m3u8이
EXT-X-MAP과 세그먼트 URL(또는EXT-X-BYTERANGE)을 나열합니다. - DASH 쪽: MPD가
BaseURL과SegmentTemplate또는SegmentList로 같은 URL·Range를 기술합니다.
미디어 바이트는 한 벌이고 “어디서 찾는지”를 알려 주는 인덱스만 두 벌인 셈이며, 이것이 CMAF라는 이름의 “Common”이 뜻하는 바입니다.
fMP4 세그먼트 공유
공유한다는 것은 결국 URL이 같다는 뜻입니다.
https://cdn.example.com/cmaf/video/720p/seg_00012.m4s를 m3u8과 MPD가 그대로 가리킬 수 있습니다(또는 하나의.mp4파일 안의 byte range).EXT-X-MAP의 URI = Header URL- MPD
Initialization@sourceURL= 같은 Header URL
CDN의 캐시 키는 최종 URL(과 Range)이므로, HLS 사용자와 DASH 사용자가 같은 캐시 객체를 히트하게 되어 오리진 부하와 대역 비용 면에서 유리합니다.
Playlist(m3u8) vs Manifest(MPD) 차이
| 측면 | HLS(Playlist) | DASH(MPD) |
|---|---|---|
| 형식 | 텍스트(태그+URI) | XML(요소+속성) |
| ABR | EXT-X-STREAM-INF + variant m3u8 | AdaptationSet + Representation@bandwidth |
| 초기화 | EXT-X-MAP | Initialization (Range) |
| 지속 | EXT-X-TARGETDURATION, EXTINF | SegmentTemplate@duration 등 |
| 고급/확장 | Apple의 LL-HLS·DRM 관련 태그 | MPD @profiles, DASH-IF CMAF 관련 프로파일 |
표현력은 DASH MPD가 더 풍부하지만, 가장 많은 단말(특히 Apple 기기)을 커버하려면 HLS 쪽 요구 사항도 빠짐없이 맞춰야 합니다. CMAF는 미디어만 공통으로 만들어 줄 뿐이므로, 두 인덱스가 각자의 규칙을 만족하는지는 따로 검수해야 합니다.
저장공간 50% 절약이 성립하는 원리
전제가 중요합니다. 과거에는 HLS용 MPEG-2 TS 세그먼트와 DASH(또는 Smooth Streaming)용 fMP4 세그먼트를 따로 만들어, 같은 인코딩 결과를 서로 다른 컨테이너로 두 벌 보관하는 경우가 많았습니다. CMAF로 한 벌의 fMP4가 양쪽을 커버하면 이 중복이 사라지므로 미디어 저장량이 절반 가까이 줄어들 수 있습니다. 매니페스트, 자막, 메타데이터는 소량 중복되므로 정확히 50%는 아닙니다.
패키징과 CDN 캐시도 한 벌로 줄어 작업 비용과 캐시 효율 면에서도 이득이 있습니다. 다만 구형 단말 호환, 광고 삽입 시스템, DRM 방식(예: 구형 FairPlay 클라이언트는 cbcs만 지원하는 반면 일부 Widevine/PlayReady 구형 클라이언트는 cenc만 지원) 때문에 TS나 다른 암호화 변형을 계속 병행해야 하는 서비스라면 50% 모델이 그대로 적용되지 않습니다.
LL-HLS & LL-DASH(저지연 CMAF)
Low-Latency의 구현 골격 (CMAF 맥락)
저지연은 짧은 조각, 조각이 완성되기 전부터 공개하는 조기 가용성, HTTP 청크 전송, 빠르게 갱신되는 인덱스가 모두 갖춰져야 가능합니다. Apple LL-HLS는 파트(Partial Segment), 프리로드 힌트(EXT-X-PRELOAD-HINT), 블로킹 플레이리스트 리로드로 이를 구현하고, DASH 쪽은 DASH-IF의 저지연 가이드라인에 따라 CMAF 청크를 청크 전송으로 흘려보내는 방식(LL-DASH)을 씁니다.
목표로 흔히 말하는 2~3초 지연은 키프레임 간격, 플레이어 버퍼, 네트워크 지터에 따라 쉽게 무너집니다. CMAF는 포맷 차원에서 저지연을 가능하게 할 뿐이고, 실제 수치는 인코더부터 플레이어까지 전 구간을 튜닝한 결과입니다.
Chunked Transfer Encoding
HTTP/1.1의 청크 전송(Transfer-Encoding: chunked)은 응답 본문 전체 길이를 모르는 상태에서도 만들어지는 대로 조금씩 보낼 수 있게 해 줍니다. 그래서 세그먼트 파일이 다 써지기 전에 엣지와 클라이언트가 앞부분부터 받아 재생을 시작할 수 있습니다. HTTP/2와 HTTP/3에는 청크 전송 인코딩이 없고, 대신 DATA 프레임으로 같은 효과를 냅니다. 저지연에서는 다음을 맞춰야 합니다.
- 오리진 → CDN → 클라이언트 전 구간이 응답을 모았다가 보내지 않고 받은 즉시 흘려보낼 것
- 중간 프록시가 전체 응답을 버퍼링한 뒤에야 전달하는 설정이 아닐 것
- Range 요청과 청크 전송에 대한 정책이 오리진과 CDN에서 일치할 것
일부 CDN이나 구성은 완성되지 않은 객체를 스트리밍으로 전달하는 데 최적화되어 있지 않으므로, 평균이 아니라 P95 지연을 측정해 판단해야 합니다.
Partial Segments(파트)와 “조기 가용”
LL-HLS에서는 세그먼트를 더 잘게 쪼갠 파트를 EXT-X-PART 태그로 차례차례 공개하고, 플레이어는 세그먼트 전체가 완성되기를 기다리지 않고 최신 파트부터 재생할 수 있습니다. 이 효과를 보려면 플레이어, 오리진, CDN이 모두 지원해야 합니다. 참고로 LL-HLS는 RFC 8216 본문이 아니라 Apple이 관리하는 후속 개정 사양(8216bis 초안)에 정의되어 있습니다. DASH·CMAF 쪽에서는 “chunk”라는 말이 문맥마다 다르게 쓰이므로, 사용하는 패키저의 문서를 1차 기준으로 삼으십시오.
용어 주의: Partial Segment, Chunk, CMAF Chunk라는 말은 제품과 문서마다 가리키는 대상이 겹쳐서 팀 내 혼란이 잦습니다. (a) 컨테이너 단위(moof+mdat 한 쌍인 CMAF 청크), (b) HTTP 청크 전송, (c) m3u8·MPD에 조기 공개되는 단위 중 어느 것을 말하는지 명시하는 습관을 들이는 것이 좋습니다.
HTTP/2(및 “Push”)와의 관계
초기 LL-HLS 사양은 HTTP/2 Server Push로 다음 파트를 밀어 주는 방식을 요구했지만, Apple은 2020년 개정에서 이를 프리로드 힌트와 블로킹 리로드로 대체했습니다. Chrome도 HTTP/2 Server Push 지원을 제거했으므로 새 설계에서 Push에 의존할 이유는 없습니다. 저지연의 핵심은 짧은 CMAF 프래그먼트·파트, 빠르게 갱신되는 인덱스, 오리진과 엣지의 지연 억제입니다. HTTP/3(QUIC) 같은 전송 계층 최적화는 별개의 축이므로, CMAF 패키징 변경과 섞지 말고 재생 시작 시간·리버퍼링·드롭 프레임 지표로 따로 측정하십시오.
2~3초 목표는 GOP 길이, 초기 버퍼, 전송 지연의 합이 모두 작을 때만 가능하며, ABR·암호화·광고 삽입이 더해지면 달성하기가 더 어려워집니다.
실전 구현(FFmpeg, Shaka, Nginx, 브라우저)
아래 명령과 설정은 형태를 이해하기 위한 예시입니다. 코덱, 키프레임 간격, 비트레이트 상한은 서비스 요구에 맞게 조정하고 검수하십시오.
FFmpeg로 CMAF(유사) fMP4 래더 생성
VOD나 테스트용 ABR 래더를 빠르게 만들 때는 FFmpeg의 DASH fMP4 출력이 편리합니다. 다만 CMAF 적합성 검증과 HLS·DASH 매니페스트 동시 생성까지 엄격히 챙기려면 전용 패키저를 쓰는 편이 낫습니다.
예시(개념): 입력 하나를 여러 비트레이트로 인코딩해 DASH fMP4로 출력합니다.
# 예시(개념/환경·코덱에 맞게 수정): 1080p/720p/480p 3Rend, DASH fMP4
ffmpeg -y -i input.mp4 -filter_complex \
"[0:v]split=3[v1][v2][v3]; \
[v1]scale=1920:1080[v1out]; [v2]scale=1280:720[v2out]; [v3]scale=854:480[v3out]" \
-map "[v1out]" -c:v:0 libx264 -b:v:0 5000k -maxrate:v:0 5500k -bufsize:v:0 11000k -g 48 -keyint_min 48 -sc_threshold 0 \
-map "[v2out]" -c:v:1 libx264 -b:v:1 3000k -maxrate:v:1 3300k -bufsize:v:1 6600k -g 48 -keyint_min 48 -sc_threshold 0 \
-map "[v3out]" -c:v:2 libx264 -b:v:2 1000k -maxrate:v:2 1100k -bufsize:v:2 2000k -g 48 -keyint_min 48 -sc_threshold 0 \
-map 0:a? -c:a aac -b:a 128k -ac 2 \
-f dash -use_timeline 1 -use_template 1 -init_seg_name "init_$RepresentationID$.m4s" -media_seg_name "seg_$Number$.$RepresentationID$.m4s" \
-seg_duration 4 -adaptation_sets "id=0,streams=v id=1,streams=a" out/manifest.mpd
-g, -keyint_min, -sc_threshold 0으로 키프레임 간격을 고정해 모든 렌디션의 경계가 같은 시점에 오도록 합니다. 입력이 24fps라면 -g 48은 2초 GOP이고, -seg_duration 4는 GOP 두 개마다 세그먼트를 끊습니다. 세그먼트 길이는 GOP 길이의 정수배여야 경계가 정확히 맞습니다. FFmpeg의 dash 먹서는 -hls_playlist 1 옵션으로 같은 세그먼트를 가리키는 m3u8도 함께 쓸 수 있지만, 두 매니페스트의 교차 정합까지 확인하려면 Shaka Packager나 Bento4, 그리고 실제 플레이어 재생 테스트를 병행하는 편이 안전합니다.
Shaka Packager — CMAF
Shaka Packager는 한 번의 실행으로 같은 fMP4 세그먼트에 대한 DASH MPD와 HLS 플레이리스트를 함께 만들 수 있어 CMAF 워크플로에 자주 쓰입니다. 입력은 스트림 디스크립터로 지정하며, 정확한 플래그는 릴리스마다 바뀔 수 있으니 문서를 확인하십시오.
형태(템플릿):
# 예시(개념): --hls / --mpd, CMAF, DRM 옵션은 릴리스·라이선스에 맞게
packager \
in=input.mp4,stream=video,init_segment=init_video.mp4,segment_template=video_$Number$.m4s,drm_label=SD \
in=input.mp4,stream=audio,init_segment=init_audio.mp4,segment_template=audio_$Number$.m4s,drm_label=SD \
--hls_master_playlist_output hls.m3u8 --mpd_output manifest.mpd
- DRM(Widevine/PlayReady/FairPlay)을 하나의 CMAF 세트로 처리하려면
--protection_scheme cbcs로 암호화하고, 모든 대상 클라이언트가cbcs를 지원하는지 확인해야 합니다. 옵션 이름은 버전에 민감하니 릴리스 노트를 확인하십시오.
Nginx로 CMAF 정적/준동적 서빙
핵심은 네 가지입니다. (1) 올바른 MIME 타입(video/mp4, application/dash+xml, application/vnd.apple.mpegurl), (2) Range 지원과 캐시 헤더, (3) 웹 플레이어를 위한 CORS, (4) 저지연이라면 버퍼링 억제입니다.
최소 구성(개념, http / server / location):
# mime.types에 mpd/m3u8/m4s 등 매핑을 명확히
location /cmaf/ {
alias /var/www/cmaf/;
add_header Access-Control-Allow-Origin * always;
add_header Cache-Control "public, max-age=31536000, immutable" always;
# 인덱스(playlist/mpd)는 짧은 TTL(라이브)
# 주의: 하위 location에 add_header를 쓰면 상위의 add_header가 모두 무시되므로 CORS 헤더를 다시 적어야 함
location ~* \.(m3u8|mpd)$ {
add_header Access-Control-Allow-Origin * always;
add_header Cache-Control "public, max-age=1, s-maxage=1" always;
}
# 작은 CMAF 파트(저지연) 캐시 — CDN과 정책을 맞출 것
types {
application/dash+xml mpd;
application/vnd.apple.mpegurl m3u8;
video/mp4 m4s mp4;
}
}
Nginx의 add_header는 상속 규칙이 독특해서, 하위 location에 add_header가 하나라도 있으면 상위 블록의 add_header는 전부 적용되지 않습니다. 매니페스트에만 CORS 헤더가 빠져 브라우저 플레이어가 첫 요청부터 실패하는 흔한 원인이 이것입니다.
- 저지연 구성에서 m3u8·MPD는
Cache-Control: no-cache나 아주 짧은s-maxage,stale-while-revalidate를 조합하는 경우가 많습니다. 반면.m4s세그먼트는 URL이 바뀌지 않는 한 내용도 바뀌지 않으므로 긴 캐시를 주는 것이 전형적입니다.
브라우저: hls.js + dash.js
- HLS(fMP4/CMAF):
hls.js, 또는 Video.js의@videojs/http-streaming(VHS)을 씁니다. 저지연 모드와 fMP4 지원 범위는 버전별로 확인하십시오. - DASH(CMAF):
dash.js의 DRM(Protection), ABR 설정, 저지연 모드를 버전별 문서로 확인하십시오.
Video Element + MSE 공통 패턴(개념):
<video id="v" controls playsinline></video>
<script type="module">
const video = document.getElementById("v");
// HLS: new Hls(); hls.loadSource("master.m3u8"); hls.attachMedia(video);
// DASH: dashjs.MediaPlayer().create().initialize(video, "manifest.mpd", true);
</script>
Safari는 HLS를 네이티브로 재생하고, Chromium 계열은 MSE 위에서 JS 플레이어가 동작합니다. 그래서 CORS, CSP, 플랫폼별 HEVC 지원, EME(DRM) 문제가 브라우저마다 다르게 나타나며, CMAF에 DRM까지 얹으면 조합이 더 늘어납니다. hls.js와 dash.js의 릴리스 노트에서 저지연, CMCD, ABR, MSE 제약 관련 변경을 먼저 확인하십시오.
최적화(프래그먼트·청크·CDN·대역)
Fragment 크기 튜닝
- 프래그먼트가 짧을수록 지연은 줄지만, HTTP 요청 수와 인덱스 갱신 부하는 늘어납니다.
- 키프레임(RAP)이 프래그먼트 경계와 맞지 않으면 ABR 전환 품질이 떨어집니다. 세그먼트 경계에는 반드시 키프레임이 있어야 합니다.
- 전통적인 ABR은 4
6초, 저지연을 시도할 때는 12초 세그먼트가 흔합니다. 짧은 GOP는 압축 효율을 떨어뜨리므로, 저지연 구성에서는 세그먼트는 그대로 두고 그 안을 CMAF 청크나 LL-HLS 파트로 잘게 나누는 방식이 일반적입니다. - 오디오 프레임 길이(AAC는 1024샘플)는 비디오 프레임 길이와 딱 나누어떨어지지 않으므로, 오디오 세그먼트 경계가 비디오와 조금씩 어긋나는 것은 정상입니다. 어긋남이 누적되지 않는지를
ffprobe와 검증기로 확인합니다.
Chunked Encoding(전송) 설정
- 오리진(Nginx, Node, Go, Envoy 등)이 응답을 모았다가 보내지 않고 스트리밍하는지, 앞단 프록시의 버퍼링을 꺼야 하는지 확인합니다.
- HTTP/2·HTTP/3의 멀티플렉싱이 플레이리스트와 세그먼트를 동시에 요청하는 패턴에서 실제로 이득이 있는지 측정합니다.
- CDN이 완성되지 않은 객체를 여러 클라이언트에게 동시에 스트리밍해 주는지는 상품과 지역에 따라 편차가 크므로 벤더에 확인합니다.
CDN 캐싱 전략
- Header(init): 긴 TTL을 주되, 키 로테이션 등으로 KID가 바뀌면 Header도 바뀌므로 URL도 바꿔야 합니다.
- 세그먼트(
.m4s): 콘텐츠 해시나 버전이 담긴 경로를 써서 같은 URL에 다른 바이트가 올라가는 일을 막습니다. - m3u8/MPD: 짧은 TTL과 일관된
ETag/Last-Modified. 저지연에서는stale-while-revalidate를 섞는 경우가 흔합니다. - Range: Range 요청을 캐시가 어떻게 저장하고 응답하는지(전체 객체를 받아 잘라 주는지, 조각별로 캐싱하는지) 벤더별로 확인합니다.
- 지역(PoP) 편차: P95 지연, 리버퍼링 비율 등을 지역별 KPI로 봅니다.
대역폭 절약(압축/적응·CMCD)
- ABR 래더 설계, 코덱 선택(AVC/HEVC/AV1), 콘텐츠별 인코딩(per-title encoding)이 가장 큰 효과를 냅니다. CMAF는 같은 컨테이너 규칙으로 렌디션을 추가하기 쉽습니다.
- 오디오 전용 렌디션이나 WebVTT 같은 텍스트 트랙은 비디오를 보지 않는 상황의 대역을 줄여 줍니다.
- CMAF URL이 안정적이면 CDN 캐시 히트율이 올라가 원본 트래픽이 줄어듭니다.
- CMCD(Common Media Client Data, CTA-5004)는 플레이어가 요청마다 버퍼 길이, 비트레이트 같은 정보를 CDN에 전달하는 규격으로, 렌디션별 분석과 이상 구간 추적에 유용합니다.
트러블슈팅(현장 견해)
- A/V 싱크 드리프트: edit list, 타임스탬프 오프셋, 잘못된 Header 재사용(
EXT-X-MAP오지정)을 의심합니다.ffprobe, DASH-IF 검증기, 패키저 로그를 함께 봅니다. - ABR 떨림(과도한 전환): 대개 ABR 알고리즘(처리량 기반, 버퍼 기반 BOLA 등)과 설정 문제이며 CMAF 자체의 문제는 아닐 수 있습니다. dash.js는
addABRCustomRule로 사용자 규칙을 넣을 수 있습니다. 단 세그먼트 정렬이 나쁘면 그것이 원인일 수 있습니다. - CORS/EME/HTTPS: EME의 키 시스템은 Chrome은 Widevine, Edge는 PlayReady와 Widevine, Safari는 FairPlay로 나뉩니다. Header와 세그먼트, 라이선스 요청 모두 인증과 CORS를 통과해야 합니다.
- 캐시 오염: 배포 버그로 같은 URL에 다른 바이트가 올라가면 CDN마다 다른 내용을 내보냅니다. URL에 해시나 버전을 넣으십시오.
- 저지연 효과 없음: GOP, 세그먼트, 파트, 플레이리스트 갱신 주기, 엣지 버퍼를 함께 점검해야 합니다. 한 축만 짧게 줄이면 끊김만 늘어날 수 있습니다.
참고 표준·문서
- CMAF: ISO/IEC 23000-19
- ISO BMFF: ISO/IEC 14496-12
- DASH(매니페스트): ISO/IEC 23009-1
- HLS(인덱스): RFC 8216 — fMP4와
EXT-X-MAP은 여기에, LL-HLS 확장은 후속 개정 초안(8216bis)에 있습니다 - 실무 가이드(비표준): DASH-IF 가이드라인, Apple HLS Authoring Specification, Shaka Packager·FFmpeg 문서, CDN 벤더 문서 — 최신 개정을 확인하십시오
부록: 용어 정리(팀 합의용)
- CMAF Segment / Fragment / Chunk: 제품과 문서마다 정의가 조금씩 다르므로, 팀 안에서는 기준 문서를 하나 정해 그 정의를 따르십시오.
- CMAF Switching Set vs DASH Period 전환: 이름은 비슷해도 하나는 컨테이너·트랙 계층, 다른 하나는 매니페스트 타임라인 계층의 개념입니다.
같이 보면 좋은 글
- HLS(HTTP Live Streaming) 레퍼런스 — M3U8·ABR·암호화·LL-HLS
- Opus 오디오 코덱 차세대 표준 | WebRTC·저지연·FFmpeg 실전 가이드
- MP4 컨테이너 구조
- WebRTC 레퍼런스 — PeerConnection·ICE·STUN·TURN·시그널링·SFU