Linux上で特定フォーマットの音声や動画が再生できない時の対処法


## 概要

Firefox や Totem 等、GStreamer[^1] を利用して再生を行うアプリケーションの処方箋です。

これらはLinux界の慣習に沿って README やソースを読んで行けば判明する事なのですが、
音声(動画)再生はプログラマ以外にも需要のあるジャンル[^2]だと思いますので、私が以前に
それらを行って問題を解消した経験を踏まえて手順をまとめてみます。

通常は適切に不足ライブラリを埋めるとかOSのバージョンを上げるとかすれば解決する事が
多いですが、特殊なインストールや様々なバリエーションを持つLinuxでは、原因の調査方法を
知っておく事は悪い事ではないと思います。

## 調査の進め方と解決例

音声(動画)が再生出来ないだけでは情報が足りないのでその詳細を追います。
まず再生出来るフォーマットと再生出来ないフォーマットのログを比較します。
これには gst-launch gst-discover gst-inspect というツール群[^1]を活用します
(Ubuntu なら gstreamerX.XX[^3]-tools パッケージ内)。

例えば ogg は再生出来るけれど mp3 が再生出来ない[^4]という状況の場合は、以下を実行します。

````
$ gst-launch-X.XX filesrc location=～.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! alsasink
$ gst-launch-X.XX filesrc location=～.mp3 ! id3demux ! mpegaudioparse ! audioconvert ! audioresample ! alsasink
 (新しめの Linux の場合)
$ gst-launch-X.XX filesrc location=～.mp3 ! id3demux ! mpegaudioparse ! mpg123audiodec ! alsasink
````

次に以下を実行します。

````
$ GST_DEBUG=typefind:9,decodebin2:9 gst-discoverer-X.XX ～.ogg |& sed 's/32;43m/33m/g' | sed 's/32;41m/31m/g'
$ GST_DEBUG=typefind:9,decodebin2:9 gst-discoverer-X.XX ～.mp3 |& sed 's/32;43m/33m/g' | sed 's/32;41m/31m/g'
 (新しめの Linux の場合)
$ GST_DEBUG=typefind:9,decodebin:9 gst-typefind-X.XX ～.ogg |& sed 's/32;43m/33m/g' | sed 's/32;41m/31m/g'
$ GST_DEBUG=typefind:9,decodebin:9 gst-typefind-X.XX ～.mp3 |& sed 's/32;43m/33m/g' | sed 's/32;41m/31m/g'
````
※ 使用しているターミナルによっては最後２つの sed フィルタは不要かもしれません

これで怪しい箇所が見えてきます。以前私が遭遇したこの問題では以下のようになっていました。

````
DEBUG     decodebin2 gstdecodebin2.c:XXXX:analyze_new_pad:<decodebin21> Pad mpegaudioparse0:src caps:audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], mpegaudioversion=(int)[ 1, 3 ], rate=(int)[ 8000, 48000 ], channels=(int)[ 1, 2 ], parsed=(boolean)true
DEBUG     decodebin2 gstdecodebin2.c:XXXX:gst_decode_pad_new:<decodebin21> making new decodepad
LOG       decodebin2 gstdecodebin2.c:XXXX:are_final_caps:<decodebin21> Checking with caps audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], mpegaudioversion=(int)[ 1, 3 ], rate=(int)[ 8000, 48000 ], channels=(int)[ 1, 2 ], parsed=(boolean)true
LOG       decodebin2 gstdecodebin2.c:XXXX:are_final_caps:<decodebin21> Caps are not final caps
DEBUG     decodebin2 gstdecodebin2.c:XXXX:analyze_new_pad:<mpegaudioparse0:src> pad has non-fixed caps delay autoplugging
````

正常な方のログと比較すると、最後の行は本来なら以下のようになっているべきです。

````
LOG       decodebin2 gstdecodebin2.c:XXXX:analyze_new_pad:<decodebin21> Pad is final. autoplug-continue:1
````

そして gst-inspect の出番です。

