Converting MP4 to WebM

This post is over six (6) months old. Some things on this page my be out of date or no longer applicable.


I recently created a Bolt CMS extension that adds in HTML5 videos so I could use those in a Gif like animation, or regular videos. While doing this I wanted to use some "stockish" video files and some screen recordings.

I went about converting MP4 videos to Webm. I crashed Firefox for Android's browser on my Nexus Devices (Nexus 5 and 5X). That's no bueno. So I figured out it was the Webm profile that came from my screen recording software. It gave me a webm with a YUV444p profile.

Converting an MP4 to webm is a fairly straightforward process for video services like Cloudinary or gyfcat. Doing it yourself can be a different can o worms. FFmpeg's wiki and the webm project differ in their instructions on how to convert a video. After converting a few videos I wanted a centralized place with a conversion workflow that I knew worked. So here is pretty good process for converting a MP4 to a Webm with VP9, removing audio from files for webm or mp4 for gif like animations and trimming a videos length with FFmpeg.

Tools To Use / Install

There are two (2) tools we can use to optmize our videos. FFmpeg as mentioned above and Handbrake .

Handbrake will be used for our MP4 files since its extremely easy to use. You could also use FFmpeg for the MP4 files to reduce the work load between tools.

For these Examples I'm using a video from Archive.org  . Here are the details/properties of this unoptimized MP4 video.

  • 1920x1080 (1080p)
  • 1 Minute 25 Seconds in duration
  • 460 megabytes

With Handbrake I've optimized the MP4 with these settings

  • Web Optimized box checked
  • Profile: Normal
  • Quality: Constant @ 22
  • Variable Frame rate

This produces a 45 megabyte MP4

Handbrake Settings

To go over optimizing a video with Handbrake is outside the scope of this post. Luckily Matt Gadient has a post on getting the "best" settings for video optimization with handbrake. It's from 2013 but gives you a very good run down.

FFmpeg Installation

Here we'll go through on how to nstall FFmpeg on various OS'

FFmpeg on Linux

I'll be using Ubuntu for these Linux examples. FFmpeg on Ubuntu is a confusing hot mess. If you are on an Ubuntu distro >= 15.04 you can install "FFmpeg" like:

apt-get install ffmpeg

If you're on Ubuntu 14.04 - which many are since it's an LTS release, you'll have to do some hoop jumping.

  1. Download a Static build: Linux Builds
    • Doesn't Support Non Free Codecs
  2. Compile it: Compile FFmpeg Ubuntu
  3. Use a PPA: 14.04 LTS MultiMedia PPA: Doug McMahon

FFmpeg on a Mac

I'll preface this with - I don't use a Mac so use this at your own discretion. The easiest way to install FFmpeg on a Mac is through Homebrew and should more than likely be the one you choose to use.

$ brew install ffmpeg

For a full guide see FFmpeg's FFmpeg through Homebrew Guide.  

The second way to install FFmpeg is to use a static build  . Download the appropriate one for your system, extract the archive

Additionally you can compile it yourself from source: Compile FFmpeg - OSX  

FFmpeg on Windows

FFmpeg on Windows can be downloaded two ways. The "simple" way is to just download it and extract the archive.

  1. Visit FFmpeg Downloads   and download the appropriate one for your system.
  2. Extract it to your computer. Example - Extract to C:\ffmpeg
  3. If the path isn't automatically added to your path add the bin directory to your Environment Variable Path. Example: C:\ffmpeg\bin

With Ubuntu On Windows for Windows 10 you can also add the PPA mentioned above in the Ubuntu section. This too has all the hoop jumping as Ubuntu.

# add this PPA to your system
sudo add-apt-repository ppa:mc3man/trusty-media
sudo apt-get update
# now install ffmpeg
sudo apt-get install ffmpeg

Now if Ubuntu gets updated to 16.04 on Windows 10 before you update the distro you should purge this PPA to allow for a smooth upgrade.

# Remove this PPA to your system
sudo ppa-purge ppa:mc3man/trusty-media

Note: If you're on Windows and not using a shell replacement (babun, conemu, cygwin etc) you'll need to make a few changes to these commands that will be below.

  • Any Instance of \ ( a back slash ) will need to be replaced with ^ ( a caret )
  • Replace /dev/null with NUL
    • If you're using Bash On Ubuntu On Windows you can keep /dev/null

Converting MP4 To Webm with FFmpeg

Open a terminal / command prompt in the directory of your videos. From here we'll run our commands to convert the video. Webm will benefit from two (2) pass encoding. The first pass gathers data and statistics from the video, and the second will actually encode the video to a file with the data from the null file created in the first pass.

Audio included in a Webm file can be two formats, Vorbis or Opus. Since Microsoft Edge as of Edge 14 supports Webm with Opus audio (currently only in Media Source Extensions) you should use the Opus audio codec. FFmpeg's site's examples use the Vorbis codec so if you want wide Webm support use Opus.

