Stream Video Downloader logo
← Back to Blog

H.264 vs. H.265 vs. VP9 vs. AV1 in HLS: What the CODECS Attribute Actually Declares

July 20, 2026 · 7 min read

The ABR post on this blog covers BANDWIDTH and RESOLUTION, the two #EXT-X-STREAM-INFattributes a player uses to pick a quality level. Neither one says anything about the format the video inside that variant is actually encoded in. That's a separate attribute — CODECS— and it matters more than its one-line RFC 8216 definition suggests, because a browser that's perfectly capable of playing an .m3u8 playlist can still fail on a specific variant if that variant's codec isn't one the browser knows how to decode. Four codecs cover almost every HLS stream you'll encounter, and they don't compress, license, or decode the same way.

What the CODECS attribute actually declares

Per RFC 8216 §4.3.4.2, CODECS is an optional quoted-string attribute on #EXT-X-STREAM-INF containing a comma-separated list of format identifiers, one per media type present in that variant — typically one for video and one for audio:

  • #EXT-X-STREAM-INF:BANDWIDTH=2600000,RESOLUTION=1920x1080,CODECS="avc1.64001f,mp4a.40.2"

Each identifier follows the RFC 6381 codec-string convention already introduced in the MSE post, where addSourceBuffer() takes a full MIME type plus codec string before it will accept a single byte of media. The prefix names the codec family — avc1 for H.264, hvc1/hev1 for H.265, vp09 for VP9, av01 for AV1, mp4a for AAC audio — and the digits after it encode a profile, level, and constraint set that get progressively pickier about exactly which encoder settings are allowed. The whole point of putting this in the master playlist, rather than making a player discover it by downloading segments, is that a client can decide a variant is unplayable — and skip requesting it — before spending a single byte of bandwidth on it.

H.264 / AVC — the one every device can decode

H.264, standardized in 2003, is the codec Apple's original HLS specification was built around, and it remains the safe default for exactly one reason: hardware decode support is close to universal — every phone, laptop, smart TV, and set-top box sold in the last decade-plus can decode it, usually with a dedicated hardware block that barely touches battery life. Its cost is compression efficiency: at a given bitrate, H.264 needs meaningfully more data to hit the same visual quality than any of the three codecs below it. A stream that has to work everywhere, with no fallback and no variant negotiation, still typically ships an H.264 rendition even when higher-efficiency codecs are also available in the same master playlist.

H.265 / HEVC — better compression, messier rollout

H.265 (HEVC) is H.264's direct successor, commonly cited as needing on the order of 25–50% less bitrate for comparable quality. Apple has supported HEVC in HLS for years — it's the codec recommended for high-resolution and HDR content in Apple's own HLS authoring guidelines, and iOS, macOS, and tvOS all decode it in hardware. Support elsewhere is less uniform: many Android devices decode HEVC in hardware too, but desktop Chrome and Firefox have historically shipped without built-in HEVC decode, leaning on whatever codec the operating system happens to provide instead. Part of that hesitation is licensing — unlike H.264's single patent pool, HEVC's patents are split across multiple competing pools, which has made licensing terms a genuine deterrent for some browser vendors and hardware makers.

VP9 — royalty-free, and mostly a DASH/YouTube codec

VP9 is Google's royalty-free answer to HEVC, with compression efficiency in a similar range, and it's decoded natively and often in hardware across Chrome and Android. Its adoption has run mostly through MPEG-DASH rather than HLS — YouTube is the highest-profile example — because Apple's platforms, which HLS exists to serve, never adopted VP9 the way they adopted HEVC. It shows up in HLS far less often as a result, even though nothing in the HLS spec itself excludes it.

AV1 — the newest, most efficient, and most expensive to decode

AV1 is a royalty-free codec from the Alliance for Open Media, a consortium that includes Google, Apple, Microsoft, Netflix, and Mozilla among others, and it's the most efficient of the four — commonly cited as needing significantly less bitrate than HEVC or VP9 at comparable quality, with the gap widest at higher resolutions. The catch is decode cost: dedicated AV1 hardware decoders only started showing up broadly in phone chipsets and GPUs in the last few years, so playing AV1 on older hardware often falls back to software decode, which is far more CPU- and battery-intensive than a hardware path. Streaming services have been adding AV1 renditions as an additional variant in the bitrate ladder — not a replacement — precisely so a player can fall back to HEVC or H.264 on hardware that can't decode AV1 efficiently.

Why /convert doesn't care which of these a stream uses

The ffmpeg.wasm post already covers this site's converter running FFmpeg in stream-copy mode (-c copy): it repackages the existing compressed bitstream into a new MP4 container without decoding a single frame. That means /convert's output is correct regardless of whether the source segments are H.264, HEVC, VP9, or AV1 — it never has to know. It's also consistent with what this site's own parser does today: parseMaster() in lib/m3u8-parser.ts reads RESOLUTION and BANDWIDTH off every #EXT-X-STREAM-INF line to pick the highest-resolution variant, and never inspects CODECSat all. For a repackaging tool that copies whatever bitstream it's given, that's not a bug — the attribute genuinely isn't needed for the job the converter does.

Why /play does care, indirectly

Playback is where codec choice actually matters, just not through a check this site's own code performs directly. /play hands the stream to hls.js, which owns the Media Source Extensions buffer and, before appending any segment, relies on the browser's own MediaSource.isTypeSupported() to decide whether a given codec string can be decoded at all — the same check described in the MSE post, and the reason a variant with an unsupported CODECS value fails at the buffer, not at the network layer. A tool built on WebCodecs instead would ask the analogous question through VideoDecoder.isConfigSupported(). Either way, the browser — not this site's parser — is what ultimately decides whether a given codec plays.

FAQ

Does a higher-efficiency codec mean a smaller download? For the same visual quality, yes — that's the entire point of HEVC, VP9, and AV1 over H.264. But a master playlist's variants are usually sized by bitrate target, not by codec alone, so the actual file size difference for a given stream depends on how the packager set up its bitrate ladder, not just which codec it picked.

If a browser can't decode a variant's codec, does the whole stream fail? Not usually. Well-authored master playlists that offer HEVC or AV1 typically also include an H.264 variant in the same bitrate ladder, so a player that can't decode the higher-efficiency codec — or, in hls.js's case, a player whose MediaSource.isTypeSupported() check rejects it — can fall back to a variant it can actually play. A playlist with only one codec and no fallback variant is the case where an unsupported codec breaks playback entirely.

Does this site's converter re-encode between codecs? No. /convert only repackages the container — see the ffmpeg.wasm post — so the output MP4 keeps whatever codec the source segments were already encoded in. A tool that needed to transcode from one codec to another would need an actual decode/encode pass, the kind of work described in the WebCodecs post, not a stream copy.