Encode Videos with FFmpeg

FFmpeg can be used to encode videos into difference formats. It can re-encode videos and join, merge or split videos at ones will. FFmpeg is a powerful tool compatible with major Operating Systems (Linux, Mac, Windows). FFmpeg has a lot of options/parameters and sometimes these can get quite convoluted, so we will go through the most common video tasks explaining in detail the options/parameters to be passed.

If you haven’t already installed FFmpeg, you can download and install it from here.


Some Basics concepts about a Video –

  • Codec: A codec is nothing but a way/method of encoding or decoding a video. Encoding is the process where the video data is compressed/encrypted for transmission or storage. Decoding is a process that reverses the encoding process for playback. The codec to be used is decided depending on factors like target file-size and target quality. Currently, h265 and vp9 are popular video codecs with great support.
  • Container: A container, (as the word suggests) is something that contains the components of a video together. These components would be the video itself, the audio track(or even multiple audio tracks), the subtitles if any, meta-data and so on. The container is represented by a file extension. Examples of some popular containers are OGG (.ogg), AVI (.avi), MPEG (.mpeg), Matroska (.mkv).

Encode Videos
Now that you have an idea of the basics of a Video file, lets go ahead and learn how we could encode video into a different format.


1. Encoding a Video from 1 format to another:

Copy Encoding/ Stream copy –

Lets say you wish to encode an AVI into a MP4 file.

ffmpeg -i inputFile.avi -c copy outputFile.mp4
/**
 * -i => Input file
 * -c => codec to use 
 */

Here, we passed the -c copy option which causes the original audio + video streams (with their codecs) to simply be copied. i.e. No real encoding takes place. (which is why this type of encoding will be very fast!) The only thing that changes is the container. The filesize of the output video remains the same as that of the input.

Note:

To see a small preview of how the output will look, you could pass a -t 30 option, which means that only the first 30 seconds of the input video will be processed. If you wish to specify a starting point for the preview, you can pass a -ss 10 option which in this case will generate a 30-second clip beginning from the 10th second.

ffmpeg -i inputFile.avi -c copy -t 30 outputFile.mp4
ffmpeg -i inputFile.avi -c copy -ss 10 -t 30 outputFile.mp4
/**
 * -i => Input file
 * -c => codec to use
 * -t => time duration in seconds
 * -ss => start time in seconds or HH:MM:SS
 */

Lossy Encoding –

Lets take the same example as above, i.e. we wish to encode an avi file into an mp4 file. But this time real encoding will take place.

ffmpeg -i inputFile.avi outputFile.mp4
/**
 * -i => Input file
 */

Executing the above command initiates the process of encoding. It could take certain amount of time to complete depending on your computers processing power. The output will be a video in the mp4 format. Just by changing the file extensions as needed, the same command can be used to convert a video from any format to any other format.

Since we did not specify any options when executing the command, the default options are used. The encoding process compresses the original video resulting in a lossy encoding. Sometimes the output video may not be what you wanted in terms of quality or file-size.
Lets see how we could have finer control over the file-size/video quality.

Adjusting the Bitrate –

Bit rate is the amount of information stored for each second of media that is played. The higher the bit rate, the lesser the compression, giving you a overall higher quality video but at the cost of a larger file size. Vice-versa holds true as well. Bitrate is usually expressed in kbps or mbps.

// results in a video with a small file-size and of lower quality
ffmpeg -i inputFile.avi -b:v 1500k -b:a 128k outputFile.mp4
/**
 * -i => Input file
 * -b:v => Bitrate of the Video codec. [in kbps(k) or mbps(m)]
 * -b:a => Bitrate of the Audio codec. [in kbps(k)]
 */

// results in a video with a larger file-size but of higher quality
ffmpeg -i inputFile.avi -b:v 7500k -b:a 320k outputFile.mp4
/**
 * -i => Input file
 * -b:v => Bitrate of the Video codec. [in kbps(k) or mbps(m)]
 * -b:a => Bitrate of the Audio codec. [in kbps(k)]
 */

Selecting a Codec –

You can also decide which audio/video codec you want to use. Choice of the codec depends on what the end result should be.
h265, vp9 are 2 popular and widely supported video codecs while aac and mp3 are 2 famous and fully supported audio codecs.

// use libx265 video and aac audio codec
ffmpeg -i inputFile.avi -c:v libx265 -c:a aac outputFile.mp4
ffmpeg -i inputFile.avi -c:v libx265 -c:a aac -b:v 7000k -b:a 320k outputFile.mp4      // with higher bitrates

// use vp9 video and mp3 audio codec
ffmpeg -i inputFile.avi -c:v vp9 -c:a libmp3lame outputFile.mp4
ffmpeg -i inputFile.avi -c:v vp9 -c:a libmp3lame -b:v 7000k -b:a 320k outputFile.mp4    // with higher bitrates

/**
 * -i => Input file
 * -c:v => Video codec to use. (alternatively, use option -vcodec)
 * -c:a => Audio codec to use. (alternatively, use option -acodec)
 * -b:v => Bitrate of the Video codec. [in kbps(k) or mbps(m)]
 * -b:a => Bitrate of the Audio codec. [in kbps(k)]
 */

Alternatively, with h264/h265 encoding, there is an option -crf(Constant Rate Factor) which can be changed to improve the visual quality of the video.
The lower the value, the better the visual quality.

ffmpeg -i inputFile.avi -c:v libx264 -c:a aac -crf 20 outputFile.mp4
/**
 * -i => Input file
 * -c:v => Video codec to use. (alternatively, use option -vcodec)
 * -c:a => Audio codec to use. (alternatively, use option -acodec)
 * -crf => Constant Rate Factor (lower value gives better quality)
 */

Lossless Encoding –

The commands for Lossless encoding vary depending upon the codecs used. For example, for h264/h265 encoding, you can set the -crf option to 0 to get a lossless encoding. And for Vp9, you can set the -lossless option to 1.

ffmpeg -i inputFile.mkv -c:v libx264 -preset ultrafast -crf 0 outputFile.mkv
ffmpeg -i inputFile.mkv -c:v libx265 -crf 0 outputFile.mkv

// For lossless VP9 encoding, 
ffmpeg -i input.mp4 -c:v vp9 -lossless 1 output.webm

/**
 * -i => Input file
 * -c:v => Video codec. You can also use the option -vcodec instead
 * -preset => Encoding speed to compression ratio. ultrafast/superfast/veryfast/faster/fast/medium/slow/slower/veryslow (defaults to medium)
 * -crf => Constant Rate Factor (lower value gives better quality, use 0 for lossless)
 */

2. Resize video resolution

With FFmpeg, you can easily resize/scale your video’s resolution to either have fixed dimensions or to have proportional dimensions(i.e. Resizing proportinally). To do this, provide only 1 of the dimension you wish to use (height/width) and set the other one to -1.

// resize to a fixed dimension/resolution
ffmpeg -i inputFile.avi -c:v vp8 -vf scale=640:360 -c:a libvorbis outputFile.mkv
// resize proportionally
ffmpeg -i inputFile.VOB -c:v libx265 -c:a aac -vf scale=1080:-1 outputFile.mkv
ffmpeg -i inputFile.VOB -c:v libx265 -c:a aac -vf scale=-1:1080 outputFile.mkv

/**
 * -i => Input file
 * -c:v => Video codec. You can also use the option -vcodec instead
 * -c:a => Audio codec. You can also use the option -acodec instead
 * -vf => filter
 */

It is recommended to resize proportionally as it ensures that there is no stretching of the video.

3. Join or merge 2 or more videos

To merge several videos together, use the following command:

ffmpeg -i "concat:file1.mpg|file2.mpg|file3.mpg" output.avi
ffmpeg -i "concat:file1.mpg|file2.mpg|file3.mpg" -c copy output.mpg

Note: Sometimes, this might not work as expected with certain formats (like MP4 files) when the files to be joined have been encoded differently or have a different resolution. In this case, you will be required to convert each input file into an intermediate format and then join those intermediate files together.

// convert each file
ffmpeg -i file1.mp4 -c copy -bsf:v h264_mp4toannexb temp1.ts
ffmpeg -i file2.mp4 -c copy -bsf:v h264_mp4toannexb temp2.ts
// Then join the intermediate files
ffmpeg -i "concat:temp1.ts|temp2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

/**
 * -i => Input file
 * -c => codecs (audio+video)
 * -bsf:v => Bitstream filter for video
 * -bsf:a => Bitstream filter for audio
 */

4. Split/Cut a video into multiple videos

