Merge branch 'master' of git.opendreambox.org:/git/enigma2
[enigma2.git] / lib / dvb / teletext.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/dvb/teletext.h>
3 #include <lib/dvb/idemux.h>
4 #include <lib/gdi/gpixmap.h>
5
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)
9
10 unsigned char NationalOptionSubsetsLookup[16*8] =
11 {
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
28 };
29
30 unsigned char NationalReplaceMap[128] =
31 {
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
40 };
41
42 // national option subsets (UTF8)
43 // see table 36 in ETSI EN 300 706
44
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
59 };
60
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
88 };
89
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
117 };
118
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,
126 };
127
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!
131  
132 DEFINE_REF(eDVBTeletextParser);
133
134         /* we asumme error free transmission! */
135 static inline unsigned char decode_odd_parity(unsigned char *b)
136 {
137         int i;
138         unsigned char res = 0;
139         for (i=0; i<7; ++i)
140                 if (*b & (0x80 >> i))
141                         res |= 1<<i;
142         return res;
143 }
144
145 static inline unsigned char decode_hamming_84(unsigned char *b)
146 {
147         return ((*b << 3) & 8) | ((*b     ) & 4) | ((*b >> 3) & 2) | ((*b >> 6) & 1);
148 }
149
150 static inline unsigned long decode_hamming_2418(unsigned char *b)
151 {
152         static const unsigned char rev[16] = {
153                 0x00,0x08,0x04,0x0c,
154                 0x02,0x0a,0x06,0x0e,
155                 0x01,0x09,0x05,0x0d,
156                 0x03,0x0b,0x07,0x0f
157         };
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);
162 }
163
164 static int extractPTS(pts_t &pts, unsigned char *pkt)
165 {
166         pkt += 7;
167         int flags = *pkt++;
168         
169         pkt++; // header length
170         
171         if (flags & 0x80) /* PTS present? */
172         {
173                         /* damn gcc bug */
174                 pts  = ((unsigned long long)(((pkt[0] >> 1) & 7))) << 30;
175                 pts |=   pkt[1] << 22;
176                 pts |=  (pkt[2]>>1) << 15;
177                 pts |=   pkt[3] << 7;
178                 pts |=  (pkt[5]>>1);
179                 
180                 return 0;
181         } else
182                 return -1;
183 }
184
185 eDVBTeletextParser::eDVBTeletextParser(iDVBDemux *demux)
186 {
187         setStreamID(0xBD); /* as per en 300 472 */
188         
189         setPageAndMagazine(-1, -1);
190         
191         if (demux->createPESReader(eApp, m_pes_reader))
192                 eDebug("failed to create teletext subtitle PES reader!");
193         else
194                 m_pes_reader->connectRead(slot(*this, &eDVBTeletextParser::processData), m_read_connection);
195 }
196
197 eDVBTeletextParser::~eDVBTeletextParser()
198 {
199 }
200
201 char *get_bits(int val, int count)
202 {
203         static char buf[33];
204         memset(buf, 0, 32);
205         if (count < 33)
206                 for (int i=0; i < count; ++i)
207                 {
208                         buf[(count-i)-1]=val&1?'1':'0';
209                         val>>=1;
210                 }
211         return buf;
212 }
213
214 void eDVBTeletextParser::processPESPacket(__u8 *pkt, int len)
215 {
216         unsigned char *p = pkt;
217         
218         pts_t pts;
219         int have_pts = extractPTS(pts, pkt);
220         
221         p += 4; len -= 4; /* start code, already be verified by pes parser */
222         p += 2; len -= 2; /* length, better use the argument */ 
223         
224         p += 3; len -= 3; /* pes header */
225         
226         p += 0x24; len -= 0x24; /* skip header */
227         
228 //      eDebug("data identifier: %02x", *p);
229         
230         p++; len--;
231         
232         while (len > 2)
233         {
234                 /*unsigned char data_unit_id = */*p++;
235                 unsigned char data_unit_length = *p++;
236                 len -= 2;
237                 
238                 if (len < data_unit_length)
239                 {
240                         eDebug("data_unit_length > len");
241                         break;
242                 }
243                 
244                 if (data_unit_length != 44)
245                 {
246                         /* eDebug("illegal data unit length %d", data_unit_length); */
247                         break;
248                 }
249                 
250 //              if (data_unit_id != 0x03)
251 //              {
252 //                      /* eDebug("non subtitle data unit id %d", data_unit_id); */
253 //                      break;
254 //              }
255                 
256                 /*unsigned char line_offset =*/ *p++; len--;
257                 unsigned char framing_code = *p++; len--;
258
259                 int magazine_and_packet_address = decode_hamming_84(p++); len--;
260                 magazine_and_packet_address |= decode_hamming_84(p++)<<4; len--;
261
262                 unsigned char *data = p; p += 40; len -= 40;
263                 
264                 if (framing_code != 0xe4) /* no teletxt data */
265                         continue;
266
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);
270
271                 if (Y == 0) /* page header */
272                 {
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),
276 //                              S2 = S2C4 & 7,
277 //                              S3 = decode_hamming_84(data + 4),
278                                 S4C5C6 = decode_hamming_84(data + 5),
279 //                              S4 = S4C5C6 & 3,
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);
285
286                                 /* page on the same magazine? end current page. */
287                         if ((serial_mode || M == m_page_M) && m_page_open)
288                         {
289                                 eDebug("Page End %d %lld", !have_pts, pts);
290                                 handlePageEnd(have_pts, pts);
291                                 m_page_open = 0;
292                         }
293
294                         if ((C & (1<<6)) && (X != 0xFF) && !(C & (1<<5))) /* scan for pages with subtitle bit set */
295                         {
296                                 eDVBServicePMTHandler::subtitleStream s;
297                                 s.pid = m_pid;
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);
302                         }
303
304                                 /* correct page on correct magazine? open page. */
305                         if (M == m_page_M && X == m_page_X)
306                         {
307                                 eDebug("Page Start %d %lld", !have_pts, pts);
308                                 m_C = C;
309                                 m_Y = Y;
310                                 handlePageStart();
311                                 m_page_open = 1;
312                                 m_box_open = 0;
313                                 handleLine(data + 8, 32);
314                         }
315                 } else if (Y < 26) // directly displayable packet
316                 {
317                         /* data for the selected page ? */
318                         if (M == m_page_M && m_page_open)
319                         {
320                                 m_Y = Y;
321                                 m_box_open = 0;
322                                 handleLine(data, 40);
323                         }
324                 } else if (Y == 26 && m_page_open && M == m_page_M)
325                 {
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)
329                         {
330                                 int val;
331                                 if ((val=decode_hamming_2418(data+a)) >= 0)
332                                 {
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
337                                                 break;
338                                         if (addr >= 40)
339                                         {
340                                                 if (mode == 4)
341                                                 {
342                                                         display_row = addr - 40;
343                                                         continue;
344                                                 }
345                                                 else
346                                                         eDebugNoNewLine("ignore unimplemented: ");
347                                         }
348                                         else //0..39 means column 0..39
349                                         {
350                                                 if (display_row != -1)
351                                                 {
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.
356                                                         {
357                                                                 unsigned int ch=data;
358                                                                 if (!mode&0xF)
359                                                                 {
360                                                                         if (data == 0x2A)
361                                                                                 ch = '@';
362                                                                 }
363                                                                 else
364                                                                 {
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];
369                                                                 }
370                                                                 if (ch)
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);
376                                                                 continue;
377                                                         }
378                                                         else if (mode == 15) // char from G2 set
379                                                         {
380                                                                 if (data > 0x19)
381                                                                 {
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);
385                                                                         continue;
386                                                                 }
387                                                                 else
388                                                                         eDebugNoNewLine("ignore G2 char < 0x20: ");
389                                                         }
390                                                         else
391                                                                 eDebugNoNewLine("ignore unimplemented: ");
392                                                 }
393                                                 else
394                                                         eDebugNoNewLine("row is not selected.. ignore: ");
395                                         }
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));
400                                 }
401                         }
402                 } else if (Y > 29)
403                         /*eDebug("non handled packet 30, 31", Y, decode_hamming_84(data))*/;
404                 else if (Y == 29 && M == m_page_M)
405                 {
406                         int designation_code = decode_hamming_84(data++);
407                         if (designation_code == 0) // 29/0
408                         {
409                                 m_M29_t1 = decode_hamming_2418(data++);
410                                 m_M29_t2 = decode_hamming_2418(data++);
411                                 if ((m_M29_t1 & 0xF) == 0) // format1
412                                         m_M29_0_valid = 1;
413                                 else
414                                         eDebug("non handled packet M/%d/0 format %d", Y, m_M29_t1 & 0xF);
415                         }
416                         else
417                                 eDebug("non handled packet M/%d/%d", Y, designation_code);
418                 }
419                 else if (m_page_open && M == m_page_M)
420                 {
421                         int designation_code = decode_hamming_84(data++);
422                         if (Y == 28 && designation_code == 0)   // 28/0
423                         {
424 #if 1
425                                 m_X28_t1 = decode_hamming_2418(data++);
426                                 m_X28_t2 = decode_hamming_2418(data++);
427                                 if ((m_X28_t1 & 0xF) == 0) // format1
428                                         m_X28_0_valid = 1;
429                                 else
430                                         eDebug("non handled packet X/%d/0 format %d", Y, m_X28_t1 & 0xF);
431 #else
432                                         int i=0;
433                                         for (; i < 39; i+=3)
434                                         {
435                                                 int tripletX = decode_hamming_2418(data+i);
436                                                 if (tripletX >= 0)
437                                                 {
438                                                         char *c = get_bits(tripletX, 18);
439                                                         int x=0;
440                                                         for (; x < 18; ++x)
441                                                                 eDebugNoNewLine("%c", c[x]);
442                                                         eDebug("");
443                                                 }
444                                                 else
445                                                         eDebug("decode_hamming_2418 failed!\n");
446                                                 data += 3;
447                                         }
448 #endif
449                         }
450                         else
451                                 eDebug("non handled packet X/%d/%d", Y, designation_code);
452                 }
453         }
454 }
455
456 int eDVBTeletextParser::start(int pid)
457 {
458         m_page_open = 0;
459
460         if (m_pes_reader)
461         {
462                 m_pid = pid;
463                 return m_pes_reader->start(pid);
464         }
465         else
466                 return -1;
467 }
468
469 void eDVBTeletextParser::handlePageStart()
470 {
471         if (m_C & (1<<4)) /* erase flag set */
472         {
473                 m_subtitle_page.clear();
474                 m_modifications.clear();
475                 m_X28_0_valid = 0;
476 //              eDebug("erase page!");
477         }
478 //      else
479 //              eDebug("no erase flag set!");
480 }
481
482 void eDVBTeletextParser::handleLine(unsigned char *data, int len)
483 {
484 /* // hexdump
485         for (int i=0; i<len; ++i)
486                 eDebugNoNewLine("%02x ", decode_odd_parity(data + i));
487         eDebug(""); */
488         if (!m_Y) /* first line is page header, we don't need that. */
489         {
490                 m_double_height = -1;
491                 return;
492         }
493                 
494         if (m_double_height == m_Y)
495         {
496                 m_double_height = -1;
497                 return;
498         }
499
500         int last_was_white = 1, color = 1; /* start with whitespace. start with color=white. (that's unrelated.) */
501
502         static unsigned char out[128];
503
504         int outidx = 0,
505                 Gtriplet = 0,
506                 nat_opts = (m_C & (1<<14) ? 1 : 0) |
507                                         (m_C & (1<<13) ? 2 : 0) |
508                                         (m_C & (1<<12) ? 4 : 0),
509                 nat_subset_2 = NationalOptionSubsetsLookup[Gtriplet*8+nat_opts],
510                 nat_subset = nat_subset_2,
511                 second_G0_set = 0;
512
513                 if (m_X28_0_valid)
514                 {
515                         nat_subset = NationalOptionSubsetsLookup[((m_X28_t1 >> 14) & 0xF) | ((m_X28_t2 & 7) << 4)];
516                         nat_subset_2 = NationalOptionSubsetsLookup[(m_X28_t1 >> 7) & 0xF];
517 //                      eDebug("override nat subset with X28/0... nat_subset2 is %d", nat_subset_2);
518                 }
519                 else if (m_M29_0_valid)
520                 {
521                         nat_subset = NationalOptionSubsetsLookup[((m_M29_t1 >> 14) & 0xF) | ((m_M29_t2 & 7) << 4)];
522                         nat_subset_2 = NationalOptionSubsetsLookup[(m_M29_t1 >> 7) & 0xF];
523 //                      eDebug("override nat subset with M29/0... nat_subset2 is %d", nat_subset_2);
524                 }
525
526         /*eDebug("nat_opts = %d, nat_subset = %d, C121314 = %d%d%d",
527                 nat_opts, nat_subset,
528                 (m_C & (1<<12))?1:0,
529                 (m_C & (1<<13))?1:0,
530                 (m_C & (1<<14))?1:0);*/
531
532 //      eDebug("handle subtitle line: %d len", len);
533         for (int i=0; i<len; ++i)
534         {
535                 unsigned char b = decode_odd_parity(data + i);
536                 std::map<int,unsigned int>::iterator it = m_modifications.find((m_Y<<16)|i);
537
538                 if (it != m_modifications.end())
539                 {
540                         unsigned int utf8_code = it->second;
541 //                      eDebugNoNewLine("%c[%d]", b, b);
542                         if (utf8_code < 0x10)
543                         {
544                                 int mode = utf8_code;
545                                 if (b > 96 && b < 123)
546                                         utf8_code = diacr_lower_cmap[(b-97)*15+mode-1];
547                                 else if (b > 64 && b < 91)
548                                         utf8_code = diacr_upper_cmap[(b-65)*15+mode-1];
549                         }
550                         if (utf8_code > 0xFFFFFF)
551                                 out[outidx++]=(utf8_code&0xFF000000)>>24;
552                         if (utf8_code > 0xFFFF)
553                                 out[outidx++]=(utf8_code&0xFF0000)>>16;
554                         if (utf8_code > 0xFF)
555                                 out[outidx++]=(utf8_code&0xFF00)>>8;
556                         if (utf8_code)
557                                 out[outidx++]=utf8_code&0xFF;
558                         m_modifications.erase(it);
559                         continue;
560                 }
561
562                 if (b < 0x10) /* spacing attribute */
563                 {
564                         if (b < 8) /* colors */
565                         {
566                                 if (b != color) /* new color is split into a new string */
567                                 {
568                                         addSubtitleString(color, std::string((const char*)out, outidx));
569                                         outidx = 0;
570                                         color = b;
571                                 }
572                         }
573                         else if (b == 0xd)
574                                 m_double_height = m_Y + 1;
575                         else if (b == 0xa)  // close box
576                                 m_box_open=0;
577                         else if (b == 0xb)  // open box
578                                 ++m_box_open;
579                         else
580                                 eDebug("[ignore %x]", b);
581                                 /* ignore other attributes */
582                 } else if (m_box_open>1)
583                 {
584 //                      eDebugNoNewLine("%c(%d)", b, b);
585                                 /* no more than one whitespace, only printable chars */
586                         if (((!last_was_white) || (b != ' ')) && (b >= 0x20))
587                         {
588                                 int cur_nat_subset = second_G0_set ? nat_subset_2 : nat_subset;
589
590                                 unsigned char offs = NationalReplaceMap[b];
591                                 if (offs)
592                                 {
593                                         unsigned int utf8_code =
594                                                 NationalOptionSubsets[cur_nat_subset*14+offs];
595                                         if (utf8_code > 0xFFFFFF)
596                                                 out[outidx++]=(utf8_code&0xFF000000)>>24;
597                                         if (utf8_code > 0xFFFF)
598                                                 out[outidx++]=(utf8_code&0xFF0000)>>16;
599                                         if (utf8_code > 0xFF)
600                                                 out[outidx++]=(utf8_code&0xFF00)>>8;
601                                         out[outidx++]=utf8_code&0xFF;
602                                 }
603                                 else
604                                         out[outidx++] = b;
605                                 last_was_white = b == ' ';
606                         }
607                         else if (b == 0x1b) // ESC ... switch between default G0 and second G0 charset
608                                 second_G0_set ^= 1;
609                 }
610         }
611 //      eDebug("");
612         addSubtitleString(color, std::string((const char*)out, outidx));
613 }
614
615 void eDVBTeletextParser::handlePageEnd(int have_pts, const pts_t &pts)
616 {
617 //      eDebug("handle page end");
618         addSubtitleString(-2, ""); /* end last line */ 
619         
620         m_subtitle_page.m_have_pts = have_pts;
621         m_subtitle_page.m_pts = pts;
622         m_subtitle_page.m_timeout = 90000 * 20; /* 20s */
623         if (m_page_X != 0)
624                 sendSubtitlePage();  /* send assembled subtitle page to display */
625 }
626
627 void eDVBTeletextParser::setPageAndMagazine(int page, int magazine)
628 {
629         if (page > 0)
630                 eDebug("enable teletext subtitle page %x%02x", magazine, page);
631         else
632                 eDebug("disable teletext subtitles");
633         m_M29_0_valid = 0;
634         m_page_M = magazine; /* magazine to look for */
635         if (magazine != -1)
636                 m_page_M &= 7;
637         m_page_X = page;  /* page number */
638         if (page != -1)
639                 m_page_X &= 0xFF;
640 }
641
642 void eDVBTeletextParser::connectNewPage(const Slot1<void, const eDVBTeletextSubtitlePage&> &slot, ePtr<eConnection> &connection)
643 {
644         connection = new eConnection(this, m_new_subtitle_page.connect(slot));
645 }
646
647 void eDVBTeletextParser::addSubtitleString(int color, std::string string)
648 {
649 //      eDebug("(%d)add subtitle string: %s, col %d", m_Y, string.c_str(), color);
650         int force_cell = 0;
651
652         if (string.substr(0, 2) == "- ")
653         {
654                 string = string.substr(2);
655                 force_cell = 1;
656         }
657
658 //      eDebug("color %d, m_subtitle_color %d", color, m_subtitle_color);
659         gRGB rgbcol((color & 1) ? 255 : 128, (color & 2) ? 255 : 128, (color & 4) ? 255 : 128);
660         if ((color != m_subtitle_color || force_cell) && !m_subtitle_text.empty() && ((color == -2) || !string.empty()))
661         {
662 //              eDebug("add text |%s|: %d != %d || %d", m_subtitle_text.c_str(), color, m_subtitle_color, force_cell);
663                 m_subtitle_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(rgbcol, m_subtitle_text));
664                 m_subtitle_text = "";
665         } else if (!m_subtitle_text.empty() && m_subtitle_text[m_subtitle_text.size()-1] != ' ')
666                 m_subtitle_text += " ";
667         
668         if (!string.empty())
669         {
670 //              eDebug("set %d as new color", color);
671                 m_subtitle_color = color;
672                 m_subtitle_text += string;
673         }
674 }
675
676 void eDVBTeletextParser::sendSubtitlePage()
677 {
678 //      eDebug("subtitle page:");
679         bool empty=true;
680         if (empty)
681                 for (unsigned int i = 0; i < m_subtitle_page.m_elements.size(); ++i)
682                         if (!m_subtitle_page.m_elements[i].m_text.empty())
683                                 empty=false;
684         if (!empty)
685                 m_new_subtitle_page(m_subtitle_page);
686 }