Skip to content

MPEG-DASH Complete Guide: Protocol Principles, Dash.js Implementation vs HLS

MPEG-DASH is the other major adaptive streaming protocol alongside HLS. While HLS dominates Apple ecosystem and mobile, DASH powers web streaming for Netflix, YouTube, and Amazon Prime Video. This guide explains how DASH works, how to implement it with dash.js, and how it compares to HLS.

What is MPEG-DASH?

DASH (Dynamic Adaptive Streaming over HTTP) is an ISO/IEC standard (ISO/IEC 23009-1) for adaptive bitrate streaming over HTTP. Released in 2012, it solves the same problem as HLS: delivering video efficiently over standard HTTP infrastructure with quality adaptation based on network conditions.

Key characteristics:

  • Open standard (ISO/IEC, not proprietary)
  • HTTP-based (works with any CDN, no special server needed)
  • Codec-agnostic (supports H.264, H.265, VP9, AV1, etc.)
  • Segmented (video split into small chunks for ABR)

How DASH works

Basic flow

  1. Encoding: Source video encoded at multiple bitrates/resolutions
  2. Segmentation: Each version split into small segments (2-10 seconds)
  3. Manifest creation: MPD file generated describing all available versions
  4. Distribution: MPD and segments served over HTTP/CDN
  5. Playback: Client downloads MPD, requests segments based on bandwidth
  6. Adaptation: Client switches between bitrates as network conditions change

MPD file structure

MPD (Media Presentation Description) is the DASH manifest, equivalent to HLS M3U8. It's XML format:

xml
<?xml version="1.0" encoding="UTF-8"?>
<MPD type="static" mediaPresentationDuration="PT1H30M" minBufferTime="PT2S">
  <Period>
    <AdaptationSet mimeType="video/mp4" segmentAlignment="true">
      <!-- 360p representation -->
      <Representation id="v0" bandwidth="800000" width="640" height="360" codecs="avc1.42E01E">
        <SegmentTemplate media="video-$Number$.m4s" initialization="video-init.m4s" duration="4" startNumber="1"/>
      </Representation>
      <!-- 720p representation -->
      <Representation id="v1" bandwidth="2000000" width="1280" height="720" codecs="avc1.4D401F">
        <SegmentTemplate media="video-$Number$.m4s" initialization="video-init.m4s" duration="4" startNumber="1"/>
      </Representation>
      <!-- 1080p representation -->
      <Representation id="v2" bandwidth="5000000" width="1920" height="1080" codecs="avc1.640028">
        <SegmentTemplate media="video-$Number$.m4s" initialization="video-init.m4s" duration="4" startNumber="1"/>
      </Representation>
    </AdaptationSet>
    
    <AdaptationSet mimeType="audio/mp4" lang="en">
      <Representation id="a0" bandwidth="128000" codecs="mp4a.40.2">
        <SegmentTemplate media="audio-$Number$.m4s" initialization="audio-init.m4s" duration="4" startNumber="1"/>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>

MPD hierarchy

  • MPD: Root element, contains metadata
  • Period: Time segment (e.g., main content, ads)
  • AdaptationSet: Group of similar streams (video, audio, subtitles)
  • Representation: Specific version (bitrate/resolution combination)
  • SegmentTemplate: URL pattern for segments

Generate DASH content with FFmpeg

Basic DASH packaging

bash
ffmpeg -i input.mp4 \
  -map 0:v -map 0:a \
  -c:v libx264 -crf 23 -preset medium \
  -c:a aac -b:a 128k \
  -f dash \
  -use_timeline 1 \
  -use_template 1 \
  -seg_duration 4 \
  -adaptation_sets "id=0,streams=v id=1,streams=a" \
  output.mpd

Multi-bitrate DASH

bash
ffmpeg -i input.mp4 \
  -map 0:v:0 -map 0:v:0 -map 0:v:0 -map 0:a:0 \
  -c:v:0 libx264 -b:v:0 800k -s:v:0 640x360 \
  -c:v:1 libx264 -b:v:1 2000k -s:v:1 1280x720 \
  -c:v:2 libx264 -b:v:2 5000k -s:v:2 1920x1080 \
  -c:a aac -b:a 128k \
  -f dash \
  -use_timeline 1 \
  -use_template 1 \
  -seg_duration 4 \
  -adaptation_sets "id=0,streams=v:0,v:1,v:2 id=1,streams=a" \
  output.mpd

dash.js browser implementation

No browser natively supports DASH. All playback uses JavaScript libraries with Media Source Extensions (MSE).

Basic dash.js setup

html
<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
</head>
<body>
  <video controls style="width: 100%; max-width: 1280px;"></video>
  
  <script>
    const video = document.querySelector('video');
    const player = dashjs.MediaPlayer().create();
    player.initialize(video, 'https://example.com/stream.mpd', true);
  </script>