You can split a video by using the -ss and -to options which accept the start time and the end time respectively. Using this you can split your video into as many smaller videos as you’d like.

// create a clip of ~2 minutes beginning from the 10th minute to the 12th minute
ffmpeg -i inputVideo.mp4 -ss 00:10:00 -to 00:12:00 outputClip.mp4
/**
 * -i => Input file
 * -c => codec (audio + video)
 * -ss => start time (in seconds or hh:mm:ss)
 * -to => end time (in seconds or hh:mm:ss)
 */

5. Extract Audio from a Video

You can easily extract the audio from a video by using the -vn option which tells FFmpeg to skip processing the video giving you an output that contains only the audio stream.

ffmpeg -i input.avi -vn output.mp3

// Using custom audio sampling frequency/audio channels/audio-bitrate, 
ffmpeg -i input.avi -vn -ar 44100 -ac 2 -b:a 192k output.aac 

// get audio with the highest possible quality
ffmpeg -i input.avi -vn -q:a 0 output.aac

// extracting audio from the 5th second to the 10th second
ffmpeg -i input_input.avi -ss 5 -to 10 -vn output.mp3

/**
 * -i => Input file
 * -vn => skip the video stream
 * -ar => Audio Sampling Frequency
 * -ac => Number of Audio Channels (2 => Stereo)
 * -b:a => bit-rate for the audio stream (in kbps/mbps)
 * -q:a => audio quality
 * -ss => start time (in seconds or hh:mm:ss)
 * -to => end time (in seconds or hh:mm:ss)
 */

You can also extract the original audio in a lossless way by only copying the original audio stream. Since no real encoding takes place, this process will be super-fast.

// Get the information about video
// (This reveals the audio codec used) 
ffmpeg -i input.avi
// If the audio codec is mp3,
ffmpeg -i input.avi -c:a copy output.mp3
// If the audio codec is aac,
ffmpeg -i input.flv -c:a copy output.aac
 
/**
 * -i => Input file
 * -c:a => Audio codec to use
 */

6. Add/Remove Audio from a Video

While adding audio, there are 2 possibilities depending on the expected end result.

A. Replace the original Audio

You can overwrite the original audio with a new audio as shown below. By default, the duration of the output will be that of the longer input. That means that if the audio is longer than the video, the video will freeze when it reaches its end whereas the audio will continue until it reaches the end of its duration, and vice-versa.

To avoid that, you could use either use the -shortest option which truncates the output to the same duration as the shortest input or use the -t 300 option which will truncate the output at the 300th second.

ffmpeg -i inputAudio.mp3 -i inputVideo.avi outputVideo.avi
ffmpeg -i inputAudio.mp3 -i inputVideo.avi -shortest outputVideo.avi
ffmpeg -i inputAudio.mp3 -i inputVideo.avi -t 300 outputVideo.avi
/**
 * -i => Input file
 * -shortest => Makes output to be the same duration as the shortest input
 * -t => time in seconds
 */

B. Add an additional Audio track

If you wish to conserve the original audio, and only add a new audio track, it can be done by mapping the audio streams.

ffmpeg -i input_video_with_audio.avi -i new_audio.ac3 -map 0 -map 1 -c copy outputVideo.avi
/**
 * -i => Input file
 * -c => Codec (both audio + video)
 * -map => maps the input files
 */

Here, -map 0 copies all streams(audio + video) from the first input file (input_video_with_audio.avi) and -map 1 copies all streams (in this case, one i.e. audio) from the second input file (new_audio.ac3). Hence the output video will now have 2 audio streams. During playback, the user can choose the audio track to listen. (Works with players that support it, like VLC player) By default, it uses the first audio track that was mapped. (-map 0, where 0 refers to the first input file)

Remove Audio

To strip the Audio, use the -an option which tells FFmpeg to exclude all audio streams from the input.

ffmpeg -i inputVideo.avi -c copy -an outputVideo.avi
/**
 * -i => Input file
 * -c => codec (audio + video)
 * -an => exclude audio streams
 */

7. Add/Remove/Extract Subtitles

You can add subtitles to a video file as a stream. (i.e. the subtitles are not burned into the video but are available as a separate stream) The subtitles can therefore be enabled/disabled at will by video players supporting it.

A. Adding Subtitles

We provide the input video and the input subtitle file and copy the all streams(audio, video and subtitles) using the -c copy option.
The -c:s mov_text option is the format of the subtitles used in the videos as they cannot be used directly in their original format (.srt in this case).
The input subtitles can be provided in any format (SRT, ASS, VTT, etc)

ffmpeg -i inputVideo.mp4 -i inputSubtitle.srt -c copy -c:s mov_text outputVideo.mp4
/**
 * -i => Input file
 * -c => Codec (both audio + video + subtitle)
 * -c:s => format of subtitle used in the video (mov_text)
 */

If you wish to burn the subtitles into the video, here’s a github gist that might help!

B. Removing Subtitles

Removing Subtitles from a video is quite simple to achieve. Use the -sn option which tells FFmpeg to exclude the subtitles while generating the output.

ffmpeg -i input.mkv -c copy -sn output.mkv
/**
 * -i => Input file
 * -c => Codec (both audio + video)
 * -sn => Exclude subtitles
 */

C. Extracting Subtitles

Sometimes you may want to retrieve the subtitles from a video in text format. Lets see how we can do that. (Note that you can extract subtitles from only those videos that have embedded subtitles.)

ffmpeg -i inputVideo.avi -txt_format text output.srt
/**
 * -i => Input file
 * -txt_format => format of the text
 */

8. Convert Audio from one format to another

Audio can be re-encoded from from its original format to another one by using the -vn option which tells FFmpeg to ignore the video stream if any. Encoding happens simply by using the desired format’s file extension.

ffmpeg -i input.wav -vn output.mp3
ffmpeg -i input.mp4 -vn output.ogg
ffmpeg -i input.flv -vn output.mp3
ffmpeg -i input.flac -vn -ar 44100 -ac 2 -b:a 192k output.aac
/**
 * -i => Input file
 * -vn => skip the video stream
 * -ar => Audio Sampling Frequency
 * -ac => Number of Audio Channels (2 => Stereo)
 * -b:a => bit-rate for the audio stream (in kbps/mbps)
 */

9. Convert Video to Images and Vice-versa

You can generate images from a video in the following formats:
PGM, PPM, PAM, PGMYUV, JPEG, GIF, PNG, TIFF, SGI.
The number of images generated depends on the Framerate of the video. 1 image per frame gets generated.
The following command will generate images named image1.jpg, image2.jpg, …

ffmpeg -i input.mpg image%d.jpg
/**
 * -i => Input file
 * %d => Regular expression to denote digits
 */

Similarly, you can convert a bunch of images into a video.

ffmpeg -i image%d.jpg output.avi
/**
 * -i => Input file
 * %d => Regular expression to denote digits
 */

10. Video Filters, Additional Pro Options

With FFmpeg, there are a ton of Video filters available like Vertical Flip, Zooming & Panning, sharpening or blurring a video, and so on.
We will see how we can deinterlace videos.

Deinterlace Videos

Deinterlacing is done generally on older videos or videos that had been used for broadcasting purposes to minimize the interlacing effect. Here’s an interesting YouTube video explaining what exactly is interlacing in contrast to today’s progressive videos.

ffmpeg -i input.mp4 -vf yadif output.mp4
/**
 * -i => Input file
 * -vf => Video Filter
 */

Yadif(“yet another deinterlacing filter”) is the name of the filter used.

Customize Chroma Subsampling

Chroma subsampling is the practice of encoding images by implementing less resolution for chroma information(i.e. color information) than for luma information(brightness information), taking advantage of the human visual system’s lower acuity for color differences than for luminance. Here’s an excellent YouTube resource explaining the same.

ffmpeg -i input.mp4 -vf format=yuv420p output.mp4
/**
 * -i => Input file
 * -vf => Video Filter
 */

The Pixel format is set to yuv420p which denotes 4:2:0 chroma subsampling.

Update Interval of Keyframes

What is a Keyframe? A Keyframe is a frame that defines the starting or the ending point of a transition.
You can update the keyframes interval to reach the GOP(Group of Pictures) size. The GOP size depends on the application and the delay. A higher frame rate has a higher GOP size.

ffmpeg -i input.mp4 -force_key_frames expr:gte(t\,n_forced/2) output.mp4
/**
 * -i => Input file
 * -force_key_frames => Expression to set the keyframes interval. 
 */

The expression expr:gte(t\,n_forced/2) is used to place keyframes every half a second.

Some more interesting info can be found in the references, feel free to go through them.
Hope it helps! 🙂


References: