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