【Mac】動画のスクリーンショットを書き出す

動画の内容を一覧するために、動画から 20 枚ほどの静止画を書き出すスクリプトを作ろうと思う。
 動画の長さを取得し、その秒数を 20 分割して画像を出していく。コマンドは ffmpeg を使う。

動画の長さを取得する

ffmpeg -i INPUT.mp4

とやれば、動画の長さを調べることが出来る。duration というのがそれだ。

この数字を取り出す。

ffmpeg -i INPUT.mp4 2>&1 | grep 'Duration' | awk '{print $2}' | tr -d ','

こうやれば、たとえば 3 分ちょうどの動画なら、 00:03:00.00 という具合に動画の長さが取得できる。ただ、これだと計算しづらい。できれば秒数で長さを取得したい。
 ありがたいことに、ffprobe に -show_entries format というオプションがある。実行すると以下のような結果が返ってくる。

[FORMAT]
filename=/Users/user/Movies/input.mkv
nb_streams=2
nb_programs=0
format_name=matroska,webm
format_long_name=Matroska / WebM
start_time=0.000000
duration=219.108000
size=7885345
bit_rate=287907
probe_score=100
TAG:COMPATIBLE_BRANDS=iso6avc1mp41
TAG:MAJOR_BRAND=dash
TAG:MINOR_VERSION=0
TAG:ENCODER=Lavf58.20.100
[/FORMAT]

このなかで duration の情報が欲しい場合は、format=duration というように書く。実行すると、ログの下のほうに duration が出てくる。

$ ffprobe input.mkv -show_entries format=duration

……省略

[FORMAT]
duration=219.108000
[/FORMAT]

ログがうるさく思われるので、-loglevel quiet というオプションをつけ、さらに数字だけを取り出す。

$ ffprobe INPUT.mp4 -show_entries format=duration -loglevel quiet | grep 'duration' | sed -e 's/duration\=//'
219.108000

これでとりあえず、動画の長さは取得できそうだ。

静止画を書き出す

ffmpeg で静止画を切り出すには、以下のように書く。

$ ffmpeg -ss 30 -i INPUT.mp4 -t 1 -r 1 ~/Desktop/image%02d.jpg

-ss は開始秒数。
-t は開始秒数から何秒間、切り出すかを指定する。
-r は一秒間に切り出す画像の枚数。
%02d はふた桁の連番で画像を書き出す。上の例では「image01.jpg」。

jpg ではなく png で書き出す場合は、-vcodec png と指定する。ファイルサイズは大きいが、綺麗な画像を書き出してくれる。

コツがあって、-ss というオプションは -i INPUT.mp4より前に書く。ffmpeg -i INPUT.mp4 -ss 30 とやると、開始秒数を探す時間が異様にかかるのだ。

シェルスクリプト

以上をふまえて、シェルスクリプトを書いた。

📝 dogaImg.sh
#!/bin/bash
#
# dogaImg.sh 動画パス
#
# というように使う。
# 動画と同じディレクトリにフォルダを作ってイメージを書き出す。

nagasa=`ffprobe "$1" -show_entries format=duration -loglevel quiet | grep 'duration' | sed -e 's/duration\=//'`
duration=`echo ${nagasa%.*}`

if test $duration -ge 20; then
	atama=`echo $((duration / 20))`
	bunkatu=20
else
	atama=1
	bunkatu="$duration"
fi

mkdir "${1%.*}"
saveLoc="${1%.*}"

for INT in `seq 1 $bunkatu`
do
	Next=`echo $((atama * INT))`
	ffmpeg -ss $Next -i "$1" -t 1 -r 1 -loglevel quiet "$saveLoc"/image"$INT".jpg
done

20 秒以下の動画の場合は、一秒につき一枚の画像を書き出すようにした。

単純に、動画の一場面を書き出したい場合は、command + shift + 4 のショートカットのあとスペースキーを押して QuickTime Player の画面を選択するのがいいと思う。
 あえて ターミナルでやるなら、bashrc とかに関数を書いておくのがいいかもしれない。

function mpng() {
	ffmpeg -ss "$2" -i "$1" -t 1 -r 1 -vcodec png -loglevel quiet ~/Desktop/image%02d.png
}

こんな感じだろうか。上の例だと mpng INPUT.mp4 00:03:00 という書き方になる。