動画のキャプチャ画像を生成する

●動画から任意の秒数毎にキャプチャし、必要であればタイル画像に合成する。

require ffmpegImageMagick
usage: capture.sh –interval=60 –tile=300 –column=5 <動画パス>

#!/bin/sh
### capture image from movie file.

# defines default values
interval=60
bg=black
start=1
column=4
imagetype=png
vcodec=png
tile=
tiletype=jpg
crop=0+0
cut=
odir=.
leave=

if [ -n "$*" ] ; then
	for arg in "$@"
	do
		eval `echo "$arg" | sed -r -n 's/^--(interval|bg|start|column|imagetype|vcodec|tile|tiletype|crop|cut|odir|leave)=(.+)$/\1=\"\2\"/p'` 
	done
	eval moviepath=\$$#
fi

if [ -z "$moviepath" -o ! -e "$moviepath" ] ; then
  cat << __EOS__ 1>&2 
specified movie file is not exits.
usage: capture.sh <options> movie_file_path
options: 
  --start=1       :skip beginning second...
  --odir=.        :output directory path (no need last slash)
  --interval=60   :interval seconds to capture
  --crop=0+0      :crop pixels ( ex. 140+5 means crop top&bottom 140px,left&right 5px )
  --imagetype=png :suffix for output capture image.(no need dot)
  --vcodec=png    :ffmpeg option for output capture vcodec
  --tile=         :each pixel width of capture images if you want.
  --tiletype=jpg  :output tiled image type
  --bg=black      :background color if -tile is specied
  --column=4      :column nums if -tile is specied
  --cut=          :y means throw away the last remaindered images when tile is available
  --leave=        :y means leave thumbnail files when tile is specified
__EOS__
	exit 1
fi
if [ ! -d "$odir" ]; then
  mkdir -p "$odir"
fi

odir=${odir}/caps.$$
mkdir -p "$odir"

info=`ffprobe -show_streams "$moviepath" 2> /dev/null | sed -n -r '/^(duration|width|height|display_aspect_ratio)=/p'`

duration=`echo $info | grep -oP '(?<=duration=)\d+' | head -n 1`
if [ -z "$duration" ] ; then
  evalstr=`ffprobe "$moviepath" 2>&1 | sed -n -r 's/^.*Duration: ([0-9]+):([0-9]+):([0-9]+).*$/eval expr \1 \\\* 3600 + \2 \\\* 60 + \3/p'`
  duration=`$evalstr`
fi
 
mwidth=`echo $info | grep -oP '(?<=width=)\d+' | head -n 1`
mheight=`echo $info | grep -oP '(?<=height=)\d+' | head -n 1`
aspect=`echo $info | grep -oP '(?<=display_aspect_ratio=)\d+:\d+'`

aw=`echo $aspect | sed -r 's/([0-9]+):([0-9]+)/\1/'`
ah=`echo $aspect | sed -r 's/([0-9]+):([0-9]+)/\2/'`

if [ $aw -gt 0 -a $ah -gt 0 ] ; then
  mwidth=`expr $mheight \* $aw \/ $ah`
fi

if [ "$start" -gt "$duration" ] ; then
	echo skip seconds over duration... 1>&2
	exit 1
fi
echo -n "Input end point(default $duration): "
read cin
if [ -n "$cin" ]; then
	if expr $cin + 1 > /dev/null 2>&1 ; then duration=$cin; fi
fi
if [ "$duration" -lt "$start" ] ; then
	echo end seconds letter than start second... 1>&2
	exit 1
fi

cropw=`echo $crop | sed -n -r 's/^([0-9]+)\+([0-9]+)$/\2/p'`
croph=`echo $crop | sed -n -r 's/^([0-9]+)\+([0-9]+)$/\1/p'`
crop=`echo $crop | sed -n -r '/^[0-9]+$/p'`

if [ -z "$cropw" -a -z "$croph" -a -n "$crop" ] ; then
	croph="$crop"
fi
if [ -z "$cropw" ] ; then cropw=0 ; fi
if [ -z "$croph" ] ; then croph=0 ; fi

crop_mheight=$mheight
if [ $croph -gt 0 ] ; then
 	crop_mheight=`expr $mheight - 2 \* $croph`
fi
crop_mwidth=$mwidth
if [ $cropw -gt 0 ] ; then
 	crop_mwidth=`expr $mwidth - 2 \* $cropw`
fi

if [ $cropw -gt 0 -o $croph -gt 0 ] ; then
	geometry=${crop_mwidth}x${crop_mheight}+${cropw}+${croph}
fi

movieext=`echo "$moviepath" | grep -Eo '\..+$'`
moviebase=`basename "$moviepath" "$movieext"`
for i in `seq $start $interval $duration`; do
	thumbfile=`printf "${odir}/%s-%05d.${imagetype}" "$moviebase" $i`
  ffmpeg -y -v error -ss $i -i "$moviepath" -vframes 1 -vcodec $vcodec -s ${mwidth}x${mheight} "$thumbfile"
  if [ -n "$geometry" ] ; then
			mogrify -crop $geometry "$thumbfile"
	fi
	echo Generated $thumbfile ... 2>&1
done

echo Generated thumbnails done.
if [ -n "$tile" ] ; then
  srcfiles=$(find "${odir}" -type f -name "${moviebase}*.${imagetype}" | sed -e 's/^/"/' -e 's/$/"/')
  filenum=$(echo "$srcfiles" | wc -l)
	if [ "$cut" = "y" ] ; then
    cutnum=$(expr $filenum % $column) 
    if [ $cutnum -ne 0 ] ; then
      srcfiles=$(echo "$srcfiles" | head -n -$cutnum) 
      filenum=$(expr $filenum - $cutnum)
    fi
	fi
	tmptile="/tmp/tmp-tile-image.$$.$tiletype"
  thumfiles=$(echo $srcfiles)
  eval montage $thumfiles -geometry ${tile}x+0+0 -tile ${column}x -background $bg -monitor $tmptile
	mv $tmptile "${odir}/../${moviebase}.$tiletype"

	if [ "$leave" != 'y' ] ; then
	  echo deleting $odir ... 1>&2
	  rm -fr "$odir"
		exit 0
	fi
fi
mv "$odir" "${odir}/../${moviebase}_$$"

exit 0