Chienomi

メディアアーカイブ(動画/写真)の圧縮を行った

Live With Linux::dailyhack

私は旧 “world” 系統のストレージに収められていたデータと、 “degraded” 系統のストレージに収められていたデータをそれぞれ local.old, local として分離している。 この理由は、運用の違いとデータ整理に関係する。

“world” 系統のストレージが構築されたとき(当時実効12TB)、システムストレージは128GBのSSDであり、残りのすべてを “world” ストレージに置く形であった。

つまり、worldストレージは書き込みが行われる対象であり、どうしても保存するその時は「あっ、どこに置こう」となることが多いため、汚れやすい。 このことから既にファイルを探すことが難しくなってしまっている。

対して、degratedストレージはSSD上で整理されたデータをまとめて転送するだけであるから、きれいに整理した状態が保たれる。また、worldストレージで当初の想定ではうまくいかなかった部分をカバーしているため、かなりきれいに運用されている。

こうした事情もあってlocallocal.oldに分かれているわけだが、言い換えると非常に古いデータ(90年代のデータ)を含むlocal.old以下のデータはそのまま持ってこれるものでなければ触らない方針になっていた。 カメラ撮影のデータもその一部だ。

だが、先日から写真データの新しいアーカイブへの適合作業をやっていた流れで、動画も変換する方針となった。

圧縮効果

静止画(JPEG)の場合はだいたい40〜70%程度の圧縮が可能である。

一方、動画(H.264/H.265)の場合は20〜95%の圧縮が目安となる。

基本的にJPEGからAVIFへの変換は視覚的劣化はほとんどの場合ないと言っていい程度に収まり、処理もそこまで重くなく、良好な結果が得られる。 対して動画はソースにより圧縮可能な程度の違いも大きく、同じ設定だと劣化度合いも大きく異なる。

だが、これだけでは判断できない部分がある。 画像は割と短時間で変換できるのに対し、動画は途方もない時間を要する。 だが、画像は動画と比べるともとのサイズ自体小さく、圧縮による容量への貢献は小さい。 一方、動画はファイルサイズが大きいため、それほど大きく圧縮されなくても容量としてはかなりの違いが出てくる。

これをどのように判断するかは場合によるが、ゲームのプレイ動画をアーカイブする場合は確実に圧縮すべきだ。 どのようなゲームであるかによってパラメータを調整する必要はあるが、Radeon ReLiveで収録した動画は30000kb/sほどあるが、よほど派手なゲームでなければ6000kb/s程度はターゲットにでき、アドベンチャーゲームなら1500kb/sを余裕で下回る。 エフェクトな派手なゲームもそれはそれで15000kb/sくらいまで制限しても割と困らないため、著しい圧縮になる。

カメラで撮影した動画はシーンによって大きく異なってくるから、本当は個別に判断したい。 だが、私の経験的にはCRF35, 20000kb/sのConstrained QualityのVP9は割と汎用性のある圧縮であると考えている。 カメラ動画もだいたい30000kb/sくらいのソースが多く、30〜50%程度の圧縮が可能である。 ただし、この圧縮処理は重く、その割に効果が出ないこと、変換された結果が安定しないために確認が必要であることを考えると、ゲーム動画ほどやる価値があるものではない。

なお、ダウンロードした動画など、配信されている動画データを圧縮しようと考えるべきではない。 なぜならばそのようなデータは通常、配信される時点で圧縮されてエンコードされており、エンコードに必要なコストに対して十分な利益が得られない。

圧縮の価値

動画データの場合、例えば1TBの動画データが200GBとかになるわけで、アーカイブする時点で圧縮が不可欠であると考えられる。 これは音楽データをライブラリにするときにFLACにしたほうが良いというのと同じような話で、そもそも(アーカイブされるオリジナルデータとして)要求される品質の範囲でデータを小さくしないとアーカイブという行為自体が成り立たない。

だが、そこまで莫大なサイズにならないデータ、つまりそのままアーカイブすることが可能であるようなデータに手間をかけて圧縮する価値はあるのだろうか。

私の写真データのライブラリサイズはもともと350GBほどである。これが160GBほどになった、つまり半分以下になったわけだが、言い換えればこれによって空いたディスクスペースは190GBに過ぎない。 もちろん、190GBのストレージ容量が貴重だと考える人は少なくないだろうが、この程度のデータであれば処理に時間をかけずにアーカイブできるように大容量のディスクが用意されているわけで、このような容量の節約は必須ではない。

動画に関しても、私がカメラで撮影した動画の容量は2TBあたり。50%の圧縮率では1TBほどと、もちろん小さくはないが、労力の割には利益が小さい。 その程度の話であればディスクを買うほうが早いとも考えられるのだ。

だが、大きな違いになってくるのが、「データサイズが小さくなると取り回しがよくなる」ということだ。

例えば、災害に備えてバックアップのディスクを作るとして、写真というのはそれこそエッセンシャルなデータのひとつだろう。だが、写真や動画はかなり大きなデータサイズとなり、バックアップのディスクに容量を求める原因になる。 HDDにすると経年での故障が気になるし、3.5インチは重いのでできればSSDにバックアップしたいところだが、そうなると容量の問題がより強く出る。これはクラウドへのバックアップでも同じ話だ。

私は写真+動画だけで2TBを越えてしまい、バックアップ用ディスクが2TBなのである程度削る必要があった。 しかし今回の圧縮で、大幅にデータが増加したにも関わらず1TBを切るようになったので、他のデータも含められるようになった。これはかなり大きな成果だ。

写真などのデータは時と共に増加するため、たとえバックアップのディスクをより大きいものにできるとしても、圧縮すると扱いやすくなり、やる価値はある。

ファイルフォーマットが変わることによる副作用

JPEGと比べAVIFの取り回しが悪いのは間違いない。

リーガルな側面で見れば、JPEGはCLIの特許を侵害しているとされ、これを利用してForgent Networksが荒稼ぎしたという事件があった。 だが、この特許は既に失効している。 対してAV1はロイヤリティフリーのパテントライセンスを採用しており、基本的には不安はない(争いがないという意味ではない)。 この点からみれば「どっちもどっち」である。

だが、AVIFはWebPやJPEG XLと比べ対応するアプリは多いとはいえ、AVIFに対応した環境はかなり限られる。1 JPEGが再生できない環境はほとんどないから、明らかに制限が発生する。 また、AVIFのデコード速度はWebPと同等であるものの、JPEGは圧倒的に速く、大きな画像だとJPEGよりも表示するときにラグを感じる。

この問題について、私は2サイズの小さなサムネイルJPEG画像を生成することで解決している。 写真を1枚1枚確認するときは開くのが少し遅いことはあまり気にならない。問題になるのはブラウジングのときであり、この場合はどのみちオリジナルのJPEG画像でも重すぎるため、判別可能な範囲で軽くしたサムネイル画像を別途用意するのが効率的だ。

また、スマートフォンでAVIFの表示が難しいという問題もある。 ただこれも、スマートフォンに入れたり、クラウドフォルダに入れたりする場合はポータビリティが大事で、結局オリジナルがAVIFであれJPEGであれ、ある程度軽くしたものを収蔵すると考えられる。

もちろん、そのような手間を取らないユーザーが大多数だろうが、これは私の運用の話なので問題ない。 ImageMagickを使うだけだ。 これについては後述する。

一方、H.264/MP4もしくはH.265/MP4からVP9/WebMへの変換は良し悪し両面である。

ソフトウェアデコーディングという話で言えば、VP9はかなり重く、FHDでも結構厳しい。 だが、H.265でも4k映像はRyzen9 5950Xを用いても厳しいことが多いため、どのみちハードウェアアクセラレーションなしには考えられないとも言える。

そのハードウェアビデオアクセラレーションについては、H.264/H.265が圧倒的に恵まれており、VP9はそれなりに新しいハードウェアに限られる2。 私の手元のRX580もVP9支援が効かない。

