ffmpegにはフレームレートの設定方法がいくつかあるが、同じオプションでも指定場所では効果が違ったりするので一般的な用途のまとめ。オリジナルよりもフレームレートが少ないときは同じように間引かれるが、出力結果も一致するとは限らない。オプションの-rは出力コンテナによって既定値が異なるのでMP4出力時と今回テストしているMKVとでは結果が異なり以下に説明している-fps_modeも併用する。

公式Wiki:ChangingFrameRate – FFmpeg

ffmpeg – Framerate vs r vs Filter fps – Stack Overflow
changing the framerate: “fps=X” filter vs “-r X” option : ffmpeg

実験用の動画を作る

  • 0番から249番までの250フレーム、25fps の基本動画(手軽)
    ffmpeg -f lavfi -i testsrc2=d=10 -vcodec utvideo input.mkv
  • 0番から249番までの250フレーム、25fps の基本動画
    ffmpeg -f lavfi -i testsrc=d=10,drawtext=fontfile="C\\:/Windows/Fonts/msgothic.ttc:text='%{n}':fontsize=30:x=W-tw:y=H-th" -vcodec utvideo input.mkv

コマンド例

  • フィルタとしてのfps
    オリジナルよりフレームレートが少なければ間引く、多ければ重複フレームをつくる。動画時間は変わらない

    コマンド例
    ffmpeg -i input.mkv -vf fps=30 -vcodec utvideo output.mkv

    参考記事:フレームレートを変更するfps

  • フィルタとしてのframerate
    オリジナルよりフレームレートが少なければ間引く、多ければ前後フレームを平均して増やす。動画時間は変わらない。YUV限定でRGB出力不可。

    コマンド例
    ffmpeg -i input.mkv -vf framerate=30 -vcodec utvideo output.mkv

    参考記事:簡易的なフレーム補間をする framerate

  • フィルタとしてのminterpolate
    フレーム補間フィルタなのでオリジナルよりも多い値を指定する。補間方法は平均と予測がある。動画時間は変わらない。

    コマンド例(予測なのでかなり遅い)
    ffmpeg -i input.mkv -vf minterpolate=50 -vcodec utvideo output.mkv

    参考記事:ffmpeg でフレーム補間する minterpolate

  • 入力オプションとしての-r
    入力ファイルの前に指定する。総フレーム数はそのままに1秒あたりのフレームレートを指定するので、オリジナルよりフレームレートが少なければ動画時間が長く、多ければ動画時間が短くなる。-c copyと併用しても効果がない。

    コマンド例
    ffmpeg -r 30 -i input.mkv -vcodec utvideo output.mkv

    公式ドキュメント:ffmpeg Documentation : Video Options

  • 出力オプションとしての-r
    入力ファイルの後に指定する。オリジナルよりフレームレートが少なければ間引く、多ければオリジナルのまま。動画時間は変わらない。だたしこの-rは出力コンテナによって既定値が異なるのでMP4出力時と今回テストしているMKVとでは結果が異なり以下に説明している-fps_modeも併用する。-c copyと併用しても効果がない。

    コマンド例
    ffmpeg -i input.mkv -r 30 -vcodec utvideo output.mkv
    ffmpeg -i input.mkv -r 30 -vcodec libx264 -preset ultrafast output.mp4

    出力コンテナ 出力オプションの-r frames time 備考
    mp4 20 201 10.00 間引く
    mkv 20 202 10.05 間引く
    mp4 30 300 9.96 重複フレーム
    mkv 30 250 9.96 変化なし

    公式ドキュメント:ffmpeg Documentation : Video Options

  • 出力オプションとしての-fpsmax
    ffmpeg 4.4以降から使える。この値よりも高い値とのときの上限を指定する。オリジナルのほうが低ければ変更しない。-rと併用できない。ストリームコピーすると機能しない

  • dshowとしての-framerate
    Windows の DirectShow 入力での入力フレームレート。SCFFなどの仮想デバイスのように任意に指定できる場合と、キャプチャカードやウェブカメラのように任意に指定できない場合がある

    コマンド例
    ffmpeg -rtbufsize 100MB -f dshow -framerate 30 -i video=device_name -vcodec utvideo output.mkv

    公式ドキュメント:FFmpeg Devices Documentation : dshow

  • 連番画像を入力するときのフレームレートを決める-framerate

    連番画像を入力するときのフレームレートは-rではなくて-framerateを使う方がより正確であり、公式ドキュメントを見ても設定項目に書いてある

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

    また、長時間の連番画像を100フレーム毎などフレームを間引いてタイムラプス(低速度撮影)にする場合はframestepフィルタを使う。
    コマンド例
    ffmpeg -framerate 30 -i img%03d.png -vf colorspace=all=bt709:iall=bt601-6-625:fast=1,framestep=100 -pix_fmt yuv420p -colorspace 1 -color_primaries 1 -color_trc 1 out.mp4

    参考記事:指定フレーム毎に出力する

  • 1枚画像から動画を作るときのフレームレートを決める-framerate
    これも-rではなくて-framerateを使う方がより正確であり、公式ドキュメントを見ても設定項目に書いてある

    コマンド例
    ffmpeg -framerate 30 -loop 1 -i img.png -vf colorspace=all=bt709:iall=bt601-6-625:fast=1 -pix_fmt yuv420p -colorspace 1 -color_primaries 1 -color_trc 1 out.mp4

    公式ドキュメント:FFmpeg Formats Documentation : image2
    参考記事:【ffmpeg】動画から特定フレームを画像で出力する方法

