Web Video Formats: MP4, WebM, AVI, MKV, MOV and the Codecs Inside Them
Video format confusion comes from mixing up containers and codecs. This guide untangles them, covers browser support, explains conversion, and shows how to edit video in the browser without uploading anything.
The single most important concept for understanding video formats: the file extension tells you the container, not the codec. They're different things.Containers vs Codecs
A container is the file wrapper. It holds the video stream, audio stream(s), subtitles, chapter markers, and metadata in one file. The container knows where each stream starts and how to keep them synchronized. Examples: MP4, MKV, AVI, MOV, WebM.
A codec is the compression algorithm that encoded the video data. The codec determines file size, quality, and whether the browser can decode it. Examples: H.264, H.265 (HEVC), VP9, AV1, MPEG-4.
A browser can refuse to play a video because of the container (MKV doesn't play in browsers), because of the codec (H.265 doesn't play in Chrome), or because of the audio codec (some older AAC variants). The error message rarely tells you which one it is.
Container Formats Explained
MP4 (.mp4, .m4v)
MP4 is the MPEG-4 Part 14 container, the standard for video distribution on the web, mobile devices, and streaming platforms. It's technically a subset of the QuickTime container Apple developed. MP4 supports H.264, H.265, AV1, and MPEG-4 video codecs, plus AAC and MP3 audio.
The important production flag is -movflags +faststart. By default, MP4 stores its index (the moov atom) at the end of the file. The browser has to download the entire file before it can start playing. Faststart moves the moov atom to the beginning so playback starts immediately during download.
WebM (.webm)
WebM was created by Google for open, royalty-free web video. It uses the Matroska container (below) restricted to VP8, VP9, or AV1 video with Vorbis or Opus audio. Chrome, Firefox, and Edge all support it natively. Safari added WebM support in 2022 but support is inconsistent across iOS versions.
VP9 in WebM is typically 30-50% smaller than H.264 in MP4 at the same visual quality. AV1 in WebM is another 30% smaller on top of that.
MKV (.mkv) — Matroska
MKV is an open container that can hold virtually any video codec, multiple audio tracks in different languages, multiple subtitle tracks, chapter markers, cover art, and arbitrary metadata. It's the container of choice for high-quality video rips and archiving. MKV does not play natively in any browser — it's for desktop playback with VLC, Plex, Kodi, etc.
If you have an MKV file that uses H.264, you can often just remux it to MP4 without re-encoding — it's fast (seconds, not minutes) and lossless. Only the container changes, not the video data.
AVI (.avi) — Audio Video Interleave
AVI is Microsoft's 1992 container format. It's still common because many older cameras, dashcams, and DVD rips produce it. AVI lacks modern features: no variable frame rates, poor support for H.264 (technically works but not the intended use), no proper support for modern audio codecs, and no streaming (the index is at the end).
AVI doesn't play in browsers. Convert it to MP4. If it contains an MPEG-4 or H.264 video stream, remuxing (without re-encoding) to MP4 is lossless and takes seconds.
MOV (.mov) — QuickTime Movie
MOV is Apple's QuickTime container. It's closely related to MP4 — technically, MPEG-4 was derived from QuickTime. MOV files from iPhones and Macs typically use H.264 or H.265 video with AAC audio. The H.264 ones usually play fine on macOS and Windows, but browsers (especially Chrome on Windows/Linux) often struggle with them, particularly iPhone recordings that use HEVC.
For web use, convert MOV to MP4. If the MOV uses H.264, remuxing (no re-encoding) is fine. If it uses H.265 (common on newer iPhones), re-encode to H.264 or VP9 for compatibility.
FLV (.flv) — Flash Video
Flash Video was the web video format from 2002 to 2017. YouTube started as an FLV site. Adobe Flash Player was killed at end of 2020. No modern browser plays FLV. Convert old FLV files to MP4 — they typically contain H.264 video and AAC audio that remux losslessly.
TS / MTS / M2TS (.ts, .mts, .m2ts)
MPEG Transport Streams are designed for broadcast television and Blu-ray. Many cameras (especially Sony and Panasonic) record to MTS/M2TS. These don't play in browsers. Convert to MP4 for web use.
Video Codecs: H.264, H.265, VP9, AV1
H.264 (AVC) — the safe default
H.264 (Advanced Video Coding, MPEG-4 Part 10) became the web standard because it offered far better quality than MPEG-2 and MPEG-4 at the time, and every device released since 2008 has hardware decode support. Encoding parameters that matter for web:
- Profile: High Profile for maximum compression, Baseline for older iOS/Android. Use High.
- Level: 4.0 or 4.1 for 1080p. 5.1 for 4K.
- CRF (Constant Rate Factor): 23 is the FFmpeg default. 18 is visually lossless. 28 is visibly lossy. For web, 22-26 is the sweet spot.
- Preset:
slowormediumfor web output.ultrafastfor quick previews.
# Encode for web — H.264, CRF 23, faststart
ffmpeg -i input.mov
-c:v libx264 -crf 23 -preset slow
-c:a aac -b:a 128k
-movflags +faststart
output.mp4Target a specific resolution
ffmpeg -i input.mov
-c:v libx264 -crf 23
-vf "scale=-2:720"
-c:a aac -b:a 128k
-movflags +faststart
output_720p.mp4
H.265 (HEVC) — better compression, poor web support
H.265 encodes video at roughly half the bitrate of H.264 for the same quality. An H.264 file at 5 Mbps looks similar to H.265 at 2.5 Mbps. The problem is patents. Chromium-based browsers and Firefox don't include H.265 decoders. Only Safari on Apple hardware supports it, because Apple has hardware decoders and pays the licensing fees.
Where H.265 makes sense: archiving, Apple-only workflows, and 4K content where file size is critical. For web distribution to general audiences, convert to H.264, VP9, or AV1 instead.
VP9 — royalty-free alternative to H.264
Google developed VP9 as an open alternative to H.264. Quality is roughly equivalent to H.265 at similar bitrates — 30-50% better than H.264. All major browsers support VP9 in WebM except Safari on older iOS (iOS 14.5 added support). YouTube uses VP9 as its default codec when serving to Chrome.
# Encode VP9 in WebM — two-pass is recommended for VP9
ffmpeg -i input.mp4
-c:v libvpx-vp9 -b:v 0 -crf 33
-pass 1 -an -f null /dev/null &&
ffmpeg -i input.mp4
-c:v libvpx-vp9 -b:v 0 -crf 33
-pass 2 -c:a libopus -b:a 128k
output.webmAV1 — the future of web video
AV1 is developed by the Alliance for Open Media, a coalition that includes Google, Apple, Microsoft, Netflix, Amazon, Meta, and Intel. It achieves 30-50% better compression than H.264 at the same quality, with full HDR support, and no patent royalties.
Browser support as of 2026:
| Browser | AV1 Decode | Hardware Decode |
|---|---|---|
| Chrome 70+ | Yes | GPU-dependent |
| Firefox 67+ | Yes | GPU-dependent |
| Edge 79+ | Yes | GPU-dependent |
| Safari 17+ (macOS/iOS) | Yes | Apple Silicon, A17+ |
| Samsung Internet 15+ | Yes | Newer Exynos/Snapdragon |
AV1 encoding is slow — even on powerful hardware, encoding time can be 10-20x longer than H.264. For production, use hardware encoders (NVIDIA NVENC AV1, Intel Arc, AMD AV1) or cloud encoding services. For smaller projects, the FFmpeg libsvtav1 encoder is much faster than libaom-av1:
# AV1 with SVT-AV1 (fast encoder)
ffmpeg -i input.mp4
-c:v libsvtav1 -crf 35 -preset 5
-c:a libopus -b:a 128k
output.webmAV1 with libaom (reference encoder, slow but best quality)
ffmpeg -i input.mp4
-c:v libaom-av1 -crf 30 -b:v 0
-cpu-used 4
-c:a libopus
output.webm
Audio codecs
| Codec | Container | Support | Notes |
|---|---|---|---|
| AAC | MP4, MOV | Universal | Standard for H.264 in MP4 |
| Opus | WebM, MKV | All browsers | Best quality/size ratio, ideal for WebM |
| MP3 | MP4, AVI | Universal | Legacy, AAC is better at same bitrate |
| Vorbis | WebM, Ogg | Most browsers | Legacy WebM audio, Opus is preferred |
| AC-3 / DTS | MKV, AVI | Desktop only | Surround sound, not for web |
Browser Support Table
| Format | Container | Video Codec | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|---|---|
| MP4/H.264 | .mp4 | H.264 + AAC | Yes | Yes | Yes | Yes |
| WebM/VP9 | .webm | VP9 + Opus | Yes | Yes | Yes* | Yes |
| WebM/AV1 | .webm | AV1 + Opus | Yes | Yes | Yes† | Yes |
| MP4/H.265 | .mp4 | H.265 + AAC | No | No | Yes | Partial |
| MKV | .mkv | Any | No | No | No | No |
| AVI | .avi | Any | No | No | No | No |
| FLV | .flv | H.264 | No | No | No | No |
* Safari on iOS 14.5+. † Safari 17+ on macOS Ventura+, iOS 17+.
HTML5 Video Code
Basic embed
<video controls width="1280" height="720">
<source src="video.mp4" type="video/mp4">
</video>Multiple sources with fallback
The browser picks the first source it supports. List the most efficient format first:
<video controls width="1280" height="720"
poster="thumbnail.jpg"
preload="metadata">
<source src="video.webm" type="video/webm; codecs=av01.0.05M.08">
<source src="video-vp9.webm" type="video/webm; codecs=vp9">
<source src="video.mp4" type="video/mp4">
<!-- Subtitles -->
<track kind="subtitles" src="en.vtt" srclang="en" label="English">
</video>Responsive full-width video
<!-- CSS -->
video {
width: 100%;
height: auto;
display: block;
}
<!-- Or Bootstrap -->
<video class="w-100" controls>
<source src="video.mp4" type="video/mp4">
</video>
Background video loop (muted for autoplay)
<video autoplay muted loop playsinline
style="width:100%; height:100%; object-fit:cover;">
<source src="background.webm" type="video/webm">
<source src="background.mp4" type="video/mp4">
</video>Checking codec support with JavaScript
const video = document.createElement('video');
function canPlay(type) {
const result = video.canPlayType(type);
return result === 'probably' || result === 'maybe';
}
const supportsAV1 = canPlay('video/webm; codecs="av01.0.05M.08"');
const supportsVP9 = canPlay('video/webm; codecs="vp9"');
const supportsH265 = canPlay('video/mp4; codecs="hev1.1.6.L93.B0"');
console.log({ supportsAV1, supportsVP9, supportsH265 });
All major browsers block autoplay for videos with audio since 2018. This is permanent browser policy, not a bug. It's there because autoplaying video with sound was universally hated by users.Autoplay Rules
| Scenario | Chrome | Firefox | Safari |
|---|---|---|---|
| Muted video autoplay | Allowed | Allowed | Allowed |
| Video with audio autoplay | Blocked | Blocked | Blocked |
| Autoplay after user gesture (click) | Allowed | Allowed | Allowed |
| Site added to homescreen (iOS) | N/A | N/A | Varies |
<!-- Correct: muted autoplay -->
<video autoplay muted loop playsinline>
<source src="video.mp4" type="video/mp4">
</video><!-- Let user unmute on click --> <div style="position:relative; display:inline-block;"> <video id="bgVideo" autoplay muted loop playsinline> <source src="video.mp4" type="video/mp4"> </video> <button id="soundBtn" style="position:absolute; bottom:10px; right:10px;" onclick="toggleMute()"> Unmute </button> </div>
<script> function toggleMute() { var video = document.getElementById('bgVideo'); var btn = document.getElementById('soundBtn'); video.muted = !video.muted; btn.textContent = video.muted ? 'Unmute' : 'Mute'; } </script>
The playsinline attribute is required for iOS. Without it, Safari opens the video in fullscreen instead of playing it inline in the page.
Converting Between Formats
Remuxing vs re-encoding
Remuxing changes the container without touching the video/audio data. It's fast (seconds), lossless, and the right approach when the codec is already compatible — for example, converting an H.264 MKV to MP4, or an H.264 MOV to MP4.
Re-encoding compresses the video again, which takes time and loses some quality (generational loss). Required when changing codecs or fixing issues in the video stream.
# Remux MKV to MP4 (lossless, fast, no quality loss)
ffmpeg -i input.mkv -c copy -movflags +faststart output.mp4Re-encode to H.264 (for incompatible codecs or quality improvement)
ffmpeg -i input.avi
-c:v libx264 -crf 23 -preset slow
-c:a aac -b:a 128k
-movflags +faststart
output.mp4
Convert HEVC/H.265 to H.264 for web compatibility
ffmpeg -i input_hevc.mp4
-c:v libx264 -crf 23
-c:a copy
-movflags +faststart
output_h264.mp4
Convert to WebM/VP9
ffmpeg -i input.mp4
-c:v libvpx-vp9 -b:v 0 -crf 33
-c:a libopus -b:a 128k
output.webm
Online conversion tools
For files up to a few hundred MB, browser-based tools process them entirely client-side:
- Video to MP4 — convert any format to web-compatible H.264
- Video to WebM — VP9 for smaller files in modern browsers
- MKV to MP4 — remux Matroska to MP4
- MOV to MP4 — convert QuickTime for web
- AVI to MP4 — convert legacy AVI files
- Video Compressor — reduce file size while maintaining quality
FFmpeg compiled to WebAssembly runs entirely in the browser. No uploads, no servers. It handles the same operations as command-line FFmpeg, just slower (typically 3-10x depending on operation and hardware).Browser-Based Editing with FFmpeg WASM
What FFmpeg WASM can do
- Trim video to a time range
- Cut segments and join them
- Change container format (remux)
- Re-encode with different codec settings
- Add, remove, or replace audio tracks
- Burn in subtitles
- Add a watermark
- Scale/resize video
- Extract frames as images
- Convert video to GIF
Basic FFmpeg WASM usage
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';
const ffmpeg = createFFmpeg({ log: true });
async function convertToMp4(videoFile) {
// Load FFmpeg WASM (downloads ~30 MB on first use)
await ffmpeg.load();
// Write input file to FFmpeg's virtual filesystem
ffmpeg.FS('writeFile', 'input.avi', await fetchFile(videoFile));
// Run FFmpeg command
await ffmpeg.run(
'-i', 'input.avi',
'-c:v', 'libx264',
'-crf', '23',
'-c:a', 'aac',
'-movflags', '+faststart',
'output.mp4'
);
// Read the output
const data = ffmpeg.FS('readFile', 'output.mp4');
// Create a download URL
const url = URL.createObjectURL(
new Blob([data.buffer], { type: 'video/mp4' })
);
return url;
}
// Track progress
ffmpeg.setProgress(({ ratio }) => {
console.log(Progress: ${Math.round(ratio * 100)}%);
});
Trimming a video
// Trim from 0:30 to 1:45 (75 seconds total)
await ffmpeg.run(
'-i', 'input.mp4',
'-ss', '00:00:30', // start time
'-t', '00:01:15', // duration
'-c', 'copy', // copy streams (fast, no re-encode)
'trimmed.mp4'
);
// Accurate trim (re-encodes to keyframe boundary)
await ffmpeg.run(
'-i', 'input.mp4',
'-ss', '00:00:30',
'-to', '00:01:45',
'-c:v', 'libx264',
'-c:a', 'aac',
'trimmed_accurate.mp4'
);
Performance considerations
FFmpeg WASM runs in a Web Worker to avoid blocking the main thread. Encoding speed depends heavily on the operation. Remuxing (stream copy) is fast. H.264 re-encoding at 1080p takes roughly 1-2x realtime on a modern laptop CPU — a 5-minute video takes 5-10 minutes to encode. VP9 is slower; AV1 is much slower.
For production video pipelines, use server-side FFmpeg. For user-facing tools where the "no upload" privacy angle matters, FFmpeg WASM is a good fit for files under ~500 MB.
ToolsDock video tools are built on FFmpeg WASM: Video Trimmer, Video Merger, Video Speed Changer, Video Rotate.
Compression Tips
CRF vs bitrate encoding
Fixed bitrate (CBR) wastes bits on simple scenes and runs out of bits on complex ones. CRF (Constant Rate Factor) allocates more bits where the content needs it. Use CRF for web video — you control quality, the encoder controls bitrate.
| CRF value (H.264) | Quality | Typical bitrate (1080p) |
|---|---|---|
| 18-20 | Visually lossless | 10-20 Mbps |
| 22-24 | High quality | 4-8 Mbps |
| 25-28 | Good (web standard) | 2-4 Mbps |
| 29-32 | Acceptable | 1-2 Mbps |
| 33+ | Visibly compressed | <1 Mbps |
Resolution matters more than bitrate
Downscaling from 4K to 1080p removes 75% of the pixels to encode and makes a much bigger difference than adjusting CRF. For typical web video where viewers watch on laptop/phone screens, 720p is often indistinguishable from 1080p and produces much smaller files.
Frame rate reduction
60 fps is roughly twice the data of 30 fps. Most web video doesn't benefit from 60 fps — it matters for action games and sports, not talking heads or screen recordings. Convert to 24 fps for cinematic content, 30 fps for general web video.
# Reduce frame rate to 30 fps
ffmpeg -i input.mp4 -r 30 -c:v libx264 -crf 23 -c:a copy output.mp4Scale to 720p and limit frame rate
ffmpeg -i input.mp4
-vf "scale=-2:720,fps=30"
-c:v libx264 -crf 24
-c:a aac -b:a 128k
-movflags +faststart
output_720p30.mp4
Audio settings
AAC at 128 kbps stereo is transparent (indistinguishable from uncompressed) for most content. 192 kbps for music. 96 kbps for voice. Don't encode at higher than the source bitrate — you're just wasting space.
Checking file details before converting
# What codec/resolution/bitrate is in this file?
ffprobe -v quiet -print_format json -show_streams input.mp4
Or just the important bits
ffprobe -v error -show_entries stream=codec_name,width,height,bit_rate
-of default=noprint_wrappers=1 input.mp4
Choosing the Right Format
| Use Case | Recommended Format | Notes |
|---|---|---|
| Web video (maximum compatibility) | MP4 + H.264 + AAC | Works on every browser and device |
| Web video (modern browsers) | WebM + VP9 + Opus, fallback to MP4 | 30-50% smaller than H.264 |
| Web video (cutting edge) | WebM + AV1 + Opus, fallback to MP4 | Best compression, needs fallback |
| Background video / hero loop | MP4 + H.264, muted + autoplay + loop | Keep under 5 MB for fast load |
| Social media (Instagram/TikTok) | MP4 + H.264, 9:16 vertical | Max bitrate varies by platform |
| YouTube | MP4 + H.264 or H.265 | YouTube re-encodes to VP9/AV1 anyway |
| Archiving / master files | MKV + H.265 (or lossless) | Best long-term storage format |
| Apple-only distribution | MP4 + H.265 | HLS for streaming on Apple devices |
| Screen recordings | MP4 + H.264 (lossless or CRF 18) | Text in video needs higher quality |
Recommended encoding settings for web
| Setting | Value | Reason |
|---|---|---|
| Container | MP4 | Universal browser support |
| Video codec | H.264 (High Profile) | Hardware decode on every device |
| CRF | 23-26 | Good quality-size balance |
| Preset | slow or medium | Better compression than fast |
| Audio codec | AAC stereo | Universal support |
| Audio bitrate | 128 kbps | Transparent for most content |
| Resolution | 720p or 1080p | 720p often sufficient for web |
| Frame rate | 24-30 fps | 60 fps rarely needed |
| Faststart | Enabled | Required for streaming playback |