【ffmpeg】動画から特定フレームを画像で出力する方法

ffmpeg のフィルタの fps, trim, select, framestep, thumbnail などを使い分けながら、動画の I, P, B フレームだけを出力したり、指定秒や指定フレーム間を出力する。

コマンドサンプルには付いているが、コマンドの個別説明で書いてない-vsync vfr、ffmpeg 5.1以降は-fps_mode vfrを付け忘れると2枚目以降のファイルが大量に複製されるので注意すること。

ffmpeg Documentation : Advanced options


連番画像を出力する


出力ファイル名に %03d をつけることで3桁の連番で画像を出力できる。画像のフォーマットは.jpgに変えることでJPGで出力できる。

ffmpeg -i video -an -vsync vfr img%03d.png


出力例
img001.png
img002.png
img003.png

このままだと動画の全フレームを画像で出力することになりファイル数が膨大になるのでその他のオプションも指定する。ここでは一つ下で説明する tileフィルタを使う。

%03d の他に、%02d にすると最初から表示される値が2桁になる。

出力時の開始番号を1ではなく0にするには -start_number 0 を指定する。100 ならば -start_number 100 を指定する。

ffmpeg -i video -start_number 0 -an -vsync vfr img%03d.png


出力例
img000.png
img001.png
img002.png

出力に-flags +global_headerをつけてもよいかもしれない。
ffmpeg -i input -flags +global_header -an -vsync vfr img%03d.png


avformat/img2: Add support for AVIF mux in image2 · FFmpeg/FFmpeg@dd99d34

出力ファイルの拡張子を .jpg にしたときに、何も設定しなければ最適な品質指定で変換される。個別に指定する場合には -qscale:v [num] で 1 から 31 までの数値を指定する。小さい値ほど高画質・低圧縮・大容量で何も指定しなければ frame= 1 fps=0.0 q=17.2 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=0.321x のようにコンソールに表示され、q=17.2 の部分が -qscale:v、または -q:v で指定した値になる。

ffmpeg -i video -an -vsync vfr -qscale:v 15 img%03d.jpg


JPEG のエンコードは MJPEG エンコーダが使われて、通常はビットレートが200 kbps に指定されているので -q:v だけでは品質指定が不正確で -qmin, -qmax も併用し同じ値を指定する。(追記:2019年12月28日)

ffmpeg -i video -an -vsync vfr -qscale:v 15 -qmin 15 -qmax 15 img%03d.jpg


ffmpeg video to jpg frames poor quality - Stack Overflow
How can I extract a good quality JPEG image from a video file with ffmpeg? - Stack Overflow

-vframes(-frames:v) 100 のようにすれば出力フレーム数を指定できる。

ffmpeg -i video -an -vsync vfr -vframes 100 img%03d.jpg


デバイス入力するときにファイルの書き込み時間ではなく、実際のキャプチャ時間をファイル名にする。

ffmpeg -f dshow -rtbufsize 100M -video_size 1920x1080 -use_wallclock_as_timestamps 1 -copyts -i video="QP0203 PCI, Analog 01 Capture" -vf setpts=PTS-STARTPTS -vsync vfr -vframes 300 camera1/%d.jpeg -c copy -vsync vfr -vframes 300 -f mkvtimestamp_v2 timings1.txt

FFmpeg Formats Documentation : Format Options
Sync files timestamp with ffmpeg - Stack Overflow
video - Mjpeg recording with FFMPEG preserving time information - Super User

1枚画像のファイル名に時間指定も出来る。2019-08-03_13-00-00形式になる。

ffmpeg -i video -strftime 1 -vframes 1 "%Y-%m-%d_%H-%M-%S.jpg"

FFmpeg Formats Documentation
strftime
If set to 1, expand the filename with date and time information from strftime(). Default value is 0.

strftime() 書式で使えるフォーマット一覧。
フォーマット説明返り値の例
%A曜日の名前Wednesday
%a短縮された曜日の名前Wed
%B月の名前January
%b省略された月の名前Jan
%d2桁の日付08
%H24時間制の時(00-23)20
%I12時間制の時(01-12)11
%j年中の通算日(001-366)008
%M分(00-59)53
%m月を表す数字(01-12)01
%p午前または午後(AM,PM)AM
%S秒(00-60) (60はうるう秒)06
%U週を表す数。最初の日曜日が第1週の始まり(00-53)01
%W週を表す数。最初の月曜日が第1週の始まり(00-53)01
%w曜日を表す数(0-6) 日曜日が03
%y西暦の下2桁(00-99)14
%Zタイムゾーンの略称東京 (標準時)
%zタイムゾーンの略称東京 (標準時)


映像の再生速度を速めるには PTS を小さくし、遅くするには PTS を大きくする。

【ffmpeg】倍速再生できる動画にエンコードする
APNG をループ出力する
ffmpeg で 256色を最適化する palettegen, paletteuse
リサイズする scale
Zライブラリを使ったリサイズフィルタ zscale

元のフレームレートを変えずに再生速度を速くするとフレームは間引かれ、遅くするとフレーム数はそのままになる。さらに速くするときにフレームレートを変えないと間引かれ、フレームレートを倍速分だけ増やすと間引かれない。palettegen, paletteuse フィルタを使うと256色までの減色処理をする。

3倍速になるがフレームが間引かれる。
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)/3 -plays 0 -f apng x3.png
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)/3 x3.gif
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)/3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse -plays 0 -f apng x3-256.png
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)/3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse x3-256.gif

3倍速になりフレームが間引かれない。元の動画のフレームレートが25fpsのとき。
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)/3 -r 3*25 -plays 0 -f apng x3.png
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)/3 -r 3*25 x3.gif
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)/3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse -r 3*25 -plays 0 -f apng x3-256.png
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)/3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse -r 3*25 x3-256.gif

3分の1速度。
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)*3 -plays 0 -f apng s3.png
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)*3 s3.gif
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)*3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse -plays 0 -f apng s3-256.png
ffmpeg -i input -an -vf setpts=(PTS-STARTPTS)*3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse s3-256.gif

trim フィルタでフレーム単位に切り取るときは切り取った最後に setpts フィルタで速度変更する。
ffmpeg -i input -an -vf trim=start_frame=0:end_frame=50,setpts=(PTS-STARTPTS)/3 -plays 0 -f apng x3.png
ffmpeg -i input -an -vf trim=start_frame=0:end_frame=50,setpts=(PTS-STARTPTS)/3 x3.gif
ffmpeg -i input -an -vf trim=start_frame=0:end_frame=50,setpts=(PTS-STARTPTS)/3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse -plays 0 -f apng x3-256.png
ffmpeg -i input -an -vf trim=start_frame=0:end_frame=50,setpts=(PTS-STARTPTS)/3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse x3-256.gif

リサイズする scale, zscale フィルタなどは trim フィルタの後に使う。
ffmpeg -i input -an -vf trim=start_frame=0:end_frame=50,scale=iw/2:-2,setpts=(PTS-STARTPTS)/3 -plays 0 -f apng x3.png
ffmpeg -i input -an -vf trim=start_frame=0:end_frame=50,scale=iw/2:-2,setpts=(PTS-STARTPTS)/3 x3.gif
ffmpeg -i input -an -vf trim=start_frame=0:end_frame=50,scale=iw/2:-2,setpts=(PTS-STARTPTS)/3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse -plays 0 -f apng x3-256.png
ffmpeg -i input -an -vf trim=start_frame=0:end_frame=50,scale=iw/2:-2,setpts=(PTS-STARTPTS)/3,split[a][b];[a]palettegen[pal];[b][pal]paletteuse x3-256.gif

VFR動画を連番画像で出力する。
ffmpeg -i Video_Stream_0.mp4 -vf "settb=AVTB,setpts=N/TB" -fps_mode passthrough out-%03d.jpg

ffmpeg - Frame export for VFR video failing with -vsync passthrough option - Super User

色を厳格に変換する。bt709から。
ffmpeg -i input -an -vf zscale=p=709:t=iec61966-2-1:m=709:r=full:pin=709:tin=709:min=709:rin=limited:f=spline36,format=rgb48 output%d.png

bt601から。
ffmpeg -i input -an -vf zscale=p=709:t=iec61966-2-1:m=gbr:r=full:pin=smpte170m:tin=smpte170m:min=smpte170m:rin=limited:cin=left:agamma=false:d=error_diffusion,format=gbrp output%d.png

But then I discovered another way of doing this, resulting in 16-bit PNGs:

