対象読者
以下のように、動画を 100 分割して 1 画面 100 分割表示させたい方を対象としています。
やり方
10x10.sh
## USAGE: sh 10x10.sh input.mp4
ffmpeg -i "$1" -filter_complex '[0:a]asplit=100'`seq -s '' -f '[a%02g]' 0 99`';[0:v]scale=192:-1,split=100'`seq -s '' -f '[v%02g]' 0 99`';'`ffprobe "$1" -hide_banner -show_entries format=duration | perl -ne 'next if not m{^duration=(.*)$}; printf q([v%1$02d]trim=%2$f:%3$f,setpts=PTS-STARTPTS[v%1$02d];[a%1$02d]atrim=%2$f:%3$f,asetpts=PTS-STARTPTS[a%1$02d];), $_, $1*$_/100, $1*($_+1)/100 for (00 .. 99);'``seq -s '' -f '[v%02g]' 0 99`'xstack=inputs=100:layout='"`perl -e 'for $y (0 .. $ARGV[1] - 1) { $h = ($y ? qq($h+h0) : 0); for $x (0 .. $ARGV[0] - 1) { $w = ($x ? qq($w+w0) : 0); push @o, qq(${w}_$h) } } END { print join q(|), @o }' 10 10`"':shortest=1[v];'`seq -s '' -f '[a%02g]' 0 99`'amix=inputs=100:duration=shortest,loudnorm[a]' -map '[v]' -map '[a]' -shortest output.mp4 -y
上記を保存して、sh 10x10.sh input.mp4
と実行すると、input.mp4
から output.mp4
ができます。バージョン 4.3.1 の ffmpeg
ffprobe
と perl
seq
を使っています。perl
や seq
は filter 文を生成しているだけです。
処理の流れ
ffmpeg
-i 'input.mp4'
-filter_complex '
[0:a]asplit=100[a00](中略)[a99];
[0:v]scale=192:-1,split=100[v00](中略)[v99];
[v00]trim=0.000000:18.099510,setpts=PTS-STARTPTS[v00];[a00]atrim=0.000000:18.099510,asetpts=PTS-STARTPTS[a00];
(中略)
[v99]trim=1791.851490:1809.951000,setpts=PTS-STARTPTS[v99];[a99]atrim=1791.851490:1809.951000,asetpts=PTS-STARTPTS[a99];
[v00](中略)[v99]xstack=inputs=100:layout=0_0|0+w0_0|(中略)|0+w0+w0+w0+w0+w0+w0+w0+w0+w0_0+h0+h0+h0+h0+h0+h0+h0+h0+h0:shortest=1[v];
[a00](中略)[a99]amix=inputs=100:duration=shortest,loudnorm[a]
'
-map '[v]'
-map '[a]'
-shortest
output.mp4
-y
video [v]
の処理
- scale: 出力は横 1920px 想定なので、ここで 192px にしています。
- split: ここで 100 個になります。
- 各入力毎の処理:
ffprobe
から取得した duration で、それぞれの video input をオリジナルの 1/100 の長さにしています。 - xstack: 100 個を左上から順に並べます。全入力同じ大きさなので、位置計算には w0 と h0 しか使ってません。
audio [a]
の処理
- asplit: ここで 100 個になります。
- 各入力毎の処理:
ffprobe
から取得した duration で、それぞれの audio input をオリジナルの 1/100 の長さにしています。 - amix: 100 個の音声をミックスします。
- loudnorm: そのままだと音声が大分小さくなるので、ノーマライズします。