ffmpeg-cheatsheet icon indicating copy to clipboard operation
ffmpeg-cheatsheet copied to clipboard

Common operations with ffmpeg

ffmpeg-cheatsheet

Common operations with ffmpeg. For the love of me, I can never remember them off the top of my head... :sweat_smile:

Unless otherwise noted, these commands assume Windows + Powershell.

Check this guide by @nonoesp for other cool tricks. This guide is also good for advanced compression commands.

Check out my other ImageMagick cheatsheet too.

Extract frames from video

ffmpeg -i input.mp4 frames/frame_%05d.png

This will take an input video, and export all frames to a folder in the video's native fps. Please note that the folder must exist.

To extract a frame every n seconds:

ffmpeg -i input.mp4 -vf fps=1/n frame_%05d.png

Frames can be rescaled on the fly, and image quality controlled. This example will downsample to 1024 px width and scale the height proportionally, and set jpeg quality to best (2 best-32 worst range):

ffmpeg -i input.mp4 -vf scale=1024:-1 -qscale:v 2 frames/frame_%05d.jpg

Video from frames

ffmpeg -framerate 30 -i frame_%05d.png output.mp4

-framerate 30 sets the rate for the input stream.
frame_%05d.png assumes a filename with a suffix of 5 padded digits starting at 0. Otherwise, add starting number: ffmpeg -start_number 100 -i input.mp4 ...

To force a particular codec, use -vf format=:

ffmpeg -framerate 30 -i frame_%05d.png -vf format=yuv420p output.mp4

If setting a different fps, force ffmpeg to not drop frames by matching the input and output streams rates:

ffmpeg -framerate 15 -i frame_%05d.png -r 15 output.mp4

