1 #include <lib/base/eerror.h>
2 #include <lib/dvb/teletext.h>
3 #include <lib/dvb/idemux.h>
4 #include <lib/gdi/gpixmap.h>
6 // G0 and G2 national option table
7 // see table 33 in ETSI EN 300 706
8 // use it with (triplet 1 bits 14-11)*(ctrl bits C12-14)
10 unsigned char NationalOptionSubsetsLookup[16*8] =
12 1, 4, 11, 5, 3, 8, 0, 9,
13 7, 4, 11, 5, 3, 1, 0, 1,
14 1, 4, 11, 5, 3, 8, 12, 1,
15 1, 1, 1, 1, 1, 10, 1, 9,
16 1, 4, 2, 6, 1, 1, 0, 1,
17 1, 1, 1, 1, 1, 1, 1, 1, // reserved
18 1, 1, 1, 1, 1, 1, 12, 1,
19 1, 1, 1, 1, 1, 1, 1, 1, // reserved
20 1, 1, 1, 1, 3, 1, 1, 1,
21 1, 1, 1, 1, 1, 1, 1, 1, // reserved
22 1, 1, 1, 1, 1, 1, 1, 1,
23 1, 1, 1, 1, 1, 1, 1, 1, // reserved
24 1, 1, 1, 1, 1, 1, 1, 1, // reserved
25 1, 1, 1, 1, 1, 1, 1, 1, // reserved
26 1, 1, 1, 1, 1, 1, 1, 1, // reserved
27 1, 1, 1, 1, 1, 1, 1, 1 // reserved
30 unsigned char NationalReplaceMap[128] =
32 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
34 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8,
38 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0
42 // national option subsets (UTF8)
43 // see table 36 in ETSI EN 300 706
45 unsigned int NationalOptionSubsets[13*14] = {
46 0, 0x0023, 0xc5af, 0xc48d, 0xc5a3, 0xc5be, 0xc3bd, 0xc3ad, 0xc599, 0xc3a9, 0xc3a1, 0xc49b, 0xc3ba, 0xc5a1, // Slovak/Czech
47 0, 0xc2a3, 0x0024, 0x0040, 0xe28690, 0xc2bd, 0xe28692, 0xe28691, 0x0023, 0x002d, 0xc2bc, 0xc781, 0xc2be, 0xc3b7, // English
48 0, 0x0023, 0xc3b5, 0xc5A0, 0xc384, 0xc396, 0xc5bd, 0xc39c, 0xc395, 0xc5a1, 0xc3a4, 0xc3b6, 0xc5be, 0xc3bc, // Estonian
49 0, 0xc3a9, 0xc3af, 0xc3a0, 0xc3ab, 0xc3aa, 0xc3b9, 0xc3ae, 0x0023, 0xc3a8, 0xc3a2, 0xc3b4, 0xc3bb, 0xc3a7, // French
50 0, 0x0023, 0x0024, 0xc2a7, 0xc384, 0xc396, 0xc39c, 0x005e, 0x005f, 0xcb9a, 0xc3a4, 0xc3b6, 0xc3bc, 0xc39f, // German
51 0, 0xc2a3, 0x0024, 0xc3a9, 0xcb9a, 0xc3a7, 0xe28692, 0xe28691, 0x0023, 0xc3b9, 0xc3a0, 0xc3b2, 0xc3a8, 0xc3ac, // Italian
52 0, 0x0023, 0x0024, 0xc5a0, 0xc497, 0xc8a9, 0xc5bd, 0xc48d, 0xc5ab, 0xc5a1, 0xc485, 0xc5b3, 0xc5be, 0xc4af/*FIXMEE*/, // Lithuanian/Lettish
53 0, 0x0023, 0xc584, 0xc485, 0xc6b5, 0xc59a, 0xc581, 0xc487, 0xc3b3, 0xc499, 0xc5bc, 0xc59b, 0xc582, 0xc5ba, // Polish
54 0, 0xc3a7, 0x0024, 0xc2a1, 0xc3a1, 0xc3a9, 0xc3ad, 0xc3b3, 0xc3ba, 0xc2bf, 0xc3bc, 0xc3b1, 0xc3a8, 0xc3a0, // Spanish/Portuguese
55 0, 0x0023, 0xc2a4, 0xc5a2, 0xc382, 0xc59e, 0xc78d, 0xc38e, 0xc4b1, 0xc5a3, 0xc3a2, 0xc59f, 0xc78e, 0xc3ae, // Rumanian
56 0, 0x0023, 0xc38b, 0xc48c, 0xc486, 0xc5bd, 0xc490, 0xc5a0, 0xc3ab, 0xc48d, 0xc487, 0xc5be, 0xc491, 0xc5a1, // Slovenian/Serbian/Croation
57 0, 0x0023, 0xc2a4, 0xc389, 0xc384, 0xc396, 0xc385, 0xc39c, 0x005f, 0xc3a9, 0xc3a4, 0xc3b6, 0xc3a5, 0xc3bc, // Finnish/Hungarian/Swedish
58 0, 0xee8080/*FIXME*/, 0xc7a7, 0xc4b0, 0xc59e, 0xc396, 0xc387, 0xc39c, 0xc7a6, 0xc4b1, 0xc59f, 0xc3b6, 0xc3a7, 0xc3bc // Turkish
61 unsigned short diacr_upper_cmap[26*15] = {
62 0xc380, 0xc381, 0xc382, 0xc383, 0xc480, 0xc482, 0x0000, 0xc384, 0x0000, 0xc385, 0x0000, 0x0000, 0x0000, 0xc484, 0xc482,
63 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
64 0x0000, 0xc486, 0xc488, 0x0000, 0x0000, 0xc48c, 0xc48a, 0x0000, 0x0000, 0x0000, 0xc387, 0x0000, 0x0000, 0x0000, 0xc48c,
65 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48e,
66 0xc388, 0xc389, 0xc38a, 0x0000, 0xc492, 0xc494, 0xc496, 0xc38b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc498, 0xc49a,
67 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
68 0x0000, 0x0000, 0xc49c, 0x0000, 0x0000, 0xc49e, 0xc4a0, 0x0000, 0x0000, 0x0000, 0xc4a2, 0x0000, 0x0000, 0x0000, 0x0000,
69 0x0000, 0x0000, 0xc4a4, 0x0000, 0xc4a6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
70 0xc38c, 0xc38d, 0xc38e, 0xc4a8, 0xc4aa, 0xc4ac, 0xc4b0, 0xc38f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4ae, 0xc4ac,
71 0x0000, 0x0000, 0xc4b4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
72 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4b6, 0x0000, 0x0000, 0x0000, 0x0000,
73 0x0000, 0xc4b9, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4bf, 0x0000, 0x0000, 0x0000, 0xc4bb, 0x0000, 0x0000, 0x0000, 0xc4bd,
74 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
75 0x0000, 0xc583, 0x0000, 0xc391, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc585, 0x0000, 0x0000, 0x0000, 0xc587,
76 0xc392, 0xc393, 0xc394, 0xc395, 0xc58c, 0xc58e, 0x0000, 0xc396, 0x0000, 0x0000, 0x0000, 0x0000, 0xc590, 0x0000, 0xc58e,
77 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
78 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
79 0x0000, 0xc594, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc596, 0x0000, 0x0000, 0x0000, 0xc598,
80 0x0000, 0xc59a, 0xc59c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc59e, 0x0000, 0x0000, 0x0000, 0xc5a0,
81 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5a2, 0x0000, 0x0000, 0x0000, 0xc5a4,
82 0xc399, 0xc39a, 0xc39b, 0xc5a8, 0xc5aa, 0xc5ac, 0x0000, 0xc39c, 0x0000, 0xc5ae, 0x0000, 0x0000, 0xc5b0, 0xc5b2, 0xc5ac,
83 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
84 0x0000, 0x0000, 0xc5b4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
85 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
86 0x0000, 0xc39d, 0xc5b6, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5b8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
87 0x0000, 0xc5b9, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bb, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bd
90 unsigned short diacr_lower_cmap[26*15] = {
91 0xc3a0, 0xc3a1, 0xc3a2, 0xc3a3, 0xc481, 0xc483, 0x0000, 0xc3a4, 0x0000, 0xc3a5, 0x0000, 0x0000, 0x0000, 0xc485, 0xc483,
92 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
93 0x0000, 0xc487, 0xc489, 0x0000, 0x0000, 0xc48d, 0xc48b, 0x0000, 0x0000, 0x0000, 0xc3a7, 0x0000, 0x0000, 0x0000, 0xc48d,
94 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48f,
95 0xc3a8, 0xc3a9, 0xc3aa, 0x0000, 0xc493, 0xc495, 0xc497, 0xc3ab, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc499, 0xc49b,
96 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
97 0x0000, 0x0000, 0xc49d, 0x0000, 0x0000, 0xc49f, 0xc4a1, 0x0000, 0x0000, 0x0000, 0xc4a3, 0x0000, 0x0000, 0x0000, 0x0000,
98 0x0000, 0x0000, 0xc4a5, 0x0000, 0xc4a7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
99 0xc3ac, 0xc3ad, 0xc3ae, 0xc4a9, 0xc4ab, 0xc4ad, 0xc4b1, 0xc3af, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4af, 0xc4ad,
100 0x0000, 0x0000, 0xc4b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
101 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4b7, 0x0000, 0x0000, 0x0000, 0x0000,
102 0x0000, 0xc4ba, 0x0000, 0x0000, 0x0000, 0x0000, 0xc580, 0x0000, 0x0000, 0x0000, 0xc4bc, 0x0000, 0x0000, 0x0000, 0xc4be,
103 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
104 0x0000, 0xc584, 0x0000, 0xc3b1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc586, 0x0000, 0x0000, 0x0000, 0xc588,
105 0xc3b2, 0xc3b3, 0xc3b4, 0xc3b5, 0xc58d, 0xc58f, 0x0000, 0xc3b6, 0x0000, 0x0000, 0x0000, 0x0000, 0xc591, 0x0000, 0xc58f,
106 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
107 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
108 0x0000, 0xc595, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc597, 0x0000, 0x0000, 0x0000, 0xc599,
109 0x0000, 0xc59b, 0xc59d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc59f, 0x0000, 0x0000, 0x0000, 0xc5a1,
110 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5a3, 0x0000, 0x0000, 0x0000, 0xc5a5,
111 0xc3b9, 0xc3ba, 0xc3bb, 0xc5a9, 0xc5ab, 0xc5ad, 0x0000, 0xc3bc, 0x0000, 0xc5af, 0x0000, 0x0000, 0xc5b1, 0xc5b3, 0xc5ad,
112 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
113 0x0000, 0x0000, 0xc5b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
114 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
115 0x0000, 0xc3bd, 0xc5b7, 0x0000, 0x0000, 0x0000, 0x0000, 0xc3bf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
116 0x0000, 0xc5ba, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5be
119 unsigned int Latin_G2_set[6*16] = {
120 0x0020, 0xc2a1, 0xc2a2, 0xc2a3, 0x0024, 0xc2a5, 0x0023, 0xc2a7, 0xc2a4, 0xc2b4, 0x0022, 0xc2ab, 0x003c, 0x005e, 0x003d, 0x0076,
121 0xc2b0, 0xc2b1, 0xc2b2, 0xc2b3, 0xc397, 0xc2b5, 0xc2b6, 0xc2b7, 0xc3b7, 0xc2b4, 0x0022, 0xc2bb, 0xc2bc, 0xc2bd, 0xc2be, 0xc2bf,
122 0x0020, 0x0060, 0xc2b4, 0xcb86, 0x007e, 0xcb89, 0xcb98, 0xcb99, 0xcc88, 0x002e, 0xcb9a, 0x0020, 0x005f, 0x0022, 0x0020, 0xcb98,
123 0x002d, 0xc2b9, 0xc2ae, 0xc2a9, 0xc4a2, 0x002a, 0xc2ac, 0xc0b0, 0xceb1, 0x0020, 0x0020, 0x0020, 0x002a, 0x002a, 0x002a, 0x002a,
124 0xcea9, 0xc386, 0xc490, 0x0061, 0xc4a6, 0x0020, 0xc4b2, 0xc4bf, 0xc581, 0xc398, 0xc592, 0x006f, 0xc39e, 0xc5a6, 0xc58a, 0xc589,
125 0xc4b8, 0xc3a6, 0xc491, 0xc48f, 0xc4a7, 0xc4b1, 0xc4b3, 0xc580, 0xc582, 0xc3b8, 0xc593, 0xc39f, 0xc3be, 0xc5a7, 0xc58b, 0x0020,
128 // This is a very simple en300 706 telext decoder.
129 // It can only decode a single page at a time, thus it's only used
132 DEFINE_REF(eDVBTeletextParser);
134 /* we asumme error free transmission! */
135 static inline unsigned char decode_odd_parity(unsigned char *b)
138 unsigned char res = 0;
140 if (*b & (0x80 >> i))
145 static inline unsigned char decode_hamming_84(unsigned char *b)
147 return ((*b << 3) & 8) | ((*b ) & 4) | ((*b >> 3) & 2) | ((*b >> 6) & 1);
150 static inline unsigned long decode_hamming_2418(unsigned char *b)
152 return ((b[0] & 0x04) >> 2) | ((b[0] & 0x70) >> 3) | ((b[1] & 0x7f) << 4) | ((b[2] & 0x7f) << 11);
155 static int extractPTS(pts_t &pts, unsigned char *pkt)
160 pkt++; // header length
162 if (flags & 0x80) /* PTS present? */
165 pts = ((unsigned long long)(((pkt[0] >> 1) & 7))) << 30;
167 pts |= (pkt[2]>>1) << 15;
176 eDVBTeletextParser::eDVBTeletextParser(iDVBDemux *demux)
178 setStreamID(0xBD); /* as per en 300 472 */
180 setPageAndMagazine(-1, -1);
182 if (demux->createPESReader(eApp, m_pes_reader))
183 eDebug("failed to create teletext subtitle PES reader!");
185 m_pes_reader->connectRead(slot(*this, &eDVBTeletextParser::processData), m_read_connection);
188 eDVBTeletextParser::~eDVBTeletextParser()
192 char *get_bits(int val, int count)
197 for (int i=0; i < count; ++i)
199 buf[(count-i)-1]=val&1?'1':'0';
205 void eDVBTeletextParser::processPESPacket(__u8 *pkt, int len)
207 unsigned char *p = pkt;
210 int have_pts = extractPTS(pts, pkt);
212 p += 4; len -= 4; /* start code, already be verified by pes parser */
213 p += 2; len -= 2; /* length, better use the argument */
215 p += 3; len -= 3; /* pes header */
217 p += 0x24; len -= 0x24; /* skip header */
219 // eDebug("data identifier: %02x", *p);
225 /*unsigned char data_unit_id = */*p++;
226 unsigned char data_unit_length = *p++;
229 if (len < data_unit_length)
231 eDebug("data_unit_length > len");
235 if (data_unit_length != 44)
237 /* eDebug("illegal data unit length %d", data_unit_length); */
241 // if (data_unit_id != 0x03)
243 // /* eDebug("non subtitle data unit id %d", data_unit_id); */
247 /*unsigned char line_offset =*/ *p++; len--;
248 unsigned char framing_code = *p++; len--;
250 int magazine_and_packet_address = decode_hamming_84(p++); len--;
251 magazine_and_packet_address |= decode_hamming_84(p++)<<4; len--;
253 unsigned char *data = p; p += 40; len -= 40;
255 if (framing_code != 0xe4) /* no teletxt data */
258 int M = magazine_and_packet_address & 7,
259 Y = magazine_and_packet_address >> 3;
260 // eDebug("line %d, framing code: %02x, M=%02x, Y=%02x", line_offset, framing_code, m_M, m_Y);
262 if (Y == 0) /* page header */
264 int X = decode_hamming_84(data + 1) * 0x10 + decode_hamming_84(data),
265 // S1 = decode_hamming_84(data + 2),
266 S2C4 = decode_hamming_84(data + 3),
268 // S3 = decode_hamming_84(data + 4),
269 S4C5C6 = decode_hamming_84(data + 5),
271 C = ((S2C4 & 8) ? (1<<4) : 0) |
272 ((S4C5C6 & 0xC) << 3) |
273 (decode_hamming_84(data + 6) << 7) |
274 (decode_hamming_84(data + 7) << 11),
275 serial_mode = C & (1<<11);
277 /* page on the same magazine? end current page. */
278 if ((serial_mode || M == m_page_M) && m_page_open)
280 eDebug("Page End %d %lld", !have_pts, pts);
281 handlePageEnd(have_pts, pts);
285 if ((C & (1<<6)) && (X != 0xFF) && !(C & (1<<5))) /* scan for pages with subtitle bit set */
287 eDVBServicePMTHandler::subtitleStream s;
289 s.subtitling_type = 0x01; // ebu teletext subtitle
290 s.teletext_page_number = X & 0xFF;
291 s.teletext_magazine_number = M & 7;
292 m_found_subtitle_pages.insert(s);
295 /* correct page on correct magazine? open page. */
296 if (M == m_page_M && X == m_page_X)
298 eDebug("Page Start %d %lld", !have_pts, pts);
304 handleLine(data + 8, 32);
306 } else if (Y < 26) // directly displayable packet
308 /* data for the selected page ? */
309 if (M == m_page_M && m_page_open)
313 handleLine(data, 40);
315 } else if (Y == 26 && m_page_open && M == m_page_M)
317 // int designation_code = decode_hamming_84(data);
318 static const unsigned char rev[16] = {
324 int display_row=-1, display_column=-1;
325 for (int a = 1; a < 40; a+=3)
328 data[a] = rev[data[a] >> 4] | (rev[data[a] & 0xf] << 4);
329 data[a+1] = rev[data[a+1] >> 4] | (rev[data[a+1] & 0xf] << 4);
330 data[a+2] = rev[data[a+2] >> 4] | (rev[data[a+2] & 0xf] << 4);
331 if ((val=decode_hamming_2418(data+a)) >= 0)
333 unsigned char addr = val & 0x3F;
334 unsigned char mode = (val >> 6) & 0x1F;
335 unsigned char data = (val >> 11) & 0x7F;
336 if (addr == 0x3f && mode == 0x1f) // termination marker
342 display_row = addr - 40;
346 eDebugNoNewLine("ignore unimplemented: ");
348 else //0..39 means column 0..39
350 if (display_row != -1)
352 display_column = addr;
353 // eDebugNoNewLine("PosX(%d) ", display_column);
354 // eDebugNoNewLine("PosY(%d) ", display_row);
355 if (mode > 15) //char from G0 set w/ diacr.
357 unsigned int ch=data;
365 if (ch > 96 && ch < 123)
366 ch = diacr_lower_cmap[(ch-97)*15+(mode&0xF)-1];
367 else if (ch > 64 && ch < 91)
368 ch = diacr_upper_cmap[(ch-65)*15+(mode&0xF)-1];
371 m_modifications[(display_row<<16)|display_column] = ch ? ch : data;
372 else /* when data is 0 we set the diacr. mark later on the existing character ..
373 this isn't described in the EN300706.. but i have seen this on "Das Erste" */
374 m_modifications[(display_row<<16)|display_column] = (mode&0xF);
375 // eDebug("char(%04x) w/ diacr. mark", ch);
378 else if (mode == 15) // char from G2 set
382 unsigned int ch=Latin_G2_set[data-0x20];
383 m_modifications[(display_row<<16)|display_column] = ch;
384 // eDebug("char(%04x) from G2 set", ch);
388 eDebugNoNewLine("ignore G2 char < 0x20: ");
391 eDebugNoNewLine("ignore unimplemented: ");
394 eDebugNoNewLine("row is not selected.. ignore: ");
396 eDebugNoNewLine("triplet = %08x(%s) ", val, get_bits(val, 18));
397 eDebugNoNewLine("address = %02x(%s) ", addr, get_bits(addr, 6));
398 eDebugNoNewLine("mode = %02x(%s) ", mode, get_bits(mode, 5));
399 eDebug("data = %02x(%s)", data, get_bits(data, 7));
403 /*eDebug("non handled packet 30, 31", Y, decode_hamming_84(data))*/;
405 eDebug("non handled packet M/%d/%d", Y, decode_hamming_84(data));
406 else if (m_page_open)
409 eDebug("non handled packet X/%d/%d", Y, decode_hamming_84(data));
414 int eDVBTeletextParser::start(int pid)
421 return m_pes_reader->start(pid);
427 void eDVBTeletextParser::handlePageStart()
429 if (m_C & (1<<4)) /* erase flag set */
431 m_subtitle_page.clear();
432 m_modifications.clear();
433 // eDebug("erase page!");
436 // eDebug("no erase flag set!");
439 void eDVBTeletextParser::handleLine(unsigned char *data, int len)
442 for (int i=0; i<len; ++i)
443 eDebugNoNewLine("%02x ", decode_odd_parity(data + i));
445 if (!m_Y) /* first line is page header, we don't need that. */
447 m_double_height = -1;
451 if (m_double_height == m_Y)
453 m_double_height = -1;
457 int last_was_white = 1, color = 1; /* start with whitespace. start with color=white. (that's unrelated.) */
459 static unsigned char out[128];
463 nat_opts = (m_C & (1<<14) ? 1 : 0) |
464 (m_C & (1<<13) ? 2 : 0) |
465 (m_C & (1<<12) ? 4 : 0),
466 nat_subset = NationalOptionSubsetsLookup[Gtriplet*8+nat_opts];
467 /* eDebug("nat_opts = %d, nat_subset = %d, C121314 = %d%d%d",
468 nat_opts, nat_subset,
471 (m_C & (1<<14))?1:0);*/
473 // eDebug("handle subtitle line: %d len", len);
474 for (int i=0; i<len; ++i)
476 std::map<int,unsigned int>::iterator it = m_modifications.find((m_Y<<16)|i);
477 if (it != m_modifications.end())
479 unsigned int utf8_code = it->second;
480 if (utf8_code < 0x10)
482 int mode = utf8_code;
483 unsigned char ch = decode_odd_parity(data + i);
484 if (ch > 96 && ch < 123)
485 utf8_code = diacr_lower_cmap[(ch-97)*15+mode-1];
486 else if (ch > 64 && ch < 91)
487 utf8_code = diacr_upper_cmap[(ch-65)*15+mode-1];
489 if (utf8_code > 0xFFFFFF)
490 out[outidx++]=(utf8_code&0xFF000000)>>24;
491 if (utf8_code > 0xFFFF)
492 out[outidx++]=(utf8_code&0xFF0000)>>16;
493 if (utf8_code > 0xFF)
494 out[outidx++]=(utf8_code&0xFF00)>>8;
496 out[outidx++]=utf8_code&0xFF;
497 m_modifications.erase(it);
501 unsigned char b = decode_odd_parity(data + i);
503 if (b < 0x10) /* spacing attribute */
505 if (b < 8) /* colors */
507 if (b != color) /* new color is split into a new string */
509 addSubtitleString(color, std::string((const char*)out, outidx));
515 m_double_height = m_Y + 1;
516 else if (b == 0xa) // close box
518 else if (b == 0xb) // open box
521 eDebug("[ignore %x]", b);
522 /* ignore other attributes */
523 } else if (m_box_open>1)
525 //eDebugNoNewLine("%c", b);
526 /* no more than one whitespace, only printable chars */
527 if (((!last_was_white) || (b != ' ')) && (b >= 0x20))
529 int cur_nat_subset = nat_subset;
531 if (b == 0x24) // workaround for currency sign.. the only on non latin1 char in G0 set
537 unsigned char offs = NationalReplaceMap[b];
540 unsigned int utf8_code =
541 NationalOptionSubsets[cur_nat_subset*14+offs];
542 if (utf8_code > 0xFFFFFF)
543 out[outidx++]=(utf8_code&0xFF000000)>>24;
544 if (utf8_code > 0xFFFF)
545 out[outidx++]=(utf8_code&0xFF0000)>>16;
546 if (utf8_code > 0xFF)
547 out[outidx++]=(utf8_code&0xFF00)>>8;
548 out[outidx++]=utf8_code&0xFF;
552 last_was_white = b == ' ';
557 addSubtitleString(color, std::string((const char*)out, outidx));
560 void eDVBTeletextParser::handlePageEnd(int have_pts, const pts_t &pts)
562 // eDebug("handle page end");
563 addSubtitleString(-2, ""); /* end last line */
565 m_subtitle_page.m_have_pts = have_pts;
566 m_subtitle_page.m_pts = pts;
567 m_subtitle_page.m_timeout = 90000 * 20; /* 20s */
569 sendSubtitlePage(); /* send assembled subtitle page to display */
572 void eDVBTeletextParser::setPageAndMagazine(int page, int magazine)
575 eDebug("enable teletext subtitle page %x%02x", magazine, page);
577 eDebug("disable teletext subtitles");
578 m_page_M = magazine; /* magazine to look for */
581 m_page_X = page; /* page number */
586 void eDVBTeletextParser::connectNewPage(const Slot1<void, const eDVBTeletextSubtitlePage&> &slot, ePtr<eConnection> &connection)
588 connection = new eConnection(this, m_new_subtitle_page.connect(slot));
591 void eDVBTeletextParser::addSubtitleString(int color, std::string string)
593 // eDebug("(%d)add subtitle string: %s, col %d", m_Y, string.c_str(), color);
596 if (string.substr(0, 2) == "- ")
598 string = string.substr(2);
602 // eDebug("color %d, m_subtitle_color %d", color, m_subtitle_color);
603 gRGB rgbcol((color & 1) ? 255 : 128, (color & 2) ? 255 : 128, (color & 4) ? 255 : 128);
604 if ((color != m_subtitle_color || force_cell) && !m_subtitle_text.empty() && ((color == -2) || !string.empty()))
606 // eDebug("add text |%s|: %d != %d || %d", m_subtitle_text.c_str(), color, m_subtitle_color, force_cell);
607 m_subtitle_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(rgbcol, m_subtitle_text));
608 m_subtitle_text = "";
609 } else if (!m_subtitle_text.empty() && m_subtitle_text[m_subtitle_text.size()-1] != ' ')
610 m_subtitle_text += " ";
614 // eDebug("set %d as new color", color);
615 m_subtitle_color = color;
616 m_subtitle_text += string;
620 void eDVBTeletextParser::sendSubtitlePage()
622 // eDebug("subtitle page:");
625 for (unsigned int i = 0; i < m_subtitle_page.m_elements.size(); ++i)
626 if (!m_subtitle_page.m_elements[i].m_text.empty())
629 m_new_subtitle_page(m_subtitle_page);