mpeg2tsファイルがAndroidTV/GoogleTV(ExoPlayer)で再生できないことの解消法

MPEG-2 TSのCA descriptorを無効化するパイプフィルター

はじめに

スクランブルされていないにもかかわらず、CA Descriptorが設定されているmpeg2tsファイルを、AndroidTV(GoogleTV)上のアプリで再生しようとしたら、なぜか再生できない。

VLCやMPCでは問題なく再生できるのに、AndroidTV(GoogleTV)アプリだけ再生できない。エラーも出ないか、出てもよくわからないメッセージが表示されるだけ。

NOTE

この問題はExoPlayerを内部的に使っているAndroidTV(GoogleTV)アプリ全般で発生しうる。ネット上にほぼ情報がなく、同じ問題で悩んでいる人は多いのではないかと思われる。

この記事では、その原因と解消法を解説する。

原因:CA descriptorの存在

PSI(Program Specific Information)セクション、具体的には CAT(Conditional Access Table)PMT(Program Map Table) の中に CA descriptor(Conditional Access descriptor) が残ったままになっている。

CA descriptorは、「このストリームはスクランブルされており、CAS(Conditional Access System)による解除が必要」であることを示すメタデータであり、ペイロードのデータだけをスクランブル解除処理されたmpeg2tsファイルに設定されていると正しくないmpeg2tsのデータとなる。

ExoPlayerの誤判断

ExoPlayer(Jetpack Media3)のTsExtractorは、PMTやCATにCA descriptorが存在すると、ペイロードのスクランブル状態(transport_scrambling_controlフィールド)に関わらず、そのストリームをスクランブル済みと判断し、MediaCasによる解除処理を試みる。

しかしMediaCasはB-CASに対応していないため、解除に失敗して再生できなくなる。

NOTE:

VLCやMPCはCA descriptorの有無に関係なく、実際のペイロードのスクランブル状態を見て再生を試みるため、問題なく再生できる。ExoPlayerだけが厳格にCA descriptorを見ている。

解消法:パイプフィルタープログラム

根本的な解決策は、CA descriptorを無効化したうえで、TSパケットヘッダのtransport_scrambling_controlビットをクリアすること。

これをリアルタイムに行うCのパイプフィルターの検証用プログラムを作成した。188バイトのTSパケットを標準入力から受け取り、加工して標準出力に流す。

対処内容

  • 全パケットのTSヘッダ(packet[3])の上位2ビットをクリア
    transport_scrambling_controlフィールド(2ビット)を00(クリア)に強制する。
  • CAT(table_id=0x01)およびPMT(table_id=0x02)のCA descriptor(tag=0x09)を無効化
    CA descriptorのtagを0xFFに書き換え、ペイロードを0xFFで埋める。descriptor loopの構造は維持する。
  • 変更後にCRC32を再計算
    PSIセクションのCRCを正しい値に更新する。

ソースコード

matching/ts_ca_strip: mpeg2tsからCA Descriptorを無効化するパイプ

実装上のポイント

CA descriptorのtagは0xFFに書き換える

CA descriptorを無効化する際、tagを0x00に書き換えると、パーサーによっては別のdescriptorとして誤認識されることがある。0xFFは無効値として定義されているようであり、0xFFに書き換えている。

lengthフィールドは変えない

descriptor loopのパースはlengthフィールドを使って次のdescriptorの位置を計算する。tagを書き換えてもlengthを維持することでループ構造が壊れず、後続のdescriptorのパースに影響しない。

TIP

パケット分割されたPSIセクション(複数のTSパケットにまたがるケース)は対象外でそのままスルーするため問題が出る可能性がある。(あくまで検証用プログラムであり、これで変換したものを最終的に残すことは推奨しない)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です