Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3 | pmbaty | 1 | /* |
2 | SMPEG - SDL MPEG Player Library |
||
3 | Copyright (C) 1999 Loki Entertainment Software |
||
4 | |||
5 | - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr> for popcorn - |
||
6 | |||
7 | This library is free software; you can redistribute it and/or |
||
8 | modify it under the terms of the GNU Library General Public |
||
9 | License as published by the Free Software Foundation; either |
||
10 | version 2 of the License, or (at your option) any later version. |
||
11 | |||
12 | This library is distributed in the hope that it will be useful, |
||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
15 | Library General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU Library General Public |
||
18 | License along with this library; if not, write to the Free |
||
19 | Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
20 | */ |
||
21 | |||
22 | /* A class based on the MPEG stream class, used to parse and play audio */ |
||
23 | |||
24 | #ifndef _MPEGAUDIO_H_ |
||
25 | #define _MPEGAUDIO_H_ |
||
26 | |||
27 | #include "SDL.h" |
||
28 | #include "MPEGerror.h" |
||
29 | #include "MPEGaction.h" |
||
30 | |||
31 | #ifdef THREADED_AUDIO |
||
32 | #include "MPEGring.h" |
||
33 | #endif |
||
34 | |||
35 | void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len); |
||
36 | #ifdef THREADED_AUDIO |
||
37 | int Decode_MPEGaudio(void *udata); |
||
38 | #endif |
||
39 | |||
40 | class MPEGstream; |
||
41 | |||
42 | /* MPEG/WAVE Sound library |
||
43 | (C) 1997 by Woo-jae Jung */ |
||
44 | |||
45 | /**************************/ |
||
46 | /* Define values for MPEG */ |
||
47 | /**************************/ |
||
48 | #define SCALEBLOCK 12 |
||
49 | #define CALCBUFFERSIZE 512 |
||
50 | #define MAXSUBBAND 32 |
||
51 | #define MAXCHANNEL 2 |
||
52 | #define MAXTABLE 2 |
||
53 | #define SCALE 32768 |
||
54 | #define MAXSCALE (SCALE-1) |
||
55 | #define MINSCALE (-SCALE) |
||
56 | #define RAWDATASIZE (2*2*32*SSLIMIT) |
||
57 | |||
58 | #define LS 0 |
||
59 | #define RS 1 |
||
60 | |||
61 | #define SSLIMIT 18 |
||
62 | #define SBLIMIT 32 |
||
63 | |||
64 | #define WINDOWSIZE 4096 |
||
65 | |||
66 | // Huffmancode |
||
67 | #define HTN 34 |
||
68 | |||
69 | /********************/ |
||
70 | /* Type definitions */ |
||
71 | /********************/ |
||
72 | typedef float REAL; |
||
73 | |||
74 | typedef struct |
||
75 | { |
||
76 | bool generalflag; |
||
77 | unsigned int part2_3_length; |
||
78 | unsigned int big_values; |
||
79 | unsigned int global_gain; |
||
80 | unsigned int scalefac_compress; |
||
81 | unsigned int window_switching_flag; |
||
82 | unsigned int block_type; |
||
83 | unsigned int mixed_block_flag; |
||
84 | unsigned int table_select[3]; |
||
85 | unsigned int subblock_gain[3]; |
||
86 | unsigned int region0_count; |
||
87 | unsigned int region1_count; |
||
88 | unsigned int preflag; |
||
89 | unsigned int scalefac_scale; |
||
90 | unsigned int count1table_select; |
||
91 | }layer3grinfo; |
||
92 | |||
93 | typedef struct |
||
94 | { |
||
95 | unsigned main_data_begin; |
||
96 | unsigned private_bits; |
||
97 | struct |
||
98 | { |
||
99 | unsigned scfsi[4]; |
||
100 | layer3grinfo gr[2]; |
||
101 | }ch[2]; |
||
102 | }layer3sideinfo; |
||
103 | |||
104 | typedef struct |
||
105 | { |
||
106 | int l[23]; /* [cb] */ |
||
107 | int s[3][13]; /* [window][cb] */ |
||
108 | }layer3scalefactor; /* [ch] */ |
||
109 | |||
110 | typedef struct |
||
111 | { |
||
112 | int tablename; |
||
113 | unsigned int xlen,ylen; |
||
114 | unsigned int linbits; |
||
115 | unsigned int treelen; |
||
116 | const unsigned int (*val)[2]; |
||
117 | }HUFFMANCODETABLE; |
||
118 | |||
119 | |||
120 | // Class for Mpeg layer3 |
||
121 | class Mpegbitwindow |
||
122 | { |
||
123 | public: |
||
124 | Mpegbitwindow(){bitindex=point=0;}; |
||
125 | |||
126 | void initialize(void) {bitindex=point=0;}; |
||
127 | int gettotalbit(void) const {return bitindex;}; |
||
128 | void putbyte(int c) {buffer[point&(WINDOWSIZE-1)]=c;point++;}; |
||
129 | void wrap(void); |
||
130 | void rewind(int bits) {bitindex-=bits;}; |
||
131 | void forward(int bits) {bitindex+=bits;}; |
||
132 | int getbit(void) { |
||
133 | register int r=(buffer[bitindex>>3]>>(7-(bitindex&7)))&1; |
||
134 | bitindex++; |
||
135 | return r; |
||
136 | } |
||
137 | int getbits9(int bits) |
||
138 | { |
||
139 | register unsigned short a; |
||
140 | { int offset=bitindex>>3; |
||
141 | |||
142 | a=(((unsigned char)buffer[offset])<<8) | ((unsigned char)buffer[offset+1]); |
||
143 | } |
||
144 | a<<=(bitindex&7); |
||
145 | bitindex+=bits; |
||
146 | return (int)((unsigned int)(a>>(16-bits))); |
||
147 | } |
||
148 | int getbits(int bits); |
||
149 | |||
150 | private: |
||
151 | int point,bitindex; |
||
152 | char buffer[2*WINDOWSIZE]; |
||
153 | }; |
||
154 | |||
155 | /* The actual MPEG audio class */ |
||
156 | class MPEGaudio : public MPEGerror, public MPEGaudioaction { |
||
157 | |||
158 | public: |
||
159 | MPEGaudio(MPEGstream *stream, bool initSDL = true); |
||
160 | virtual ~MPEGaudio(); |
||
161 | |||
162 | /* MPEG actions */ |
||
163 | bool GetAudioInfo(MPEG_AudioInfo *info); |
||
164 | double Time(void); |
||
165 | void Play(void); |
||
166 | void Stop(void); |
||
167 | void Rewind(void); |
||
168 | void ResetSynchro(double time); |
||
169 | void Skip(float seconds); |
||
170 | void Volume(int vol); |
||
171 | /* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name in popcorn */ |
||
172 | MPEGstatus GetStatus(void); |
||
173 | |||
174 | /* Returns the desired SDL audio spec for this stream */ |
||
175 | bool WantedSpec(SDL_AudioSpec *wanted); |
||
176 | |||
177 | /* Inform SMPEG of the actual audio format if configuring SDL |
||
178 | outside of this class */ |
||
179 | void ActualSpec(SDL_AudioSpec *actual); |
||
180 | |||
181 | protected: |
||
182 | bool sdl_audio; |
||
183 | MPEGstream *mpeg; |
||
184 | int valid_stream; |
||
185 | bool stereo; |
||
186 | double rate_in_s; |
||
187 | Uint32 frags_playing; |
||
188 | Uint32 frag_time; |
||
189 | #ifdef THREADED_AUDIO |
||
190 | bool decoding; |
||
191 | SDL_Thread *decode_thread; |
||
192 | |||
193 | void StartDecoding(void); |
||
194 | void StopDecoding(void); |
||
195 | #endif |
||
196 | |||
197 | /* Code from splay 1.8.2 */ |
||
198 | |||
199 | /*****************************/ |
||
200 | /* Constant tables for layer */ |
||
201 | /*****************************/ |
||
202 | private: |
||
203 | static const int bitrate[2][3][15],frequencies[2][3]; |
||
204 | static const REAL scalefactorstable[64]; |
||
205 | static const HUFFMANCODETABLE ht[HTN]; |
||
206 | static const REAL filter[512]; |
||
207 | static REAL hcos_64[16],hcos_32[8],hcos_16[4],hcos_8[2],hcos_4; |
||
208 | |||
209 | /*************************/ |
||
210 | /* MPEG header variables */ |
||
211 | /*************************/ |
||
212 | private: |
||
213 | int last_speed; |
||
214 | int layer,protection,bitrateindex,padding,extendedmode; |
||
215 | enum _mpegversion {mpeg1,mpeg2} version; |
||
216 | enum _mode {fullstereo,joint,dual,single} mode; |
||
217 | enum _frequency {frequency44100,frequency48000,frequency32000} frequency; |
||
218 | |||
219 | /***************************************/ |
||
220 | /* Interface for setting music quality */ |
||
221 | /***************************************/ |
||
222 | private: |
||
223 | bool forcetomonoflag; |
||
224 | bool forcetostereoflag; |
||
225 | bool swapendianflag; |
||
226 | int downfrequency; |
||
227 | |||
228 | public: |
||
229 | void setforcetomono(bool flag); |
||
230 | void setdownfrequency(int value); |
||
231 | |||
232 | /******************************/ |
||
233 | /* Frame management variables */ |
||
234 | /******************************/ |
||
235 | private: |
||
236 | int decodedframe,currentframe,totalframe; |
||
237 | |||
238 | /***************************************/ |
||
239 | /* Variables made by MPEG-Audio header */ |
||
240 | /***************************************/ |
||
241 | private: |
||
242 | int tableindex,channelbitrate; |
||
243 | int stereobound,subbandnumber,inputstereo,outputstereo; |
||
244 | REAL scalefactor; |
||
245 | int framesize; |
||
246 | |||
247 | /*******************/ |
||
248 | /* Mpegtoraw class */ |
||
249 | /*******************/ |
||
250 | public: |
||
251 | void initialize(); |
||
252 | bool run(int frames, double *timestamp = NULL); |
||
253 | void clearbuffer(void); |
||
254 | |||
255 | /*****************************/ |
||
256 | /* Loading MPEG-Audio stream */ |
||
257 | /*****************************/ |
||
258 | private: |
||
259 | Uint8 _buffer[4096]; |
||
260 | Uint32 _buffer_pos; |
||
261 | int bitindex; |
||
262 | bool fillbuffer(int size); |
||
263 | void sync(void); |
||
264 | bool issync(void); |
||
265 | int getbyte(void); |
||
266 | int getbit(void); |
||
267 | int getbits8(void); |
||
268 | int getbits9(int bits); |
||
269 | int getbits(int bits); |
||
270 | |||
271 | |||
272 | /********************/ |
||
273 | /* Global variables */ |
||
274 | /********************/ |
||
275 | private: |
||
276 | int lastfrequency,laststereo; |
||
277 | |||
278 | // for Layer3 |
||
279 | int layer3slots,layer3framestart,layer3part2start; |
||
280 | REAL prevblck[2][2][SBLIMIT][SSLIMIT]; |
||
281 | int currentprevblock; |
||
282 | layer3sideinfo sideinfo; |
||
283 | layer3scalefactor scalefactors[2]; |
||
284 | |||
285 | Mpegbitwindow bitwindow; |
||
286 | int wgetbit (void) {return bitwindow.getbit (); } |
||
287 | int wgetbits9(int bits){return bitwindow.getbits9(bits);} |
||
288 | int wgetbits (int bits){return bitwindow.getbits (bits);} |
||
289 | |||
290 | |||
291 | /*************************************/ |
||
292 | /* Decoding functions for each layer */ |
||
293 | /*************************************/ |
||
294 | private: |
||
295 | bool loadheader(void); |
||
296 | |||
297 | // |
||
298 | // Subbandsynthesis |
||
299 | // |
||
300 | REAL calcbufferL[2][CALCBUFFERSIZE],calcbufferR[2][CALCBUFFERSIZE]; |
||
301 | int currentcalcbuffer,calcbufferoffset; |
||
302 | |||
303 | void computebuffer(REAL *fraction,REAL buffer[2][CALCBUFFERSIZE]); |
||
304 | void generatesingle(void); |
||
305 | void generate(void); |
||
306 | void subbandsynthesis(REAL *fractionL,REAL *fractionR); |
||
307 | |||
308 | void computebuffer_2(REAL *fraction,REAL buffer[2][CALCBUFFERSIZE]); |
||
309 | void generatesingle_2(void); |
||
310 | void generate_2(void); |
||
311 | void subbandsynthesis_2(REAL *fractionL,REAL *fractionR); |
||
312 | |||
313 | // Extarctor |
||
314 | void extractlayer1(void); // MPEG-1 |
||
315 | void extractlayer2(void); |
||
316 | void extractlayer3(void); |
||
317 | void extractlayer3_2(void); // MPEG-2 |
||
318 | |||
319 | |||
320 | // Functions for layer 3 |
||
321 | void layer3initialize(void); |
||
322 | bool layer3getsideinfo(void); |
||
323 | bool layer3getsideinfo_2(void); |
||
324 | void layer3getscalefactors(int ch,int gr); |
||
325 | void layer3getscalefactors_2(int ch); |
||
326 | void layer3huffmandecode(int ch,int gr,int out[SBLIMIT][SSLIMIT]); |
||
327 | REAL layer3twopow2(int scale,int preflag,int pretab_offset,int l); |
||
328 | REAL layer3twopow2_1(int a,int b,int c); |
||
329 | void layer3dequantizesample(int ch,int gr,int in[SBLIMIT][SSLIMIT], |
||
330 | REAL out[SBLIMIT][SSLIMIT]); |
||
331 | void layer3fixtostereo(int gr,REAL in[2][SBLIMIT][SSLIMIT]); |
||
332 | void layer3reorderandantialias(int ch,int gr,REAL in[SBLIMIT][SSLIMIT], |
||
333 | REAL out[SBLIMIT][SSLIMIT]); |
||
334 | |||
335 | void layer3hybrid(int ch,int gr,REAL in[SBLIMIT][SSLIMIT], |
||
336 | REAL out[SSLIMIT][SBLIMIT]); |
||
337 | |||
338 | void huffmandecoder_1(const HUFFMANCODETABLE *h,int *x,int *y); |
||
339 | void huffmandecoder_2(const HUFFMANCODETABLE *h,int *x,int *y,int *v,int *w); |
||
340 | |||
341 | /********************/ |
||
342 | /* Playing raw data */ |
||
343 | /********************/ |
||
344 | private: |
||
345 | int samplesperframe; |
||
346 | int rawdatareadoffset, rawdatawriteoffset; |
||
347 | Sint16 *rawdata; |
||
348 | #ifdef THREADED_AUDIO |
||
349 | MPEG_ring *ring; |
||
350 | #else |
||
351 | Sint16 spillover[ RAWDATASIZE ]; |
||
352 | #endif |
||
353 | int volume; |
||
354 | |||
355 | void clearrawdata(void) { |
||
356 | rawdatareadoffset=0; |
||
357 | rawdatawriteoffset=0; |
||
358 | rawdata=NULL; |
||
359 | } |
||
360 | void putraw(short int pcm) {rawdata[rawdatawriteoffset++]=pcm;} |
||
361 | |||
362 | /********************/ |
||
363 | /* Timestamp sync */ |
||
364 | /********************/ |
||
365 | public: |
||
366 | #define N_TIMESTAMPS 5 |
||
367 | |||
368 | double timestamp[N_TIMESTAMPS]; |
||
369 | |||
370 | /* Functions which access MPEGaudio internals */ |
||
371 | friend void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len); |
||
372 | friend int Play_MPEGaudio(MPEGaudio *audio, Uint8 *stream, int len); |
||
373 | #ifdef THREADED_AUDIO |
||
374 | friend int Decode_MPEGaudio(void *udata); |
||
375 | #endif |
||
376 | }; |
||
377 | |||
378 | /* Need to duplicate the prototypes, this is not a typo :) */ |
||
379 | void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len); |
||
380 | int Play_MPEGaudio(MPEGaudio *audio, Uint8 *stream, int len); |
||
381 | #ifdef THREADED_AUDIO |
||
382 | int Decode_MPEGaudio(void *udata); |
||
383 | #endif |
||
384 | |||
385 | #endif /* _MPEGAUDIO_H_ */ |