1枚画像ではなく1枚に複数の画像(タイル状)で出力する


1フレームに1画像ではなくて、1画像に複数のフレームの画像を書き込むことができるフィルタ tile について。

-vf tile=wxh


-vf tile=横x縦 で使い、指定した値の枚数で左上から順に画像が順番に出力される。既定値は 8x8

ffmpeg -i video -vf tile=8x8 -an -vsync vfr img%03d.png


tile=8x8 の出力例
ffmpeg_tile.jpg

1フレームに複数のフレームを表示する tile

任意の場所に並べる場合は xstack フィルタを使う。
解像度が一致しなくても映像を並べられる xstack

順番を変える場合はshuffleframesフィルタを併用する。
指定フレーム毎に順番を入れ換える shuffleframes

指定フレーム毎に出力する


新しい方法


thumbnail フィルタは正確に指定フレーム毎に出力しない(Select the most representative frame)ので framestep フィルタを使う。

100フレーム毎に出力する例。既定値:1(全てのフレーム)

-vf framestep=100


連番画像出力し、tileフィルタで8x8に1フレームにまとめている。

ffmpeg -i video -vf framestep=100,tile=8x8 -vsync vfr img%03d.png


指定フレーム間隔で出力し、ファイル名をフレーム番号にする。例は5フレーム毎に出力。

ffmpeg -i video -vf "setpts=N/TB,fps=1,select='not(mod(n\,5))'" -vsync vfr -frame_pts 1 img%03d.jpg


Extract frames from video FFMPEG with frameskip and name it accordingly.\ - Stack Overflow
Create a thumbnail image every X seconds of the video – FFmpeg

従来の方法


指定フレーム毎に出力できるフィルタ thumbnail について。
例では100フレーム毎に出力するので100,200,300...となる。

-vf thumbnail=100


指定した値のフレーム毎で出力する。既定値は 100
フィルタをつなげる場合は「,」でつなぐ。

ffmpeg -i video -vf thumbnail=100,tile=8x8 -an -vsync vfr img%03d.png


指定秒毎に出力する


新しい方法


fps フィルタを使って1秒ごとのフレームを切り取る方法を使う。切り取る時間の指定は分母に指定し、分子は 1 を指定する。つまり 1/1 = 1 なら1秒ごと、1/10 なら10秒ごとになる。最後のフレームが指定秒で割り切れなくても1番最後の画像で出力される。

round の設定で小数点以下を切り捨てる
-vf fps=fps=1:round=down

ffmpeg -i video -vf fps=fps=1:round=down,tile=8x8 -an -vsync vfr img-%03d.png

指定秒毎に出力し、ファイル名を秒時間にする。以下の例は5秒毎に出力する。
ffmpeg -i video -vf fps=1,select='not(mod(t,5))' -an -vsync vfr -frame_pts 1 img-%03d.jpg

jpeg - ffmpeg output images filename with time position - Stack Overflow

FFmpeg Formats Documentation : image2
frame_pts
If set to 1, expand the filename with pts from pkt->pts. Default value is 0.

従来の方法


select フィルタで指定した秒の間だけを出力する。

注:select フィルタを使うとCPU負荷が90%近くまで上がり長時間の動画ほど処理時間がかかるのに注意。よって、出力開始時点が後ろの動画時間の場合は予め -ss で読み込み開始時点を遅らせると処理が早くなる。

-vf select=isnan(prev_selected_t)+gte(t-prev_selected_t\,10)


上の例では最後の10が10秒おきに出力する設定になる。分数も可能で60fpsの動画に1/30とすると2フレームごとに出力する設定になる。

ffmpeg -i video -vf select=isnan(prev_selected_t)+gte(t-prev_selected_t\,10),tile=8x8 -an -vsync vfr img%03d.png


指定秒間を出力する


新しい方法


select フィルタは処理が重たいので trim フィルタを使う。

-vf trim=10:20,setpts=PTS-STARTPTS


上の例では10秒から20秒までのフレームを出力する。1ファイルだけならば trim を使わずに ーss、-t の併用の方が処理が早い。

ffmpeg -ss 10 -i input -t 10


従来の方法


select フィルタで指定した値のフレームの間だけを出力する。

-vf select=gte(t\,10)*lte(t\,20),setpts=PTS-STARTPTS


上の例では10秒から20秒までのフレームを出力する。指定した値の丁度を含まない場合は gte,lte の「e」を消す。

-vf select=gt(t\,10)*lt(t\,20),setpts=PTS-STARTPTS


ffmpeg -i video -vf select=gte(t\,10)*lte(t\,20),setpts=PTS-STARTPTS,tile=8x8 -an -vsync vfr img%03d.png


特定の映像フレームや音声サンプルを出力する select, aselect

指定フレーム間を出力する


新しい方法


select フィルタは処理が重たいので trim フィルタを使う。

-vf trim=start_frame=299:end_frame=600,setpts=PTS-STARTPTS


上の例では300フレームから600までの301フレームを出力する。trim フィルタの使い方は個別記事 trim フィルタの使い方 を参照。

従来の方法


select フィルタで指定した値のフレームだけを出力する

-vf select=gte(n\,300)*lte(n\,600),setpts=PTS-STARTPTS


上の例では300フレームから600までの301フレームを出力する。指定した値の丁度を含まない場合は gte,lte の「e」を消す。

-vf select=gt(n\,300)*lt(n\,600),setpts=PTS-STARTPTS


ffmpeg -i video -vf select=gte(n\,300)*lte(n\,600),setpts=PTS-STARTPTS,tile=8x8 -an -vsync vfr img%03d.png


特定フレームを出力する


任意のフレームを連番画像で出力する。-fps_modeが使えなければ-vsyncを使う。
ffmpeg -i input -vf select=eq(n\,50)+eq(n\,51)+eq(n\,52)+eq(n\,53)+eq(n\,54) -vframes 5 -fps_mode vfr img-%03d.png

select フィルタでB,P,Iフレームのどれかを出力する。

  • Bフレーム
    -vf select=eq(pict_type\,B)
  • Pフレーム
    -vf select=eq(pict_type\,P)
  • Iフレーム
    -vf select=eq(pict_type\,I)

動画のサムネイル一覧を取得するなら少ない画像で内容がわかるIフレームを使う。
tile フィルタと併用すると一覧性が増す。

-vf select=eq(pict_type\,I),tile=8x8


Iフレームの出力例
ffmpeg_iframe_tile.jpg

ffmpeg -i video -vf select=eq(pict_type\,I),tile=8x8 -an -vsync vfr img-%03d-I.png

frame_pts 1 を使うと0開始ではなくフレーム番号がファイル名に付く。

ffmpeg -i video -vf select=eq(pict_type\,I),tile=8x8 -an -vsync vfr -frame_pts 1 img-%03d-I.png


さらに H.264, H.265 のときは無劣化でキーフレームだけの動画が作れる。適宜 -r の値を変えることで出力フレームレートを変えられる。小さくするとゆっくり映像が流れる。
ffmpeg -discard nokey -i input.mp4 -c:v copy -an tmp.264
ffmpeg -r 24 -i tmp.264 -c copy output.mp4


任意のフレームを画像出力する。フレームはeq()でつなげて指定できる。
ffmpeg -i input.mp4 -vf "select='eq(n\,1315)+eq(n\,1607)'" -fps_mode vfr out-%06d.png


14フレームのキーフレーム毎に画像出力する。
ffmpeg -skip_frame nokey -i input.mp4 -vf "select='if(eq(n\,0)\,1\,gte(t-prev_selected_t\,14))'" -fps_mode vfr -frame_pts true out-%06d.png


framerate - How to extact multiple specific frames from video which their number is saved in a filename using ffmpeg in linux? - Super User

ffmpeg - Obtain the filtered keyframe screenshot from the video - Stack Overflow

H.265だとこの方法でもキーフレーム以外を間引くことができる。
ffmpeg -i test.mkv -c copy -map v -bsf:v "filter_units=pass_types=16-23|32-34" key.mkv


ffmpeg - Remove all non key frames from video without re-encoding - Stack Overflow

最終フレームの画像を出力する。最終フレームから3秒以内なら以下のコマンドで出力できる。これでエラーが出る場合は -3 をもう少し値を小さくして -10 などとする。

ffmpeg -sseof -3 -i input -update 1 -q:v 1 last.jpg

最後のキーフレームなら skip_frame nokey をつける。

ffmpeg -sseof -10 -skip_frame nokey -i input -update 1 -q:v 1 last.jpg

FFmpeg : How to get last frame from a video - Super User

一定時間ごとに出力するのを高速化する


select フィルタを使うと長時間の動画ほど凄まじく時間がかかるので、少し誤差はあるがかなり高速化する方法。

キーフレーム(I フレームより出力が少なくなる。つまりキーフレームはすべてIフレームだが、Iフレームのすべてがキーフレームではない)だけを出力する設定を用いて読み込みを高速化する。ただしライブストリームなどで正しくキーフレームを出力できずに ffmpeg が認識しなかった場合はすべてのフレームを出力するので、その場合は thumbnail, framestep フィルタで指定する。

-skip_frame nokey


参照フレーム以外を出力する場合はこちら。nokey でうまくサムネイルが出力しない場合はこちらを試す
-skip_frame noref


skip_frame の使い方:FFmpeg documentation : : Codec Options の下の方に説明がある。

キーフレームはおおよそ1秒に1枚程度あるのを利用して thumbnail フィルタを併用することで高速化できる。以下のコマンドは200キーフレーム毎に 8x8の画像を png で出力すコマンド。

ffmpeg -skip_frame nokey -i video -vf "thumbnail=200,tile=8x8" -an -vsync vfr -frame_pts true img%03d.png


そのほかの設定方法:ニコ生のTSからサムネイルを出力する

ffmpeg - Extract I-frames to images quickly - Super User

リサイズとリサイズオプション


動画の解像度そのままを tileフィルタで出力すると解像度が大きくなるので scaleフィルタを使って小さくする。リサイズオプションも併用できる。デフォルトのリサイズオプションはbicubicになっている。

-vf scale=横:縦 にリサイズする

-vf scale=320:240


片方を実数にして、もう片方を-1にすると実数の値からアスペクト比固定で横幅を自動設定できる。

横幅240pxでアスペクト比固定でリサイズし、lanczosのリサイズオプションを取る

-vf scale=240:-1 -sws_flags lanczos
-vf scale=240:-1:flags=lanczos


accurate_rnd は ffdshow では「正確な丸め処理」と表記されている。

オプション名メモ
accurate_rnd+bilinearぼんやり
bilinearぼんやり
experimentalややぼんやり
bicubicややシャープ
splineややシャープ
accurate_rnd+lanczosシャープ
lanczosシャープ
neighborかなりシャープ


ffmpeg -i video -vf scale=240:-1,select=eq(pict_type\,I),tile=8x8 -sws_flags lanczos -an -vsync vfr img%03d.png


リサイズする scale
Zライブラリを使ったリサイズフィルタ zscale

取得するの画像の座標を指定する


cropフィルタを使って特定の位置、例えば右上の局ロゴや、左下のワイプなどの一部の場所を指定して出力する。

crop=x:y:w:h:t


x:y は出力解像度。横:縦
w:h は出力解像度の左上隅の座標。横:縦
左上隅の座標が 0:0

NHK総合の局ロゴの位置

ffmpeg -i video -vf crop=109:28:1274:63 -an -vsync vfr img%03d.png


映像を指定座標に切り取る crop

動画から画像に標準出力する


動画、もしくは連番画像から画像形式で標準出力する。

ffmpeg -i input -vcodec png -an -f image2pipe - |...


画像から動画を作る


画像から動画にするときは、JPGやWebpなどのYUVからYUVの動画にする場合と、PNGやBMPなどのRGBからYUVの動画にする場合でフィルタの扱いが異なる。さらにメタデータをつけることで意図した色で表示できる。

色関係の設定のまとめ

JPGやWebpなど。
ffmpeg -framerate 1 -loop 1 -i img.jpg -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 output.mp4

PNG
ffmpeg -framerate 1 -loop 1 -i img.png -vf colorspace=all=bt709:iall=bt601-6-625:fast=1:out_range=tv -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 output.mp4

bsf併用する方法もある。
ffmpeg -framerate 1 -loop 1 -i img.png -vf colorspace=all=bt709:iall=bt601-6-625:fast=1:out_range=tv -pix_fmt yuv420p -bsf:v h264_metadata=video_full_range_flag=0:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 output.mp4

ICCプロファイル付きのPNGだとうまくいかないかも。

BMP
ffmpeg -framerate 1 -loop 1 -i img.bmp -vf format=rgb24 -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 output.mp4

video - FFmpeg BMP to YUV x264 color shift - Video Production Stack Exchange
Talking About Colorspaces and FFmpeg | by InVideo | InSide InVideo | Oct, 2020 | Medium
How can I apply the appropriate color space and gamma transfer function to my ffmpeg command? - Super User

1枚画像から動画と音声を併せて動画を作る。-framerate で入力フレームレート、-r で出力フレームレートの指定。画像なので動画のような高いフレームレートを指定する必要はない。ただしBMP画像のときはフィルタでフォーマットをRGB24に指定してから出力する。

ffmpeg -loop 1 -i img.png -i audio.mp3 -r 5 -vf colorspace=all=bt709:iall=bt601-6-625:fast=1 -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 -shortest -pix_fmt yuv420p -vcodec libx264 -acodec copy loop.mkv

ffmpeg -loop 1 -i img.bmp -i audio.mp3 -r 5 -vf format=rgb24 -shortest -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 -vcodec libx264 -acodec copy loop.mkv

video - FFmpeg BMP to YUV x264 color shift - Video Production Stack Exchange

libx264 を使う場合にチューンを画像用にすると処理が速くなる。

ffmpeg -loop 1 -i img.png -i audio.mp3 -r 5 -shortest -vf colorspace=all=bt709:iall=bt601-6-625:fast=1 -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 -vcodec libx264 -tune stillimage -acodec copy loop.mkv

Encode/H.264 – FFmpeg

解像度が奇数でエラーになる場合は偶数に直す。

ffmpeg -loop 1 -i img.png -i audio.mp3 -r 5 -vf scale=iw:-2,colorspace=all=bt709:iall=bt601-6-625:fast=1 -shortest -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 -vcodec libx264 -tune stillimage -acodec copy loop.mkv

intel CPU を使っている場合、ハードウェアエンコーダーの QSV を使って高速にH.264出力できる。

ffmpeg -loop 1 -i img.png -i audio.mp3 -r 5 -shortest -vf colorspace=all=bt709:iall=bt601-6-625:fast=1 -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 -vcodec h264_qsv -look_ahead 0 -q:v 20 -acodec copy loop.mkv

qsv 対応の ffmpeg をつくる

「Too many packets buffered for output stream」のエラーが出るときは-shortest -fflags +shortest -max_interleave_delta 100Mをつける。

ffmpeg -loop 1 -framerate 1 -i img.png -i audio.mp3 -r 5 -vf colorspace=all=bt709:iall=bt601-6-625:fast=1 -shortest -fflags +shortest -max_interleave_delta 100M -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 -vcodec h264_qsv -look_ahead 0 -q:v 20 -acodec copy loop.mkv

unix - Python convert mp3 to mp4 with static image - Stack Overflow
windows - My ffmpeg output always add extra 30s of silence at the end - Stack Overflow
#6375 ([bug][regression] Too many packets buffered for output stream) – FFmpeg

音声が mp3 なら再生時のサムネイルに登録できる。映像はエンコードしないので処理が速い。

ffmpeg -i input.mp3 -i cover.png -c copy -map 0 -map 1 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (Front)" out.mp3

mp4, mp3 にカバーアートを付ける
FFmpeg Formats Documentation : mp3

連番で出力された画像をまとめて動画を作る。特定の番号の画像から動画を作ることもできる。

30フレームレートの動画を連番画像の150番からつなげた out.mp4 の動画にする

ffmpeg -framerate 30 -start_number 150 -i img%03d.png -vf colorspace=all=bt709:iall=bt601-6-625:fast=1 -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 out.mp4

  • -f image2 は画像を入力しますよというフォーマット指定(2016年現在は標準入力するとか入力ファイルの拡張子を見て判断するので不要)
  • -framerate は画像何枚で1秒表示にするかの設定。連番画像を入力する場合は動画で使われている -r ではなく -framerate を使う。既定値は25

    FFmpeg Formats Documentation :: image2
    saveVideo: ffmpeg drops frames (use -framerate on input) · Issue #74 · yihui/animation
  • -start_number 入力オプションと出力オプションどちらも使える。入力オプションでは入力開始番号の指定。出力オプションでは出力開始番号の指定。既定値は0

