(FFmpeg) How to use filter_complex without losing video quality?

This is one of the most asked questions on google about FFMPEG and for a good reason, by default automatic compression is added depending on the filter. This is usually done to perform the filter quicker as the higher the quality, the longer the command completion time. 

Compression can be avoided using recommended codecs and setting quality. It is recommended that the H.264 aka libx264 encoder is used with most video formats. Libx264 is used entirely throughout this book. This assumes that your FFMPEG installation is configured with –enable-libx264.

The H.264 codec can be set as seen in the example below:

 $ ffmpeg -i input.mp4 -c:v libx264 output.mp4 

Another useful command is setting the constant rate factor (-crf) a rate control mode. The setting for a lossless output is 0, the lower the number the higher the quality but larger the file size. The default value is 23 while 51 is the worst quality. According to the documentation, values between 17-28 are “virtually lossless” visually but technically not. 

$ ffmpeg -i input.mp4 -c:v libx264 -crf 18 output.mp4

In addition to the previous two, selecting a preset can also increase quality but will increase file size. Setting the preset will determine which encoding speed and compression ratio. The slower the preset the longer the computation time. The presets are as follows:

  • ultrafast 
  • superfast 
  • veryfast 
  • faster 
  • fast 
  • medium – default 
  • slow 
  • slower 
  • veryslow

For the highest video quality with all 3 settings are as follows:

 $ ffmpeg -i input.mp4 -c:v libx264 -crf 0 -preset veryslow output.mp4 

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

(FFmpeg) How to chain multiple filters ?

As you use FFMPEG one command might get the job done but at times applying multiple filters to a video is needed. It is possible to apply one filter at a time constantly referencing the last output file but ideally, chains are used to efficiently apply multiple filters.

There are two types of filter chaining in FFMPEG; Linear chains and distinct linear chains. Linear chains are separated by commas while distinct linear chains are separated by semicolons. 

Linear chains are filtering done on the input stream or virtual temporary streams but do not require an additional temporary stream before creating the output file. Below is an example of a linear chain horizontally flipping a video and then inverting the colors:

  $ ffmpeg -i input.mp4 -vf "hflip,negate" output.mp4  

Distinct linear chains use secondary inputs or create temporary streams before creating the final output. Below is an example of a distinct linear chain. The input.mp3, [main], will split into a temporary stream [tmp]. The [tmp] audio is reversed creating [new] and finally the two streams ([main] + [new]) will merge and output as a new file, output.mp3:

$ ffmpeg -i input.mp3 -filter_complex "asplit [main][tmp]; [tmp] areverse [new]; [main][new]amix=inputs=2[out]" -map "[out]" output.mp3 

Don’t worry if the above code looks intimidating, distinct linear chains are easy once the more you use them and get used to the syntax.

In addition to chaining, some filters may take a list of parameters which might look like chaining in itself. To distinguish between chaining and a parameter list the filter starts with the name followed by an equal sign and value then each additional parameter separated by a colon. As seen in the example below, adding 2 seconds to the end of an audio file:

$ ffmpeg -i input.mp3 -af "apad=packet_size=4096:pad_dur=2" output.mp3

Where apad is a padding audio filter with a packet size of 4096 and a pad duration of 2 seconds.

Note: It is important to use -af or -filter_compex when applying an audio filter. Using -vf (video filter) would output a new file but not apply the apad filter.

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

(FFmpeg) How to mix additional audio in an mp4?

Adding an additional audio source on top of the audio already in a video can be accomplished with the amix filter. This might be useful for adding background music to a commentary video as seen in the example below:

  $ ffmpeg -i input.mp4 -i input.mp3 -filter_complex "amix" -map 0:v -map 0:a -map 1:a output.mp4  

A common issue that comes up with amix is the volume of one input over powers the second, to solve this, setting the louder input volume down can resolve this. In the example below the volume of the first input audio [0:a] will be reduce 40%:

  $ ffmpeg -i input.mp4 -i input.mp3 -filter_complex [0:a]volume=0.40,amix -map 0:v -map 0:a -map 1:a -shortest output.mp4  

