Googleフォトをエンコーダとして使う

自力でエンコードするのがだるい

無圧縮のmkvとかクソでかい動画ファイルをエンコードしてファイルサイズを抑えようと思ったとき、 ffmepgとかHandbreakとかでローカルPCで自力エンコードするのが1番最初に来る選択肢だと思います。

が、だるい。 高品質に仕上げようとするとパラメータいじらなきゃいけないし、時間もかかる。 数日間CPUファン全回転とか現実的じゃない

Googleフォトの高画質設定使えばクラウド上で(無料で)エンコードできんじゃねってのが始まりです

Googleフォトの仕様

Googleフォトのアップロードの種類には2通りあります。
* 元のサイズを維持したまま圧縮無しでアップロードする(Google Driveの容量を消費する)
* Googleのファイル圧縮エンコーダ?を通してアップロードする(容量無限)

f:id:natena-bitte:20200915043241p:plain

今回は下の高画質を使用

Googleフォト対応形式等

詳細はここ support.google.com 解像度上限は1080pまで
対応動画形式: .mpg、.mod、.mmv、.tod、.wmv、.asf、.avi、.divx、.mov、.m4v、.3gp、.3g2、.mp4、.m2t、.m2ts、.mts、.mkv ファイル
ただし、mkvファイルをそのままGoogleフォトにアップロードしても高画質エンコードされなかったため、今回はmkv→mp4に無劣化変換処理を挟みます
ファイルサイズに10GBの制限があるため、今回はmkv→mp4の際に分割することにしました

全体の流れ

1.無圧縮mkvを用意する
2.ffmpegmkv→mp4(分割処理含む)に変換
3.Googleフォトにアップロード
4.Googleフォトからダウンロード
5.ffmpegで分割ファイルを結合

事前準備

  • 良質な回線
  • ffmpeg ※こちらの導入手順は省略します

1.無圧縮mkvを用意する

無圧縮mkvファイルの準備手段は何でも構いません。
深くは言及しませんが私はMakeMKVを使っています。

今回使用したファイル
無圧縮状態で30GB
解像度 1080p

2.ffmpegmkv→mp4(分割処理含む)に変換

今回は無圧縮mkvにチャプターがあったのでチャプターごとに分割します。

チャプター情報の取得

ffmpegに同梱されているffprobeを使います。

ffprobe input.mkv

出力結果の一部

Chapter #0:0: start 0.000000, end 236.569667
    Metadata:
      title           : Chapter 01
    Chapter #0:1: start 236.569667, end 519.819300
    Metadata:
      title           : Chapter 02
    Chapter #0:2: start 519.819300, end 773.539433
    Metadata:
      title           : Chapter 03
    Chapter #0:3: start 773.539433, end 1125.891433
    Metadata:
      title           : Chapter 04
    Chapter #0:4: start 1125.891433, end 1378.110067

分割ファイル作成コマンド

チャプター情報を元に以下のようなコマンドを作成します
ffprobeの結果をjsonで出す等すれば自動化できるかもしれません。
今回はGoogleスプレッドシートを使用しました。

ffmpeg -ss           0 -t 114.981533 -i input.mkv -c:v copy -acodec libmp3lame -b:a 320k -async 1 split00.mp4
ffmpeg -ss  114.981533 -t 289.0888   -i input.mkv -c:v copy -acodec libmp3lame -b:a 320k -async 1 split01.mp4
ffmpeg -ss  404.070333 -t 257.323734 -i input.mkv -c:v copy -acodec libmp3lame -b:a 320k -async 1 split02.mp4
ffmpeg -ss  661.394067 -t 372.4721   -i input.mkv -c:v copy -acodec libmp3lame -b:a 320k -async 1 split03.mp4
ffmpeg -ss 1033.866167 -t 456.923133 -i input.mkv -c:v copy -acodec libmp3lame -b:a 320k -async 1 split04.mp4

ffmpegのオプションの説明
-ss Chapterのstartを設定
-t Chapterのendからstartを引いた時間を設定
-i 入力ファイル
-c:v copy 無劣化コピーする
-acodec libmp3lame -b:a 320k 音声はmp3 320kbpsでエンコード(本当はAAC使いたかったけど諸事情で見送り)
-async 1 映像と音声のズレをなくすやつ なくても良さそう
一番最後 出力ファイル名を指定(mp4にすること)

分割実行

作成したコマンドを入力ファイルがある場所で実行します。
劣化コピーしているだけなので数分で全て完了します。
今回はこの時点で分割ファイルの総容量が15GBになりました。

3.Googleフォトにアップロード

ブラウザからGoogleフォトに一気に複数ファイルをアップロードするとファイルサイズが大きすぎてエラーになりました。
なので今回は一度バックアップと同期ツールでGoogleドライブにアップロードし、Googleフォトの画面でGoogleドライブに入れたファイルを選択してアップロードを行いました。
今更ですが、私はGoogleドライブの容量を増やしているのでこれが出来ましたが無料だと無理そうですね
頑張ってブラウザから1ファイルずつアップロードしましょう。
*1

4.Googleフォトからダウンロード

エンコード完了待ち

Googleフォトにアップロードした直後は360pでしか再生出来ないかもしれません。
Googleエンコード処理が終わっていないだけなので数時間ほど待ちます。

ダウンロード

ブラウザから1080pで再生できることを確認したら分割したファイルを全て選択し、ダウンロードボタンを押す。
Photos.zipというファイルがダウンロードされます。
解凍もしておきましょう。

5.ffmpegで分割ファイルを結合

分割ファイル情報作成

以下のように結合したいファイルを各行に記述したテキストファイルを作り、Googleフォトでエンコードした分割ファイルと同じ場所に配置します。
split.txt

file split00.mp4
file split01.mp4
file split02.mp4
file split03.mp4
file split04.mp4

結合実行

ffmpeg -f concat -i split.txt -c copy output.mp4

参考
qiita.com

品質等

ファイルサイズは30GBから5GBまで小さくなりました。スバラシイ
肝心の画質面ですが、無圧縮の動画と見比べても大きな劣化は見られず、とてもファイルサイズが1/6になったとは思えないクオリティです
さすがGoogle

余談

私はこの作業をそれほど頻繁にやらないため自動化等は考えていませんが、やるとしたらGoogle Photos APIsを使うのかなと思います。

*1:ちなみにGoogleフォトには一日15GBのアップロード制限があると公式は言っています