Log in

View Full Version : Optimizing VP9 encoding for ultra low bitrate


Blue_MiSfit
28th October 2017, 02:38
Hey folks!!

I'm looking to optimize VP9 compression to target a very low bitrate scenario - specifically 150 Kbps average bitrate.

Resolution is flexible, but we're probably shooting for 428x240. The use case is offline playback, so pure unrestricted 2 pass VBR is probably ideal.

Thoughts, other than just using -quality best and -speed 0?

Some of the content will be animated, so anything similar to x264's --tune animation would probably be useful. I see some AQ modes listed in ffmpeg for libvpx-vp9, is there any consensus on those?

Thanks in advance!

Phanton_13
28th October 2017, 11:11
My recomenation:

Filter the video with a noise reduction filter ("nlmeans" in medium preset is a good option), this helps reduce the bitrate needs and as the birate is very low shoftening the video is a plus as it prevent blocking artifacs.

Use 10bit video in the encoding, it helps with banding and blockines in the dark regions specially at this low bitrate.

When downscalig select a algorithm good for downscaling and adecuate for the content, "bilinear", "area" and "sinc" are my prefered options.

Only the aq0 (none) aq1 (variance, based on the complexity variance in a frame) and aq2 (complexity, based on the computational cost) are somewhat recomendable, for me is better to use aq0 or aq1, and my preference is aq1, aq3 is for videoconferency but it can be useful for presentations, aq4 is a no.

This is an example of a batch in windows with my preferences:
@@:LOOP
"D:\media-autobuild_suite\local64\bin-video\ffmpeg.exe" -i %1 -map 0 -c copy -c:v libvpx-vp9 -pass 1 -passlogfile "%~dpn1.log" -b:v 150K -threads 1 -deadline good -cpu-used 4 -tile-columns 0 -frame-parallel 0 -auto-alt-ref 1 -lag-in-frames 24 -g 9600 -aq-mode 1 -sws_dither none -pix_fmt yuv420p10le -filter:v nlmeans=s=6:p=5:r=7,scale=w=428:h=240:force_original_aspect_ratio=decrease:sws_flags=area:sws_dither=none,crop=trunc(iw/2)*2:trunc(ih/2)*2:0:0 -an -f null NUL
"D:\media-autobuild_suite\local64\bin-video\ffmpeg.exe" -i %1 -map 0 -c copy -c:v libvpx-vp9 -pass 2 -passlogfile "%~dpn1.log" -b:v 150K -threads 1 -deadline good -cpu-used 1 -tile-columns 0 -frame-parallel 0 -auto-alt-ref 1 -lag-in-frames 24 -g 9600 -aq-mode 1 -sws_dither none -pix_fmt yuv420p10le -filter:v nlmeans=s=6:p=5:r=7,scale=w=428:h=240:force_original_aspect_ratio=decrease:sws_flags=area:sws_dither=none,crop=trunc(iw/2)*2:trunc(ih/2)*2:0:0 -c:a libopus -b:a 32k -ac 2 -f webm "%~dpn1.webm"
@shift
@if not (%1)==() goto LOOP
pause

-pix_fmt yuv420p10le send 10bit video to the encoder, this makes the encoder use profile2, but only if ffmpeg is compiled with 10bit support for vp9.

in the vp9 option "-threads 1" force the use only one thread and "ntile-columns 0 -frame-parallel 0" disable tiles and some frame parallelism witch boost quality at the cost of speed, also I use "-deadline good" because best don't guive actually better quality than good unles in very rare cases and sometimes the quality is also worse plus is much slower.

Also this script is dumb and only work with square pixel and don't crop the video. It encodes the audio in opus at 32kbps, if ffmpeg uses libopus 1.2.x the quality is going to me more than acceptable and you can test the audio at 24kbps to view it is acceptable for you.

Edit: batch change to make the video dimensions always mod2 after the scaling.

Blue_MiSfit
30th October 2017, 04:26
@Phanton_13

Thank you for the notes! Super helpful. I'll look into some testing here.

I've found that out of the box so far x264 gives more stable results in this use case, even if vp9 is more detailed in some scenes. When vp9 fails it seems to fail quite spectacularly, whereas x264 is quite consistent.

I'll try your recommendations out!

Phanton_13
30th October 2017, 08:43
vp9 even with my recomendation is going to fail miserably due to an inferior data rate management, the only option to somewhat mitigate this is to force the minimun quantizer to be <50, you can also try x265 10bit.

Phanton_13
1st November 2017, 16:32
I tested VP9 with two videos and found that limiting the max quantification can prevent VP9 to fail misserably but at the same time it penalizes the bitrate for 854x480 video up to 50% using -qmax 36 depending of various factors but more in the line of a max of 25% of the target bitrate, for 426x240 the penalization at -qmax 36 virtually don't exist in comparison with the target bitrate. And even at -qmax 48 de quality in comparison with when vp9 screws is much highter in the same part. Also I found that at 150kbps at a resolution of 854x480 is really workable and even cosidering that with the penalization of -qmax 36 the bitrate is bellow 200 Kbps in the samples the result is really good.

854x480 anime target 150kbps
-aq-mode 2 : 124 Kbps
-aq-mode 1 : 127 Kbps
-aq-mode 0 : 128 Kbps
-qmax 36 -aq-mode 0: 186 Kbps
-qmax 42 -aq-mode 0: 163 Kbps
-qmax 48 -aq-mode 0: 154 Kbps

426x240 anime target 150kbps
-qmax 36 -aq-mode 0: 146 Kbps
-qmax 42 -aq-mode 0: 137 Kbps

854x356 movie target 150kbps
-aq-mode 2 : 124 Kbps
-aq-mode 1 : 131 Kbps
-aq-mode 0 : 141 Kbps
-qmax 36 -aq-mode 0: 168 Kbps
-qmax 42 -aq-mode 0: 156 Kbps
-qmax 48 -aq-mode 0: 153 Kbps

428x178 movie target 150 Kbps
-qmax 36 -aq-mode 0: 153 Kbps
-qmax 42 -aq-mode 0: 145 Kbps

TD-Linux
3rd November 2017, 02:28
If you can at all manage, you should try one of the --end-usage=q --cq-level=x (ideally with two pass enabled, unlike x265, it does do something in "crf" mode). You'll avoid the crazy jumps in quality from frame to frame. Of course, you're no longer rate controlled, so this may be totally unviable for your application...