素のJavaScriptでTVの放送用字幕を作ってみた話

この記事の内容は20219年あたりにやっていたときの内容です。2023年版を書いてみました。良かったら併せてご覧ください🙇🏻‍♂️

https://qiita.com/Kaitou/items/115dbdd5c76ca7175651

<br><br>

# TV放送用の字幕、作ってみたくありませんか？
JavaScript（以下JS）は万能言語として、不動の地位を築いていますが、テレビ放送用の字幕…… 正確にはスーパーインポーズ（以下スーパー）も、当然JSで作れます。
今日、突然**「◯◯くん、△△局に行って、TVに流す字幕を作ってくれ。」**という辞令が下りても、この記事を読んでおけば万全です。

# 作るもの
![qiita_20210124@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620149/d69effe1-cc22-7ddb-9581-0e1c35750d08.png)
**ステップ**
①必要なデータを集める。
②ウィンドウその1でデータを受け取るまた必要な情報を加える。
③ウィンドウその2で情報を受け取りスーパーの画像を生成する（フィル信号）。
④ウィンドウその3で情報を受け取りスーパーの表示領域を生成する（キー信号）。
⑤2と3のウィンドウをそれぞれ別ディスプレイに全画面表示する。その際、確認用ディスプレイと放送用ミキサーに分配する。
⑥放送用ミキサーに持ち込む際、必要に応じて信号を変換する（ex 1080p→1080i）。
⑦無事他の映像と重なり、視聴者に届く。

**各ウィンドウの役割**
- **ウィンドウその1（以下W1）**
    - 各種APIからデータを受け取り、それぞれのウィンドウに渡す。もしくはそれぞれのウィンドウの表示モードを切り替える。
- **ウィンドウその2（以下W2）**
    - 表示される映像の元データ（フィル信号）を生成する。ここでは透過情報が持てない。
- **ウィンドウその3（以下W3）**
    - 表示される映像の箇所を指定するデータ（キー信号）を生成する。これが透過情報になる。

# ①必要なデータを集める。
おそらく多くの場合、スーパーは事前に画像を用意しておいて、それと切り替える事が多く、今回のようにわざわざプログラムで画面を生成するというのは、**何かしらのデータをどこかから持ってきて、そのデータから画像を生成する**というニーズがあるからだと思います。
今までの業務だと、WebサービスのAPIからデータを持ってきて、画像を生成するパターンもありましたし、とあるローカルネットワーク内のデータを、そのネットワーク内に立てたローカルサーバーで整形して、その整形データを読み込むというパターンもありました。
このあたりは必要に応じて仕組みを作ってください。

# ②ウィンドウその1でデータを受け取るまた必要な情報を加える。
今回はChromeを使って、3つのウィンドウを立ち上げ、そのウィンドウ間で処理を渡してスーパーの画面を作成しています。
初期の頃に作っていたものでは、W1は、W2とW3の表示モードを切り替えるのみの操作画面にしていて、W2とW3がそれぞれAPIにデータを取りに行くという処理にしていたのですが、これだとそれぞれのウィンドウへのレスポンスに大きな差が出るケースが有り断念。APIの通信等の外部要因の大きなものや、処理自体が重いものは極力W1に寄せて、W2とW3は、データ等を受け取ったら、いかに早く表示処理をするか？という方針にして安定するようになりました。

**補足**
複数ウィンドウをJSで制御するには前準備が必要です。
今回はW1からW2、W3を開くということをしています。

```JS:W1(index.html)
var windowObject = [];
document.getElementById('button').onclick = function() {
  windowObject[0] = window.open('fill.html', 'window2');
  windowObject[1] = window.open('key.html', 'window3');
}
```

またW1からW2を操作するには、上記の方法でウィンドウを開いた上で、このような方法で行ってください。

```JS:W1(index.html)
windowObj[0].hogehoge(data);
```
```JS:W2(fill.html)
function hogehoge(data) {

}
```

# ③ウィンドウその2で情報を受け取りスーパーの画像を生成する（フィル信号）。
このW2では、前述の通り表示される映像の元データを作ります。色は全て扱えますが、透過情報は持てません。透過情報は後述するW3の方で解説します。
ここで画面を生成する方法は、ぱっと思いつくだけでも**HTML＋CSS**と**canvas**の2つの方式がありますが、生成した画像したいも必要に応じて納品して欲しい（その場で渡す）ということが多かったので、canvasで作っていました。
canvasの表示速度の最適化は重要なのですが、ここでは割愛。

# ④ウィンドウその3で情報を受け取りスーパーの表示領域を生成する（キー信号）。
このW3では、W2で作った画面の表示したい位置を白、非表示にしたい箇所を黒、透過の割合に応じてグレーで表示するデータを作ります。Photoshopで言うところの不透明度80%にしたい場合は`#cccccc`、不透明度50%にしたい場合は`#808080`にしてください。
ただ透過部分をグレーにして問題ないと思いますが、放送用ミキサー側の問題もありますので、このあたりは打ち合わせで担当者に確認や、事前テストでトラブルが起こらないかは要チェックです。

# ⑤2と3のウィンドウをそれぞれ別ディスプレイに全画面表示する。その際、確認用ディスプレイと放送用ミキサーに分配する。
これは究極的にはやらなくても良いのですが、現場で何か不具合が起こった時に、問題の切り分けがしやすいようにやっていました。表示するディスプレイは必ず放送用のミキサーに持ち込みたい解像度…… 1920×1080で持ち込みたいならその解像度のディスプレイを使用します。
また分配する際のスプリッターは、こんなのを使っていました。※ちゃんと事前のテストをしましょう
https://www.amazon.co.jp/dp/B0732MD43P/

# ⑥放送用ミキサーに持ち込む際、必要に応じて信号を変換する（ex 1080p→1080i）。
ここは必要ないケースもあったり、必要があれば放送側の方が用意してくださることも多いのですが、事前打ち合わせとテストが重要です。放送機材ではプログレッシブ（1080pのp）は上手く扱えず、インターレース（1080iのi）でないと駄目という機材もあり、また一般的なPCで表示されている画面をそのまま取り込むのに慣れていない方とのお仕事だと、土壇場でやっぱりプログレッシブでは駄目で、インターレースにして欲しい！ということもありました。
予算が許すのであれば、自前でコンバーターを持っていても良いかもしれません。
僕はこんなコンバーターをを使っていました。
https://www.amazon.co.jp/dp/B07C2QMH6W/

# ⑦無事他の映像と重なり、視聴者に届く。
ここまでくれば自分の手を離れて、JSが生成したスーパーがお茶の間に届いているはずです。 :v_tone1:

---

# 補足その1
②のところの補足になりますが、W2とW3の表示のタイムラグは、チラツキとなって現れます。
表示させるときの処理の重さや、使用している機材のスペックやコンディション等々、場合によってはどうしても上手くいかないみたいなことも出てくるかもしれませんが、それは放送側のディレクターさんやミキサーさんと相談すると、一回向こうで非表示にしてくれて、こちらの切り替えを行い、向こうで再表示というオペレーションをしてくれることもあります。大体、みなさん協力的なことが多いので、ぜひ相談してみてください。 :thumbsup_tone1:

# 補足その2
この仕組を使った業務を最後にやったのは2019年の秋なので、現状とは異なる箇所があるかもしれません。
主に屋外での中継がメインの番組をお手伝いさせていただくことが多かったのですが、残念ながらこの状況になってからさっぱり相談がなくなってしまいました。
早くこの状況が終わり、また面白いことが世の中に溢れることを願って公開してみました。 みなさん一緒に頑張りましょう！ 💪🏻