Frames can also be duplicated by setting faster output fps (IG won't let me publish videos at 5fps 😭😭):

ffmpeg -r 5 -i frame_%05d.png -r 30 -vf format=yuv420p output.mp4 

Alternatively, a video can be "accelerated" by purposedly dropping frames, setting different input and output streams rates. This example accelerates the video by x10, still creating it at 30fps:

ffmpeg -framerate 300 -i frame_%05d.png -r 30 output.mp4

GIF from frames with single palette

~This creates a lightweight, optimized GIF file with one palette. Useful when color is consistent across frames.~

ffmpeg -y -i frame_%05d.png -vf palettegen palette.png

~The above generates a palette file from the first frame of the sequence.~

~GIF can then be generated from files:~

ffmpeg -r 5 -y -i frame_%05d.png -i palette.png -filter_complex "paletteuse" animation.gif

~-r defines the fps rate for the GIF.~ ~-y auto-overwrites previous existing files.~

This creates a lightweight, optimized GIF file with one palette. Useful when color is consistent across frames. This version generates a palette by looking at all frames:

ffmpeg -r 5 -start_number 1005 -i frame_%05d.png -filter_complex "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" animation.gif

GIF from frames with multiple palettes

When color varies significantly across frames in the input, it is better to create one palette per frame; better quality GIF, heavier file:

ffmpeg -r 5 -i frame_%05d.png -filter_complex "[0:v] split [a][b];[a] palettegen=stats_mode=single [p];[b][p] paletteuse=new=1" animation.gif

Taken from this article.

GIF from video

Similarly to before, GIFs can be created directly from video.

ffmpeg -i input.mp4 -vf "fps=10,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif

See more options here.

Speeding video up

ffmpeg -i input.mp4 -an -filter:v "setpts=0.1*PTS" output.mp4

0.1 accelerates x10 by dropping frames, 0.01 would accelerate x100 and so on. -an removes audio.

New frames can be added using motion interpolation via minterpolate:

ffmpeg -i input_30fps.mp4 -filter:v minterpolate -r 60 outut_60fps.mp4

This can work too when creating a video from frames, but if they are not related, result is wonky:

ffmpeg -r 4 -i .\frame_%05d.png -filter:v minterpolate -r 30 output.mp4

Alternatively, Butterflow is also an option...

Extreme video compression

Sometimes, it is useful to compress a video to a very lossy output, like when editing very HQ files.

ffmpeg -i input.mp4 -c:v libx264 -crf 51 -preset veryslow -c:a copy -r 30 ouptut.mp4

This example sets quality to terrible (-crf from 0 best quality to 51 worst), and drops frames to 30fps. Remove the -preset to trade speed of a few extra bytes.

Lossless cropping/trimming

ffmpeg -i input.mp4 -ss 00:00:00 -to 01:30:15 -c:v copy -c:a copy output.mp4

Omit the -to parameter to trim till the end. Use -t parameter instead to specify duration (not end time). @RamyAydarous notes that this method doesn't start the trim from the previous keyframe, and therefore generates an initial static frame that extends into the next keyframe. Switch the order of -ss and -i parameters to force trim from previous keyframe (see here end of the page).

Changing video size

ffmpeg -i input.mp4 -vf scale=960:540 -c:v libx264 smaller.mp4

Taken from here.

Reversing video (and audio)

ffmpeg -i input.mp4 -vf reverse -af areverse reversed.mp4

Apparently, this buffers the entire clip, so for long ones, chop it, reverse them and concat.

Looping video

A video can be looped by "multiplying" the input stream:

ffmpeg -stream_loop 2 -i frame_%03d.png landscape_loop.mp4

The above will generate a video with the frames repeating 3 times (the regular one + -stream_loop 2).

You can create boomerang effect by applying reverse and loop filters:

ffmpeg -framerate 30 -i Frame_%05d.png -filter_complex "[0]reverse[r];[0][r]concat,loop=2:244,setpts=N/30/TB" output.mp4

Where 30 is the fps, and 2:224 is the number of extra loops:2 * frames per video.

Simpler 1-loop boomerang gif with palette:

ffmpeg -framerate 30 -i Frame_%05d.png -filter_complex "[0]reverse[r];[0][r]concat,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" boomerang_palette.gif

Resize/fit video to resolution

The following will scale up the video to fit 1920x1080, maintaining ratio and padding with a black background (source):

ffmpeg -i .\small_video.mp4 -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1" fullhd_video.mp4

Concat video: from the same source

Concattenating a list of videos from the same source (same format and codecs) can be done fast with the concat demuxer without needing to reencode them.

Concat all *.mp4 (same dimensions & codecs) into a single file (bash/sh):

ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy output.mp4

Alternatively, create a playlist.txt file with the names of the files to concat (PS):

foreach ($i in Get-ChildItem .\*.mp4) {echo "file '$i'" >> playlist.txt}

If using CMD:

(for %i in (*.mp4) do @echo file '%i') > playlist.txt

Files can now be stitched:

ffmpeg -f concat -i playlist.txt -c copy output.mp4

Concat video: from different sources

If videos come from different sources and/or have different formats/codecs, it is necessary to reencode them. For three files, it would look like this:

ffmpeg -i 01.mp4 -i 02.mp4 -i 03.mp4 -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mp4

Unfortunately, there is no way a playlist.txt file can be fed as input for longer lists; the whole call must be programmatically generated. Also, PowerShell has a 8191 char max limit...

~~This repo contains concat_generator a Processing sketch that points to a folder, and generates a concat.bat file with a bash call to concat all video files in that folder. Remember to change the allowed extensions in the Processing file.~~ See this repo for a video-concat helper.

Batch process a bunch of files in a folder

Say you want to reencode a bunch of mp4 files in a folder. Powershell doesn't take -pattern_type glob... So, a possible batch process could be this:

foreach ($i in Get-ChildItem .\*.mp4) {ffmpeg -i $i.Name $i.Name.Replace(".mp4","_lite.mp4")}

Takes al mp4 files in a folder, and reencodes them with a suffix. I know, this is hideous, but it works! :sweat_smile:

Creating a mosaic/montage/collage of images

For this one, use Imagemagick :)

magick montage *.png -geometry 224x224 -tile 27x14 montage.png

Creates a 27x14 collage with the stills. Margins can be added to the geometry parameter, as well as background and borders:

magick montage *.png -geometry 256x128>+10+5 -tile 12x10 -background white -border 1 -bordercolor lightgray montage.png

The > operator reduces images only bigger than 256x128.

Creating a mosaic/montage/collage of videos

The following code produces a 3x3 collage of videos at 1920x1080:

ffmpeg -i .\videos\01.mp4 -i .\videos\02.mp4 -i .\videos\03.mp4 -i .\videos\04.mp4 -i .\videos\05.mp4 -i .\videos\06.mp4 -i .\videos\07.mp4 -i .\videos\08.mp4 -i .\videos\09.mp4 -filter_complex " [0:v] setpts=PTS-STARTPTS, scale=640:320 [a0]; [1:v] setpts=PTS-STARTPTS, scale=640:320 [a1]; [2:v] setpts=PTS-STARTPTS, scale=640:320 [a2]; [3:v] setpts=PTS-STARTPTS, scale=640:320 [a3]; [4:v] setpts=PTS-STARTPTS, scale=640:320 [a4]; [5:v] setpts=PTS-STARTPTS, scale=640:320 [a5]; [6:v] setpts=PTS-STARTPTS, scale=640:320 [a6]; [7:v] setpts=PTS-STARTPTS, scale=640:320 [a7]; [8:v] setpts=PTS-STARTPTS, scale=640:320 [a8]; [a0][a1][a2][a3][a4][a5][a6][a7][a8]xstack=inputs=9:layout=0_0|w0_0|w0+w1_0|0_h0|w0_h0|w0+w1_h0|0_h0+h1|w0_h0+h1|w0+w1_h0+h1[out]" -map "[out]" -c:v libx264 -t '30' -f matroska mosaic.mp4

Yes, each video needs to be manually in the command. Things are easy to replace on a text editor though. From here.

Check properties of a video

This prints out the duration of a video in seconds, like 18.544322 (more):

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4

This prints out the framerate of a video, like 30/1:

ffprobe -v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=r_frame_rate input.mp4

The following prints out the timestamps for the keyframes of a video (source):

ffprobe -loglevel error -skip_frame nokey -select_streams v:0 -show_entries frame=pkt_pts_time -of csv=print_section=0 input.mp4

General metadata of a file can be exported to text:

ffmpeg -i input.mp4 -f ffmetadata metadata.txt

Dump all stream props to a json fil :

ffprobe -hide_banner -show_streams -of json .\video.mp4 > video_props.json

Replacing the sound track on a video

Or in other words, extracting the audio track of a video, removing it and adding a new one. Thanks @arastoo for the pointers!

First of all, and to avoid transcoding, you should check the audio file type that the video file contains:

ffprobe video.mp4

Once the file format is determined, extract sound the file without re-encoding:

ffmpeg -i video.mp4 -vn -acodec copy oldAudio.aac

Remove the audio file from the video:

ffmpeg -i video.mp4 -c copy -an videoNoSound.mp4

And now just add new audio to that file:

ffmpeg -i videoNoSound.mp4 -i newAudio.mp3 -c:v copy -c:a copy videoWithNewSound.mp4

This guide has lots of ffmpeg audio-related tips!

Increase audio volume

Volume can be amplified with a filter:

ffmpeg -i input.mkv -filter:a "volume=5.0dB" output.mkv;

However, on my end this is typically super slow and with a lot of dropped frames. This one works better:

ffmpeg -i input.mkv -b:a 160k -vol 1024 -vcodec copy output.mkv;

Although not sure what 1024 is measured in, and must be multiples of 256.

Alternatively, we can just extract the audio track as shown above:

ffmpeg -i input.mp4 audio.wav

Crank the voume up in an audio editor, and re-stitch without encoding the video:

ffmpeg -i input.mp4 -i audio_up.wav -b:a 160k -map 0:0 -map 1:0 -vcodec copy input_higher_vol.mp4

Add dummy silent audio to video

concat has given me problems when adding a video with no sound (like a timelapse). This adds a dummy silent track (taken from here):

ffmpeg -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100 -i input.mp4 -c:v copy -c:a aac -shortest output.mp4

Add watermark to the video

Piece of cake (more info):

ffmpeg -i test.mp4 -i watermark.png -filter_complex "overlay=10:10" test1.mp4

Batch converting a bunch of files

You can apply the same ffmpeg command to multiple files from cmd doing this:

for %i in (*.mkv) do ffmpeg -i "%i" "%~ni_converted.mp4"