Chienomi

libfdk_aacをもっと常用したい

Live With Linux::tips

本記事はタイトルに情報を含めるのがかなり難しかったので、まず前提を説明する。

音楽ファイル(PCMデータ、あるいはFLAC)をlossyなフォーマットに変換するとき、できる限り高音質に保ちたいと考えたとする。 ここで最も良い方法は、Opusを使うことである。Opusは優れた音声データフォーマットであり、リファレンス実装のlibopusを用いて非常に高音質なファイルを生成することができる。

PC、またはAndroidスマートフォンで再生するのであれば、これは許容できる選択である。 Androidスマートフォンでは.opus拡張子が認識されないため、.oggまたは.oga拡張子にする必要がある。 .opusファイルはOgg Opusであるため、これは単純に拡張子の問題だ。 Mac、及びiOSの付属ソフトウェアではOpusオーディオを現状まだ再生できないため、これらの環境では少し考えるべきである。

Opusが先進的すぎるのであれば、次の候補はVorbis、あるいはAACである。 高ビットレートにおける音声品質はどちらも遜色なく高いが、VorbisがOpus同様に考慮すべき点がなく高音質が実現できるのに対し、AACは権利上の問題があるだけでなく、(MP3同様に)エンコーダーによる音質の差という問題が存在する。

多くのオーディオプレイヤーはOgg Vorbisを再生できるだろうから、ほとんどの場合Vorbisは汎用的な解決策になる。 しかし、AppleはOpus同様、Vorbisのことが嫌いだ。そもそもAppleはMPEG側についている関係上、VorbisやOpusは音声面でのライバルフォーマットということになり、どうしても採用したくないのだろう。 そして、SonyのWalkmanもまた、頑なにVorbisをサポートしない。

このような場合に選択肢として挙がるのがAACである。 AACとVorbisのどちらが汎用性が高いかというのは難しい話だ。政治的(権利的)な理由でAACを採用しVorbisを採用しないケースもあるし、オープンで実装を使いやすいVorbisをサポートして難しい事情を抱えたAACをサポートしないことも考えられる。 結局、これに関してはどっちもどっち、と言える。

状況としてはAACやVorbisよりもOpusが用いられるようになりつつある(iOSですら通話にAAC-HEでなくOpusを使うようになった)が、単独の音声データファイルとしてOpusを扱うことはほとんどない。

さて、こうした事情によって、具体的には私がWALKMANを使っているという事情によって、AACを使用することを決めたとする。 もちろん、そのようなケースにおいてより汎用性の高いMP3を使うという手もあるが、機能的にも音質的にも納得ができないとしよう。MP3にしたところでAACに対して事情が緩和されるわけではないのでMP3の話はしない。

では大量のオーディオライブラリを一括でAACに変換しようと考えると、やはりそこはシェルスクリプトという話になると思うのだが、AACだとどうやって変換するかの問題がある。 もちろん、一番簡単なのはソースデータを気にしなくて良いffmpegを用いることだ。

ffmpegにはlibavcodecのaacエンコーダが搭載されている。 だがこのエンコーダ、かなり品質が低い。ffmpegとしても、高品位なコーデックが欲しい場合、libfdk_aacを用いるように推奨している。 libfdk_aacはノンフリーなものであるため、これを含むffmpegは自力ビルドが必要だ。

Arch Linux (incl. Manjaro Linux)の場合、ffmpeg-libfdk_aacというAURパッケージがあり、これによりlibfdk_aacサポートを含むffmpegをビルドすることができる。それを用いて

ffmpeg -i 01-foosong.wav -c:a libfdk_aac -b:a 320k 01-foosong.m4a

とでもすれば良いわけだ。 めでたしめでたし。

そう、私もそのようにしていた。だが、これには問題がある。

その問題は、システムとしてffmpegは深い依存を持ったパッケージであり、システムアップグレード時には必ずffmpegの依存関係の破壊が起きる、ということだ。大抵はアップデートできないが、動かなくなることもある。

そのため、通常

# pacman -S ffmpeg
# pacman -Syu

という流れになるが、依存が深いためにffmpegを入れ直すこともできないことがある。 アーカイブパッケージがあればそれで再インストールすれば良いが、ないと結構厄介だ。

そして、アップグレードのたびにffmpeg-libfdk_aacを作り直すのだが、そもそもかなり重いビルドになる。

結論、めんどくさい。

