Video codec support in browsers and devices
Checking a codec name is not enough. A file plays only if the browser handles the whole combination: codec, profile, level or tier, bit depth, chroma, container and audio codec, through the playback API you use.
Native browser playback
Section titled “Native browser playback”| Format | Native browser playback | Check on your targets |
|---|---|---|
| AVC / H.264 | All major browsers. Chromium builds without proprietary codecs lack it. | Profile, level and MP4 setup |
| HEVC / H.265 | Safari. Chrome only with a hardware decoder. Mozilla lists Firefox support as limited. | Hardware and OS availability, hvc1 versus hev1, depth, chroma and HDR display behavior |
| VP8 | Chrome and Firefox. Safari on macOS since 14.1, on iOS and iPadOS since 17.4. | File playback versus WebRTC, audio track and WebM/MSE path |
| VP9 | Chrome and Firefox. Safari on macOS since 14.1, on iOS and iPadOS since 17.4. | Profile 0 versus 2, 8/10/12-bit, chroma, HDR and hardware decode |
| AV1 | Chrome and Firefox. Safari 17+ only on devices with hardware AV1 decoding. | Device, profile, depth, level, software decode speed and container |
| Theora | Legacy. Firefox disabled it by default in 126, and Chromium no longer lists it. | Not a web fallback any more |
| Everything else | None: VVC, AV2, AVS3, VC-1, FFV1, ProRes, Ut Video, DSV, DSV2, ECM | Ship a web rendition in one of the codecs above, or bring your own application decoder |
Sources: Chromium’s codec list, Mozilla’s supported-format table, Firefox 126 release notes, and WebKit’s Safari 17.0 and Safari 17.4 notes. Edge and other Chromium browsers follow Chrome, except where the vendor removes proprietary codecs.
Four playback paths
Section titled “Four playback paths”| Path | Appropriate check | What a positive result leaves unresolved |
|---|---|---|
| Native file / HTML video | HTMLMediaElement.canPlayType() and an actual file | Decode rate, seeking, timestamps, audio, HDR and display correctness |
| Media Source Extensions (MSE) | MediaSource.isTypeSupported() for the intended byte-stream type | Segmentation, initialization data, append boundaries and adaptive switching |
| WebCodecs | VideoDecoder.isConfigSupported() for the exact codec configuration | Demuxing, timestamps, audio synchronization and frame rendering |
| JavaScript / WebAssembly codec | Application-specific decode test | Integration, CPU and memory budget, battery cost and renderer correctness |
The same browser can give different answers for each path. A WebCodecs decoder does not demux MP4 or play audio by itself, and a software WASM decoder does not add to the browser’s native codec list. The WebCodecs specification defines the configuration queries and the encode and decode model.
Probe a concrete rendition
Section titled “Probe a concrete rendition”Run this in the target page’s browser console. The configurations are examples. Derive the real codec string, dimensions, bitrate and frame rate from your encoded file, and use its container’s MIME type.
const candidates = [ { name: 'AVC High 8-bit', contentType: 'video/mp4; codecs="avc1.640028"' }, { name: 'HEVC Main 10', contentType: 'video/mp4; codecs="hvc1.2.4.L120.B0"' }, { name: 'VP9 profile 0', contentType: 'video/webm; codecs="vp09.00.40.08"' }, { name: 'VP9 profile 2', contentType: 'video/webm; codecs="vp09.02.40.10"' }, { name: 'AV1 Main 10-bit', contentType: 'video/mp4; codecs="av01.0.08M.10"' },];const element = document.createElement('video');for (const candidate of candidates) { const result = { name: candidate.name, canPlayType: element.canPlayType(candidate.contentType), mse: globalThis.MediaSource?.isTypeSupported(candidate.contentType) ?? null, }; if (navigator.mediaCapabilities?.decodingInfo) { try { result.mediaCapabilities = await navigator.mediaCapabilities.decodingInfo({ type: 'file', video: { contentType: candidate.contentType, width: 1920, height: 1080, bitrate: 6_000_000, framerate: 30, }, }); } catch (error) { result.error = String(error); } } console.log(result);}canPlayType() returns an empty string, maybe or probably. Media Capabilities
adds supported, smooth and powerEfficient estimates. These can be unavailable, and they do not
certify an HDR display, a specific decoder, or every frame of a file. For MSE, query with
type: 'media-source' and your real configuration.
A WebCodecs check uses the same idea with an AV1 configuration:
if (globalThis.VideoDecoder?.isConfigSupported) { const result = await VideoDecoder.isConfigSupported({ codec: 'av01.0.08M.10', codedWidth: 1920, codedHeight: 1080, hardwareAcceleration: 'prefer-hardware', }); console.log(result);}prefer-hardware is a preference: a supported: true result can still mean software decoding. For AVC,
supply the AVC configuration data when your input needs it. The AVC registration
distinguishes AVC-format input from Annex B, and the AV1 registration
defines AV1 codec strings and chunk expectations. Handle unsupported configurations and decode errors
in code rather than choosing a codec from a user-agent string.
Hardware and device validation
Section titled “Hardware and device validation”Hardware encoding and decoding are separate capabilities. Check the GPU or SoC model, OS, driver, application backend, profile, depth, chroma, resolution and frame-rate limit. The vendor matrix lists encode and decode support per sample format, and a newer chip in a product family is not evidence for an older one.
For each rendition you deliver:
- Inspect the final file with
ffprobe -show_streams -show_format, and note the codec, profile, pixel format, dimensions, frame rate and color metadata. - Run a full decode with an independent software decoder to catch stream errors before device testing.
- Play the exact file on representative browsers and devices, including low-power and older supported targets. Check startup, seeking, audio sync, captions, adaptive switching and dropped frames.
- Compare SDR range and matrix, and HDR output, against a known-good source and display path. A picture on screen does not confirm color or tone mapping.
Keep a fallback rendition, and handle playback errors without breaking the page.
For preservation and editing codecs, keep the original or a lossless master, and encode delivery renditions separately. For AV2, ECM or custom codecs, use the matching decoder revision and state the research or deployment constraints of the output.