MPEG-DASH 完整指南:協定原理、Dash.js 實作與 HLS 比較
HLS 佔據串流市場,但 MPEG-DASH 是國際標準的替代方案。YouTube、Netflix 部分使用 DASH。這篇解析 DASH 的 MPD 檔案結構、Dash.js 實作、與 HLS 的詳細比較。
MPEG-DASH 是什麼
MPEG-DASH(Dynamic Adaptive Streaming over HTTP)是基於 HTTP 的自適應位元率串流協定。MPEG 在 2012 年標準化。和 HLS 一樣,把影片切成小區段,依網路狀況調整位元率。
DASH 的核心概念:
- MPD 檔案:XML 格式的媒體描述清單(相當於 HLS 的 M3U8)
- 區段(Segment):把影片切成小塊(通常 2-10 秒)
- Representation:同一內容的不同位元率/解析度版本
- ABR(Adaptive Bitrate):依網路狀況切換 Representation
MPD 檔案結構
MPD(Media Presentation Description)是 DASH 的核心。XML 格式:
xml
<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011"
type="static"
mediaPresentationDuration="PT1H30M0S"
minBufferTime="PT2.0S"
profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
<Period>
<!-- 視訊 AdaptationSet -->
<AdaptationSet mimeType="video/mp4" segmentAlignment="true">
<!-- 1080p Representation -->
<Representation id="v1" bandwidth="5000000" width="1920" height="1080" codecs="avc1.640028">
<SegmentTemplate
media="video_$Number$.m4s"
initialization="video_init.m4s"
duration="4"
startNumber="1"/>
</Representation>
<!-- 720p Representation -->
<Representation id="v2" bandwidth="2500000" width="1280" height="720" codecs="avc1.640020">
<SegmentTemplate
media="video_$Number$.m4s"
initialization="video_init.m4s"
duration="4"
startNumber="1"/>
</Representation>
<!-- 480p Representation -->
<Representation id="v3" bandwidth="1000000" width="854" height="480" codecs="avc1.64001f">
<SegmentTemplate
media="video_$Number$.m4s"
initialization="video_init.m4s"
duration="4"
startNumber="1"/>
</Representation>
</AdaptationSet>
<!-- 音訊 AdaptationSet -->
<AdaptationSet mimeType="audio/mp4" lang="en" segmentAlignment="true">
<Representation id="a1" bandwidth="128000" codecs="mp4a.40.2">
<SegmentTemplate
media="audio_$Number$.m4s"
initialization="audio_init.m4s"
duration="4"
startNumber="1"/>
</Representation>
</AdaptationSet>
</Period>
</MPD>MPD 結構
MPD
├── Period (時間區段,如廣告和主內容)
│ ├── AdaptationSet (同內容不同編碼器/語言)
│ │ ├── Representation (具體位元率/解析度)
│ │ │ └── SegmentTemplate (區段 URL 模式)
│ │ └── Representation
│ └── AdaptationSet
└── PeriodSegmentTemplate
SegmentTemplate 用模式生成區段 URL:
xml
<SegmentTemplate
media="video_$Number$.m4s"
initialization="video_init.m4s"
duration="4"
startNumber="1"/>media="video_$Number$.m4s":區段 URL 模式($Number$是區段編號)initialization="video_init.m4s":初始化區段(包含 moov box)duration="4":每個區段 4 秒startNumber="1":區段編號從 1 開始
實際生成的 URL:
video_init.m4s(初始化)video_1.m4s(0-4 秒)video_2.m4s(4-8 秒)video_3.m4s(8-12 秒)- ...
Dash.js 實作
Dash.js 是 DASH 串流的 JavaScript 參考實作。
基本 HTML 播放器
html
<!DOCTYPE html>
<html>
<head>
<title>DASH Player</title>
<style>
video { width: 100%; max-width: 1280px; }
</style>
</head>
<body>
<video id="video" controls></video>
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
<script>
const url = "https://example.com/stream.mpd";
const player = dashjs.MediaPlayer().create();
player.initialize(document.querySelector("#video"), url, true);
</script>
</body>
</html>進階設定
javascript
const player = dashjs.MediaPlayer().create();
// 設定
player.updateSettings({
streaming: {
buffer: {
bufferTarget: 30, // 緩衝目標 30 秒
bufferTimeAtTopQuality: 30, // 高畫質緩衝
bufferTimeAtTopQualityLongForm: 60 // 長影片緩衝
},
abr: {
autoSwitchBitrate: { video: true, audio: true }, // 自動 ABR
minBitrate: { video: 1000, audio: 128 }, // 最低位元率
maxBitrate: { video: 5000, audio: 256 } // 最高位元率
}
}
});
// 事件監聽
player.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, () => {
console.log("串流初始化完成");
});
player.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_REQUESTED, (e) => {
console.log(`畫質切換: ${e.oldQuality} → ${e.newQuality}`);
});
player.on(dashjs.MediaPlayer.events.ERROR, (e) => {
console.error("錯誤:", e);
});
// 初始化
player.initialize(document.querySelector("#video"), "stream.mpd", true);自訂 UI
javascript
// 取得可用位元率
const bitrates = player.getBitrateInfoListFor("video");
console.log("可用畫質:", bitrates);
// 手動設定畫質
player.updateSettings({
streaming: { abr: { autoSwitchBitrate: { video: false } } }
});
player.setRepresentationForTypeById("video", 1, true); // 設定為第 2 個 Representation
// 取得當前位元率
const currentBitrate = player.getBitrateFor("video");
console.log("當前位元率:", currentBitrate);DASH vs HLS 詳細比較
| 特性 | MPEG-DASH | HLS |
|---|---|---|
| 標準化 | MPEG 國際標準 | Apple(開放) |
| 清單格式 | XML(MPD) | M3U8(文字) |
| 容器格式 | fMP4、WebM | MPEG-TS、fMP4 |
| 編碼器支援 | 幾乎所有 | H.264、H.265、AAC |
| 區段長度 | 可變(通常 2-10 秒) | 通常 6-10 秒 |
| 瀏覽器原生支援 | Chrome(部分)、Edge | Safari |
| JavaScript 需求 | dash.js(所有瀏覽器) | hls.js(非 Safari) |
| 直播延遲 | 2-5 秒(LL-DASH) | 10-30 秒(2-5 秒 LL-HLS) |
| DRM | Widevine、PlayReady | FairPlay、Widevine |
| CDN 快取 | HTTP 快取 | HTTP 快取 |
| Apple 生態 | ✗ | ✓ |
| 開源工具 | Bento4、FFmpeg | FFmpeg、Apple tools |
編碼器支援差異
DASH 支援:
- H.264、H.265、AV1
- VP8、VP9
- AAC、Opus、Vorbis
HLS 支援:
- H.264、H.265
- AAC(部分瀏覽器支援 AC-3)
容器格式差異
DASH 主要用 fMP4(Fragmented MP4):
[moov] ← 初始化區段
[moof] [mdat] ← 媒體區段 1
[moof] [mdat] ← 媒體區段 2
...HLS 傳統用 MPEG-TS,最新版也支援 fMP4。
詳見 M3U8 完全指南。
用 FFmpeg 生成 DASH 串流
bash
# MP4 轉 DASH(多解析度)
ffmpeg -i input.mp4 \
-map 0:v -map 0:a -s:v:0 1920x1080 -b:v:0 5000k \
-map 0:v -map 0:a -s:v:1 1280x720 -b:v:1 2500k \
-map 0:v -map 0:a -s:v:2 854x480 -b:v:2 1000k \
-c:v libx264 -c:a aac \
-f dash -seg_duration 4 \
-use_template 1 -use_timeline 1 \
output.mpd參數:
-map 0:v -map 0:a:每個輸出保留視訊和音訊-s:v:0 1920x1080 -b:v:0 5000k:第一個輸出 1080p 5Mbps-f dash:DASH 格式-seg_duration 4:區段 4 秒-use_template 1:使用 SegmentTemplate-use_timeline 1:使用 SegmentTimeline
自適應位元率(ABR)運作原理
ABR 是 DASH 的核心功能:
- 頻寬估算:播放器測量下載速度
- 緩衝區狀態:監控播放緩衝區大小
- Representation 選擇:依頻寬和緩衝區選最佳 Representation
- 區段下載:下載選定 Representation 的下一個區段
- 動態切換:網路變化時切換 Representation
ABR 切換策略
- 保守策略:緩衝區小時降位元率,避免重緩衝
- 激進策略:網路好時立即升位元率
- 平滑策略:避免頻繁切換,提升觀看體驗
Dash.js 提供多種 ABR 演算法,可自訂策略。
常見問題
1. Dash.js 播放失敗
原因: CORS 問題或 MPD 格式錯誤
解決方案:
javascript
// 開啟偵錯
player.updateSettings({ debug: { logLevel: 5 } });
// 確認 CORS 設定
// 伺服器需要:
// Access-Control-Allow-Origin: *
// Access-Control-Allow-Headers: Range2. 畫質切換頻繁
原因: ABR 演算法太激進
解決方案:
javascript
player.updateSettings({
streaming: {
abr: {
autoSwitchBitrate: { video: true },
ABRStrategy: "Bola" // 或 "Throughput"
}
}
});3. 直播延遲高
原因: 緩衝區設定過大
解決方案:
javascript
// 低延遲模式
player.updateSettings({
streaming: {
delay: {
liveDelay: 3 // 目標延遲 3 秒
},
buffer: {
bufferTarget: 6
}
}
});總結
MPEG-DASH 是 HLS 的替代方案,提供更靈活的編碼器支援和國際標準地位。
選擇指南:
- Apple 生態: HLS
- 跨平台 Web: DASH
- 國際標準: DASH
- 多編碼器: DASH
- 普及度: HLS
快速參考:
- MPD 檔案: XML 格式清單
- SegmentTemplate: 區段 URL 模式
- Dash.js:
dashjs.MediaPlayer().create() - FFmpeg 生成:
ffmpeg -i input.mp4 ... -f dash output.mpd