Skip to content

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 的核心概念:

  1. MPD 檔案:XML 格式的媒體描述清單(相當於 HLS 的 M3U8)
  2. 區段(Segment):把影片切成小塊(通常 2-10 秒)
  3. Representation:同一內容的不同位元率/解析度版本
  4. 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
└── Period

SegmentTemplate

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-DASHHLS
標準化MPEG 國際標準Apple(開放)
清單格式XML(MPD)M3U8(文字)
容器格式fMP4、WebMMPEG-TS、fMP4
編碼器支援幾乎所有H.264、H.265、AAC
區段長度可變(通常 2-10 秒)通常 6-10 秒
瀏覽器原生支援Chrome(部分)、EdgeSafari
JavaScript 需求dash.js(所有瀏覽器)hls.js(非 Safari)
直播延遲2-5 秒(LL-DASH)10-30 秒(2-5 秒 LL-HLS)
DRMWidevine、PlayReadyFairPlay、Widevine
CDN 快取HTTP 快取HTTP 快取
Apple 生態
開源工具Bento4、FFmpegFFmpeg、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 的核心功能:

  1. 頻寬估算:播放器測量下載速度
  2. 緩衝區狀態:監控播放緩衝區大小
  3. Representation 選擇:依頻寬和緩衝區選最佳 Representation
  4. 區段下載:下載選定 Representation 的下一個區段
  5. 動態切換:網路變化時切換 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: Range

2. 畫質切換頻繁

原因: 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

參考資料

Last updated: