ガラケー時代にハマっていた動画変換ナレッジを令和最新版にアプデしてみる

（この記事は [KDDI Engineer & Designer Advent Calendar 2021](https://qiita.com/advent-calendar/2021/engineer-designer) の第16日目エントリーです）

今月は調子に乗ってアドベントカレンダーやイベント参戦を詰め込みすぎてしまい、業後や週末はずっと記事書いたり資料作ってる気がします。。笑

# むかしむかし…
もう十数年前の話になります。私は中学高校のころ、実家から片道1時間半かけて電車通学をしていました。
その長い通学時間を有効に使うべく、**お気に入りの動画を当時全盛のガラケーやMP3ウォークマンで持ち運べるよう変換することに命をかけていた**時期がありました。
クラスのみんながニコニコ動画で盛り上がり、文化祭でハルヒダンスを踊るのが流行っていた時代です。

今やスマホ＆5Gの時代。もはや動画なんて変換しなくてもストリーミングでどこでもすぐに再生できます。でもたまにWi-Fiが使えない飛行機内や、ギガを節約したいけどビデオ観たい…みたいなとき、動画や音声を自由自在にエンコードできると何かと便利です。

私は当時のH.264時代のまま知識が止まってしまっているので、久々に最新の状況をキャッチアップしてみようと思います。

# 環境ビフォーアフター
当時は「携帯動画変換君」というフリーソフトを愛用していました。
環境はマルチコアCPUが普及し始めたころのWindows PCです。
![スクリーンショット 2021-12-11 17.13.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/c8bf6238-b758-b184-362e-62d970a21bb2.png)
*（画像出典：[MobileHackerz](http://mobilehackerz.jp)）*

「変換君」のすごいところは、**FFmpeg**という有名なエンコードライブラリをシンプルなGUIで簡単に操作できること、かつ設定ファイルをカスタマイズしたり外部エンコーダーを配置することで動画・音声変換の統合フロントエンドとして自由自在に何でもできることです。そして無料。
ど文系の私でも簡単に使えました。

あらゆるオプションを駆使して最高画質＆軽量サイズを探究するのは楽しく、コンフィグファイルを電子辞書に転送して学校の授業中もずっと眺めていたものです。
x264開発者のDark_Shikari氏（アニメ好きのアメリカ人？）と海外のフォーラムで直接QAを交わしてみたりして、英語力も若干鍛えられました。笑

しかし当時SONY教に傾倒しアンチiPodを掲げていた私も、今やAppleに心を売り渡しスマホはiPhone、自宅PCはMacのみ。自作していたWindows PCも売り払ってしまいました。
ということで変換君が使えないため、最新のM1 MacBook Air環境でFFmpegやx265の最新版をコマンドベースで動かしてみたいと思います。

# 大抵の動画をエラーなく変換できちゃう「FFmpeg」
動画を変換する際に考えることは、アウトプットする動画ファイルの形式です。
**変換効率がよく** （画質を保ったままファイルサイズを節約できる）、**汎用性が高い**（だいたいどんな機器でも再生できる）コーデックを選定し、それに適したエンコーダーを使う必要があります。

当時はH.264コーデック全盛期、エンコーダーはx264がデファクトスタンダードでした。FFmpegにもlibx264ライブラリが内包されています。
ただし、FFmpeg付属のlibx264だと最新版x264の機能が使えないこと、またデフォルト指定のオプションが微妙（アンチパターンっぽい設定値が含まれていたことがある）ためネイティブのx264をそのまま使えればそれがベストでした。
![X264.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/801488aa-1fcf-c566-87dd-eb391586f783.png)
*（画像出典：[Wikipedia](https://ja.wikipedia.org/wiki/X264)）*

しかしながら、x264だとインプットファイルのデコード段階で結構な確率でエラーを吐きます。
動画ファイルには様々なフォーマット、コーデックを含む可能性があるため当然なのですが、これを解決するのがFFmpegくんです。こいつは大抵の動画であれば問題なく取り込み、エンコードしてくれるため**「とりあえずFFmpegに放り込んでロスレス（品質を損なわない可逆圧縮）変換しておき、それから目当てのエンコーダーに通す」**といった使い方が可能です。

また、様々な動画・音声コーデックのライブラリを内包しているため、個別のエンコーダーを別途入手することなく大抵の形式でデコードとエンコードができてしまいます。

# FFmpegをM1 Macにインストールしてみる
ターミナルを起動。まずはパッケージマネージャーのHomebrewをインストールします。
（ `brew help` が通ればインストール済みなのでスキップ可能）
[このへん](https://fukatsu.tech/install-ffmpeg)を参考に、curlコマンドをコピペして1行打つだけです。

```bash:ターミナル
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

終わったら出力に従って、パスを通しておきます。

```bash:ターミナル
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/(ユーザー名)/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
```

完了したら、このHomebrewを使ってMacにFFmpegをインストールします。

```bash:ターミナル
brew install ffmpeg
```

結構かかります。

# FFmpegを使って動画変換してみる
FFmpegの基本文法は以下です。

```
ffmpeg -i (入力ファイル) (出力ファイル）
```

変換元のサンプルファイルとして、私が大好きな長野県上高地の梓川を撮ったホームビデオを使います。

iPhoneで撮影。フルHDですが、18秒と短いためファイルサイズは39MB。
コーデックはHEVC（H.265）動画＋AAC音声、コンテナはQuicktime形式のMOV。
![スクリーンショット 2021-12-11 17.52.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/f853b7ad-ee8b-0ee5-3424-8ab63d10b845.png)
こいつをまずはシンプルにコンテナのみMP4形式に変換してみます。

```bash:ターミナル
ffmpeg -i kamikochi.mov test1.mp4
```

変換中はターミナルに進捗がゴリゴリ出力されます。そして成功した模様。
![スクリーンショット 2021-12-11 18.15.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/ea40bf97-499a-e3d5-cb14-da9e7d10d592.png)
比べてみると、変換後の方がファイルサイズ大きくなってますねｗ
HEVCからAVC（H.264）になっており、やはり圧縮効率が落ちたものと思われます。
見た目の画質は両者、大差なし。

明示的にオプションを指定していませんでしたが、ターミナルを遡ってログを確認するとどのようなオプションが暗黙的に指定されたか見ることができます。

```bash:ターミナル
[libx264 @ 0x15b009200] profile High, level 4.2, 4:2:0, 8-bit
[libx264 @ 0x15b009200] 264 - core 163 r3060 5db6aa6 - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'test1.mp4':
```

（長いのでめっちゃ右にスクロールします）
見慣れないと難しそうにみえますが、大事な点は以下です。

- プロファイル指定：再生機器の互換性が左右されます。今回はH.264のHighプロファイル、レベルは4.2
- `crf=23.0`：可変ビットレート（VBR）における動画品質の重みづけ。小さいほど高画質＆サイズ大。23は結構いい方のはず。出力結果を見ると今回は結果的に21,973 kbpsになっていました。
- `keyint=250`：動画ファイルはパラパラ漫画のようなもので、GOP（Group of Picture）という単位で画像の束がまとめられています。このオプションで束のインデックス間隔を指定するのですが、値を大きくすれば圧縮効率が上がってファイルサイズを節約できるものの、再生時にシークバーでコマ送りをするときの間隔がガバッと広くなりユーザビリティが落ちるため注意。
- `-r` オプションでフレームレートも指定可能なのですが、見当たりませんね。どこかの値で入力コピーしているような気がします。

それでは、少しオプションをいじって再トライしてみます。要件は以下とします。

- ビデオ：H.265形式、HD解像度（1280x720）
- オーディオ：変更なし
- コンテナはMP4

```bash:ターミナル
ffmpeg -i kamikochi.mov -c:v libx265 -s 1280x720 test2.mp4
```

変換完了。サイズも縮んだようなのですが、残念ながらQuicktime Playerで再生エラーとなってしまいました。
![スクリーンショット 2021-12-11 18.44.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/1b9969ba-2cc0-f53f-065a-731d7bc006ef.png)
恐らく互換性に問題がありそうなので、ググって対処します。
[このへん](http://kameya-z.way-nifty.com/blog/2019/07/post-b775d1.html)を参考にして `-tag` オプションを追加しました。

```bash:ターミナル
ffmpeg -i kamikochi.mov -c:v libx265 -s 1280x720 -tag:v hvc1 test2.mp4
```

すると上手くいったようです。今度はQuicktimeでも再生可能。
指定どおり解像度がリサイズされ、H.265（HEVC）の軽量なビデオになりました。
![スクリーンショット 2021-12-11 18.55.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/d1f25e20-c2da-60dd-f0e3-4008420f5a49.png)

# おわりに
今回はここまでにしますが、今度はネイティブのx265エンコーダーを使ってみたり、音声フォーマットも好きな形式に変えてみたりと色々試してみたいなと思います。

こいつを**AWS上で動かして、ウェブブラウザからGUIで操作できるアプリ**なんか作っても面白そうだな〜と思いつきました。冬休みの宿題にしてみます。。

※ ちなみに梓川のホームビデオはS3にアップしてCloudFrontでストリーミングしてみました。皆さんもぜひ癒されてみてください。
https://cloudfront.minoruonda.com/azusa.mp4