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.
#!/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.
#!/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