映像を重ねてワイプを作ったり、重ねた映像を動かしたりできる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に動かす内容、zx時間外には動かさない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 -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=alpha=0、Rが透過具合によって減少

overlay=alpha=1、Rだけに少しづつGBが加算

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

公式ドキュメント:FFmpeg Filters Documentation : overlay_opencl

One thought on “映像の上に映像をのせる overlay”

動画を合成する方法 (overlay) [FFmpeg] – Site-Builder.wiki へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)