Skip to content

ABR adaptive bitrate testing

Adaptive Bitrate streaming is not a single-rendition system. Real viewers watch at different quality levels depending on their connection speed, device, and screen size. A load test that only fetches your highest-quality rendition misses the actual traffic mix — and potentially the bottlenecks that only appear under a mixed rendition load.

This page explains how ABR switching works, how to model a realistic viewer mix across renditions, and how to read the results in MaxoPerf.

  • Read HLS and DASH manifest and segment testing — this page builds on the player simulation pattern introduced there.
  • Have your manifest URLs ready: master manifest, variant playlist URL for each rendition, and sample segment URLs for each rendition.

A typical HLS or DASH stream offers 4–6 renditions, for example:

RenditionBitrateSegment size (4s)Bytes/viewer/min
240p400 Kbps~200 KB~3 MB
480p1.2 Mbps~600 KB~9 MB
720p2.5 Mbps~1.25 MB~18.75 MB
1080p5 Mbps~2.5 MB~37.5 MB
4K15 Mbps~7.5 MB~112.5 MB

A viewer on a mobile network may consume the 400 Kbps rendition; a desktop viewer on fiber will climb to 1080p. If your test only runs the 4K rendition, you will drive 20–40× more bytes per VU than your average real viewer and will exhaust bandwidth before you hit the viewer concurrency you actually need to test. Conversely, a 240p-only test under-stresses your origin.

Structure your test as multiple scenarios — one per rendition — weighted to reflect your real viewer distribution:

execution:
# 60% of viewers on 720p (mobile + mid-tier desktop)
- concurrency: 300
ramp-up: 2m
hold-for: 10m
scenario: viewer-720p
# 30% of viewers on 1080p (desktop, connected TV)
- concurrency: 150
ramp-up: 2m
hold-for: 10m
scenario: viewer-1080p
# 10% of viewers on 480p (constrained mobile)
- concurrency: 50
ramp-up: 2m
hold-for: 10m
scenario: viewer-480p
scenarios:
viewer-720p:
requests:
- label: master-manifest
url: https://cdn.example.com/stream/master.m3u8
method: GET
- label: variant-playlist-720p
url: https://cdn.example.com/stream/720p/playlist.m3u8
method: GET
- label: segment
url: https://cdn.example.com/stream/720p/seg-0001.ts
method: GET
- label: segment
url: https://cdn.example.com/stream/720p/seg-0002.ts
method: GET
think-time: 4s
- label: segment
url: https://cdn.example.com/stream/720p/seg-0003.ts
method: GET
think-time: 4s
- label: segment
url: https://cdn.example.com/stream/720p/seg-0004.ts
method: GET
think-time: 4s
viewer-1080p:
requests:
- label: master-manifest
url: https://cdn.example.com/stream/master.m3u8
method: GET
- label: variant-playlist-1080p
url: https://cdn.example.com/stream/1080p/playlist.m3u8
method: GET
- label: segment
url: https://cdn.example.com/stream/1080p/seg-0001.ts
method: GET
- label: segment
url: https://cdn.example.com/stream/1080p/seg-0002.ts
method: GET
think-time: 4s
# continue for segment coverage needed...
viewer-480p:
requests:
- label: master-manifest
url: https://cdn.example.com/stream/master.m3u8
method: GET
- label: variant-playlist-480p
url: https://cdn.example.com/stream/480p/playlist.m3u8
method: GET
- label: segment
url: https://cdn.example.com/stream/480p/seg-0001.ts
method: GET
- label: segment
url: https://cdn.example.com/stream/480p/seg-0002.ts
method: GET
think-time: 4s

By running all three execution blocks in parallel, MaxoPerf drives a realistic mixed-bitrate load against your CDN and origin simultaneously.

Simulating bitrate switching within a session

Section titled “Simulating bitrate switching within a session”

A viewer who starts on 720p and then switches to 1080p mid-stream creates a different CDN request pattern. To model this, structure a single viewer scenario to switch renditions partway through:

scenarios:
viewer-with-quality-switch:
requests:
# Start on 720p
- label: master-manifest
url: https://cdn.example.com/stream/master.m3u8
- label: variant-playlist-720p
url: https://cdn.example.com/stream/720p/playlist.m3u8
- label: segment-720p
url: https://cdn.example.com/stream/720p/seg-0001.ts
- label: segment-720p
url: https://cdn.example.com/stream/720p/seg-0002.ts
think-time: 4s
- label: segment-720p
url: https://cdn.example.com/stream/720p/seg-0003.ts
think-time: 4s
# Switch to 1080p — triggers a new playlist fetch + resync
- label: variant-playlist-1080p
url: https://cdn.example.com/stream/1080p/playlist.m3u8
- label: segment-1080p
url: https://cdn.example.com/stream/1080p/seg-0004.ts
think-time: 4s
- label: segment-1080p
url: https://cdn.example.com/stream/1080p/seg-0005.ts
think-time: 4s
- label: segment-1080p
url: https://cdn.example.com/stream/1080p/seg-0006.ts
think-time: 4s

The extra variant playlist fetch at the switch point is the detail that matters — CDN origin hit rates can shift significantly when large numbers of viewers simultaneously upgrade their rendition (for example, when a slow CDN region recovers and players all step up at once).

In the results Overview tab, the per-label breakdown gives you latency for each rendition separately:

What you seeWhat it means
segment-720p p95 < 4000msCDN is serving 720p segments within the segment duration — good
segment-1080p p95 > 4000ms, segment-720p p95 OKOrigin is stressed for large segments; CDN miss-rate is high for 1080p
variant-playlist-* latency risingManifest server under pressure — common when playlist generation is not cached
Error rate spiking on segment-1080p only1080p rendition origin / storage tier is the bottleneck

Do:

  • Base your rendition mix on real analytics data (average bitrate your users actually consume).
  • Label requests with the rendition name so you can isolate which rendition is causing problems.
  • Include a bitrate-switch scenario if your platform has frequent quality switches (e.g., mobile on variable networks).

Don’t:

  • Test only your highest-quality rendition — it overstresses per-VU bandwidth and masks issues in lower-bitrate delivery paths.
  • Assume all renditions perform equally — packaging infrastructure, CDN rules, and storage tiers often differ between renditions.