Finding the right settings for good quality and small filesize is almost like fiddling with knobs on a radio. You just keep turning and tweaking until you get a good combination.

If you already know what conversion method you want to use and you're going to be using videos in a giflike animation you can skip down to the giflike animations section below to convert, scale and trim your videos all at once.

Best Quality

This is the "Best quality" FFmpeg commands as recommended by the Webm project. This can be very, and I repeat, VERY SLOW depending on your computer and the length of the video. This will give you the best quality but the file size might be even a little larger than your MP4. Only way you'll really know is if you do it so prepare to set aside some time if you wanna do this one :).

ffmpeg -i your-file.mp4 -c:v libvpx-vp9 -pass 1 -b:v 1000K -threads 1 -speed 4 \
-tile-columns 0 -frame-parallel 0 \
-g 9999 -aq-mode 0 -an -f webm /dev/null

# Once that finishes then run
ffmpeg -i your-file.mp4 -c:v libvpx-vp9 -pass 2 -b:v 1000K -threads 1 -speed 0 \
-tile-columns 0 -frame-parallel 0 -auto-alt-ref 1 -lag-in-frames 25 \
-g 9999 -aq-mode 0 -c:a libopus -b:a 64k -f webm your-file.webm
      

This gives us an ≈10.2 megabyte file.

Constant Quality

This is the "Constant Quality" settings. Here is where we can adjust the "constant rate factor". For VP9 videos this is a number from 0 to 63. The lower the value the better the quality. In the examples we have 33 for the constant rate factor. Adjust this to get bigger or smaller file size and adjust the quality.

# the "threads" flag recommendation is number of real cores - 1
ffmpeg -i our-file.mp4 -c:v libvpx-vp9 -pass 1 -b:v 0 -crf 33 -threads 8 -speed 4 \
-tile-columns 6 -frame-parallel 1 \
-an -f webm /dev/null

# once that finishes run
ffmpeg -i our-file.mp4 -c:v libvpx-vp9 -pass 2 -b:v 0 -crf 33 -threads 8 -speed 2 \
-tile-columns 6 -frame-parallel 1 -auto-alt-ref 1 -lag-in-frames 25 \
-c:a libopus -b:a 64k -f webm our-file.webm

If you're on an older machine or if this crashes you can run a single pass encode as shown below or remove the '-threads' option from the two pass encode.

ffmpeg -i our-file.mp4 -c:v libvpx-vp9 -crf 33 -b:v 0 -c:a libopus our-file..webm

The constant quality run gives us a webm that is ~19 megabytes. If you adjust the constant rate factor (crf) to 43 we are left with a ≈9 megabyte file with little to almost no difference in quality. You can see those two examples below

Constrained Quality

Constrained quality is useful for bulk encoding of videos where you want all videos to have a consistent quality or look. We can increase quality or decrease quality by adjusting the crf parameters along with the bitrate (-b:v parameter).

FFmpegs wiki suggests using of 1000k and a crf of 10. While The webm project suggests 1400k for the bitrate and 23 for the constant rate factor. You can drastically shrink your file by adjusting those down.

# the "threads" flag recommendation is number of real cores - 1
ffmpeg -i our-file.mp4  -c:v libvpx-vp9 -pass 1 -b:v 1400K -crf 23 -threads 8 -speed 4 \
-tile-columns 6 -frame-parallel 1 \
-an -f webm /dev/null

# once that finishes run
ffmpeg -i our-file.mp4 -c:v libvpx-vp9 -pass 2 -b:v 1400K -crf 23 -threads 8 -speed 2 \
-tile-columns 6 -frame-parallel 1 -auto-alt-ref 1 -lag-in-frames 25 \
-c:a libopus -b:a 64k -f webm our-file.webm

For my reference video I ran one with a bit rate of 1400k and a constant rate factor of 23 and this gave me a 15 megabyte file. Adjusting the bit rate to 800k produced a 9 megabyte file with little difference in perceptible quality.

Webm File Sizes After Conversion

Ok, you read all that but you just wanna know the file size difference. Here you go!

Webm File Size after Converting from MP4
Conversion Type Size in MB Link To Video
Unoptimized MP4 ≈461MB Unoptimized Video (it's BIG)  
Handbrake Optmized MP4 ≈44.7MB Optimized With Handbrake  
Best ≈10.2MB MP4 to Webm Best  
Constant w/43 crf ≈8.9MB MP4 to Webm Constant  
Constrained 800k bit rate ≈8.4MB MP4 to Webm Constrained  

Using Webm and MP4 as 'Gifs'. hard G :)

Our giflike videos won't need to be the full resolution (in this instance 1920x1800). This is a waste and if we scaled the video down we can achieve some pretty small file sizes. Most videos are longer than the animation you'll want so you would only want a portion of the video to be used for the animation. So I'll go over scaling the video to a smaller size and trimming the video length and removing the audio track if it's present since it wont be needed for animations.

