What is DASH (Dynamic Adaptive Streaming over HTTP) and why did it broke my yt-dlp filter?
When you run yt-dlp -F on a YouTube video you will see lots of entries ending in mp4_dash, webm_dash or m4a_dash. I thought at first that this is a new format, so I started searching. As my current filter would complain: "No video formats found!"
The short version
DASH stands for Dynamic Adaptive Streaming over HTTP, also known as MPEG-DASH. It is an international standard (first described in ISO/IEC 23009-1) for streaming video and audio over plain HTTP. The same protocol your browser uses to load any webpage.
The core idea: Don't send one big file. Cut the media into many small segments, offer them in several qualities, and let the player decide which quality it wants to fetch next. And reading this, I finally understood a bit more how some things related to streaming work (yeah, all that audio/video stuff is not my bright side).
The problem DASH solves
Before adaptive streaming there were basically two options to watch a video on the web:
- Download the whole file (progressive download)
- Simple, but you can't react if your connection gets slower. The video just stutters and buffers.
- Special streaming servers and protocols like RTMP (remember Flash?)
- They worked, but needed dedicated server software (remember RealServer or RealPlayer?), were a pain with firewalls and didn't play well with caches and CDNs from what I read.
DASH takes a different approach: A video is just a bunch of static files on a normal web server. No special server logic required. Any HTTP server or CDN can deliver it. That's a big reason why it became so popular.
How it works
1. Encoding: many qualities, small segments
The provider encodes the video several times, in different resolutions and bitrates (144p, 360p, 720p, 1080p, ...). Each of these versions is called a Representation. Every representation is then cut into segments, usually a few seconds long.
Video and audio are separate representations. (Keep this in mind if you want to setup yt-dlp!) Audio can also exist in several bitrates, codecs and languages.
2. The XML-manifest tying everthing together
A small XML file, the Media Presentation Description (MPD), describes what is available. Which representations exist, which codecs, which bitrates and where to find the segments.
A heavily simplified, non-working example - as there are many attributes, etc. missing, is below:
Note: I use YouTube IDs here to make it easier to understand how yt-dlp, DASH/MPD and YouTube play together:
<MPD type="static" mediaPresentationDuration="PT10M">
<Period>
<AdaptationSet mimeType="video/mp4">
<Representation id="137" codecs="avc1.640028" width="1920" height="1080" bandwidth="3500000"/>
<Representation id="136" codecs="avc1.64001F" width="1280" height="720" bandwidth="2000000"/>
<Representation id="134" codecs="avc1.4D401E" width="640" height="360" bandwidth="700000"/>
</AdaptationSet>
<AdaptationSet mimeType="audio/mp4" lang="de">
<Representation id="140" codecs="mp4a.40.2" bandwidth="129000"/>
</AdaptationSet>
</Period>
</MPD>
The AdaptationSet groups interchangeable versions of the same thing (e.g. "the video in different resolutions" or "the German audio track in different bitrates"). The player picks one representation out of each set.
Real world examples can be found here, but I can't say if they are up-to-date or working:
- https://reference.dashif.org/dash.js/v4.4.0/samples/index.html
- https://docs.aws.amazon.com/mediatailor/latest/ug/manifest-dash-example.html
- https://ottverse.com/free-mpeg-dash-mpd-manifest-example-test-urls/
3. The player does the thinking
The player downloads the MPD and then:
- Starts with a low or medium quality, so playback begins quickly.
- Measures how fast the segments arrive (and how full its buffer is).
- Switches to a higher or lower representation for the next segment, depending on the result.
That is the "adaptive" in the name. It's also why a YouTube video gets blurry for a moment when your WLAN is acting up, instead of stopping to buffer. The server isn't even involved in this decision. It just hands out files.
This provided a nice "Ahhh!"-moment for me, as now I understood the technical details of how streaming services achieve this.
How it plays out is basically this:
Server (plain HTTP): Player:
video_1080p/seg001.m4s ---> fast connection -> fetch 1080p
video_1080p/seg002.m4s ---> fetch segment 2
video_360p/seg003.m4s ---> connection drops -> switch to 360p
video_720p/seg004.m4s ---> recovered -> raise to 720p
audio_de/seg001.m4s ---> audio is fetched independently
Why video and audio are separate
This is the part that matters for yt-dlp. Because video and audio are independent representations, a provider doesn't need to store every combination of resolution and language as an own file. Imagine a video with 8 resolutions, 3 codecs and 5 languages. Without separation that would be 120 files (8*3*5). With DASH it is 24 video representations (8*3) plus 5 audio ones. And the player combines them on the fly.
The downside for us as downloaders: There is often no single file containing both video and audio in high quality. That's why a plain best format selector in yt-dlp can come up empty on YouTube, as I happened to experience today. You have to select video and audio separately and merge them (which needs ffmpeg), but luckily yt-dlp does this for us too if ffmpeg (see: https://github.com/yt-dlp/yt-dlp#strongly-recommended) can be found in your systems environment variables (like PATH).
To download a video with that filter, use:
user@host:~$ yt-dlp -f "bv*+ba" "URL"
bv* is the best video, ba the best audio and the + tells yt-dlp to download both and merge them.
DASH in the yt-dlp format list
In the yt-dlp -F output you recognise DASH streams by the _dash suffix in the MORE INFO column:
Note: For clarity I removed several columns (like FPS, CH, FILESIZE, etc.) in this output.
user@host:~$ yt-dlp -F https://www.youtube.com/watch?v=ID
[youtube] Extracting URL: https://www.youtube.com/watch?v=ID
[youtube] ID: Downloading webpage
[youtube] ID: Downloading visionos player API JSON
[youtube] ID: Downloading m3u8 information
[info] Available formats for ID:
ID EXT RESOLUTION │ VCODEC ACODED MORE INFO
─────────────────────────────────────────────────────────────────────
137 mp4 1920x1080 │ avc1.640028 video only 1080p, mp4_dash
140 m4a audio only │ audio only mp4a.40.2 medium, m4a_dash
251 webm audio only │ audio only opus medium, webm_dash
The container (mp4, webm, m4a) is independent of DASH. DASH only describes how the media is delivered, not what is inside. It is codec-agnostic: H.264, VP9, AV1, AAC, Opus, all of that works.
And now you know why your player never asks you which of the 20 formats it should play and why the video quality automatically fixes it itself after network/bandwidth issues. 😅