技法集と豆知識¶
本稿では FFmpeg を利用した手筋を集める。各トピックを論理的な塊に集約するほどの理解がないので、実現の簡単なものから難しいものに並べる。なお、このページに目を通す前に、参考文献 にある記事集を当たること。技術も記述も正確性において高い。
解法がフィルター単品の適用による手筋については、公式文書の当該フィルターの記載をも併せて確認すること: FFmpeg Filters Documentation
倍速¶
ただし speed は 0.5 から 100 までの値でなければならない。
$ speed=2
$ ffmpeg -i input.mp4 -vf setpts=PTS/${speed} -af atempo=${speed} out.mp4
逆再生¶
See also
映像と音声を同時に逆転させることも、一方だけを逆転させることも可能だ。
$ ffmpeg -i input.mp4 -vf reverse output.mp4
$ ffmpeg -i input.mp4 -vf reverse -af areverse output.mp4
この処理は入力全体をメモリーに格納することに注意を要する。巨大なビデオに対しては、何分割かしてからそれぞれを個別に逆転させて結合する(上述)ことを検討する。
回転および反転¶
携帯電話で撮影した映像を扱うのであれば、ちょうど 90 度だけ回転させたり反転させたりする手筋を覚えておくと何かのときに助かる。
See also
反転¶
映像フィルター hfilter, vfilter を用いる。水平軸または垂直軸に関する反転を実現する。オプションがないので紛れがない。
$ ffmpeg -i input.avi -vf "hflip" -c:a copy output.avi
$ ffmpeg -i input.avi -vf "vflip" -c:a copy output.avi
回転¶
映像フィルター transpose を用いる。コマンドの基本形は次のとおり:
$ ffmpeg -i input.mp4 -vf "transpose=dir=1" -c:a copy output.mp4
引数 dir の値は数字かキーワードで指定できる。都合の良いほうを使っていい:
| 番号 | 名前 | 変換内容 | 
|---|---|---|
| 
 | 
 | +90 度回転してミラー | 
| 
 | 
 | -90 度回転 | 
| 
 | 
 | +90 度回転 | 
| 
 | 
 | -90 度回転してミラー | 
- 有効な値には - 4..- 7もあるが、これは非推奨だ。代わりに後述の引数を指示する。
- 180 度回転は - transposeを合成すれば実現できる。
縦長・横長を ffmpeg 判定させて必要な場合に限り回転させるというコマンドもあり得る。引数 passthrough=landscape 等を指定する。「横長ならば横長のままとする」の指示を意味する:
$ ffmpeg -i input.mp4 -vf "transpose=dir=2:passthrough=landscape" -c:a copy output.mp4
ビデオを Twitter に投稿可能な状態にエンコードし直す¶
See also
携帯電話で撮影した MP4 ファイルに対してならば、上記リンク先スレッドの foone
commented on May 18, 2018 コメントのコマンドを加工して実行するといい。状況に応じてオプションを加えたり除いたりすることだ。
静止画像抽出¶
画像ファイル群からスライドショウを作成する¶
紙幅がないのでコツを箇条書きにして済ませる:
- 単純な成果で良ければフィルターを用いることはなく実現できる。入力オプション - -framerate DURATIONくらいしか本質的には与えない。
- ページごとに表示時間を変えたいなどの場合には、後述するビデオ結合の手法を選ぶ。 - file行の次に- duration行を明記する。
- 末端付近で - fileエントリーを重複させるのがコツとなる。二度目では- durationを指定しない。
- 出力オプション - -vsync vfrを指定することがある。これは、同じタイムスタンプを持つフレームが二つと存在しないように、タイムスタンプのまま通過させるか、一つを除いて捨てる。
 
一枚絵のビデオを作成する¶
画像ファイル input.jpg を 10 秒間表示するだけのビデオを作成したいとする。それには次のようなコマンドを実行する:
$ ffmpeg -loop 1 -i input.jpg -c:v libx264 -t 10 output.mp4
次のコマンドは再生時間を音楽に合わせて input.mp3 を BGM とする MP4 ビデオを出力する:
$ ffmpeg -loop 1 -i input.jpg -i input.mp3 -c:v libx264 -c:a copy -shortest output.mp4
ビデオを結合する¶
See also
同一形式のものを結合する¶
いちばん単純な場合は画面寸法、ピクセルフォーマット、codec などが同じである MP4 ファイル二つを連結するものだ。携帯電話で撮影して保存した MP4 ファイルに対して適用可能。結合処理は二段階からなる:
- 連結したいファイルの名前とパスが記載されたテキストファイルを用意する 
- このテキストファイルを ffmpeg コマンドに与える 
テキストファイルの内容は次のようなものだ:
# fileList.txt
file '/path/to/input0.mp4'
file '/path/to/input1.mp4'
コマンドラインはこうなる:
$ ffmpeg -f concat -safe 0 -i fileList.txt -c copy output.mp4
- -f concat: demuxer を- concatとする。
- -safe 0: ファイルパスに対するチェックを大甘にする。
一般の条件で結合する¶
結合コマンドを実行する前に、対象ビデオファイル群を同一形式に再エンコードする必要がある。
- 結合前のファイルに対して再エンコードする。結合する前に品質を正確に制御できる。 
- 映像フィルターのほうの - concatを用いる。
後者の例は次のようなものだ。ここでは与えないが、出力オプションで encoder を指定する余地がある:
$ ffmpeg -i input0.mp4 -i input1.mp4 -i input2.mp4 \
  -filter_complex "[0:v][0:a][1:v][1:a][2:v][2:a]
    concat=n=3:v=1:a=1[vv][aa]" \
  -map "[vv]" -map "[aa]" output.mp4
また、紙幅の都合上ここには記さぬが、ビデオファイルを TS フォーマットに変換すると UNIX/Linux コマンドの cat で直接連結が可能になる。詳しくは上述の文献を参照。
再生区間を抽出する¶
時間帯を指定して元ビデオから再生時間がより短いビデオを得たい。
See also
時間指定用オプションを以下にまとめる。まずは一部を捨てるコマンドから:
| 指定方式 | コマンド | 外で計算 | 
|---|---|---|
| 開始から指定時間だけ捨てる | 
 | NO | 
| 開始から指定時刻まで捨てる | 
 | NO | 
| 終了までの指定時間だけ捨てる | 
 | YES | 
| 指定時刻から終了まで捨てる | 
 | YES | 
終了時間付近のカットは時刻なり時間なりをあらかじめ計算しておかねばならない。
一部を残すコマンドについて述べる。 -sseof POSITION -i INPUT を用いると、時刻を終端基準とし、かつ時間軸が逆向きになる。したがって引数は負の数を指定する必要がある。
| 指定方式 | コマンド | 外で計算 | 
|---|---|---|
| 開始から指定時間だけ残す | 
 | NO | 
| 開始から指定時刻まで残す | 
 | NO | 
| 終了までの指定時間だけ残す | 
 | NO | 
| 指定時刻から終了まで残す | 
 | NO | 
内側を残す方法は上記をどうにか組み合わせる。
- -t DURATION(input/output)- (input) 入力ファイルから読み込まれるデータの継続時間 
- (output) 出力が - DURATIONに達した後、書き込みを停止する。
 
- -to POSITION(input/output)- 出力の書き込みまたは入力の読み取りを - POSITIONで停止する。
 
オプション -to と -t は同時に機能しない。両方指定すると -t が優先される。
- -ss position(input/output)- (input) この入力ファイルの位置まで seek する。厳密には - POSITIONにセットされないことが普通だ。
- (output) タイムスタンプが - POSITIONに達するまで、入力を復号しつつも捨てる。
 
- -sseof position(input)- -ssの EOF 基準バージョン。0 は EOF を指し、負の値はより BOF に近づく。
 
最後に、再エンコードをするかしないかで結合処理の性質が異なることを考慮することだ。再エンコードせずに済むならば、変質せずに高速に処理される。
ビデオの画面を伸縮する¶
See also
伸縮操作の基本は映像フィルター scale を用いるものだ。次のコマンド呼び出しは省略部分が同一ならばすべてが同値だ:
$ ffmpeg -i input.mp4 -vf scale=w=${width}:h=${height} ... output.mp4
$ ffmpeg -i input.mp4 -vf scale=${width}:${height} ... output.mp4
$ ffmpeg -i input.mp4 -vf scale=${width}x${height} ... output.mp4
品質が劣化するのが気になる場合は出力オプション部に encoding 指定をする。例えば
libx264 の低速プリセットで crf=18 を使用するなど:
$ ffmpeg -i input.mp4 -vf scale=${width}:${height} -preset slow -crf 18 output.mp4
入力画面の幅と高さをそれぞれ iw と ih で参照できる。
- 例:画面幅を二倍に拡大する - scale=iw*2:ih. この- *はシェルに展開されない。
- 例:寸法を半分にする - scale=iw/2:ih/2. こちらは引用符で囲むこと。
アスペクト比を維持して伸縮する¶
アスペクト比を保ったまま動画を拡大縮小したい場合、 height か``width`` のどちらかの引数を値で設定し、もう一方の引数の値を負の値に設定するといい。
映像形式によっては画面寸法が偶数であることを要求する。そのときは -1 の代わりに -2 を指定する:
$ ffmpeg -i input.mp4 -vf scale=320:-2 output.mp4
関数 min() と iw, ih を組み合わせれば最小の幅と高さを決められる。単純な方法で質の悪い伸縮を防げる手筋だ:
$ ffmpeg -i input.mp4 -vf "scale='min(320,iw)':'min(240,ih)'" output.mp4
テキスト¶
字幕という手もあるが、ここではフィルター drawtext を用いる方法を述べる。
See also
文字を打ち込む作業は何度も何度も画面を見直すから ffplay で確認するといい:
$ ffplay -vf "drawtext=text='なんらかのテキスト':
    fontfile=/path/to/fontfile:
    box=0:boxcolor=white@0.5:
    x=20:y=20:
    shadowx=1:shadowy=1:shadowcolor=deeppink@0.9:
    fontcolor=deeppink:fontsize=48:line_spacing=8" -autoexit -y 480 input.mp4
