What You’ll Learn
- The basic MPEG-DASH segmenting command
- Multi-bitrate adaptive streaming (ABR) setup
- Segment duration (
-seg_duration) and initialization file settings - Key differences between HLS and MPEG-DASH
- Comparison of VOD and live streaming options
Tested with: FFmpeg 6.1 (ubuntu-latest / CI-verified) Platform: Windows / macOS / Linux
MPEG-DASH Fundamentals
MPEG-DASH (Dynamic Adaptive Streaming over HTTP) is a standard that delivers video over HTTP by splitting it into small segment files.
| Component | Description |
|---|---|
| MPD file | Manifest (equivalent to a playlist) |
| Segment file | The actual video/audio data (typically 2–10 seconds) |
| Representation | A bitrate/resolution combination |
| AdaptationSet | A group of video or audio streams |
Basic Command (Single Bitrate)
ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -c:a aac -b:a 128k -f dash -seg_duration 4 output.mpd
This produces:
output.mpd— the manifest fileinit-stream0.m4s— video initialization segmentinit-stream1.m4s— audio initialization segmentchunk-stream0-XXXXX.m4s— numbered video segmentschunk-stream1-XXXXX.m4s— numbered audio segments
Multi-Bitrate ABR Setup
The real power of adaptive streaming comes from generating multiple quality levels in parallel. Use -map to produce several bitrates from the same input.
ffmpeg -i input.mp4 \
-map 0:v -map 0:a -map 0:v -map 0:a \
-c:v libx264 \
-b:v:0 2500k -s:v:0 1280x720 \
-b:v:1 800k -s:v:1 854x480 \
-c:a aac -b:a 128k \
-f dash \
-seg_duration 4 \
-adaptation_sets "id=0,streams=v id=1,streams=a" \
output.mpd
The command above produces two bitrates: 720p (2500 kbps) and 480p (800 kbps). The player switches between them automatically based on network conditions.
Key Options
| Option | Example | Description |
|---|---|---|
-seg_duration | 4 | Segment length in seconds (usually 2–6) |
-use_timeline | 1 | SegmentTimeline mode (recommended for VOD) |
-use_template | 1 | Template URLs (recommended for live) |
-window_size | 5 | Number of segments kept in the manifest during live |
-adaptation_sets | "id=0,streams=v" | Grouping of representations |
-init_seg_name | "init_$RepresentationID$.m4s" | Initialization segment name template |
-media_seg_name | "seg_$Number$.m4s" | Media segment name template |
VOD Settings
ffmpeg -i input.mp4 \
-c:v libx264 -b:v 1500k \
-c:a aac -b:a 128k \
-f dash \
-seg_duration 4 \
-use_timeline 1 \
-use_template 1 \
output.mpd
Choosing HLS vs. MPEG-DASH
| Criterion | HLS | MPEG-DASH |
|---|---|---|
| Native Safari support | Yes (built-in) | Partial (requires JS) |
| Segment format | .ts / .m4s | .m4s / .mp4 |
| Standards body | Apple proprietary | ISO international |
| Dynamic ABR switching | Yes | Yes |
| Primary use case | iOS and Safari | General-purpose / OTT |
Frequently Asked Questions
DASH vs HLS — which should I use?
HLS is mandatory for iOS/Safari, DASH is preferred for desktop browsers and smart TVs. For the widest reach, generate both with -hls_segment_filename and -dash.
What segment length should I pick?
4–6 second segments balance startup time and switching latency. Shorter (2 s) gives faster channel-change but increases manifest churn and CDN cost.
Why does my DASH player buffer at every quality switch?
Most likely keyframes are not aligned across renditions. Force keyframes with -force_key_frames "expr:gte(t,n_forced*4)" for every rendition.
Can I do live DASH from FFmpeg directly?
Yes — -f dash -window_size 5 -extra_window_size 10 produces a sliding live window. Pair it with HTTP PUT to a CDN ingest endpoint.
Do I need separate audio segments?
For multi-bitrate or multi-language audio, yes. Use -adaptation_sets "id=0,streams=v id=1,streams=a" to split video and audio sets.
Related Articles
- HLS Segmenting with FFmpeg — Build Streaming-Ready Files
- Video Format Conversion — Containers vs. Codecs
Tested with ffmpeg 6.1 / Ubuntu 24.04 (GitHub Actions runner) Primary sources: ffmpeg.org/ffmpeg-formats.html#dash / trac.ffmpeg.org/wiki/Create%20a%20DASH%20playlist