1 #include <lib/base/eerror.h>
2 #include <lib/dvb/teletext.h>
3 #include <lib/dvb/idemux.h>
4 #include <lib/gdi/gpixmap.h>
6 // G0 and G2 national option table
7 // see table 33 in ETSI EN 300 706
8 // use it with (triplet 1 bits 14-11)*(ctrl bits C12-14)
10 unsigned char NationalOptionSubsetsLookup[16*8] =
12 1, 4, 11, 5, 3, 8, 0, 9,
13 7, 4, 11, 5, 3, 1, 0, 1,
14 1, 4, 11, 5, 3, 8, 12, 1,
15 1, 1, 1, 1, 1, 10, 1, 9,
16 1, 4, 2, 6, 1, 1, 0, 1,
17 1, 1, 1, 1, 1, 1, 1, 1, // reserved
18 1, 1, 1, 1, 1, 1, 12, 1,
19 1, 1, 1, 1, 1, 1, 1, 1, // reserved
20 1, 1, 1, 1, 3, 1, 1, 1,
21 1, 1, 1, 1, 1, 1, 1, 1, // reserved
22 1, 1, 1, 1, 1, 1, 1, 1,
23 1, 1, 1, 1, 1, 1, 1, 1, // reserved
24 1, 1, 1, 1, 1, 1, 1, 1, // reserved
25 1, 1, 1, 1, 1, 1, 1, 1, // reserved
26 1, 1, 1, 1, 1, 1, 1, 1, // reserved
27 1, 1, 1, 1, 1, 1, 1, 1 // reserved
30 unsigned char NationalReplaceMap[128] =
32 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
34 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8,
38 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0
42 // national option subsets (UTF8)
43 // see table 36 in ETSI EN 300 706
45 unsigned int NationalOptionSubsets[13*14] = {
46 0, 0x0023, 0xc5af, 0xc48d, 0xc5a3, 0xc5be, 0xc3bd, 0xc3ad, 0xc599, 0xc3a9, 0xc3a1, 0xc49b, 0xc3ba, 0xc5a1, // Slovak/Czech
47 0, 0xc2a3, 0x0024, 0x0040, 0xe28690, 0xc2bd, 0xe28692, 0xe28691, 0x0023, 0x002d, 0xc2bc, 0xc781, 0xc2be, 0xc3b7, // English
48 0, 0x0023, 0xc3b5, 0xc5A0, 0xc384, 0xc396, 0xc5bd, 0xc39c, 0xc395, 0xc5a1, 0xc3a4, 0xc3b6, 0xc5be, 0xc3bc, // Estonian
49 0, 0xc3a9, 0xc3af, 0xc3a0, 0xc3ab, 0xc3aa, 0xc3b9, 0xc3ae, 0x0023, 0xc3a8, 0xc3a2, 0xc3b4, 0xc3bb, 0xc3a7, // French
50 0, 0x0023, 0x0024, 0xc2a7, 0xc384, 0xc396, 0xc39c, 0x005e, 0x005f, 0xcb9a, 0xc3a4, 0xc3b6, 0xc3bc, 0xc39f, // German
51 0, 0xc2a3, 0x0024, 0xc3a9, 0xcb9a, 0xc3a7, 0xe28692, 0xe28691, 0x0023, 0xc3b9, 0xc3a0, 0xc3b2, 0xc3a8, 0xc3ac, // Italian
52 0, 0x0023, 0x0024, 0xc5a0, 0xc497, 0xc8a9, 0xc5bd, 0xc48d, 0xc5ab, 0xc5a1, 0xc485, 0xc5b3, 0xc5be, 0xc4af/*FIXMEE*/, // Lithuanian/Lettish
53 0, 0x0023, 0xc584, 0xc485, 0xc6b5, 0xc59a, 0xc581, 0xc487, 0xc3b3, 0xc499, 0xc5bc, 0xc59b, 0xc582, 0xc5ba, // Polish
54 0, 0xc3a7, 0x0024, 0xc2a1, 0xc3a1, 0xc3a9, 0xc3ad, 0xc3b3, 0xc3ba, 0xc2bf, 0xc3bc, 0xc3b1, 0xc3a8, 0xc3a0, // Spanish/Portuguese
55 0, 0x0023, 0xc2a4, 0xc5a2, 0xc382, 0xc59e, 0xc78d, 0xc38e, 0xc4b1, 0xc5a3, 0xc3a2, 0xc59f, 0xc78e, 0xc3ae, // Rumanian
56 0, 0x0023, 0xc38b, 0xc48c, 0xc486, 0xc5bd, 0xc490, 0xc5a0, 0xc3ab, 0xc48d, 0xc487, 0xc5be, 0xc491, 0xc5a1, // Slovenian/Serbian/Croation
57 0, 0x0023, 0xc2a4, 0xc389, 0xc384, 0xc396, 0xc385, 0xc39c, 0x005f, 0xc3a9, 0xc3a4, 0xc3b6, 0xc3a5, 0xc3bc, // Finnish/Hungarian/Swedish
58 0, 0xee8080/*FIXME*/, 0xc7a7, 0xc4b0, 0xc59e, 0xc396, 0xc387, 0xc39c, 0xc7a6, 0xc4b1, 0xc59f, 0xc3b6, 0xc3a7, 0xc3bc // Turkish
61 unsigned short diacr_upper_cmap[26*15] = {
62 0xc380, 0xc381, 0xc382, 0xc383, 0xc480, 0xc482, 0x0000, 0xc384, 0x0000, 0xc385, 0x0000, 0x0000, 0x0000, 0xc484, 0xc482,
63 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
64 0x0000, 0xc486, 0xc488, 0x0000, 0x0000, 0xc48c, 0xc48a, 0x0000, 0x0000, 0x0000, 0xc387, 0x0000, 0x0000, 0x0000, 0xc48c,
65 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48e,
66 0xc388, 0xc389, 0xc38a, 0x0000, 0xc492, 0xc494, 0xc496, 0xc38b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc498, 0xc49a,
67 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
68 0x0000, 0x0000, 0xc49c, 0x0000, 0x0000, 0xc49e, 0xc4a0, 0x0000, 0x0000, 0x0000, 0xc4a2, 0x0000, 0x0000, 0x0000, 0x0000,
69 0x0000, 0x0000, 0xc4a4, 0x0000, 0xc4a6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
70 0xc38c, 0xc38d, 0xc38e, 0xc4a8, 0xc4aa, 0xc4ac, 0xc4b0, 0xc38f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4ae, 0xc4ac,
71 0x0000, 0x0000, 0xc4b4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
72 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4b6, 0x0000, 0x0000, 0x0000, 0x0000,
73 0x0000, 0xc4b9, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4bf, 0x0000, 0x0000, 0x0000, 0xc4bb, 0x0000, 0x0000, 0x0000, 0xc4bd,
74 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
75 0x0000, 0xc583, 0x0000, 0xc391, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc585, 0x0000, 0x0000, 0x0000, 0xc587,
76 0xc392, 0xc393, 0xc394, 0xc395, 0xc58c, 0xc58e, 0x0000, 0xc396, 0x0000, 0x0000, 0x0000, 0x0000, 0xc590, 0x0000, 0xc58e,
77 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
78 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
79 0x0000, 0xc594, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc596, 0x0000, 0x0000, 0x0000, 0xc598,
80 0x0000, 0xc59a, 0xc59c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc59e, 0x0000, 0x0000, 0x0000, 0xc5a0,
81 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5a2, 0x0000, 0x0000, 0x0000, 0xc5a4,
82 0xc399, 0xc39a, 0xc39b, 0xc5a8, 0xc5aa, 0xc5ac, 0x0000, 0xc39c, 0x0000, 0xc5ae, 0x0000, 0x0000, 0xc5b0, 0xc5b2, 0xc5ac,
83 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
84 0x0000, 0x0000, 0xc5b4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
85 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
86 0x0000, 0xc39d, 0xc5b6, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5b8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
87 0x0000, 0xc5b9, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bb, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bd
90 unsigned short diacr_lower_cmap[26*15] = {
91 0xc3a0, 0xc3a1, 0xc3a2, 0xc3a3, 0xc481, 0xc483, 0x0000, 0xc3a4, 0x0000, 0xc3a5, 0x0000, 0x0000, 0x0000, 0xc485, 0xc483,
92 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
93 0x0000, 0xc487, 0xc489, 0x0000, 0x0000, 0xc48d, 0xc48b, 0x0000, 0x0000, 0x0000, 0xc3a7, 0x0000, 0x0000, 0x0000, 0xc48d,
94 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48f,
95 0xc3a8, 0xc3a9, 0xc3aa, 0x0000, 0xc493, 0xc495, 0xc497, 0xc3ab, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc499, 0xc49b,
96 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
97 0x0000, 0x0000, 0xc49d, 0x0000, 0x0000, 0xc49f, 0xc4a1, 0x0000, 0x0000, 0x0000, 0xc4a3, 0x0000, 0x0000, 0x0000, 0x0000,
98 0x0000, 0x0000, 0xc4a5, 0x0000, 0xc4a7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
99 0xc3ac, 0xc3ad, 0xc3ae, 0xc4a9, 0xc4ab, 0xc4ad, 0xc4b1, 0xc3af, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4af, 0xc4ad,
100 0x0000, 0x0000, 0xc4b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
101 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4b7, 0x0000, 0x0000, 0x0000, 0x0000,
102 0x0000, 0xc4ba, 0x0000, 0x0000, 0x0000, 0x0000, 0xc580, 0x0000, 0x0000, 0x0000, 0xc4bc, 0x0000, 0x0000, 0x0000, 0xc4be,
103 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
104 0x0000, 0xc584, 0x0000, 0xc3b1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc586, 0x0000, 0x0000, 0x0000, 0xc588,
105 0xc3b2, 0xc3b3, 0xc3b4, 0xc3b5, 0xc58d, 0xc58f, 0x0000, 0xc3b6, 0x0000, 0x0000, 0x0000, 0x0000, 0xc591, 0x0000, 0xc58f,
106 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
107 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
108 0x0000, 0xc595, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc597, 0x0000, 0x0000, 0x0000, 0xc599,
109 0x0000, 0xc59b, 0xc59d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc59f, 0x0000, 0x0000, 0x0000, 0xc5a1,
110 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5a3, 0x0000, 0x0000, 0x0000, 0xc5a5,
111 0xc3b9, 0xc3ba, 0xc3bb, 0xc5a9, 0xc5ab, 0xc5ad, 0x0000, 0xc3bc, 0x0000, 0xc5af, 0x0000, 0x0000, 0xc5b1, 0xc5b3, 0xc5ad,
112 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
113 0x0000, 0x0000, 0xc5b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
114 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
115 0x0000, 0xc3bd, 0xc5b7, 0x0000, 0x0000, 0x0000, 0x0000, 0xc3bf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
116 0x0000, 0xc5ba, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5be
119 unsigned int Latin_G2_set[6*16] = {
120 0x0020, 0xc2a1, 0xc2a2, 0xc2a3, 0x0024, 0xc2a5, 0x0023, 0xc2a7, 0xc2a4, 0xc2b4, 0x0022, 0xc2ab, 0x003c, 0x005e, 0x003d, 0x0076,
121 0xc2b0, 0xc2b1, 0xc2b2, 0xc2b3, 0xc397, 0xc2b5, 0xc2b6, 0xc2b7, 0xc3b7, 0xc2b4, 0x0022, 0xc2bb, 0xc2bc, 0xc2bd, 0xc2be, 0xc2bf,
122 0x0020, 0x0060, 0xc2b4, 0xcb86, 0x007e, 0xcb89, 0xcb98, 0xcb99, 0xcc88, 0x002e, 0xcb9a, 0x0020, 0x005f, 0x0022, 0x0020, 0xcb98,
123 0x002d, 0xc2b9, 0xc2ae, 0xc2a9, 0xc4a2, 0x002a, 0xc2ac, 0xc0b0, 0xceb1, 0x0020, 0x0020, 0x0020, 0x002a, 0x002a, 0x002a, 0x002a,
124 0xcea9, 0xc386, 0xc490, 0x0061, 0xc4a6, 0x0020, 0xc4b2, 0xc4bf, 0xc581, 0xc398, 0xc592, 0x006f, 0xc39e, 0xc5a6, 0xc58a, 0xc589,
125 0xc4b8, 0xc3a6, 0xc491, 0xc48f, 0xc4a7, 0xc4b1, 0xc4b3, 0xc580, 0xc582, 0xc3b8, 0xc593, 0xc39f, 0xc3be, 0xc5a7, 0xc58b, 0x0020,
128 // This is a very simple en300 706 telext decoder.
129 // It can only decode a single page at a time, thus it's only used
130 // for subtitles. And it ONLY support LATIN Charsets yet!
132 DEFINE_REF(eDVBTeletextParser);
134 /* we asumme error free transmission! */
135 static inline unsigned char decode_odd_parity(unsigned char *b)
138 unsigned char res = 0;
140 if (*b & (0x80 >> i))
145 static inline unsigned char decode_hamming_84(unsigned char *b)
147 return ((*b << 3) & 8) | ((*b ) & 4) | ((*b >> 3) & 2) | ((*b >> 6) & 1);
150 static inline unsigned long decode_hamming_2418(unsigned char *b)
152 static const unsigned char rev[16] = {
158 b[0] = rev[b[0] >> 4] | (rev[b[0] & 0xf] << 4);
159 b[1] = rev[b[1] >> 4] | (rev[b[1] & 0xf] << 4);
160 b[2] = rev[b[2] >> 4] | (rev[b[2] & 0xf] << 4);
161 return ((b[0] & 0x04) >> 2) | ((b[0] & 0x70) >> 3) | ((b[1] & 0x7f) << 4) | ((b[2] & 0x7f) << 11);
164 static int extractPTS(pts_t &pts, unsigned char *pkt)
169 pkt++; // header length
171 if (flags & 0x80) /* PTS present? */
174 pts = ((unsigned long long)(((pkt[0] >> 1) & 7))) << 30;
176 pts |= (pkt[2]>>1) << 15;
185 eDVBTeletextParser::eDVBTeletextParser(iDVBDemux *demux)
187 setStreamID(0xBD); /* as per en 300 472 */
189 setPageAndMagazine(-1, -1);
191 if (demux->createPESReader(eApp, m_pes_reader))
192 eDebug("failed to create teletext subtitle PES reader!");
194 m_pes_reader->connectRead(slot(*this, &eDVBTeletextParser::processData), m_read_connection);
197 eDVBTeletextParser::~eDVBTeletextParser()
201 char *get_bits(int val, int count)
206 for (int i=0; i < count; ++i)
208 buf[(count-i)-1]=val&1?'1':'0';
214 void eDVBTeletextParser::processPESPacket(__u8 *pkt, int len)
216 unsigned char *p = pkt;
219 int have_pts = extractPTS(pts, pkt);
221 p += 4; len -= 4; /* start code, already be verified by pes parser */
222 p += 2; len -= 2; /* length, better use the argument */
224 p += 3; len -= 3; /* pes header */
226 p += 0x24; len -= 0x24; /* skip header */
228 // eDebug("data identifier: %02x", *p);
234 /*unsigned char data_unit_id = */*p++;
235 unsigned char data_unit_length = *p++;
238 if (len < data_unit_length)
240 eDebug("data_unit_length > len");
244 if (data_unit_length != 44)
246 /* eDebug("illegal data unit length %d", data_unit_length); */
250 // if (data_unit_id != 0x03)
252 // /* eDebug("non subtitle data unit id %d", data_unit_id); */
256 /*unsigned char line_offset =*/ *p++; len--;
257 unsigned char framing_code = *p++; len--;
259 int magazine_and_packet_address = decode_hamming_84(p++); len--;
260 magazine_and_packet_address |= decode_hamming_84(p++)<<4; len--;
262 unsigned char *data = p; p += 40; len -= 40;
264 if (framing_code != 0xe4) /* no teletxt data */
267 int M = magazine_and_packet_address & 7,
268 Y = magazine_and_packet_address >> 3;
269 // eDebug("line %d, framing code: %02x, M=%02x, Y=%02x", line_offset, framing_code, m_M, m_Y);
271 if (Y == 0) /* page header */
273 int X = decode_hamming_84(data + 1) * 0x10 + decode_hamming_84(data),
274 // S1 = decode_hamming_84(data + 2),
275 S2C4 = decode_hamming_84(data + 3),
277 // S3 = decode_hamming_84(data + 4),
278 S4C5C6 = decode_hamming_84(data + 5),
280 C = ((S2C4 & 8) ? (1<<4) : 0) |
281 ((S4C5C6 & 0xC) << 3) |
282 (decode_hamming_84(data + 6) << 7) |
283 (decode_hamming_84(data + 7) << 11),
284 serial_mode = C & (1<<11);
286 /* page on the same magazine? end current page. */
287 if ((serial_mode || M == m_page_M) && m_page_open)
289 eDebug("Page End %d %lld", !have_pts, pts);
290 handlePageEnd(!have_pts, pts);
294 if ((C & (1<<6)) && (X != 0xFF) && !(C & (1<<5))) /* scan for pages with subtitle bit set */
296 eDVBServicePMTHandler::subtitleStream s;
298 s.subtitling_type = 0x01; // ebu teletext subtitle
299 s.teletext_page_number = X & 0xFF;
300 s.teletext_magazine_number = M & 7;
301 m_found_subtitle_pages.insert(s);
304 /* correct page on correct magazine? open page. */
305 if (M == m_page_M && X == m_page_X)
307 eDebug("Page Start %d %lld", !have_pts, pts);
313 handleLine(data + 8, 32);
315 } else if (Y < 26) // directly displayable packet
317 /* data for the selected page ? */
318 if (M == m_page_M && m_page_open)
322 handleLine(data, 40);
324 } else if (Y == 26 && m_page_open && M == m_page_M)
326 // int designation_code = decode_hamming_84(data);
327 int display_row=-1, display_column=-1;
328 for (int a = 1; a < 40; a+=3)
331 if ((val=decode_hamming_2418(data+a)) >= 0)
333 unsigned char addr = val & 0x3F;
334 unsigned char mode = (val >> 6) & 0x1F;
335 unsigned char data = (val >> 11) & 0x7F;
336 if (addr == 0x3f && mode == 0x1f) // termination marker
342 display_row = addr - 40;
346 eDebugNoNewLine("ignore unimplemented: ");
348 else //0..39 means column 0..39
350 if (display_row != -1)
352 display_column = addr;
353 // eDebugNoNewLine("PosX(%d) ", display_column);
354 // eDebugNoNewLine("PosY(%d) ", display_row);
355 if (mode > 15) //char from G0 set w/ diacr.
357 unsigned int ch=data;
365 if (ch > 96 && ch < 123)
366 ch = diacr_lower_cmap[(ch-97)*15+(mode&0xF)-1];
367 else if (ch > 64 && ch < 91)
368 ch = diacr_upper_cmap[(ch-65)*15+(mode&0xF)-1];
371 m_modifications[(display_row<<16)|display_column] = ch ? ch : data;
372 else /* when data is 0 we set the diacr. mark later on the existing character ..
373 this isn't described in the EN300706.. but i have seen this on "Das Erste" */
374 m_modifications[(display_row<<16)|display_column] = (mode&0xF);
375 // eDebug("char(%04x) w/ diacr. mark", ch);
378 else if (mode == 15) // char from G2 set
382 unsigned int ch=Latin_G2_set[data-0x20];
383 m_modifications[(display_row<<16)|display_column] = ch;
384 // eDebug("char(%04x) from G2 set", ch);
388 eDebugNoNewLine("ignore G2 char < 0x20: ");
391 eDebugNoNewLine("ignore unimplemented: ");
394 eDebugNoNewLine("row is not selected.. ignore: ");
396 eDebugNoNewLine("triplet = %08x(%s) ", val, get_bits(val, 18));
397 eDebugNoNewLine("address = %02x(%s) ", addr, get_bits(addr, 6));
398 eDebugNoNewLine("mode = %02x(%s) ", mode, get_bits(mode, 5));
399 eDebug("data = %02x(%s)", data, get_bits(data, 7));
403 /*eDebug("non handled packet 30, 31", Y, decode_hamming_84(data))*/;
404 else if (Y == 29 && M == m_page_M)
406 int designation_code = decode_hamming_84(data++);
407 if (designation_code == 0) // 29/0
409 m_M29_t1 = decode_hamming_2418(data);
410 m_M29_t2 = decode_hamming_2418(data+3);
411 if ((m_M29_t1 & 0xF) == 0) // format1
414 eDebug("non handled packet M/%d/0 format %d", Y, m_M29_t1 & 0xF);
417 eDebug("non handled packet M/%d/%d", Y, designation_code);
419 else if (m_page_open && M == m_page_M)
421 int designation_code = decode_hamming_84(data++);
422 if (Y == 28 && designation_code == 0) // 28/0
425 m_X28_t1 = decode_hamming_2418(data);
426 m_X28_t2 = decode_hamming_2418(data+3);
427 if ((m_X28_t1 & 0xF) == 0) // format1
430 eDebug("non handled packet X/%d/0 format %d", Y, m_X28_t1 & 0xF);
435 int tripletX = decode_hamming_2418(data+i);
440 if ((m_X28_t1 & 0xF) == 0) // format1
447 char *c = get_bits(tripletX, 18);
450 eDebugNoNewLine("%c", c[x]);
454 eDebug("decode_hamming_2418 failed!\n");
460 eDebug("non handled packet X/%d/%d", Y, designation_code);
465 int eDVBTeletextParser::start(int pid)
472 return m_pes_reader->start(pid);
478 void eDVBTeletextParser::handlePageStart()
480 if (m_C & (1<<4)) /* erase flag set */
482 m_subtitle_page.clear();
483 m_modifications.clear();
485 // eDebug("erase page!");
488 // eDebug("no erase flag set!");
491 void eDVBTeletextParser::handleLine(unsigned char *data, int len)
494 for (int i=0; i<len; ++i)
495 eDebugNoNewLine("%02x ", decode_odd_parity(data + i));
497 if (!m_Y) /* first line is page header, we don't need that. */
499 m_double_height = -1;
503 if (m_double_height == m_Y)
505 m_double_height = -1;
509 int last_was_white = 1, color = 1; /* start with whitespace. start with color=white. (that's unrelated.) */
511 static unsigned char out[128];
515 nat_opts = (m_C & (1<<14) ? 1 : 0) |
516 (m_C & (1<<13) ? 2 : 0) |
517 (m_C & (1<<12) ? 4 : 0),
518 nat_subset_2 = NationalOptionSubsetsLookup[Gtriplet*8+nat_opts],
519 nat_subset = nat_subset_2,
524 nat_subset = NationalOptionSubsetsLookup[(m_X28_t1 >> 7) & 0x7F];
525 nat_subset_2 = NationalOptionSubsetsLookup[((m_X28_t1 >> 14) & 0xF) | ((m_X28_t2 & 7) << 4)];
526 // eDebug("X/28/0 nat_subset %d, nat_subset2 %d", nat_subset, nat_subset_2);
528 else if (m_M29_0_valid)
530 nat_subset = NationalOptionSubsetsLookup[(m_M29_t1 >> 7) & 0x7F];
531 nat_subset_2 = NationalOptionSubsetsLookup[((m_M29_t1 >> 14) & 0xF) | ((m_M29_t2 & 7) << 4)];
532 // eDebug("M/29/0 nat_subset %d, nat_subset2 %d", nat_subset, nat_subset_2);
535 eDebug("nat_opts = %d, nat_subset = %d, C121314 = %d%d%d",
536 nat_opts, nat_subset,
539 (m_C & (1<<14))?1:0);*/
541 // eDebug("handle subtitle line: %d len", len);
542 for (int i=0; i<len; ++i)
544 unsigned char b = decode_odd_parity(data + i);
545 std::map<int,unsigned int>::iterator it = m_modifications.find((m_Y<<16)|i);
547 if (it != m_modifications.end())
549 unsigned int utf8_code = it->second;
550 // eDebugNoNewLine("%c[%d]", b, b);
551 if (utf8_code < 0x10)
553 int mode = utf8_code;
554 if (b > 96 && b < 123)
555 utf8_code = diacr_lower_cmap[(b-97)*15+mode-1];
556 else if (b > 64 && b < 91)
557 utf8_code = diacr_upper_cmap[(b-65)*15+mode-1];
559 if (utf8_code > 0xFFFFFF)
560 out[outidx++]=(utf8_code&0xFF000000)>>24;
561 if (utf8_code > 0xFFFF)
562 out[outidx++]=(utf8_code&0xFF0000)>>16;
563 if (utf8_code > 0xFF)
564 out[outidx++]=(utf8_code&0xFF00)>>8;
566 out[outidx++]=utf8_code&0xFF;
567 m_modifications.erase(it);
571 if (b < 0x10) /* spacing attribute */
573 if (b < 8) /* colors */
575 if (b != color) /* new color is split into a new string */
577 addSubtitleString(color, std::string((const char*)out, outidx));
583 m_double_height = m_Y + 1;
584 else if (b == 0xa) // close box
586 else if (b == 0xb) // open box
589 eDebug("[ignore %x]", b);
590 /* ignore other attributes */
591 } else if (m_box_open>1)
593 // eDebugNoNewLine("%c(%d)", b, b);
594 /* no more than one whitespace, only printable chars */
595 if (((!last_was_white) || (b != ' ')) && (b >= 0x20))
597 int cur_nat_subset = second_G0_set ? nat_subset_2 : nat_subset;
599 unsigned char offs = NationalReplaceMap[b];
602 unsigned int utf8_code =
603 NationalOptionSubsets[cur_nat_subset*14+offs];
604 if (utf8_code > 0xFFFFFF)
605 out[outidx++]=(utf8_code&0xFF000000)>>24;
606 if (utf8_code > 0xFFFF)
607 out[outidx++]=(utf8_code&0xFF0000)>>16;
608 if (utf8_code > 0xFF)
609 out[outidx++]=(utf8_code&0xFF00)>>8;
610 out[outidx++]=utf8_code&0xFF;
614 last_was_white = b == ' ';
616 else if (b == 0x1b) // ESC ... switch between default G0 and second G0 charset
621 addSubtitleString(color, std::string((const char*)out, outidx));
624 void eDVBTeletextParser::handlePageEnd(int have_pts, const pts_t &pts)
626 // eDebug("handle page end");
627 addSubtitleString(-2, ""); /* end last line */
629 m_subtitle_page.m_have_pts = have_pts;
630 m_subtitle_page.m_pts = pts;
631 m_subtitle_page.m_timeout = 90000 * 20; /* 20s */
633 sendSubtitlePage(); /* send assembled subtitle page to display */
636 void eDVBTeletextParser::setPageAndMagazine(int page, int magazine)
639 eDebug("enable teletext subtitle page %x%02x", magazine, page);
641 eDebug("disable teletext subtitles");
643 m_page_M = magazine; /* magazine to look for */
646 m_page_X = page; /* page number */
651 void eDVBTeletextParser::connectNewPage(const Slot1<void, const eDVBTeletextSubtitlePage&> &slot, ePtr<eConnection> &connection)
653 connection = new eConnection(this, m_new_subtitle_page.connect(slot));
656 void eDVBTeletextParser::addSubtitleString(int color, std::string string)
658 // eDebug("(%d)add subtitle string: %s, col %d", m_Y, string.c_str(), color);
661 if (string.substr(0, 2) == "- ")
663 string = string.substr(2);
667 // eDebug("color %d, m_subtitle_color %d", color, m_subtitle_color);
668 gRGB rgbcol((color & 1) ? 255 : 128, (color & 2) ? 255 : 128, (color & 4) ? 255 : 128);
669 if ((color != m_subtitle_color || force_cell) && !m_subtitle_text.empty() && ((color == -2) || !string.empty()))
671 // eDebug("add text |%s|: %d != %d || %d", m_subtitle_text.c_str(), color, m_subtitle_color, force_cell);
672 m_subtitle_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(rgbcol, m_subtitle_text));
673 m_subtitle_text = "";
674 } else if (!m_subtitle_text.empty() && m_subtitle_text[m_subtitle_text.size()-1] != ' ')
675 m_subtitle_text += " ";
679 // eDebug("set %d as new color", color);
680 m_subtitle_color = color;
681 m_subtitle_text += string;
685 void eDVBTeletextParser::sendSubtitlePage()
687 // eDebug("subtitle page:");
688 bool send=m_C & (1<<4);
689 for (unsigned int i = 0; i < m_subtitle_page.m_elements.size(); ++i)
690 if (!m_subtitle_page.m_elements[i].m_text.empty())
693 m_new_subtitle_page(m_subtitle_page);