利用者ノート
問題はオプション fontfile の指定だ。これは Windows のフォントを指定しても
OK ではある。しかし、できれば WSL 側で適宜設定して単純なパスで指定するか、あるいは代わりにオプション font でフォント名だけを指定すれば十分であるように持っていきたい。
あと、TrueType フォントを指定すると描画が乱れる現象が起こっている。現状、拡張子 .ttc のものしか描けない。
複数配置¶
フィルター hstack, vstack, xstack がその目的にはふさわしい。
See also
フィルター hstack, vstack を組み合わることで 2x2 レイアウトを実現することもできるが、効率がより良いフィルター xstack があるのでそれを利用したい。例を示す。簡単のために、入力映像の画面寸法はすべて同じであると仮定する:
$ ffmpeg \
    -i input0.mp4 -i input1.mp4 \
    -i input2.mp4 -i input3.mp4 \
    -filter_complex "xstack=inputs=4:layout=0_0|0_h0|w0_0|w0_h0:shortest=1"
    output.mp4
これは次のようなレイアウトになる:
input0 input2
input1 input3
引数 layout の値は縦棒区切りの謎の記号だが、これで出力における各映像入力の位置を指示する。POSX_POSY のような形式で座標を指定している。数字は序数で
w0 や h0 はそれぞれ入力映像 0 の幅と高さを表す。
同系統のフィルターと同様に、入力映像すべてが同一のピクセルフォーマットでなければならない。
グリッドの個数は 2 以上でも可能だし、極端に言えばグリッド状でなくてもいい。同一の映像入力を用いてもよい。演習として、ビートマニアの V のクリップのようなものを構成してみるといい。
ぼかし¶
映像の空間的に、または時間的に一部をぼかす方法を記す。
See also
考え方を述べる。オリジナルの映像の一部を矩形に「クリップボード」にコピーし、ぼかしフィルターで加工する。加工した映像矩形を元映像の同じ位置に「貼り付ける」というのが基本的な考え方だ。コマンドラインも比較的単純な構造になる。オプション
-filter_complex の引数だけを抜粋したものを示す:
$ ffmpeg -i input.mp4 \
  -filter_complex "
    [0:v]crop=400:400:300:350,boxblur=10[fg];
    [0:v][fg]overlay=300:350[v]" \
  -map "[v]" output.mp4
模式化しておく:
- crop=400:400:300:350: 座標 (300, 350) を原点とする矩形 400x400 を crop するの意。
- overlay=300:350: オーバーレイ座標。
- boxblur=10: ぼかしの強度。
ぼかしを矩形の周囲にしたい場合は全域を boxblur した絵にオリジナルの矩形を
crop したものを overlay すればいい。また、フィルターには boxblur の他にも豊富にある。
映像遷移効果¶
Demuxer concat で物足りないときにはフィルター xfade を検討したい。これはある映像から別の映像へ切り替わるときに、スライドやワイプなどの視覚的効果を与えるものだ。
See also
次のコマンドは input0.mp4 から input1.mp4 へクロスフェイドする映像を出力するはずだ:
$ ffmpeg \
    -i input0.mp4 \
    -i input1.mp4 \
    -filter_complex "xfade=transition=fade:
    duration=${TRANSITION_DURATION_IN_SECONDS}:
    offset=${OFFSET_RELATIVE_TO_FIRST_STREAM_IN_SECONDS}" \
    output.mp4
オプション transition に効果を指定する。xfade が対応する利用可能な遷移効果を指定する。選択肢がべらぼうに多いので本稿では割愛。
オプション duration には遷移効果時間を指定する。60 秒以下である必要がある。
オプション offset には遷移を開始する時刻を秒単位で指定する。時刻の基準は最初の映像開始時点とする。
最後に出力ファイルを指定する。望むなら encoding オプションを追加的に指定する。