Adaptive streaming
An adaptive bitrate job produces a ladder: the same video encoded several times at different resolutions and bitrates, plus a manifest that tells the player which rung to pull. The player switches rungs as the viewer's bandwidth changes, which is why streaming looks stable on a bad connection where a single 1080p file would stall.
What the presets give you
| Preset | Rungs | Codec | Package | Plan |
|---|---|---|---|---|
hls_abr_264_basic | 240p, 480p, 720p | H.264 with AAC | HLS, CMAF fMP4 | Free |
hls_abr_264_standard | 240p, 360p, 480p, 720p, 1080p | H.264 with AAC | HLS, CMAF fMP4 | Pro |
dash_abr_vp9_standard | ladder | VP9 with Opus | DASH | Pro |
dash_abr_av1_efficient_1080p | ladder to 1080p | AV1 | DASH | Business |
hls_abr_265_efficient_4k | ladder to 4K | HEVC | HLS, CMAF fMP4 | Enterprise |
dash_abr_av1_efficient_4k | ladder to 4K | AV1 | DASH | Enterprise |
The H.264 HLS ladders use six-second segments, a two-second GOP, and independent segments, so a player can switch rung at any segment boundary.
Here is the standard five-rung ladder in full:
| Rung | Resolution | Peak bitrate | Buffer | Audio |
|---|---|---|---|---|
| 1080p | 1920x1080 | 5200k | 10400k | 192k |
| 720p | 1280x720 | 2800k | 5600k | 128k |
| 480p | 854x480 | 1200k | 2400k | 96k |
| 360p | 640x360 | 600k | 1200k | 96k |
| 240p | 426x240 | 300k | 600k | 64k |
The output is a ZIP
A streaming job produces many files, so the output is delivered as a single ZIP archive rather than a playable URL. Unpack it and you get:
master.m3u8 the multivariant playlist a player loads
manifest.json an index of every file with its byte size
thumbnail.jpg a frame taken from the source
v0/prog_index.m3u8 media playlist for the first rung
v0/seg_000.m4s fMP4 segments for the first rung
v1/… and so on, one directory per rungDASH jobs have the same shape with an MPD manifest in place of the playlists.
manifest.json is there so you can enumerate and verify the archive without
parsing playlists:
{
"version": "1.0",
"type": "hls-cmaf",
"master": "master.m3u8",
"files": [
{ "path": "master.m3u8", "bytes": 412 },
{ "path": "v0/prog_index.m3u8", "bytes": 1180 },
{ "path": "v0/seg_000.m4s", "bytes": 241664 }
]
}Serving it
The signed link we give you points at the ZIP. That link is for you, not for your viewers: a player cannot stream from inside an archive, and the link expires. Unpack the archive and publish the files yourself.
curl -o hls.zip "$OUTPUT_URL"
unzip hls.zip -d ./hls
aws s3 sync ./hls s3://your-bucket/videos/9d1f5c0a/ --acl public-readPoint your player at master.m3u8 in the location you published to.
Two things break playback if you skip them:
Content types. Many object stores guess wrong. Serve .m3u8 as
application/vnd.apple.mpegurl, .mpd as application/dash+xml, and .m4s
as video/iso.segment. A playlist served as text/plain will not play.
CORS. If the player runs on a different origin from the files, the segment requests need permissive CORS headers, or the browser blocks them with no useful error.
Which one to pick
Start with hls_abr_264_basic. Three rungs cover most viewers, it is on every
plan, and H.264 decodes everywhere.
Move to hls_abr_264_standard when you have 1080p sources worth delivering and
an audience with the bandwidth for the top rung. The extra rungs cost encoding
time, not playback quality.
Choose DASH over HLS when your player is browser-based and you want VP9 or AV1. Choose HLS when Apple devices matter, since Safari plays HLS natively.
Reach for the HEVC and AV1 ladders when bandwidth cost is the constraint and you control the client. They halve the bytes and narrow the set of devices that can play them.
Encoding time
A ladder encodes every rung, so it takes several times longer than one MP4 of the same source. The five-rung H.264 preset estimates 8 to 18 minutes for a typical source. Use a webhook rather than holding a request open.