Skip to main content

FFMPEG Cheat Sheet

Shenzhen, China

ffmpeg -version
ffmpeg version 5.0-full_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers built with gcc 11.2.0 (Rev5, Built by MSYS2 project)

Conversions

Get audio from a video file:

ffmpeg -i video.mp4 -vn -c:a copy song.mp3
ffmpeg -i video.mp4 -vn -c:a mp3 -b:a 128k -ar 44100 -ac 2 song.mp3

size=2456kB time=00:02:37.12 bitrate=128.0kbits/s speed=59.6x video:0kB audio:2456kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.013761%

ffmpeg -i song.m4a -af loudnorm -c:a mp3 -b:a 320k -ar 48000 song.mp3

size=12213kB time=00:05:12.60 bitrate=320.1kbits/s speed=16.8x video:0kB audio:12212kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.008781%

Strip audio from a video file:

ffmpeg -i video.mp4 -an -c:v copy video_only.mp4
ffmpeg -i video.mp4 -an video_only.h265

frame= 4707 fps=466 q=35.8 Lsize=659kB time=00:02:36.99 bitrate=34.4kbits/s speed=15.6x
video:659kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000% encoded 4707 frames in 10.08s (467.10 fps), 31.01 kb/s, Avg QP:34.70

ffmpeg -i https://my-domain.com/movie.mkv -t 00:02:30 -c:v h264 -b:v 2500k -c:a mp3 -b:a 128k -ar 44100 -ac 2 movie.mp4

video:398897kB audio:16473kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.321552% [libx264 @ 0000028f21bb09c0] kb/s:2477.36

Convert ALL streams included in your input file using the MAP flag:

ffmpeg -i video.mp4 -map 0 -c:a aac -c:v hevc output.mkv

h.264 (AVC)

Encoding Presets

  • ultrafast
  • superfast
  • veryfast
  • faster
  • fast
  • medium
  • slow
  • slower
  • veryslow
  • placebo

Tuning Presets

  • psnr
  • ssim
  • grain
  • zerolatency
  • fastdecode
  • animation

Costant Rate Factor

  • 051 (lossless - low quality), default 23, usable range 1728

Profiles

  • -profile:v baseline
  • -profile:v high
  • -profile:v high

leave out to let FFMPEG decide based on input (recommended)

ffmpeg -i video.mkv -c:v hevc -crf 23 -preset slower -tune zerolatency output.mp4

video:1422kB audio:2350kB subtitle:0kB other streams:0kB global headers:2kB muxing overhead: 4.637553% x265 [info]: frame I: 19, Avg QP:10.82 kb/s: 5285.69 x265 [info]: frame P: 4689, Avg QP:15.41 kb/s: 52.07 x265 [info]: Weighted P-Frames: Y:1.9% UV:1.8% x265 [info]: consecutive B-frames: 100.0% encoded 4708 frames in 307.38s (15.32 fps), 73.19 kb/s, Avg QP:15.39 [aac @ 0000021ab0643d00] Qavg: 4054.659

Move flags to start (make file playable before fully downloaded):

ffmpeg -i video.mkv -c:v h264 -crf 23 -maxrate 1M -bufsize 2M -movflags +faststart output.mp4

[mp4 @ 000001f50ef56140] Starting second pass: moving the moov atom to the beginning of the file frame= 4708 fps=716 q=-1.0 Lsize= 3418kB time=00:02:37.12 bitrate= 178.2kbits/s dup=1 drop=0 speed=23.9x

h.265 (HEVC)

Encoding Presets

  • ultrafast
  • superfast
  • veryfast
  • faster
  • fast
  • medium
  • slow
  • slower
  • veryslow
  • placebo

Tuning Presets

  • psnr
  • ssim
  • grain
  • zerolatency
  • fastdecode

Costant Rate Factor

  • 051 (lossless - low quality), default 28, usable range 1728

Profiles

  • -profile:v baseline
  • -profile:v high
  • -profile:v high
ffmpeg -i video.mp4 -c:v libx265 -crf 28 -c:a aac -b:a 128k output.mp4

Stream #0:0(und): Video: hevc (hev1 / 0x31766568), yuv420p(progressive), 480x360 [SAR 1:1 DAR 4:3], q=2-31, 29.97 fps, 30k tbn (default) Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)

h.266 (VVC)

not available yet

VP8 & webM

ffmpeg -i video.mp4 -c:v libvpx -b:v 1M -c:a libvorbis output.webm

Stream #0:0(und): Video: vp8, yuv420p(progressive), 480x360 [SAR 1:1 DAR 4:3], q=2-31, 1000 kb/s, 29.97 fps, 1k tbn (default) Stream #0:1(und): Audio: vorbis, 44100 Hz, stereo, fltp (default)

Costant Rate Factor

ffmpeg -i video.mp4 -c:v libvpx -crf 10 -b:v 1M -c:a libvorbis output.webm

VP9 & webM

Google VP9 Developer Docs

1-pass encoding with an average video bitrate of 1M:

ffmpeg -i video.mp4 -c:v libvpx-vp9 -b:v 1M -c:a libvorbis output.webm

Stream #0:0(und): Video: vp9, yuv420p(progressive), 480x360 [SAR 1:1 DAR 4:3], q=2-31, 1000 kb/s, 29.97 fps, 1k tbn (default) Stream #0:1(und): Audio: vorbis, 44100 Hz, stereo, fltp (default)

2-pass encoding:

ffmpeg -i video.mp4 -c:v libvpx-vp9 -b:v 0 -crf 30 -pass 1 -an -f webm /dev/null&&ffmpeg -i video.mp4 -c:v libvpx-vp9 -b:v 0 -crf 30 -pass 2 -c:a libopus output.webm

Constant Rate Factor

  • 063 (high - low quality), default 31, usable range 1535

Constant Quality 1-pass encoding:

ffmpeg -i video.mp4 -c:v libvpx-vp9 -crf 31 -b:v 0 output.webm

Stream #0:0(und): Video: vp9, yuv420p(progressive), 480x360 [SAR 1:1 DAR 4:3], q=2-31, 29.97 fps, 1k tbn (default) Stream #0:1(und): Audio: opus, 48000 Hz, stereo, flt, 96 kb/s (default)

Constrained Quality 1-pass encoding when b:v > 0.

ffmpeg -i video.mp4 -c:v libvpx-vp9 -crf 31 -b:v 2500k output.webm

Stream #0:0(und): Video: vp9, yuv420p(progressive), 480x360 [SAR 1:1 DAR 4:3], q=2-31, 2500 kb/s, 29.97 fps, 1k tbn (default) Stream #0:1(und): Audio: opus, 48000 Hz, stereo, flt, 96 kb/s (default)

Lossless Encoding

fmpeg -i video.mp4 -c:v libvpx-vp9 -lossless 1 output.webm

Stream #0:0(und): Video: vp9, yuv420p(progressive), 480x360 [SAR 1:1 DAR 4:3], q=2-31, 29.97 fps, 1k tbn (default) Stream #0:1(und): Audio: opus, 48000 Hz, stereo, flt, 96 kb/s (default)

Advanced Settings

ffmpeg -i video.mp4 -b:v 3600k -minrate 1800k -maxrate 5220k -tile-columns 2 -g 240 -threads 8 -quality good -crf 27 -c:v libvpx-vp9 -map 0 -sn -c:a libopus -ac 2 -b:a 128k -pass 1 -speed 4 output.webm&&ffmpeg -i video.mp4 -b:v 3600k -minrate 1800k -maxrate 5220k -tile-columns 3 -g 240 -threads 8 -quality good -crf 27 -c:v libvpx-vp9 -map 0 -sn -c:a libopus -ac 2 -b:a 128k -pass 2 -speed 4 -y output.webm

Opus Audio

ffmpeg -i video.mp4 -c:a libopus -b:a 128k -ar 48000 -ac 2 output.opus

Stream #0:1[0x2] (und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 122 kb/s (default) Stream #0:1 -> #0:0 (aac (native) -> opus (libopus))

AV1 & webM