Now you have two audio streams playing in a single video. Quick and easy.

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

(FFmpeg) How to use filters (-vf/-af vs -filter_complex)?

Converting between one file format to another is extremely useful and might be all that’s needed for your use of FFMPEG but where the real fun begins is in the filters. Filters are used to manipulate audio and video with the libavfilter library.

A filter might result in a single change to an input file with a new output file or multiple changes to multiple output files or anything in between. Filters follow a sequential order as given by the command.

-vf / -af (video filter / audio filter) is used for simple filtergraphs (one input, one output), and -filter_complex is used for complex filtergraphs (one or more inputs, one or more outputs). Using -filter_complex will allow you omit the movie multimedia source filter and have a shorter command. 

Below is an example of reversing the video and audio of the input with both syntax types:

-vf / -af syntax 

  $ ffmpeg -i input.mp4 -vf reverse -af areverse output.mp4   

-filter_complex syntax

  $ ffmpeg -i input.mp4 -filter_complex "[0:v]reverse;[0:a]areverse" output.mp4  

-filter_complex doesn’t just apply to when chaining manipulation to video and audio. -filter_complex is used when multiple inputs are used or temporary streams are created.

Lastly FFMPEG does have streaming capabilities and filters can be applied and changed at runtime. FFMPEG documentation references these filters as supporting the variables as a command. An example of a filter command is as follows:

 $ ffmpeg -h filter=<name of filter> 

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

How to install FFmpeg on Linux?

On Ubuntu or Debian based linux operating systems using apt-get installed makes installation of FFMPEG is easy:

$ sudo apt-get update 
$ sudo apt-get install ffmpeg 

This will install the latest FFMPEG package but some linux users will want to install from source. FFMPEG requires compilation and installation of various codecs and libraries not bundled with FFMPEG source code.

Linux users who want to configure extra dependencies are required to install from source. Here’s an example of install dependencies, given from the FFMPEG wiki:

cd ~/ffmpeg_sources && \
wget -O ffmpeg-snapshot.tar.bz2 https://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2 && \
tar xjvf ffmpeg-snapshot.tar.bz2 && \
cd ffmpeg && \
PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig" ./configure \
  --prefix="$HOME/ffmpeg_build" \
  --pkg-config-flags="--static" \
  --extra-cflags="-I$HOME/ffmpeg_build/include" \
  --extra-ldflags="-L$HOME/ffmpeg_build/lib" \
  --extra-libs="-lpthread -lm" \
  --bindir="$HOME/bin" \
  --enable-gpl \
  --enable-libaom \
  --enable-libass \
  --enable-libfdk-aac \
  --enable-libfreetype \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libvorbis \
  --enable-libvpx \
  --enable-libx264 \
  --enable-libx265 \
  --enable-nonfree && \
PATH="$HOME/bin:$PATH" make && \
make install && \
hash -r

Source: https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

How to Install FFmpeg on MacOS?

Installation on MacOS is simple for users with homebrew installed. Homebrew is the package manager – users always wanted but yet to have natively. Think of it as an equivalent to apt-get on linux.  The installation command is as follows:

$ brew install ffmpeg  

As of March 25th, 2020, MacOS + homebrew install has disabled native dependencies support. If additional libraries are required for an FFMPEG build, installing all the extra configurations can be accomplished with this script:

brew uninstall --force --ignore-dependencies ffmpeg
brew install chromaprint amiaopensource/amiaos/decklinksdk
brew tap homebrew-ffmpeg/ffmpeg
brew install ffmpeg
brew upgrade homebrew-ffmpeg/ffmpeg/ffmpeg $(brew options homebrew-ffmpeg/ffmpeg/ffmpeg | grep -vE '\s' | grep -- '--with-' | grep -vi chromaprint | tr '\n' ' ')

Luckily, thanks to a discussion on github the current work around is the best we have.

Source discussion: https://gist.github.com/Piasy/b5dfd5c048eb69d1b91719988c0325d8

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

How to Check the Installed FFmpeg Version?

At this point FFMPEG should be installed on your operating system of choice and ready for use. To double check installation, it’s always good to view the current version installed. 

