A logo that says ‘OP&C’

FFmpeg incantations

Using FFmpeg magic to convert and process video and audio files on your computer.

FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video, and it’s used under the hood by large projects and software such as Youtube, VLC media player, Blender, and the Perserverance rover on Mars. (?!)

An incantation is a use of spells or verbal charms spoken or sung as a part of a ritual of magic; a written or recited formula of words designed to produce a particular effect.

Using magical spells and charms gathered from StackOverflow to (hopefully) produce the desired effect on my audio and video files is exactly how I use FFmpeg.

Sometimes it works, sometimes it doesn’t. It’s extremely mysterious.

Here are a few incantations I’ve found to be effective … usually.

In the spellbook

FLAC to MP3

Use case: you have music in FLAC format because you are a connoisseur, but you need MP3 versions to load into your iTunes library so you can transfer them to your iPhone to play while you’re out and about or whatever.

Converting to MP3 uses the libmp3lame library. If your FFmpeg install doesn’t include libmp3lame, you’ll need to install a version that does include it.

Check your install for the libmp3lame library by running ffmpeg on the command line and looking for --enable-libmp3lame in the output.

For Windows, the FFmpeg site recommends using builds from gyan.dev. The ffmpeg-release-essentials.zip under the Release Builds section includes libmp3lame.

FLAC to MP3 for a single file

ffmpeg -i input.flac -b:a 320k -map_metadata 0 -id3v2_version 3 output.mp3 -hide_banner

What’s happening there?

-i flags the input url or filename.
input would be the actual name of your file, and output is the name of the file once converted.
-b:a 320k sets the bitrate of the audio to 320kbps.
-map_metadata 0 keeps all the metadata from the input file.
-id3v2_version 3 uses ID3v2.3 tags for the metadata for best compatibility.
-hide_banner hides all the extra FFmpeg info that is usually output.

Or convert all the FLAC files in a folder using a Bash script

for f in *.flac; do ffmpeg -i "$f" -b:a 320k -map_metadata 0 -id3v2_version 3 "${f%.*}".mp3 -hide_banner; done

(I run Bash scripts in Git Bash, which came along with my Git-SCM install for Windows. It will be different if you’re using PowerShell or the Windows CMD prompt.)


Make an extremely compatible video

Use case: you’ve hooked up your Blu-Ray player to your network so you can play your videos on the TV instead of the computer, but your Blu-Ray player is old and doesn’t handle modern codecs or 5.1 surround sound audio or whatever just because.

ffmpeg -i input.mkv -c:v copy -c:a aac -q:a 2 -ac 2 -c:s dvd_subtitle output.mp4 -hide_banner

What’s that all about?

-c is short for codec, which is the name of a decoder or encoder.
-c:v picks the codec for the video stream.
-c:v copy makes a copy of the video stream instead of re-encoding it. (-c:v libx264 -crf 18 if you need to make sure it‘s going to use the H.264 codec)
-c:a picks the codec for the audio stream.
-c:a aac re-encodes the audio with the AAC codec.
-q:a 2 uses a variable bitrate for the AAC audio. (0.1 is low, 10 is high)
-ac 2 sets the number of audio channels to 2.
-c:s dvd_subtitle chooses the codec for the subtitles. (Sometimes this is mov_text instead)
.mp4 converts the file to MP4 format.
-hide_banner hides all the extra FFmpeg info that is usually output.

(My player likes AAC audio, doesn’t like 5.1 surround or multiple audio tracks.)

Doing this for your own old Blu-Ray player

  1. Find a file that does work with your old Blu-Ray player.
  2. Run ffmpeg -i input.mkv -hide_banner to get the details for that file, and use those details to figure out which codecs/etc are compatible.
  3. Type up an incantation that will convert your file to match.
Screenshot of ffmpeg -i command
An example output that shows video and audio codecs for an excellent kung-fu movie.

Converting all the video files in a folder with a Bash script

This code was used to convert a folder of HEVC-encoded files to H.264. (It took ages.)

for f in *.mkv; do ffmpeg -i "$f" -c:v libx264 -crf 18 -preset fast -vf format=yuv420p ./h264/"${f%.*}".mp4 -hide_banner; done

Save it as (for e.g.) convert.sh in the folder with the files to convert and run it from command line. The quotes around the "$f" parts allow for filenames that include spaces.


Remove an audio track from a video

Use case: your networked Blu-Ray player doesn’t always like multiple audio tracks.

Here’s how to make a version of a video that has the one audio track that you want.

