Where we are going, we don’t need no GIFs!
If your goal is to improve your website’s loading performance, then a GIF needs to be yanked! But then how do you have moving pictures? The answer is a video. And in most cases, you’ll get better quality as well as almost 50-90% size savings! In life, most things have a pro and a con. When you’re replacing a GIF with a video, in majority of the cases you’ll be hard pressed to find a con
Replace all the GIFs!
Fortunately, replacing GIFs with video has now been common for a few years so the tools needed to pull off this trick are already in play. In this blog, I’m not going to break new ground, but improve upon what already exists. So, here’s the lowdown on what you can currently do:
- Take a GIF and convert it into video
- Encode it with H.264 or VP9 codec i.e. compress it and package in a MP4 of WebM container
- Replace animated GIF
- Set the video to play automatically, sliently and in a loop to replicate the GIF functionality
It is 2019
It’s 2019. Tech moves forward and we need to move with it. Until now you’ve had two choices of codecs that are widely adopted across all browsers and platforms for encoding the video:
- H.264 – Introduced in 2003 and the most widely used codec today
- VP9 – Introduced in 2013 and achieves up to 50% more compression compared to H.264 most of the times but it can look worse sometimes according to this discussion on reddit.
NOTE: Even though H.265 is the next-gen version of H.264 and competes with VP9, I’m not including it in this comparison becuase of lack of browser support as noted on https://caniuse.com/#feat=hevc. Licensing costs is the major reason why H.265 is not as widely adopted as H.264 and why Alliance of Open Media consortium is working a royalty-free codec i.e. AV1.
Remember, our goal is to reduce the humongous GIF to as small a size as possible to improve our webpage loading time. It wouldn’t be 2019 if we didn’t have a new video compression standard we could encode to. This is called AV1. With AV1, we are able to achieve ~30% more compression compared to VP9. Exciting! :)
Serving you AV1 since 2019!
Recently, support for decoding AV1 video has been enabled in desktop versions of Google Chrome 70 and Mozilla Firefox 65. At present, support in Firefox is buggy and can cause crashes but is expected to improve with the adoption of the dav1d decoder in Firefox 67. For more info on the dav1d decoder and the latest release, see dav1d 0.3.0 release: even faster!.
For smartphones, the support is lacking at present but that’s to be expected due to the lack of hardware decoders. Without hardware decoders, the decoding can be done in software without any hiccups but it would cause an increase in battery consumption. The first set of mobile SOCs with hardware decoding support for AV1 are expected to come to market in 2020.
Target audience of this article AKA “If mobile users can’t decode, then why adopt AV1?”
AV1 is a fairly new codec and we’re at the beginning of it’s adoption curve. Think of this article as the build-it phase of “If you build it, they will come” approach. We know with desktop browser support, we can enable a subset of the market and reduce the amount of data downloaded. We an also employ a strategy where we can fallback to supported codecs on user devices if AV1 support is not enabled. When these users upgrade to devices with AV1 support, they will automatically get the smaller AV1 video. To enable this we’ll need to create a video tag like below which will allow us to serve the videos in this preference order - AV1->VP9->H.264. If a user has a really old browser or a device that cannot decode any of the videos (highly unlikely with H264 video inluded), then they would just get the GIF file 😞
<video style="display:block; margin: 0 auto;" autoplay loop muted playsinline poster="RollingCredits.jpg"> <source src="media/RollingCredits.av1.mp4" type="video/mp4"> <source src="media/RollingCredits.vp9.webm" type="video/webm"> <source src="media/RollingCredits.x264.mp4" type="video/mp4"> <img src="media/RollingCredits.gif"> </video>
The AV1 recipe
Creating an AV1 video is pretty simple. Download the latest build of ffmpeg for your platform from here and use the below commandline. We’re going to be using a 2-pass encoding mode to achieve a target bitrate. For this, we’ll run ffmpeg twice. In the first pass we’ll output to a null file descriptor, not an actual file. This generates a logfile that ffmpeg needs for the second pass.
# Linux or Mac ## Pass 1 ffmpeg -i input.mp4 -c:v libaom-av1 -b:v 200k -filter:v scale=720:-1 -strict experimental -cpu-used 1 -tile-columns 2 -row-mt 1 -threads 8 -pass 1 -f mp4 /dev/null && \ ## Pass 2 ffmpeg -i input.mp4 -pix_fmt yuv420p -movflags faststart -c:v libaom-av1 -b:v 200k -filter:v scale=720:-1 -strict experimental -cpu-used 1 -tile-columns 2 -row-mt 1 -threads 8 -pass 2 output.mp4 # Windows ## Pass 1 ffmpeg.exe -i input.mp4 -c:v libaom-av1 -b:v 200k -filter:v scale=720:-1 -strict experimental -cpu-used 1 -tile-columns 2 -row-mt 1 -threads 8 -pass 1 -f mp4 NUL && ^ ## Pass 2 ffmpeg.exe -i input.mp4 -pix_fmt yuv420p -movflags faststart -c:v libaom-av1 -b:v 200k -filter:v scale=720:-1 -strict experimental -cpu-used 1 -tile-columns 2 -row-mt 1 -threads 8 -pass 2 output.mp4
Here’s an explanation of what the command line options do
-i - Used to specify the input file -pix_fmt - Use to specify the 4:2:0 chroma subsampling for the color information in the video. There are many different pixel formats but 4:2:0 is the most compatible, hence we specify that here. -c:v - Used to specify the encoder to use i.e. AV1 in this case -b:v – Used to specify the average bitrate we want to achieve -filter:v scale - ffmpeg’s scale filter to reduce the resolution of the video. We specify this in the X:-1 format which tells ffmpeg to reduce the width of the video to X while and automatically set height that maintains the aspect ratio -strict experimental - Used because AV1 is a fairly new encoder -cpu-used - Horribly named parameter but this is way to select the level of quality we want to achieve. Valid values are 0-4. Lower values (i.e. closer to 0) mean more quality as well as more encoding time taken -tile-columns - Used to achieve multi-threading. Tells the AV1 encoder to split the scene into separate columns which can then be encoded independently of each other, thereby increasing CPU usage -row-mt – Similar concept as columns above but for rows within those columns -threads - # of threads the encoder can use -pass - Which pass the command executes -f - Only used in the first pass. Specifies the format of the output file in the second pass i.e. MP4 in this case -movflags faststart - Enables fast start of video by moving some data to the beginning of the file. This allows the video to be played before it is completely downloaded
For generating the GIF, I used the below command. To reduce the size of the GIF, I scaled the GIF to 720px wide and 12 fps instead of 24 fps source video.
./ffmpeg -i /mnt/c/Users/kasing/Desktop/ToS.mov -ss 00:08:08 -t 12 -filter_complex "[0:v] fps=12,scale=720:-1" -y scene2.gif
The proof is in the pudding, right? Let’s see why AV1 is the right codec for this choice of work. I took the open source video Tears of Steel available here https://mango.blender.org/ and encoded it to approximately similar bitrates for AV1, VP9, H.264 codecs. The resulting files are looping below so you can compare between them.
NOTE 1: If a file below doesn’t load for you, it’s possible you’ll need to update your browser. If your browser doesn’t work, I suggest using browsing in a Chromium based browser such as Chrome, Vivaldi, Brave or Opera. Here’s the latest on browser support for AV1 https://caniuse.com/#feat=av1
NOTE 2: For Firefox 66 on Linux, you’ll need to set the
media.av1.enabledflag to true in
NOTE 2: I’m not including the GIFs inline below due to their large size and amount of data it will take to load this page! (Also would be ironic as that’s what I’m to get us away from :)). But you can view the GIFs here https://github.com/singhkays/its-time-replace-gifs-with-av1-video/blob/master/GIFs
Scene 1 @ 200 Kbps
This is a high motion scene so it really stresses the encoders at low bitrates. We quickly see how bad H.264 is at this bitrate exhibiting extreme blockiness. VP9 improves things a bit but you can still notice some blockiness. AV1 clearly wins in this test rendering a clearly better image.
Scene 2 @ 200 Kbps
This scene shows off a lot of translucent CGI generated content. The results are a lot closer than the last scene but overall AV1 ends up being the best.
Scene 3 @ 100 Kbps
In this scene, we really dial down the bitrate to 100 Kbps and the results are no surprise. AV1 maintains it’s advantage at this low bitrate as well!
To really drive home the point of the amount of space savings compared to a GIF – The total size of all the videos embedded above is …. 1.62 MB!! That’s right. 1,708,032 freakin bytes! For comparison, here’s the GIF and AV1 video size for each of the scenes
|Scene 1||11.7 MB||0.33 MB|
|Scene 2||7.27 MB||0.18 MB|
|Scene 3||5.62 MB||0.088 MB|
Absolutely mind blowing! Isn’t it?
NOTE: I haven’t listed out the file sizes for VP9 and H264 because they are very similar to AV1 because of using the same bitrate for all codecs. Also, it would be redundant to add two more columns with similar sizes just to make the point that these codecs offer much better quality than GIF at highly reduced file sizes.
- Published v1
- Updated size of Scene 2 GIF to 7.27 MB. This was erroneously specified as 9.06 MB before.
- Added links to GIFs based on Hacker News comment
- Added info about why H.265 wasn’t included in this comparison
- Added a link to latest browser support for AV1
- Added more info on desktop vs browser compatibility
Reach out if you have any questions! Feel free to follow me on