質問やフィードバックがありましたら、フォームからお願いします
本文は台湾華語で、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パケットのさまざまな説明は、こちらの図を参照してください。
主なフィールドには以下のようなものがあります:
- 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

このような文字は別途解析する必要があります。字幕の解析が成功したら、最も重要なのは、正しいタイミングで画面に表示する方法です。信号伝送中には、タイムテーブルが送信され、同期を取ります。
デモ
動画データを直接アップロードできないため、ここではコードとキャプチャ画像のみの紹介となります。興味がある方は自分で実装してみてください。

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