Step 1: find out the references for the video and audio stream

ffmpeg -i input.mkv -hide_banner

This command will output stats for the input file, including something like this.

Screenshot - crop of ffmpeg -i that shows video and audio streams.

Here we can see the video stream is at Stream #0:0, with Chinese and English language audio tracks at Stream #0:1(zho) and Stream #0:2(eng). (Not pictured: Stream #0:4(eng) for the subtitles.)

Step 2: use -map to pick the streams to be kept

ffmpeg -i input.mkv -c:v copy -c:a aac -q:a 2 -ac 2 -map 0:0 -map 0:2 -map 0:4 -c:s dvd_subtitle output.mp4 -hide_banner

-map 0:0 and -map 0:2 and -map 0:4 select the streams to be kept in the output. (In this example, the video, the English audio, and the English subtitles are kept.)


Converting a recording into versions of different quality

Use case: you recorded a mixtape as a WAV file, and you want to make a 128kbps MP3 to share with your buddies because no one is going to listen to your mix if they have to download a 600 MB WAV file.

ffmpeg -i input.wav -b:a 128k -map_metadata 0 -id3v2_version 3 output.mp3 -hide_banner

-b:a 128k sets the bitrate of the audio to 128kbps.
-map_metadata 0 keeps all the metadata from the input file.
-id3v2_version 3 uses ID3v2.3 tags for the metadata for best compatibility.
-hide_banner hides all the extra FFmpeg info that is usually output.

Why not use Mixcloud or Soundcloud to share it? I do that, too. It’s good to have your own copies, though, in case Mixcloud or Soundcloud shut down, or turn evil, or get hacked, or get banned in your locality (Edit 2022/10: or limit you to ten mixes). (Also—pretty good bet that Mixcloud and Soundcloud use FFmpeg in the background, yes?)


Join separate audio files into one big file

Use case: you have a mix CD with multiple tracks where the audio all flows together, and you want to copy it on to your computer before the cat scratches up the CD, but your other media player on the computer (ahem, VLC) puts a gap between each track during playback and it just ruins the vibe, man.

Step 1: make a list of the files

In the folder where all the files are, make a file named list.txt (for example) that holds a list of all the separate audio files.

Example list.txt

file '01 Track 1.wav'
file '02 Track 2.wav'
file '03 Track 3.wav'
file '04 Track 4.wav'
file '05 Track 5.wav'

Use quotes around the file names if there are spaces. And even if there aren’t spaces. FFmpeg is a bit picky with this part.

Step 2: use that list to process the files into one big file

Run this command in the same folder as list.txt.

ffmpeg -f concat -safe 0 -i list.txt -c:a copy output.wav -hide_banner

-f concat is picking the Virtual concatenation script demuxer, which reads a list of files and other directives from a text file.
-safe 0 sets FFmpeg to accept unsafe file names in list.txt. An example of an unsafe file name is one that starts with a number, so yes, FFmpeg is a bit picky with this part. Use -safe 1 to reject unsafe file names. (More on that here)
-i list.txt is saying that the input files are those listed in list.txt.
-c:a copy is making a copy of the audio files instead of re-encoding them.
-hide_banner hides all the extra FFmpeg info that is usually output.

Notes

  1. Use dir *.flac > list.txt to make a list.txt with all the FLAC files listed in order, then edit each line to prepend the file and surround the file name with 's.
  2. Escape any 's in the file name with '\''. (See Filename quoting in ffmpeg concat on StackExchange)
  3. If your output file is FLAC format and the length of the file after concatenation is incorrect, try -c:a flac instead of -c:a copy. (See FFMPEG: flac audio file duration in metadata is 0 on StackOverflow)

Adding specific metadata to the big file

(Actual example)

ffmpeg -safe 0 -f concat -i ./list.txt -c:a flac -metadata album="The Prodigy Presents The Dirtchamber Sessions Vol.1" -metadata artist="Liam Howlett" -metadata date="1999" -id3v2_version 3 "Liam Howlett - The Prodigy Presents The Dirtchamber Sessions Vol.1.flac" -hide_banner

See a list of FFmpeg metadata options. (wiki.multimedia.cx)


Video stabilisation

Use case: stabilising a bumpy video?

I have been trying to make fancy time-lapse videos using a Raspberry Pi to control a DSLR. The initial videos were not that exciting, and they were also a bit bumpy.

The bumpiness can be mostly fixed with image stabilisation. I’m still working on making the videos exciting.

Step 1: analyse the video

