Skip to content

Instantly share code, notes, and snippets.

@steven2358
Last active December 2, 2024 01:24
Show Gist options
  • Save steven2358/ba153c642fe2bb1e47485962df07c730 to your computer and use it in GitHub Desktop.
Save steven2358/ba153c642fe2bb1e47485962df07c730 to your computer and use it in GitHub Desktop.
FFmpeg cheat sheet

FFmpeg cheat sheet

A list of useful commands for the FFmpeg command line tool.

Download FFmpeg: https://www.ffmpeg.org/download.html

Full documentation: https://www.ffmpeg.org/ffmpeg.html

Basic conversion

ffmpeg -i in.mp4 out.avi

Remux an MKV file into MP4

ffmpeg -i in.mkv -c:v copy -c:a copy out.mp4

High-quality encoding

Use the crf (Constant Rate Factor) parameter to control the output quality. The lower crf, the higher the quality (range: 0-51). The default value is 23, and visually lossless compression corresponds to -crf 18. Use the preset parameter to control the speed of the compression process. Additional info: https://trac.ffmpeg.org/wiki/Encode/H.264

ffmpeg -i in.mp4 -preset slower -crf 18 out.mp4

Trimming

Without re-encoding:

ffmpeg -ss [start] -i in.mp4 -t [duration] -c copy out.mp4
  • -ss specifies the start time, e.g. 00:01:23.000 or 83 (in seconds)
  • -t specifies the duration of the clip (same format).
  • Recent ffmpeg also has a flag to supply the end time with -to.
  • -c copy copies the first video, audio, and subtitle bitstream from the input to the output file without re-encoding them. This won't harm the quality and make the command run within seconds.

With re-encoding:

If you leave out the -c copy option, ffmpeg will automatically re-encode the output video and audio according to the format you chose. For high quality video and audio, read the x264 Encoding Guide and the AAC Encoding Guide, respectively.

For example:

ffmpeg -ss [start] -i in.mp4 -t [duration] -c:v libx264 -c:a aac -strict experimental -b:a 128k out.mp4

Mux video and audio from another video

To copy the video from in0.mp4 and audio from in1.mp4:

ffmpeg -i in0.mp4 -i in1.mp4 -c copy -map 0:0 -map 1:1 -shortest out.mp4

Concat demuxer

First, make a text file.

file 'in1.mp4'
file 'in2.mp4'
file 'in3.mp4'
file 'in4.mp4'

Then, run ffmpeg:

ffmpeg -f concat -i list.txt -c copy out.mp4

Delay audio/video

Delay video by 3.84 seconds:

ffmpeg -i in.mp4 -itsoffset 3.84 -i in.mp4 -map 1:v -map 0:a -vcodec copy -acodec copy out.mp4

Delay audio by 3.84 seconds:

ffmpeg -i in.mp4 -itsoffset 3.84 -i in.mp4 -map 0:v -map 1:a -vcodec copy -acodec copy out.mp4

Burn subtitles

Use the libass library (make sure your ffmpeg install has the library in the configuration --enable-libass).

First convert the subtitles to .ass format:

ffmpeg -i sub.srt sub.ass

Then add them using a video filter:

ffmpeg -i in.mp4 -vf ass=sub.ass out.mp4

Extract the frames from a video

To extract all frames from between 1 and 5 seconds, and also between 11 and 15 seconds:

ffmpeg -i in.mp4 -vf select='between(t,1,5)+between(t,11,15)' -vsync 0 out%d.png

To extract one frame per second only:

ffmpeg -i in.mp4 -fps=1 -vsync 0 out%d.png

Rotate a video

Rotate 90 clockwise:

ffmpeg -i in.mov -vf "transpose=1" out.mov

For the transpose parameter you can pass:

0 = 90CounterCLockwise and Vertical Flip (default)
1 = 90Clockwise
2 = 90CounterClockwise
3 = 90Clockwise and Vertical Flip

Use -vf "transpose=2,transpose=2" for 180 degrees.

Download "Transport Stream" video streams

  1. Locate the playlist file, e.g. using Chrome > F12 > Network > Filter: m3u8
  2. Download and concatenate the video fragments:
ffmpeg -i "path_to_playlist.m3u8" -c copy -bsf:a aac_adtstoasc out.mp4

If you get a "Protocol 'https not on whitelist 'file,crypto'!" error, add the protocol_whitelist option:

ffmpeg -protocol_whitelist "file,http,https,tcp,tls" -i "path_to_playlist.m3u8" -c copy -bsf:a aac_adtstoasc out.mp4

Mute some of the audio

To replace the first 90 seconds of audio with silence:

ffmpeg -i in.mp4 -vcodec copy -af "volume=enable='lte(t,90)':volume=0" out.mp4

To replace all audio between 1'20" and 1'30" with silence:

