The container and the codec are two different things. They get conflated because they travel together, but confusing them causes real problems when video breaks in ways you can't explain. An .mp4 file is not a codec. H.264 is a codec. The file is H.264-encoded video (and probably AAC-encoded audio) wrapped in the MPEG-4 Part 14 container. The container is the packaging. The codec is the compression algorithm for the data inside.
The container holds multiple streams — video, audio, subtitles, chapter markers, metadata — and gives a player the structure it needs to navigate and synchronize them. It records which codec encoded each stream, how the streams line up in time, where the keyframes are (so seeking works without decoding from the start), and whatever descriptive metadata the file carries. The container is a file format specification. The codec is an algorithm.
This distinction matters most when something doesn't play. Browser compatibility questions are almost always really two questions: does the browser support the container, and does it support the codec inside? A browser can parse an MP4 container without supporting every codec that can legally go inside one. When video plays in Chrome but fails in Firefox, or works on desktop but not iOS, the codec is usually where the problem is. MP4 and WebM have broad container support. What's inside determines whether a given decoder can handle it.
Three containers cover most web video. MP4 (formally MPEG-4 Part 14, sometimes called ISOBMFF for the ISO Base Media File Format spec it extends) is the format most video comes out of: cameras, phones, production tools. It can hold H.264, H.265/HEVC, AV1, and others. WebM is Google's open container, paired with VP8, VP9, or AV1 video and Vorbis or Opus audio, designed specifically for web delivery. HLS and DASH use a variant called fragmented MP4 (fMP4) — regular MP4 restructured so that each segment is independently decodable, without needing the file's initial metadata block (the "moov" atom) to be present before playback can start.
A standard MP4 file has its moov atom at the end by default — the encoder puts it there because it doesn't know the final file size until encoding finishes. For progressive download, you move it to the front with ffmpeg's -movflags +faststart, which lets the browser start playing before the full file arrives. That works fine for single-file delivery. For adaptive streaming with HLS or DASH, where the player is fetching separate two-to-six-second segments, it doesn't work at all — each segment needs to be independently decodable, with no dependency on a moov atom somewhere else in the file. Fragmented MP4 handles this by embedding the timing and offset information into each segment rather than collecting it centrally.
Codec licensing is where it gets complicated. H.264 is the most widely deployed video codec ever built, but it's covered by patents administered by the MPEG LA patent pool. Browser vendors have paid licensing fees to ship H.264 decoders, which is why it works everywhere. H.265/HEVC compresses better — roughly half the bitrate of H.264 at equivalent quality — but is messier legally, with multiple competing patent pools and higher per-unit royalties. Browser support is patchier as a result: Safari supports it, Chrome does on some platforms, Firefox doesn't ship a decoder by default. AV1 was produced by the Alliance for Open Media to give the industry a royalty-free path. Browser support is solid across Chrome, Firefox, Edge, and Safari on Apple Silicon.
The codec string in the type attribute is worth actually understanding rather than copying from Stack Overflow. For H.264, `avc1.42E01E` breaks down like this: avc1 is the codec identifier; 42 is the profile byte (0x42 = 66 decimal, the Constrained Baseline profile); E0 is a constraints byte; 1E is the level (0x1E = 30 decimal, meaning Level 3.0, which caps out at 720p/30fps). Serving 1080p requires at least Level 4.0 — `avc1.640028`. The browser checks these values before fetching anything. A device that can't handle Level 4.0 skips that source entirely rather than downloading it and choking partway through, which is the actual reason to be specific rather than just writing `video/mp4`.
For web delivery: H.264 in MP4 is still the safe baseline. Add VP9 or AV1 in WebM if you want better compression or want out of the licensing situation, with explicit type attributes on each <source> so the browser can decide without fetching. For adaptive streaming, fMP4 segments are the right call for both HLS and DASH — the MPEG-TS segments that older HLS used are mostly legacy at this point, and every player worth using handles fMP4.