fdkaac単独利用

しかし動画を作ろうというのであれば、サポートされていないコーデックを使うというのは相当面倒な話になる。 動画を出力して、音声を出力して、それを合成する、という手間がかかるからだ。

だが、音声ファイルだけの話であればそう面倒でもない。 なんといっても、Arch Linuxはlibfdk-aacパッケージとfdkaacパッケージ(libfdk-aacのフロントエンドとなるfdkaacコマンド)はCommunityパッケージとして存在するのだから。

fdkaacは入力ファイルとしてWAV/PCMファイルのみをサポートする。が、実際PCMデータをパイプで流しても受け取らないので、WAVのみだと思ったほうが良さそうだ。

ffmpeg-libfdk_aacを使う場合

ffmpeg -i 01-foosong.wav -c:a libfdk_aac -b:a 320k 01-foosong.m4a

としていたわけだが、fdkaacを使う場合は

ffmpeg -i 01-foosong.wav -vn -f wav -c:a pcm_s16le - | fdkaac -b 320 -o 01-foosong.m4a -

となる。

案外簡単だ。fdkaacは色々パラメータがあって面倒に感じるが、オーディオデータに関してはほぼデフォルトで最適になっている。

考えられるのは-bまたは-mパラメータである。

-mはVBRを使うための設定で、5が最大品質。 一方、-bはCBRを使う場合における全体のビットレート指定で、単位はkb/s。 全体の、というのは、何チャンネルあろうと合計で、ということである。(opusencはチャンネルあたりのビットレート指定になっている)

fdkaacのビットレート

fdkaac -m5 source.wav dest.m4aとした場合、ソースが2ch, 16bit, 44100kHzオーディオだとすると200kb/sを越える程度になる。

結構低い、と感じたのだが、-m5で聴覚上、違いを感じ取るのが困難なのは事実だ。 私は音声上の劣化を確認したので引き続きCBRの-b 320(ビットレート320kb/s)を使っているが、聴覚上識別可能かというと、難しいという答えになると思う。だが、ごく一部分だけをフォーカスすれば、-m5に対して感じ取ることは可能だった。 (優劣を感じるのではなく、差異がどのようにあるのかわかっている状態でその箇所をクローズアップすることで、発音に差異があることを聴覚的に発見可能であるという意味である。)

-b 256でもかなり余裕があるはずなので、おそらく十分な(というより過剰な)値なのだろう。 しかし、私もそうだけれど、音に対して非常に神経質な(敏感な)人もいるので、その「十分」はどのような人にとっても絶対に意味をなさないとは言えないように思われる。

心理的安心を含めるなら-b 256は十分現実的な選択肢だと思うし、もっとFLACに近い、損失を感じない音声を求めるなら-b 320もアリではあると思う。 というより、-b 320はアーカイブ用途を除く、FLACに近い目的の値だと言って良い。 (ハイレゾの要素を考えないのなら)ASMRのような音質を追求したいケースにおいても使えるくらいの品質になる。

なお、こうした高ビットレートにおいてもMP3はやや微妙である。 やはり基本的には「Vorbis or AAC」を前提において良いだろう。

AACって実際どうなのか

品質面では良い、という主張なのだけど、実際にAACが使われている状況はlibav-aacであることが多いため、現実のAAC音声はあんまりよくない。libmp3lameのMP3音声よりは、いくらかマシである「かもしれない」くらいだろうか。

少し視点を変えて、特別な高音質を謳うことが多いASMR作品において、AACデータフォーマットによる配布を行っているものがどのようなエンコーダーを使っているか調べてみた。

結果、判別できるものについてはすべてiTunesのライブラリを用いていた。 (メタデータをストリップしてあるため、わからないものもあった)

おそらくAppleのAACコーデックが現状最も高品位であり、iTunesがそれを使う。 QAACはiTunesのライブラリをコマンドラインで叩くものであるため、dBpowerampを使っている場合も同じ結果になる。

しかし、私としてはこの前提は難しい。そもそもffmpegで扱うことができないし、あまりにも条件が限定されすぎており、「AACの特徴」とは言い難い。

なにより、ここで言っているように、すごくめんどくさい。 MP3もそうだったけれど、権利関係が絡むため面倒である上に、 とにかくコーデック品質に音質や特性が左右されるのは、一度エンコードした内容を「やっぱりもう一度アレでエンコードしたほうがいいかな」みたいなことを考える理由にもなるので、煩わしさ満点である。