ffmpeg -i input.mkv -vf vidstabdetect -f null -

Step 1 produces a transforms.trf file containing stabilisation data.

Step 2: use the analysis to process it

ffmpeg -i input.mkv -vf vidstabtransform output.mkv

Step 2 uses the data in transforms.trf to produce a stabilised video.

See a better explanation of the process in Video Stabilization With `ffmpeg` and `VidStab`. (paulirish.com)

Here’s a before-after comparison of one of my time-lapse videos.

No, not extremely exciting.

Producing different video formats for self-hosting videos

Video format support varies among browsers, so a web page can provide video in multiple formats. (Wikipedia quote)

Providing multiple formats gives a better chance of your self-hosted video working for your viewers.

Here’s how I did the formats for the video stabilisation demonstration above, making OGV, WEBM, and MP4 files from the original MOV.

(Updated 2024/06/25: changed the MP4 conversion for better compatibility with Safari/iOS)

# Output resized versions in ogv, webm, and mp4 format, with mp4 optimised for iOS/Safari (http://trac.ffmpeg.org/wiki/Encode/H.264)
# -vf "scale=640:-1" means "make it 640 pixels wide, keeping the same proportions"
# use -vf "scale=w=640:h=-2" if you're getting a "height not divisible by 2" error

ffmpeg -i Video-stabilisation-before-after.mp4 \
-vf "scale=640:-1" -c:v libtheora -q:v 7 -c:a libvorbis -q:a 5 Video-stabilisation-before-after_640.ogv \
-vf "scale=640:-1" -c:v libvpx-vp9 -b:v 1M -c:a libopus -b:a 128k Video-stabilisation-before-after_640.webm \
-vf "scale=640:-1" -c:v libx264 -profile:v high -level:v 4.1 -pix_fmt yuv420p -crf 18 -preset slow -c:a aac -b:a 128k -movflags +faststart Video-stabilisation-before-after_640.mp4

# Output the first frame of the video file to use as a poster for the video tag

ffmpeg -i Video-stabilisation-before-after.mp4 -vframes 1 -vf "scale=640:-1" Video-stabilisation-before-after_640_poster.jpg

The MP4 conversion has a few extras.

  • -profile:v high -level:v 4.1: set the H.264 profile to ‘high’ and the level to 4.1 (combatibility settings)
  • -movflags +faststart: allows the video to start playing before fully downloaded.

The HTML to embed in the page looks like this.

<video controls loop muted preload="auto" poster="https://files.opie-etc.com/assets/2022/08/Video-stabilisation-before-after_640_poster.jpg" width="640" height="214" title="Video stabilisation example">
	<source src="https://files.opie-etc.com/assets/2022/08/Video-stabilisation-before-after_640.mp4" type="video/mp4">
	<source src="https://files.opie-etc.com/assets/2022/08/Video-stabilisation-before-after_640.webm" type="video/webm">
	<source src="https://files.opie-etc.com/assets/2022/08/Video-stabilisation-before-after_640.ogv" type="video/ogg">
	<p>Your browser doesn’t support this video. <a href="https://files.opie-etc.com/assets/2022/08/Video-stabilisation-before-after_640.mp4">Download and watch offline</a>.</p>
</video>

References

FFmpeg reference

FFmpeg Documentation (ffmpeg.org)

FLAC to MP3

Convert .flac to .mp3 with ffmpeg, keeping all metadata (stackoverflow.com)

AAC encoding quality

Encode/AAC (trac.ffmpeg.org)

Joining separate files into one big file

Concatenating Videos Using FFmpeg (baeldung.com)

Safe file names (baeldung.com)

Video stabilisation

Video Stabilization With `ffmpeg` and `VidStab`. (paulirish.com)

Available options with vidstab filters (github.com/georgmartius)

Producing different video formats

A Brief Theora and Vorbis Encoding Guide (trac.ffmpeg.org)

Creating multiple outputs (trac.ffmpeg.org)

H.264 Video Encoding Guide (for the mp4 format, trac.ffmpeg.org)

Convert to WebM (gist.github.com/Vestride)

ffmpeg – Convert MP4 to WebM, poor results (stackoverflow.com)

Installation

I can’t remember how I installed FFmpeg on my main computer. It might have been bundled with an ImageMagick install. Anyway, it just worked.

For Windows, the FFmpeg site recommends using builds from gyan.dev.

I have FFmpeg working on a Raspberry Pi, and at some point I’ll tidy up and publish the notes I made on how much I enjoyed that installation process.