ffmpeg -i in.mp4 -vcodec copy -af "volume=enable='between(t,80,90)':volume=0" out.mp4

Deinterlace

Deinterlacing using "yet another deinterlacing filter".

ffmpeg -i in.mp4 -vf yadif out.mp4

Create a video slideshow from images

Parameters: -r marks the image framerate (inverse time of each image); -vf fps=25 marks the true framerate of the output.

ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4

Extract images from a video

  • Extract all frames: ffmpeg -i input.mp4 thumb%04d.jpg -hide_banner
  • Extract a frame each second: ffmpeg -i input.mp4 -vf fps=1 thumb%04d.jpg -hide_banner
  • Extract only one frame: ffmpeg -i input.mp4 -ss 00:00:10.000 -vframes 1 thumb.jpg

Display the frame number on each frame

ffmpeg -i in.mov -vf "drawtext=fontfile=arial.ttf: text=%{n}: x=(w-tw)/2: y=h-(2*lh): fontcolor=white: box=1: boxcolor=0x00000099: fontsize=72" -y out.mov

Metadata: Change the title

ffmpeg -i in.mp4 -map_metadata -1 -metadata title="My Title" -c:v copy -c:a copy out.mp4

Tools

https://ffmpeg.lav.io/ is an interactive resource to compose FFmpeg actions.

@RojjaCebolla
Copy link

RojjaCebolla commented Feb 27, 2021

Thanks for this cheatsheet! I've used it a couple times for the simpler stuff. I had trouble just now with the command for merging a DASH_AUDIO and DASH_VIDEO file together. I tried this:
ffmpeg -i rollover0.mp4 -i rollover1.mp4 -c copy -map 0:0 -map 1:1 -shortest rollingover.mp4
and it said this:
Stream map '1:1' matches no streams. To ignore this, add a trailing '?' to the map.

I had better luck with the following from superuser!
ffmpeg -i rollover0.mp4 -i rollover1.mp4 -c:v copy -c:a aac -shortest rollingover.mp4

@steven2358
Copy link
Author

I tried this:
ffmpeg -i rollover0.mp4 -i rollover1.mp4 -c copy -map 0:0 -map 1:1 -shortest rollingover.mp4
and it said this:
Stream map '1:1' matches no streams. To ignore this, add a trailing '?' to the map.

Usually the problem is the stream index. If rollingover1.mp4 only contains audio or video then the stream you want has index 0, not 1. In that case the following command should work:

ffmpeg -i rollover0.mp4 -i rollover1.mp4 -c copy -map 0:0 -map 1:0 -shortest rollingover.mp4

@acnhia
Copy link

acnhia commented Mar 29, 2021

Hi I am looking for commands for these 2 use cases, could you please help

  1. If a Prores has baked in Video+audio (5.1, mono, downmix) -. output a clean prores video + 5.1 audio tracks only.
  2. if a prores stereo L&R are in single track need a clean output with L and R on different tracks

@dcambria
Copy link

how to start a video from X frame, like -ss?

@paulschreiber
Copy link

ffmpeg -i in.mkv -c:v copy -c:a copy out.mp4

You can simplify to:

ffmpeg -i in.mkv -c copy out.mp4

@jugshaurya
Copy link

jugshaurya commented May 13, 2021

I am using

ffmpeg -f concat -safe 0 -protocol_whitelist file,http,https,tcp,tls,crypto -i ${args.fileList} -c copy ${outputFileName}

and fileList is a file in /tmp/tmp-65420oJVGcsBokCX.txt file with data

file '/home/shaurya/dev/git_repos/merge-videos/assets/course/1.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/2.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/3.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/4.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/5.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/6.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/7.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/8.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/9.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/10.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/11.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/12.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/13.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/14.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/15.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/16.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/17.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/18.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/19.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/20.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/21.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/22.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/23.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/24.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/25.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/26.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/27.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/28.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/29.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/30.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/31.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/32.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/33.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/34.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/35.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/36.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/37.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/38.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/39.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/40.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/41.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/42.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/43.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/44.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/45.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/46.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/47.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/48.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/49.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/50.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/51.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/52.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/53.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/54.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/55.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/56.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/57.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/58.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/59.mp4'
file '/home/shaurya/dev/git_repos/merge-videos/assets/course/60.mp4'

and I am trying to merge these videos into a single video, but this error is coming and only the initial 21 videos are merging, and the rest just not!
can you please look into it (Invalid data found when processing input below image) and let me know if I need to change something in the above command?

Github Repo for the same: https://github.com/jugshaurya/merge-videos

Screenshot from 2021-05-13 13-26-21

@steven2358
Thank you in advance

@steven2358
Copy link
Author

@jugshaurya I don't see the error at first glance. I suggest you start with a minimal working example and extend it until you hit an error.

@jugshaurya
Copy link

