VP8 single pass conversion with good quality in ffmpeg

2

I am working at a raw to timelapse program, and I am using ffmpeg to generate a video out of a sequence of JPGs that my program outputs.

The user can select from different codecs, such as libx264, mjpeg, vp8, vp9.

I am having good results with h264 and mjpeg, but vp8 gives me some very bad quality videos, even though I set the quality pretty high, and the file size is comparable to h264 videos.

I am using the following settings:

ffmpeg.exe -framerate 12 -i "./output/img_%05d.jpg" -dst_range 1 -color_range 2 -c:v libvpx -b:v 0 -threads 8 -speed 2 -crf 8 "./output/video.webm"

You can see a sample video here: https://www.youtube.com/watch?v=eG2jxzR3Uxs (the encoding problems are mostly visible after 9 seconds).

Someone at Stack Overflow said that VP8 needs two passes, but this is unpractical. Is it any way to get good results in a single pass? Something comparable to h264 in terms of size/quality?

Radu

Posted 2017-12-26T21:59:49.453

Reputation: 123

-b:v 0? Seems you have set the bitrate to 0 for some reason... – Arete – 2017-12-26T22:18:04.813

That is needed to use -crf – Radu – 2017-12-26T22:23:33.833

Hmm, it seems the v:b 0 was for VP9 encoding. I'll run some tests with set rates. – Radu – 2017-12-26T22:30:37.207

You can also set quality with the -quality variable. Here is a great guide.

– Arete – 2017-12-26T22:31:57.230

Thank you, it seems that the b:v 0 was the problem. I assumed that, like vp9, it will automatically select whatever rate would match the best compression. Please post it as an answer, so I can mark it as solved. – Radu – 2017-12-26T23:22:08.863

2Someone at Stack Overflow, for context, is Ronald Bultje, who maintains the libvpx wrappers in ffmpeg. – Gyan – 2017-12-27T11:04:34.003

@Radu Can you link the thread or edit your question to include it? I would be interested in the 2-pass answer but I'm having trouble finding it. – glenneroo – 2018-06-29T23:30:29.340

Answers

0

Although the perceived quality is subjective you can adjust the overall quality using the -quality variable for example -quality good. The bitrate will impact the quality which you have set to 0, which I assume was just a mistake.

Arete

Posted 2017-12-26T21:59:49.453

Reputation: 830

Thanks again. As a side note, is there any way to get an acceptable quality without specifying the bit rate? – Radu – 2017-12-26T23:44:26.743

No problem. As far as I know you don't have to specify the bitrate at all. You can leave it out and let -quality do the job. – Arete – 2017-12-26T23:59:56.820

1-b:v 0 is the correct way for CRF encoding in VP8. VP8, by default, implements CRF as constrained quality i.e. it encodes a frame to maintain the specified quality and then compresses it further, if required, to keep it under the specified bitrate. When no bitrate is specified, vp8 inherits ffmpeg's default bitrate of 200 kbps. When some bitrate is specified, like 1M, VP8 will further compress the CRF encode to meet that target, if needed. If 0 is specified, it's "pure" CRF, like x264. – Gyan – 2017-12-27T09:49:01.170

-quality good is the default anyway; the only viable alternative here is -quality best, but then encoding will take forever. – slhck – 2017-12-27T10:30:27.957

Weirdly, I get lower PSNR (-0.5) and SSIM with best relative to both good and realtime. Size, though, is ~60% of good. – Gyan – 2017-12-27T12:17:17.520

-b:v 0 is for vp9, it's not specified in the vp8 guides, and it doesn't work. Setting it to 100M works much better, but there are other things that need to be set too, such as -qmin 0 -qmax 32 – Radu – 2017-12-28T00:25:19.877

The fallback maximum bitrate is 1000M which is set when -b:v is set to 0. – Gyan – 2017-12-28T04:53:06.587

@Radu Just because it's not in the guides doesn't mean libvpx doesn't work the same with VP8 and VP9… at least in principle :) (I rewrote the FFmpeg VP8 and VP9 guides a while ago but never cared to update VP8 when I improved the VP9 one, since it's rather a legacy format.) – slhck – 2017-12-28T08:38:45.493

Well, I am not trying to disagree with you, but setting -v:b to 0 is what got me those really bad frames, and a file size comparable to h264. – Radu – 2017-12-28T14:49:26.957

4

The only way to get good quality results in a single pass is to use a constant rate factor (CRF) mode. Please read the VP8 and VP9 guides for more info.

When setting -crf X, each frame is encoded with that target quality level X. However, an additional constraint is applied in the encoder, depending on the bitrate set by -b:v:

  • If -b:v 0 is used, the bitrate can vary freely depending on the source sequence and the set target quality. This is the option you want for a “normal CRF mode”, equivalent to -crf X with x264.

  • If -b:v is set to a positive bitrate, that constraint will be used as a maximum bitrate.

    For example, with VP8, using -crf 10 and -b:v 500K for a 1080p video will most certainly always reduce the bitrate to 500 kBit/s rather than letting the quality vary freely, making the output look rather bad, since 1080p video requires much more than 500 kBit/s. Setting -crf 10 -b:v 5M would make more sense for VP8. For VP9, you generally want lower bitrate values, since it is more efficient.

  • If -b:v is not set at all, ffmpeg will choose a default of 200 kBit/s, which will very likely lead to bad quality (unless you have a low resolution, easy to encode sequence). So, don't do this when using -crf.

You can verify the encoder settings by looking at the output produced by ffmpeg when run with the -loglevel debug setting.

In your specific case, I don't see anything wrong with the options, except maybe -speed 2. Setting this will disable some encoder features at the expense of rate control accuracy. Remove the option and see if that improves your quality.

Note that the -quality option is misleading; it's a legacy option now called -deadline (see ffmpeg -h encoder=libvpx for more info). The only viable settings for -quality are good or best (and realtime, but this is for live streaming). good is the default, so you don't have to explicitly specify it. best will result in very long encoding times.

slhck

Posted 2017-12-26T21:59:49.453

Reputation: 182 472

1After doing a lot of tests, I get the best results like so: ffmpeg.exe -framerate 12 -i "./output/img_%05d.jpg" -dst_range 1 -color_range 2 -c:v libvpx -qmin 0 -qmax 32 -bufsize 100M -quality good -cpu-used 0 -minrate 50M -maxrate 50M -b:v 50M -threads 8 -speed 1 "./output/vide o.webm". I have to set those two values too, or else the quality is not good enough even with a 100M bitrate: -qmin 0 -qmax 32 – Radu – 2017-12-28T00:23:18.877

@Radu Hm, that doesn't seem right, since setting -minrate, -b:v and -maxrate to the same value will essentially get you a constant bitrate encode, not a constant quality one (for constant quality you have to set CRF). Also, -cpu-used and -speed are the same option, so you're overwriting your own settings (choose either of those). The default is -qmax 63, so in essence you're limiting how efficient the encoder can be at compressing easy sources. But I have the feeling that your source in particular may screw up rate control. Have you tried this with other clips? – slhck – 2017-12-28T09:07:49.150

Well, my program is for timelapse videos, so I am not interested in other usage scenarios. My goal was trying to get similar results as with h264 (similar visual quality, and similar file size). I wish it were possible to just set the constant quality value and not worry about anything else, as is the case for h264. Not setting min/max rates too will give me smaller file size, but the quality isn't that good. – Radu – 2017-12-28T14:47:19.423