MPEG-DASH 구조를 HLS와 비교해서 보기
DASH는 MPEG이 2012년에 ISO 국제 표준으로 발표한 HTTP 기반 적응형 스트리밍 프로토콜입니다. HLS가 Apple의 독점 규격에서 출발한 것과 달리, DASH는 처음부터 벤더 중립적인 국제 표준으로 설계됐습니다. MPD라는 XML 매니페스트가 미디어 구조를 기술하고, 클라이언트가 이를 파싱해서 세그먼트를 요청하는 구조입니다.
들어가기 전에
2010년대 초반, 스트리밍 프로토콜은 난립 상태였습니다. Apple HLS, Microsoft Smooth Streaming, Adobe HDS — 각 벤더가 자기 규격을 밀고 있었습니다. 업계는 "벤더 독립적인 표준"이 필요하다고 판단했고, MPEG이 이를 통합하는 역할을 맡았습니다. 그 결과물이 MPEG-DASH입니다.
기술적으로는 HLS와 근본 원리가 같습니다 — HTTP 위에서 매니페스트 + 세그먼트를 주고받습니다. 하지만 MPD의 표현력이 HLS의 m3u8보다 훨씬 풍부합니다. 복잡한 멀티 DRM, 다중 Period, 이벤트 시그널링 같은 걸 하나의 매니페스트에서 표현할 수 있습니다.
그런데 현실은 어떨까요? Apple이 iOS/Safari에서 DASH를 지원하지 않으니까, 모바일 커버리지를 위해 HLS를 병행해야 합니다. "국제 표준인데 왜 HLS보다 점유율이 낮냐"는 이유가 여기에 있습니다. 표준의 힘보다 생태계의 힘이 셌습니다.
기원과 역사
| 연도 | 이벤트 |
|---|---|
| 2009 | Apple HLS 발표 (WWDC) |
| 2010 | MPEG, DASH 표준화 작업 시작 |
| 2011 | Microsoft Smooth Streaming, Adobe HDS 각각 존재 |
| 2012 | ISO/IEC 23009-1:2012 최초 발표. MPEG-DASH 탄생 |
| 2014 | DASH-IF 설립, 구현 가이드라인 배포 |
| 2019 | CMAF 등장 — HLS와 DASH가 동일 세그먼트 공유 가능 |
| 2022 | ISO/IEC 23009-1 4th Edition |
DASH의 설계에는 Microsoft Smooth Streaming의 영향이 큽니다. Smooth Streaming의 fragmented MP4 구조와 매니페스트 기반 적응형 스위칭을 표준화한 것이 DASH라고 볼 수 있습니다.
MPD 구조 분석
MPD는 XML 기반 매니페스트입니다. 계층 구조가 핵심입니다.
계층별 역할
| 계층 | 역할 | HLS 대응 |
|---|---|---|
| MPD | 전체 프레젠테이션 최상위. 타입, 시간 정보 | Master Playlist |
| Period | 시간 구간 분리. 광고/본편 분리에 사용 | 없음 (HLS는 단일 타임라인) |
| AdaptationSet | 콘텐츠 타입별 그룹 (비디오, 오디오, 자막) | #EXT-X-MEDIA 그룹 |
| Representation | 동일 콘텐츠의 품질 변형 | Variant Stream |
| Segment | 실제 미디어 청크 | .ts / .m4s 파일 |
실제 MPD 예시
<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011"
type="dynamic"
availabilityStartTime="2026-06-01T10:00:00Z"
minimumUpdatePeriod="PT2S"
minBufferTime="PT4S"
publishTime="2026-06-01T10:05:00Z"
timeShiftBufferDepth="PT30M">
<Period id="content-1" start="PT0S">
<!-- 비디오 -->
<AdaptationSet mimeType="video/mp4" codecs="avc1.640028"
segmentAlignment="true" startWithSAP="1">
<Representation id="1080p" bandwidth="5000000" width="1920" height="1080">
<SegmentTemplate timescale="90000"
initialization="init_1080p.mp4"
media="seg_1080p_$Number$.m4s"
startNumber="1"
duration="180000"/>
</Representation>
<Representation id="720p" bandwidth="2500000" width="1280" height="720">
<SegmentTemplate timescale="90000"
initialization="init_720p.mp4"
media="seg_720p_$Number$.m4s"
startNumber="1"
duration="180000"/>
</Representation>
</AdaptationSet>
<!-- 오디오 -->
<AdaptationSet mimeType="audio/mp4" codecs="mp4a.40.2" lang="ko">
<Representation id="audio_ko" bandwidth="128000">
<SegmentTemplate timescale="44100"
initialization="init_audio_ko.mp4"
media="seg_audio_ko_$Number$.m4s"
startNumber="1"
duration="88200"/>
</Representation>
</AdaptationSet>
</Period>
</MPD>MPD 주요 태그/속성
MPD 레벨
| 속성 | 설명 |
|---|---|
type | static (VOD) 또는 dynamic (라이브) |
availabilityStartTime | 라이브 시작 시각 (ISO 8601) |
publishTime | MPD 게시 시각 |
minimumUpdatePeriod | 클라이언트가 MPD를 다시 가져올 최소 간격 |
minBufferTime | 클라이언트 최소 버퍼 시간 |
timeShiftBufferDepth | DVR 가능한 과거 구간 길이 |
mediaPresentationDuration | VOD 전체 길이 |
maxSegmentDuration | 세그먼트 최대 길이 |
profiles | DASH 프로파일 (urn:mpeg💨profile:isoff-live:2011 등) |
Period
| 속성 | 설명 |
|---|---|
id | Period 식별자 |
start | Period 시작 시간 (MPD 시작 기준 오프셋) |
duration | Period 길이 |
Period가 DASH의 가장 큰 차별점입니다. HLS에는 Period 개념이 없어서, 광고 구간을
#EXT-X-DISCONTINUITY로 처리해야 합니다. DASH는 광고를 별도 Period로 깔끔하게 분리할 수 있습니다.
AdaptationSet
| 속성 | 설명 |
|---|---|
mimeType | 미디어 타입 (video/mp4, audio/mp4, text/vtt) |
codecs | 코덱 문자열 (avc1.640028, mp4a.40.2 등) |
lang | 언어 코드 |
segmentAlignment | 세그먼트 정렬 여부 (ABR 스위칭에 중요) |
startWithSAP | SAP 타입. 1이면 모든 세그먼트가 IDR로 시작 |
contentType | video / audio / text |
Representation
| 속성 | 설명 |
|---|---|
id | 렌디션 식별자 |
bandwidth | 비트레이트 (bps). ABR 스위칭 결정에 사용 |
width / height | 해상도 |
frameRate | 프레임레이트 (예: "30000/1001") |
qualityRanking | 품질 순위 (낮을수록 높은 품질) |
SegmentTemplate
세그먼트 URL 패턴을 템플릿으로 정의합니다. 클라이언트가 세그먼트 번호를 계산해서 직접 URL을 만듭니다.
| 속성 | 설명 |
|---|---|
initialization | 초기화 세그먼트 URL |
media | 미디어 세그먼트 URL 템플릿. $Number$, $Time$ 변수 사용 |
timescale | 시간 단위 (90000 = 90kHz) |
duration | 세그먼트 길이 (timescale 단위) |
startNumber | 첫 세그먼트 번호 |
presentationTimeOffset | 프레젠테이션 시간 오프셋 |
URL 변수:
$Number$— 세그먼트 시퀀스 번호$Time$— 세그먼트 시작 타임스탬프$Bandwidth$— Representation의 bandwidth 값$RepresentationID$— Representation ID
SegmentTimeline
세그먼트별 정확한 타이밍 정보를 명시적으로 제공합니다 (가변 세그먼트 길이에 사용):
<SegmentTimeline>
<S t="0" d="180000" r="9"/> <!-- 10개 세그먼트, 각 2초 -->
<S d="90000"/> <!-- 1개 세그먼트, 1초 (짧은 세그먼트) -->
</SegmentTimeline>| 속성 | 설명 |
|---|---|
t | 시작 시간 (생략 시 이전 세그먼트 끝) |
d | 세그먼트 길이 (timescale 단위) |
r | 반복 횟수 (-1이면 무한 반복) |
세그먼트 주소 지정 방식 비교
| 방식 | 설명 | 용도 |
|---|---|---|
| SegmentTemplate + Number | seg_$Number$.m4s | 고정 길이 세그먼트. 라이브에 적합 |
| SegmentTemplate + Time | seg_$Time$.m4s | 가변 길이 세그먼트 |
| SegmentTimeline | 명시적 타이밍 목록 | 정밀한 시간 제어 필요 시 |
| SegmentList | 세그먼트 URL 직접 나열 | VOD. 유연하지만 MPD가 커짐 |
| SegmentBase | 단일 파일 + 바이트 범위 | 짧은 VOD |
라이브에서는 SegmentTemplate + Number 또는 SegmentTemplate + SegmentTimeline이 일반적입니다.
DASH의 DRM: ContentProtection
DASH는 DRM을 매니페스트 레벨에서 선언합니다:
<AdaptationSet>
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<!-- Widevine -->
<cenc:pssh>AAAA...</cenc:pssh>
</ContentProtection>
<ContentProtection schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95">
<!-- PlayReady -->
<mspr:pro>...</mspr:pro>
</ContentProtection>
</AdaptationSet>| DRM | schemeIdUri (UUID) |
|---|---|
| Widevine | edef8ba9-79d6-4ace-a3c8-27dcd51d21ed |
| PlayReady | 9a04f079-9840-4286-ab92-e65be0885f95 |
| FairPlay | 94ce86fb-07ff-4f43-adb8-93d2fa968ca2 |
| ClearKey | e2719d58-a985-b3c9-781a-b030af78d30e |
하나의 MPD에 여러 DRM을 동시에 선언할 수 있습니다. 클라이언트가 지원하는 DRM을 선택해서 키를 획득하는 구조입니다. 이게 "Multi-DRM"의 실체입니다.
HLS에서 Widevine을 쓰려면 좀 억지스러운 구조가 됩니다. DASH에서는 네이티브하게 멀티 DRM이 동작합니다. DRM 유연성은 DASH의 확실한 강점입니다.
이벤트 시그널링: EventStream
DASH는 매니페스트 내에서 이벤트를 시그널링할 수 있습니다:
<Period>
<EventStream schemeIdUri="urn:scte:scte35:2013:xml" timescale="90000">
<Event presentationTime="5400000" duration="2700000" id="1">
<Signal xmlns="http://www.scte.org/schemas/35/2016">
<Binary>/DAlAAAAAA...</Binary>
</Signal>
</Event>
</EventStream>
</Period>SCTE-35 광고 신호, 챕터 마커, 프로그램 메타데이터 등을 이 구조로 전달합니다. HLS의 #EXT-X-DATERANGE와 유사한 역할을 합니다.
DASH 프로파일
DASH는 다양한 사용 케이스를 위해 프로파일을 정의합니다:
| 프로파일 | 설명 |
|---|---|
urn:mpeg:dash:profile:isoff-live:2011 | 라이브. SegmentTemplate 기반 |
urn:mpeg:dash:profile:isoff-on-demand:2011 | VOD. SegmentBase + 바이트 범위 |
urn:mpeg:dash:profile:isoff-main:2011 | 메인. 가장 유연하지만 구현 복잡 |
대부분의 라이브 서비스는 isoff-live 프로파일을 사용합니다.
HLS vs DASH 비교
| 항목 | HLS | DASH |
|---|---|---|
| 기원 | Apple (2009, 독점 규격) | MPEG (2012, ISO 국제 표준) |
| 매니페스트 | m3u8 (텍스트 기반) | MPD (XML) |
| Period 개념 | 없음 | 있음 (광고/본편 분리에 강점) |
| DRM | FairPlay 중심 | Multi-DRM 네이티브 (Widevine, PlayReady 등) |
| 세그먼트 포맷 | TS 또는 fMP4 | fMP4 (CMAF) |
| iOS 지원 | 네이티브 | 미지원 (MSE/EME 필요) |
| Android 지원 | ExoPlayer로 지원 | 네이티브 (ExoPlayer) |
| 매니페스트 복잡도 | 낮음 | 높음 |
| 표현력 | 제한적 | 매우 풍부 |
| 시장 점유율 | 더 높음 (Apple 생태계) | 낮지만 증가 중 |
CMAF: HLS와 DASH의 합류점
CMAF(ISO/IEC 23000-19)은 HLS와 DASH가 같은 세그먼트 파일을 공유할 수 있게 하는 규격입니다.
인코더가 fMP4 세그먼트(CMAF)를 한 번만 만들어두면, 여기서 HLS용 .m3u8 매니페스트와 DASH용 .mpd 매니페스트를 각각 뽑아낼 수 있습니다. iOS/Safari는 .m3u8을, Android/Web은 .mpd을 읽지만 실제로 내려받는 세그먼트 파일은 같습니다.
동일한 미디어를 두 번 인코딩하지 않아도 됩니다. 스토리지와 CDN 비용이 절반으로 줄어드는 것이 실질적인 이점입니다.
마치며
DASH는 기술적으로 HLS보다 풍부합니다. Multi-Period로 광고 구간을 깔끔하게 분리할 수 있고, 멀티 DRM을 네이티브로 지원하며, EventStream으로 인밴드 이벤트를 매니페스트에서 표현할 수 있습니다.
그런데 현실은 Apple이 iOS에서 DASH를 안 열어줬기 때문에, 대부분의 서비스가 HLS를 기본으로 쓰고 DASH를 보조로 씁니다. 또는 CMAF로 세그먼트를 통합하고 매니페스트만 두 벌로 내리는 하이브리드 구조를 택합니다.
DASH가 진짜 빛나는 영역은 DRM이 복잡한 프리미엄 콘텐츠(Widevine + PlayReady 동시 지원)와 SSAI가 필요한 광고 기반 서비스(Multi-Period 활용)입니다. 이 두 가지가 아니라면 HLS만으로도 충분한 경우가 많습니다.
참고 자료
- ISO/IEC 23009-1:2022: https://www.iso.org/standard/83314.html
- DASH-IF Guidelines: https://dashif.org/guidelines/