それFFmpegで出来るよ！

※この記事は、[mast Another Advent Calendar 2018](https://adventar.org/calendars/3341) の8日目の記事です。

# 紹介
動画や音声を加工するのに強力で万能な簡単ツール[FFmpeg](https://www.ffmpeg.org/)について便利すぎるのでいつも使っているものをまとめようと思います。

[FFmpeg](https://www.ffmpeg.org/)を使えるようになれば、用途ごとにフリーソフトをインストールしたり、重いGUIソフトを立ち上げる必要が無くなるかも？

※このツールは基本的にコマンドラインインターフェースから使うのでコマンドラインインターフェースが苦手無理って人のために、GUIで扱えるものあります。

# インストール
FFmpegのいいところは **WindowsでもmacOSでもUbuntuでも使えるところ**
便利フリーソフトはだいたい限られたOSでしか使えないこと思えば、どのOSでも使えることは大きい。

macOSでのインストールはターミナルをひらいてこんな感じ(筆者はのPCはmacOSなので...)

```bash:インストール
brew install ffmpeg
```
`-bash: brew: command not found` になる場合は[こちら](https://qiita.com/pypypyo14/items/4bf3b8bd511b6e93c9f9)

WindowsとLinuxについては公式ページを参照してください。
https://trac.ffmpeg.org/wiki/CompilationGuide

# 基本的な使い方

FFmpegの基本的な使い方はこんな感じ

```bash:基本的な使い方
ffmpeg 入力オプション -i 入力ファイル名 出力オプション 出力ファイル名
```

オプションはなくてもいい(ツールが自動で認識してくれる)

```bash:MP4動画をAVI動画に変換する
ffmpeg -i input.mp4 output.avi
```

# ケース1:動画のサイズやコーディックを知りたい
この動画のサイズ(縦横何ピクセル)や長さ(時間)を単純に知りたいときってあるよね
あとは、この動画なんか再生できないんだけどコーディックなんだろうとか

そんなときはこれ

```bash:動画の情報を調べる
ffmpeg -i 入力ファイル名
```

```bash:結果
$ ffmpeg -i input.mov 
ffmpeg version 3.4.2 Copyright (c) 2000-2018 the FFmpeg developers
  built with Apple LLVM version 9.0.0 (clang-900.0.39.2)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/3.4.2 --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --disable-jack --enable-gpl --enable-libmp3lame --enable-libx264 --enable-libxvid --enable-opencl --enable-videotoolbox --disable-lzma
  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
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mov':
  Metadata:
    major_brand     : qt  
    minor_version   : 0
    compatible_brands: qt  
    creation_time   : 2018-12-05T21:48:56.000000Z
    com.apple.quicktime.make: Apple
    com.apple.quicktime.model: MacBookPro13,3
    com.apple.quicktime.software: Mac OS X 10.13.4 (17E199)
    com.apple.quicktime.creationdate: 2018-12-06T06:47:52+0900
  Duration: 00:00:14.02, start: -0.016667, bitrate: 1509 kb/s
    Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1832x1680 [SAR 1:1 DAR 229:210], 1481 kb/s, 59.65 fps, 60 tbr, 6k tbn, 12k tbc (default)
    Metadata:
      creation_time   : 2018-12-05T21:48:56.000000Z
      handler_name    : Core Media Data Handler
      encoder         : H.264
At least one output file must be specified
```

どうやら `input.mov`は`Duration(長さ): 00:00:14.02` `サイズ:1832x1680` `コーディック:H.264` `フレームレート:59.65 fps` `ビットレート:1481 kb/s`の動画であることがわかった。

ただ `At least one output file must be specified` これは良くないので **下のが推奨**

```bash:動画の情報を調べる
ffprobe -i 入力ファイル名
```

# ケース2:動画を変換したい
macOSのQuick Playerでは再生できるのに、WindowsのWindows Media Playerでは再生できないとか、動画をMP4形式で提出してくださいだの動画の形式を変換しないといけないことって生きていればあるよね、でもFFmpegがあれば大丈夫

ただ **単純** に動画を変換するだけなら拡張子を変えるだけ

```bash:FLV形式の動画をMP4形式に変換する
ffmpeg -i input.flv output.mp4
```

```bash:MP4形式の動画をAVI形式に変換する
ffmpeg -i input.mp4 output.avi
```

拡張子から自動で判別してくれるのはありがたい。
変換に関して `コーデック` ` ビットレート` `フレームレート` `オーディオ形式` `サンプリングレート`等について指定があれば、出力オプションに追加する。


```bash:MP4形式の動画をコーディックH.265のMP4形式の動画に変換する
ffmpeg -i input.mp4 -vcodec libx265 output.mp4
```

```bash:MP4形式の動画をビットレート340kbpsのMP4形式の動画に変換する
ffmpeg -i input.mp4 -vb 340k output.mp4
```

```bash:MP4形式の動画をフレームレート120fpsのMP4形式の動画に変換する
ffmpeg -i input.mp4 -r 120 output.mp4
```

# ケース3:連番画像から動画を作りたい
`image001.png` `image002.png` `image003.png` … `imageXXX.png` と連番の画像から動画ファイルを作りたいときもFFmpeg

一番簡単なのは次のコマンド

```bash:連番ファイルから動画をつくる
ffmpeg -i image%03d.png output.mp4
```

数字が連番になっているところを`%03d`みたいなので置換する。
数字が0埋めされていなければ`%d`
0埋めされていれば`%0桁数d`にする

ただ、これだとmacOSのQuick Playerで開けないので、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/224134/7ba5f7bf-353f-5f07-5930-df3cbaa7d38e.png)


出力オプションに`-pix_fmt yuv420p`を加える

```bash:連番ファイルからmacで再生できる動画をつくる
ffmpeg -i image%03d.png -pix_fmt yuv420p output.mp4
```

自分の環境では、デフォルトで `h264 (High 4:4:4 Predictive)` になるのですがコーデックを指定したい場合は出力オプションに `-vcodec libx264`など形式を指定してあげる。

```bash:連番ファイルからH.264コーディックの動画をつくる
ffmpeg -i image%03d.png -vcodec libx264 output.mp4
```

ただ、連番画像が何枚で1秒かっていうのはFFmpegに教えてあげないといけないので
連番画像が60枚で1秒だった場合はこうだ！

```bash:60fpsの連番ファイルから動画をつくる
ffmpeg -r 60 -i image%03d.png output.mp4
```

# ケース4:動画から連番画像を作りたい
**ケース3:連番画像から動画を作りたい** の **逆** ですね。
入力ファイル名に動画を指定して、出力ファイル名に画像の拡張子を指定すればいいですね。

```bash:動画から連番ファイルをつくる
ffmpeg -i input.mp4 image%03d.png
```

このままだと、動画1秒あたりフレームレートの枚数分画像が生成するので、1秒あたり何枚かは `-r 動画一秒あたりの枚数` で指定すればよい

```bash:動画から1秒あたり60枚の連番ファイルをつくる
ffmpeg -i input.mp4 -r 60 image%03d.png
```

# ケース5:動画をgif画像にしたい
Webページに載せたりTwitterに上げたりするときgif画像って便利
FFmpegならgifを動画からつくるのは簡単

```bash:動画をgifに変換する
ffmpeg -i input.mp4 output.gif
```
たったこれだけで出来るのですが、問題はそのままのサイズ、フレームレートでgifを作ってしまうため、めちゃくちゃ大きくて重いgifができてしまいます

なのでサイズとフレームレートを指定しなければなりません。
フレームレートは `-r XX` 
サイズは `-s 横幅ピクセルx縦幅ピクセル` 
アスペクト比固定で変えるなら
`-vf scale=横幅ピクセル:-1`
`-vf scale=-1:縦幅ピクセル`
で指定できるので出力オプションに加えてあげます

```bash:動画をアスペクト比を保ったまま横幅640ピクセルにリサイズ、フレームレートは10fpsでgifに変換
ffmpeg -i input.mp4 -vf scale=640:-1 -r 10 output.gif
```
* アスペクト比を維持してサイズを変える場合は、横幅か縦幅を `-1` にします
アスペクト比を保ったまま横幅320ピクセルにリサイズなら `-vf scale=320:-1`
アスペクト比を保ったまま縦幅720ピクセルにリサイズなら `-vf scale=-1:720`

筆者はいつも [ここ](https://qiita.com/wMETAw/items/fdb754022aec1da88e6e) を参考にしている

# ケース6:動画をリサイズする
動画のピクセルサイズを変更するのもFFmpegならおてのもの、 出力オプションに `-s` を加えてあげれるだけ

```bash:動画を横幅1920ピクセル縦幅1080ピクセルにリサイズする
ffmpeg -i input.mp4 -s 1920x1080 output.mp4
```

ただ、横幅ピクセル数・縦幅ピクセル数を動画のアスペクト比によって計算しないといけないのは面倒なので
アスペクト比を維持してサイズを変える場合は、`-vf`オプションを使い横幅か縦幅を `-1` にします(ケース5にかかれたとおりですね)
アスペクト比を保ったまま横幅320ピクセルにリサイズなら `-vf scale=320:-1`
アスペクト比を保ったまま縦幅720ピクセルにリサイズなら `-vf scale=-1:720`

# ケース7:動画から音声を抜きだしたい
GUIソフトを起動して映像部分を消して音声ファイルで書き出しよりFFmpegなら少ない手順でできます。

```bash:動画からmp3形式で音声ファイルを生成する
ffmpeg -i input.mp4 output.mp3
```

余裕ですね、ファイルの拡張子を変えるだけ
ただ、これだと動画コンテナに入っている音声にはエンコードがかかる場合があるので
動画コンテナに保存されている音声をエンコードせずに抜き出したい場合は一旦中の音声形式を調べて

```bash:中に入っている音声の形式を調べる
ffmpeg -i input.mp4
#---省略---#
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 317 kb/s (default)
    Metadata:
      creation_time   : 2018-05-15T15:48:22.000000Z
      handler_name    : #Mainconcept MP4 Sound Media Handler
```
この場合は `AAC形式` なので拡張子は `m4a` ですね。出力オプションに `-acodec copy` 加えて

```bash:動画コンテナに保存されている音声をエンコードせずに抜き出す
ffmpeg -i input.mp4 -acodec copy output.m4a
```


ちなみに、動画から音を消す場合は `-an` のオプションを使います

```bash:動画コンテナに保存されている音声だけを消す
ffmpeg -i input.mp4 -vcodec copy -an output.mp4
```

# ケース8:動画を連結したい
[こちらに移動しています](https://qiita.com/cha84rakanal/items/af7884d9188ef1787a90)

<!--
動画同士を連結したいときもFFmpegなら比較的簡単!

まずは連結したい動画のリストを作る
`input01.mp4`と`input02.mp4`と`input03.mp4` を連結したいときは以下のように `inputs.txt` に書く

```text:inputs.txt
file './input01.mp4'
file './input02.mp4'
file './input03.mp4'
```
`inputs.txt` を作成して、次のコマンドを実行すると、複数の動画が連結される。

```bash:inputs.txtにリストされた動画を連結してoutput.mp4を作成する
ffmpeg -f concat -safe 0 -i inputs.txt -c copy output.mp4
```

`-safe 0`のオプションをつけているので、動画リストのファイルパスは絶対パスでも相対パスでも良い。
連結したい動画のコーディック(h.264やvp9など)がすべて同じなら `-c copy`オプションをつけることで、 **高速・無変換・無劣化** で連結できる。

連結する動画がたくさんあるならこのやり方でも手間はかからないが、 **動画A+動画B=動画C**みたいに、2つの動画をつなげたいときに、**`inputs.txt`を作成するのは手間**
そんなときは以下のコマンド、`-filter_complexs`を使って結合する

```bash:input01.mp4とinput02.mp4をつなげてoutput.mp4を作成する
ffmpeg -i input01.mp4 -i input02.mp4 \
-filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" output.mp4
```
※ `-filter_complex` の詳細は長くなるので、ここでは割愛する

**拡張子・コーディックが違くても大丈夫**

```bash:input01.mp4とinput02.webmをつなげてoutput.movを作成する
ffmpeg -i input01.mp4 -i input02.webm \
-filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" output.mov
```

**ただし、動画を連結する際、気をつけないと行けないのは、異なるサイズの動画は上記の方法では連結できない...**
例えば、 「解像度`640x480` の動画」と「解像度`1920x1080` の動画」を結合することはできない。もし結合したい場合、どちらかの解像度に **ケース6:動画をリサイズする** を参考に、解像度を変換してから結合する。
-->

# ケース9:動画をクロップ(トリミング)したい
[こちらに移動しています](https://qiita.com/cha84rakanal/items/af7884d9188ef1787a90)

<!--
画像でよくするトリミングもFFmpegならコマンドだけできる！
基本的なコマンドは次の通り

```bash:動画をクロップする
ffmpeg -i input.mp4 -vf crop={X size}:{Y size}:{X position}:{Y position} output.mp4
```

切り出す基準となる原点と、そこから切り出す動画の解像度を指定する
`X size` : 切り出す横幅ピクセル数
`Y size` : 切り出す横幅ピクセル数
`X position` : 切り出すX座標原点
`Y position` : 切り出すY座標原点

例を挙げると次のように指定する

```bash:動画を左上からX座標50ピクセル、Y座標75ピクセルの位置から横1280ピクセル、縦720ピクセルのサイズでトリミングする
ffmpeg -i input.mp4 -vf crop=1280:720:50:75 output.mp4
```

難点なのは、絵を見ながら切り抜けないところではあるが、
半分の大きさや1/4の大きさを切り出すといったときには、とても便利

参考: https://w.atwiki.jp/kobapan/pages/173.html
-->

# ケース10:動画の特定の時間範囲を取り出したい
[こちらに移動しています](https://qiita.com/cha84rakanal/items/af7884d9188ef1787a90)

# 番外編1:DVD-Video形式の動画に変換したい

DVDに書き込まれる動画形式にFFmpegなら出力オプションに `-target ntsc-dvd` を加えることで変換することができます

```bash:MP4形式の動画をDVD形式の動画に変換する
ffmpeg -i input.mp4 -target ntsc-dvd -aspect 16:9 output.mpg
```

他にも出力オプションに `-target pal-dvd` などにがあるので詳しいことは、[公式ドキュメント](https://ffmpeg.org/ffmpeg.html) を見てください

DVDに書き込まれる動画の形式は、 `MPEG-2` で解像度が主に `720x480` になります
実際に変換された動画のメタ情報をみると

```bash:変換後のメタ情報
Output #0, dvd, to 'output':
  Metadata:
    major_brand     : mp42
    minor_version   : 1
    compatible_brands: mp41mp42isom
    encoder         : Lavf58.20.100
    Stream #0:0(eng): Video: mpeg2video (Main), yuv420p, 720x480 [SAR 32:27 DAR 16:9], q=2-31, 6000 kb/s, 29.97 fps, 90k tbn, 29.97 tbc (default)
```
形式が `mpeg2video` で解像度が `720x480` になってることがわかります

<!-- 
```bash:連番ファイルから動画をつくる
ffmpeg -i 
```

https://nico-lab.net/cutting_ffmpeg/
-->

# 最後に
マルチメディアを扱う人なら覚えておきたい一品だと思います