To convert a WebM file to MP4 with ffmpeg, re-encode it: WebM holds VP8 or VP9 video and Vorbis or Opus audio, MP4 wants H.264 and AAC, so the streams have to be transcoded, not copied.
ffmpeg -i in.webm -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 192k -movflags +faststart out.mp4That is the whole job for most files. -crf 23 is the default quality, -preset medium balances speed against size, and -movflags +faststart moves the MP4 index to the front so the file starts playing before it has fully downloaded (worth it for anything you serve on the web). The rest of this page is the why behind that command, the one flag that fixes the "plays in ffmpeg but black in QuickTime" bug, and the reverse trip back to WebM.
You cannot stream-copy WebM into MP4
The first thing people try is the fast path, copying the streams without re-encoding:
# This will NOT work for WebM -> MP4
ffmpeg -i in.webm -c copy out.mp4-c copy (stream copy) is instant and lossless because it just lifts the existing video and audio streams into a new container. It works when the codecs already fit the target container, for example remuxing H.264-in-MKV to H.264-in-MP4. It does not work here. WebM's VP8/VP9 video and Vorbis/Opus audio are not valid in an MP4 container, so ffmpeg either errors with a muxer complaint or writes a file that no normal player will open. There is no shortcut: WebM to MP4 is a transcode, and a transcode takes time and loses a little quality. Budget for it.
The full WebM to MP4 command, flag by flag
ffmpeg -i in.webm -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -c:a aac -b:a 192k -movflags +faststart out.mp4-c:v libx264encodes the video as H.264, the codec every browser, phone, and TV understands. Use the modern-c:v, not the legacy-vcodecalias.-crf 23is the quality knob for libx264. Lower means better and bigger; the sane range is 18 to 28 and 23 is the default. Drop to 18 for near-visually-lossless, push to 26 to 28 when size matters more than fidelity.-preset mediumtrades encode speed for compression efficiency.slowandveryslowgive a smaller file at the same quality for more CPU time;fastandveryfastare the reverse.-pix_fmt yuv420pis the compatibility flag (see the next section).-c:a aac -b:a 192kre-encodes the audio to AAC at 192 kbps. Passing-b:ato ffmpeg's nativeaacencoder selects constant-bitrate mode, and the built-in encoder is fine for general use. Stereo AAC is effectively transparent from about 128k (roughly 64k per channel), so 192k leaves comfortable headroom; drop to 128k if you want a smaller file.-movflags +faststartrelocates themoovatom (the index) to the start of the file so it streams progressively instead of needing the whole download first.
Fix the QuickTime black screen: pix_fmt yuv420p
If your MP4 plays in VLC and ffmpeg's own player but shows a black screen (or refuses to open) in QuickTime, Safari, or an iPhone, the cause is almost always the pixel format. libx264 will happily encode to yuv444p or yuv422p when the source is in one of those formats, and Apple's decoders only reliably handle yuv420p 8-bit H.264. The fix is to force it:
ffmpeg -i in.webm -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -c:a aac -b:a 192k out.mp4I add -pix_fmt yuv420p to every MP4 I intend to share, even when the source is already 4:2:0, because it costs nothing and removes a whole category of "works on my machine" support tickets.
Convert MP4 to WebM (VP9 and Opus)
Going the other way also re-encodes, for the same codec-incompatibility reason. The modern WebM is VP9 video with Opus audio, not the old VP8 and Vorbis pairing:
ffmpeg -i in.mp4 -c:v libvpx-vp9 -crf 31 -b:v 0 -c:a libopus -b:a 128k out.webmThe detail that trips people up is -b:v 0. VP9's constant-quality mode only engages when you set the target bitrate to zero alongside -crf; leave -b:v out and ffmpeg runs in a constrained-quality mode that behaves differently. VP9's CRF scale is 0 to 63 (not libx264's 0 to 51), so the numbers do not transfer between encoders. Around 31 is a good general-purpose starting point; 15 to 35 covers most needs, lower being higher quality.
VP9 is slow to encode. If you can spare the wall-clock time, a two-pass encode produces a noticeably better file at a given size:
ffmpeg -i in.mp4 -c:v libvpx-vp9 -b:v 1M -pass 1 -an -f null /dev/null
ffmpeg -i in.mp4 -c:v libvpx-vp9 -b:v 1M -pass 2 -c:a libopus -b:a 128k out.webmYou will still see the old VP8 form in tutorials from a decade ago:
# Legacy VP8 + Vorbis (use VP9 + Opus instead unless you need ancient compatibility)
ffmpeg -i in.mp4 -c:v libvpx -crf 10 -b:v 1M -c:a libvorbis out.webmVP8 has a much smaller CRF scale (4 to 63, lower is better) and worse compression than VP9. There is rarely a reason to choose it in 2026; every browser that plays WebM at all plays VP9. AV1 (via libaom-av1 or the faster libsvtav1) is the next step up in compression if you have the encode time to spend, but it sits outside this WebM-versus-MP4 conversion question.
Which CRF for which encoder
The quality numbers are not interchangeable. A quick reference for the two encoders in play here:
| Encoder | Codec | CRF range | Sensible default | Bitrate flag |
|---|---|---|---|---|
libx264 | H.264 (MP4) | 0 to 51 (use 18 to 28) | 23 | omit, CRF drives it |
libvpx-vp9 | VP9 (WebM) | 0 to 63 (use 15 to 35) | 31 | -b:v 0 (required) |
Lower CRF is always higher quality and a larger file. The takeaway: do not copy a -crf 23 you used for H.264 onto a VP9 command and expect the same result, and never forget VP9's -b:v 0.
FAQ
See also
- The ffmpeg command cheat sheet: convert, crop, trim, and compress video from one reference page.
- Trim and cut a video with ffmpeg: the fast keyframe cut versus the frame-accurate re-encode, and where to put
-ss. - Convert images to WebP from the command line: the still-image side of WebM's codec family, with cwebp and gif2webp.
Sources
Authoritative references this article was fact-checked against.
- ffmpeg H.264 encoding guide (official wiki)trac.ffmpeg.org
- ffmpeg VP9 encoding guide (official wiki)trac.ffmpeg.org
- ffmpeg AAC encoding guide (official wiki)trac.ffmpeg.org
- VP9 encoding guide (WebM Project wiki)wiki.webmproject.org
- ffmpeg codecs documentation (native AAC encoder)ffmpeg.org