だが、ハードウェア側で支援が効くとなると、VP9のほうが取り回しが良い。 というのも、まずMESAのデフォルトからH.264/H.265のハードウェアサポートが外されてしまったため、これらのビデオフォーマットの再生に対応しようとするとMESAを自力でビルドする必要があり、これが結構しんどい。 また、H.264/H.265よりもVP9のほうが(少なくともAMDでは)挙動も安定している。

これはNvidiaユーザーにはない感覚である。 Nvidiaユーザーの場合、Nouveauでは(プロプライエタリドライバーを借りずに)ハードウェアビデオアクセラレーションを有効にすることができず、NvidiaドライバーであればNVDECを使って再生するから全く気にならない。

つまり、望ましいフォーマットとしては次のような状況になる。

条件 H.264 H.265 VP9
最新PC/Windows
最新Intel/Linux
最新AMD/Linux
最新Nvidia/Linux
やや古いIntel/Linux
やや古いAMD/Linux
やや古いNvidia/Linux
古いPC
Web掲載
最新Android
古めAndroid
iPhone
  • 新しいAndroidでもSnapDragon 400シリーズはVP9デコーダを持っていない
  • iPhoneはA10(=iPhone 7)からHEVCとVP9のデコーダー両方載せたようなので、両者に差はない。それまではH.264だった

一番安全な(再生に確実性がある)フォーマットという意味ではH.264/MP4だが、その方針でH.264を採用すると圧縮に支障が出る。 だから「HEVCを使うくらいならVP9でいいだろう」と言えるのだけど、(RX580のように)中途半端に古い場合だけ困ってしまう。

だが、画質の面でH.265は圧縮によって文字が読めなくなったりブロックノイズが出たりといった「一律のパラメータで変換すると苦手とするソースですごく困ることになる」と考えると、機械的に圧縮するならVP9でアーカイブするのが正しくはある。 問題は再生環境が限られることだが、未来の自分に期待するしかないこともあるだろう……

スマートフォンへの写真の転送

これについては、次のようなスクリプトで解決している。

#!/bin/zsh
ORIGINAL_DIR="$1"
shift

if [[ -z $ORIGINAL_DIR ]]
then
  exit 3
fi


for i in */*
do
  if [[ ! -e ../Dest/${i:h} ]]
  then
    mkdir -v ../Dest/${i:h}
  fi
  
  convert $ORIGINAL_DIR/*/${${i:t}:r}.(avif|jpeg|jxl|png) ../Dest/${i:r}.jpeg
done

画像の確認はViewnior、もしくはPixを使う。 Viewniorは開いている画像からドラッグ・アンド・ドロップが可能だし、Pixはブラウザモードであれば選択しているファイルはドラッグ・アンド・ドロップできる。 このとき確認しコピーするのは基本的にはサムネイルファイルである。

そして、サムネイルファイルをコピーしたら、オリジナルファイルを探してJPEGに変換する。 オリジナルファイルを探す処理は、「写真ファイルは基本的にカメラの中での連番、もしくはタイムスタンプであるため、ファイル名の重複は原則としてない」という理屈に基づいており(実際は「絶対にない」とは言えないが、少なくとも私のライブラリではそうだった)、シンプルな処理となっている。 $ORIGINAL_DIRとは探索元となるAVIFのアルバムのディレクトリ($photo_dir/album/photo)だ。

スナップショット

今回データを圧縮してファイルサイズを小さくしたが、実はディスクの使用量は大幅に増えている。

なぜならば、私はBtrfsでスナップショットを取っているため、元の状態に戻すことができる、つまりソースファイルも依然としてデータとしては残っているのだ。

一見すると、スレーブ側はスナップショットを更新したあと、古いスナップショットを消せばオリジナルデータの所在が消えるため、容量が空きそうに思える。 しかし実際は、スナップショットを削除してもディスク容量は空かないようだ。

違いが出るケースとして、スレーブ側にBtrfsを再構築して最新スナップショットだけを転送した場合は古いデータを含めないため、容量は小さくなるだろう。 つまり、この処理は現在に対して容量の利益はなく、将来再構成する際の利益になる。