</body>
</html>

Advanced configuration

javascript
const player = dashjs.MediaPlayer().create();

// Configure ABR
player.updateSettings({
  streaming: {
    abr: {
      autoSwitchBitrate: { video: true, audio: true },
      ABRStrategy: 'abrBola',
      minBitrate: { video: 800 },
      maxBitrate: { video: 5000 }
    },
    buffer: {
      bufferGoalAtTopQuality: 30,
      bufferTimeDefault: 20
    }
  }
});

// Quality change events
player.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_REQUESTED, (e) => {
  console.log(`Switching to quality ${e.newQuality}`);
});

player.initialize(video, 'https://example.com/stream.mpd', true);

Custom quality selector

javascript
// Get available bitrates
const bitrates = player.getBitrateInfoListFor('video');
console.log('Available qualities:', bitrates);

// Manual quality selection
player.updateSettings({
  streaming: { abr: { autoSwitchBitrate: { video: false } } }
});
player.setQualityFor('video', 1); // Index in bitrates array

DASH vs HLS comparison

FeatureMPEG-DASHHLS
StandardISO/IEC 23009-1RFC 8216
Manifest formatXML (MPD)Text (M3U8)
Segment formatfMP4, WebMTS, fMP4
Codec supportAll (H.264, H.265, VP9, AV1)All (limited by player)
Browser native supportNoneSafari only
JS library requiredYes (dash.js)Yes (hls.js) for non-Safari
Apple ecosystemNoYes (native iOS/macOS)
Latency5-30s (standard), 1-2s (LL-DASH)5-30s (standard), 1-2s (LL-HLS)
DRMWidevine, PlayReady (CENC)FairPlay, Widevine, PlayReady
AdoptionNetflix, YouTube, AmazonApple, Disney+, Twitch
StandardizationISO/IECRFC

When to use which

Use HLS when:

  • Targeting iOS/macOS (native support)
  • Broad mobile compatibility needed
  • Apple ecosystem is primary audience

Use DASH when:

  • Web-first streaming
  • Need codec flexibility (AV1, VP9)
  • Want open standard with no patent concerns
  • Targeting Chrome/Android ecosystem

Use both (recommended for large services):

  • Multi-format strategy ensures maximum compatibility
  • Cloud services (AWS MediaConvert, Mux) can generate both formats from one source

Low-Latency DASH (LL-DASH)

Standard DASH has 5-30 second latency. LL-DASH reduces this to 1-2 seconds using:

  1. Chunked transfer encoding: Server streams segments as they're encoded
  2. Resync elements: MPD contains resync points for faster seeking
  3. Smaller segments: 1-2 seconds instead of 6-10 seconds
  4. Client-side optimization: Smaller buffer, faster ABR decisions
bash
# Generate LL-DASH content
ffmpeg -i input.mp4 \
  -c:v libx264 -crf 23 -preset veryfast -tune zerolatency \
  -c:a aac -b:a 128k \
  -f dash \
  -seg_duration 1 \
  -use_timeline 1 \
  -use_template 1 \
  -write_timeline 0 \
  output.mpd

DRM support

DASH uses CENC (Common Encryption) standard, supporting multiple DRM systems:

DRMProviderBrowser support
WidevineGoogleChrome, Firefox, Edge, Android
PlayReadyMicrosoftEdge, IE, Xbox
FairPlayAppleSafari (limited DASH support)

For cross-platform DRM, use Multi-DRM services like AWS Elemental MediaPackage, Axinom, or EZDRM.

Common issues

IssueCauseSolution
Video won't playCORS not configuredAdd Access-Control-Allow-Origin: * to segment responses
Stuck on loadingMPD malformedValidate XML structure
No quality switchingABR disabledEnable in dash.js settings
Buffering frequentlyNetwork bandwidth lowLower maxBitrate in settings
Audio missingMultiple audio tracksCheck AdaptationSet lang attribute
Live stream not updatingStatic MPD usedUse type="dynamic" for live

Summary

MPEG-DASH is a powerful, open alternative to HLS for adaptive bitrate streaming. While HLS has native iOS support, DASH dominates web streaming with Netflix, YouTube, and Amazon using it. For maximum compatibility, use both formats (multi-CDN strategy).

Quick reference:

  • Standard: ISO/IEC 23009-1
  • Manifest: MPD (XML)
  • Segments: fMP4 (typically)
  • Browser playback: dash.js with MSE
  • Generate content: ffmpeg -i input.mp4 -f dash -seg_duration 4 output.mpd

For HLS comparison, see our M3U8 file complete guide.

References

Last updated: