HLS and MPEG-DASH solve the same problem in the same way. A video is encoded at several bitrates, cut into segments a few seconds long, and served over ordinary HTTP. A manifest tells the player what renditions exist and where the segments are, and the player decides, segment by segment, which rendition to fetch. Neither protocol needs a streaming server; a CDN serving files is enough. The differences are in the manifest format, the ecosystem around each, and which devices play which one natively.

That makes HLS versus DASH less a contest than a packaging decision. Most large services publish both, built from one set of segments. This article explains the two manifests side by side, how live streams update in each, where each one plays in 2026, how DRM and ad markers differ, and then walks through a concrete dual-manifest setup with the failure modes that bite in production.

Advertisement

What both protocols are

HLS (HTTP Live Streaming) was created by Apple and published as RFC 8216 in 2017; a second edition is maintained as the Internet-Draft known as rfc8216bis, which is still a draft. Its manifests are text playlists with the m3u8 extension. MPEG-DASH (Dynamic Adaptive Streaming over HTTP) is an ISO standard, ISO/IEC 23009-1, with interoperability profiles published by the DASH Industry Forum. Its manifest is an XML document called the Media Presentation Description, or MPD.

Historically HLS used MPEG-2 transport stream segments and DASH used fragmented MP4. HLS has accepted fragmented MP4 for years, and the CMAF standard defines a fragmented MP4 profile that both can reference. That is what makes the shared-segment architecture below practical.

One encode, one CMAF segment set, two manifests: how most services serve both protocolsEncoderABR ladderPackagerfMP4 / CMAF, cbcsHLS playlistsm3u8DASH MPDXMLSegmentsshared by bothCDNmanifests: short TTLSafari, iOS, tvOSnative HLS, FairPlayChrome, Edge, FirefoxMSE player, eitherAndroidMedia3, eitherSmart TVs, HbbTVoften DASHHLSDASHEach player picks a rendition per segment from the manifest: the adaptation logic lives in the client.
A typical dual-protocol pipeline. Segments are packaged once, each protocol gets its own manifest, and the CDN serves all of it. Players differ only in which manifest they read.

The manifests side by side

HLS uses two levels of playlist. The multivariant playlist (called the master playlist in RFC 8216) lists the variant streams with their bandwidth, codecs and resolution, and points to one media playlist per rendition. Each media playlist lists the segments.

# multivariant playlist: main.m3u8
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="English",LANGUAGE="en",DEFAULT=YES,AUTOSELECT=YES,URI="audio/index.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=5200000,AVERAGE-BANDWIDTH=4800000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=30,AUDIO="audio"
v1080/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2400000,CODECS="avc1.64001f,mp4a.40.2",RESOLUTION=1280x720,FRAME-RATE=30,AUDIO="audio"
v720/index.m3u8

# media playlist: v720/index.m3u8 (video-on-demand)
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="init.mp4"
#EXTINF:6.000,
seg_1.m4s
#EXTINF:6.000,
seg_2.m4s
#EXT-X-ENDLIST

DASH puts everything in one XML document. A Period contains AdaptationSets, usually one per media type or language; each AdaptationSet contains Representations, one per bitrate. Instead of listing segments, the MPD normally gives a SegmentTemplate that the player fills in.

<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" type="static"
     mediaPresentationDuration="PT10M" minBufferTime="PT2S"
     profiles="urn:mpeg:dash:profile:isoff-live:2011">
  <Period id="1" start="PT0S">
    <AdaptationSet contentType="video" mimeType="video/mp4" segmentAlignment="true">
      <SegmentTemplate timescale="90000" duration="540000" startNumber="1"
                       initialization="$RepresentationID$/init.mp4"
                       media="$RepresentationID$/seg_$Number$.m4s"/>
      <Representation id="v1080" bandwidth="5200000" codecs="avc1.640028"
                      width="1920" height="1080"/>
      <Representation id="v720" bandwidth="2400000" codecs="avc1.64001f"
                      width="1280" height="720"/>
    </AdaptationSet>
  </Period>
</MPD>

Note what is the same: bandwidth, codec strings, resolution and segment URLs. Note what differs: HLS repeats per-segment entries in every media playlist, which makes playlists grow and forces re-fetching for live, while DASH can describe an unbounded live stream in a few lines through the template and a clock.

Advertisement

The differences that matter

TopicHLSDASH
SpecificationRFC 8216; second edition in draftISO/IEC 23009-1 plus DASH-IF guidelines
ManifestText playlists, two levelsOne XML MPD
SegmentsMPEG-TS or fragmented MP4Fragmented MP4 (CMAF); WebM possible
CodecsThose Apple devices decode, plus others by clientCodec-agnostic by design
Live updatesReload the media playlistTemplate plus clock; MPD refresh only on change
Low latencyLL-HLS: partial segments, blocking reloadChunked CMAF delivery, latency targets in the MPD
DRMFairPlay; Widevine and PlayReady possibleWidevine, PlayReady; FairPlay possible
Native playbackSafari, iOS, tvOS, many TVsMany TVs and set-top boxes; browsers via MSE

Low-latency variants deserve their own treatment; low-latency streaming explains partial segments, preload hints and chunked transfer in detail. The short version is that both reach a few seconds of glass-to-glass latency, through different mechanisms, and both are harder to operate than standard segments.

Device reach in 2026

Apple platforms play HLS natively through AVPlayer and Safari's video element, and FairPlay protects it. That alone makes HLS non-negotiable for most consumer services. Browsers on other platforms play neither protocol natively; they use JavaScript players such as hls.js, dash.js or Shaka Player on top of Media Source Extensions, and those players handle both. Android's Media3 ExoPlayer plays both. Smart TVs vary by maker and year, and broadcast-related platforms such as HbbTV are built around DASH.

The historical gap was iPhone Safari, which lacked Media Source Extensions, so a DASH player could not run there. Since iOS 17.1 Safari exposes ManagedMediaSource, an MSE-compatible API in which the system can ask the player to release buffered data, and current releases of the major JavaScript players support it. Native HLS remains the path that works on every iPhone and with FairPlay, so treat ManagedMediaSource as an option for consistency across browsers, not a reason to drop HLS.

Live streams: how each one moves forward

In HLS live, the media playlist has no end tag. The player reloads it, appends new segments, and must not begin playback closer to the live edge than the spec allows: RFC 8216 says a client should not start with a segment that begins less than three target durations from the end of the playlist. Every EXTINF duration, rounded to the nearest integer, must not exceed EXT-X-TARGETDURATION, and players use the target duration to pace reloads. That makes the playlist itself a hot object at the CDN.

In DASH live, the MPD has type dynamic and an availabilityStartTime. With a numbered SegmentTemplate, the player computes which segments exist from the wall clock, so it does not need to reload the MPD unless it changes. That puts clock accuracy at the centre: a client whose clock runs ahead requests segments that do not exist yet and gets 404 errors, one whose clock runs behind sits further from live than intended. The UTCTiming element points players at a time source for exactly this reason.

from datetime import datetime, timezone

def latest_available_segment(now, availability_start, period_start_s,
                             seg_duration_s, start_number, availability_time_offset_s=0.0):
    """Number of the newest complete segment for a numbered SegmentTemplate."""
    elapsed = (now - availability_start).total_seconds() - period_start_s
    elapsed += availability_time_offset_s
    complete = int(elapsed // seg_duration_s)   # segments whose end time has passed
    return start_number + complete - 1

ast = datetime(2026, 10, 1, 12, 0, 0, tzinfo=timezone.utc)
now = datetime(2026, 10, 1, 12, 1, 3, tzinfo=timezone.utc)
print(latest_available_segment(now, ast, 0, 6.0, 1))   # 63 s elapsed: 10 complete, so 10

Worked through: 63 seconds after the start with 6-second segments, ten segments are complete, so with startNumber 1 the newest is segment 10. A player that also wants to stay a few seconds behind live subtracts its target delay before choosing. The HLS equivalent is simply the last entry in the most recent playlist, which is easier to reason about and costs a request per reload.

DRM and encryption

Both protocols carry encrypted segments defined by MPEG Common Encryption, which has two relevant schemes: cenc (AES-CTR) and cbcs (AES-CBC with a pattern). FairPlay requires cbcs. Current Widevine and PlayReady clients also accept cbcs, which means one cbcs-encrypted CMAF segment set can be licensed by all three DRM systems, with HLS carrying the FairPlay signalling and DASH carrying the Widevine and PlayReady signalling in ContentProtection elements.

The catch is older devices. Some older TVs, set-top boxes and clients only implement cenc, so a fleet that must reach them needs a second cenc set or a decision to drop those devices. Measure the device mix before committing. The DRM architecture article covers licence servers and key rotation.

Captions, metadata and ads

  • Captions. HLS typically uses segmented WebVTT renditions declared with EXT-X-MEDIA, or CEA-608/708 captions carried in the video. DASH uses TTML (often the IMSC1 profile) or WebVTT in their own AdaptationSets. If you serve both, generate both formats from one source.
  • Timed metadata and ad markers. HLS carries SCTE-35 cues and other events with EXT-X-DATERANGE tags. DASH uses EventStream elements in the MPD or emsg boxes in segments, and represents ad breaks naturally as separate Periods.
  • Server-side ad insertion. HLS splices ads with EXT-X-DISCONTINUITY around the ad segments; DASH switches Periods. Both work; testing them is where the effort goes. See server-side ad insertion for the full flow.

Worked example: one segment set, two manifests

Suppose a service with an Apple app, a web player and an Android app wants one pipeline. Encode a ladder with aligned keyframes (the same GOP length in every rendition), package into CMAF fragmented MP4 with cbcs encryption, and emit both manifests. With Shaka Packager, a VOD job looks like this; flag names should be checked against the version you install.

packager \
  'in=v1080.mp4,stream=video,init_segment=v1080/init.mp4,segment_template=v1080/seg_$Number$.m4s,playlist_name=v1080/index.m3u8' \
  'in=v720.mp4,stream=video,init_segment=v720/init.mp4,segment_template=v720/seg_$Number$.m4s,playlist_name=v720/index.m3u8' \
  'in=v720.mp4,stream=audio,init_segment=audio/init.mp4,segment_template=audio/seg_$Number$.m4s,playlist_name=audio/index.m3u8,hls_group_id=audio' \
  --segment_duration 6 \
  --mpd_output main.mpd \
  --hls_master_playlist_output main.m3u8

Then route by client: Apple apps and Safari get main.m3u8 with FairPlay; the web player and Android get main.mpd, or HLS if you prefer one player configuration everywhere. The segments are shared, so storage and CDN cache hit rates are the same as for a single protocol. For live, the same packager runs continuously, or a just-in-time packager builds either manifest on request from one mezzanine.

Failure modes in production

  • Unaligned keyframes across renditions. Switching bitrate then glitches or stalls. Force a fixed GOP and scene-cut alignment in the encoder.
  • Wrong CODECS or codecs strings. Players reject renditions they think they cannot decode, or pick ones they cannot. Generate the strings from the encoded stream, never by hand.
  • Manifest caching. A live playlist or MPD cached for longer than a segment makes players fall behind or stall. Give manifests a TTL well under the segment duration; give segments long TTLs.
  • Clock drift in DASH live. Clients ahead of the server get 404s at the live edge. Provide UTCTiming and monitor 404 rates per client type.
  • Segment longer than target duration. An HLS playlist that violates the target duration rule fails validation and confuses players. Check with Apple's mediastreamvalidator and DASH-IF conformance tools.
  • Discontinuities mishandled. Timestamp jumps at ad boundaries without a discontinuity tag or a new Period cause stalls or audio drift.

Operating both protocols

Serving two manifests doubles the number of things that can drift apart, so treat them as one product with two views. Generate both from the same packaging job, never by editing one by hand, and run a nightly check that compares them: the same renditions, the same bandwidth figures, the same segment count and total duration for each title. A mismatch usually means a failed partial repackage.

Measure quality of experience per protocol and per player, not only in aggregate: startup time, rebuffering ratio, average delivered bitrate and error rates by HTTP status. A regression that appears only on DASH clients points at the MPD or the JavaScript player; one that appears only on Apple devices points at the playlists, FairPlay or the native player. At the CDN, log manifest and segment requests separately, because manifest hit rates and 404s at the live edge are the earliest signal that caching or clock settings are wrong.

Decision guide

If you must reach iPhones, Apple TVs or Safari with DRM, you need HLS with FairPlay. If you must reach TV platforms or broadcasters that specify DASH, you need DASH. If both, which is the usual case, publish both from CMAF segments and pick per client. A single-protocol service is only realistic when the device list is narrow, for example an Apple-only app or an internal web tool. The bitrate ladder and the adaptive bitrate logic matter more to viewer experience than the protocol choice.

What to do next

  1. List your target devices and DRM requirements, and mark which need HLS, which need DASH and which accept either.
  2. Check whether any target devices only support cenc; if none do, plan a single cbcs CMAF segment set.
  3. Configure the encoder with a fixed GOP aligned across all renditions and segment durations that divide evenly into it.
  4. Package one title into both manifests and validate each with mediastreamvalidator and the DASH-IF conformance tool.
  5. Set CDN cache rules: short TTL for manifests, long TTL for segments, and confirm with response headers.
  6. For live, add UTCTiming to the MPD, and alert on 404 rates at the live edge and playlist staleness per protocol.
Key takeaway: HLS and DASH both deliver segmented video over HTTP with client-side adaptation; they differ in manifest format, live update model, native device support and DRM ecosystem. HLS is required for Apple devices and FairPlay, DASH for many TV platforms, and browsers can play either through MSE, now including iPhone Safari through ManagedMediaSource. Most services should package CMAF once, encrypt with cbcs where devices allow, publish both manifests, and spend their effort on aligned keyframes, manifest caching, clock sync and validation.