Using AV1 video codec to reduce web page size

  • Gérald Barré

This post is part of the series 'Web Performance'. Be sure to check out the rest of the blog posts of the series!

Video represent a large part of the internet traffic. According to Cisco, it represents about 80% of the total traffic! So, reducing the size of video files can help to reduce the amount of data that is transferred over the internet, and it may reduce the hosting costs of your website.

AV1 is a next generation codec developed by the Alliance for Open Media (AOM). AV1 improves compression efficiency by ~30% over the previous state-of-the-art video codec, VP9, and by ~50% over x264.

AV1 is currently supported by Chrome, Firefox, Opera, and Edge, so about 75% of usages. Apple should support AV1 in the future.

As web supports progressive enhancement, you can provide multiple versions of the same video. This means you can provide an AV1 and a H.264 version of the same video to support all browsers. The browser will choose the best video for the user. So, there is no reason to not use AV1 today!

Can I use: MPEG-4/H.264 video format

Can I use: AV1 video format

#Encoding videos to AV1

You can use ffmpeg to convert video to AV1.

  1. Download ffmpeg: https://ffmpeg.org/download.html

  2. Convert the video to AV1:

    Shell
    # Adjust the crf value to change the quality and size of the video.
    # The valid CRF value range is 0-63, with the default being 50.
    # Lower values correspond to higher quality and greater file size.
    ffmpeg -i input.mp4 -c:v libsvtav1 -crf 50 -b:v 0 -c:a libopus -movflags faststart output.mp4

    You can better control the output size using a 2-pass encoding:

    Shell
    # Change -b:v 2M to change the bitrate and control the output size
    
    # Linux
    ffmpeg -i input.mp4 -c:v libsvtav1 -b:v 2M -pass 1 -an -f null /dev/null
    ffmpeg -i input.mp4 -c:v libsvtav1 -b:v 2M -pass 2 -c:a libopus -movflags faststart output.mp4
    
    # Windows
    ffmpeg -i input.mp4 -c:v libsvtav1 -b:v 2M -pass 1 -an -f null NUL
    ffmpeg -i input.mp4 -c:v libsvtav1 -b:v 2M -pass 2 -c:a libopus -movflags faststart output.mp4

The documentation of all available options for AV1 can be found at:

#Updating the <video> element

You now have 2 video files. One using the H264 codec and another one using the AV1 codec. You have to set both sources for the <video> element.

Both videos having the same mime type video/mp4, the browser is not able to choose the best video for the user. The solution is to set the codecs parameter of the mime type (e.g. video/mp4; codecs="av01.0.04M.08").

HTML
<video>
    <source src="./demo-av1.mp4" type="video/mp4; codecs='av01.0.04M.08'; profiles='isom,av01,iso2,mp41'">
    <source src="./demo-x264.mp4" type="video/mp4">
</video>

However, the codecs is not trivial to determine. The first part av01 is constant for AV1. The next parts depends of how the file is encoded (documentation). This means you may need a tool to get the right value for the codecs parameter.

##Finding the codecs parameter

To find the value of the codecs parameter, you can use the following website: https://gpac.github.io/mp4box.js/test/filereader.html:

Or you can use some nodejs code to get it:

Shell
npm install mp4box@0.5.2
index.mjs (JavaScript)
import { createFile } from 'mp4box';
import fs from 'fs';

const filePath = process.argv[2];
const content = await fs.promises.readFile(filePath);

let buffer = content.buffer;
buffer.fileStart = 0;

var mp4boxfile = createFile();
mp4boxfile.onError = e => console.error(e);
mp4boxfile.onReady = info => console.log(info.mime);
mp4boxfile.appendBuffer(buffer);
mp4boxfile.flush();

You can now call the application to get the mime type:

Shell
node index.mjs input.mp4

##Validating the browser use the AV1 video

You can check your browser is using the right source using the Dev Tools. The property currentSrc shows the source used by the browser:

#Microsoft Edge

It seems Microsoft Edge selects the av1 video. However, it cannot play it unless the AV1 Video Extension is installed. The resulting experience is bad, as most users won't see the video. A possible workaround is to detect Microsoft Edge and remove the av1 source.

JavaScript
(function () {
    for (let brand of navigator.userAgentData.brands) {
        if (brand.brand == "Microsoft Edge") {
            for (let element of document.querySelectorAll("video>source[type*='av01.']")) {
                let parentElement = element.parentElement;

                // Remove the <source> element
                element.remove();

                // force reload the video, so the browser loads the new sources
                parentElement.load();
            }
        }
    }
})();

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub