· 6分で読了

日本のテレビ字幕を解析する旅

この記事は中国語から自動翻訳されたものです。翻訳によりニュアンスが失われている場合があります。

はじめに

みんなは日本でテレビを見たことがあるだろうか?日本では、放送信号の中に番組表やテレビ映像(解像度の切り替えも可能)、字幕など、多くの情報が含まれている。そのため、テレビ上で字幕のオン・オフを切り替えることができる。

では、実際にはどのように動いているのだろうか?今回は、日本のテレビ放送における字幕解析について話してみようと思う。

この技術を研究し始めたきっかけは、謙謙の以前のツイートに加え、以前からチューナーをPCに繋いでテレビを見られないか試してみたいと思っていたからだ。実際に調べてみると、多くの興味深い技術的詳細があることに気づいた。

日本のテレビ放送

日本のテレビ放送は、日本独自に策定された ISDB(Integrated Services Digital Broadcasting)という規格に基づいている。無線基地局から信号を送信し、各家庭でテレビ信号を受信した後、復号して元のデータに復元する仕組みだ。

B-CAS

日本のテレビ信号は、無限の複製防止や著作権保護のため、実は暗号化されてから送信されている。この仕様は ARIB(STD-B25)で標準化されている。そして B-CAS はまさに鍵のようなもので、このカードがなければテレビを見ることができない。日本でテレビを買ったことがある人なら分かると思うが、テレビを購入すると通常はこの B-CAS カードが同梱されており、それがないと映像を見ることができない。

放送局は複製規約の遵守に同意したメーカーと契約を結び、それらのメーカーに暗号鍵の情報を直接提供する。メーカーはその鍵を組み込んだハードウェアを製造する。例えば、現在よくあるUSBタイプのチューナーは、PCに挿すだけで信号を受信してテレビを見ることができる。しかし、この手のチューナーは勝手な複製を防ぐため、通常は専用の再生ソフトをダウンロードしなければ正常に視聴できないようになっている。

MPEG2-TS

MPEG2-TS は動画のコンテナフォーマットの一種で、日本の放送伝送には通常 MPEG2-TS が使われている。ここでの TS は Transport Stream の略だ。映像は通常 h.262(MPEG-2 Video)でエンコードされ、音声は AAC でエンコードされている。h.262 は比較的古いため、同じ動画でもファイルサイズが大きくなる。普段僕たちがPCで視聴する .mp4 動画は、通常 h.264 でエンコードされている。

パケット伝送において、各 TS パケットの最大サイズは 188 バイトだ。無線伝送時にはノイズやエラーが発生する可能性があるが、188 バイトという小ささなら遅延を抑えられ、エラー復元も比較的容易になる。

TS パケットの構造については、以下の図を参考にしてほしい。

詳細な構造の参考資料:https://www.researchgate.net/figure/Detailed-structure-of-the-MPEG-2-transport-stream-TS_fig16_41949828

MPEG-TS パケットの概念図:4バイトのヘッダーと184バイトのデータ領域。縮尺は実際とは異なる

重要なフィールドは以下の通りだ:

  • sync_byte:常に 0x47
  • PID:パケット識別子。通常、このパケットの内容が何であるかを判断するために使用される
  • PAT:PID マッピングテーブル
  • PES:字幕、音声、映像はすべて PES の中にカプセル化される

字幕を解析する

放送技術の詳細には研究すべき点が数多くあるが、紙幅の都合上、ここでは字幕の解析に絞って解説する。字幕の解析と伝送は ARIB STD-B24 で規定されている。

大まかな手順は以下の通りだ:

  • パケットを読み進め、0x47 を探す
  • 解析しやすくするため、データを 188 バイトごとに分割する
  • PAT から PID のマッピングを探す(PAT の PID は 0)
  • 字幕(caption)の PID を見つけたら、データの解析を開始する

data unit

