Some useful FFmpeg commands
- Full FFmpeg documentation @ https://ffmpeg.org/ffmpeg-all.html
- Full FFplay documentation @ https://ffmpeg.org/ffplay-all.html
- Full FFprobe documentation @ https://ffmpeg.org/ffprobe-all.html
Get FFmpeg from https://ffmpeg.org/download.html.
I currently use the FFmpeg builds from https://www.gyan.dev/ffmpeg/builds/ (for Windows 7+)
under the release builds section the file ffmpeg-release-full.7z
or directly https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z
To check your version use
ffmpeg -version
Note: the order of (some) parameters/flags matters - before or after a given input or output (FFmpeg supports multiple input files and creating multiple output streams with one command)
- FFplay video viewing
- FFmpeg video editing
- Only output warnings and stats when running a command
- Convert MKV to MP4
- Convert MP4 to M4A (audio only mp4)
- Edit metadata (add chapters)
- Add thumbnail
- Add subtitles
- Extract frames
- Create video from frames
- crop video
- compress video
- cut video
- loop video
- Reverse video and/or Audio
- Concatenate multiple videos into one
- Cut and combine multiple sections of multiple files
- Create/download video with m3u8 playlist
- find silence parts in video
Scroll TOP
ffplay -v level+error -stats -loop -1 INPUT.mp4
A window will show the video looping infinitly (Q or ESC to exit)
- Only output warnings and stats when running a command
- Convert MKV to MP4
- Convert MP4 to M4A (audio only mp4)
- Edit metadata (add chapters)
- Add thumbnail
- Add subtitles
- Extract frames
- Create video from frames
- crop video
- compress video
- cut video
- loop video
- Reverse video and/or Audio
- Concatenate multiple videos into one
- Cut and combine multiple sections of multiple files
- Create/download video with m3u8 playlist
- find silence parts in video
Scroll TOP
ffmpeg -v level+warning -stats # [...]
the mkv video file format is suggested when streaming or recording (via OBS) since it can be easily recovert
# Audio codec already is AAC, so it can be copied to save some time
# Also use some compression to shrink the file size a bit
ffmpeg -v level+warning -stats -i INPUT.mkv -c:a copy -c:v libx264 -crf 12 OUTPUT.mp4
-v
documentation-stats
documentation-c
documentation-crf
documentation (the best description is under libaom-AV1 but it's also in other encoders like MPEG-4)- also see this guide for CRF with
libx264
only include audio and subtitles (if present)
ffmpeg -v level+warning -stats -i INPUT.mp4 -c copy -map 0:a -map 0:s? OUTPUT.m4a
or only exclude video
ffmpeg -v level+warning -stats -i INPUT.mp4 -c copy -map 0 -map -0:v OUTPUT.m4a
export all metadata to a file
ffmpeg -v level+warning -stats -i INPUT.mp4 -f ffmetadata FFMETADATAFILE.txt
it looks something like this
;FFMETADATA1
# empty lines or lines starting with ; or # will be ignored
# whitespace will not be ignored so "title = A" would be interpreted as key "title " and value " A"
title=Video Title
artist=Artist Name
# newlines and other special characters like = ; # \ must be escaped with a \
description=Text\
Line two\
\
\
Line five\
Line with Û̕͝͡n̊̑̓̊i͚͚ͬ́c̗͕̈́̀o̵̯ͣ͊ḑ̴̱̐ḛ̯̓̒
# then adding chapters is very simple | order does not matter (no intersection ofc), so easiest is to append them to the end of file
[CHAPTER]
# fractions of a second so 1/1000 says the following START and END are in milliseconds
TIMEBASE=1/1000
# start and end might change a bit when reinserting (snaps to nearest frame when video stream is copied and not encoded)
START=0
END=10000
title=0 to 10sec of the video
[CHAPTER]
TIMEBASE=1/1000
START=10000
END=20000
title=10sec to 20sec of the video
then to reinsert the edited metadata file
ffmpeg -v level+warning -stats -i INPUT.mp4 -i FFMETADATAFILE.txt -map_metadata 1 -c copy OUTPUT.mp4
-v
documentation-stats
documentation- full metadata documentation
- You might also want to look at the
-metadata
documentation
ffmpeg -v level+warning -stats -i INPUT.mp4 -i IMAGE.png -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic OUTPUT.mp4
-v
documentation-stats
documentation-c
documentation-map
documentation-disposition
documentation- How To add an embedded cover/thumbnail (within the
-disposition
documentation)
Adding subtitles as an extra stream so they can be turned on and off.
Needs a video player that supports this feature like VLC.
# for mkv output
ffmpeg -v level+warning -stats -i INPUT.mp4 -i SUB.srt -c copy OUTPUT.mkv
# for mp4 output
ffmpeg -v level+warning -stats -i INPUT.mp4 -i SUB.srt -c copy -c:s mov_text OUTPUT.mp4
# ... with multiple subtitle files
ffmpeg -v level+warning -stats -i INPUT.mp4 -i SUB_ENG.srt -i SUB_GER.srt -map 0:0 -map 1:0 -map 2:0 -c copy -c:s mov_text OUTPUT.mp4
# ... with language codes
ffmpeg -v level+warning -stats -i INPUT.mp4 -i SUB_ENG.srt -i SUB_GER.srt -map 0:0 -map 1:0 -map 2:0 -c copy -c:s mov_text -metadata:s:s:0 language=eng -metadata:s:s:1 language=ger OUTPUT.mp4
A subtitle file (.srt
) may look like this:
1
00:00:00,000 --> 00:00:03,000
hello there
2
00:00:04,000 --> 00:00:08,000
general kenobi
3
00:00:10,000 --> 00:01:00,000
multi
line
subtitles
displayed like in file → new line in SRT = new line in video
Unicode can be used → tested with z̵̢͎̟͛ͥ̄͑̐͐a̡͈̳̟ͧ̑̓͆̔ͬl̗̠̭͖͓͚ͭ̐͊͊ģ͖͈̍̓ͭͩ̚͝͞ơ̢̞̫̜̞̓͗͊ͪ text and it "pushed" the subtitles of screen (big line height)
Note: not all subtitle files are supported by FFmpeg.
# ! subfolder must be created first (recommended)
# dump ALL frames
ffmpeg -v level+warning -stats -i INPUT.mp4 ./_dump/frame%03d.png
# dump frames with custom frame rate (here 1fps)
ffmpeg -v level+warning -stats -i INPUT.mp4 -r 1 ./_dump/frame%03d.png
# dump custom number of frames
ffmpeg -v level+warning -stats -i INPUT.mp4 -frames:v 3 ./_dump/frame%03d.png
# dump all frames in a timeframe (here from 0:00:02 to 0:00:05)
ffmpeg -v level+warning -stats -ss 2 -i INPUT.mp4 -t 3 ./_dump/frame%03d.png
ffmpeg -v level+warning -stats -ss 2 -i INPUT.mp4 -to 5 ./_dump/frame%03d.png
png
is a good middle ground (lossless compression, but supports less colors)jpeg
is slower but has good compression (not lossless compression)bmp
is faster but has large file size (uncompressed)
The format frame%03d.png
means files will be named: frame000.png
, frame001.png
, ..., frame050.png
, ..., frame1000.png
, and so on
-v
documentation-stats
documentation- image file muxer (output)
-r
documentation-ss
documentation-t
documentation-to
documentation
-ss
, -t
, and -to
expect a specific time format
in short [-][HH:]MM:SS[.m...]
or [-]S+[.m...][s|ms|us]
# uses files INPUT000.png, INPUT001.png, etc to create the mp4 video (with 24fps)
ffmpeg -v level+warning -stats -framerate 24 -i INPUT%03d.png OUTPUT.mp4
# uses every png file that starts with INPUT (at 24fps)
ffmpeg -v level+warning -stats -framerate 24 -i INPUT*.png OUTPUT.mp4
# uses every png file (at 24fps)
ffmpeg -v level+warning -stats -framerate 24 -i *.png OUTPUT.mp4
ffmpeg -v level+warning -stats -i INPUT.mp4 -vf crop=WIDTH:HEIGHT:POSX:POSY OUTPUT.mp4
-
WIDTH
- the width of the croped window -
HEIGHT
- the height of the croped window -
POSX
- the X position of the croped window (can be omitted = auto center) -
POSY
- the Y position of the croped window (can be omitted = auto center) -
all values are in pixels, but there is no "px" after it (or an expression that gets calculated each frame)
lower values are better (higher bitrate), but also lead to larger file size
# for `h.264` values from 18 to 23 are very good
ffmpeg -v level+warning -stats -i INPUT.mp4 -c copy -c:v libx264 -crf 20 OUTPUT.mp4
# for `h.265` values from 24 to 30 are very good
ffmpeg -v level+warning -stats -i INPUT.mp4 -c copy -c:v libx265 -crf 25 OUTPUT.mp4
faster with GPU hardware acceleration / NVIDIA CUDA
# for h.265 → h264_nvenc with NVIDIA CUDA
ffmpeg -v level+warning -stats -hwaccel cuda -hwaccel_output_format cuda -i INPUT.mp4 -c copy -c:v h264_nvenc -fps_mode passthrough -b_ref_mode disabled -preset medium -tune hq -rc vbr -multipass disabled -qp 20 OUTPUT.mp4
# for h.265 → hevc_nvenc with NVIDIA CUDA
ffmpeg -v level+warning -stats -hwaccel cuda -hwaccel_output_format cuda -i INPUT.mp4 -c copy -c:v hevc_nvenc -fps_mode passthrough -b_ref_mode disabled -preset medium -tune hq -rc vbr -multipass disabled -qp 25 OUTPUT.mp4
-v
documentation-stats
documentation-c
documentation-crf
documentation (the best description is under libaom-AV1 but it's also in other encoders like MPEG-4)- also see this FFmpeg guide for CRF with
libx264
- and "Using FFmpeg with NVIDIA GPU Hardware Acceleration" on the NVIDIA Documentation Hub
- CUDA ignores
-crf
(the best description is under libaom-AV1 but it's also in other encoders like MPEG-4) so it's-qp
for the hardware acceleration
# start at 0:00:01 and stop at 0:00:10
ffmpeg -v level+warning -stats -ss 1 -i INPUT.mp4 -to 10 -c copy OUTPUT.mp4
# start at 0:00:10 and stop at 0:00:20 (0:00:10 duration)
ffmpeg -v level+warning -stats -ss 10 -i INPUT.mp4 -t 10 -c copy OUTPUT.mp4
# caps output to be 0:00:30 max
ffmpeg -v level+warning -stats -i INPUT.mp4 -t 30 -c copy OUTPUT.mp4
timing from -ss
, -to
, and -t
shift to the nearest frame and not at the exact timestamp when stream is copied (like here)
if exact time is needed the video needs to be re-encoded (-c:v libx264
after or instead of -c copy
) which obviously takes longer
when -ss
is after -i
it will decode and discard the video until the time is reached,
when it's before -i
like here it will seek into the video without decoding it first (during the seek) so it will be faster.
-v
documentation-stats
documentation-ss
documentation-to
documentation-t
documentation-c
documentation
# loop video infinitely but stop after 0:00:30
ffmpeg -v level+warning -stats -stream_loop -1 -i INPUT.mp4 -t 30 -c copy OUTPUT.mp4
# loop video to length of audio
ffmpeg -v level+warning -stats -stream_loop -1 -i INPUT.mp4 -i INPUT.mp3 -shortest -map 0:v -map 1:a OUTPUT.mp4
# loop audio to length of video
ffmpeg -v level+warning -stats -i INPUT.mp4 -stream_loop -1 -i INPUT.mp3 -shortest -map 0:v -map 1:a OUTPUT.mp4
if exact timing is needed, it is better to re-encode the video (-c:v libx264
after or instead of -c copy
)
-v
documentation-stats
documentation-stream_loop
documentation (note: looping once results in two videos)-t
documentation-c
documentation-shortest
documentation-map
documentation
Warning: these filters require a lot of memory (buffer of the entire clip) so it's suggested to also use the trim filter as shown
# reverse video only (first 5sec)
ffmpeg -v level+warning -stats -i INPUT.mp4 -vf trim=end=5,reverse OUTPUT.mp4
# reverse audio only (first 5sec)
ffmpeg -v level+warning -stats -i INPUT.mp4 -af atrim=end=5,areverse OUTPUT.mp4
-v
documentation-stats
documentation- reverse filter documentation
- trim filter documentation
- areverse filter documentation
- atrim filter documentation
# using filter complex and the concat filter (if video formats are not the same add `:unsafe` to the `concat` filter)
ffmpeg -v level+warning -stats -i INPUT_0.mp4 -i INPUT_1.mp4 -filter_complex "[0:v] [0:a] [1:v] [1:a] concat=n=2:v=1:a=1 [v1] [a1]" -map "[v1]" -map "[a1]" OUTPUT.mp4
# using a list file and demuxer
ffmpeg -v level+warning -stats -safe 0 -f concat -i VIDEO_LIST.txt -c copy OUTPUT.mp4
content of VIDEO_LIST.txt
as follows
file 'INPUT_0.mp4'
file 'INPUT_1.mp4'
-v
documentation-stats
documentation-filter_complex
documentation- concat multimedia filter
-map
documentation- concat demuxer documentation
-safe
option for concat demuxer-c
documentation
Cut clips and concat them (with re-encoding) as follows (video and audio are cut and combined separately).
# 00:00 to 00:02 video and audio of INPUT_0.mp4
# 00:04 to 00:08 video and audio of INPUT_0.mp4
# 00:01 to 00:05 video and audio of INPUT_1.mp4
# 00:06 to 00:08 video and audio of INPUT_1.mp4
ffmpeg -v level+warning -stats -i INPUT_0.mp4 -i INPUT_1.mp4 -filter_complex "[0:v]trim=0:2,setpts=PTS-STARTPTS[i0v0];[0:v]atrim=0:2,asetpts=PTS-STARTPTS[i0a0];[0:v]trim=4:8,setpts=PTS-STARTPTS[i0v1];[0:v]atrim=4:8,asetpts=PTS-STARTPTS[i0a1];[1:v]trim=1:5,setpts=PTS-STARTPTS[i1v0];[1:v]atrim=1:5,asetpts=PTS-STARTPTS[i1a0];[1:v]trim=6:8,setpts=PTS-STARTPTS[i1v1];[1:v]atrim=6:8,asetpts=PTS-STARTPTS[i1a1];[i0v0][i0a0][i0v1][i0a1][i1v0][i1a0][i1v1][i1a1]concat=n=4:v=1:a=1[cv][ca]" -map "[cv]" -map "[ca]" OUTPUT.mp4
# with (h.264) NVIDIA:CUDA and slow/low compression (4 to 8 MB variable bitrate and 4 QP) for the first video stream of the combined video clips
ffmpeg -v level+warning -stats -hwaccel cuda -hwaccel_output_format cuda -i INPUT_0.mp4 -hwaccel cuda -hwaccel_output_format cuda -i INPUT_1.mp4 -filter_complex "[0:v]trim=0:2,setpts=PTS-STARTPTS[i0v0];[0:v]atrim=0:2,asetpts=PTS-STARTPTS[i0a0];[0:v]trim=4:8,setpts=PTS-STARTPTS[i0v1];[0:v]atrim=4:8,asetpts=PTS-STARTPTS[i0a1];[1:v]trim=1:5,setpts=PTS-STARTPTS[i1v0];[1:v]atrim=1:5,asetpts=PTS-STARTPTS[i1a0];[1:v]trim=6:8,setpts=PTS-STARTPTS[i1v1];[1:v]atrim=6:8,asetpts=PTS-STARTPTS[i1a1];[i0v0][i0a0][i0v1][i0a1][i1v0][i1a0][i1v1][i1a1]concat=n=4:v=1:a=1[cv][ca]" -map "[cv]" -c:v:0 h264_nvenc -preset p7 -tune hq -profile:v:0 high -level:v:0 auto -rc vbr -b:v:0 4M -minrate:v:0 500k -maxrate:v:0 8M -bufsize:v:0 8M -multipass disabled -fps_mode passthrough -b_ref_mode:v:0 disabled -rc-lookahead:v:0 32 -qp 4 -map "[ca]" OUTPUT.mp4
# the `-hwaccel cuda -hwaccel_output_format cuda` must be in front of every input video (that is in the filter and gets encoded as video stream)
-v
documentation-stats
documentation-filter_complex
documentation- trim multimedia filter
- atrim multimedia filter
- concat multimedia filter
-map
documentation-c
documentation- also, see the section about video compression specifically with GPU hardware acceleration / NVIDIA CUDA
# this will whitelist urls (`-i`) for files available via file, http/s, tcp, tls, or crypto protocol (for this command, not permanent)
ffmpeg -v level+warning -stats -protocol_whitelist file,http,https,tcp,tls,crypto -i INPUT.m3u8 -c copy OUTPUT.mp4
ffmpeg -v level+warning -stats -protocol_whitelist file,http,https,tcp,tls,crypto -i https://example.com/INPUT.m3u8 -c copy OUTPUT.mp4
# finds sections min 240sec long and max -70db loud and writes them to LOG.txt
ffmpeg -v level+warning -stats -i INPUT.mp4 -af silencedetect=noise=-70dB:d=240 -f null - 2> LOG.txt
look for [silencedetect @ *
lines in log file
[silencedetect @ 0000000000******] silence_start: 01:00:02.500
[silencedetect @ 0000000000******] silence_end: 01:10:02.500 | silence_duration: 00:09:59.989
[silencedetect @ 000000000*******] silence_start: 02:00:02.500
[silencedetect @ 000000000*******] silence_end: 02:10:02.500 | silence_duration: 00:09:59.989
[...]