The idea: many small files, and a choice before each one

A streaming service does not send one big video file. It encodes the same video several times at different bitrates, a bitrate ladder (here 360p at 0.8 Mbps up to 1080p at 5 Mbps), and cuts every version into short segments of a few seconds. The player downloads the segments one by one over ordinary HTTP, and before each download it picks which rendition to ask for. That choice is adaptive bitrate (ABR) streaming: HLS from Apple and MPEG-DASH both work this way.

A grid of 4 renditions (360p, 480p, 720p, 1080p) by 8 segments; the player's path picks 360p for segment 0, climbs to 1080p, drops to 480p when the bandwidth falls and climbs back.
Every segment exists in every rendition, so the player can change quality at any segment boundary.

The page plays a 60 s video: 15 segments of 4 s, in 4 renditions. The top left grid is the server, the top right is the player and its buffer, and the two charts show each download's bitrate against the bandwidth and the buffer level over time.

Playlists and segments

In HLS the player first loads a master playlist (master.m3u8) that lists the renditions with their bandwidth and resolution. Each rendition has its own media playlist listing its segment files, all of the same length (#EXT-X-TARGETDURATION). DASH puts the same information in one XML MPD file. Because segments are plain files, any HTTP cache or CDN can serve them (see HTTP caching). Segment sizes follow from the bitrate: 4 s at 5 Mbps is 20 Mbit (2.5 MB), at 0.8 Mbps only 3.2 Mbit.

The buffer and stalls

Playback starts as soon as the first segment is in (the startup delay) and then uses up 1 s of buffer per second. Each download adds 4 s. If a download takes longer than what is left in the buffer, the screen freezes until it arrives: a stall or rebuffering event. Viewers mind stalls far more than a softer picture. The player also stops asking when the buffer is full (here: no request above 12 s, so it never holds more than 16 s). Demo 2 has no ABR at all: it always asks for 1080p, and when the bandwidth drops to 1.6 Mbps one 20 Mbit segment takes 12.5 s; the video stalls twice, 13.6 s in all.

Throughput rule

The obvious rule measures how fast the last downloads went and picks the highest rendition that fits, with a margin: here the mean of the last 3 downloads times a safety factor of 0.9, like dash.js's throughput rule. With no measurement yet, it starts at the lowest rendition so the video starts fast (Demo 1: startup 0.5 s, then 1080p from segment 1). Its weakness is that it only knows the past. In Demo 3 the bandwidth falls at t = 16 s while a 1080p segment is loading; the average still remembers 6 Mbps, so the next pick is 720p, and two stalls of 3.0 s follow before the average catches up.

Buffer-based rule

A buffer-based rule (BBA, from Netflix's 2014 study) ignores throughput and looks at the buffer: below a reservoir (4 s) it asks for the lowest rendition, above the cushion (12 s) for the highest, and in between it moves along a straight line. A full buffer is time in the bank: Demo 4 runs into the same drop with 12.7 s buffered, steps down as the buffer empties, and stalls only 0.5 s.

The buffer-based map: buffer level 0 to 16 s on the x axis, bitrate on the y axis; flat at 0.8 Mbps up to 4 s, a straight line up to 5 Mbps at 12 s, flat above; the chosen rendition steps under the line.
The buffer-based rule maps the buffer level to a rate, and the player takes the highest rendition under it.

The price is switching. On a bursty network (Demo 5) the buffer goes up and down and the quality follows: no stalls, but 9 switches in 15 segments. Real players mix both signals: dash.js's default rule switches between throughput and buffer (BOLA), hls.js uses a moving average of throughput and the time left in the buffer.

On the drop networkStallsSwitchesAverage bitrate
fixed 1080p (Demo 2)2, 13.6 s ✗05.0 Mbps
throughput (Demo 3)2, 6.0 s ✗53.4 Mbps
buffer-based (Demo 4)1, 0.5 s72.8 Mbps

The download itself runs over TCP, whose congestion control decides the throughput the player measures. Live calls cannot wait for a 16 s buffer; they use a jitter buffer of a few tens of milliseconds instead.

What the page leaves out

The page has no request round trip, no TCP slow start between segments and one request at a time. It leaves out separate audio and video tracks, low-latency HLS and CMAF chunks (parts of a segment sent while it is still being encoded), live streams whose playlist grows, BOLA and other model-based rules, abandoning a slow download half way, screen-size caps on the rendition, DRM, and CDN choice and failover.

On the mind map

This page on the Networking mind map · 49 pages in 10 branches · open it to see the whole map and test yourself in recall mode.