1 #include <lib/base/eerror.h>
2 #include <lib/dvb/teletext.h>
3 #include <lib/dvb/idemux.h>
4 #include <lib/gdi/gpixmap.h>
6 // G0 and G2 national option table
7 // see table 33 in ETSI EN 300 706
8 // use it with (triplet 1 bits 14-11)*(ctrl bits C12-14)
10 unsigned char NationalOptionSubsetsLookup[16*8] =
12 1, 4, 11, 5, 3, 8, 0, 9,
13 7, 4, 11, 5, 3, 1, 0, 1,
14 1, 4, 11, 5, 3, 8, 12, 1,
15 1, 1, 1, 1, 1, 10, 1, 9,
16 1, 4, 2, 6, 1, 1, 0, 1,
17 1, 1, 1, 1, 1, 1, 1, 1, // reserved
18 1, 1, 1, 1, 1, 1, 12, 1,
19 1, 1, 1, 1, 1, 1, 1, 1, // reserved
20 1, 1, 1, 1, 3, 1, 1, 1,
21 1, 1, 1, 1, 1, 1, 1, 1, // reserved
22 1, 1, 1, 1, 1, 1, 1, 1,
23 1, 1, 1, 1, 1, 1, 1, 1, // reserved
24 1, 1, 1, 1, 1, 1, 1, 1, // reserved
25 1, 1, 1, 1, 1, 1, 1, 1, // reserved
26 1, 1, 1, 1, 1, 1, 1, 1, // reserved
27 1, 1, 1, 1, 1, 1, 1, 1 // reserved
30 unsigned char NationalReplaceMap[128] =
32 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
34 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8,
38 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0
42 // national option subsets (UTF8)
43 // see table 36 in ETSI EN 300 706
45 unsigned int NationalOptionSubsets[13*14] = {
46 0, 0x0023, 0xc5af, 0xc48d, 0xc5a3, 0xc5be, 0xc3bd, 0xc3ad, 0xc599, 0xc3a9, 0xc3a1, 0xc49b, 0xc3ba, 0xc5a1, // Slovak/Czech
47 0, 0xc2a3, 0x0024, 0x0040, 0xe28690, 0xc2bd, 0xe28692, 0xe28691, 0x0023, 0x002d, 0xc2bc, 0xc781, 0xc2be, 0xc3b7, // English
48 0, 0x0023, 0xc3b5, 0xc5A0, 0xc384, 0xc396, 0xc5bd, 0xc39c, 0xc395, 0xc5a1, 0xc3a4, 0xc3b6, 0xc5be, 0xc3bc, // Estonian
49 0, 0xc3a9, 0xc3af, 0xc3a0, 0xc3ab, 0xc3aa, 0xc3b9, 0xc3ae, 0x0023, 0xc3a8, 0xc3a2, 0xc3b4, 0xc3bb, 0xc3a7, // French
50 0, 0x0023, 0x0024, 0xc2a7, 0xc384, 0xc396, 0xc39c, 0x005e, 0x005f, 0xcb9a, 0xc3a4, 0xc3b6, 0xc3bc, 0xc39f, // German
51 0, 0xc2a3, 0x0024, 0xc3a9, 0xcb9a, 0xc3a7, 0xe28692, 0xe28691, 0x0023, 0xc3b9, 0xc3a0, 0xc3b2, 0xc3a8, 0xc3ac, // Italian
52 0, 0x0023, 0x0024, 0xc5a0, 0xc497, 0xc8a9, 0xc5bd, 0xc48d, 0xc5ab, 0xc5a1, 0xc485, 0xc5b3, 0xc5be, 0xc4af/*FIXMEE*/, // Lithuanian/Lettish
53 0, 0x0023, 0xc584, 0xc485, 0xc6b5, 0xc59a, 0xc581, 0xc487, 0xc3b3, 0xc499, 0xc5bc, 0xc59b, 0xc582, 0xc5ba, // Polish
54 0, 0xc3a7, 0x0024, 0xc2a1, 0xc3a1, 0xc3a9, 0xc3ad, 0xc3b3, 0xc3ba, 0xc2bf, 0xc3bc, 0xc3b1, 0xc3a8, 0xc3a0, // Spanish/Portuguese
55 0, 0x0023, 0xc2a4, 0xc5a2, 0xc382, 0xc59e, 0xc78d, 0xc38e, 0xc4b1, 0xc5a3, 0xc3a2, 0xc59f, 0xc78e, 0xc3ae, // Rumanian
56 0, 0x0023, 0xc38b, 0xc48c, 0xc486, 0xc5bd, 0xc490, 0xc5a0, 0xc3ab, 0xc48d, 0xc487, 0xc5be, 0xc491, 0xc5a1, // Slovenian/Serbian/Croation
57 0, 0x0023, 0xc2a4, 0xc389, 0xc384, 0xc396, 0xc385, 0xc39c, 0x005f, 0xc3a9, 0xc3a4, 0xc3b6, 0xc3a5, 0xc3bc, // Finnish/Hungarian/Swedish
58 0, 0xee8080/*FIXME*/, 0xc7a7, 0xc4b0, 0xc59e, 0xc396, 0xc387, 0xc39c, 0xc7a6, 0xc4b1, 0xc59f, 0xc3b6, 0xc3a7, 0xc3bc // Turkish
61 unsigned short diacr_upper_cmap[26*15] = {
62 0xc380, 0xc381, 0xc382, 0xc383, 0xc480, 0xc482, 0x0000, 0xc384, 0x0000, 0xc385, 0x0000, 0x0000, 0x0000, 0xc484, 0xc482, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
63 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc486, 0xc488, 0x0000, 0x0000, 0xc48c, 0xc48a, 0x0000, 0x0000, 0x0000, 0xc387, 0x0000, 0x0000, 0x0000, 0xc48c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48e, 0x0000,
64 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48e, 0xc388, 0xc389, 0xc38a, 0x0000, 0xc492, 0xc494, 0xc496, 0xc38b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc498, 0xc49a, 0x0000, 0x0000, 0x0000,
65 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc49c, 0x0000, 0x0000, 0xc49e, 0xc4a0, 0x0000, 0x0000, 0x0000, 0xc4a2, 0x0000, 0x0000, 0x0000,
66 0x0000, 0x0000, 0x0000, 0xc4a4, 0x0000, 0xc4a6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc38c, 0xc38d, 0xc38e, 0xc4a8, 0xc4aa, 0xc4ac, 0xc4b0, 0xc38f, 0x0000, 0x0000,
67 0x0000, 0x0000, 0x0000, 0xc4ae, 0xc4ac, 0x0000, 0x0000, 0xc4b4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
68 0x0000, 0x0000, 0x0000, 0x0000, 0xc4b6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4b9, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4bf, 0x0000, 0x0000, 0x0000, 0xc4bb, 0x0000, 0x0000, 0x0000, 0xc4bd, 0x0000, 0x0000,
69 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc583, 0x0000, 0xc391, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc585, 0x0000, 0x0000,
70 0x0000, 0xc587, 0xc392, 0xc393, 0xc394, 0xc395, 0xc58c, 0xc58e, 0x0000, 0xc396, 0x0000, 0x0000, 0x0000, 0x0000, 0xc590, 0x0000, 0xc58e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
71 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc594, 0x0000, 0x0000, 0x0000,
72 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc596, 0x0000, 0x0000, 0x0000, 0xc598, 0x0000, 0xc59a, 0xc59c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc59e, 0x0000, 0x0000, 0x0000, 0xc5a0, 0x0000,
73 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5a2, 0x0000, 0x0000, 0x0000, 0xc5a4, 0xc399, 0xc39a, 0xc39b, 0xc5a8, 0xc5aa, 0xc5ac, 0x0000, 0xc39c, 0x0000, 0xc5ae, 0x0000, 0x0000,
74 0xc5b0, 0xc5b2, 0xc5ac, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5b4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
75 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc39d, 0xc5b6, 0x0000,
76 0x0000, 0x0000, 0x0000, 0xc5b8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5b9, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bb, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bd,
79 unsigned short diacr_lower_cmap[26*15] = {
80 0xc3a0, 0xc3a1, 0xc3a2, 0xc3a3, 0xc481, 0xc483, 0x0000, 0xc3a4, 0x0000, 0xc3a5, 0x0000, 0x0000, 0x0000, 0xc485, 0xc483, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
81 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc487, 0xc489, 0x0000, 0x0000, 0xc48d, 0xc48b, 0x0000, 0x0000, 0x0000, 0xc3a7, 0x0000, 0x0000, 0x0000, 0xc48d, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48f, 0x0000, 0x0000,
82 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc48f, 0xc3a8, 0xc3a9, 0xc3aa, 0x0000, 0xc493, 0xc495, 0xc497, 0xc3ab, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc499, 0xc49b, 0x0000, 0x0000, 0x0000, 0x0000,
83 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc49d, 0x0000, 0x0000, 0xc49f, 0xc4a1, 0x0000, 0x0000, 0x0000, 0xc4a3, 0x0000, 0x0000, 0x0000, 0x0000,
84 0x0000, 0x0000, 0xc4a5, 0x0000, 0xc4a7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc3ac, 0xc3ad, 0xc3ae, 0xc4a9, 0xc4ab, 0xc4ad, 0xc4b1, 0xc3af, 0x0000, 0x0000, 0x0000,
85 0x0000, 0x0000, 0xc4af, 0xc4ad, 0x0000, 0x0000, 0xc4b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
86 0x0000, 0x0000, 0x0000, 0xc4b7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc4ba, 0x0000, 0x0000, 0x0000, 0x0000, 0xc580, 0x0000, 0x0000, 0x0000, 0xc4bc, 0x0000, 0x0000, 0x0000, 0xc4be, 0x0000, 0x0000, 0x0000,
87 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc584, 0x0000, 0xc3b1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc586, 0x0000, 0x0000, 0x0000,
88 0xc588, 0xc3b2, 0xc3b3, 0xc3b4, 0xc3b5, 0xc58d, 0xc58f, 0x0000, 0xc3b6, 0x0000, 0x0000, 0x0000, 0x0000, 0xc591, 0x0000, 0xc58f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
89 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc595, 0x0000, 0x0000, 0x0000, 0x0000,
90 0x0000, 0x0000, 0x0000, 0x0000, 0xc597, 0x0000, 0x0000, 0x0000, 0xc599, 0x0000, 0xc59b, 0xc59d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc59f, 0x0000, 0x0000, 0x0000, 0xc5a1, 0x0000, 0x0000,
91 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5a3, 0x0000, 0x0000, 0x0000, 0xc5a5, 0xc3b9, 0xc3ba, 0xc3bb, 0xc5a9, 0xc5ab, 0xc5ad, 0x0000, 0xc3bc, 0x0000, 0xc5af, 0x0000, 0x0000, 0xc5b1,
92 0xc5b3, 0xc5ad, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
93 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc3bd, 0xc5b7, 0x0000, 0x0000,
94 0x0000, 0x0000, 0xc3bf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5ba, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5bc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc5be, 0x0000,
97 unsigned int Latin_G2_set[6*16] = {
98 0x0020, 0xc2a1, 0xc2a2, 0xc2a3, 0x0024, 0xc2a5, 0x0023, 0xc2a7, 0xc2a4, 0xc2b4, 0x0022, 0xc2ab, 0x003c, 0x005e, 0x003d, 0x0076,
99 0xc2b0, 0xc2b1, 0xc2b2, 0xc2b3, 0xc397, 0xc2b5, 0xc2b6, 0xc2b7, 0xc3b7, 0xc2b4, 0x0022, 0xc2bb, 0xc2bc, 0xc2bd, 0xc2be, 0xc2bf,
100 0x0020, 0x0060, 0xc2b4, 0xcb86, 0x007e, 0xcb89, 0xcb98, 0xcb99, 0xcc88, 0x002e, 0xcb9a, 0x0020, 0x005f, 0x0022, 0x0020, 0xcb98,
101 0x002d, 0xc2b9, 0xc2ae, 0xc2a9, 0xc4a2, 0x002a, 0xc2ac, 0xc0b0, 0xceb1, 0x0020, 0x0020, 0x0020, 0x002a, 0x002a, 0x002a, 0x002a,
102 0xcea9, 0xc386, 0xc490, 0x0061, 0xc4a6, 0x0020, 0xc4b2, 0xc4bf, 0xc581, 0xc398, 0xc592, 0x006f, 0xc39e, 0xc5a6, 0xc58a, 0xc589,
103 0xc4b8, 0xc3a6, 0xc491, 0xc48f, 0xc4a7, 0xc4b1, 0xc4b3, 0xc580, 0xc582, 0xc3b8, 0xc593, 0xc39f, 0xc3be, 0xc5a7, 0xc58b, 0x0020,
106 // This is a very simple en300 706 telext decoder.
107 // It can only decode a single page at a time, thus it's only used
110 DEFINE_REF(eDVBTeletextParser);
112 /* we asumme error free transmission! */
113 static inline unsigned char decode_odd_parity(unsigned char *b)
116 unsigned char res = 0;
118 if (*b & (0x80 >> i))
123 static inline unsigned char decode_hamming_84(unsigned char *b)
125 return ((*b << 3) & 8) | ((*b ) & 4) | ((*b >> 3) & 2) | ((*b >> 6) & 1);
128 static inline unsigned long decode_hamming_2418(unsigned char *b)
130 return ((b[0] & 0x04) >> 2) | ((b[0] & 0x70) >> 3) | ((b[1] & 0x7f) << 4) | ((b[2] & 0x7f) << 11);
133 static int extractPTS(pts_t &pts, unsigned char *pkt)
138 pkt++; // header length
140 if (flags & 0x80) /* PTS present? */
143 pts = ((unsigned long long)(((pkt[0] >> 1) & 7))) << 30;
145 pts |= (pkt[2]>>1) << 15;
154 eDVBTeletextParser::eDVBTeletextParser(iDVBDemux *demux)
156 setStreamID(0xBD); /* as per en 300 472 */
158 setPageAndMagazine(-1, -1);
160 if (demux->createPESReader(eApp, m_pes_reader))
161 eDebug("failed to create teletext subtitle PES reader!");
163 m_pes_reader->connectRead(slot(*this, &eDVBTeletextParser::processData), m_read_connection);
166 eDVBTeletextParser::~eDVBTeletextParser()
170 char *get_bits(int val, int count)
175 for (int i=0; i < count; ++i)
177 buf[(count-i)-1]=val&1?'1':'0';
183 void eDVBTeletextParser::processPESPacket(__u8 *pkt, int len)
185 unsigned char *p = pkt;
188 int have_pts = extractPTS(pts, pkt);
190 p += 4; len -= 4; /* start code, already be verified by pes parser */
191 p += 2; len -= 2; /* length, better use the argument */
193 p += 3; len -= 3; /* pes header */
195 p += 0x24; len -= 0x24; /* skip header */
197 // eDebug("data identifier: %02x", *p);
203 /*unsigned char data_unit_id = */*p++;
204 unsigned char data_unit_length = *p++;
207 if (len < data_unit_length)
209 eDebug("data_unit_length > len");
213 if (data_unit_length != 44)
215 /* eDebug("illegal data unit length %d", data_unit_length); */
219 // if (data_unit_id != 0x03)
221 // /* eDebug("non subtitle data unit id %d", data_unit_id); */
225 /*unsigned char line_offset =*/ *p++; len--;
226 unsigned char framing_code = *p++; len--;
228 int magazine_and_packet_address = decode_hamming_84(p++); len--;
229 magazine_and_packet_address |= decode_hamming_84(p++)<<4; len--;
231 unsigned char *data = p; p += 40; len -= 40;
233 if (framing_code != 0xe4) /* no teletxt data */
236 int M = magazine_and_packet_address & 7,
237 Y = magazine_and_packet_address >> 3;
238 // eDebug("line %d, framing code: %02x, M=%02x, Y=%02x", line_offset, framing_code, m_M, m_Y);
240 if (Y == 0) /* page header */
242 int X = decode_hamming_84(data + 1) * 0x10 + decode_hamming_84(data),
243 // S1 = decode_hamming_84(data + 2),
244 S2C4 = decode_hamming_84(data + 3),
246 // S3 = decode_hamming_84(data + 4),
247 S4C5C6 = decode_hamming_84(data + 5),
249 C = ((S2C4 & 8) ? (1<<4) : 0) |
250 ((S4C5C6 & 0xC) << 3) |
251 (decode_hamming_84(data + 6) << 7) |
252 (decode_hamming_84(data + 7) << 11),
253 serial_mode = C & (1<<11);
255 /* page on the same magazine? end current page. */
256 if ((serial_mode || M == m_page_M) && m_page_open)
258 eDebug("Page End %d %lld", !have_pts, pts);
259 handlePageEnd(have_pts, pts);
263 if ((C & (1<<6)) && (X != 0xFF) && !(C & (1<<5))) /* scan for pages with subtitle bit set */
265 eDVBServicePMTHandler::subtitleStream s;
267 s.subtitling_type = 0x01; // ebu teletext subtitle
268 s.teletext_page_number = X & 0xFF;
269 s.teletext_magazine_number = M & 7;
270 m_found_subtitle_pages.insert(s);
273 /* correct page on correct magazine? open page. */
274 if (M == m_page_M && X == m_page_X)
276 eDebug("Page Start %d %lld", !have_pts, pts);
278 m_subtitle_page.m_C = C;
279 m_subtitle_page.m_Y = Y;
282 handleLine(data + 8, 32);
284 } else if (Y < 26) // directly displayable packet
286 /* data for the selected page ? */
287 if (M == m_page_M && m_page_open)
289 m_subtitle_page.m_Y = Y;
291 handleLine(data, 40);
293 } else if (Y == 26 && m_page_open && M == m_page_M)
295 // int designation_code = decode_hamming_84(data);
296 static const unsigned char rev[16] = {
302 int display_row=-1, display_column=-1;
303 for (int a = 1; a < 40; a+=3)
306 data[a] = rev[data[a] >> 4] | (rev[data[a] & 0xf] << 4);
307 data[a+1] = rev[data[a+1] >> 4] | (rev[data[a+1] & 0xf] << 4);
308 data[a+2] = rev[data[a+2] >> 4] | (rev[data[a+2] & 0xf] << 4);
309 if ((val=decode_hamming_2418(data+a)) >= 0)
311 unsigned char addr = val & 0x3F;
312 unsigned char mode = (val >> 6) & 0x1F;
313 unsigned char data = (val >> 11) & 0x7F;
314 if (addr == 0x3f && mode == 0x1f) // termination marker
320 display_row = addr - 40;
324 eDebugNoNewLine("ignore unimplemented: ");
326 else //0..39 means column 0..39
328 if (display_row != -1)
330 display_column = addr;
331 // eDebugNoNewLine("PosX(%d) ", display_column);
332 // eDebugNoNewLine("PosY(%d) ", display_row);
333 if (mode > 15) //char from G0 set w/ diacr.
335 unsigned int ch=data;
343 if (ch > 96 && ch < 123)
344 ch = diacr_lower_cmap[(ch-97)*15+(mode&0xF)-1];
345 else if (ch > 64 && ch < 91)
346 ch = diacr_upper_cmap[(ch-65)*15+(mode&0xF)-1];
348 m_modifications[(display_row<<16)|display_column] = ch ? ch : data;
349 // eDebug("char(%04x) w/ diacr. mark", ch);
352 else if (mode == 15) // char from G2 set
356 unsigned int ch=Latin_G2_set[data-0x20];
357 m_modifications[(display_row<<16)|display_column] = ch;
358 // eDebug("char(%04x) from G2 set", ch);
362 eDebugNoNewLine("ignore G2 char < 0x20: ");
365 eDebugNoNewLine("ignore unimplemented: ");
368 eDebugNoNewLine("row is not selected.. ignore: ");
370 eDebugNoNewLine("triplet = %08x(%s) ", val, get_bits(val, 18));
371 eDebugNoNewLine("address = %02x(%s) ", addr, get_bits(addr, 6));
372 eDebugNoNewLine("mode = %02x(%s) ", mode, get_bits(mode, 5));
373 eDebug("data = %02x(%s)", data, get_bits(data, 7));
377 /*eDebug("non handled packet 30, 31", Y, decode_hamming_84(data))*/;
379 eDebug("non handled packet M/%d/%d", Y, decode_hamming_84(data));
380 else if (m_page_open)
383 eDebug("non handled packet X/%d/%d", Y, decode_hamming_84(data));
388 int eDVBTeletextParser::start(int pid)
395 return m_pes_reader->start(pid);
401 void eDVBTeletextParser::handlePageStart()
403 // if (m_C & (1<<4)) /* erase flag set */
405 /* we are always erasing the page,
406 even when the erase flag is not set. */
407 m_subtitle_page.clear();
408 m_modifications.clear();
411 void eDVBTeletextParser::handleLine(unsigned char *data, int len)
414 for (int i=0; i<len; ++i)
415 eDebugNoNewLine("%02x ", decode_odd_parity(data + i));
417 if (!m_subtitle_page.m_Y) /* first line is page header, we don't need that. */
419 m_double_height = -1;
423 if (m_double_height == m_subtitle_page.m_Y)
425 m_double_height = -1;
429 int last_was_white = 1, color = 1; /* start with whitespace. start with color=white. (that's unrelated.) */
431 static unsigned char out[128];
435 nat_opts = (m_subtitle_page.m_C & (1<<14) ? 1 : 0) |
436 (m_subtitle_page.m_C & (1<<13) ? 2 : 0) |
437 (m_subtitle_page.m_C & (1<<12) ? 4 : 0),
438 nat_subset = NationalOptionSubsetsLookup[Gtriplet*8+nat_opts];
439 /* eDebug("nat_opts = %d, nat_subset = %d, C121314 = %d%d%d",
440 nat_opts, nat_subset,
441 (m_subtitle_page.m_C & (1<<12))?1:0,
442 (m_subtitle_page.m_C & (1<<13))?1:0,
443 (m_subtitle_page.m_C & (1<<14))?1:0);*/
445 // eDebug("handle subtitle line: %d len", len);
446 for (int i=0; i<len; ++i)
448 std::map<int,unsigned int>::iterator it = m_modifications.find((m_subtitle_page.m_Y<<16)|i);
449 if (it != m_modifications.end())
451 unsigned int utf8_code = it->second;
452 if (utf8_code > 0xFFFFFF)
453 out[outidx++]=(utf8_code&0xFF000000)>>24;
454 if (utf8_code > 0xFFFF)
455 out[outidx++]=(utf8_code&0xFF0000)>>16;
456 if (utf8_code > 0xFF)
457 out[outidx++]=(utf8_code&0xFF00)>>8;
458 out[outidx++]=utf8_code&0xFF;
462 unsigned char b = decode_odd_parity(data + i);
464 if (b < 0x10) /* spacing attribute */
466 if (b < 8) /* colors */
468 if (b != color) /* new color is split into a new string */
470 addSubtitleString(color, std::string((const char*)out, outidx));
476 m_double_height = m_subtitle_page.m_Y + 1;
477 else if (b == 0xa) // close box
479 else if (b == 0xb) // open box
482 eDebug("[ignore %x]", b);
483 /* ignore other attributes */
484 } else if (m_box_open>1)
486 //eDebugNoNewLine("%c", b);
487 /* no more than one whitespace, only printable chars */
488 if (((!last_was_white) || (b != ' ')) && (b >= 0x20))
490 int cur_nat_subset = nat_subset;
492 if (b == 0x24) // workaround for currency sign.. the only on non latin1 char in G0 set
498 unsigned char offs = NationalReplaceMap[b];
501 unsigned int utf8_code =
502 NationalOptionSubsets[cur_nat_subset*14+offs];
503 if (utf8_code > 0xFFFFFF)
504 out[outidx++]=(utf8_code&0xFF000000)>>24;
505 if (utf8_code > 0xFFFF)
506 out[outidx++]=(utf8_code&0xFF0000)>>16;
507 if (utf8_code > 0xFF)
508 out[outidx++]=(utf8_code&0xFF00)>>8;
509 out[outidx++]=utf8_code&0xFF;
513 last_was_white = b == ' ';
518 addSubtitleString(color, std::string((const char*)out, outidx));
521 void eDVBTeletextParser::handlePageEnd(int have_pts, const pts_t &pts)
523 // eDebug("handle page end");
524 addSubtitleString(-2, ""); /* end last line */
526 m_subtitle_page.m_have_pts = have_pts;
527 m_subtitle_page.m_pts = pts;
528 m_subtitle_page.m_timeout = 90000 * 20; /* 20s */
530 sendSubtitlePage(); /* send assembled subtitle page to display */
533 void eDVBTeletextParser::setPageAndMagazine(int page, int magazine)
536 eDebug("enable teletext subtitle page %x%02x", magazine, page);
538 eDebug("disable teletext subtitles");
539 m_page_M = magazine; /* magazine to look for */
542 m_page_X = page; /* page number */
547 void eDVBTeletextParser::connectNewPage(const Slot1<void, const eDVBTeletextSubtitlePage&> &slot, ePtr<eConnection> &connection)
549 connection = new eConnection(this, m_new_subtitle_page.connect(slot));
552 void eDVBTeletextParser::addSubtitleString(int color, std::string string)
554 // eDebug("(%d)add subtitle string: %s, col %d", m_subtitle_page.m_Y, string.c_str(), color);
557 if (string.substr(0, 2) == "- ")
559 string = string.substr(2);
563 // eDebug("color %d, m_subtitle_color %d", color, m_subtitle_color);
564 gRGB rgbcol((color & 1) ? 255 : 128, (color & 2) ? 255 : 128, (color & 4) ? 255 : 128);
565 if ((color != m_subtitle_color || force_cell) && !m_subtitle_text.empty() && ((color == -2) || !string.empty()))
567 // eDebug("add text |%s|: %d != %d || %d", m_subtitle_text.c_str(), color, m_subtitle_color, force_cell);
568 m_subtitle_page.m_elements.push_back(eDVBTeletextSubtitlePageElement(rgbcol, m_subtitle_text));
569 m_subtitle_text = "";
570 } else if (!m_subtitle_text.empty() && m_subtitle_text[m_subtitle_text.size()-1] != ' ')
571 m_subtitle_text += " ";
575 // eDebug("set %d as new color", color);
576 m_subtitle_color = color;
577 m_subtitle_text += string;
581 void eDVBTeletextParser::sendSubtitlePage()
583 // eDebug("subtitle page:");
586 for (unsigned int i = 0; i < m_subtitle_page.m_elements.size(); ++i)
587 if (!m_subtitle_page.m_elements[i].m_text.empty())
590 m_new_subtitle_page(m_subtitle_page);