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, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
63 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc486, 0xc488, 0x0000, 0x0000, 0xc48c, 0xc48a, 0x0000, 0x0000, 0x0000, 0xc387, 0x0000, 0x0000, 0x0000, 0xc48c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48e, 0x0000,
64 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48e, 0xc388, 0xc389, 0xc38a, 0x0000, 0xc492, 0xc494, 0xc496, 0xc38b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc498, 0xc49a, 0x0000, 0x0000, 0x0000,
65 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc49c, 0x0000, 0x0000, 0xc49e, 0xc4a0, 0x0000, 0x0000, 0x0000, 0xc4a2, 0x0000, 0x0000, 0x0000,
66 0x0000, 0x0000, 0x0000, 0xc4a4, 0x0000, 0xc4a6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc38c, 0xc38d, 0xc38e, 0xc4a8, 0xc4aa, 0xc4ac, 0xc4b0, 0xc38f, 0x0000, 0x0000,
67 0x0000, 0x0000, 0x0000, 0xc4ae, 0xc4ac, 0x0000, 0x0000, 0xc4b4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
68 0x0000, 0x0000, 0x0000, 0x0000, 0xc4b6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4b9, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4bf, 0x0000, 0x0000, 0x0000, 0xc4bb, 0x0000, 0x0000, 0x0000, 0xc4bd, 0x0000, 0x0000,
69 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc583, 0x0000, 0xc391, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc585, 0x0000, 0x0000,
70 0x0000, 0xc587, 0xc392, 0xc393, 0xc394, 0xc395, 0xc58c, 0xc58e, 0x0000, 0xc396, 0x0000, 0x0000, 0x0000, 0x0000, 0xc590, 0x0000, 0xc58e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
71 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc594, 0x0000, 0x0000, 0x0000,
72 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc596, 0x0000, 0x0000, 0x0000, 0xc598, 0x0000, 0xc59a, 0xc59c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc59e, 0x0000, 0x0000, 0x0000, 0xc5a0, 0x0000,
73 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5a2, 0x0000, 0x0000, 0x0000, 0xc5a4, 0xc399, 0xc39a, 0xc39b, 0xc5a8, 0xc5aa, 0xc5ac, 0x0000, 0xc39c, 0x0000, 0xc5ae, 0x0000, 0x0000,
74 0xc5b0, 0xc5b2, 0xc5ac, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5b4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
75 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc39d, 0xc5b6, 0x0000,
76 0x0000, 0x0000, 0x0000, 0xc5b8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5b9, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bb, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bd,
79 unsigned short diacr_lower_cmap[26*15] = {
80 0xc3a0, 0xc3a1, 0xc3a2, 0xc3a3, 0xc481, 0xc483, 0x0000, 0xc3a4, 0x0000, 0xc3a5, 0x0000, 0x0000, 0x0000, 0xc485, 0xc483, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
81 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc487, 0xc489, 0x0000, 0x0000, 0xc48d, 0xc48b, 0x0000, 0x0000, 0x0000, 0xc3a7, 0x0000, 0x0000, 0x0000, 0xc48d, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48f, 0x0000, 0x0000,
82 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48f, 0xc3a8, 0xc3a9, 0xc3aa, 0x0000, 0xc493, 0xc495, 0xc497, 0xc3ab, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc499, 0xc49b, 0x0000, 0x0000, 0x0000, 0x0000,
83 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc49d, 0x0000, 0x0000, 0xc49f, 0xc4a1, 0x0000, 0x0000, 0x0000, 0xc4a3, 0x0000, 0x0000, 0x0000, 0x0000,
84 0x0000, 0x0000, 0xc4a5, 0x0000, 0xc4a7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc3ac, 0xc3ad, 0xc3ae, 0xc4a9, 0xc4ab, 0xc4ad, 0xc4b1, 0xc3af, 0x0000, 0x0000, 0x0000,
85 0x0000, 0x0000, 0xc4af, 0xc4ad, 0x0000, 0x0000, 0xc4b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
86 0x0000, 0x0000, 0x0000, 0xc4b7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4ba, 0x0000, 0x0000, 0x0000, 0x0000, 0xc580, 0x0000, 0x0000, 0x0000, 0xc4bc, 0x0000, 0x0000, 0x0000, 0xc4be, 0x0000, 0x0000, 0x0000,
87 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc584, 0x0000, 0xc3b1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc586, 0x0000, 0x0000, 0x0000,
88 0xc588, 0xc3b2, 0xc3b3, 0xc3b4, 0xc3b5, 0xc58d, 0xc58f, 0x0000, 0xc3b6, 0x0000, 0x0000, 0x0000, 0x0000, 0xc591, 0x0000, 0xc58f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
89 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc595, 0x0000, 0x0000, 0x0000, 0x0000,
90 0x0000, 0x0000, 0x0000, 0x0000, 0xc597, 0x0000, 0x0000, 0x0000, 0xc599, 0x0000, 0xc59b, 0xc59d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc59f, 0x0000, 0x0000, 0x0000, 0xc5a1, 0x0000, 0x0000,
91 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5a3, 0x0000, 0x0000, 0x0000, 0xc5a5, 0xc3b9, 0xc3ba, 0xc3bb, 0xc5a9, 0xc5ab, 0xc5ad, 0x0000, 0xc3bc, 0x0000, 0xc5af, 0x0000, 0x0000, 0xc5b1,
92 0xc5b3, 0xc5ad, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
93 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc3bd, 0xc5b7, 0x0000, 0x0000,
94 0x0000, 0x0000, 0xc3bf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5ba, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5be, 0x0000,
97 unsigned int Latin_G2_set[6*16] = {
98 0x0020, 0xc2a1, 0xc2a2, 0xc2a3, 0x0024, 0xc2a5, 0x0023, 0xc2a7, 0xc2a4, 0xc2b4, 0x0022, 0xc2ab, 0x003c, 0x005e, 0x003d, 0x0076,
99 0xc2b0, 0xc2b1, 0xc2b2, 0xc2b3, 0xc397, 0xc2b5, 0xc2b6, 0xc2b7, 0xc3b7, 0xc2b4, 0x0022, 0xc2bb, 0xc2bc, 0xc2bd, 0xc2be, 0xc2bf,
100 0x0020, 0x0060, 0xc2b4, 0xcb86, 0x007e, 0xcb89, 0xcb98, 0xcb99, 0xcc88, 0x002e, 0xcb9a, 0x0020, 0x005f, 0x0022, 0x0020, 0xcb98,
101 0x002d, 0xc2b9, 0xc2ae, 0xc2a9, 0xc4a2, 0x002a, 0xc2ac, 0xc0b0, 0xceb1, 0x0020, 0x0020, 0x0020, 0x002a, 0x002a, 0x002a, 0x002a,
102 0xcea9, 0xc386, 0xc490, 0x0061, 0xc4a6, 0x0020, 0xc4b2, 0xc4bf, 0xc581, 0xc398, 0xc592, 0x006f, 0xc39e, 0xc5a6, 0xc58a, 0xc589,
103 0xc4b8, 0xc3a6, 0xc491, 0xc48f, 0xc4a7, 0xc4b1, 0xc4b3, 0xc580, 0xc582, 0xc3b8, 0xc593, 0xc39f, 0xc3be, 0xc5a7, 0xc58b, 0x0020,
106 // This is a very simple en300 706 telext decoder.
107 // It can only decode a single page at a time, thus it's only used
110 DEFINE_REF(eDVBTeletextParser);
112 /* we asumme error free transmission! */
113 static inline unsigned char decode_odd_parity(unsigned char *b)
116 unsigned char res = 0;
118 if (*b & (0x80 >> i))
123 static inline unsigned char decode_hamming_84(unsigned char *b)
125 return ((*b << 3) & 8) | ((*b ) & 4) | ((*b >> 3) & 2) | ((*b >> 6) & 1);
128 static inline unsigned long decode_hamming_2418(unsigned char *b)
130 return ((b[0] & 0x04) >> 2) | ((b[0] & 0x70) >> 3) | ((b[1] & 0x7f) << 4) | ((b[2] & 0x7f) << 11);
133 static int extractPTS(pts_t &pts, unsigned char *pkt)
138 pkt++; // header length
140 if (flags & 0x80) /* PTS present? */
143 pts = ((unsigned long long)(((pkt[0] >> 1) & 7))) << 30;
145 pts |= (pkt[2]>>1) << 15;
154 eDVBTeletextParser::eDVBTeletextParser(iDVBDemux *demux)
156 setStreamID(0xBD); /* as per en 300 472 */
158 setPageAndMagazine(-1, -1);
160 if (demux->createPESReader(eApp, m_pes_reader))
161 eDebug("failed to create teletext subtitle PES reader!");
163 m_pes_reader->connectRead(slot(*this, &eDVBTeletextParser::processData), m_read_connection);
166 eDVBTeletextParser::~eDVBTeletextParser()
170 char *get_bits(int val, int count)
175 for (int i=0; i < count; ++i)
177 buf[(count-i)-1]=val&1?'1':'0';
183 void eDVBTeletextParser::processPESPacket(__u8 *pkt, int len)
185 unsigned char *p = pkt;
188 int have_pts = extractPTS(pts, pkt);
190 p += 4; len -= 4; /* start code, already be verified by pes parser */
191 p += 2; len -= 2; /* length, better use the argument */
193 p += 3; len -= 3; /* pes header */
195 p += 0x24; len -= 0x24; /* skip header */
197 // eDebug("data identifier: %02x", *p);
203 /*unsigned char data_unit_id = */*p++;
204 unsigned char data_unit_length = *p++;
207 if (len < data_unit_length)
209 eDebug("data_unit_length > len");
213 if (data_unit_length != 44)
215 /* eDebug("illegal data unit length %d", data_unit_length); */
219 // if (data_unit_id != 0x03)
221 // /* eDebug("non subtitle data unit id %d", data_unit_id); */
225 /*unsigned char line_offset =*/ *p++; len--;
226 unsigned char framing_code = *p++; len--;
228 int magazine_and_packet_address = decode_hamming_84(p++); len--;
229 magazine_and_packet_address |= decode_hamming_84(p++)<<4; len--;
231 unsigned char *data = p; p += 40; len -= 40;
233 if (framing_code != 0xe4) /* no teletxt data */
236 int M = magazine_and_packet_address & 7,
237 Y = magazine_and_packet_address >> 3;
238 // eDebug("line %d, framing code: %02x, M=%02x, Y=%02x", line_offset, framing_code, m_M, m_Y);
240 if (Y == 0) /* page header */
242 int X = decode_hamming_84(data + 1) * 0x10 + decode_hamming_84(data),
243 // S1 = decode_hamming_84(data + 2),
244 S2C4 = decode_hamming_84(data + 3),
246 // S3 = decode_hamming_84(data + 4),
247 S4C5C6 = decode_hamming_84(data + 5),
249 C = ((S2C4 & 8) ? (1<<4) : 0) |
250 ((S4C5C6 & 0xC) << 3) |
251 (decode_hamming_84(data + 6) << 7) |
252 (decode_hamming_84(data + 7) << 11),
253 serial_mode = C & (1<<11);
255 /* page on the same magazine? end current page. */
256 if ((serial_mode || M == m_page_M) && m_page_open)
258 handlePageEnd(have_pts, pts);
262 if ((C & (1<<6)) && (X != 0xFF) && !(C & (1<<5))) /* scan for pages with subtitle bit set */
264 eDVBServicePMTHandler::subtitleStream s;
266 s.subtitling_type = 0x01; // ebu teletext subtitle
267 s.teletext_page_number = X & 0xFF;
268 s.teletext_magazine_number = M & 7;
269 m_found_subtitle_pages.insert(s);
272 /* correct page on correct magazine? open page. */
273 if (M == m_page_M && X == m_page_X)
276 m_subtitle_page.m_C = C;
277 m_subtitle_page.m_Y = Y;
280 handleLine(data + 8, 32);
282 } else if (Y < 26) // directly displayable packet
284 /* data for the selected page ? */
285 if (M == m_page_M && m_page_open)
287 m_subtitle_page.m_Y = Y;
289 handleLine(data, 40);
291 } else if (Y == 26 && m_page_open && M == m_page_M)
293 // int designation_code = decode_hamming_84(data);
294 static const unsigned char rev[16] = {
300 int display_row=-1, display_column=-1;
301 for (int a = 1; a < 40; a+=3)
304 data[a] = rev[data[a] >> 4] | (rev[data[a] & 0xf] << 4);
305 data[a+1] = rev[data[a+1] >> 4] | (rev[data[a+1] & 0xf] << 4);
306 data[a+2] = rev[data[a+2] >> 4] | (rev[data[a+2] & 0xf] << 4);
307 if ((val=decode_hamming_2418(data+a)) >= 0)
309 unsigned char addr = val & 0x3F;
310 unsigned char mode = (val >> 6) & 0x1F;
311 unsigned char data = (val >> 11) & 0x7F;
312 if (addr == 0x3f && mode == 0x1f) // termination marker
318 display_row = addr - 40;
322 eDebugNoNewLine("ignore unimplemented: ");
324 else //0..39 means column 0..39
326 if (display_row != -1)
328 display_column = addr;
329 // eDebugNoNewLine("PosX(%d) ", display_column);
330 // eDebugNoNewLine("PosY(%d) ", display_row);
331 if (mode > 15) //char from G0 set w/ diacr.
333 unsigned int ch=data;
341 if (ch > 96 && ch < 123)
342 ch = diacr_lower_cmap[(ch-97)*15+(mode&0xF)-1];
343 else if (ch > 64 && ch < 91)
344 ch = diacr_upper_cmap[(ch-65)*15+(mode&0xF)-1];
346 m_modifications[(display_row<<16)|display_column] = ch ? ch : data;
347 // eDebug("char(%04x) w/ diacr. mark", ch);
350 else if (mode == 15) // char from G2 set
354 unsigned int ch=Latin_G2_set[data-0x20];
355 m_modifications[(display_row<<16)|display_column] = ch;
356 // eDebug("char(%04x) from G2 set", ch);
360 eDebugNoNewLine("ignore G2 char < 0x20: ");
363 eDebugNoNewLine("ignore unimplemented: ");
366 eDebugNoNewLine("row is not selected.. ignore: ");
368 eDebugNoNewLine("triplet = %08x(%s) ", val, get_bits(val, 18));
369 eDebugNoNewLine("address = %02x(%s) ", addr, get_bits(addr, 6));
370 eDebugNoNewLine("mode = %02x(%s) ", mode, get_bits(mode, 5));
371 eDebug("data = %02x(%s)", data, get_bits(data, 7));
375 /*eDebug("non handled packet 30, 31", Y, decode_hamming_84(data))*/;
377 eDebug("non handled packet M/%d/%d", Y, decode_hamming_84(data));
378 else if (m_page_open)
381 eDebug("non handled packet X/%d/%d", Y, decode_hamming_84(data));
386 int eDVBTeletextParser::start(int pid)
393 return m_pes_reader->start(pid);
399 void eDVBTeletextParser::handlePageStart()
401 // if (m_C & (1<<4)) /* erase flag set */
403 /* we are always erasing the page,
404 even when the erase flag is not set. */
405 m_subtitle_page.clear();
406 m_modifications.clear();
409 void eDVBTeletextParser::handleLine(unsigned char *data, int len)
412 for (int i=0; i<len; ++i)
413 eDebugNoNewLine("%02x ", decode_odd_parity(data + i));
415 if (!m_subtitle_page.m_Y) /* first line is page header, we don't need that. */
417 m_double_height = -1;
421 if (m_double_height == m_subtitle_page.m_Y)
423 m_double_height = -1;
427 int last_was_white = 1, color = 1; /* start with whitespace. start with color=white. (that's unrelated.) */
429 static unsigned char out[128];
433 nat_opts = (m_subtitle_page.m_C & (1<<14) ? 1 : 0) |
434 (m_subtitle_page.m_C & (1<<13) ? 2 : 0) |
435 (m_subtitle_page.m_C & (1<<12) ? 4 : 0),
436 nat_subset = NationalOptionSubsetsLookup[Gtriplet*8+nat_opts];
437 /* eDebug("nat_opts = %d, nat_subset = %d, C121314 = %d%d%d",
438 nat_opts, nat_subset,
439 (m_subtitle_page.m_C & (1<<12))?1:0,
440 (m_subtitle_page.m_C & (1<<13))?1:0,
441 (m_subtitle_page.m_C & (1<<14))?1:0);*/
443 // eDebug("handle subtitle line: %d len", len);
444 for (int i=0; i<len; ++i)
446 std::map<int,unsigned int>::iterator it = m_modifications.find((m_subtitle_page.m_Y<<16)|i);
447 if (it != m_modifications.end())
449 unsigned int utf8_code = it->second;
450 if (utf8_code > 0xFFFFFF)
451 out[outidx++]=(utf8_code&0xFF000000)>>24;
452 if (utf8_code > 0xFFFF)
453 out[outidx++]=(utf8_code&0xFF0000)>>16;
454 if (utf8_code > 0xFF)
455 out[outidx++]=(utf8_code&0xFF00)>>8;
456 out[outidx++]=utf8_code&0xFF;
460 unsigned char b = decode_odd_parity(data + i);
462 if (b < 0x10) /* spacing attribute */
464 if (b < 8) /* colors */
466 if (b != color) /* new color is split into a new string */
468 addSubtitleString(color, std::string((const char*)out, outidx));
474 m_double_height = m_subtitle_page.m_Y + 1;
475 else if (b == 0xa) // close box
477 else if (b == 0xb) // open box
480 eDebug("[ignore %x]", b);
481 /* ignore other attributes */
482 } else if (m_box_open>1)
484 //eDebugNoNewLine("%c", b);
485 /* no more than one whitespace, only printable chars */
486 if (((!last_was_white) || (b != ' ')) && (b >= 0x20))
488 int cur_nat_subset = nat_subset;
490 if (b == 0x24) // workaround for currency sign.. the only on non latin1 char in G0 set
496 unsigned char offs = NationalReplaceMap[b];
499 unsigned int utf8_code =
500 NationalOptionSubsets[cur_nat_subset*14+offs];
501 if (utf8_code > 0xFFFFFF)
502 out[outidx++]=(utf8_code&0xFF000000)>>24;
503 if (utf8_code > 0xFFFF)
504 out[outidx++]=(utf8_code&0xFF0000)>>16;
505 if (utf8_code > 0xFF)
506 out[outidx++]=(utf8_code&0xFF00)>>8;
507 out[outidx++]=utf8_code&0xFF;
511 last_was_white = b == ' ';
516 addSubtitleString(color, std::string((const char*)out, outidx));
519 void eDVBTeletextParser::handlePageEnd(int have_pts, const pts_t &pts)
521 // eDebug("handle page end");
522 addSubtitleString(-2, ""); /* end last line */
524 m_subtitle_page.m_have_pts = have_pts;
525 m_subtitle_page.m_pts = pts;
526 m_subtitle_page.m_timeout = 90000 * 20; /* 20s */
528 sendSubtitlePage(); /* send assembled subtitle page to display */
531 void eDVBTeletextParser::setPageAndMagazine(int page, int magazine)
534 eDebug("enable teletext subtitle page %x%02x", magazine, page);
536 eDebug("disable teletext subtitles");
537 m_page_M = magazine; /* magazine to look for */
540 m_page_X = page; /* page number */
545 void eDVBTeletextParser::connectNewPage(const Slot1<void, const eDVBTeletextSubtitlePage&> &slot, ePtr<eConnection> &connection)
547 connection = new eConnection(this, m_new_subtitle_page.connect(slot));
550 void eDVBTeletextParser::addSubtitleString(int color, std::string string)
552 // eDebug("(%d)add subtitle string: %s, col %d", m_subtitle_page.m_Y, string.c_str(), color);
555 if (string.substr(0, 2) == "- ")
557 string = string.substr(2);
561 // eDebug("color %d, m_subtitle_color %d", color, m_subtitle_color);
562 gRGB rgbcol((color & 1) ? 255 : 128, (color & 2) ? 255 : 128, (color & 4) ? 255 : 128);
563 if ((color != m_subtitle_color || force_cell) && !m_subtitle_text.empty() && ((color == -2) || !string.empty()))
565 // eDebug("add text |%s|: %d != %d || %d", m_subtitle_text.c_str(), color, m_subtitle_color, force_cell);
566 m_subtitle_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(rgbcol, m_subtitle_text));
567 m_subtitle_text = "";
568 } else if (!m_subtitle_text.empty() && m_subtitle_text[m_subtitle_text.size()-1] != ' ')
569 m_subtitle_text += " ";
573 // eDebug("set %d as new color", color);
574 m_subtitle_color = color;
575 m_subtitle_text += string;
579 void eDVBTeletextParser::sendSubtitlePage()
581 // eDebug("subtitle page:");
584 for (unsigned int i = 0; i < m_subtitle_page.m_elements.size(); ++i)
585 if (!m_subtitle_page.m_elements[i].m_text.empty())
588 m_new_subtitle_page(m_subtitle_page);