末尾のフレーム指定ができないので不要ならば別フォルダに移動する。
-vframes を指定することで出力するフレーム数を指定できる。訂正:2013年6月14日

90フレームから90フレーム分(179フレームまで)を出力する。
ffmpeg -framerate 30 -start_number 90 -i img%03d.png -vframes 90 -vf colorspace=all=bt709:iall=bt601-6-625:fast=1 -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 out.mp4

より正確にカラーフォーマットを指定するのなら。

ffmpeg -framerate 30 -i img%03d.jpg -vf scale=out_color_matrix=bt709:out_range=tv:flags=+accurate_rnd+bitexact -c:v libx264 -tune stillimage -pix_fmt yuv420p -color_primaries bt709 -color_trc bt709 -colorspace bt709 out.mp4

pngなどで途中でピクセルフォーマットが変更になる。たとえば、argbやrgb24などのときは-reinit_filterを無効にする。

ffmpeg -reinit_filter 0 -i a_%04d.png -reinit_filter 0 -i b_%04d.png -filter_complex "[0]format=rgb24[a];[1]format=rgb24[b];[a][b]blend=average" -c:v libvpx -crf 4 -b:v 20M ab.webm

animation - FFMPEG dropping frames due to color space mismatch - Stack Overflow
command line - create slideshow video using ffmpeg and batch file (Windows) and have all images resized to 1080 height and crossfaded - Super User

連番のファイル名にしたくないときは concat デマクサで個別のファイル名を指定する。

input.txt の内容。

file first.jpg
file second.jpg
file third.jpg
...
file last.jpg



任意の時間にするときは duration を指定する。

input.txt の内容。

file first.jpg
duration 3
file second.jpg
duration 3
file third.jpg
duration 3
...
file last.jpg
duration 3



Use multiple files in ffmpeg slideshow as input without glob - Super User

入力の -r で1フレーム1画像にして、出力の -r で1秒間に5フレーム同じ映像が流れる5fpsにした動画にする。-safe 0 は絶対パスで input.txt の内容を記述したときにつける。
ffmpeg -f concat -r 1 -safe 0 -i input.txt -r 5 -c:v libx264 -pix_fmt yuv420p out.mp4

ffmpeg でのフレームレート設定の違い
【ffmpeg】動画・音声を連結する concat の使い方 其の3
ffmpeg - Create video from bunch of JPEGs - Super User

音声ファイル毎に画像ファイルも変える。出力フレームレートは -r で調整する。映像と音声のペア数を concat=n で指定する。
2枚の画像に2つの音声ファイル。
ffmpeg -framerate 1 -i img1.jpg -i audio1.mp3 -framerate 1 -i img2.jpg -i audio2.mp3 -filter_complex [0:v][1:a][2:v][3:a]concat=n=2:v=1:a=1[v][a];[v]colorspace=all=bt709:iall=bt601-6-625:fast=1[v] -map [v] -map [a] -r 30 -color_primaries bt709 -color_trc bt709 -colorspace bt709 output.mp4

3枚の画像に3つの音声ファイル。
ffmpeg -framerate 1 -i img1.jpg -i audio1.mp3 -framerate 1 -i img2.jpg -i audio2.mp3 -framerate 1 -i img3.jpg -i audio3.mp3 -filter_complex [0:v][1:a][2:v][3:a]concat=n=3:v=1:a=1[v][a];[v]colorspace=all=bt709:iall=bt601-6-625:fast=1[v] -map [v] -map [a] -r 30 -color_primaries bt709 -color_trc bt709 -colorspace bt709 output.mp4

【ffmpeg】動画・音声を連結する concat の使い方

標準入力から連番画像を入力する。
process-piping-images | ffmpeg -f image2pipe -i - output

is it possible to send ffmpeg images by using pipe? - Stack Overflow

VFRからCFRの動画を作る。
ffmpeg - Can I create a VFR video from timestamped images? - Stack Overflow

画像からアニメGIFを作る


ffmpeg 2.6 でパレットに対応したので ImageMagick で遜色のないレベルで高画質、低容量でアニメGIFが作れるようになった。

ffmpeg で 256 色を最適化する

ffmpegの出力先をgifにすればアニメGIFを作ることができるが、ffmpegはアニメGIFを作るのが苦手なので ImageMagick を使う。

