Create Multi-Resolution DASH Ladder with FFmpeg

This article provides a complete, step-by-step guide to generating a multi-resolution Dynamic Adaptive Streaming over HTTP (DASH) bitrate ladder using FFmpeg. You will learn how to take a single source video, transcode it into multiple resolutions and bitrates with aligned keyframes, and package the output into a playback-ready DASH manifest (.mpd) and media segments.


Step 1: Understand the Requirements for DASH

To ensure seamless switching between resolutions during playback, your adaptive bitrate (ABR) ladder must meet two strict criteria:

  1. Identical Keyframe Intervals (GOP Size): Keyframes must occur at the exact same timestamps across all video streams. If a player switches from 1080p to 720p, it must do so at a keyframe boundary.
  2. Segment Alignment: The audio and video segments must be cut at identical intervals (typically between 2 to 6 seconds).

Step 2: The FFmpeg Command

To create a three-tier DASH ladder (1080p, 720p, and 480p) from an input file named input.mp4, run the following command in your terminal:

ffmpeg -i input.mp4 \
  -map 0:v:0 -map 0:v:0 -map 0:v:0 -map 0:a:0 \
  -b:v:0 4500k -s:v:0 1920x1080 -profile:v:0 high \
  -b:v:1 2500k -s:v:1 1280x720 -profile:v:1 main \
  -b:v:2 1000k -s:v:2 854x480 -profile:v:2 main \
  -b:a:0 128k \
  -c:v libx264 -pix_fmt yuv420p \
  -c:a aac \
  -keyint_min 48 -g 48 -sc_threshold 0 \
  -bf 3 -b_strategy 1 \
  -use_timeline 1 -use_template 1 \
  -window_size 5 -adaptation_sets "id=0,streams=v id=1,streams=a" \
  -f dash manifest.mpd

Step 3: Command Breakdown

Here is what each part of the command does:

Stream Mapping

  • -map 0:v:0 (repeated three times): Instructs FFmpeg to read the first video stream of the input file three separate times to create three independent output video streams.
  • -map 0:a:0: Instructs FFmpeg to read the first audio stream once.

Video Representation Settings

  • -b:v:[index]: Sets the target bitrate for each video stream (e.g., 4500k for 1080p, 2500k for 720p, and 1000k for 480p).
  • -s:v:[index]: Sets the resolution scale for each stream (e.g., 1920x1080, 1280x720, 854x480).
  • -profile:v:[index]: Sets the H.264 profile. Use high for 1080p for better compression, and main for lower resolutions to ensure compatibility with older devices.

Encoder and Keyframe Settings

  • -c:v libx264 -pix_fmt yuv420p: Encodes the video using the H.264 codec with a standard 8-bit YUV 4:2:0 color space.
  • -c:a aac -b:a:0 128k: Encodes the audio to AAC format at a bitrate of 128 kbps.
  • -g 48 -keyint_min 48: Forces a keyframe (I-frame) every 48 frames. Assuming a 24 fps source video, this guarantees a keyframe precisely every 2 seconds. Adjust this number based on your source framerate (e.g., use 60 for 30 fps video).
  • -sc_threshold 0: Disables scene change detection. This prevents FFmpeg from inserting extra keyframes at scene transitions, keeping the GOP size strictly locked.

DASH Packaging Settings

  • -f dash: Specifies the output format as DASH.
  • -use_timeline 1: Enables the Media Presentation Description (MPD) timeline, ensuring highly accurate playback synchronization.
  • -use_template 1: Uses template-based URLs for segment naming (e.g., chunk-stream0-00001.m4s), which reduces the size of the XML manifest file.
  • -window_size 5: Retains only the 5 most recent segments in the manifest (highly useful for live streaming). For video-on-demand (VOD), you can omit this option to keep all segments.
  • -adaptation_sets "id=0,streams=v id=1,streams=a": Groups all video streams into Adaptation Set 0 and the audio stream into Adaptation Set 1. This tells the video player that the video streams are alternative representations of the same content and can be swapped dynamically.
  • manifest.mpd: The name of the output index file. FFmpeg will write this file alongside the video and audio segment files (.m4s) in your working directory.