2Mbyte以下のwebmファイルを作りたい

webmファイルを2Mに抑えたい時ってありますよね。何の話かわからない?まぁ某所にはそういう需要があるんですよ。今回は2M以下のwebmファイルのビットレート試行錯誤をわりと効率よく作れる感じになったのでメモ書き。

1. aviutilで動画を編集する

そのまんまです。aviutilの編集の使い方は省略。

2. おもむろにエンコする

ffmpeg/arvconv出力を使ってwebm出力します。

-c:a libopus -b:a {音声のビットレート} 
-c:v libvpx-vp9 -b:v {動画のビットレート} -cpu-used 0 -speed 0 -threads 1 -quality best

※threadsは動画サイズによって適切な値が異なります。エンコ速度に関わるので詳しくはぐぐってください。

動画コーデックはVP9、音声コーデックはopusを使います。サイズ当たりの画質を少しでも上げたいので2パスでエンコしましょう。mp4ではなくてwebmを使うのはVP9が使えるからです。mp4のx265はブラウザで再生できないので今回の用途には使えません。

出力されたwebmが2M以下なら完成です。お疲れさまでした。

3. ここから今回書きたいこと

画質はいい感じだけど2Mを少し!少しだけ超えてる!画質落とすより音質削りたい!
このパターンが結構あって困ります。画質は割とぎりぎりを狙っているのに2M以下になってくれない。そういう時は仕方がないので音質を落としていきましょう。
再エンコは動画部分のエンコに時間が無駄なのでffmpegを直にたたいて調整していきます。
今回エンコしたwebmをa.webmとします。

aviutilのファイル→WAV出力でソースとなるWAVファイルを出力します。(a.wavとします)

まず、a.webmから音声ファイルを削除しb.webmを出力します。

> ffmpeg.exe -i a.webm -an -vcodec copy b.webm 

この時b.webmのサイズが動画だけのサイズなので次に作成するb.opusのサイズは(2M - a.webmのサイズ - 1k)くらいとなるようにすればいいことがわかります。1kくらい余分を持たせているのは詳しく調べていませんので不明ですがヘッダかな何かで単純に動画+音声とはなりません。余裕を持たせます。

それでは出力したa.wavファイルをopusに変換します。目標になるまで{音声のビットレート}を調整してコマンドを実行します。

> ffmpeg.exe -i a.wav -acodec libopus -b:a {音声のビットレート} b.opus

b.webmとb.opusのサイズを見ていい感じだと思ったら結合します。

> ffmpeg.exe" -i b.webm -i b.opus -vcodec copy -acodec copy c.webm

4. サムネイルをきれいにする

サムネに来るのは動画の0フレーム目なので0フレームに目立つ画像を配置しましょう。
編集→現在のフレームの画像をコピーして0フレーム目に編集→現在のフレームに画像を張り付けするといいでしょう…
とか書いてたんですが、長い動画だとすごく汚くなります。すごく。

そこで、サムネにしたい画像1フレームをaviutilで切り出し、d.webmにエンコします。(このとき無音の音声も追加してください)(3.)で確定したVP9とopusの設定でエンコするとトラブルがないと思います。

1フレームの動画ができたら、ffmpegで結合します。(ffmpegのconcatはバージョンによって記載法方法が違うらしいのでお使いのバージョンに合わせて読み替えてください)

> (echo file d.webm && echo file c.webm) | ffmpeg.exe -protocol_whitelist file,pipe  -f concat -i pipe:0 -c copy e.webm

あとはe.webmを投稿すれば終わり。お疲れ様でした。