31

What is the best way to convert a mp4 file to webm without quality loss (using vp8 or vp9) with ffmpeg?

If I do ffmpeg -i in.mp4 out.webm the quality is very bad. I can specify a target bitrate via -b:v and constant quality mode via crf, i.e.

ffmpeg -i in.mp4 -crf 10 -b:v 1M out.webm

This gives better quality. However for this I have to lookup the bitrate of the input video (here 1M).

I also noticed that if you specify a much larger value for the target bitrate than the bitrate of the input (here for example -b:v 100M), ffmpeg just seems to use approximately the bitrate from the input video with vp9 or slightly higher bitrate with vp8. However this solution doesn't seem to be the intended way to do this.

How would you choose the crf value and why?

Is there a parameter which automatically chooses the bitrate of the input file and a suitable crf value to get the same quality as the input file?

7
  • Set bitrate to 0. And experiment with crf. But your method of a high bitrate works too, since the value acts as a ceiling not a target
    – Gyan
    Oct 15, 2016 at 18:22
  • 1
    @Mulvya: Does bitrate 0 mean that there is no limit? I didn't find this in the man page.
    – student
    Oct 15, 2016 at 19:21
  • With bitrate not set to zero, CRF is constrained by that value. With zero, it's not. It's a quirk of the VPn encoders.
    – Gyan
    Oct 17, 2016 at 3:14
  • Ok, but if I omit the bitrate parameter completely the quality gets very bad even thoug I didn't give an upper limit for the bitrate.
    – student
    Oct 17, 2016 at 11:57
  • 1
    Link for 200k (see first option). For WebM b:v 0, see this page.
    – Gyan
    Oct 17, 2016 at 12:33

2 Answers 2

39

Answer

Use two-pass Constant Quality mode:

ffmpeg  -i input.mp4  -b:v 0  -crf 30  -pass 1  -an -f webm -y /dev/null
ffmpeg  -i input.mp4  -b:v 0  -crf 30  -pass 2  output.webm

Notes

  1. If you're using Microsoft Windows™ instead of UNIX, change /dev/null to NUL.

  2. We discard the video using /dev/null because the first pass's only purpose is to generate a log file of statistics.

mp42webm shell script

To save typing in the future, this can be put in a UNIX shell script:

#!/bin/sh -xe
ffmpeg -i "$1" -b:v 0 -crf 30 -pass 1 -an -f webm -y /dev/null
ffmpeg -i "$1" -b:v 0 -crf 30 -pass 2 "${1%.mp4}.webm"

Usage: mp42webm filename.mp4.
Creates filename.webm.

Explanation:

Setting the video bitrate to zero while also specifying the CRF (Constant Rate Factor) enables Constant Quality mode which targets a certain perceptual quality level. For VP9, the CRF can range from 0 (best quality) to 63 (smallest file size).

It is important to set the video bitrate to zero. If you do not specify a video bitrate, it defaults to something low which gets you Constrained Quality mode, where each frame has a maximum bitrate. While that can be useful for streaming, it reduces quality significantly as frames with a lot of motion will not have the bandwidth needed to look good.

Another part of the reason you’re losing quality is that webm (VP9) prefers to encode in two passes for best results. The first pass compiles statistics about the video which is then used in the second pass to make a smaller and higher quality video.

Please see the ffmpeg VP9 documentation if you’d like to learn more.

A word about transcoding

By the way, in general, transcoding formats (taking a compressed video and recompressing it with a different codec) is a bad idea as you’ll not only add the normal errors from lossy video encoding, but you’ll waste bits in the new format trying to preserve the artifacts from the old.

If you mean “without quality loss” literally

The -lossless 1 option of ffmpeg’s VP9 encoder enables lossless quality mode, but with a potentially enormous increase in filesize.

All you need is this:

ffmpeg  -i input.mp4  -lossless 1  output.webm

When I tried -lossless 1 on a low-quality mp4, the resulting webm was 100× larger, which was not accceptable to me. However, if your mp4 files are already very high quality, I expect the size difference will not be so great.

10
  • 1
    /dev/null? What does this mean? What would the equivalent be for windows users? Are you overwriting input.mp4 on the first pass? This answer needs more explanation on what exactly each component is doing. It doesn't offer intermediate users much explanation of how it works.
    – Hatefiend
    Feb 16, 2020 at 9:01
  • 2
    Hi Hatefriend: My answer already includes a long explanation section plus a link for more information, so I'd rather not make it longer. Did you see the footnote regarding Microsoft Windows which answers your specific question? Also, as mentioned above, the first pass compiles statistics about the input file. There is no need to fear that it might overwrite the input.
    – hackerb9
    Feb 20, 2020 at 4:09
  • I tried convert .MTS file to .webm usig these two commands (Ubuntu 20.10, ffmpeg version 4.2.2). But I have got errors: "Invalid channel layout 5.1(side) for specified mapping family -1. Error initializing output stream 0:1 -- Error while opening encoder for output stream #0:1 - maybe incorrect parameters such as bit_rate, rate, width or height" May 2, 2020 at 14:54
  • thanks for the answer. if transcoding is generally a bad idea, what do you recommend instead if you need to convert mp4 videos to webm and webm videos to mp4?
    – Crashalot
    Jan 9, 2021 at 9:43
  • Hmm. That didn't work. Second command failed: "Invalid channel layout 5.1(side) for specified mapping family -1. Error initializing output stream 0:1 -- Error while opening encoder for output stream #0:1 - maybe incorrect parameters such as bit_rate, rate, width or height"
    – Ken Ingram
    Feb 8, 2021 at 22:59
1

On Linux I use optimizeVideo, which is a wrapper around ffmpeg that automatically detects those settings according to Google's recommendations.

The result is a video which quality difference you cannot tell, but usually orders of magnitude smaller.

Logo

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.