Adaptive bitrate and CDN selection
Adaptive bitrate streaming lets a player choose among encoded representations as network and playback conditions change. A smaller next segment can help avoid a stall. It cannot undo time already spent waiting for an earlier segment.
There are three related decisions: which rendition the viewer requests now, which renditions the service prepares, and where their bytes should be cached. We'll separate them, then use real segment sizes in a small simulation to see why reacting to the last transfer can be too late.
The player chooses from a prepared offer
The transcoding pipeline creates the representations. In HLS, a master playlist identifies available variants, and their media playlists identify ordered segments. The player chooses files that already exist; it does not ask the encoder to change an in-flight file's quality.
The ladder is the set of offered resolutions and bitrates. It must fit supported devices and codecs, with corresponding content aligned in time. A higher resolution is not automatically useful on a small display, and bitrate alone does not compare visual quality across different codecs or scenes.
Three quantities guide playback:
| Quantity | Meaning |
|---|---|
| Media bitrate | Encoded bits per second of media |
| Download throughput | Received bits per second of transfer time |
| Buffer | Seconds of media available ahead of playback |
Production selectors may combine throughput estimates, buffer levels, device limits and switching history. For example, dash.js documents distinct throughput, buffer, dropped-frame and request-abandonment rules. Our rule below intentionally uses only the previous completed transfer so its delay is easy to see.
A three-request experiment
The lab and media helper generate the same HLS files as the preceding lesson. Use its pinned Python environment and FFmpeg 8.1.2. File sizes are measured; download times and stalls are calculated under a chosen capacity schedule, with no real congested network.
Both policies start with one second buffered. Fixed-high always requests the larger rendition. Adaptive requests high if its previous observed capacity is at least 200,000 bits/s, otherwise low. Its initial observation is 400,000 bits/s; neither policy can see the next capacity before choosing.
/tmp/fanout-m24/bin/python m24-lab.py abr
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=55648,RESOLUTION=160x90
low/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=188000,RESOLUTION=320x180
high/index.m3u8
chosen capacity bits/s=[400000, 40000, 400000] initial buffer=1.000s
fixed-high download/buffer/stall: high:0.447s/1.553s/0.000s, high:4.474s/1.000s/2.922s, high:0.470s/1.530s/0.000s total_stall=2.922s
adaptive download/buffer/stall: high:0.447s/1.553s/0.000s, high:4.474s/1.000s/2.922s, low:0.139s/1.861s/0.000s total_stall=2.922s
simulated origin observations: A age=4 refused; B age=1 selected=B
Each generated segment lasts one second. The largest high segment contains 23,500 bytes, giving the advertised peak of 188,000 bits/s. This calculation is valid for the fixture's equal one-second segments and one-second target duration; it is not a promise of network capacity.
For a segment of S bytes and a path capacity of C bits/s, ideal transfer time is 8*S/C. If the player starts that request with B seconds buffered, the stall is max(0, transfer time − B). Afterward, the buffer is max(0, B − transfer time) + segment duration.
The first high segment is 22,372 bytes. At 400,000 bits/s it takes 0.44744 seconds, leaving 1.55256 seconds buffered after adding the new second of media. The next high segment has the same size, but capacity drops to 40,000 bits/s.
That transfer takes 4.4744 seconds: 2.92184 seconds longer than the available buffer. Both policies stall by the displayed 2.922 seconds. Adaptive learns about the drop only after that transfer completes, then switches low just as capacity recovers.
Fast transfer"] --> B["Request 2: high
Capacity drops; stall"] B --> C["Observe slow transfer"] C --> D["Request 3: low
Capacity has recovered"]
The last low segment's 6,956 bytes arrive quickly, but cannot recover time already stalled. On this schedule the adaptive rule does not improve the total-stall metric. The experiment omits round trips, protocol overhead, contention and decoder startup; it tests the consequence of delayed information, not a production ABR algorithm.
A buffer-aware rule could become more cautious as playable time runs low. More startup buffer can absorb longer transfers, but makes the viewer wait before playback. Evaluate startup delay, rebuffering and quality changes together rather than choosing a universal threshold from this three-second clip.
Which renditions should exist?
The player cannot select a version the service has not prepared. Encoding every upload into every possible format spends compute and storage even on videos that nobody watches. Deferring everything makes the first viewer wait for processing.
| Preparation policy | Useful when | Cost or delay |
|---|---|---|
| Eager ladder | The expected audience needs several representations immediately | Work is paid even if some renditions are never watched |
| Baseline, then more on demand | A complete initial offer is enough for less-watched uploads | New representations take time to become available |
| Prepare for predicted demand | A release or rising audience provides advance notice | A wrong prediction wastes work or misses demand |
This is independent of the request-by-request ABR rule. It changes what the rule will be able to choose later.
The CDN decider controls preparation and placement
“CDN decider” is a name for our proposed policy service, not a standard CDN API. It combines recent view velocity, viewer geography, channel audience, content type, shares, trending signals and known release spikes to decide where extra work is justified.
Its actions may include generating another rendition, warming selected ready objects in a region, retaining an origin copy or retiring an unused cache placement. The available controls depend on the delivery provider; ordinary CDN eviction is often automatic, not a per-object command the application owns.
Warming transfers bytes before a viewer requests them. It can reduce a first miss while consuming fill bandwidth and cache space. Moving a source to colder storage is a separate retention choice and may increase retrieval delay. Keep encoding, cache placement and storage tiering as separate actions with explicit costs.
Netflix's Open Connect fill documentation gives a concrete placement example: appliances hold portions of the catalog and primarily receive updates in off-peak windows. Popularity changes and new or re-encoded titles affect those updates. This is Netflix's documented delivery model, not a guarantee offered by every CDN.
Our controller can consume product events such as video.published, video.viewed and video.trending, and emit a request to prepare or cache a version. Treat variant.generated as evidence of a ready output, not merely a queued task. Repeated events should converge on one intended action.
Use bounded budgets and a quiet period before reversing a placement decision. Otherwise noisy demand can repeatedly trigger expensive encodes or cache fills. Measure useful cache hits and avoided viewer delay against the work spent; traffic volume alone does not show that warming paid off.
Choosing a delivery location
After selecting a ready object, a player or delivery service may still choose which CDN or origin serves it. This is a separate decision from choosing the rendition. Old latency samples can mislead either choice.
The final line of the replay compares two simulated origins transferring the same 1,000 bytes. A took 0.1 seconds at tick 1; B took 0.2 seconds at tick 4. At tick 5, a maximum age of two ticks excludes the faster but stale A sample, so B wins.
That toy rule only compares fresh equal-size observations. A real selector also needs failure rates, comparable workloads and a fallback when no candidate is eligible. Neither the example nor the label “CDN” establishes a global performance result.
The next access lesson checks permission on every playlist and segment the player chooses.
Adaptive Bitrate (ABR) Protocols: HLS & DASH
Adaptive Bitrate streaming dynamically adjusts video quality in real time based on the viewer's current network bandwidth and device capabilities. If a viewer walks into an elevator, the stream drops from 1080p to 480p, usually before the buffer runs dry, so playback continues at lower quality instead of stalling.
Manifest and Segment Hierarchy
The video player first downloads a Master Playlist containing a list of available quality stream variants and their respective bandwidths:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=4500000,RESOLUTION=1920x1080
1080p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2200000,RESOLUTION=1280x720
720p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=854x480
480p/index.m3u8
The player continuously measures download speeds for each 6-second segment. It keeps a smoothed throughput estimate, watches buffer level, and picks a lower rendition (with a safety margin) before downloads fall behind playback; waiting until a download takes longer than the segment duration means the buffer is already draining.
Worked example: a throughput-based decision
Ladder: 4.5, 2.2 and 0.8 Mbit/s; segments are 6 seconds.
- The player's smoothed throughput estimate is 3.0 Mbit/s. With a 0.8 safety factor it may choose up to 2.4 Mbit/s, so it picks 720p (2.2 Mbit/s).
- A 720p segment is 2.2 x 6 = 13.2 Mbit. At 3.0 Mbit/s it downloads in 4.4 seconds, so the buffer grows by 1.6 seconds per segment.
- The network drops to 1.0 Mbit/s. The same segment now takes 13.2 seconds while only 6 seconds of video are added: the buffer shrinks 7.2 seconds per segment. With a 20 second buffer, the player has about 2 segments before stalling, so it must drop to 0.8 Mbit/s promptly (a 480p segment at 1.0 Mbit/s takes 4.8 seconds, and the buffer grows again).
Buffer-based adaptation
The buffer-based approach (Huang et al., SIGCOMM 2014, with Netflix) chooses rate mainly from buffer occupancy: below a reservoir of, say, 10 seconds always pick the lowest rung; above 30 seconds pick the highest; in between map linearly. It uses throughput mainly at startup, and it reduced rebuffering in Netflix's experiments while keeping similar average quality.
| Algorithm family | Signal | Strength | Weakness |
|---|---|---|---|
| Throughput-based | Recent segment download speeds | Fast startup, simple | Noisy estimates cause oscillation and stalls |
| Buffer-based (BBA, BOLA) | Buffer level | Fewer rebuffers, stable | Slow to ramp up at startup |
| Hybrid or model predictive | Both, plus a short-horizon prediction | Best quality versus stall trade-off | More complex to tune |
The CDN decider
- Inputs: per ISP and region quality data (throughput, rebuffer ratio, error rate), CDN health, capacity and cost commitments.
- Standards: HLS content steering (EXT-X-CONTENT-STEERING) and DASH-IF content steering let a server update the preferred CDN order during playback.
- Netflix's steering service chooses Open Connect appliances, often inside the viewer's ISP, and returns ranked URLs so the client can fall back if one server fails.