DrawLintDrawLint.ai
🗺️Design Patterns·6 min read

HLS / DASH Adaptive Streaming

Stream video as small multi-bitrate chunks so quality adapts to each viewer's network.

HLS and DASH solve a deceptively hard video problem: one viewer is on fiber, another is on hotel Wi-Fi, another is on a subway, and the same movie must keep playing for all of them. Adaptive streamingencodes the video into short segments at multiple bitrates, publishes a manifest that lists those choices, and lets the player choose the next segment quality based on real-time network conditions.

🔭Think of it like…
Think of video as a road trip with gas stations every few miles. If the highway is clear, you take the fast lane between stations. If traffic gets bad, you switch to the slower lane for the next stretch instead of being stuck behind one giant truck for the whole journey.

The problem: one fixed file cannot fit every network

A single movie.mp4 at one bitrate is simple to store, but it fails in two directions. High bitrate video stalls on slow networks because the player cannot download bytes as fast as it consumes them. Low bitrate video plays everywhere but looks blurry on fast networks and large screens. Adaptive streaming turns one large file into many small decisions.

Delivery modelWhat the player downloadsWhat breaks
Single fixed MP4One continuous file at one qualityEither stalls on slow links or wastes quality on fast links
Progressive download with RangeByte ranges from one renditionSeeking works, but quality cannot change without switching files
HLS or DASHSmall segments chosen from many renditionsNeeds an encoding pipeline, manifests, and more objects
The core idea
Segment duration is the adaptation window. Every 2-6 seconds the player gets a chance to ask, "Can I afford a better rendition now, or should I downgrade before the buffer empties?"

Encoding pipeline: renditions, segments, and manifests

After upload, a transcoding pipeline produces a ladder ofrenditions: the same content at different resolutions and bitrates. Each rendition is cut into aligned segments, usually a few seconds long. Alignment matters: segment 120 in the 360p stream must represent the same time range as segment 120 in the 1080p stream so the player can switch cleanly.

typical adaptive streaming pipeline
raw_upload.mp4
  → validate and probe duration/codecs
  → encode rendition ladder:
      426x240   400 kbps
      854x480   900 kbps
      1280x720  2500 kbps
      1920x1080 5000 kbps
  → segment each rendition into 4-second chunks
  → write chunks + manifest to object storage
  → put CDN in front of the manifest and segments

Why storage grows

You are storing several versions of the same video. If the original is 1 GB, the total adaptive set might be 2-4 GB depending on the ladder, codecs, audio tracks, thumbnails, captions, and packaging. The payoff is that every segment is cacheable and every viewer can receive an appropriate bitrate.

  • HLS: uses .m3u8 playlists and is the default for Apple platforms and most web players.
  • DASH: uses an .mpd manifest and is common in standards-based players and Android ecosystems.
  • CMAF: a packaging approach that lets HLS and DASH share many of the same fragmented MP4 media segments.

The manifest: a menu of segment choices

The manifest is not the video. It is a small text file that tells the player which renditions exist, their approximate bandwidth, codecs, resolution, and where to fetch each media playlist or segment. The player loads the manifest first, then requests media segments from the chosen rendition.

simplified HLS master playlist
#EXTM3U
#EXT-X-VERSION:7

#EXT-X-STREAM-INF:BANDWIDTH=450000,RESOLUTION=426x240,CODECS="avc1.4d401e,mp4a.40.2"
240p/playlist.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=854x480,CODECS="avc1.4d401f,mp4a.40.2"
480p/playlist.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2"
720p/playlist.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=5500000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2"
1080p/playlist.m3u8
one media playlist points at short segments
#EXTM3U
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:1200
#EXTINF:4.000,
seg-1200.m4s
#EXTINF:4.000,
seg-1201.m4s
#EXTINF:4.000,
seg-1202.m4s

Many modern packages use byte-range requests instead of one physical file per segment. The manifest can point to ranges inside a larger media file, and the player sends Range headers to fetch just the bytes it needs. This reduces object counts while keeping segment-level adaptation.