$ ffmpeg -version 

The output not only details the FFMPEG version but also the various configurations enabled and disabled as well as what codec are installed.

$ ffmpeg -version
ffmpeg version 4.2.2 Copyright (c) 2000-2019 the FFmpeg developers
built with Apple clang version 11.0.0 (clang-1100.0.33.17)
configuration: --prefix=/usr/local/Cellar/ffmpeg/4.2.2_2 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libmp3lame --enable-libopus --enable-librubberband --enable-libsnappy --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libflite --enable-libzvbi --enable-libopenjpeg --enable-librtmp --enable-libspeex --enable-libsoxr --enable-videotoolbox --disable-libjack --disable-indev=jack 
libavutil      56. 31.100 / 56. 31.100
libavcodec     58. 54.100 / 58. 54.100
libavformat    58. 29.100 / 58. 29.100
libavdevice    58.  8.100 / 58.  8.100
libavfilter     7. 57.100 /  7. 57.100
libavresample   4.  0.  0 /  4.  0.  0
libswscale      5.  5.100 /  5.  5.100
libswresample   3.  5.100 /  3.  5.100
libpostproc    55.  5.100 / 55.  5.100

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

How to Use FFmpeg in Ruby?

Command line one-liners are great for quick and one off FFMPEG experiences but sooner or later you’re going to want to start building custom applications for efficiency. FFMPEG can be used with almost any programming language with a couple of simple tricks. Some languages might even have libraries of their own to extend FFMPEG natively. Below are a few examples of various languages using FFMPEG:

Using Streamio to natively use FFMPEG in ruby, More information: https://github.com/streamio/streamio-ffmpeg

require 'streamio-ffmpeg'
input = FFMPEG::Movie.new("path/to/input.mov") 
output.transcode("movie.mp4") # Output to mp4 

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

How to check audio / video file information in FFmpeg?

Now that you understand the importance of knowing which codecs your file formats should conform to. It is useful to have the ability to check the input file format before using FFMPEG commands. Luckily this functionality is native to FFMPEG, the command is as follows:

$ ffmpeg -i input.mp3
ffmpeg version 4.2.2 Copyright (c) 2000-2019 the FFmpeg developers
  built with Apple clang version 11.0.0 (clang-1100.0.33.17)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.2.2_2 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libmp3lame --enable-libopus --enable-librubberband --enable-libsnappy --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librtmp --enable-libspeex --enable-libsoxr --enable-videotoolbox --disable-libjack --disable-indev=jack
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
Input #0, mp3, from 'input.mp3':
  Metadata:
    title           : 1989 MAZDA FAMILIA // Car
    artist          : テレビCM
    track           : 16
    album           : Visual Signals
    date            : 2020
    encoder         : Lavf58.29.100
  Duration: 00:00:16.58, start: 0.023021, bitrate: 128 kb/s
    Stream #0:0: Audio: mp3, 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc58.54
    Side data:
      replaygain: track gain - 13.100000, track peak - unknown, album gain - unknown, album peak - unknown, 
At least one output file must be specified

After the installed FFMPEG version and configuration information the Input section details information like metadata, duration, encoding and more. In the above example it can be noted that input.mp3 is indeed an mp3 with a Lavc/Lavf encoder which I guess is the standard encoding for Bandcamp downloads.

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon

How to Use FFmpeg in Bash script?

Command line one-liners are great for quick and one off FFmpeg experiences but sooner or later you’re going to want to start building custom applications for efficiency. FFmpeg can be used with almost any programming language with a couple of simple tricks. Some languages might even have libraries of their own to extend FFmpeg natively. Below are a few examples of various languages using FFmpeg:

In this example, File mp4tomp3.sh converts all mp4 files in a folder to mp3

for i in *.mp4; do
	OUTPUT=${i%.mp4}
	echo $OUTPUT
	ffmpeg -i "$i" $OUTPUT.mp3
done

Love FFmpeg? Grab a copy of FFmpeg For Beginners on Kindle or Paperback to learn over 120 ways to master FFmpeg!

buy now on amazon