Open3

FFmpegのRGB->YUV変換対応

FFmpegでpngを合成してmp4を生成する時にRGBの色空間を持つソースと生成されるmp4のYUVの色空間がデフォルトだと変換がイマイチで全体的に明るめの色になってしまう。

例えばこんな感じのコマンドだと発生する。

ffmpeg -r 15 -i img%03d.png -vcodec libx264 -pix_fmt yuv420p output.mp4

公式のcolorspaceについての記述を読むと、どうもYUV->YUV変換はcolorspace,colormatrixオプションだけでなんとか出来るけどrgb->YUVの変換はswscaleというフィルタが必要らしい。

そのドキュメントを参考に試しにこんな感じのfilterでmp4の生成を試すと確かに色味が明るくなる現象は避けられた。

ffmpeg -stream_loop -1 -i base.png -stream_loop -1 -i overlay.png -sws_flags spline+accurate_rnd+full_chroma_int \
-filter_complex "[1:v] format=yuva444p,colorspace=bt709:iall=bt601-6-525:fast=1[a];[a][0:v] overlay=100:100" \
-color_range 1 -colorspace 1 -color_primaries 1 -color_trc 1 -codec:a copy -t 3 -y output.mp4

ただしこれだとRGB->YUVの変換しか出来なくてアルファチャンネルが無視されてしまうので、例えば背景が透明な画像は白背景になってしまったりする。

これを避けるにはalphaextractというalphaチャンネルを待避してくれるフィルタを使う。公式Documentを読んでも使い方が全くわからんのでニコラボを読むと良い。

https://nico-lab.net/extractplanes_with_ffmpeg/

このフィルタを使ってcolorspace変換をし、alphaをextractしてalphamerge、そんでそのあとはお好きなようにscaleとかrotateをやってoverlayして合成とかやれば良いという流れ。例えばこんな感じ。

ffmpeg -stream_loop -1 -i base.png -stream_loop -1 -i overlay.png -sws_flags spline+accurate_rnd+full_chroma_int -filter_complex "[1:v] format=yuva444p,colorspace=bt709:iall=bt601-6-525:fast=1[alphaee1];[1:v]format=rgba,alphaextract[alpha1];[alphaee1][alpha1]alphamerge[alphaed1];[alphaed1]scale=374.0:56.0,setsar=1,rotate=0.0:c=black@0:ow=rotw(0.0):oh=roth(0.0)[rotate1];[0:v][rotate1] overlay=45.5+(374.0-56.0*sin(0.0)-374.0*cos(0.0))/2:177.5-(((374.0*sin(0.0)+56.0*cos(0.0)))/2-56.0/2) [merged];[merged] scale=512:-2" -color_range 1 -colorspace 1 -color_primaries 1 -color_trc 1 -codec:a copy -t 3 -y output.mp4

注意としてはalphaextractにはその対象となる画像等のformatを適切に指定すること。自分の場合だとpngでformat=rgbaを指定しないといけなかった。これを忘れると下記のようなエラーが出る。formatに何を指定すればいいかは対象になる画像/動画をffprobeしたりすると良いはず。

[Parsed_alphaextract_5 @ 0x7f954f407c00] Requested planes not available.
[Parsed_alphaextract_5 @ 0x7f954f407c00] Failed to configure input pad on Parsed_alphaextract_5
ログインするとコメントできます