ffmpeg shortcuts in 2026

I have a couple of one-offs that I use when working with the videos that I’ve taken. I either need to do one thing or another, but I keep coming back to a couple basic actions.

This is my dump of my FFmpeg shorts.

Animated Gifs

Usually I’m creating “many” animated gifs, and I wasn’t exactly sure of dimensions, size, or framerate so a loop was always relevant. This typically gets embedded in a bash script, where $1 is the parameter passed into the script. Adjust the HEIGHT or FPS variables as needed, but these values always gave me good results.

for HEIGHT in "450" "300" "150"; do
  for FPS in "15" "10" "5"; do
    ffmpeg -i "$1" -filter_complex "[0:v] fps=$FPS,scale=$HEIGHT:-1:flags=lanczos,split [a][b];[a] palettegen [p];[b][p] paletteuse" "$1"_"$HEIGHT"_"$FPS".gif
  done
done

Infinite Loop

Good, short videos, especially for website backgrounds, can get looped easily and cleanly with the right set of commands. It’s really a 2-step process: (1) reverse the video, (2) concatenate the videos. $1 being the source filename.

# make reverse
ffmpeg -i "$1" -vf reverse rev_"$1"

# ffmpeg
ffmpeg -i "$1" -i rev_"$1" \
 -filter_complex "[0:v:0][1:v:0]concat=n=2:v=1[outv]" \
 -map "[outv]" vidlooper.mp4

There are two ways to do the concatenation, with the first using the “concat” filter and a list of files as the input. The second way is the recommended way to concatenate files of separate codecs which has better results than using the filter alone.

Streaming Video

This one got a bit complicated the more I learned of it. The final result is so I can use video.js to stream large videos, like a vimeo or youtube channel.

The input is $1, and two additional parameters I’ve adapted: $VIDEOFOLDER is the name of the folder to place all files, and $FILENAME9 is the first 9 digits of the file hash of the video to make the end result filenames unique across a large swatch of videos I’ve had to encode.

ffmpeg \
  -i "$1" \
  -filter_complex '[0:v]split=1[v1]; [v1]copy[v1out];' \
  -map [v1out] \
  -c:v:0 libx264 \
  -x264-params nal-hrd=cbr:force-cfr=1 \
  -b:v:0 5M \
  -maxrate:v:0 5M \
  -minrate:v:0 5M \
  -bufsize:v:0 10M \
  -preset slow \
  -g 48 \
  -sc_threshold 0 \
  -keyint_min 48 \
  -map a:0 \
  -c:a:0 aac \
  -b:a:0 128k \
  -ac 2 \
  -f hls \
  -hls_time 15 \
  -hls_playlist_type vod \
  -hls_flags independent_segments \
  -hls_segment_type mpegts \
  -hls_segment_filename "$VIDEOFOLDER/$FILENAME9-data%04d.ts" \
  -master_pl_name "$FILENAME9-master.m3u8" \
  -var_stream_map v:0,a:0 \
  "$VIDEOFOLDER"/"$FILENAME9".m3u8

Video Dimensions

Programmatically I can pull dimensions of a video with ffprobe, and even determine if the multimedia file is a video or not due to the lack of data returned. The only data returned is comma-separated.

ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$1"

Leave a Reply