はじめまして、株式会社モルフォのシニアリサーチャーの佐藤真希です。いつもと趣向を変えて、今回から3回にわたり ffmpeg というツールの使い方を紹介したいと思います。
ffmpeg というのは、動画ファイルの形式を変換したり、動画に画像処理を施したりすることができる高性能なフリーソフトです。動画処理技術の開発を行う上でなくてはならないもので、弊社でも広く使われています。(もちろん製品内部には使われていません。)とても高性能なのですが、使い方にクセがあって、検索してもまとまった情報を見つけるのがなかなか難しいのが現状です。
「ちょっと ffmpeg を使ってみたいけど、どうすればいいのか分からない」という人の役に立てばと思い、社内向けの資料の一部を公開します。なお、話を簡単にするために、以下のように限定された場合についてのみ考えます。
- 1つのファイルに動画ストリームが1つだけ含まれている
- 入力は YUV データで、色空間の変換は行わない
- 音声や字幕は考えない
いくつかの例で処理結果を埋め込んでいますが、その元動画はこれです。
また、この記事を書くにあたって動作を確認している ffmpeg のバージョン情報は、以下の通りです。
ffmpeg version 3.4.6-0ubuntu0.18.04.1 Copyright (c) 2000-2019 the FFmpeg developers built with gcc 7 (Ubuntu 7.3.0-16ubuntu3) configuration: --prefix=/usr --extra-version=0ubuntu0.18.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared libavutil 55. 78.100 / 55. 78.100 libavcodec 57.107.100 / 57.107.100 libavformat 57. 83.100 / 57. 83.100 libavdevice 57. 10.100 / 57. 10.100 libavfilter 6.107.100 / 6.107.100 libavresample 3. 7. 0 / 3. 7. 0 libswscale 4. 8.100 / 4. 8.100 libswresample 2. 9.100 / 2. 9.100 libpostproc 54. 7.100 / 54. 7.100
第1回目の内容は、ffmpeg の基本である動画形式の変換についての話です。参考になれば幸いです。
- トランスコード
- 主要オプション解説
- フォーマット指定: -f (in/out)
- コーデック指定: -c:v / -codec:v / -vcodec (in/out)
- 動画の長さの指定: -t (in/out)
- 動画の開始時刻の指定: -ss (in/out)
- 品質指定: -q:v / -qscale:v (out)
- 品質指定(最小): -qmin (out)
- 品質指定(最大): -qmax (out)
- フレームレート指定: -r (in/out)
- 動画サイズ指定: -s (in/out)
- ピクセルフォーマット指定: -pix_fmt (in/out)
- ビットレート指定: -b:v (out)
- 音声無効化: -an (in/out)
- コマンド例
- 主要オプション解説
トランスコード
基本となるトランスコーダー的使い方について説明する。トランスコードとは、符号化してあるものを一旦復号化し、別の形式で符号化しなおす処理全般のことを言う。書式は以下の通り。
ffmpeg INPUT_OPTIONS -i INPUT_FILE OUTPUT_OPTIONS OUTPUT_FILE
入力ファイルと出力ファイルを指定して、あとは適宜オプションを指定すればよい。基本的にはそれだけである。例えば、AVI を MP4 に変換するには、
ffmpeg -i input.avi output.mp4
とすればよい。実際これで動くわけだが、これだと出力のコーデックがどうなっているのか、ビットレートはどうなのか、何も分からない。これらの不足している情報は自動的に補われ、例えばこの場合だと、出力のコーデックはおそらく H.264 になるものと思われる。
出力のビットレート等を具体的に指定したくなったときに使うのが出力オプションである。例えば動画のビットレートを 2 Mbps にしたいのであれば、
ffmpeg -i input.avi -b:v 2M output.mp4
とすればよい。もちろん1パス処理なので正確にこの値になるわけではないが、ある程度コントロールできる。では入力のオプションは何に使うのかと言うと、フォーマットに含まれていない情報を補ったり、それを上書きしたりするときに使う。また、純粋なトランスコード以外の簡単な加工、例えば動画サイズ変更、を行うオプションも存在する。
主要オプション解説
以下、主要なオプションについて簡単に解説する。/ で区切られているのは同じオプションの表記違い、(in), (out), (in/out) はそれぞれ、入力用オプション、出力用オプション、両方に使用可能なオプションを意味する。
フォーマット指定: -f (in/out)
フォーマットを指定するオプションだが、ほぼ100%拡張子から判定できるので、よほど変なことをしようと思わない限り基本的には不要。変なことというのは、例えば拡張子が avi の MP4 ファイルを作るなど。使う可能性があるものとしては、複数の動画を結合する際に使う concat
と、RAW データを表す rawvideo
がある。
コーデック指定: -c:v / -codec:v / -vcodec (in/out)
v
の部分はビデオを意味する。同様にして、音声コーデックは -c:a
で指定できる。動画も音声もまとめて扱う際は、-c
とすればよい。使うことが多いと思われるコーデックをいくつか挙げておく。
ffmpeg での表記 | 対応するコーデック |
---|---|
libx264 OR h264 | H.264 / AVC |
libx265 OR hevc | H.265 / HEAV |
mpeg4 | MPEG-4 Part 2 |
mpeg2video | MPEG-2 Part 2 |
rawvideo | RAW |
MPEG-1 は古すぎるので、MPEG-3 は存在しないので挙げていない。H.264 と H.265 については、libx264 と libx265 がエンコーダー、h264 と hevc がデコーダーに対応する。仕様可能なコーデック一覧は、
ffmpeg -codecs
で取得できる。
動画の長さの指定: -t (in/out)
動画を指定した長さで打ち切ることができる。単位は秒。入力と出力に適応可能だが、これはそれぞれ、入力動画基準で何秒か、出力動画基準で何秒かという指定になる。この区別は、例えば途中で再生速度を変更したりタイムスタンプを書き換えたりした際に意味を持つ。
動画の開始時刻の指定: -ss (in/out)
単位は秒で、入出力両方に適応可能なことの意味合いは -t
と同様。
品質指定: -q:v / -qscale:v (out)
出力の品質を指定できる。小さい方が高品質だが、ファイルサイズは大きくなる。具体的な意味合いはエンコーダーに依存する。なお、H.264 の場合はどうやらエンコーダーがこの指定を無視するようなので、代わりに以下の2つのエンコーダーオプションを用いる必要がある。
品質指定(最小): -qmin (out)
H.264 等のエンコーダーは、フレームごとに異なる q の値を使っている。このオプションは q の値域の最小値を指定する。
品質指定(最大): -qmax (out)
同様に q の値域の最大値を指定する。具体的な使い方はここを参照。
品質オプションのようにエンコーダー依存が大きいものに関しては、コーデックごとに何が有効か色々と試してみる必要がある。
フレームレート指定: -r (in/out)
単位は FPS。入力への指定と出力への指定で、振る舞いが異なる。入力へ指定した場合、動画に元からあるタイムスタンプが破棄され、ここで指定したフレームレートに基づいて新しくタイムスタンプが振り直される。つまり、間接的に動画の長さが変わることになる。出力へ指定した場合は、いわゆるフレームレート変換的な振る舞いになり、動画の長さは変わらない。なおフレーム補間は行われず、時間的に近いフレームが参照される。
動画サイズ指定: -s (in/out)
指定は -s 1920x1080
という要領で行う。これも入力と出力で意味が異なる。RAW データ等サイズが分からないフォーマットの場合、このオプションを用いてサイズ指定を行う。出力へ指定した場合は、そのサイズへの拡大縮小処理が走る。
ピクセルフォーマット指定: -pix_fmt (in/out)
ピクセルフォーマットとは、YUV データの並び方、ビット深度、UV のサブサンプリング方式等を指定するものである。動画サイズと同様、入力は値が不明なフォーマットの場合の指定、出力はその形式への変換となる。よく使われる、8-bit PLANAR のピクセルフォーマット例をいくつか挙げる。PLANAR というのは、YUV チャンネルをそれぞれ1枚の画像として保持する形式である。
ffmpeg での表記 | UV サブサンプリング |
---|---|
yuv420p | 縦横共に 1/ 2 にサブサンプリング |
yuvj420p | 縦横共に 1/ 2 にサブサンプリング |
yuv422p | 縦のみ 1/ 2 にサブサンプリング |
yuv444p | サブサンプリングしない |
yuvj420p
とは yuv420p
のフルレンジ版であり、j
は JPEG からきている。レンジ設定は別にあるので、これは本来であればピクセルフォーマットに含めるべきものではない。ffmpeg としても depricated な設定だが、見かけることがあるので挙げた。フォーマットの一覧は、
ffmpeg -pix_fmts
で取得できる。
ビットレート指定: -b:v (out)
単位は bps。M や K などの接頭辞も使用可能。-qmin
, -qmax
と同様これもエンコーダーへのオプション指定であるが、あまり違いについて考える必要はない。なお、品質と同時に指定した場合にどちらが優先されるのかは把握していない。
音声無効化: -an (in/out)
最後に動画用のオプションではないが、便利なので挙げておく。これを指定すれば音声が削除される。
コマンド例
フォーマットだけ変換する
例えば AVI を MP4 に変換したいが、動画も音声もコーデックはそのままでいいという場合がある。そのときは、
ffmpeg -i input.avi -c copy output.mp4
とすれば、再エンコードなしで入れ物(フォーマット)だけ変更することができる。逆に言えば、-c copy
を指定しない場合、仮に同じコーデックであったとしても再エンコードが走るので、品質が落ちる結果になる。
動画のコーデックを H.264 に変換する
人に動画を渡す際は、コーデックを H.264 にしておくのが現状では無難。
ffmpeg -i input.mp4 -c:v libx264 output.mp4
ただ、どこまで確実なのかは把握していないが、コーデック指定を省いて
ffmpeg -i input.mp4 output.mp4
としても望む結果は得られると思う。
RAW データをエンコードする
RAW データの場合は、最低限画像サイズとピクセルフォーマットを指定する必要がある。
ffmpeg -f rawvideo -s 1920x1080 -pix_fmt yuv420p -r 30 -i input.yuv output.mp4
input.yuv
は、エンコードしたい全てのフレームデータを1つのファイル内で並べたものである。この例のように yuv 拡張子を使えば、-f rawvideo
は省略できる。
H.264 動画の品質コントロール
オプションのところでも述べたが、H.264 の品質コントロールには -qmin
, -qmax
を用いる必要がある。例えば、
ffmpeg -i input.mp4 -qmax 16 -c:v libx264 output.mp4
として q の最大値を 16 あたりで抑えると、かなり高品質な動画になる。望む品質を得るには、数字を変更しつつ必要に応じて -qmin
も指定すればよい。
4K 10-bit の動画を 2K 8-bit YUV420 に変換する
4K 動画や 10-bit 動画は扱いにくいので、2K 8-bit の YUV420 動画に変換したいときがある。
ffmpeg -i input.mp4 -s 1920x1080 -pix_fmt yuv420p output.mp4
YUV444 動画を用意する
あまり見かけないフォーマット(例えば YUV444)の動画が必要な時があるが、変換すれば簡単に手に入る。
ffmpeg -i input.mp4 -pix_fmt yuv444p output.mp4
動画を連番 JPEG に変換する
printf の要領で JPEG ファイル名のパターンを出力に指定すれば、連番 JPEG への変換が行われる。
ffmpeg -r 1 -i input.mp4 'out/img%05d.jpg'
ファイルパスは特殊文字や空白を含むことがあるので、念の為に '
で囲っている。一般的に動画のフレームレートは一定ではないが、ffmpeg の連番 JPEG 出力機能は定フレームレートで JPEG を作ってしまう。そのままだと、タイムスタンプがズレて飛ばされるフレームや重複するフレームが出てしまうので、入力側に -r 1
を設定して防止している。強制的に入力を定フレームレートにしたいだけなので、-r 1
の 1
の部分は何でもよい。
なお、別のやり方としては以下でもよい。
ffmpeg -i input.mp4 -vsync passthrough 'out/img%05d.jpg'
これは、出力側と入力側で同じタイムスタンプを使うことを強制している。つまり、「勝手に定フレームレートにせずに、入力通りのタイミングで JPEG にせよ」という指示である。
連番 JPEG を動画に変換する
これは先ほどの逆操作で、簡単である。
ffmpeg -r 30 -i 'in/img%05d.jpg' output.mp4
フレームレートを指定しないと 25 FPS になる。つまり、30 FPS 動画を作ろうとして
ffmpeg -i 'in/img%05d.jpg' -r 30 output.mp4
としてしまうと、25 FPS の動画を 30 FPS に変換したものができてしまうので注意。
簡易スローモーション動画の作成
例えば入力動画が 30 FPS だとすると、
ffmpeg -r 7.5 -i input.mp4 output.mp4
とするだけで、4倍のスローモーション動画を作ることができる。
簡易タイムラプス動画の作成
基本的にはスローモーションの逆である。30 FPS 動画を4倍速にするには、以下のようにすればよい。
ffmpeg -r 120 -i input.mp4 -r 30 output.mp4
120 FPS 動画を表示させるのは現実的ではないので、出力側に常識的なフレームレートを指定して間引きを行っている。
複数の動画ファイルを結合する
複数の動画ファイルを結合するには、まず結合する順番にファイルパスを並べたテキストファイルを用意する。
# 動画のパスをつなげる順に列挙する file 'input1.mp4' file 'input2.mp4' file 'input3.mp4'
このように、file
の後にパスを記述する。なお、#
はコメントであり、念のためにパスを '
で囲っている。フォーマットを concat
とし、このテキストファイルを入力として設定すれば、結合された結果が得られる。
ffmpeg -f concat -safe 0 -i input.txt output.mp4
オプション -safe 0
は必須ではないが、これがないと書き方によっては「安全ではないパス」として弾かれてしまい面倒なので、付けている。入力動画のコーデックが同一なら、
ffmpeg -f concat -safe 0 -i input.txt -c copy output.mp4
のように書いて再エンコードを避けることもできる。
一定間隔おきに動画の内容を静止画にして保存する
長い動画の内容をひと目で把握するために、例えば10秒おきにフレームを取り出したい場合がある。出力のフレームレート指定を利用して連番 JPEG に変換すれば、簡単に実現できる。
ffmpeg -i input.mp4 -r 1/10 'out/img%05d.jpg'
動画から音声だけを削除する
動画データには手を加えずに、音声データだけファイルから削除する。
ffmpeg -i input.mp4 -c:v copy -an output.mp4
ffprobe
話が少しズレるが、動画ファイルの情報を調べたいときは ffprobe を使うのがよい。
ffprobe input.mp4
また、オプションを追加して
ffprobe -show_streams input.mp4
とすれば、かなり詳細な情報が得られる。