4

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?

  • 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 '16 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 '16 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 '16 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 '16 at 11:57
  • 1
    Link for 200k (see first option). For WebM b:v 0, see this page. – Gyan Oct 17 '16 at 12:33
1

Answer

Use two-pass Constant Quality mode:¹

ffmpeg  -i input.mp4  -b:v 0  -crf 30  -pass 1  -an -f webm /dev/null
ffmpeg  -i input.mp4  -b:v 0  -crf 30  -pass 2  output.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.


Footnote 1: If you're using Microsoft Windows instead of UNIX, change /dev/null to NULL.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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