ffmpeg Basics and Recipes

Recently I wrote about ffmpeg, a Swiss-army knife command-line utility for media. While I find it incredibly handy NOW, it took time to build up a working knowledge of the tool to handle certain tasks with confidence. The downside of having a versatile tool is that it can do an awful lot of things!

So let's break down how it works and I'll share some of my most common recipes for converting media.

Installing

The easiest way to install (on a Mac) is with homebrew:

brew install ffmpeg

You can also download directly from their site, but that's a tad more involved. Homebrew drops it into your path, ready to go.

Basics

An ffmpeg command will take:

  1. An input file,
  2. several sets of options,
  3. and an output file to spit everything out into.

A basic command will look something like:

ffmpeg -i input-file {lots of options here} output-file

Compression

One of the handiest things ffmpeg can do is give you fine-grained control over video compression. Not only can you pick the method of compression, you can choose what codec to use.

There are several methods of compression, but two of the main ones you'll see are:

Bitrates can get quite complicated but give you a lot of control. They're useful in situations for streaming videos or where you need to specify a minimum, maximum, or ensure a constant bitrate. Because I use ffmpeg to operate on smaller videos I gravitate towards -crf values.

Read more on how CRF works.

Convert to h264 mp4

If you need to share a video, you can't go wrong with an mp4. It's widely supported and everything except ancient devices should be able to play it. Here's a good default compression recipe:

ffmpeg -i input.mov -c:v libx264 -crf 28 -preset very slow output.mp4

Option descriptions:

One benefit of H264 compression is it's FAST and pretty efficient. I can usually get a .mov file down to about 10% of its size with this recipe.

Read more about H264 compression.

Convert to webm

webm is now fully supported in modern browsers but is a little more finicky to encode, it's quite easy to set some options and wind up with large webm files. I find webm's to be slightly larger than well-compressed mp4s.

ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 output.webm

They recommend that you use a two-pass method on webm for the best results, but it is QUITE slow, so grab a coffee while you wait:

ffmpeg -i input.mp4 -c:v libvpx-vp9 -b:v 0 -crf 30 -pass 1 -an -f null /dev/null && \
ffmpeg -i input.mp4 -c:v libvpx-vp9 -b:v 0 -crf 30 -pass 2 -c:a libopus output.webm

Read more on VP9 compression here.

Heads Up!

When you do a two-pass encoding, the first pass will LOOK like nothing is happening, just be patient, it will eventually start showing progress and spit out your file.

I'll also state that I haven't found much difference between the single pass and the double pass methods, but I also think I'm not operating at the size and length of video files to see the difference. If it's a smaller file, the single pass is probably good enough for your needs.

Common Recipes

Now we've talked about compression, what are some other things you can do? Here are a few of the tasks I find myself running.

Scale Video by Height

One of the easiest ways to shrink file size is to reduce the size of the video, especially if you've got a mondo-sized source file. To produce a 1080p video:

ffmpeg -i input.mp4 -vf scale=-1:1080 output.mp4

Note: Common resolutions for 16:9 video are: 1024Γ—576, 1152Γ—648, 1280Γ—720, 1366Γ—768, 1600Γ—900, 1920Γ—1080, 2560Γ—1440 and 3840Γ—2160. You can use these as some numbers to start with.

Trim Video by Timecode

Sometimes you only need a slice of a video, or you need to just shave off the first few seconds of something. Here's how you trim by timecode:

ffmpeg -i input.mp4 -ss 00:01:02.500 -t 00:01:03.250 -c copy output.mp4
ffmpeg -i input.mp4 -ss 00:00:03 output.mp4

Remove Audio

ffmpeg -i example.mp4 -c copy -an example-nosound.mp4

Boost Volume

Note that this can work on audio files, not just videos.

ffmpeg -i input.wav -af "volume=1.5" output.wav

Create a Poster Image

Embedding an HTML video and don't have a poster image? Rather than trying to awkwardly screengrab something, you can use this to create an image at a specific timestamp.

ffmpeg -i example.mp4 -ss 00:00:00.000 -vframes 1 'thumb.png'

Advanced Recipes

Here are some of the more complicated recipes I use that string together some of the operations I've already covered.

Create Ambient Video MP4

Need to load up a looping ambient video, but you're given a 200+MB file?

ffmpeg -i input.mp4 -c:v libx264 -crf 28 -preset veryslow -vf scale=-1:720 -movflags +faststart -an output.mp4

GIF to MP4

Want a GIF, but not with the filesize overhead?

ffmpeg -i animated.gif -movflags +faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" video.mp4

MP4 to GIF

Going the other way is a bit more involved because we need to take a full-color video and restrict it to 256 colors for a GIF. First, we'll need to generate a color palette from the video:

ffmpeg -i input.mp4 -y -ss 10 -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png

Then, using that palette, we'll convert the video into the best-fit gif.

ffmpeg -i input.mp4 -i palette.png -filter_complex "fps=10,scale=-1:480:flags=lanczos[x];[x][1:v]paletteuse" output.gif

Max Compatibility

I hardly use this recipe anymore since MOST devices can handle mp4's just fine. But just in case you need to get something running on an older device:

ffmpeg -i input.mp4 -c:v libx264 -crf 23 -profile:v baseline -level 3.0 -pix_fmt yuv420p -c:a aac -ac 2 -b:a 128k -movflags +faststart output.mp4

If you've come across other recipes, or you see a way how these could be improved, shoot me a note! I'm constantly improving and adding to this list.

Newsletter

Want to receive these thoughts and others in your inbox?

Discussion

Want to discuss this? Email Me