1 #include <lib/base/eerror.h>
2 #include <lib/dvb/radiotext.h>
3 #include <lib/dvb/idemux.h>
4 #include <lib/gdi/gpixmap.h>
6 DEFINE_REF(eDVBRadioTextParser);
8 eDVBRadioTextParser::eDVBRadioTextParser(iDVBDemux *demux)
9 :bytesread(0), ptr(0), p1(-1), p2(-1), msgPtr(0), state(0)
12 setStreamID(0xC0, 0xC0);
14 if (demux->createPESReader(eApp, m_pes_reader))
15 eDebug("failed to create PES reader!");
17 m_pes_reader->connectRead(slot(*this, &eDVBRadioTextParser::processData), m_read_connection);
18 CONNECT(m_abortTimer.timeout, eDVBRadioTextParser::abortNonAvail);
21 #define SWAP(x) ((x<<8)|(x>>8))
22 #define LO(x) (x&0xFF)
24 static inline unsigned short crc_ccitt_byte( unsigned short crc, unsigned char c )
27 crc = crc ^ (LO(crc) >> 4);
28 crc = crc ^ (SWAP(LO(crc)) << 4) ^ (LO(crc) << 5);
32 static int bitrate[3][3][16] = {
35 {-1,8000,16000,24000,32000,40000,48000,56000,64000,80000,96000,112000,128000,144000,160000,0},
37 {-1,8000,16000,24000,32000,40000,48000,56000,64000,80000,96000,112000,128000,144000,160000,0},
39 {-1,32000,48000,56000,64000,80000,96000,112000,128000,144000,160000,176000,192000,224000,256000,0}
43 {-1,32000,40000,48000,56000,64000,80000,96000,112000,128000,160000,192000,224000,256000,320000,0},
45 {-1,32000,48000,56000,64000,80000,96000,112000,128000,160000,192000,224000,256000,320000,384000,0},
47 {-1,32000,64000,96000,128000,160000,192000,224000,256000,288000,320000,352000,384000,416000,448000,0}
51 {-1,6000,8000,10000,12000,16000,20000,24000,28000,320000,40000,48000,56000,64000,80000,0},
53 {-1,6000,8000,10000,12000,16000,20000,24000,28000,320000,40000,48000,56000,64000,80000,0},
55 {-1,8000,12000,16000,20000,24000,32000,40000,48000,560000,64000,80000,96000,112000,128000,0}
59 static int frequency[3][4] = {
60 // MPEG2 - 22.05, 24, 16khz
61 { 22050,24000,16000,0 },
62 // MPEG1 - 44.1, 48, 32khz
63 { 44100,48000,32000,0 },
64 // MPEG2.5 - 11.025, 12, 8khz
65 { 11025,12000,8000,0 }
68 void eDVBRadioTextParser::connectUpdatedRadiotext(const Slot0<void> &slot, ePtr<eConnection> &connection)
70 connection = new eConnection(this, m_updated_radiotext.connect(slot));
73 void eDVBRadioTextParser::processPESPacket(__u8 *data, int len)
75 int pos=9+data[8];// skip pes header
79 if ((0xFF & data[pos]) != 0xFF || (0xF0 & data[pos + 1]) != 0xF0)
82 int padding_bit = (data[pos + 2]>>1) & 1;
83 int mode = (data[pos + 3]>>6) & 3;
84 int channel = mode == 3 ? 1 : 2;
85 int id = (data[pos + 1] >> 3) & 1;
86 int emphasis_bit = data[pos + 3] & 3;
87 int protection_bit = data[pos + 1] & 1;
92 if (emphasis_bit == 2 && id == 1 )
95 if ((layer = (data[pos + 1]>>1) & 3) < 1)
98 if ((rate = bitrate[id][layer - 1][(data[pos + 2]>>4) & 0xf]) < 1)
101 if ((sample_freq = frequency[id][(data[pos + 2]>>2) & 3]) == 0)
104 if (id == 1 && layer == 2)
106 if (rate / channel < 32000)
108 if (rate / channel > 192000)
112 int frame_size = layer < 3 ?
113 (144 * rate / sample_freq) + padding_bit :
114 ((12 * rate / sample_freq) * 4) + (4 * padding_bit);
119 // eDebug("protection_bit ? %d", protection_bit);
120 // int offs = protection_bit ? pos - 1 : pos - 3;
121 // if (data[offs] != 0xFD)
123 // eDebug("%02x %02x %02x %02x %02x", data[offs-2], data[offs-1], data[offs], data[offs+1], data[offs+2]);
128 if (data[offs] == 0xFD)
131 int ancillary_len = 1 + data[offs - 1];
132 offs -= ancillary_len;
134 gotAncillaryByte(data[offs++]);
139 inline void eDVBRadioTextParser::gotAncillaryByte(__u8 data)
143 if ( bytesread == 128 )
147 if ( buf[ptr] == 0xFD )
154 if ( p1 != -1 && p2 != -1 )
159 unsigned char c = buf[--p2];
162 if ( state >= 1 && state < 11 )
163 crc = crc_ccitt_byte(crc, c);
168 if ( c==0xFE ) // Startkennung
171 case 1: // 10bit Site Address + 6bit Encoder Address
173 case 3: // Sequence Counter
181 if ( c==0x0A ) // message element code 0x0A Radio Text
186 case 6: // Data Set Number ... ignore
187 case 7: // Program Service Number ... ignore
190 case 8: // Message Element Length
192 if ( !todo || todo > 65 || todo > leninfo-4)
201 case 9: // Radio Text Status bit:
202 // 0 = AB-flagcontrol
203 // 1-4 = Transmission-Number
204 // 5-6 = Buffer-Config
205 ++state; // ignore ...
208 // TODO build a complete radiotext charcode to UTF8 conversion table for all character > 0x80
211 case 0 ... 0x7f: break;
212 case 0x8d: c='ß'; break;
213 case 0x91: c='ä'; break;
214 case 0xd1: c='Ä'; break;
215 case 0x97: c='ö'; break;
216 case 0xd7: c='Ö'; break;
217 case 0x99: c='ü'; break;
218 case 0xd9: c='Ü'; break;
219 default: c=' '; break; // convert all unknown to space
234 while(message[msgPtr] == ' ' && msgPtr > 0)
235 message[msgPtr--] = 0;
236 if ( crc16 == (crc^0xFFFF) )
238 eDebug("radiotext: (%s)", message);
239 /*emit*/ m_updated_radiotext();
242 eDebug("invalid radiotext crc (%s)", message);
252 if (p1 != -1 && (128-p1) != 128)
254 bytesread=ptr=128-p1;
255 memcpy(buf, buf+p1, ptr);
263 int eDVBRadioTextParser::start(int pid)
266 if (m_pes_reader && !(ret = m_pes_reader->start(pid)))
267 m_abortTimer.startLongTimer(20);
271 void eDVBRadioTextParser::abortNonAvail()
273 eDebug("no ancillary data in audio stream... abort radiotext pes parser");
275 m_pes_reader->stop();