Convert Mp4 to Webm

Nov 18th 2019

At the moment of creating this blog, I had the problem of having pretty heavy mp4 videos and I knew that webm files tend to be smaller and more streaming friendly. So I ended up making a script that converts an mp4 file to webm using the ffmpeg open-source command.

This is the following you have to do to make the conversion.

1.- Install ffmpeg-4

1.1.- Add repository

If you install ffmpeg with the default repositories you will install ffmpeg version 3. In my case I just installed the version 4 which worked like a charm. To install ffmpeg 4 you need to add a repository with this command:

1
$ sudo add-apt-repository ppa:jonathonf/ffmpeg-4

1.2.- Upgrade and update

Be sure you have the latest version of everything

1
$ sudo apt-get update && sudo apt-get upgrade

1.3.- Install ffmpeg

1
$ sudo apt-get install ffmpeg

And say yes to all.

At this moment if you check the ffmpeg version you installed. It should say ffmpeg version 4.x.x

1
2
3
$ ffmpeg -version
ffmpeg version 4.1.3-0york1~16.04 Copyright (c) 2000-2019 the FFmpeg developers
(... tons of verbose nonsense nobody understands or care...)

You have already ffmpeg installed. Cool!

2.- Use ffmpeg to convert mp4 to webm with a script

There are many ways to convert mp4 to webm format. The best quality converstion that worked for me was the two-pass enconding described here.

As you have to put input and output filenames multiple times plus many parameters and stuff, I just made a nodejs script that do that job for me.

2.1.- Create a convert.js

Create an empty file in the same directory you have the videos you want to convert. Name it convert.js and put this on it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const args = process.argv.slice(2);
let filename = args[0].split(".")[0];
console.log(`Converting ${filename}.mp4 to ${filename}.webm`);
console.log(`yes | ffmpeg -i ${filename}.mp4 -c:v libvpx-vp9 -b:v 2M -pass 1 -an -f webm /dev/null && ffmpeg -i ${filename}.mp4 -c:v libvpx-vp9 -b:v 2M -pass 2 -c:a libopus ${filename}.webm`)
async function convert() {
try{
const { stdout, stderr } = await exec(`yes | ffmpeg -i ${filename}.mp4 -c:v libvpx-vp9 -b:v 2M -pass 1 -an -f webm /dev/null && ffmpeg -i ${filename}.mp4 -c:v libvpx-vp9 -b:v 2M -pass 2 -c:a libopus ${filename}.webm`);
console.log('stdout:', stdout);
console.log('stderr:', stderr);
}catch (e){
console.log('stdout:', e.stdout);
console.log('stderr:', e.stderr);
}
}
convert();

2.2.- Convert and wait

The conversion script does not require any extra package which is awesome so we don’t need to install anything.
To run it you just need go to the directory you have the videos and run:

1
$ node convert.js filename.mp4

This will generate a filename.webm in the same directory.

As two-pass conversion is pretty slow (but generate awesome results) it will take some time so don’t worry if nothing happens for a while. Just wait.

Known bugs

I didn’t have too much time to make the script. I just needed something that does the job so is not a super strict-clean-perfect-correct script.

Please consider ths following limitations:

  1. It will not convert the file when the filename has spaces on it so rename your file if that happens.
  2. The script prints nothing until the hole webm file has been made so be patient and don’t worry.

Feel free to fix anything you want. Here is the gist.