日本のテレビ字幕解析の旅

作成者:カランカラン
💡

質問やフィードバックがありましたら、フォームからお願いします

本文は台湾華語で、ChatGPT で翻訳している記事なので、不確かな部分や間違いがあるかもしれません。ご了承ください

前書き

皆さんは日本でテレビを見たことがありますか?日本では、放送される信号の中に多くの情報が含まれており、番組のスケジュール、テレビ映像(解像度の切り替えも可能)、字幕などがあります。そのため、テレビでは字幕をオンまたはオフにすることができます。

では、実際にはどのように機能しているのでしょうか?今日は日本のテレビ放送における字幕解析についてお話しします。

この技術について研究を始めたのは、以前の謙謙のツイートがきっかけで、さらにコンピュータにチューナーを接続してテレビを見ることができるか試してみたところ、思わぬ技術的な詳細が学べることに気づいたからです。

日本のテレビ放送

日本のテレビ放送は、ISDB(Integrated Services Digital Broadcasting)という日本独自の規格に基づいています。無線基地局を介して信号を送信し、各家庭ではテレビ信号を受信後、復号化して元のデータに戻します。

B-CAS

日本のテレビ信号は無限にコピーされるのを防ぎ、著作権を保護するために、まず暗号化されてから送信されます。この部分はARIB(STD-B25)で規定されています。そして、B-CASは鍵の役割を果たし、このカードがなければテレビを見ることができません。日本でテレビを購入したことがある方は、購入時にB-CASカードが付属していることが一般的で、これがないと映像を見ることができません。

放送局は、コピー規制を遵守することを約束したメーカーと契約し、直接これらのメーカーに鍵の情報を提供します。メーカーは、その鍵を含むハードウェアを製造します。たとえば、現在多くのUSB型チューナーは、コンピュータに接続するだけで信号を受信しテレビを見ることができます。しかし、この種のチューナーは通常、彼らの専用プレーヤーをダウンロードする必要があります。これは無断コピーを防ぐためです。

MPEG2-TS

MPEG2-TSは映像のパッケージフォーマットで、日本の放送伝送では通常MPEG2-TSが使用されます。ここでのTSはTransport Streamの略です。映像は通常h.262でエンコードされ、音声はAACでエンコードされます。h.262は古い形式のため、同じ映像をエンコードするとサイズが大きくなります。一般的に私たちがコンピュータで見る動画の.mp4は通常h.264でエンコードされています。

パケット送信において、各TSパケットの最大サイズは188bytesです。無線伝送中にノイズやエラーが発生する可能性があるため、188bytesというサイズは小さく、遅延を減らし、エラー復元が容易です。

TSパケットのさまざまな説明は、こちらの図を参照してください。

引用元: https://www.researchgate.net/figure/Detailed-structure-of-the-MPEG-2-transport-stream-TS_fig16_41949828

Detailed-structure-of-the-MPEG-2-transport-stream-TS

主なフィールドには以下のようなものがあります:

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

字幕の解析

放送の技術的詳細には多くの研究すべき点がありますが、今回は字幕解析に焦点を当てます。字幕の解析と送信は、ARIB-B24によって規定されています。

大まかな流れは以下の通りです:

  • パケットを読み取り、0x47を見つけるまで続けます
  • データを188bytesに分割し、解析しやすくします
  • PATからpidのマッピングを探します(PATのpidは0です)
  • キャプションのpidを見つけたら、データの解析を開始します

data unit

一つのキャプションデータは「文字メッセージ」だけでなく、色、形、字幕の表示位置など多くの情報を含んでいます。これらのデータは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 (リードバイト)
    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-0208の文字セットを使用しているため、別途デコードが必要です。しかし、JavaScriptではTextDecoderを使用でき、EUC-JPもサポートされているため、new TextDecoder('EUC-JP').decodeを直接使用できます。

また、日本語の表示の中には「外字」と呼ばれるものがあり、これはARIBによって定義され、JIS-0208には存在しない文字です。主に情報を表示したり、テロップを表示したりするために使用されます。https://zh.wikipedia.org/wiki/ARIB%E5%A4%96%E5%AD%97

![キャプチャ 2023-09-30 23.17.08](/Users/chenkaiyi/Desktop/截圖 2023-09-30 23.17.08.png)

このような文字は別途解析する必要があります。字幕の解析が成功したら、最も重要なのは、正しいタイミングで画面に表示する方法です。信号伝送中には、タイムテーブルが送信され、同期を取ります。

デモ

動画データを直接アップロードできないため、ここではコードとキャプチャ画像のみの紹介となります。興味がある方は自分で実装してみてください。

![キャプチャ 2023-09-30 23.26.40](/Users/chenkaiyi/Desktop/截圖 2023-09-30 23.26.40.png)

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

その他の技術的詳細

h.262を使用しているため、ほとんどのブラウザではサポートされておらず、ウェブ上で表示するには、WebAssemblyを使用してh.262をソフトウェアでデコードする方法がありますが、これは非常にCPU性能を消費します。動画を見る前に大きなWASMをダウンロードしなければならず、遊び程度であれば良いですが、実際のユーザー体験は非常に悪くなります。そのため、ほとんどの場合、ffmpegなどのツールを使ってh.262をh.264に変換する必要があります。

現在、比較的有名なオープンソースのソリューションはmirakurunです。この原理は、サーバーを立ち上げて放送信号をh.264に変換し続けるというものです。これにより、ブラウザで直接視聴することが可能になります。

この他にも、参考になるオープンソースのソリューションがあります:

後書き

ただ字幕を表示するだけでも、背後には多くの技術的な詳細があり、学ぶ価値があります。今回の実装の過程で、MPEG-TSのフォーマットについても知らなかったし、ARIBやISDB-Tの存在も全く知らなかったことを学びましたが、実際にはこれらの規格は日本の放送を何年も支えてきました。

実際に操作してみると、想像していたほど難しくはないことがわかります(字幕解析に関しては、元の信号の復元は全く理解していませんが)。根気よくドキュメントを読み進めれば、実装することも可能です。

この記事が役に立ったと思ったら、下のリンクからコーヒーを奢ってくれると嬉しいです ☕ 私の普通の一日が輝かしいものになります ✨

Buy me a coffee