use stride, allocate accel surface
[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+3);
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+3);
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                                                         if (i == 0)
439                                                         {
440                                                                 if ((m_X28_t1 & 0xF) == 0) // format1
441                                                                         m_X28_0_valid = 1;
442                                                                 m_X28_t1 = tripletX;
443                                                         }
444                                                         else if (i == 1)
445                                                                 m_X28_t2 = tripletX;
446
447                                                         char *c = get_bits(tripletX, 18);
448                                                         int x=0;
449                                                         for (; x < 18; ++x)
450                                                                 eDebugNoNewLine("%c", c[x]);
451                                                         eDebug("");
452                                                 }
453                                                 else
454                                                         eDebug("decode_hamming_2418 failed!\n");
455                                                 data += 3;
456                                         }
457 #endif
458                         }
459                         else
460                                 eDebug("non handled packet X/%d/%d", Y, designation_code);
461                 }
462         }
463 }
464
465 int eDVBTeletextParser::start(int pid)
466 {
467         m_page_open = 0;
468
469         if (m_pes_reader)
470         {
471                 m_pid = pid;
472                 return m_pes_reader->start(pid);
473         }
474         else
475                 return -1;
476 }
477
478 void eDVBTeletextParser::handlePageStart()
479 {
480         if (m_C & (1<<4)) /* erase flag set */
481         {
482                 m_subtitle_page.clear();
483                 m_modifications.clear();
484                 m_X28_0_valid = 0;
485 //              eDebug("erase page!");
486         }
487 //      else
488 //              eDebug("no erase flag set!");
489 }
490
491 void eDVBTeletextParser::handleLine(unsigned char *data, int len)
492 {
493 /* // hexdump
494         for (int i=0; i<len; ++i)
495                 eDebugNoNewLine("%02x ", decode_odd_parity(data + i));
496         eDebug(""); */
497         if (!m_Y) /* first line is page header, we don't need that. */
498         {
499                 m_double_height = -1;
500                 return;
501         }
502                 
503         if (m_double_height == m_Y)
504         {
505                 m_double_height = -1;
506                 return;
507         }
508
509         int last_was_white = 1, color = 1; /* start with whitespace. start with color=white. (that's unrelated.) */
510
511         static unsigned char out[128];
512
513         int outidx = 0,
514                 Gtriplet = 0,
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,
520                 second_G0_set = 0;
521
522         if (m_X28_0_valid)
523         {
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);
527         }
528         else if (m_M29_0_valid)
529         {
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);
533         }
534 /*      else
535                 eDebug("nat_opts = %d, nat_subset = %d, C121314 = %d%d%d",
536                         nat_opts, nat_subset,
537                         (m_C & (1<<12))?1:0,
538                         (m_C & (1<<13))?1:0,
539                         (m_C & (1<<14))?1:0);*/
540
541 //      eDebug("handle subtitle line: %d len", len);
542         for (int i=0; i<len; ++i)
543         {
544                 unsigned char b = decode_odd_parity(data + i);
545                 std::map<int,unsigned int>::iterator it = m_modifications.find((m_Y<<16)|i);
546
547                 if (it != m_modifications.end())
548                 {
549                         unsigned int utf8_code = it->second;
550 //                      eDebugNoNewLine("%c[%d]", b, b);
551                         if (utf8_code < 0x10)
552                         {
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];
558                         }
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;
565                         if (utf8_code)
566                                 out[outidx++]=utf8_code&0xFF;
567                         m_modifications.erase(it);
568                         continue;
569                 }
570
571                 if (b < 0x10) /* spacing attribute */
572                 {
573                         if (b < 8) /* colors */
574                         {
575                                 if (b != color) /* new color is split into a new string */
576                                 {
577                                         addSubtitleString(color, std::string((const char*)out, outidx));
578                                         outidx = 0;
579                                         color = b;
580                                 }
581                         }
582                         else if (b == 0xd)
583                                 m_double_height = m_Y + 1;
584                         else if (b == 0xa)  // close box
585                                 m_box_open=0;
586                         else if (b == 0xb)  // open box
587                                 ++m_box_open;
588                         else
589                                 eDebug("[ignore %x]", b);
590                                 /* ignore other attributes */
591                 } else if (m_box_open>1)
592                 {
593 //                      eDebugNoNewLine("%c(%d)", b, b);
594                                 /* no more than one whitespace, only printable chars */
595                         if (((!last_was_white) || (b != ' ')) && (b >= 0x20))
596                         {
597                                 int cur_nat_subset = second_G0_set ? nat_subset_2 : nat_subset;
598
599                                 unsigned char offs = NationalReplaceMap[b];
600                                 if (offs)
601                                 {
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;
611                                 }
612                                 else
613                                         out[outidx++] = b;
614                                 last_was_white = b == ' ';
615                         }
616                         else if (b == 0x1b) // ESC ... switch between default G0 and second G0 charset
617                                 second_G0_set ^= 1;
618                 }
619         }
620 //      eDebug("");
621         addSubtitleString(color, std::string((const char*)out, outidx));
622 }
623
624 void eDVBTeletextParser::handlePageEnd(int have_pts, const pts_t &pts)
625 {
626 //      eDebug("handle page end");
627         addSubtitleString(-2, ""); /* end last line */ 
628         
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 */
632         if (m_page_X != 0)
633                 sendSubtitlePage();  /* send assembled subtitle page to display */
634 }
635
636 void eDVBTeletextParser::setPageAndMagazine(int page, int magazine)
637 {
638         if (page > 0)
639                 eDebug("enable teletext subtitle page %x%02x", magazine, page);
640         else
641                 eDebug("disable teletext subtitles");
642         m_M29_0_valid = 0;
643         m_page_M = magazine; /* magazine to look for */
644         if (magazine != -1)
645                 m_page_M &= 7;
646         m_page_X = page;  /* page number */
647         if (page != -1)
648                 m_page_X &= 0xFF;
649 }
650
651 void eDVBTeletextParser::connectNewPage(const Slot1<void, const eDVBTeletextSubtitlePage&> &slot, ePtr<eConnection> &connection)
652 {
653         connection = new eConnection(this, m_new_subtitle_page.connect(slot));
654 }
655
656 void eDVBTeletextParser::addSubtitleString(int color, std::string string)
657 {
658 //      eDebug("(%d)add subtitle string: %s, col %d", m_Y, string.c_str(), color);
659         int force_cell = 0;
660
661         if (string.substr(0, 2) == "- ")
662         {
663                 string = string.substr(2);
664                 force_cell = 1;
665         }
666
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()))
670         {
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 += " ";
676         
677         if (!string.empty())
678         {
679 //              eDebug("set %d as new color", color);
680                 m_subtitle_color = color;
681                 m_subtitle_text += string;
682         }
683 }
684
685 void eDVBTeletextParser::sendSubtitlePage()
686 {
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())
691                         send=true;
692         if (send)
693                 m_new_subtitle_page(m_subtitle_page);
694 }