毎回探すのがいやになりました。

使用例のいくつかは私のgistに置いてあります。 あとたいていのことはffmpeg wikiにのってます。

入力の指定とか初めの色々

ほとんどのことはニコラボに載ってますが一応。

ffmpegは指定された順番に入力を割りあてます。ファイルを入力に指定したい場合は以下の通り。 ()はオプション、|はどちらかを指定です。

(-ss hh:mm:ss) (-to hh:mm:ss | -t seconds) -i input.mkv

ニコラボの解説が詳細に書かれています。

動画だけフィルターにかけたい場合は-filter:vでフィルタをそれぞれ,で区切ります。 音声だけフィルターにかけたい場合は-filter:aで同様にします。 フィルター内のオプションの各値は:で区切ります。

動画と音声の両方をフィルターにかけたい場合は-filter_complexを使います。 それぞれのフィルターは;で区切り、フィルターの出力を[name]のように指定します。

入力をfilter_complexで使う場合は最初の入力を0番目として数えます。 0番目の動画は[0:v]、0番目の音声は[0:a]。 音声が複数トラックある場合、その最初のトラックの音声は[0:a:0]です。

最終的な出力をする場合にfilter_complexを使っていたなら-mapを使う必要があります。 1番目のストリームから順番にmapを並べます。 通常は1番目は動画のはずなので動画から並べます。

-map [v] -map [a]

mapについてもffmpeg wikiのmapの解説を見てください。

n倍速/スローモーション

ffmpeg wikiの該当ページも参考にしてください。

該当するフィルタはsetptsatempo

setptsはフレームごとのタイムスタンプを書きかえることで速度を変えます。 atempoは音をn倍速にします。

例えば動画と音声をそれぞれ2倍速にしたいのならば次のようなコマンドになるでしょう。

ffmpeg -i test.mkv -filter_complex "[0:v]setpts=PTS/2[v];[0:a]atempo=2[a]" -map [v] -map [a] output.mkv

PTSは現在のフレーム数なのでPTSがそれぞれ2分の1になるということは結果として2倍速になります。

逆に2分の1のスローモーションにしたい場合は以下の通り。atempoは0.5から2.0100.0までの値しか取れないので注意が必要です。

ffmpeg -i test.mkv -filter_complex "[0:v]setpts=PTS*2[v];[0:a]atempo=0.5[a]" -map [v] -map [a] output.mkv

無音を入力する

anullsrcを使います。ffmpeg wikiの解説も見てください。 そのままだと無限に無音を出力するので-shortestが必要です。

ffmpeg -i input.mkv -f lavfi -i anullsrc -c:v copy -c:a aac -map [0:v] -map [1:a] -shortest output.mp4

クロップ(切り抜く)する

ffmpegのドキュメントの該当部分も見てください。

crop=w=(出力幅):h=(出力高さ):x=(切りだすX座標,左が0):y=(切りだすy座標,上が0)

in_wiwで入力される動画の幅、in_hihで同じく高さを表わし、 sarで入力される動画のアスペクト比を表わします。

動画をつなぐ

いくつか方法がありますがconcatフィルタによるものを紹介します。 ffmpegドキュメントの該当部分も見てください。 なおこのやり方の場合は再エンコードが必要になるのでオプションの-c:v copy(再エンコードをせずに動画をコピー)等は使えません。

[0:v][0:a][1:v][1:a][2:v][2:a]concat=n=3:v=1:a=1[v][a]

他にもffmpeg wikiの解説を見ると様々な例が載っています。

クロスフェード

解説書きたいと思ったけど全然使ってないので、今使ってるスクリプトを載せてお茶を濁しておきます。

曲名スクロールしながら流す

さきに実際に使っているコマンドから。前提条件として\temp_files\foobar_nowplaying.txtに現在再生している曲名が入っています。

ffmpeg -f lavfi -i 'color=c=black:r=15:s=640x64' -f dshow -i 'audio=CABLE-B Output (VB-Audio Cable B)' -filter_complex "[0]drawtext=fontfile='\\Windows\\fonts\\meiryob.ttc':textfile='\\temp_files\\foobar_nowplaying.txt':reload=1:fontsize=(h/2.2):y=0:x=w-mod(n*6\,w+tw):y=(h-th)/2:fontcolor=white" -c:v libsvtav1 -crf 35 -c:a aac -b:a 128k -f matroska http://192.168.0.100:8080/stream.mkv

これはニコラボの”文字を描写するDRAWTEXT”から着想を得ました。文字を描写するフィルタの重要な部分だけ抜きだします。\はエスケープ文字です。

drawtext=textfile='\\temp_files\\foobar_nowplaying.txt':reload=1:fontsize=(h/2.2):y=0:x=w-mod(n*6\,w+tw):y=(h-th)/2:fontcolor=white

ここで重要なのはx=w-mod(n*6,w+tw)です。

drawtextのドキュメントを読めばわかる通り、twtext_wと同じ意味でレンダリングされるテキストの幅になります。nは開始時からのフレーム数です。mod(a, b)abで割った余りを求める関数なので通常のプログラミング言語と同じ書き方をするなら(w+tw) % (n*6)のようになるでしょうか。

例えば動画の幅が100px、文字の描画幅が合計で200pxだとしましょう。すると先の式はmod(n*6, 300)になります。nをいろいろ変えて書きだしてみましょう。

  1. n = 10 -> mod(60, 300) = 60
  2. n = 20 -> mod(120, 300) = 120
  3. n = 50 -> mod(300, 300) = 0
  4. n = 60 -> mod(360, 300) = 60
  5. n = 70 -> mod(420, 300) = 120
  6. n = 100 -> mod(600, 300) = 0

つまり50フレームごとに0になるということですね。そこで描画位置を見てみるとx=w-mod(n*6,w+tw)なので描画領域の右端(x=w)から徐々に左へ動いていくようになっています(描画位置は負の値でもかまいません)。modの部分がループする直前のn = 49で見てみるとx=w-294となってこれはさらにwを入れてみるとx=100-294になります。完全に左側へ消えませんが許容できるのではないでしょうか。

音声を聞きとりやすい音量にする

ニコラボの”ffmpegで聞き取りやすい音量に変えるdynaudnorm” が非常にわかりやすいです。

ここでは実際の使用例だけ載せておきます。

ffmpeg -f lavfi -i color=s=1280x720:c=black -i .\audio.m4a -map 0 -map 1 -c:v libx264 -filter:a dynaudnorm -c:a aac -shortest .\result.mkv

音声からノイズを除去する

ローパスフィルタを使うなどの様々な方法が存在しますが、 現状で一番手っ取り早そうなのが機械学習を用いたモデルを使う方法です。

参考記事として日本語の記事参照されている英語の記事、 そしてStackExchangeの回答を挙げておきます。

基本的な使用方法は以下の通りです。 事前にGitHubでモデルを配布しているページから必要なファイルをダウンロードしておいてください。 エンコードするファイルと同じディレクトリにあるものと仮定します。

ffmpeg -i video.mp4 -c:v copy -af 'arnndn=m=./cb.rnnn' -c:a aac -b:a 128k out.mp4

字幕をつける(ソフトサブ:mkv)

動画の字幕ファイルが別に用意してある場合、 matroska video(.mkv)形式にするとその字幕を1つのファイルにまとめることが出来ます。 このようにすることで対応したプレイヤーでは別に字幕ファイルを読まずにすみます。 ちなみに新しく字幕を自分で作る場合はsrt(SubRip)形式が簡単でおすすめです。

ffmpeg -i input.mp4 -i sub.srt -map 0:v -map 0:a -map 1 -c:v copy -c:s srt subbed.mkv

字幕は複数埋めこむことも出来ます。 この場合、それぞれの字幕にメタデータをつけておくと再生する際に混乱せずにすみます。

