Skip to main content

FFmpeg, ImageMagick and ExifTool cheat sheet

Commands I keep coming back to for video and photos. Install the tools with brew install ffmpeg imagemagick exiftool (the stabilizing scripts need a different ffmpeg).

See also LosslessCut for lossless cutting and merging with a GUI.

Video (FFmpeg)​

Count frames​

ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4

Images to video​

5 images per second, output 25 fps. Then copy the first image's date to the video:

ffmpeg -framerate 5 -pattern_type glob -i '*.jpg' -c:v libx264 -r 25 -pix_fmt yuv420p out.mp4
touch -r "$(ls *.jpg | head -1)" out.mp4

Add -vf reverse to play it backwards.

Shrink all videos in a folder​

720p H.264, keeping each file's date:

mkdir -p out
for file in *; do
[ -f "$file" ] || continue
ffmpeg -i "$file" -y -c:a aac -b:a 120k -vf scale=-2:720 -c:v libx264 -crf 30 -pix_fmt yuv420p "out/$file" || break
touch -r "$file" "out/$file"
done

Raise -crf for smaller files and lower quality (23 is the default, 30 is quite compressed). -pix_fmt yuv420p keeps the output 8-bit, so iPhone HDR (10-bit) videos still play everywhere.

Generate silent audio​

10 seconds of stereo silence:

ffmpeg -f lavfi -i anullsrc=r=44100:cl=stereo -t 10 -y silence.wav

Aurora timelapse from photos​

Turns a folder of photos (I used iPhone HEIC photos of the northern lights) into a smooth timelapse: converts them to JPEG, merges them at a few photos per second, stabilizes the result with vidstab, and blends frames up to 25 fps with minterpolate so it doesn't look choppy. Run it in the folder with the photos, and tweak the settings at the top.

aurora-timelapse.sh
#!/bin/bash
# Turns a folder of photos (e.g. iPhone HEIC photos of the northern lights) into a smooth, stabilized timelapse video.
# Run it in the folder with the photos. Needs ImageMagick (brew install imagemagick) and an ffmpeg with vidstab
# (Homebrew's ffmpeg doesn't have it, see the link below).
# Original: https://mifi.no/scripts/aurora-timelapse.sh
# See https://mifi.no/docs/media-cli/#aurora-timelapse-from-photos
set -e

# Stabilizing needs ffmpeg built with libvidstab
if ! ffmpeg -hide_banner -filters 2>/dev/null | grep -q vidstabdetect; then
echo "This ffmpeg has no vidstab filters, see https://mifi.no/docs/media-cli/#stabilizing-needs-vidstab"
exit 1
fi

# Photos per second. Lower is slower; the smoothing step fills in frames in between.
IMAGE_RATE=4/3
# Output size: 720 wide, height keeping the aspect ratio. Use scale=-2:720 for 720 high.
SCALE="scale=720:-2"
INPUT_GLOB='IMG_*.HEIC'

echo "Converting to JPEG"
mkdir -p jpeg-tmp
for f in $INPUT_GLOB; do
[ -f "jpeg-tmp/$f.jpg" ] || magick "$f" "jpeg-tmp/$f.jpg"
done

echo "Merging"
ffmpeg -r "$IMAGE_RATE" -pattern_type glob -i "jpeg-tmp/$INPUT_GLOB.jpg" -c:v libx264 -vf "$SCALE" -pix_fmt yuv420p -crf 15 -y merged.mp4

echo "Stabilizing"
ffmpeg -i merged.mp4 -vf vidstabdetect=stepsize=32:shakiness=10:accuracy=10:result=transform_vectors.trf -f null -
ffmpeg -i merged.mp4 -vf vidstabtransform=input=transform_vectors.trf:zoom=0:smoothing=10 -c:v libx264 -crf 15 -preset slow -an -y stabilized.mp4

echo "Smoothing (blending frames to 25 fps)"
ffmpeg -i stabilized.mp4 -vf minterpolate=fps=25:mi_mode=blend -c:v libx264 -crf 17 -pix_fmt yuv420p -y output.mp4

echo "Done: output.mp4"

Speed up and stabilize a video​

Turns a long handheld clip into a smooth hyperlapse: speeds it up (28× by default) and stabilizes it with vidstab.

speed-up-stabilize.sh
#!/bin/bash
# Speeds up a video (e.g. a long handheld clip into a hyperlapse) and stabilizes it. Audio is dropped.
# Usage: speed-up-stabilize.sh input.mp4 [speedup factor, default 28]
# Needs an ffmpeg with vidstab (Homebrew's ffmpeg doesn't have it, see the link below).
# Original: https://mifi.no/scripts/speed-up-stabilize.sh
# See https://mifi.no/docs/media-cli/#speed-up-and-stabilize-a-video
set -e

# Stabilizing needs ffmpeg built with libvidstab
if ! ffmpeg -hide_banner -filters 2>/dev/null | grep -q vidstabdetect; then
echo "This ffmpeg has no vidstab filters, see https://mifi.no/docs/media-cli/#stabilizing-needs-vidstab"
exit 1
fi

IN_FILE="$1"
SPEEDUP="${2:-28}"
[ -f "$IN_FILE" ] || { echo "Usage: $0 input.mp4 [speedup]"; exit 1; }

FAST_FILE="$IN_FILE-fast.mp4"
# The transforms file goes in a temp folder, because its path is inside a filter string (no : , or ')
TRF_FILE="$(mktemp -d)/transforms.trf"
OUT_FILE="$IN_FILE-stabilized.mp4"

ffmpeg -i "$IN_FILE" -vf "setpts=PTS/$SPEEDUP" -r 25 -an -c:v libx264 -crf 17 -preset slow -y "$FAST_FILE"

ffmpeg -i "$FAST_FILE" -vf vidstabdetect=stepsize=32:shakiness=10:accuracy=10:result="$TRF_FILE" -f null -
ffmpeg -i "$FAST_FILE" -vf vidstabtransform=input="$TRF_FILE":zoom=0:smoothing=10 -c:v libx264 -crf 17 -preset slow -an -y "$OUT_FILE"

echo "Done: $OUT_FILE"

Stabilizing needs vidstab​

The stabilizing scripts use the vidstab filters, which Homebrew's own ffmpeg is built without. Check with ffmpeg -filters | grep vidstab. To get them, replace it with the homebrew-ffmpeg build:

brew uninstall ffmpeg
brew tap homebrew-ffmpeg/ffmpeg
brew install homebrew-ffmpeg/ffmpeg/ffmpeg --with-libvidstab

Photos (ImageMagick and ExifTool)​

Shrink photos to a number of pixels​

The @ suffix resizes to a total pixel area instead of a width or height, so portrait and landscape photos end up the same size (300000 pixels is about 670×450):

shopt -s nullglob nocaseglob
for file in *.jpg *.jpeg; do
[[ "$file" == *-small.jpg ]] && continue
magick "$file" -resize 300000@ -auto-orient -quality 70 "${file%.*}-small.jpg"
touch -r "$file" "${file%.*}-small.jpg"
done

Set file dates from the photo's EXIF date​

Useful after copying photos, which often resets the file dates:

exiftool "-FileModifyDate<DateTimeOriginal" folder/

Strip all metadata​

Removes location, camera and other metadata before sharing a photo, but keeps the rotation and colour profile so it still looks right. -overwrite_original stops ExifTool from leaving a photo.jpg_original copy (with all the metadata) next to it:

exiftool -all= -tagsfromfile @ -Orientation -ICC_Profile -overwrite_original photo.jpg