How to Create DASH Video Streams Using FFmpeg
This guide provides a straightforward tutorial on how to use the
FFmpeg command-line tool to generate Dynamic Adaptive Streaming over
HTTP (DASH) manifests and video segments. You will learn how to package
a single video file or encode multiple adaptive bitrates, configure
segment durations, and output the required .mpd playlist
file alongside its corresponding media fragments for seamless web
playback.
Basic Single-Bitrate DASH Creation
To quickly convert a standard video file into a DASH-compliant
stream, you can use FFmpeg’s built-in dash muxer. The basic
command takes an input video, transcodes it (or copies the codecs), and
outputs the media segments along with the XML-based Media Presentation
Description (.mpd) manifest.
Run the following command in your terminal:
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -f dash output.mpdKey Parameters Explained:
-i input.mp4: Specifies your source video file.-c:v libx264: Encodes the video stream to H.264.-c:a aac: Encodes the audio stream to AAC format.-f dash: Directs FFmpeg to use the DASH muxer to segment the files and generate the manifest.output.mpd: The name of the master manifest file.
Multi-Bitrate Adaptive DASH Encoding
For true adaptive streaming, you must provide multiple resolutions and bitrates (representations). This allows the video player to dynamically switch streams depending on the user’s internet speed.
To ensure seamless transitions between qualities, you must enforce a strict keyframe interval (GOP size) that aligns with your segment duration.
ffmpeg -i input.mp4 \
-map 0:v -map 0:a -map 0:v -map 0:a \
-b:v:0 800k -s:v:0 640x360 -profile:v:0 baseline \
-b:v:1 2400k -s:v:1 1280x720 -profile:v:1 main \
-b:a:0 96k -b:a:1 128k \
-keyint_min 48 -g 48 -sc_threshold 0 \
-f dash \
-seg_duration 4 \
-use_template 1 \
-use_timeline 1 \
-init_seg_name 'init-stream$RepresentationID$.m4s' \
-media_seg_name 'chunk-stream$RepresentationID$-$Number%05d$.m4s' \
manifest.mpdCritical Flags for Multi-Bitrate Encoding:
-map 0:v -map 0:a ...: Maps the input streams multiple times to create different output qualities (two video streams and two audio streams in this example).-b:v:0/-b:v:1: Sets the target video bitrates for the first and second representations (800kbps and 2400kbps).-s:v:0/-s:v:1: Downscales the video representations (360p and 720p).-g 48 -keyint_min 48: Sets a fixed Group of Pictures (GOP) size of 48 frames. At 24 frames per second, this guarantees a keyframe every 2 seconds, which is essential for clean segment cuts.-sc_threshold 0: Disables scene change detection to prevent FFmpeg from inserting extra keyframes.-seg_duration 4: Sets the target segment duration to 4 seconds.-use_template 1: Instructs the manifest to use template-based URLs instead of listing every single segment, reducing the size of the.mpdfile.-use_timeline 1: Enables the segment timeline, which helps players handle variable frame rates and keeps audio/video in perfect sync.-init_seg_name/-media_seg_name: Defines the naming structure for the initialization files and the sequential media chunks using dynamic wildcards like$RepresentationID$and$Number$.
Deploying Your DASH Stream
Once the FFmpeg process completes, you will have a directory
containing: 1. manifest.mpd: The master
XML manifest file. 2. init-stream...m4s:
Header initialization files for each quality representation. 3.
chunk-stream...m4s: Hundreds or thousands
of small, sequential media segments.
To stream this content to users, upload all of these generated files to any standard web server or Cloud storage bucket (such as Apache, Nginx, or AWS S3). Ensure that your web server is configured to allow Cross-Origin Resource Sharing (CORS) so that players like Dash.js or Shaka Player can fetch the assets from your domain.