pngの連番を全て取り込んでout.gifとして出力する

convert -delay 4.1708375 -loop 0 -layers optimize *.png out.gif


GraphicsMagick を使う例もあるようです。
GIFアニメ生成にImageMagickはオワコン、情強は高速なGraphicsMagickを使う - 海峡

  • -delay は1秒当たり 100/n で表示されるフレーム数の指定。アニメなら 100/23.976
  • -loop は何回繰り返すか。0は無限
  • -layers optimize は最適化コマンド。容量が小さくなる。

アニメWebpを作る


動画からアニメWebpを作るコマンド例

ffmpeg -i input -vcodec libwebp -lossless 0 -qscale 75 -preset default -loop 0 -an -vsync vfr output.webp


詳しい設定は ffmpeg で アニメーションWebP(Animated WebP)を作る を参照。

avifを作る


1フレームと複数フレームに対応している。現状どのエンコーダにもアルファチャンネルに対応していない。対応ピクセルフォーマットはエンコーダで微妙に異なりgbrp対応しているのはlibaom-av1だけ、フルレンジに対応しているのはlibrav1eだけになる。
libaom-av1は-cpu-usedの値を小さくすると高品質低速度に、libsvtav1はpresetの値を小さくすると高品質低速度になる。

1フレームのavifをつくる。
ffmpeg -i input.png -c:v libaom-av1 -cpu-used 8 -crf 32 -still-picture 1 image.avif
ffmpeg -i input.png -c:v libsvtav1 -preset 10 -crf 32 -still-picture 1 image.avif
ffmpeg -i input.png -c:v librav1e -qp 60 image.avif

アニメーションavifをつくる。
ffmpeg -i input.mp4 -c:v libaom-av1 -cpu-used 8 -crf 32 -frames:v 24 image.avif
ffmpeg -i input.mp4 -c:v libsvtav1 -preset 10 -crf 32 -frames:v 24 image.avif
ffmpeg -i input.mp4 -c:v librav1e -qp 60 -frames:v 24 image.avif

エンコーダのヘルプ。
ffmpeg -h encoder=libaom-av1
ffmpeg -h encoder=libsvtav1
ffmpeg -h encoder=librav1e

SvtAv1EncApp --help · GitHub
ffmpeg -h encoder=libsvtav1 · GitHub
aomenc --help · GitHub
ffmpeg -h encoder=libaom-av1 · GitHub
rav1e-ch --help · GitHub
ffmpeg -h encoder=librav1e · GitHub

関連記事



後記


ニコニコ動画はYoutubeにあるようなシークバーを操作したらそのシーンのサムネイルが表示されるのはいつになったら実装するのか、というのを聞いたことがあるが、これはthumbnailフィルタで画像を取得するときにその時間も取得できるので、それを利用して動画のシークバーにオーバーレイの画像として利用することができる。

selectフィルタで出力フレームを色々変更できるが、リアルタイムキャプチャして配信するときにselectフィルタを使って出力フレームを操作する場合はいくつか制限がある。B,P,Iフレームだけで配信できない。フレーム数を間引く設定にするとオリジナルのfpsから間引かれて入力fpsで配信できない。

追記 2013/12/16
高速化の部分と一部注意書きを加えた。
追記 2013/12/20
-skip_frame noref を加えた。
追記 2015/01/07
select よりも trim 推奨。framestep と mjpg, webp について追記した。
訂正 2015/02/17
-delay の説明を直した。
修正 2015/05/08
細部の修正した。
追記 2016/06/26
-f image2 不要の部分と、連番画像では -r を使わない部分を追記した。
修正 2016/07/15
fps フィルタを使う方法を追記。それに伴って一部記事を直した。
修正 2018/05/14
画像から動画変換で出力フォーマットの設定を追加した。
追記 2019/04/13
-frame_pts true を追加した。
追記 2023/04/08
avifの項目を追加した。
関連記事

コメント

非公開コメント

プロフィール

ロベルト

お問い合わせはこちらまで
robelt2525[at]gmail.com

中の人 @nico_lab

広告リンク
Amazon
楽天市場

ブログ更新用 @blo_nico_lab

詳しいプロフィールはこちら

当ブログは、Amazonアソシエイトに参加しています。