Convert MP4 to Webm, Remove Audio & Trim Length

Once you've decided on which method to convert your video to webm you can add the video filter to your command to scale it, remove audio and trim the length. I've chosen the 'constant quality' method with a constant rate factor of 43 for this example.

Here is what has changed from the above 'constant quality' conversion methods to scale, trim and remove audio.

  1. add in the -vf flag for video filter with the scale option
  2. disable audio recording with the -an flag
  3. add in the start time I want to trim the video to with -ss flag and how much to capture after the start time with the -t flag.

You can find all the options you can use for scaling at ffmpeg's scaling wiki   and the options for trimming the video at ffmpeg's seeking wiki entry  .

# remove the '-threads' option if this crashes on you
ffmpeg -i our-file.mp4 -c:v libvpx-vp9 -pass 1 -b:v 0 -crf 43 -threads 8 -speed 4 \
-tile-columns 6 -frame-parallel 1 \
-an -f webm /dev/null

# once that finishes. trim the input video, scale it, and remove the audio
ffmpeg -ss 43 -i our-video.mp4 -t 5 -vf scale=800:-1 -c:v libvpx-vp9 -pass 2 -b:v 0 -crf 43 -speed 2 \
-tile-columns 6 -frame-parallel 1 -auto-alt-ref 1 -lag-in-frames 16 \
-an -f webm our-video-scaled.webm
      

Scaling, Removing Audio and Trimming already converted videos

To resize videos already in your prefered format(s)

ffmpeg -i input.webm -vf scale=640:-1 output-640.webm

If there is an audio track with the video you can remove it as follows:

ffmpeg -i input.webm -vcodec copy -an output-no-audio.webm

To trim the video that is already converted or in the format you want. The example below grabs the frames at 1 minute in and for 60 seconds after that.

ffmpeg -ss 00:01:00 -i video.webm -t 60 -c copy trimmed.webm

Comparing MP4/Webm to Gif File sizes

I'm by no means a "gif-scientist". So getting good framerates and qualtiy gifs for me a bit like magic. I just keep plugging in things from stackoverflow hoping I get a good quality gif. With that being said, I created a gif from our trimmed MP4 and used giflossy to make it "more-better".

Filesize Comparison of Gif, MP4 & WebM
File Type Type Size in MB Link To File
Unoptimized Gif ≈37.9MB Unoptimized Gif  
GifLossy Optmized Gif ≈23.0MB Optimized With giflossy  
Trimmed MP4 ≈457KB MP4 Trimmed, Resized and No Audio  
Best Trimmed Webm ≈597KB Best Webm Trimmed, Resized and No Audio  
Constant w/43 crf ≈182KB Constant Webm Trimmed, Resized and No Audio  
Constrained 800k bit rate ≈413KB Constrained Webm Trimmed, Resized and No Audio  

Visual comparison of the Optimized Gif, MP4 Video and Constant Quality WebM

Bonus! Gif, Animated Webp and Animated PNG

As an added bonus since I already had everything open I decided to convert the Gif to an animated Webp image and an Animated PNG. I've written on converting to an Animated Webp before and if you're comfortable on the command line its pretty easy to create an animated webp. Below is how I converted the Gif to an Animated Webp using Google's gif2webp  .

# -q is the quality range from 0 - 100
# -mixed uses mixed compression: from Google's docs:
# "optimize compression of the image by picking either lossy or lossless compression for each frame heuristically"
 gif2webp -q 70 -mixed squirrel.gif -o squirrel.mixed.webp

Animated PNG on the other hand is kinda tricky to create. At least find the tools to do so is tricky. Imagemagick doesn't support it currently. GIMP has a plugin for APNG   but I can't vouch for how good it is since I've never used it. The tools that I found seem to be... "old" or not updated in a while. I don't know if things have changed a lot in APNG so the "freshness" of the tools may not be an issue. These are the tools to convert to Animated PNG  .

For the Gif to Animated PNG conversion I used gif2apng from the above tools to convert APNG link. I also optimized the APNG with the apng optimizer but the file size actually ended up being bigger. Since I'm not familiar with APNG I don't know if I messed up something along the way.

So lets get on with it. Whats the file size difference if any all all these animated image formats?

Filesize Comparison of Gif, Animated PNG & Animated WebM
File Type Type Size in MB Link To File
Unoptimized Gif ≈37.9MB Unoptimized Gif  
GifLossy Optmized Gif ≈23.0MB Optimized With giflossy  
Animated PNG ≈29.47MB Animated PNG (using 7zip)   Animation only works in Firefox and Safari
Animated Webp ≈5.7MB Animated Webp (Mixed Compression)  Format only supported in Blink based browsers