Player adaptation: bandwidth, buffer, and switching

The player constantly estimates two things: how fast it can download and how much playable video is already buffered. If a 4-second 1080p segment takes 7 seconds to download, the buffer is shrinking and the next segment should be lower quality. If several segments arrive quickly and the buffer is healthy, the player can try a higher rendition.

simplified adaptive bitrate loop
for each next segment:
  measuredBandwidth = bytesDownloaded / downloadSeconds
  safetyBandwidth = measuredBandwidth * 0.75

  if bufferSeconds < 10:
    choose lower rendition immediately
  else:
    choose highest rendition whose bitrate < safetyBandwidth

  request segment with HTTP GET or Range
  append bytes to media buffer
SignalIf it gets worsePlayer response
Measured bandwidthSegments download slower than real timeSwitch down before playback stalls
Buffer depthBuffered seconds fall below a thresholdPrefer continuity over quality
Device capabilityCPU or display cannot decode high qualityCap maximum resolution or codec
CDN/cache healthEdge misses or origin latency increasePlayer sees slower downloads and adapts down
Stalls hurt more than blurry video
Users forgive a temporary drop from 1080p to 720p far more than a frozen spinner. Good ABR algorithms are conservative when the buffer is low and opportunistic only when they have cushion.

CDN delivery and byte ranges

Adaptive streaming is almost tailor-made for a CDN. Millions of viewers request the same manifests and segment URLs, so edge caches can serve them near users. Your origin should usually be object storage, often the same primitive used for blob uploads.

segment request through CDN with byte range
GET /videos/v123/720p/media.mp4 HTTP/1.1
Host: cdn.example.com
Range: bytes=8388608-10485759

HTTP/1.1 206 Partial Content
Content-Range: bytes 8388608-10485759/734003200
Cache-Control: public, max-age=31536000, immutable
  • Immutable segment URLs: include a content hash or version in the path so cached chunks can live for months without accidental stale playback.
  • Short manifest TTL for live: live manifests change as new segments appear, so cache them briefly while segments can be cached much longer.
  • Origin shielding: put a CDN shield in front of object storage so a viral video does not stampede the bucket from thousands of edge locations.

Gotchas and real-world examples

Netflix, YouTube, Twitch, sports apps, course platforms, and internal training portals all use variants of this pattern. The exact codecs and packaging differ, but the shape is the same: encode a rendition ladder, publish manifests, cache aggressively, and let the player adapt.

  • Startup latency: shorter segments adapt faster but create more requests and overhead. Longer segments are cheaper but react slowly to bandwidth changes.
  • Codec compatibility: AV1 or HEVC may save bandwidth but not every browser/device can decode them. Manifests often advertise multiple codec families.
  • Live latency: live streaming needs careful segment size, playlist window, and player buffer tuning. Low-latency HLS/DASH adds partial segments and more moving parts.
  • DRM and signed URLs: private video often combines CDN signed URLs/cookies with license servers. Do not put long-lived secrets in manifests.
Key takeaways
  • Adaptive streaming encodes the same video into multiple bitrate renditions and cuts each rendition into short aligned segments.
  • A manifest is the player's menu: it lists renditions, bandwidths, codecs, resolutions, and segment locations.
  • The player measures bandwidth and buffer health, then chooses the next segment quality; switching happens segment by segment.
  • CDNs are essential because manifests and segments are static, cacheable HTTP objects served to many viewers.
  • Byte-range requests let players fetch only the segment bytes they need, supporting seeking, resume, and lower object counts.
Short segments create decision points. Every few seconds the player can measure download speed and buffer health, then pick a higher or lower rendition for the next segment without restarting the video.
The manifest lists the available renditions and media segment locations. The player reads it first, then chooses which rendition's segments to request based on bandwidth, buffer, device capability, and policy.
Segments are immutable HTTP objects requested by many viewers. A CDN caches them near users, reducing startup latency and keeping repeated segment reads off your origin object store.
Finished this lesson?

Mark it complete to track your progress through the workbook.