映像を重ねてワイプを作ったり、重ねた映像を動かしたりできるoverlay
フィルタの使い方。1入力目の映像が背景になり、2入力目の映像が最初に入力された映像の上に表示される。2入力目に透過情報があればその部分に背景にとなる1入力目の映像が映る。
透過部分に関係なく複数の映像を任意の割合で混ぜるならmix
フィルタを使う。
複数の映像を任意の割合でミックスする mix
目次
基本コマンド
input1の中央にinput2の中央を配置。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=(W-w)/2:y=(H-h)/2" -c:a copy output
右下隅から左上10ピクセルに配置。
"overlay=x=main_w-overlay_w-10:y=main_h-overlay_h-10"
右上から左上に向かって1フレーム1ピクセル移動する。
"overlay=x=W-n:y=0"
動画上に画像をオーバーレイする。画像はループ入力する。
ffmpeg -i video.mp4 -loop 1 -i img.jpg -filter_complex "overlay=x=(W-w)/2:y=(H-h)/2:shortest=1:format=rgb,scale=out_color_matrix=bt709:out_range=tv" -c:v libx264 -crf 21 -pix_fmt yuv420p -bsf:v h264_metadata=video_full_range_flag=0:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 -c:a copy output.mp4
JPG画像をlut
フィルタで8ビットにおける半分に透過させて映像にオーバーレイする。出力が一般的な動画ではなく画像なら最後のformat
フィルタは不要。
ffmpeg -i video.mp4 -loop 1 -i img.jpg -filter_complex "[1]format=yuva420p,lut=a=128[logo];[0][logo]overlay=(W-w)/2:(H-h)/2:shortest=1::format=rgb,scale=out_color_matrix=bt709:out_range=tv" -c:v libx264 -crf 21 -pix_fmt yuv420p -bsf:v h264_metadata=video_full_range_flag=0:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 -c:a copy output.mp4
PNG画像をlut
フィルタで8ビットにおける半分に透過させて映像にオーバーレイする。出力が一般的な動画ではなく画像なら最後のformat
フィルタは不要。
ffmpeg -i video.mp4 -loop 1 -i img.png -filter_complex "[1]format=rgba,lut=a=128[logo];[0][logo]overlay=(W-w)/2:(H-h)/2:shortest=1:format=rgb,scale=out_color_matrix=bt709:out_range=tv" -c:v libx264 -crf 21 -pix_fmt yuv420p -bsf:v h264_metadata=video_full_range_flag=0:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 -c:a copy output.mp4
How to add transparent watermark in center of a video with ffmpeg? – Stack Overflow
ffmpeg overlay png on video has color issue – Stack Overflow
映像が2種類あり音声も2種類含まれるときに、どちらかの音声を選ぶには-mapを使う。例はinput2の音声を選んでいる。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=(W-w)/2:y=(H-h)/2" -map 1:a -c:a copy output
-mapの使い方:ffmpeg | 識別子の指定方法
動画をループ入力する。つまり出力時間-tを指定しないとエンコードが終わらない。配信映像をループさせるようなときに使う。しかし同じ映像をループさせるなら予めオーバーレイさせた動画を出力したのをループした方が処理がはやい。-fflags +genptsは2ループ目以降のPTSを振り直している。
ffmpeg -stream_loop -1 -i video.mp4 -loop 1 -fflags +genpts -i img.jpg -filter_complex "overlay=x=(W-w)/2:y=(H-h)/2" -t 100 output
ffmpeg で無限入力が可能に
ループ回数を指定できる loop, aloop
1枚画像どうしを入力して1枚画像にする場合にはループ入力しなくてよい。
ffmpeg -i img1.jpg -i img2.jpg -filter_complex "overlay=x=(W-w)/2:y=(H-h)/2" output.jpg
アニメGIF、APNGは-ignore_loop 0を付けると無限ループする。アニメWebpはデコードできない。
ffmpeg -i video.mp4 -ignore_loop 0 -i img.gif -filter_complex "overlay=x=(W-w)/2:y=(H-h)/2:shortest=1:format=rgb,scale=out_color_matrix=bt709:out_range=tv" -c:v libx264 -crf 21 -pix_fmt yuv420p -bsf:v h264_metadata=video_full_range_flag=0:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 -c:a copy output.mp4
高ビット深度の素材でウォーターマーク(透かし)画像をつけるにはformatの指定を元となる映像と揃える。8ビット画像しかないとき高ビット深度に変換する必要はない。
ffmpeg -i input -filter_complex "movie=wm.png,[0:v]overlay=format=yuv420p10" -c:a copy output
ffmpeg -i input -filter_complex "movie=wm.png,[0:v]overlay=format=yuv422p10" -c:a copy output
「EOF timestamp not reliable」のエラーログは気にしなくてもよい。
video streaming – ffmpeg error during encoding: EOF timestamp not reliable – Stack Overflow
エラーをなくすなら:loop=0:discontinuity=0,setpts=N/FRAME_RATE/TBを追加する。
ffmpeg -i input -filter_complex "movie=wm.png:loop=0:discontinuity=0,setpts=N/FRAME_RATE/TB,[0:v]overlay=format=yuv420p10" -c:a copy output
ffmpeg -i input -filter_complex "movie=wm.png:loop=0:discontinuity=0,setpts=N/FRAME_RATE/TB,[0:v]overlay=format=yuv422p10" -c:a copy output
透過部分だけに色を付ける
ffmpeg で動画にロゴ画像を追加し透過させる
公式ドキュメント:FFmpeg Filters Documentation : overlay
オプション
- x[string]
オーバーレイする映像の左上の横座標。(W-w)/2で中央。評価式が使える - y[string]
オーバーレイする映像の左上の縦座標。(H-h)/2で中央。評価式が使える - eof_action[int]
2入力した映像が終了したときの1入力した映像の挙動指定。framesync を参照 - eval[int]
x、yで指定した値どのように更新するか - 0, init:最初に決めたら更新しない
- 1, frame:フレーム毎に更新。既定値
- shortest[boolean]
時間の短いファイルが最後まで処理したら終了する。そのほかのオプションは framesync を参照
既定値:0(終了しない) - format[int]
出力フォーマットの指定。映像がyuv420でないときは1入力の映像に合わせて指定する。Stack Overflow - 0, yuv420:既定値
- 1, yuv420p10
- 2, yuv422
- 3, yuv422p10
- 4, yuv444
- 5, rgb
- 6, gbrp
- 7, auto
- repeatlast[boolean]
時間の短いファイルが最後まで処理し、時間の長いファイルが最後まで処理し終わるまで、時間の短いファイルの最終フレームを繰り返す
既定値:1(終了する) - alpha[int]
合成モードの指定。詳しくは後述 - 0, straight:unpremultiplied, non-premultipliedとも言う。既定値
- 1, premultiplied
評価式
ffmpeg で使える評価式を使って複雑な計算ができる。
- main_w, W:1入力目の横の解像度
- main_h, H:1入力目の縦の解像度
- overlay_w, w:2入力目の横の解像度
- overlay_h, h:2入力目の縦の解像度
- x:xで指定した値
- y:yで指定した値
- hsu:水平方向のクロマサブサンプル値。yuv422pなら2
- vsub:垂直方向のクロマサブサンプル値。yuv422pなら1
- n:1から始まるフレーム番号
- pos:映像のバイトサイズの位置。不明ならNAN
- t:0から始まるタイムスタンプ秒。1フレーム目の経過時間が最初の値になる。不明ならNAN
応用例
タイムスタンプのエラーが出るときには2入力ともにsetpts=PTS-STARTPTS
フィルタを当てて開始時間を0秒からにする。
ffmpeg -i input1 -i input2 -filter_complex [0:v]setpts=PTS-STARTPTS[0v];[1:v]setpts=PTS-STARTPTS[1v];[0v][1v]overlay="x=(W-w)/2:y=(H-h)/2" output
指定時間帯で表示する
xが0であればzを返す、そうでなければyを返すif(x,y,z)を使う。xに表示する時間帯、yに動かす内容、zはx時間外には動かさないNANを指定する。以下の例は 0.5秒以上で1秒に65ピクセル上に移動する。
ffmpeg -i input1 -i input2 -filter_complex overlay=y='if(gte(t\,0.5)\,((H/2)-h-t*65))' -c:a copy output
animation – Add moving overlay on video with ffmpeg – Stack Overflow
任意の時間で隅から隅に移動する
「隅」の項以下の例は移動計算にフレーム番号であるnを使っているが、1入力目(背景)の映像の解像度の隅から隅へ任意の秒時間で移動するには1入力目と2入力目の解像度の和にtを掛けて任意の時間で割る。
5秒で右から左に移動:((w+W)*t)/5
5秒で上から下に移動:((H+h)*t)/5
右上から見切れずに左上に5秒間でループ。厳密には1ループ目が消えるまでが5秒なので2ループ目の横幅分は右端にすでに表示している。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=W-mod(((w+W)*t)/5\,2*W):y=0[o];[o][1:v]overlay=x='W-mod(gt(((w+W)*t)/5-W\,0)*(((w+W)*t)/5-W)\,2*W)':y=0" output
ループ時間を任意の時間に遅らせるには遅らせる時間だけ減算する。gt()を使って負の時間を0秒扱いにしている。
0秒から5秒まで:((w+W)*t)/5
5秒から10秒まで:((w+W)*(gt(t-5\,0)*(t-5)))/5
隅
隅 | x | y |
左上隅 | 0 | 0 |
右上隅 | W-w | 0 |
左下隅 | 0 | H-h |
右下隅 | W-w | H-h |
指定秒毎に4隅へ移動する。例は30秒ごとに右下から反時計回りに移動する。
横座標は0から60秒まではW-w-W*10/100。60から120秒まではW*10/100。
縦座標は0から30秒まではH-h-H*5/100。30から90秒まではH*5/100。90から120秒まではH-h-H*5/100。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x='if(lt(mod(t\,120)\,60)\,W-w-W*10/100\,W*10/100)':y='if(lt(mod(t+30\,120)\,60)\,H-h-H*5/100\,H*5/100)'" output
ffmpeg – Shifting overlay position every x seconds – Stack Overflow
video – How to overlay logo in all edges in FFMPEG – Super User
ループ
表示方法は2通りあり、端に見切れ始めてすべて見切れたときに再び表示される場合と、見切れたら同時に再び表示する場合がある。後者は同時に2つの映像がオーバーレイされているので2度overlay
フィルタを当てる。
右上から左上にループ。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=W-mod(n\,W+w):y=0" output
1表示ループ | x | y |
左から右 | -w+mod(n\,W+w) | |
右から左 | W-mod(n\,W+w) | |
下から上 | H-mod(n\,H+h) | |
上から下 | -h+mod(n\,H+h) |
右上から見切れずに左上にループ。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=W-mod(n\,2*W):y=0[o];[o][1:v]overlay=x=W-mod(gt(n-W\,0)*(n-W)\,2*W):y=0" output
2表示ループ | x | x |
左から右 | -w+mod(n\,2*W) | -w+mod(gt(n-W\,0)*(n-W)\,2*W) |
右から左 | W-mod(n\,2*W) | W-mod(gt(n-W\,0)*(n-W)\,2*W) |
2表示ループ | y | y |
下から上 | H-mod(n\,2*H) | H-mod(gt(n-H\,0)*(n-H)\,2*H) |
上から下 | -h+mod(n\,2*H) | -h+mod(gt(n-H\,0)*(n-H)\,2*H) |
対角線
左上から右下。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=-w+((W+w)/(H+h))*n:y=-h+n" output
左下から右上。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=-w+((W+w)/(H+h))*n:y=H-n" output
対角線 | x | y |
左上から右下 | -w+((W+w)/(H+h))*n | -h+n |
右上から左下 | W-((W+w)/(H+h))*n | -h+n |
左下から右上 | -w+((W+w)/(H+h))*n | H-n |
右下から左上 | W-((W+w)/(H+h))*n | H-n |
時計回り、反時計回りに回転
適宜+-60の部分とsin()、cos() を入れ換えれば開始位置と回転方法を変えられる。回転速度は*nを変更する。
中央右60ピクセルから時計回りに回る。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=(W-w)/2+60*cos((PI*n)/180):y=(H-h)/2+60*sin((PI*n)/180)" output
中央右60ピクセルから反時計回りに回る。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=(W-w)/2+60*cos((PI*n)/180):y=(H-h)/2-60*sin((PI*n)/180)" output
中央上60ピクセルから時計回りに回る。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=(W-w)/2+60*sin((PI*n)/180):y=(H-h)/2-60*cos((PI*n)/180)" output
中央上60ピクセルから反時計回りに回る。
ffmpeg -i input1 -i input2 -filter_complex "overlay=x=(W-w)/2-60*sin((PI*n)/180):y=(H-h)/2-60*cos((PI*n)/180)" output
円 | x | y |
中央 | (W-w)/2 | (H-h)/2 |
時計回り、右 | (W-w)/2+60*cos((PI*n)/180) | (H-h)/2+60*sin((PI*n)/180) |
反時計回り、右 | (W-w)/2+60*cos((PI*n)/180) | (H-h)/2-60*sin((PI*n)/180) |
反時計回り、左 | (W-w)/2-60*cos((PI*n)/180) | (H-h)/2+60*sin((PI*n)/180) |
時計回り、左 | (W-w)/2-60*cos((PI*n)/180) | (H-h)/2-60*sin((PI*n)/180) |
時計回り、上 | (W-w)/2+60*sin((PI*n)/180) | (H-h)/2-60*cos((PI*n)/180) |
反時計回り、上 | (W-w)/2-60*sin((PI*n)/180) | (H-h)/2-60*cos((PI*n)/180) |
時計回り、下 | (W-w)/2-60*sin((PI*n)/180) | (H-h)/2+60*cos((PI*n)/180) |
反時計回り、下 | (W-w)/2+60*sin((PI*n)/180) | (H-h)/2+60*cos((PI*n)/180) |
alpha モード
オーバーレイする動画に予め透過具合に応じて色を変更するのがpremultiplied。
詳しい話は外部記事で。
- コンポジターに必要なアルファチャンネルの知識(前編) – コンポジゴク
- コンポジターに必要なアルファチャンネルの知識(後編) – コンポジゴク
- FFmpegで重ねた物にフリンジが出る場合はunpremultiplyフィルターで解決…なのか? #ffmpeg – Qiita
- ffmpeg rotate image shows aliasing and smudging – Super User
ffmpeg -f lavfi -i color=red,format=rgba,geq='p(X,Y):p(X,Y):p(X,Y):clip(255-sqrt(pow(X,2)+pow(Y,2)),0,255)',lutrgb=255:val:val:val -vframes 1 red.png ffmpeg -f lavfi -i color=gray,format=rgba -vframes 1 gray.png ffmpeg -i gray.png -i red.png -filter_complex "overlay=alpha=0:format=rgb" overlay-alpha0.png ffmpeg -i gray.png -i red.png -filter_complex "overlay=alpha=1:format=rgb" overlay-alpha1.png
overlay_opencl
openclを使ってoverlay_opencl
フィルタを使う。
openclが使えれば以下のコマンドを実行すると対応CPU、またはGPUが表示される。
ffmpeg -hide_banner -v verbose -init_hw_device opencl
出力コマンド例。
ポイントはopenclを使うデバイスを上の例では0.0から1.1から指定する。能力によって処理速度が大きく異なる。オプション指定は通常と同じ。
コマンド例。ポイントは2入力ともhwupload
フィルタを使う。
ffmpeg -init_hw_device opencl=ocl:1.0 -filter_hw_device ocl -i video.mp4 -loop 1 -i img.png -filter_complex "[0:v]hwupload[0v];[1:v]format=yuva420p,hwupload[1v];[0v][1v]overlay_opencl" output
通常のフィルタに切り替えるにはhwdownload,format=yuv420p
フィルタを挟む。
ffmpeg -init_hw_device opencl=ocl:1.0 -filter_hw_device ocl -i video.mp4 -loop 1 -i img.png -filter_complex "[0:v]hwupload[0v];[1:v]format=yuva420p,hwupload[1v];[0v][1v]overlay_opencl,hwdownload,format=yuv420p,lutyuv=val:128:128 output
[…] overlay – 映像の上に映像をのせる | ニコラボ […]