I am trying to merge 60 videos in a folder. and I got the `file 'paths/to/file' for each mp4 file as pasted above.
Following your advice, I tried to merge the initial 30 videos then the initial 15 videos, and so on...(using binary search) and found out because of video 22 error was coming. If I deleted 22.mp4 all rest 59 are merging correctly. I played 22.mp4 and found that It is quitting after the 4th minute even when the video is 9 min.

So I understand that the video has some error, not the FFmpeg command. Thanks for the advice @steven2358

@MarvusMedia
Copy link

MarvusMedia commented Aug 8, 2021

Thanks so much for this - it's very useful!

I realise you probably get inundated with questions, but if you can spare a moment, could you tell me if it's possible to use a CD's 'frame' numbers (as shown by ffprobe) rather than seconds (often with recurring decimals) as start and end points when extracting individual tracks with libcdio? Thanks. :)
Marcus

@nikk-ca
Copy link

nikk-ca commented Aug 13, 2021

Super handy!

Just one quick thing, under Extract the frames from a video:
ffmpeg -i in.mp4 -fps=1 -vsync 0 out%d.png should be ffmpeg -i in.mp4 -vf fps=1 -vsync 0 out%d.png, yes?

@Ghayas-cyber
Copy link

Hello. I have a Reference video in YUV format. I have encoded video (Encoded in MPEG4) .mp4.
Now My task is to calculate VMAF for YUV (Reference video) and MPEG4 (Distorted).
Can you please help me out. Thanks

@MarvusMedia
Copy link

Super handy!

Just one quick thing, under Extract the frames from a video: ffmpeg -i in.mp4 -fps=1 -vsync 0 out%d.png should be ffmpeg -i in.mp4 -vf fps=1 -vsync 0 out%d.png, yes?

No, -fps sets the framerate. It's not a video filter.

@Ghayas-cyber
Copy link

Hello
I have two files Reference (YUV) & distorted (YUV). I am calculating the VMAF score. When I run the command I get following output.

Option video_size not found.

@nikk-ca
Copy link

nikk-ca commented Jan 24, 2022

No, -fps sets the framerate. It's not a video filter.

@MarvusMedia

It's documented as a video filter here. Maybe you mean -r?

@MarvusMedia
Copy link

MarvusMedia commented Jan 24, 2022

It's documented as a video filter here. Maybe you mean -r?

@nikk-ca

Sorry, yes, I was thinking of -r.
-fps is indeed used to force a new framerate.

@JirkaSulkov
Copy link

Hi, I'm trying to save AAC audio from video to WAV, but it still reports an error on file size. Don't know what it can be?

D:>ffmpeg.exe -i D.mkv D.wav
Output #0, wav, to 'D.wav':
Stream #0:0(cze): Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s (default)

[wav @ 00000151cf2a98c0] Filesize 10.880.815.182 invalid for wav, output file will be broken
size=10.625.796kB time=17:08:02.62 bitrate=1411.2kbits/s speed= 328x

JirkaS

@MarvusMedia
Copy link

Is D.mkv really 17 hours long? If not, then it may be a malformed file (maybe an incomplete download) and ffmpeg is misreading the duration.

Can you do "D:>ffprobe D.mkv" and post the results?

@JirkaSulkov
Copy link

The D.mkv file is not downloaded. I created it in the VideoPad program. I combined 24 parts. This is due to incorrect playback on the smartTV. According to the playlist, all parts will be played at once, but the Subtitle must be set for each.
After linking to a large file, I needed to sync the subtitles in the SubtitleEdit program. But the Waveform soundtrack will only be created by 12:25:29. In consultation with the author of the SE, I found out that it will terminate FFmpeg earlier.
Here is the output of ffprobe.
D:\FF>ffprobe d.mkv
ffprobe version N-90707-g01170e9db0 Copyright (c) 2007-2018 the FFmpeg developers
built with gcc 7.1.0 (GCC)
configuration: --arch=x86_64 --target-os=mingw32 --cross-prefix=/home/jacek/ffenv/04/jpff/cross_compilers/mingw-w64-x86_64/bin/x86_64-w64-mingw32- --pkg-config=pkg-config --pkg-config-flags=--static --enable-gray --enable-version3 --disable-debug --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages --disable-w32threads --extra-cflags=-DPTW32_STATIC_LIB --extra-libs=-lstdc++ --enable-gpl --enable-version3 --enable-libx264 --enable-libx265 --enable-libxvid --enable-libmp3lame --enable-libfdk-aac --enable-libopus --enable-zlib --enable-fontconfig --enable-libass --enable-iconv --enable-libfreetype --extra-cflags=-DLIBTWOLAME_STATIC --extra-cflags=-DMODPLUG_STATIC --extra-cflags=-DCACA_STATIC --extra-cflags='-mtune=generic' --extra-cflags=-O3 --enable-shared --disable-static --prefix=/home/jacek/ffenv/04/jpff/win64/ffmpeg_git_with_fdk_aac_xp_compat_shared
libavutil 56. 13.100 / 56. 13.100
libavcodec 58. 17.100 / 58. 17.100
libavformat 58. 11.101 / 58. 11.101
libavdevice 58. 2.100 / 58. 2.100
libavfilter 7. 15.100 / 7. 15.100
libswscale 5. 0.102 / 5. 0.102
libswresample 3. 0.101 / 3. 0.101
libpostproc 55. 0.100 / 55. 0.100
Input #0, matroska,webm, from 'd.mkv':
Metadata:
encoder : libebml v1.4.2 + libmatroska v1.6.4
creation_time : 2022-01-31T22:57:04.000000Z
Duration: 17:08:02.92, start: 0.000000, bitrate: 874 kb/s
Stream #0:0: Video: h264 (Main), yuv420p(progressive), 800x600 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
Metadata:
BPS : 712784
DURATION : 17:08:02.920000000
NUMBER_OF_FRAMES: 1542073
NUMBER_OF_BYTES : 5495827574
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-01-31 22:57:04
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:1(cze): Audio: ac3, 44100 Hz, stereo, fltp, 160 kb/s (default)
Metadata:
BPS : 160000
DURATION : 17:08:02.625000000
NUMBER_OF_FRAMES: 1770966
NUMBER_OF_BYTES : 1233652506
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-01-31 22:57:04
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES

D:\FF>

@MarvusMedia
Copy link

Other than suggesting a compressed audio format instead of WAV, I don't really know how to help you. Sorry.
Maybe someone else can answer.
Good luck.

@JayRugMan
Copy link

This is great. Thanks for compiling this. Here is a bash script I wrote for easily adding metadata tags to audio files. Feel free to crack it open and add functionality for video files or adding more tags.

My Script https://github.com/JayRugMan/fun_with_bash/blob/master/metatag.sh
list of ffmpeg metadata tags: https://wiki.multimedia.cx/index.php/FFmpeg_Metadata

@fufatujuba
Copy link

Your list is very useful. But I have question.
How to use two filters to extract frames from .h265 at the same time?
ffmpeg -i input.h265 -vf "select=not(mod(n\,10))" -vsync 0 frame-%04d.png works fine to extract stepped frames . But later I realized that it always outputs frames with constant size which is 1920x1080. I have to add an other filter to scale the size like this: ffmpeg -i input.h265 -vf "select=not(mod(n\,10))" "scale=w=3840:h=2160" -vsync 0 frame-%04d.png for 4k resolution and etc... then the extraction started producing 0 frames

@laurentlbm
Copy link

One issue I've had on Plex is videos with closed captioning. I use this little snippet to remove them:

ffmpeg -i in.mp4 -codec copy -bsf:v "filter_units=remove_types=6" out.mp4

If you want to extract those captions first, you can run:

ffmpeg -f lavfi -i "movie='in.mp4'[out0+subcc]" -map s out.srt

@AlkisPis
Copy link

Great ref for exploring ffmpeg! Thanks for sharing!

@debuti
Copy link

debuti commented Aug 27, 2023

https://ffmpeg.lav.io/ is a great interactive resource to compose ffmpeg actions

@steven2358
Copy link
Author

https://ffmpeg.lav.io/ is a great interactive resource to compose ffmpeg actions

Excellent. Added.

@AlkisPis
Copy link

https://ffmpeg.lav.io/ is a great interactive resource to compose ffmpeg actions

Great interactive tool! Thanks @debuti for bringing this up!

@asifajrof
Copy link

asifajrof commented Dec 23, 2023

i once used this (found from some StackOverflow answer, can't find the link now) to convert a video to gif

ffmpeg -i in.mp4 -vf "fps=10,scale=720:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif

Edit: found the original stack post. here

@AlkisPis
Copy link

@asifajrof, nice setup. But what's the use? It creates a huge GIF file. (It can be 15 to 50 times larger, depending on the scale.) The reverse process is more useful. The resulted MP4 file can be about 20 times smaller. (I tested all that with a small MP4 file.)

@asifajrof
Copy link

asifajrof commented Dec 25, 2023

But what's the use? It creates a huge GIF file.

You are right. It does output a larger file. The one time when I used it was for a very small video file, so the size of the GIF also didn't bother me much. I mentioned it here because I didn't see any process of converting a video to GIF in this cheat sheet.

@AlkisPis
Copy link

@asifajrof, you did very well posting this FFMPEG setup. It's a very useful just by itself. I have worked for a while with FFMPEG, both with the S/W itself (i.e. using console commands) and and with programming, using a Python FFMPEG library. Yet, I couldn't master --actually, I didn't even try-- its too complicated, highly compacted and symbolic commands, an example of which you offered yourself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment