more complete implementation of national option character subsets
[enigma2.git] / lib / dvb / radiotext.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/dvb/radiotext.h>
3 #include <lib/dvb/idemux.h>
4 #include <lib/gdi/gpixmap.h>
5
6 DEFINE_REF(eDVBRadioTextParser);
7
8 eDVBRadioTextParser::eDVBRadioTextParser(iDVBDemux *demux)
9         :bytesread(0), ptr(0), p1(-1), p2(-1), msgPtr(0), state(0)
10 {
11         setStreamID(0xC0, 0xC0);
12
13         if (demux->createPESReader(eApp, m_pes_reader))
14                 eDebug("failed to create PES reader!");
15         else
16                 m_pes_reader->connectRead(slot(*this, &eDVBRadioTextParser::processData), m_read_connection);
17 }
18
19 #define SWAP(x) ((x<<8)|(x>>8))
20 #define LO(x)   (x&0xFF)
21
22 static inline unsigned short crc_ccitt_byte( unsigned short crc, unsigned char c )
23 {
24         crc = SWAP(crc) ^ c;
25         crc = crc ^ (LO(crc) >> 4);
26         crc = crc ^ (SWAP(LO(crc)) << 4) ^ (LO(crc) << 5);
27         return crc;
28 }
29
30 static int bitrate[3][3][16] = {
31         {
32                 // MPEG-2, L3
33                 {-1,8000,16000,24000,32000,40000,48000,56000,64000,80000,96000,112000,128000,144000,160000,0}, 
34                 // MPEG-2, L2
35                 {-1,8000,16000,24000,32000,40000,48000,56000,64000,80000,96000,112000,128000,144000,160000,0},
36                 // MPEG-2, L1
37                 {-1,32000,48000,56000,64000,80000,96000,112000,128000,144000,160000,176000,192000,224000,256000,0}
38         },
39         {
40                 // MPEG-1, L3
41                 {-1,32000,40000,48000,56000,64000,80000,96000,112000,128000,160000,192000,224000,256000,320000,0}, 
42                 // MPEG-1, L2
43                 {-1,32000,48000,56000,64000,80000,96000,112000,128000,160000,192000,224000,256000,320000,384000,0},
44                 // MPEG-1, L1
45                 {-1,32000,64000,96000,128000,160000,192000,224000,256000,288000,320000,352000,384000,416000,448000,0}
46         },
47         {
48                 //MPEG-2.5, L3??
49                 {-1,6000,8000,10000,12000,16000,20000,24000,28000,320000,40000,48000,56000,64000,80000,0},
50                 //MPEG-2.5, L2
51                 {-1,6000,8000,10000,12000,16000,20000,24000,28000,320000,40000,48000,56000,64000,80000,0},
52                 //MPEG-2.5, L1
53                 {-1,8000,12000,16000,20000,24000,32000,40000,48000,560000,64000,80000,96000,112000,128000,0}
54         }
55 };
56
57 static int frequency[3][4] = {
58         // MPEG2 - 22.05, 24, 16khz
59         { 22050,24000,16000,0 },
60         // MPEG1 - 44.1, 48, 32khz
61         { 44100,48000,32000,0 },
62         // MPEG2.5 - 11.025, 12, 8khz
63         { 11025,12000,8000,0 }
64 };
65
66 void eDVBRadioTextParser::connectUpdatedRadiotext(const Slot0<void> &slot, ePtr<eConnection> &connection)
67 {
68         connection = new eConnection(this, m_updated_radiotext.connect(slot));
69 }
70
71 void eDVBRadioTextParser::processPESPacket(__u8 *data, int len)
72 {
73         int pos=9+data[8];// skip pes header
74
75         while (pos < len)
76         {
77                 if ((0xFF & data[pos]) != 0xFF || (0xF0 & data[pos + 1]) != 0xF0)
78                         return;
79
80                 int padding_bit = (data[pos + 2]>>1) & 1;
81                 int mode = (data[pos + 3]>>6) & 3;
82                 int channel = mode == 3 ? 1 : 2;
83                 int id = (data[pos + 1] >> 3) & 1;
84                 int emphasis_bit = data[pos + 3] & 3;
85                 int protection_bit = data[pos + 1] & 1;
86                 int rate = -1;
87                 int sample_freq = -1;
88                 int layer = -1;
89
90                 if (emphasis_bit == 2 && id == 1 )
91                         id = 2;
92
93                 if ((layer = (data[pos + 1]>>1) & 3) < 1)
94                         return;
95
96                 if ((rate = bitrate[id][layer - 1][(data[pos + 2]>>4) & 0xf]) < 1)
97                         return;
98
99                 if ((sample_freq = frequency[id][(data[pos + 2]>>2) & 3]) == 0)
100                         return;
101
102                 if (id == 1 && layer == 2)
103                 {
104                         if (rate / channel < 32000)
105                                 return;
106                         if (rate / channel > 192000)
107                                 return;
108                 }
109
110                 int frame_size = layer < 3 ?
111                         (144 * rate / sample_freq) + padding_bit :
112                         ((12 * rate / sample_freq) * 4) + (4 * padding_bit);
113
114                 pos += frame_size;
115
116 #if 0
117 //              eDebug("protection_bit ? %d", protection_bit);
118 //              int offs = protection_bit ? pos - 1 : pos - 3;
119 //              if (data[offs] != 0xFD)
120 //                      offs += 2;
121 //              eDebug("%02x %02x %02x %02x %02x", data[offs-2], data[offs-1], data[offs], data[offs+1], data[offs+2]);
122 #else
123                 int offs = pos - 1;
124 #endif
125
126                 if (data[offs] == 0xFD)
127                 {
128                         int ancillary_len = 1 + data[offs - 1];
129                         offs -= ancillary_len;
130                         while(offs < pos)
131                                 gotAncillaryByte(data[offs++]);
132                 }
133         }
134 }
135
136 void eDVBRadioTextParser::gotAncillaryByte(__u8 data)
137 {
138         buf[bytesread]=data;
139         bytesread+=1;
140         if ( bytesread == 128 )
141         {
142                 while(ptr<128)
143                 {
144                         if ( buf[ptr] == 0xFD )
145                         {
146                                 if (p1 == -1)
147                                         p1 = ptr;
148                                 else
149                                         p2 = ptr;
150                         }
151                         if ( p1 != -1 && p2 != -1 )
152                         {
153                                 int cnt=buf[--p2];
154                                 while ( cnt-- > 0 )
155                                 {
156                                         unsigned char c = buf[--p2];
157                                         if ( state == 1 )
158                                                 crc=0xFFFF;
159                                         if ( state >= 1 && state < 11 )
160                                                 crc = crc_ccitt_byte(crc, c);
161
162                                         switch (state)
163                                         {
164                                                 case 0:
165                                                         if ( c==0xFE )  // Startkennung
166                                                                 state=1;
167                                                         break;
168                                                 case 1: // 10bit Site Address + 6bit Encoder Address
169                                                 case 2:
170                                                 case 3: // Sequence Counter
171                                                         ++state;
172                                                         break;
173                                                 case 4:
174                                                         leninfo=c;
175                                                         ++state;
176                                                         break;
177                                                 case 5:
178                                                         if ( c==0x0A ) // message element code 0x0A Radio Text
179                                                                 ++state;
180                                                         else
181                                                                 state=0;
182                                                         break;
183                                                 case 6: // Data Set Number ... ignore
184                                                 case 7: // Program Service Number ... ignore
185                                                         ++state;
186                                                         break;
187                                                 case 8: // Message Element Length
188                                                         todo=c;
189                                                         if ( !todo || todo > 65 || todo > leninfo-4)
190                                                                 state=0;
191                                                         else
192                                                         {
193                                                                 ++state;
194                                                                 todo-=2;
195                                                                 msgPtr=0;
196                                                         }
197                                                         break;
198                                                 case 9: // Radio Text Status bit:
199                                                         // 0   = AB-flagcontrol
200                                                         // 1-4 = Transmission-Number
201                                                         // 5-6 = Buffer-Config
202                                                         ++state; // ignore ...
203                                                         break;
204                                                 case 10:
205         // TODO build a complete radiotext charcode to UTF8 conversion table for all character > 0x80
206                                                         switch (c)
207                                                         {
208                                                                 case 0 ... 0x7f: break;
209                                                                 case 0x8d: c='ß'; break;
210                                                                 case 0x91: c='ä'; break;
211                                                                 case 0xd1: c='Ä'; break;
212                                                                 case 0x97: c='ö'; break;
213                                                                 case 0xd7: c='Ö'; break;
214                                                                 case 0x99: c='ü'; break;
215                                                                 case 0xd9: c='Ü'; break;
216                                                                 default: c=' '; break;  // convert all unknown to space
217                                                         }
218                                                         message[msgPtr++]=c;
219                                                         if(todo)
220                                                                 --todo;
221                                                         else
222                                                                 ++state;
223                                                         break;
224                                                 case 11:
225                                                         crc16=c<<8;
226                                                         ++state;
227                                                         break;
228                                                 case 12:
229                                                         crc16|=c;
230                                                         message[msgPtr--]=0;
231                                                         while(message[msgPtr] == ' ' && msgPtr > 0)
232                                                                 message[msgPtr--] = 0;
233                                                         if ( crc16 == (crc^0xFFFF) )
234                                                         {
235                                                                 eDebug("radiotext: (%s)", message);
236                                                                 /*emit*/ m_updated_radiotext();
237                                                         }
238                                                         else
239                                                                 eDebug("invalid radiotext crc (%s)", message);
240                                                         state=0;
241                                                         break;
242                                         }
243                                 }
244                                 p1=ptr;
245                                 p2=-1;
246                         }
247                         ++ptr;
248                 }
249                 if (p1 != -1 && (128-p1) != 128)
250                 {
251                         bytesread=ptr=128-p1;
252                         memcpy(buf, buf+p1, ptr);
253                         p1=0;
254                 }
255                 else
256                         bytesread=ptr=0;
257         }
258 }
259
260 int eDVBRadioTextParser::start(int pid)
261 {
262         if (m_pes_reader)
263                 return m_pes_reader->start(pid);
264         else
265                 return -1;
266 }
267