````
$ gst-inspect-X.XX vorbisdec
...
SINK Capabilities: audio/x-vorbis   SRC Capabilities: audio/x-raw-float
...
$ gst-inspect-X.XX mpegaudioparse
...
SINK Capabilities: audio/mpeg   SRC Capabilities: audio/mpeg
...
$ gst-inspect-X.XX mad
...
No such element or plugin 'mad'
...
````

これら各プラグインは /usr/lib/i386-linux-gnu/gstreamer-X.XX/ (32bit Linux の場合)
配下に libgstXXX.so というELFファイルとしてインストールされているはずです。
これを確認すると、libgstmad.so は正しく存在しているにも関わらず、それが GStreamer
から見えていない現象が発生している事がわかりました。
ここで GStreamer のソースを tools/gst-inspect.c から順に追うと、最終的に
~/.gstreamer-X.XX/registry.i386.bin が壊れているらしい事が判明します。

解決方法も同時に判明します。

````
$ GST_PLUGIN_PATH=/usr/lib/gstreamer-0.10:/usr/lib/i386-linux-gnu/gstreamer-0.10 gst-inspect-X.XX mad
または
$ gst-inspect-X.XX --gst-plugin-path=/usr/lib/gstreamer-0.10:/usr/lib/i386-linux-gnu/gstreamer-0.10 mad
````

GStreamer は regstry.i386.bin の情報を元にパイプラインを組み立てるのですが、regstry.i386.bin の
更新タイミングは限られていて、インストール手順の乱れ等何らかの理由でプラグインがいったん
BLACKLIST カテゴリに入ってしまうと、それが正しいプラグインであっても明示的に regstry.i386.bin の
更新を要求するまで使用不能となってしまうという現象のようでした。
上記を実行すると registry.i386.bin が正しく更新され、正常な再生が行われるようになります。

対象音声(動画)が埋め込み Web コンテンツ等で取得が面倒な場合は、
フォーマットだけを調べて同じフォーマットのファイルを準備するのがよいと思います。
例えば Youtube 動画が再生されず、Youtube 上のチェックで H.264 が怪しいと判明したので
あれば mp4/H.264 や flv/H.264 ファイルを準備し、totem 等のプレイヤーで再生出来ない事を
確認してから前述の手順を実行するといった具合です。


[^1]: Linux 上の音声(動画)再生には幾つかの手法がありますが、多くの場合は最終的に <a href="https://gstreamer.freedesktop.org/">GStreamer</a> というライブラリ上から音声(動画)を再生しています(Firefox や Totem 等)。これは Windows で言う所の <a href="https://docs.microsoft.com/en-us/windows/win32/directshow/directshow">DirectShow</a> に相当する仕組みで、<a href="https://gstreamer.freedesktop.org/">GStreamer</a> のパイプラインは <a href="https://docs.microsoft.com/en-us/windows/win32/directshow/directshow">DirectShow</a> のフィルタグラフに当たり、<a href="https://ffmpeg.org/">ffmpeg</a> 等の各種デコーダ、<a href="http://www.alsa-project.org/">ALSA</a>(ほぼ<a href="http://www.pulseaudio.org/">pulseaudio</a>) 等を統合してストリーミング再生全体を実現しています。これらについては他に参考となる記事が多く書かれていますので、説明は割愛します。

[^2]: プログラマ以外が果たしてクライアントOSとして私用でLinuxを常用するのだろうか？という根本的な疑問は残っていますので (´・ω・`)、もしこの記事が役に立ったという方がおられましたら一言コメント頂ければ幸いです。

[^3]: インストールされている GStreamer のバージョンが入ります。例えば Ubuntu 20.04 18.04 16.04 なら 1.0、14.04 12.04 なら 0.10 といった具合です('21/8/15時点)。

[^4]: さすがに今時の Linux ではあり得ない・・・とも言い切れないでしょうか。この問題は古い Ubuntu で遭遇したのですが、結局の所 mp3 プラグインのライセンス周りの特殊性が遠因で発生したと記憶しています。他にも同様の事情で main や universe に 入れられないプラグイン等もあったような。