Programster's Blog

Tutorials focusing on Linux, programming, and open-source

VP9 Encoding

Converting videos to VP9 is a fantastic solution for those that want to compress videos to save bandwidth/storage without losing perceptual quality, and be able to play those videos back in the browser (e.g. a video site like youtube). In learning to use VP9, I have had a lot of poor results along the way. With this codec, it really pays to look into the parameters and specify what you want for your use case.

Related Posts

Conversion Script

Below is the BASH script I use to encode my videos to VP9 webm after having installed ffmpeg through a PPA. I find that this script is a good balance between encoding speed and quality and I explain the parameters below it. It is a 2-pass encode targeting an overall bitrate.

#!/bin/bash
EXPECTED_NUM_ARGS=3;

if [ "$#" -ne $EXPECTED_NUM_ARGS ]; then
    echo "Expecting 3 arguments: [input filename] [output filename] [bitrate in K]"
    exit 1
fi

INPUT_FILE=$1
OUTPUT_FILE=$2
BITRATE=$3
BITRATE="`echo $BITRATE`K"

EXPECTED_NUM_ARGS=3;

if [ "$#" -ne $EXPECTED_NUM_ARGS ]; then
    echo "Illegal number of aguments"
fi

INPUT_FILE=$1
OUTPUT_FILE=$2
BITRATE=$3
BITRATE="`echo $BITRATE`K"
NUM_CORES=$(cat /proc/cpuinfo | grep processor | wc -l)

ffmpeg \
  -i $INPUT_FILE \
  -c:v libvpx-vp9 \
  -pass 1 \
  -b:v $BITRATE \
  -g 150 \
  -threads $NUM_CORES \
  -speed 4 \
  -tile-columns 4 \
  -frame-parallel 0 \
  -an -f webm /dev/null \
  && \
    ffmpeg \
    -i $INPUT_FILE \
    -c:v libvpx-vp9 \
    -pass 2 \
    -b:v $BITRATE \
    -g 150 \
    -threads $NUM_CORES \
    -speed 1 \
    -tile-columns 4 \
    -frame-parallel 0 \
    -auto-alt-ref 1 \
    -lag-in-frames 25 \
    -auto-alt-ref 1 \
    -c:a libopus \
    -b:a 128k \
    -f webm \
    $OUTPUT_FILE
  • -g 150 (or kf_max_dist)- There will be a maximum of 150 frames between keyframes. If you don't set this, it will be an absurdly high number 99999 and you will probably notice that when you seek around in a video will be slow.
  • -threads 4 - Multi-threaded encoding may be used if -threads > 1 and -tile-columns > 0.
  • -tile-columns 4 - using tile-columns slightly reduces quality. However it improves encoding and decoding speed by allowing multiple threads to be used. Most of my content has a 1920 pixel width so the maximum I can have is 4 with 4 threads.
  • -frame-parallel - Looks like this was once required for multithreading but no more so best to turn it off.
  • -cpu-used or -speed - sets how efficient the compression will be, trading faster encoding for a larger file size.
    • Generally good to use high speed for the first pass, and slow speed for the second pass.
    • For legacy reasons, -speed is an alias for -cpu-used.
  • Setting auto-alt-ref and lag-in-frames >= 12 will turn on VP9's alt-ref frames, a VP9 feature that enhances quality. More info here.
  • -row-mt 1 enables row-based multi-threading which maximizes CPU usage. Enabling row-mt is only faster when the CPU has more threads than the number of encoded tiles.

References

Last updated: 20th April 2024
First published: 16th August 2018

This blog is created by Stuart Page

I'm a freelance web developer and technology consultant based in Surrey, UK, with over 10 years experience in web development, DevOps, Linux Administration, and IT solutions.

Need support with your infrastructure or web services?

Get in touch