ffmpeg 4.1から使えるフィルタ。overlay, stack
フィルタを合わせたようなxstack
フィルタの使い方。解像度が異なっていても使えるのが特徴で、上下左右にも映像の上にも重ねられる。重なる順番は1入力から順に上に重なる。余白部分は1入力が YUV なら [0:0:0] の濃い緑、RGB なら [0:0:0] の黒になり、フレームレートが一致しないと小さい方に合わされる。解像度が異なる複数画像を並べるのに便利。余白部分の色はfillで指定できるようになった。
overlay
フィルタのように映像の上に重ねることもできるが、透過情報は引き継げないのできれいに色が抜けない。overlay
フィルタよりも処理が早いので透過させないならこちらの方がよいが、overlay_opencl, overlay_qsv
が使えるのならその限りではない。
- 映像の上に映像をのせる overlay
- qsv 対応の ffmpeg をつくる : overlay_qsv
- 1フレームに複数のフレームを表示する tile
- Windows の ffmpeg で生放送する方法 : stack
基本コマンド
1入力の右に2入力を並べ、音声は1入力をコピーする。
ffmpeg -i input1 -i input2 -filter_complex "xstack=inputs=2:layout=0_0|w0_0:shortest=0[v]" -map [v] -map 0:a -c:a copy output
ffmpeg -i input1 -i input2 -filter_complex "xstack[v]" -map [v] -map 0:a -c:a copy output
1入力の下に2入力を並べ、音声は1入力をコピーする。
ffmpeg -i input1 -i input2 -filter_complex "xstack=inputs=2:layout=0_0|0_h0:shortest=0[v]" -map [v] -map 0:a -c:a copy output
ffmpeg -i input1 -i input2 -filter_complex "hstack[v]" -map [v] -map 0:a -c:a copy output
-stream_loop -1で映像をループ入力する。
ffmpeg -stream_loop -1 -i top_left.mp4 -i top_right.mp4 -i bottom_left.mp4 -i bottom_right.mp4 -filter_complex "[0][1][2][3]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0:shortest=1:fill=black[v]" -map [v] -map 0:a -c:a copy output
FFmpeg@a9193f7のコミットからエンコード中のファイルを読み込みできるようになったので圧縮前後の目視比較が動画出力と同時にできるようになった。
上にオリジナル、下にエンコード中のファイルを並べて再生。長い時間再生していると映像の同期がずれ始める。
ffmpeg -re -i input -map 0:v:0 -c:v libx264 -crf 45 -f null - -dec 0:0 -filter_complex [0:v][dec:0]vstack[stack] -map [stack] -c:v rawvideo -f nut - | ffplay -
左上にオリジナル、左下にcrf18、右上にcrf30、右下にcrf40のエンコード中のファイルを並べて再生。
ffmpeg -re -i input -map 0:v:0 -c:v libx264 -crf 18 -f null - -dec 0:0 -map 0:v:0 -c:v libx264 -crf 30 -f null - -dec 1:0 -map 0:v:0 -c:v libx264 -crf 40 -f null - -dec 2:0 -filter_complex "[0:v][dec:0][dec:1][dec:2]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[stack]" -map [stack] -c:v rawvideo -f nut - | ffplay -
左上にオリジナル、左下にエンコード、右上にエンコードのY差分を並べる。処理負荷が重たいので-readrate 0.5で0.5倍速にしている。
ffmpeg -readrate 0.5 -i input -map 0:v:0 -c:v libx264 -crf 45 -f null - -dec 0:0 -filter_complex "[dec:0]split[dec][y];[y]lutyuv=val:128:128[y];[0:v]lutyuv=val:128:128[0y];[0y][y]blend=c0_mode=difference128[y];[0:v][dec][y]xstack=3:0_0|0_h0|w0_0:fill=black[stack]" -map [stack] -c:v rawvideo -f nut - | ffplay -
左上にオリジナル、左下にエンコード、右上にエンコードのY差分、右下の左と右にUV差分を並べる。
ffmpeg -readrate 0.5 -i input -map 0:v:0 -c:v libx264 -crf 45 -f null - -dec 0:0 -filter_complex "[dec:0]split[dec][yuv];[yuv]extractplanes=y+u+v[y][u][v];[0:v]extractplanes=y+u+v[0y][0u][0v];[0y][y]blend=c0_mode=difference128[y];[0u][u]blend=c0_mode=difference128[u];[0v][v]blend=c0_mode=difference128[v];[0:v][dec][y][u][v]xstack=5:0_0|0_h0|w0_0|w0_h0|w0+w3_h0:fill=black[stack]" -map [stack] -c:v rawvideo -f nut - | ffplay -
公式ドキュメント:FFmpeg Filters Documentation : xstack
公式wiki:Create a mosaic out of several input videos using xstack – FFmpeg
オプション
gridで並べた映像を1つの映像に戻すフィルタにuntile
フィルタがあり、映像の数だけフレームレートが増える。
映像を分割し連続フレームにするuntile
- inputs[int]
入力ファイル数
範囲:2からINT_MAXまで
既定値:2 - layout[string]
レイアウトの指定。wは横解像度で隣の数字が入力ファイルの指定で0から。hは縦解像度で数字は横解像度と同じ。座標の数値指定も可能で横_縦
既定値:”0_0|w0_0″(横に並ぶ) - grid[image_size]
グリッドのレイアウトを横x縦で指定する。並べる映像は同じ解像度でなければならない。これを指定するとinputsは無視され、layoutとの併用はできない。使用すると既定値の2入力で2×1の横並ぶ - shortest[boolean]
一番短い入力ファイルが終わったときに強制的に終了させる
既定値:0(終了しない) - fill[string]
余白部分の色の指定。色名指定と16進数指定が出来る
既定値:”none”(YUVなら濃い緑、RGBなら黒)
応用例
-
4入力したときに
1 ,2
3, 4
の順番に並べる
"xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0"
- 4入力したときに
1,3
2,4
の順番に並べる
"xstack=inputs=4:layout=0_0|0_h0|w0_0|w0_h0"
- 4入力したときに
1
2
3
4
の順番に並べる
"xstack=inputs=4:layout=0_0|0_h0|0_h0+h1|0_h0+h1+h2"
- 6入力したときに
1, 2
3, 4
5, 6
の順番に並べる
"xstack=inputs=6:layout=0_0|w0_0|0_h0|w0_h0|0_h0+h1|w0_h0+h1"
- 9入力したときに
5,1,6
4,3,8
7,2,9
の順番に並べる
"xstack=inputs=9:layout=w3_0|w3_h0+h2|w3_h0|0_h4|0_0|w3+w1_0|0_h1+h2|w3+w1_h0|w3+w1_h1+h2"
- 1,2,3
4,5,6
7,8,9
"xstack=inputs=9:layout=0_0|w0_0|w0+w1_0|0_h0|w0_h0|w0+w1_h0|0_h0+h3|w0_h0+h3|w0+w1_h0+h3"
0_0 w0_0 w0+w1_0 0_h0 w0_h0 w0+w1_h0 0_h0+h3 w0_h0+h3 w0+w1_h0+h3 - 1,4,7
2,5,8
3,6,9
”xstack=inputs=9:layout=0_0|0_h0|0_h0+h1|w0_0|w0_h0|w0_h0+h1|w0+w3_0|w0+w3_h0|w0+w3_h0+h1”
0_0 w0_0 w0+w3_0 0_h0 w0_h0 w0+w3_h0 0_h0+h1 w0_h0+h1 w0+w3_h0+h1 - 1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16
"xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w0_h0|w0+w1_h0|w0+w1+w2_h0|0_h0+h4|w0_h0+h4|w0+w1_h0+h4|w0+w1+w2_h0+h4|0_h0+h4+h8|w0_h0+h4+h8|w0+w1_h0+h4+h8|w0+w1+w2_h0+h4+h8"
0_0 w0_0 w0+w1_0 w0+w1+w2_0 0_h0 w0_h0 w0+w1_h0 w0+w1+w2_h0 0_h0+h4 w0_h0+h4 w0+w1_h0+h4 w0+w1+w2_h0+h4 0_h0+h4+h8 w0_h0+h4+h8 w0+w1_h0+h4+h8 w0+w1+w2_h0+h4+h8 - 1,5,9,13
2,6,10,14
3,7,11,15
4,8,12,16
"xstack=inputs=16:layout=0_0|0_h0|0_h0+h1|0_h0+h1+h2|w0_0|w0_h0|w0_h0+h1|w0_h0+h1+h2|w0+w4_0|w0+w4_h0|w0+w4_h0+h1|w0+w4_h0+h1+h2|w0+w4+w8_0|w0+w4+w8_h0|w0+w4+w8_h0+h1|w0+w4+w8_h0+h1+h2"
0_0 w0_0 w0+w4_0 w0+w4+w8_0 0_h0 w0_h0 w0+w4_h0 w0+w4+w8_h0 0_h0+h1 w0_h0+h1 w0+w4_h0+h1 w0+w4+w8_h0+h1 0_h0+h1+h2 w0_h0+h1+h2 w0+w4_h0+h1+h2 w0+w4+w8_h0+h1+h2