1つの caption data には、「テキスト情報」以外にも色、形状、字幕の表示位置など、多くの情報が含まれている。これらのデータは data unit によって区別される。そしてテキスト情報の data unit は 0x20 となる。

function parseText(data, length) {
  const str = data.slice(0, length + 1);
  let result = "";
  let i = 0;

  while (i < length) {
    if (str[i] === 0x20) {
      result += " ";
      i += 1;
    }

    // // JIS X 0208 (lead bytes)
    if (str[i] > 0xa0 && str[i] < 0xff) {
      const char = str.slice(i, i + 2);
      if (str[i] >= 0xfa) {
        result += parseGaiji(char);
        i += 2;
      } else {
        const decoded = new TextDecoder("EUC-JP").decode(char);
        result += decoded;
        i += 2;
      }
    } else if (Object.values(JIS_CONTROL_FUNCTION_TABLE).includes(str[i])) {
      console.log("JIS_CONTROL_TABLE!");
      i += 1;
    } else if (str[i] >= 0x80 && str[i] <= 0x87) {
      console.log("color map");
      i += 1;
    } else {
      i += 1;
    }
  }

  console.log(result);
  document.querySelector("#result").innerHTML += result + "<br/>";
}

ここでのテキストは JIS X 0208 の文字コードセットを使用しているため、別途デコードする必要がある。幸い JavaScript の TextDecoder は EUC-JP にも対応しているため、new TextDecoder('EUC-JP').decode をそのまま使用すれば問題ない。

また、日本の放送表示にはいわゆる「外字」と呼ばれるものがある。これは ARIB で独自に定義されたもので、JIS X 0208 には存在しない文字だ。主に情報の表示やテロップなどで使用される。https://ja.wikipedia.org/wiki/ARIB%E5%A4%96%E5%AD%97

日本の放送記号と字形への対応付けを示す概念図

このような文字は別途解析処理を行う必要がある。字幕のデコードに成功した後に最も重要なのは、正しいタイミングで画面に表示することだ。信号の伝送時には、同期を取るためのタイムテーブルも一緒に送信されている。

デモ

動画データを直接アップロードできないため、コードと字幕処理の概念図を掲載する。図は実際のデモ画面ではない。興味があれば自分で実装してみてほしい。

字幕のデコードと表示タイミングの概念図。実際のデモ画面ではない

https://github.com/kjj6198/ts-arib-parse/tree/master

その他の技術的詳細

映像が h.262 でエンコードされているため、大半のブラウザはネイティブ対応していない。Web ページ上で再生したい場合、WebAssembly を使って h.262 をソフトウェアデコードする方法があるが、これは CPU への負荷が非常に高く、動画を見る前に巨大な WASM ファイルをダウンロードしなければならない。お遊び程度なら良いが、実際のユーザー体験はかなり劣悪だ。そのため多くの場合、ffmpeg などのツールを使って h.262 を h.264 に変換した上で Web ページに配信・再生する必要がある。

現在比較的有名なオープンソースソリューションとしては Mirakurun がある。これはサーバーを立ち上げて放送信号を常に h.264 に変換して配信する仕組みで、これによりブラウザからでも直接視聴できるようになる。

このほかにも、参考になるオープンソースプロジェクトがいくつかある:

おわりに

単に字幕を表示するだけでも、その背後には学ぶ価値のある技術的詳細が数多く存在している。今回の実装プロセスを通じても、多くのことを学ぶことができた。例えば、以前の僕は MPEG-TS のフォーマットを知らなかったし、ARIB や ISDB-T の存在すら全く知らなかった。しかし、これらのプロトコルは日本の放送を長年にわたって支え続けているのだ。

実際に手を動かしてみると、思っていたほど難しくないことにも気づいた(字幕の解析に限った話であり、元の信号の復元処理などは僕も全く分からないが)。仕様書をじっくり読み進めさえすれば、自分でも実装することができる。

関連記事

他のトピックを探索