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