ffmpeg -i video.mp4 -c:v libaom-av1 -crf 27 -b:v 0 -strict experimental -c:a libopus -b:a 128k -movflags +faststart output.webm

Stream #0:0(und): Video: av1, yuv420p(progressive), 480x360 [SAR 1:1 DAR 4:3], q=2-31, 29.97 fps, 1k tbn (default) Stream #0:1(und): Audio: opus, 48000 Hz, stereo, flt, 128 kb/s (default)

AV1 SVT-AV1

Recordings

RTSP Streams

ffmpeg -i rtsp://admin:instar@192.168.2.19:554/livestream/11 -c:v h264 -keyint_min 25 -g 50 -sc_threshold 0 recording.mp4

frame= 1017 fps= 30 q=-1.0 Lsize= 29399kB time=10:20:37.33 bitrate= 6.5kbits/s dup=341 drop=1 speed=1.09e+03x video:29098kB audio:279kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.074037%

  • * Minimum keyframe interval 25 / maximum for a GoP is 50 = 2s @ 25fps.

Timelapse from Images

ls | cat -n | while read n f; do mv "$f" `printf "A_%03d.jpeg" $n`; done
  • -framerate 1: 1 fps
  • -framerate 1/2: 0.5 fps
  • -framerate 1/10: 0.1 fps
ffmpeg -framerate 1 -i A_%03d.jpeg -r 25 -pix_fmt yuv420p timelapse.mp4

Compress timelapse using x.265:

ffmpeg -i timelapse.mp4 -c:v hevc -crf 23 -preset slower -tune zerolatency timelapse_h265.mp4

Reduce resolution:

ffmpeg -i timelapse_h265.mp4 -s 1280x720 timelapse_h265_720p.mp4

Create Snapshots from Videos

Create a snapshot every 45s starting with P_001.png:

ffmpeg -i video.mp4 -f image2 -bt 20M -r 1/45 P_%03d.png

Start at 30s and record 5 frames:

ffmpeg -ss 00:00:30.00 -i video.mp4 -frames:v 5 -f image2 -bt 10M 5frames_%03d.png

Generate GIF from Video

Cut 10 seconds of the video starting at the 2min 30s mark:

ffmpeg -ss 00:02:30 -i video.mkv -t 00:00:10 -avoid_negative_ts 1 cut.mp4

Resize the cut video:

ffmpeg -i cut.mp4 -vf scale=640x360 -c:v h264 -crf 18 -c:a aac scaled.mp4

Create a subtitle file captions.srt:

1
00:00:00,00 --> 00:00:03,00
This is some text,

2
00:00:03,00 --> 00:00:06,00
and some more text,

3
00:00:06,00 --> 00:00:09,00
And now - The Punch Line!!

Convert the SRT file to the ASS format:

ffmpeg -i captions.srt captions.ass

Hardcode the captions:

ffmpeg -i scaled.mp4 -filter_complex "subtitles=captions.ass" subtitled.mp4

Convert to GIF:

ffmpeg -i subtitled.mp4 mygif.gif

For better results - better resolution, much smaller filesize - use Gifski:

ffmpeg -i subtitled.mp4 subtitled_frame%04d.png
gifski -o mygif.gif subtitled_frame*.png

Streaming

Dynamic Adaptive Streaming over HTTP (DASH)

Start by creating input file versions with different resolutions:

