ドキュメント作成するときに今すぐ使える ffmpeg 術

# はじめに

あらゆるドキュメントを作成する時の説明に便利な画像と動画。

画面キャプチャを取ったり、実際にカメラで撮影したりしたものや、さらに動画からのスクリーンショットを撮ったものをドキュメントに併記するだけで、かなりの読みやすさや理解のしやすさが上がります。

ということで、よくそうした事を自分のプライベートでも仕事でもやるが、やはり問題になるのが、「この動画長いな…」とか、「アップロードしようとしたら『容量でかすぎ！！』って怒られちゃった…」とか、はたまた、「文字での説明とスクリーンキャプチャを併記しながらドキュメント書きたいけど、この動画何回スクリーンキャプチャすればいいんだ…」とか。
特に最後のやつなんかはめんどくさすぎてドキュメント書く気すら失せて結局文字だけになりがちです。（そして読み手は困惑するのでです…。

こうした状況の中、動画を編集したり、画像化したりするが、わざわざ「ただ動画を○○する」という一つだけのためにアプリケーション開いて操作するのもダルいですし、そのためだけに有料アプリ購入して使用するのもなんだかなぁと思ったりしますし、まさか、それだけのために Premiere を開いてクリップを作るみたいなのもダルいです…。

という事で、はい、ここに便利なツールが古くかりますね。**ffmpeg** です。
こいつは本当に掘れば掘るほど色んな機能が出てくるめちゃくちゃ便利なツールなのですが、いかんせん、動画や画像のフォーマットや品質レベル、操作の複雑さ故、ffmpeg のコマンド操作も複雑を極めていきます。

こうした中で僕はよくこういうケースにおいてこういうコマンドをたたいているという事をシェアできればいいなと思いました。

# 基本的な使い方

ffmpeg は無料で章できるコマンドベースのアプリケーション。

https://www.ffmpeg.org

以下は、「MPEG4 形式のファイルを、Avi 形式のファイルに変化する」というコマンド。

「コマンドプロンプト」や「Windows PowerShell」、「Windows Terminal」、「ターミナル」などを開いて次のコマンドを入力してみる。

```powershell
ffmpeg -i input.mp4 <<色々色々なコマンドオプション>> output.avi
```

![output-palette.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/f1fd2e8c-bdea-7259-3e67-7bfeab9d8760.gif)

#### 説明

`input.mp4` は、入力動画ファイルパス・名前。
ここでは MPEG4 (.mp4) としているが、もちろん、ほとんどの動画ファイルは扱えるので、この限りではない。

`output.avi` は、出力動画ファイルパス・名前。
ファイル形式を変えたい場合は拡張子 (.avi) を変更する。

`<<色々色々なコマンドオプション>>` の部分に "本当に" 色んなコマンドオプションを追加していく。

基本はこんな感じで超シンプルに使えるので、使ったことない場合は一度試してみると良いと思う:exclamation::exclamation:

# ケーススタディ

## ドキュメントサービスに動画をアップロードしたい

:::note info
**想定トラブル**
* 容量制限がある
:::

例えば、Redmine を使っていたり Confluence を使っていたり、Notion を使っていたり…。
色々状況あると思うが、実際にアップロードしようとなる際に、場合によっては容量制限で怒られることがある。

そういった際には、動画の無駄を省いたり、サイズを小さくしたりしたい。
4K で撮影したものをそのままドキュメントに張り付ける…なんてことは、さすがにドキュメントサービス側も想定してないだろうし…:sweat_smile:

### トリムする

```powershell
ffmpeg -i input.mp4 -ss 00:00:02 -to 00:00:07 output.mp4
```

こういう長さのものを、

![output-palette.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/053512c6-6b32-9499-4dbe-f48d175a96f3.gif)

こうできる。
無駄な前後余白を消せた:exclamation: 

![preview_01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/66fa3d52-c693-b7e2-ea61-1f18501ab1c3.gif)

#### 説明

`-ss` は開始時間。「00:00:00」は、「時間:分:秒」の並び。
`-to` 終了時間。開始時間と同じ表記もできるが、秒数でも指定できる。
その場合は `-to 300` (5分と同等) と「開始時間からの長さ」として指定できる。ただ、この指定の仕方は、分レベルの長さになってくると計算がめんどくさくなってくるので、動画プレイヤーの表記どおりに認識できる前者の指定方法の方が好み。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/03bcf30c-247e-2f0d-59bb-959192c7e682.png)

### リサイズして小さくする

```powershell
ffmpeg -i input.mp4 -vf scale=600:-1 output.mp4
```

左が元の大きさ。右が解像度をリサイズ後。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/f4e500f9-51bc-dae2-2e22-b8ce893dce15.png)

容量もちゃんと落ちている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/e3c09299-be15-c5ca-2f53-6fa8187cdab2.png)

#### 説明

`scale=640:-1` は、横のサイズを `640` (pixel) に、`-1` はアスペクト比 (横/縦の比率) を維持しながら自動リサイズ。
逆に縦サイズを優先したい場合は `scale=-1:640` と指定する。

では、両方の数値を指定すると…？例えば、`640:200` とか
こんな感じになってしまう :joy:

![preview_03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/44dcccfc-f662-1cd1-02b0-ec3bee85b24b.gif)



### トリムしながら解像度を小さくする

以上のコマンドを以下の様にして一度に実行することもできる。便利 :exclamation::exclamation:

```powershell
ffmpeg -i input.mp4 -ss 00:00:02 -to 00:00:07 -vf scale=600:-1 output.mp4
```


## ページドキュメント (Word とか、Google Document とか、 Confluence とか) にキャプチャを貼り付けたい

:::note info
**想定トラブル**
* 扱うファイルは動画からキャプチャした画像でありたい
:::

```powershell
ffmpeg -i input_file.mp4 -r 2 -f image2 %06d.png
```

こんな感じに連番画像が書き出される。これを選びたいものを選んでドキュメントサービスに張り付けていくだけ。
ここまで簡単だと、いちいちドキュメント用にスクリーンキャプチャを何十枚・何百枚など撮らず、「とりあえずキャプチャ動画だけ取っておいて、このコマンドで画像化したものを選んで張る！」って選択肢の方が楽！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/35b6e307-9907-a67c-c4c5-3bbd1a40ee5f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/6c200d22-7601-4617-6c6a-5d2a9091ce42.png)


#### 説明

`-r 2` は、「1秒間に2枚撮影してください」という指定。
`-r 10` とすると、「1秒間に10枚撮影してください」という指示になる。
逆に、`-r 1/10` とすると、「10秒ごとに1枚撮影してください」という指示ができる。

また、僕は、書き出す画像は、PNG で保存することが多いが、もちろん JPEG などでも保存可能。
（ただ、ばあいによってｈ追加でオプションを入れないと劣化が発生したりするので、シンプルに PNG で出すのが楽。


## 時計回りに90°回転してしまった動画を説明動画として保存したい

:::note info
**想定トラブル**
* 携帯で撮影した動画が横むいちゃってた


:::

あるあるですね…。。

```powershell
ffmpeg -i input.mp4 -vf "transpose=2" output.mp4
```

回転してしまったものを直すのもオプション一つ渡すだけ！
もちろん逆回転したり上下反転したりとかも可能。

| 元動画| → | 回転後 |
|:-:|:-:|:-:|
|<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/7f6556dc-564e-349c-4c3f-2fa2e00da009.gif"/>||![output-palette2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/8c9986c5-8f42-6766-0ea8-618512a33340.gif)|





#### 説明

`-vf transcode=` に以下のいずれかの数値を渡す事で回転処理を行う。

| 数値 | 説明 |
|:-:|:-|
|0|90度、反時計まわり回転の後、上下を反転|
|1|90度、時計まわりに回転|
|2|90度、反時計まわりに回転|
|3|90度、時計まわり回転の後、上下を反転|


## Qiita に Gif を貼り付けたい

:::note info
**想定トラブル**
* 動画ファイルを貼り付けられない
* 容量制限がある
* 表示の品質はある程度保ちたい
:::

Qiita に動く絵を貼り付けたい。
という事ですぐに思いつくのは Gif 画像を貼り付ける方法。

```powershell
ffmpeg -i input.mov -filter_complex "[0:v] fps=10,scale=640:-1,split [a][b];[a] palettegen [p];[b][p] paletteuse" output-palette.gif
```

ちょっと長いが、今のところこのコマンドから得られる結果は容量と見やすさとの間でちょうどいいと感じている。（多分また別の方法もあるが、そこは深淵…

