Skip to content

Instantly share code, notes, and snippets.

@KeigoAlexTanaka
Forked from steven2358/ffmpeg.md
Last active May 24, 2023 12:53
Show Gist options
  • Save KeigoAlexTanaka/eb3953742f00fa6a10709f5bdbc9b845 to your computer and use it in GitHub Desktop.
Save KeigoAlexTanaka/eb3953742f00fa6a10709f5bdbc9b845 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

7s Slated File Trim (TESTED ON .MOV ONLY)

06s (Export from 07:00-13:00)

for i in *.mov; do ffmpeg -ss 00:00:07.01 -i "$i" -t 6 -c copy "${i%.*}_UNSLATED.mov"; done

15s (Export from 07:00-22:00)

for i in *.mov; do ffmpeg -ss 00:00:07.01 -i "$i" -t 15 -c copy "${i%.*}_UNSLATED.mov"; done

30s (Export from 07:00-0:37:00)

for i in *.mov; do ffmpeg -ss 00:00:07.01 -i "$i" -t 30 -c copy "${i%.*}_UNSLATED.mov"; done

45s (Export from 07:00-0:52:00)

for i in *.mov; do ffmpeg -ss 00:00:07.01 -i "$i" -t 45.01 -c copy "${i%.*}_UNSLATED.mov"; done

Trim Last Second? (In Progress)

It seems like using the -t option with -c results in inaccurate encoding lengths for mp4s (currently exports are coming out with extra frames). Will have to look into this. https://video.stackexchange.com/questions/23373/ffmpeg-not-creating-exact-duration-clip

for i in *; do duration="$(bc -l <<< "$(ffprobe -loglevel error -of csv=p=0 -show_entries format=duration "$i")-1.02")"; ffmpeg -i "$i" -t "$duration" -c copy "${i%.*}_1.${i#*.}"; done

Convert to jpg

for i in *; do ffmpeg -i "$i" "${i%.*}_1.jpg"; done

Make Slates

Batch

for i in *.png; do ffmpeg -y -i /usr/local/Cellar/ffmpeg/4.2.1/bin/generate_slate_data/Psyop_HD_Slate_23.976.mov -i "$i" -filter_complex "[0:v][1:v] overlay=25:25:enable='between(t,0,5)'" -pix_fmt yuv420p -c:a copy "${i%.*}.mov"; done

Export JPEGs for QC

Batch (Just first frame)

for i in *.m*; do duration="$(bc -l <<< "$(ffprobe -loglevel error -of csv=p=0 -show_entries format=duration "$i")-.05")"; ffmpeg -i "$i" -ss 00:00:00 -i "$i" -map 0:v:0 -frames:v 1 "${i%.*}.jpeg"; done

Batch

for i in *.m*; do duration="$(bc -l <<< "$(ffprobe -loglevel error -of csv=p=0 -show_entries format=duration "$i")-.05")"; ffmpeg -i "$i" -ss 00:00:05 -i "$i" -ss 00:00:06.5 -i "$i" -ss 00:00:07 -i "$i" -ss "$(bc -l <<< "$duration*.99")" -i "$i" -map 0:v:0 -frames:v 1 "${i%.*}_1.jpeg" -map 1:v:0 -frames:v 1 "${i%.*}_2.jpeg" -map 2:v:0 -frames:v 1 "${i%.*}_3.jpeg" -map 3:v:0 -frames:v 1 "${i%.*}_4.jpeg" -map 4:v:0 -frames:v 1 "${i%.*}_5.jpeg"; done

Export JPEGs from 25%, 50%, and 75% of clip

Batch

for i in *.m*; do duration="$(ffprobe -loglevel error -of csv=p=0 -show_entries format=duration "$i")"; ffmpeg -ss "$(bc -l <<< "$duration*.25")" -i "$i" -ss "$(bc -l <<< "$duration*.5")" -i "$i" -ss "$(bc -l <<< "$duration*.75")" -i "$i" -map 0:v:0 -frames:v 1 "${i%.*}_1.jpeg" -map 1:v:0 -frames:v 1 "${i%.*}_2.jpeg" -map 2:v:0 -frames:v 1 "${i%.*}_3.jpeg"; done

Basic conversion

ffmpeg -i in.mp4 out.avi

Make mp4 from Image Sequence

ffmpeg -framerate 23.976 -start_number 1001 -i image-%04d.png output.mp4

Make a Gif from Video

Single

ffmpeg -i input.mp4 -filter_complex "[0:v] fps=12,scale=480:-1,split [a][b];[a] palettegen [p];[b][p] paletteuse" output.gif

Batch

for i in *.m*; do ffmpeg -i "$i" -filter_complex "[0:v] fps=12,scale=720:-1,split [a][b];[a] palettegen [p];[b][p] paletteuse" "${i%.*}.gif"; done

Compress Gifs

for i in *.gif; do gifsicle -O3 --lossy=80 -o "${i%.*}_compressed.gif" "$i"; done

Taken from GIPHY

Add Watermark to 1080p file

Single

ffmpeg -i input.mp4 -i /Volumes/Work/_DMG/_BuggedMasters/_4K/Psyop_3840x2160_WHT.tif -filter_complex "[1:v]scale=1920:1080 [ovrl], [0:v][ovrl]overlay=0:0" -codec:a copy output.mp4

Batch h.264

for i in *.m*; do ffmpeg -i "$i" -i /Volumes/Work/_DMG/_BuggedMasters/_4K/Psyop_3840x2160_WHT.tif -filter_complex "[1:v]scale=1920:1080 [ovrl], [0:v][ovrl]overlay=0:0" -codec:a copy "${i%.*}_psyop.mov"; done

Batch ProRes

for i in *.m*; do ffmpeg -i "$i" -i /Volumes/Work/_DMG/_BuggedMasters/_4K/Psyop_3840x2160_WHT.tif -filter_complex "[1:v]scale=1920:1080 [ovrl], [0:v][ovrl]overlay=0:0" -c:v prores_ks -profile:v 3 "${i%.*}_psyop.mov"; done

Batch ProRes Left Side

for i in *.m*; do ffmpeg -i "$i" -i /Volumes/Work/_DMG/_BuggedMasters/_4K/Psyop_3840x2160_WHT.tif -filter_complex "[1:v]scale=1920:1080 [ovrl], [0:v][ovrl]overlay=-1400:0" -c:v prores_ks -profile:v 3 "${i%.*}_psyop.mov"; done

Batch ProRes with slates removed

for i in *.m*; do ffmpeg -ss 00:00:07 -i "$i" -i /Volumes/Work/_DMG/_BuggedMasters/_4K/Psyop_3840x2160_WHT.tif -filter_complex "[1:v]scale=1920:1080 [ovrl], [0:v][ovrl]overlay=0:0" -c:v prores_ks -profile:v 3 "${i%.*}_psyop.mov"; done

See difference between two video files

ffplay -f lavfi "movie=input1.mov[a]; movie=input2.mov[b]; [a][b]blend=all_mode=difference"

Output difference between two video files to a video file (Beta)

Green (Recommmended)

ffmpeg -i input1.mov -i input2.mov -filter_complex "blend=all_mode=difference" -pix_fmt yuv420p -c:v libx264 -crf 18 -c:a copy output.mov

Grey

ffmpeg -y -i input1.mp4 -i input2.mp4 -filter_complex "[1:v]format=yuva444p, lut=c3=128, negate[video2withAlpha], [0:v][video2withAlpha]overlay[out]" -map [out] output.mov

Downmix 5.1 Video File to Stereo Mix

Single

ffmpeg -i input.mov -vcodec copy -ac 2 -vol 425 output.mov

Batch

for i in *.m*; do ffmpeg -i "$i" -vcodec copy -ac 2 -vol 425 "${i%.*}_STEREO.mov"; done
for i in *.mov; do ffmpeg -i "$i" -vcodec libx264 -pix_fmt yuv420p -x264-params "nal-hrd=cbr" -b:v 20M -minrate 20M -maxrate 20M -bufsize 40M -ac 2 "${i%.*}.mp4"; done

Get integrated loudness

Single

ffmpeg -nostats -i input.mp4 -filter_complex ebur128 -f null - > log.txt 2>&1

Batch

for i in *.m*; do echo "${i%.*}" >> log.txt && ffmpeg -nostats -i "$i" -filter_complex ebur128 -f null - 2>&1 | grep "I:" | tail -1 | awk '{print "Integrated","Loudness:",$2, $3}' >> log.txt; done

Trim First 7 seconds of a video file

Single

ffmpeg -ss 00:00:07.01 -i input.mov -c copy output.mov

Batch

for i in *.mov; do ffmpeg -ss 00:00:07.01 -i "$i" -c copy "${i%.*}_UNSLATED.mov"; done

Transcode file as ProRes422HQ

Single

ffmpeg -i input.mov -c:v prores_ks -profile:v 3 output.mov

Batch

for i in *.mov; do ffmpeg -i "$i" -c:v prores_ks -profile:v 3 "${i%.*}_1.mov"; done

Transcode .mov as h264 vieweable in quicktime (20MB/s CBR & 192kbps Audio Bitrate)

Single

ffmpeg -i input.mov -b:a 192k -vcodec libx264 -pix_fmt yuv420p -x264-params "nal-hrd=cbr" -b:v 20M -minrate 20M -maxrate 20M -bufsize 40M output.mp4

Batch

for i in *.mov; do ffmpeg -i "$i" -b:a 192k -vcodec libx264 -pix_fmt yuv420p -x264-params "nal-hrd=cbr" -b:v 20M -minrate 20M -maxrate 20M -bufsize 40M "${i%.*}_1.mp4"; done

Remux an MKV file into MP4

ffmpeg -i in.mkv -c:v copy -c:a copy 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

In Development

  • Automating delivery for networks
    • AdStream
      • 2s of pre-black, 5s of Slate, 2s of black, SPOT, 1s of black
    • Extreme Reach
      • 5s of Slate, 2s of black, SPOT
    • Tylie
      • 5s of Slate, 2s of black, SPOT, 1s of black
  • Converting from 23.976 to 29.97
  • Converting from HD to SD
  • Automatic Generation of Slates
  • Comparing two video files
  • QC order of 5.1 mix
  • Check for interlacing, frame rate, resolution, codec, audio bit rate, audio bit depth, audio codec
  • Automate file naming
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment