100% Private

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.

Containers vs Codecs

The single most important concept for understanding video formats: the file extension tells you the container, not the codec. They're different things.

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.

Quick fix: if your video won't play in a browser, convert to MP4 with H.264 video + AAC audio using Video to MP4 Converter.

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: slow or medium for web output. ultrafast for 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.mp4

Target 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.webm

AV1 — 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:

BrowserAV1 DecodeHardware Decode
Chrome 70+YesGPU-dependent
Firefox 67+YesGPU-dependent
Edge 79+YesGPU-dependent
Safari 17+ (macOS/iOS)YesApple Silicon, A17+
Samsung Internet 15+YesNewer 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.webm

AV1 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

CodecContainerSupportNotes
AACMP4, MOVUniversalStandard for H.264 in MP4
OpusWebM, MKVAll browsersBest quality/size ratio, ideal for WebM
MP3MP4, AVIUniversalLegacy, AAC is better at same bitrate
VorbisWebM, OggMost browsersLegacy WebM audio, Opus is preferred
AC-3 / DTSMKV, AVIDesktop onlySurround sound, not for web

Browser Support Table

FormatContainerVideo CodecChromeFirefoxSafariEdge
MP4/H.264.mp4H.264 + AACYesYesYesYes
WebM/VP9.webmVP9 + OpusYesYesYes*Yes
WebM/AV1.webmAV1 + OpusYesYesYes†Yes
MP4/H.265.mp4H.265 + AACNoNoYesPartial
MKV.mkvAnyNoNoNoNo
AVI.aviAnyNoNoNoNo
FLV.flvH.264NoNoNoNo

* 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 });

Autoplay Rules

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.

ScenarioChromeFirefoxSafari
Muted video autoplayAllowedAllowedAllowed
Video with audio autoplayBlockedBlockedBlocked
Autoplay after user gesture (click)AllowedAllowedAllowed
Site added to homescreen (iOS)N/AN/AVaries

<!-- 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.mp4

Re-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:

Browser-Based Editing with FFmpeg WASM

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).

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)QualityTypical bitrate (1080p)
18-20Visually lossless10-20 Mbps
22-24High quality4-8 Mbps
25-28Good (web standard)2-4 Mbps
29-32Acceptable1-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.mp4

Scale 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 CaseRecommended FormatNotes
Web video (maximum compatibility)MP4 + H.264 + AACWorks on every browser and device
Web video (modern browsers)WebM + VP9 + Opus, fallback to MP430-50% smaller than H.264
Web video (cutting edge)WebM + AV1 + Opus, fallback to MP4Best compression, needs fallback
Background video / hero loopMP4 + H.264, muted + autoplay + loopKeep under 5 MB for fast load
Social media (Instagram/TikTok)MP4 + H.264, 9:16 verticalMax bitrate varies by platform
YouTubeMP4 + H.264 or H.265YouTube re-encodes to VP9/AV1 anyway
Archiving / master filesMKV + H.265 (or lossless)Best long-term storage format
Apple-only distributionMP4 + H.265HLS for streaming on Apple devices
Screen recordingsMP4 + H.264 (lossless or CRF 18)Text in video needs higher quality

Recommended encoding settings for web

SettingValueReason
ContainerMP4Universal browser support
Video codecH.264 (High Profile)Hardware decode on every device
CRF23-26Good quality-size balance
Presetslow or mediumBetter compression than fast
Audio codecAAC stereoUniversal support
Audio bitrate128 kbpsTransparent for most content
Resolution720p or 1080p720p often sufficient for web
Frame rate24-30 fps60 fps rarely needed
FaststartEnabledRequired for streaming playback

All ToolsDock video tools process files locally in your browser using FFmpeg WASM. Nothing is uploaded to any server.

Privacy Notice: This site works entirely in your browser. We don't collect or store your data. Optional analytics help us improve the site. You can deny without affecting functionality.