結果はこれ。

![preview_02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/83ca3419-7e86-73a6-c743-e2c3d1040733.gif)

#### 説明

`-filter_complex` オプションにオプション文字列を渡す事で複雑な表記指定ができる。

`fps=10` は、動画の fps (大体の動画は 30 や 60 くらいのことが多い。ちなみに fps は「Frame per Second の略（1秒毎のフレーム画像の枚数）」)だいたい 10-14フレームくらいであれば、ギリギリストレスなく見られる量として減らせる。
実は、先の同じ様な Gif は、fps はオリジナルのまま (30fps) で書き出している。違いが分かるだろうか？

`scale=640:-1` は、先と同様、横のサイズを `640` に、`-1` はアスペクト比を維持しながら自動リサイズ。

`split [a][b];[a] palettegen [p];[b][p] paletteuse` は、カラーパレットコントロールの部分。
256色の色の扱いを最適化してくれる。
もしこれがないと、次のようにやたらドットが多く、汚くなる。

![gif_scale_fps.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/e4628448-32a6-212c-f12a-bbee5e5460cf.gif)

#### 参考

https://qiita.com/yusuga/items/ba7b5c2cac3f2928f040

## ドキュメントにスプライトシートを貼り付けたい

:::note info
**想定トラブル**
* 動画を開くまでどういう動画かわからず探すのに迷う
:::

```powershell
ffmpeg -i input.mp4 -vf "scale=300:-1,fps=1/10,tile=3x3:padding=10:color=white,pad=iw+20:ih+20:40:40:white" -frames:v 1 output.png
```

このコマンドを使うと以下の様にスプライトシートを作成できる。（突然の原神キャプチャ
30分以上の動画とかで、そのまま上げると怒られるから、とりあえずファイルサーバーに置いておこう。ってやつも、こうして画像付きでリンク貼って会ったら参照者もとても助かる。

![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/2906146f-2bca-e2f8-7b39-7a192eac9ed2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/61460daa-3c8c-aee4-315f-95a94be7ee05.png)

#### 説明

`-vf` の `scale=1200:-1` で、アスペクト比を固定しながら、**それぞれのキャプチャを**横幅を1200ピクセルにスケール。

`-vf` の `fps=1/10` が、どれくらいのフレーム間隔でキャプチャするかの指定。
`1/10` とすると「10秒間に一回」となる。
動画の全体の総フレーム数を計算して、こちらに充てる方法もあるが、僕の場合はパパっとやっちゃう分であれば概算を入れることのほうが多い。

`-vf` の `tile=3x3:padding=20:color=white` が、「『横3列、縦3行』の『20ピクセル分』の『白色の空白』を追加したスプライトシートを作りますよ」という指定。
`:padding=20` の `20` がピクセル数。ここは画像にした際のお好み空白サイズで。
`:color=white` がない場合は黒色になるので、そこはお好みで。

`-vf` の `pad=iw+40:ih+40:80:80:white` は、「『横と縦に40px ずつ』ずらし、4方向に縦横それぞれ合計80ピクセル分の白色の空白をあける」という指示。
`iw` と `ih` の数値は、その後のあけるピクセル分の 1/2 にしておくと等間隔に空間を作れる。

`-frames:v 1` は、1フレームとして処理しますという指定。
これがないと、以下のようなエラー表示される。（動かないわけではないが、エラーは極力なくす。
```
[image2 @ 00000200f733ed40] Could not get frame filename number 2 from pattern 'putput.png'. Use '-frames:v 1' for a single image, or '-update' option, or use a pattern such as %03d within the filename.
av_interleaved_write_frame(): Invalid argument
```

# さいごに

こうして ffmpeg を駆使していくと、もはやちゃんと動画作る時以外これでいいじゃんとなってしまった:fist:
コマンド操作していて、そこに動画があったら、とりあえず ffmpeg に読ませてみて操作してたり…。。

もちろん、より品質にこだわってみたりだとか、別の表現方法を行ったりだとか、こだわるともっともっと方法が出てくるので、ffmeg がチョトダケワカルの世界に行くにはちょっとキリがないかもしれない… :thinking: 

兎にも角にも、無料でできて、今からでも始められるライフハックの一つだと思うので、皆さんもお試しあれ :movie_camera::exclamation::exclamation: