take care of mpeg frame protection bit
[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                 int offs = protection_bit ? pos - 1 : pos - 3;
117                 if (data[offs] == 0xFD)
118                 {
119                         int ancillary_len = 1 + data[offs - 1];
120                         offs -= ancillary_len;
121                         while(offs < pos)
122                                 gotAncillaryByte(data[offs++]);
123                 }
124         }
125 }
126
127 void eDVBRadioTextParser::gotAncillaryByte(__u8 data)
128 {
129         buf[bytesread]=data;
130         bytesread+=1;
131         if ( bytesread == 128 )
132         {
133                 while(ptr<128)
134                 {
135                         if ( buf[ptr] == 0xFD )
136                         {
137                                 if (p1 == -1)
138                                         p1 = ptr;
139                                 else
140                                         p2 = ptr;
141                         }
142                         if ( p1 != -1 && p2 != -1 )
143                         {
144                                 int cnt=buf[--p2];
145                                 while ( cnt-- > 0 )
146                                 {
147                                         unsigned char c = buf[--p2];
148                                         if ( state == 1 )
149                                                 crc=0xFFFF;
150                                         if ( state >= 1 && state < 11 )
151                                                 crc = crc_ccitt_byte(crc, c);
152
153                                         switch (state)
154                                         {
155                                                 case 0:
156                                                         if ( c==0xFE )  // Startkennung
157                                                                 state=1;
158                                                         break;
159                                                 case 1: // 10bit Site Address + 6bit Encoder Address
160                                                 case 2:
161                                                 case 3: // Sequence Counter
162                                                         ++state;
163                                                         break;
164                                                 case 4:
165                                                         leninfo=c;
166                                                         ++state;
167                                                         break;
168                                                 case 5:
169                                                         if ( c==0x0A ) // message element code 0x0A Radio Text
170                                                                 ++state;
171                                                         else
172                                                                 state=0;
173                                                         break;
174                                                 case 6: // Data Set Number ... ignore
175                                                 case 7: // Program Service Number ... ignore
176                                                         ++state;
177                                                         break;
178                                                 case 8: // Message Element Length
179                                                         todo=c;
180                                                         if ( !todo || todo > 65 || todo > leninfo-4)
181                                                                 state=0;
182                                                         else
183                                                         {
184                                                                 ++state;
185                                                                 todo-=2;
186                                                                 msgPtr=0;
187                                                         }
188                                                         break;
189                                                 case 9: // Radio Text Status bit:
190                                                         // 0   = AB-flagcontrol
191                                                         // 1-4 = Transmission-Number
192                                                         // 5-6 = Buffer-Config
193                                                         ++state; // ignore ...
194                                                         break;
195                                                 case 10:
196         // TODO build a complete radiotext charcode to UTF8 conversion table for all character > 0x80
197                                                         switch (c)
198                                                         {
199                                                                 case 0 ... 0x7f: break;
200                                                                 case 0x8d: c='ß'; break;
201                                                                 case 0x91: c='ä'; break;
202                                                                 case 0xd1: c='Ä'; break;
203                                                                 case 0x97: c='ö'; break;
204                                                                 case 0xd7: c='Ö'; break;
205                                                                 case 0x99: c='ü'; break;
206                                                                 case 0xd9: c='Ü'; break;
207                                                                 default: c=' '; break;  // convert all unknown to space
208                                                         }
209                                                         message[msgPtr++]=c;
210                                                         if(todo)
211                                                                 --todo;
212                                                         else
213                                                                 ++state;
214                                                         break;
215                                                 case 11:
216                                                         crc16=c<<8;
217                                                         ++state;
218                                                         break;
219                                                 case 12:
220                                                         crc16|=c;
221                                                         message[msgPtr--]=0;
222                                                         while(message[msgPtr] == ' ' && msgPtr > 0)
223                                                                 message[msgPtr--] = 0;
224                                                         if ( crc16 == (crc^0xFFFF) )
225                                                         {
226                                                                 eDebug("radiotext: (%s)", message);
227                                                                 /*emit*/ m_updated_radiotext();
228                                                         }
229                                                         else
230                                                                 eDebug("invalid radiotext crc (%s)", message);
231                                                         state=0;
232                                                         break;
233                                         }
234                                 }
235                                 p1=ptr;
236                                 p2=-1;
237                         }
238                         ++ptr;
239                 }
240                 if (p1 != -1 && (128-p1) != 128)
241                 {
242                         bytesread=ptr=128-p1;
243                         memcpy(buf, buf+p1, ptr);
244                         p1=0;
245                 }
246                 else
247                         bytesread=ptr=0;
248         }
249 }
250
251 int eDVBRadioTextParser::start(int pid)
252 {
253         if (m_pes_reader)
254                 return m_pes_reader->start(pid);
255         else
256                 return -1;
257 }
258