ariblibとDRCS

DRCSというのは Dynamic Redefinable Character Set の略で、ユーザが任意に定義できる外字です。日本の地デジ放送の字幕は ISO-2022-JP をベースにした8単位文字符号というエンコード形式が使われており、 ISO-2022-JP で定義されている文字の他に ARIB 外字というよくラテ欄で使われてるような記号を定義した文字が使えます。それでも文字が足りない場合は、ビットマップによる文字イメージと臨時の文字コードを送出し、表示側で文字の代わりにそのビットマップを表示するということが行われます。これが地デジの字幕における DRCS です。話者が画面外にいることを示す絵文字や、スピーカーや携帯電話越しの発話であることを示すスピーカーや携帯電話の絵文字、はたまた「つちよし」([土/口])とか「凜」の字は ISO-2022-JP にも ARIB 外字にも定義されていないので DRCS として表示されます。

余談ですが、「妖狐×僕SS」の主人公白鬼院凜々蝶の「凜」の字は、最初の数話は右下が「禾」でなく「示」になっている「凛」の字が表示されていましたが、途中から「凜」をイメージした DRCS に置き換えられました。

DRCS の定義

DRCS の定義は ARIB-STD-B24 第一編第2部付録規定D にあります。

Drcs_data_structure(){
    NumberOfCode                                 8  uimsbf
    For (i=0;i<numberOfCode;I++){
        CharacterCode                           16  uimsbf
        NumberOfFont                             8  uimsbf
        for (j=0;j<numberOfFont;j++){
            fontId                               4  uimsbf
            mode                                 4  bslbf
            if (mode == 0000|| mode==0001){
                depth                            8  uimsbf
                width                            8  uimsbf
                height                           8  uimsbf
                for (k=0;k<N;k++){
                    patternData                  8  uimsbf
                }
            else {
                 regionX                         8  uimsbf
                 regionY                         8  uimsbf
                 geometricData_length           16  uimsbf
                 for (k=0;k<N;k++){
                     geometricData               8  uimsbf
                 }
            }
        }
    }
}

forが大文字はじまりだったり小文字だったり if の閉じカッコがなかったりしますがそのまま引用しました。ここで mode は伝送モードを表し、0 か 1 の場合は「圧縮なし」を表し if 節の通り patternData にビットマップデータがそのまま入ります。

DRCS データ構造は、1つ以上の文字を定義でき、さらにそれぞれの文字について1つ以上のフォントを定義できるようになっています。また文字イメージの幅、高さ、色深度も指定可能になっています。実際は、フォントは1、色深度は2、幅は16、高さは18で固定されているようです。

DRCSデータ実例

具体的な DRCS_data_structure のバイナリを以下に示します:

01 41 21 01 00 00 10 12 00 00 0E 08 13 0C 31 9C 
31 98 03 18 06 10 0C 10 18 30 10 20 10 20 00 00 
00 00 20 40 70 E0 20 40 00 00 00 00

これを、先に引用したデータ構造に当てはめると以下のようになります:

バイナリ フィールド 補足
01 number_of_code
41 21 character_code DRCS1-0x21
01 number_of_font
00 font_id, mode
00 depth 2階層
10 width 幅16ドット = 2バイト
12 height 高さ18ドット
00 00 ... 00 00 pattern_data

pattern_data は 1行2バイト×18行のデータです。2進数にしてみるとどういうイメージなのかわかりやすくなります。

2バイトごとに改行2進数0をスペースに置き換え
00 00
0E 08
13 0C
31 9C
31 98
03 18
06 10
0C 10
18 30
10 20
10 20
00 00
00 00
20 40
70 E0
20 40
00 00
00 00
0000000000000000
0000111000001000
0001001100001100
0011000110011100
0011000110011000
0000001100011000
0000011000010000
0000110000010000
0001100000110000
0001000000100000
0001000000100000
0000000000000000
0000000000000000
0010000001000000
0111000011100000
0010000001000000
0000000000000000
0000000000000000
                
    111     1   
   1  11    11  
  11   11  111  
  11   11  11   
      11   11   
     11    1    
    11     1    
   11     11    
   1      1     
   1      1     


  1      1      
 111    111     
  1      1      

                

というとで、この DRCS 構造で定義されていたのは "⁈" (疑問符感嘆符, ?!) でした。

この DRCS は CharacterCode が 0x4121 で、上位バイトが 0x41 なので 1 バイト DRCS です。下位バイトは 0x21 で、字幕本文の中ではこのコードで参照されます。

次に現れた字幕本文バイナリの中身が以下だとすると:

0C 87 8A BF B4 A4 CE C0 BC 20 A4 AA CA CC A4 EC 21

これを8単位符号としてパースして以下の文字列を得られます

8単位符号 文字列
0C CS(画面消去)
87 WHF(前景色: 白)
8A NSZ(文字サイズ: 標準)
BF B4
A4 CE
C0 BC
20 (半角空白)
A4 AA
CA CC
A4 EC
21

DRCS の文字コードはあくまで臨時のものなので、 0x21 がいつも "⁈" であるとは限りません。DRCS_data_structure が出現するごとに上書きされることになります。

文字マッピング

ところで、

00 00 0E 08 13 0C 31 9C 31 98 03 18 06 10 0C 10 18 30
10 20 10 20 00 00 00 00 20 40 70 E0 20 40 00 00 00 00

というバイト列が "⁈" の字に相当しているということは今回目視で判断しました。将来画像認識とかでうまくマッピングできるようになるかもしれませんが、今回は PatternData と実際の文字のマッピングをどこかで定義しておく必要があります。とりあえず md5 でハッシュを取って TSV 形式で保存しておけば良いかなと思います。そして、PatternData のビットマップイメージを PIL などの画像処理ライブラリを使ってハッシュをファイル名にして保存しておき、適宜マッピングファイルにハッシュと相当する文字を追加していくことになるでしょう。

4360dd96063ce1a9660cc8437e8238e3    ?!

これで、 DRCS_data_structure が出たら PatternData の hash を計算し、それが既知のものなら CharacterCode に代替文字列を紐付け、字幕本文に CharacterCode が出てきたら代替文字列を表示するようにすれば DRCS を普通の文字として扱えます。未知のものなら、何らかのマーカー文字列を出力して、あとでマッピングを追加したときに置換するのがよいでしょう。

ここらへんの ariblib での実装は drcs.pycaption.py から参照できます。