最も、単にフリーなコーデックであればそのようなことに煩わされることはない、というわけでもない。 Vorbisのリファレンス実装は、初期にかなり品質の変化があった。だから私自身、iFP830というプレイヤーのために何度かOgg Vorbisファイルを作り直した。

だが、様々な問題に煩わされる度合いを考えると、AACよりVorbisのほうがずっと扱いやすく、Opusはさらに優れている。 アプリケーション側の適応という問題は常にあるものであり、それを考えなければならいな場合とはだいたいメディアプレイヤーハードウェアを購入するときだから、最初からOpusに対応しているものを買うか、Vorbisに対応するものを買うか、もしくはAACにしか対応しないのであれば今回のようにAACでファイルを作り直す、という前提のもとに取り扱うためあまり問題ではない。

だが、その結果AACで取り扱うものとすると別の煩わしさに悩まされることになるため、やはりAACは好きになれないというのが正直なところ。AACと一口にいっても互換性問題が発生しやすいのも嫌いだ。 (例えば、WALKMANはハイレゾAACは扱えない)

動画におけるAAC

ffmpegを用いてビデオを変換する場合、おおまかに次の選択肢がある。

  • 映像にVP9、音声にOpusを選びWebMにする
  • 映像にHEVC、音声にOpusを選びMatroska(MKV)にする
  • 映像にHEVC、音声にAACを選びMP4にする

WebMはMKVの一種であるから、そもそもMP4とMKVどちらを好むか、という問題にも左右される。 基本的にMKVのほうが柔軟性が高いが、プレイヤーとしてはスキップやジャンプにおいてMP4のほうが高精度に処理しやすいようだ。フィルタ処理なども含めた「再生安定性」という意味では、MP4のほうがメリットを感じることもある。 MP4の最大の欠点は、部分的なデータ損失によってビデオ全体が扱えなくなってしまうことだろう。

また、プレイヤーソフトウェア(ハードウェアのメディアプレイヤーを含む)がそもそもMKVをうまく扱えない、というケースも散見される。他にも、メッセンジャーソフトウェアでのビデオ送信が、MKVだとファイル送信になってしまったりすることもあるし、SNSだとMKVはアップロードできなかったりもする。

だが、このビデオ変換において、音声がコピー処理になる場合を除き(つまり、ffmpegで-c:a copyするようなケースを除いて)、音声がAACであるべき、と考えられるケースはないように思う。 MP4がOpusを受け入れないという事情があり、MPEG側としてはあくまでAACを推すつもりなのだが、音声技術としてはOpusが現状最高の選択肢となっているのは事実で、ビデオ配信(テレビ配信を含む)であれ、通話であれ、迷わずOpusが選択される状況である。

まして、エンコーダーの問題があるために、AACにした場合は音質の劣化という問題が避けられない。 ビットレートによってアルゴリズムをシームレスに切り替えられるというのはOpusの大きな強みだ。

だが、そこらへんは理屈の上での話であり、ほとんどの動画(ライブの動画やPV、MMDなど音楽がコンテンツとして含まれる動画以外)においては別にAACでも対して気にならないし、というよりもlibav-aacでも構わないし、AAC-HEにすべきところでAAC-LCが使われて至って気にしない。

動画変換を行う場合、よほどシビアな話であればOpusで-application voipとかしてビットレートを詰めることになるのだけど、それよりは画質面でうまく妥協点を見出すほうが効果はずっと大きいため、サイズ割合の問題を含めてそのようなことを気にすることは稀である、と言えそうだ。

私自身としては、HEVC+OpusのMKVという構成は私はほぼ使わない。 スクリーンキャプチャでも、AVC+FLACのMKVで撮って、後にVP9+Opusに変換していることがほとんど。

RipCD Evoの改良

freedb.orgを使わないようにしたというのが最近の大きな変更だったRipCD Evoだが、今回この記事に至る流れに伴って、ffmpeg-libfdk_aacを要求しないように変更した。

ripitによってリッピングし、cdrdaoによってバックアップするという二段構えのripcdに、WALKMAN向けのスクリプトを追加したのがEvoだが、Evoになった時点で結構改良してあって、今回もついでなのでちょっといじった。

これに伴い、Rubyを使わないようになった。 (なんでRubyを使っていたのだろう? 思い出せない)