再生速度の変更

再生速度を変更する場合は以下を参照。

重複フレーム

定期的に重複フレームがあるとき、ここではNTSCの30000/1001フレームレートに5分の1フレーム間引いた24000/1001フレームレートを指定している。

ffmpeg -i input -vf mpdecimate output
ffmpeg -i input -vf decimate,setpts=N/(24000/1001)/TB output

ffmpeg – remove sequentially duplicate frames – Stack Overflow

shuffleframesフィルタでも一定間隔の重複フレームを間引くことができる。
指定フレーム毎に順番を入れ換える shuffleframes

フィルタで重複フレームを自動的に間引くならdecimate、mpdecimateフィルタを使う。
フレームを間引くdecimate、mpdecimate

可変フレームレート

可変フレームレートとはPTS間隔が一定でない映像のことである。可変フレームレートに平均フレームレートをそれぞれのオプションに指定した場合、フィルタのfps, framerate, minterpolateと入力オプションとしての-rは PTS間隔を平均化させるが、出力オプションとしての-rは PTS間隔を平均化させない。

最初のコマンドで5フレーム毎に1フレーム間引きPTS間隔を修正しないのでVFRになる。
ffmpeg -f lavfi -i testsrc2=d=4:r=25 -vf select='mod(n,5)' -c:v ffv1 25.mkv
ffmpeg -i 25.mkv -vf fps=25,vfrdet -f null -
ffmpeg -r 25 -i 25.mkv -vf vfrdet -f null -
ffmpeg -i 25.mkv -r 25 -vf vfrdet -f null -

具体的に説明すると-fps_modeを無指定だと出力コンテナに合わせて自動設定する。MP4出力で-fps_modeを無指定だとVFRにならず、間引かれたフレームはその次のフレームを複製する。
ffmpeg -f lavfi -i testsrc2=d=4:r=25 -vf select='mod(n,5)' vfr.mp4
ffmpeg -i vfr.mp4 -an -vf vfrdet -f null -

MKV出力で-fps_modeを無指定だとVFRになる。
ffmpeg -f lavfi -i testsrc2=d=4:r=25 -vf select='mod(n,5)' vfr.mkv
ffmpeg -i vfr.mkv -an -vf vfrdet -f null -
ffprobe -v error -i vfr.mkv -select_streams v:0 -show_frames -show_entries frame=pkt_pts_time -of csv=p=0 > vfr.mkv.txt

フレームを間引いた動画にPTSを振り直すなら目的のフレームレートを指定したsetptsフィルタを使う。間引く前のフレームレートが25で5分の1を間引く、つまり20を指定する。
ffmpeg -i testsrc2.mp4 -vf select='mod(n,5)',setpts=N/20/TB -fps_mode vfr vfr-setpts.mp4
ffmpeg -i vfr-setpts.mp4 -an -vf vfrdet -f null -
ffprobe -v error -i vfr-setpts.mp4 -select_streams v:0 -show_frames -show_entries frame=pkt_pts_time -of csv=p=0 > vfr-setpts.mp4.txt

-vsyncの内容。ffmpeg 5.1から-vsyncが廃止予定で代わりに-fps_mode追加され-vsyncの互換性とストリーム指定ができるように。

  • -fps_mode[:stream_specifier] parameter (output,per-stream)
    • passthrough
      デマクサからマクサにタイムスタンプを通す
    • cfr
      入力した映像のフレームレートにより一定間隔のPTSにあわせてフレームを出力する。VFRだと途切れたフレームはその次のフレームを複製して固定フレームレートにする
    • vfr
      一定間隔のPTSにあわせたフレームがなければ間引き、同じタイムスタンプを持つフレームがあっても間引。つまり可変フレームレートを固定フレームレートに変換しないく
    • drop
      passthroughと同じだが、すべてのタイムスタンプを破棄する
    • auto
      出力コンテナに合わせてcfr、vfrのどちらかを選ぶ。既定値

指定例:

-fps_mode cfr
-fps_mode:v cfr
-fps_mode:0 cfr

-fps_mode dropでタイムスタンプを作り直すことができる。
ffmpeg -i input.mp4 -fps_mode drop -c copy output.mp4

もしくは生データにいったん出力してMP4に入れ直す方法もある。適宜正しいフレームレートを-rで指定する。
ffmpeg -i input.mp4 -c:v copy -bsf:v h264_mp4toannexb input.h264
ffmpeg -fflags +genpts -r 30000/1001 -i input.h264 -c:v copy output.mp4

FFmpeg: recreate timestamps without reencoding – Super User

公式ドキュメント:ffmpeg Documentation : Advanced options

参考記事:

ログの見方

ちなみにエンコードの出力ログに表示される tbc, tbn, tbr について。https://qiita.com/ymotongpoo/items/eb9754b75606be117b70(qiitaの個人ページ統計データ公開後削除)より。

tbr, tbn, tbcはそれぞれの逆数が実際のタイムベースとなる。

  • tbr: 実際にビデオを表示する際に参照するレート。ビデオストリームからの類推値。インタレースだと倍値になってたりする。
  • tbn: コンテナ側に書かれたストリームのタイムベース。
  • tbc: 特定のコーデックにだけ存在するコーデック側のタイムベース。

タイムベースはタイムスケールの1刻みの時間。
timebase = 1/timescale
pts_time = frame * pts * timebase

Timebase = 1/75; Timescale = 75
 Frame        pts           pts_time
   0          0          0 x 1/75 = 0.00
   1          3          3 x 1/75 = 0.04 
   2          6          6 x 1/75 = 0.08
   3          9          9 x 1/75 = 0.12
   ...

tbctbnを修正するには整数指定の-video_track_timescaleを使う。MOV、MP4コンテナ専用。
ffmpeg -i input -c copy -video_track_timescale 30 output.mp4

タイムコードについて

ffmpegではmovコンテナに入っているようなメタデータにあるタイムコードを映像におそらく?描写できない。
drawtextフィルタでタイムコードを描写できるが整数フレームレートしか指定できず、ドロップフレームのタイムコードを扱えない。

タイムコードを0秒リセットにするには-mapに負の値を指定する。
ffmpeg -i input.mov -map 0 -map -0:d -c copy -timecode 00:00:00:00 output.mov

7 thoughts on “ffmpeg でのフレームレート設定の違い

コメントを残す

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

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