ffmpeg -i video.mp4 -c:v h264 -crf 22 -tune zerolatency -profile:v high -level:v 4.0 -maxrate 5000k -bufsize 10000k -r 25 -keyint_min 25 -g 50 -sc_threshold 0 -c:a aac -ar 44100 -b:a 128k -ac 2 -pix_fmt yuv420p -movflags +faststart 1080.mp4 \
-s 1280x720 -c:v h264 -crf 24 -tune zerolatency -profile:v high -level:v 4.0 -maxrate 2500k -bufsize 5000k -r 25 -keyint_min 25 -g 50 -sc_threshold 0 -c:a aac -ar 44100 -b:a 128k -ac 2 -pix_fmt yuv420p -movflags +faststart 720.mp4 \
-s 854x480 -c:v h264 -crf 30 -tune zerolatency -profile:v high -level:v 4.0 -maxrate 1250k -bufsize 2500k -r 25 -keyint_min 25 -g 50 -sc_threshold 0 -c:a aac -ar 44100 -b:a 96k -ac 2 -pix_fmt yuv420p -movflags +faststart 480.mp4 \
-s 640x360 -c:v h264 -crf 33 -tune zerolatency -profile:v high -level:v 4.0 -maxrate 900k -bufsize 1800k -r 25 -keyint_min 25 -g 50 -sc_threshold 0 -c:a aac -ar 44100 -b:a 96k -ac 2 -pix_fmt yuv420p -movflags +faststart 360.mp4 \
-s 320x240 -c:v h264 -crf 36 -tune zerolatency -profile:v high -level:v 4.0 -maxrate 625k -bufsize 1250k -r 25 -keyint_min 25 -g 50 -sc_threshold 0 -c:a aac -ar 22050 -b:a 64k -ac 1 -pix_fmt yuv420p -movflags +faststart 240.mp4

Create file fragments:

mp4fragment 1080.mp4 1080-f.mp4 && \
mp4fragment 720.mp4 720-f.mp4 && \
mp4fragment 480.mp4 480-f.mp4 && \
mp4fragment 360.mp4 360-f.mp4 && \
mp4fragment 240.mp4 240-f.mp4

Generate the DASH Playlist:

mp4dash 240-f.mp4 360-f.mp4 480-f.mp4 720-f.mp4 1080-f.mp4

Adaptive WebM DASH Streaming

Playback

ffplay rtsp://admin:instar@192.168.2.19:554/livestream/11

Stream #0:0: Video: hevc (Main), yuv420p(tv), 2560x1440, 30 tbr, 90k tbn Stream #0:1: Audio: aac (LC), 16000 Hz, mono, fltp

Probing & Metadata

ffprobe recording_h264.mp4

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'recording_h264.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
title : instarsxrtpsion
encoder : Lavf59.16.100
Duration: 10:20:37.34, start: 0.000000, bitrate: 6 kb/s
Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 2560x1440, 7031 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 16000 Hz, mono, fltp, 0 kb/s (default)
Metadata:
handler_name : SoundHandler
vendor_id : [0][0][0][0]

Writing results to file:

ffprobe -v quiet -print_format json -show_format -show_streams recording_h264.mp4 > recording_h264.json
{
"streams": [
{
"index": 0,
"codec_name": "h264",
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
"profile": "High",
"codec_type": "video",
"codec_tag_string": "avc1",
"codec_tag": "0x31637661",
"width": 2560,
"height": 1440,
"coded_width": 2560,
"coded_height": 1440,
"closed_captions": 0,
"film_grain": 0,
"has_b_frames": 2,
"pix_fmt": "yuv420p",
"level": 50,
"chroma_location": "left",
"field_order": "progressive",
"refs": 1,
"is_avc": "true",
"nal_length_size": "4",
"id": "0x1",
"r_frame_rate": "30/1",
"avg_frame_rate": "30/1",
"time_base": "1/15360",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 520704,
"duration": "33.900000",
"bit_rate": "7031676",
"bits_per_raw_sample": "8",
"nb_frames": "1017",
"extradata_size": 46,
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"language": "und",
"handler_name": "VideoHandler",
"vendor_id": "[0][0][0][0]"
}
},
{
"index": 1,
"codec_name": "aac",
"codec_long_name": "AAC (Advanced Audio Coding)",
"profile": "LC",
"codec_type": "audio",
"codec_tag_string": "mp4a",
"codec_tag": "0x6134706d",
"sample_fmt": "fltp",
"sample_rate": "16000",
"channels": 1,
"channel_layout": "mono",
"bits_per_sample": 0,
"id": "0x2",
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/16000",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 595797424,
"duration": "37237.339000",
"bit_rate": "61",
"nb_frames": "565",
"extradata_size": 5,
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"language": "und",
"handler_name": "SoundHandler",
"vendor_id": "[0][0][0][0]"
}
}
],
"format": {
"filename": "recording_h264.mp4",
"nb_streams": 2,
"nb_programs": 0,
"format_name": "mov,mp4,m4a,3gp,3g2,mj2",
"format_long_name": "QuickTime / MOV",
"start_time": "0.000000",
"duration": "37237.339000",
"size": "30104435",
"bit_rate": "6467",
"probe_score": 100,
"tags": {
"major_brand": "isom",
"minor_version": "512",
"compatible_brands": "isomiso2avc1mp41",
"title": "instarsxrtpsion",
"encoder": "Lavf59.16.100"
}
}
}

Get recording length in sexagesimal format (HH:MM:SS:ms) :

ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 -sexagesimal recording_h264.mp4

0:00:33.900000

Get recording bitrate:

ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 recording_h264.mp4

7031676

Get embedded metadata:

ffmpeg -i '03. No Regrets.mp3' -print_format json -f ffmetadata meta.txt
;FFMETADATA1
title=No Regrets
artist=Joss Stone
ARTISTS=Joss Stone
album=Never Forget My Love
album_artist=Joss Stone
track=3
disc=1/1
TLEN=223000
TSRC=QMDA62165268
BARCODE=196292637489
ITUNESADVISORY=0
composer=Joss Stone
genre=R&B
date=2022

Video Editing

Cutting

Get a 10s excerpt of your video starting from the 30s marker:

ffmpeg -ss 00:00:30.000 -i video.mp4 -t 00:00:10.000 video_excerpt.mp4
ffmpeg -ss 00:00:30.000 -i video.mp4 -t 00:00:10.000 -c copy video_excerpt.mp4

frame=329 fps=0.0 q=-1.0 Lsize=395kB time=00:00:10.00 bitrate= 323.3kbits/s speed=2.77e+03x video:256kB audio:129kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 2.728323%

Resolution Scaling

ffmpeg -i video.mp4 -s 1280x720 output.mp4

Video Overlays

ffmpeg -i video.mp4 -i logo.png -filter_complex "overlay=0:0" -codec:a copy watermarked.mp4

This can also be used to watermark images:

overlay=0:0: Position from left top horizontal:vertical.

ffmpeg -i source.jpg -i logo.png -filter_complex “overlay=0:0” watermarked.jpg

Add an Audio Track

ffmpeg -i video.mp4 -i 03_No_Regrets.mp3 -map 0:v -map 1:a -c copy result.mp4

Waveform

Single audio channel:

ffmpeg -i mysong.mp3 -filter_complex "[0:a]showwaves=mode=cline:s=640x480:colors=purple[v]" -map '[v]' -map '0:a' -c:a copy -pix_fmt yuv420p mysong_waveform.mp4

Stereo channels:

ffmpeg -i mysong.mp3 -filter_complex "[0:a]showwaves=split_channels=1:mode=cline:s=640x480:colors=green[v]" -map '[v]' -map '0:a' -c:a copy -pix_fmt yuv420p mysong_waveform.mp4

Show Volume:

ffmpeg -i  mysong.mp3 -t 00:01:00 -filter_complex "[0:a]showvolume,scale=640:-1,pad=640:480 :(ow-iw)/2:(oh-ih)/2[v]" -map '[v]' -map '0:a' -c:a copy -pix_fmt yuv420p mysong_volume.mp4

Frequencies:

Default style

ffmpeg -i mysong.mp3 -t 00:01:00 -filter_complex "[0:a]showfreqs=s=640x480[v]" -map '[v]' -map '0:a' -c:a copy -pix_fmt yuv420p mysong_freq.mp4

Coloured line style

ffmpeg -i mysong.mp3 -filter_complex "[0:a]showwaves=mode=line:s=640x480:colors=red[v]" -map '[v]' -map '0:a' -c:a copy -pix_fmt yuv420p mysong_freq.mp4

Cline frequency style

ffmpeg -i mysong.mp3 -filter_complex "[0:a]showwaves=mode=cline:s=640x480:colors=dodgerblue[v]" -map '[v]' -map '0:a' -c:a copy -pix_fmt yuv420p mysong_freq.mp4