set -e
progname=$(basename $0)
usage="Usage: $progname [OPTIONS] FILE [FILE...]
-f path to font file (overrides -F)
-F font face (requires ffmpeg with --enable-fontconfig)
-t number of thumbnails, WxH (default: 4x4)
-w width of thumbnails (default: 192)
-h show this help and exit
"
die() {
[ -n "$1" ] && echo "Error: $1" || echo "$(basename $0): ffmpeg thumbnail gallery generator"
echo "$usage"
exit 1
}
tile="4x4"
width="192"
while getopts ":f:F:t:w:h" opt; do
case $opt in
f)
font=$OPTARG
;;
F)
font=${font:-$OPTARG}
;;
t)
tile=$OPTARG
;;
w)
width=$OPTARG
;;
h)
die
;;
\?)
die "Invalid option -$OPTARG"
;;
esac
done
shift $((OPTIND - 1))
[ "$#" -eq 0 ] && die "No filenames specified"
[ -z "$font" ] && die "No font specified"
thumbs=$(echo $tile | tr x \* | bc)
awkscript=$(cat << "EOT"
function format_video(idx, fmt, bitrate) {
fmt = "Stream #%d\\: %s\\, %dx%d\\, %s\\, %dkbps\\, %s"
bitrate = int(streams[idx]["bit_rate"] / 1000)
durationf = strftime("%H\\:%M\\:%S", duration, 1)
return sprintf(fmt, idx, streams[idx]["codec_name"], streams[idx]["width"],
streams[idx]["height"], streams[idx]["pix_fmt"], bitrate, durationf)
}
function format_audio(idx, fmt, bitrate) {
fmt = "Stream #%d\\: %s\\, %s\\, %dkbps"
bitrate = int(streams[idx]["bit_rate"] / 1000)
return sprintf(fmt, idx, streams[idx]["codec_name"], streams[idx]["channel_layout"], bitrate)
}
BEGIN {
FS = "[.=]"
}
/^streams/ {
gsub("\"", "", $5)
streams[$3][$4] = $5
}
/^format/ {
gsub("\"", "", $3)
duration = $3
}
END {
filter = ",\ndrawtext=fontcolor=white:text='%s':fontfile=%s:x=4:y=%d"
off = 24
for (idx in streams) {
if (streams[idx]["width"]) {
out = out sprintf(filter, format_video(idx), font, off)
off += 20
}
if (streams[idx]["channel_layout"]) {
out = out sprintf(filter, format_audio(idx), font, off)
off += 20
}
}
printf("pad=in_w:in_h+%d:0:%d", off, off)
printf(filter, filename, font, 4)
print out
}
EOT
)
for file; do
keyframes=$(ffprobe -skip_frame nokey -v error -select_streams v:0 -count_frames -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 "$file")
selection=$(($keyframes/320))
properties=$(ffprobe -v error -show_entries stream=codec_name,duration,channel_layout,nb_read_frames,width,height,pix_fmt,bit_rate:format=duration -of flat "$file" | gawk -v font="$font" -v filename="$(basename $file)" "$awkscript")
filtergraph="
select=not(mod(n\,$selection)),
scale=$width:-2,
thumbnail=20,
drawtext=fontcolor=white:shadowx=1:shadowy=1:text='%{pts\:hms}':fontfile=$font:x=w-text_w-2:y=h-text_h-2,
tile=$tile:margin=4:padding=4,
$properties"
ffmpeg -skip_frame nokey -i "$file" -vf "${filtergraph}" -frames:v 1 "$file".thumbs.png
done