ffmpeg -i input.mp4 -i eng.srt -i jpn.srt -map 0:v -map 0:a -map 1 -map 2 `
  -metadata:s:s:0 language=eng -metadata:s:s:0 title="English" `
  -metadata:s:s:1 language=jpn -metadata=s:s:1 title="Japanese" `
  out.mkv

ここのメタデータを注入する際の記述について少しだけ解説します。

メタデータはファイル全体、あるいはストリームごと、チャプターごとなどいくつかの単位で埋めこむことが出来ます。 ファイル全体に対してのメタデータの場合は-metadata:gを使い、 ストリームに対しては-metadata:sを使います。

ストリームに対して使う場合はどのストリームに対してメタデータを埋めこむかを指定しないといけないので、 -mapで使うようなストリーム指定を後に続けなければなりません。 先の例だと-metadata:s:s:0は字幕ストリームで一番最初(0番目)のストリーム(s:0)を指定していることになります。

この項は “FFmpegで動画に字幕・副音声を追加する” を参考にしました。

dispositionオプションでmkvのデフォルトのトラックを指定する

mkv(Matroska)ファイルは複数の映像/音声/字幕トラックを指定できる都合上、 デフォルトでどのトラックを再生するかという情報が重要になることがあります。 この時、元ファイルからそのまま映像等をコピーするとそのトラックがデフォルトであるという情報まで同時にコピーされます。

他のトラックをデフォルトにしたい場合はデフォルトであるという情報を消さなければなりません。 それらを操作するために-dispositionオプションを使用します。 FFmpegのドキュメントの該当部分も参照してください。

ffmpeg -i video.mp4 -i audio.wav -map 0:v -map 1 -map 0:a -c:v copy -c:a:0 aac -c:a:1 copy `
    -disposition:a:0 default `
    -disposition:a:1 0 `
    out.mkv

なお後からmkvを調整したいだけならmkvpropeditを使ったほうが良いです。

ハードウェアエンコード(nvidia)

nvidiaのハードウェアエンコードで多くのビデオカードでサポートされているのは H.264(h264_nvenc)とHEVC(hevc_nvenc)の2つです。 サポートされているオプションは次のコマンドで出すことが出来ます。

ffmpeg -h encoder=h264_nvenc
ffmpeg -h encoder=hevc_nvenc

-b:v(映像ビットレート:固定ビットレート)は通常のエンコーダーと同様に使えますが、 libx264で使える-crfは使えません。代わりに-cqを使う必要があります(0から51までの値:0は自動)。

その他プロファイル等の指定も出来ます。 デフォルトでは画質を抑える設定になっているので、 必要に応じて-presetの値を変えたり(p4からp6にするとか)、 -profileの値を変えたり(mainからhighにするとか)しましょう。

AV1エンコード(SVT-AV1)

映像をアーカイブとして保存したい場合、 H.264よりも圧縮効率のよい映像コーデックにしたいことがあります。 この時候補として挙がるのがAV1です。

AV1は効率が良いコーデックですがエンコードが重いという重大な難点があります。 一部のGPUではAV1のエンコードに対応していますが GPUエンコードは残念ながらCPUエンコードに比べて品質が落ちる場合が多々あります。

ffmpegでAV1エンコードを行う場合、最も有用と思われるのがSVT-AV1(libsvtav1)です。 エンコード時間も許容できる範囲におさまることが多く、 その設定もかなり幅広くいじれるようになっています。

FFmpeg wikiの該当部分にほとんど書いてありますが、 基本的なエンコード方法は以下の通りです。

ffmpeg -i input.mp4 -c:v libsvtav1 -crf 35 -preset 8 -c:a copy out.mkv

CRFは0から63の範囲で指定できて0が一番画質が良く63が一番画質が悪くなります。 同時に低ければ低いほどファイルサイズは大きくなり高ければ高いほど小さくなります。 デフォルト値は30ですが38程度だとバランスが良いようです。

Presetは0から13までの範囲を取り高ければ高いほどエンコード速度が速くなります。 しかし13はデバッグ用なので実用的には8から10程度になるでしょう。

H.264にある-fastdecodeオプションはSVT-AV1だと-svtav1-params fast-decode=1で使用できます。 しかしこのオプションを指定する場合はPresetが5から10までの値に制限されるようです。

なお前述の文書では1080pや720pの映像にはAV1はあまり適していないみたいなことが書いてありますが、 HEVC(H.265)でのエンコードについては記述しないでおきます。

ビットレート指定メモ

どういう場合にどのビットレート指定をすればいいかを書いた文書があるのでここにメモしておきます。 雑に要約すると以下の通りです。

  • ストリーミング用途にはConstrained Encoding(VBV)を使う
    • ffmpeg -i input -c:v libx264 -crf 23 -maxrate 1M -bufsize 2M output(改変引用)
  • 保存用途にはConstant Rate Factor(CRF)を使う

以下あとから書きます。

矩形を重ねる