diff options
author | Dave Chapman <dave@dchapman.com> | 2002-05-12 12:52:15 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2002-05-12 12:52:15 +0000 |
commit | 87758d84e6d5ca128cf3a48a09e1c57092148579 (patch) | |
tree | 023017cbe1d398e91336318d59203bbd6dc6cd95 /uisimulator/common | |
parent | ef5f97b4216042121a114afd5a9f1380283fb095 (diff) | |
download | rockbox-87758d84e6d5ca128cf3a48a09e1c57092148579.tar.gz rockbox-87758d84e6d5ca128cf3a48a09e1c57092148579.zip |
moved mpeg decoder to common
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@554 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'uisimulator/common')
-rw-r--r-- | uisimulator/common/mpegplay.c | 328 | ||||
-rw-r--r-- | uisimulator/common/mpegplay.h | 23 |
2 files changed, 351 insertions, 0 deletions
diff --git a/uisimulator/common/mpegplay.c b/uisimulator/common/mpegplay.c new file mode 100644 index 0000000000..da02ec9de4 --- /dev/null +++ b/uisimulator/common/mpegplay.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2002 Dave Chapman | ||
10 | * | ||
11 | * This file contains significant code from two other projects: | ||
12 | * | ||
13 | * 1) madldd - a sample application to use libmad | ||
14 | * 2) CoolPlayer - a win32 audio player that also uses libmad | ||
15 | * | ||
16 | * All files in this archive are subject to the GNU General Public License. | ||
17 | * See the file COPYING in the source tree root for full license agreement. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #ifdef MPEG_PLAY | ||
25 | |||
26 | #include <string.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <file.h> | ||
29 | #include <types.h> | ||
30 | #include <lcd.h> | ||
31 | #include <button.h> | ||
32 | #include "id3.h" | ||
33 | |||
34 | #include <stdio.h> | ||
35 | #include <mad.h> | ||
36 | |||
37 | #include "oss_sound.h" | ||
38 | |||
39 | /* The "dither" code to convert the 24-bit samples produced by libmad was | ||
40 | taken from the coolplayer project - coolplayer.sourceforge.net */ | ||
41 | |||
42 | struct dither { | ||
43 | mad_fixed_t error[3]; | ||
44 | mad_fixed_t random; | ||
45 | }; | ||
46 | # define SAMPLE_DEPTH 16 | ||
47 | # define scale(x, y) dither((x), (y)) | ||
48 | |||
49 | struct mad_stream Stream; | ||
50 | struct mad_frame Frame; | ||
51 | struct mad_synth Synth; | ||
52 | mad_timer_t Timer; | ||
53 | |||
54 | /* | ||
55 | * NAME: prng() | ||
56 | * DESCRIPTION: 32-bit pseudo-random number generator | ||
57 | */ | ||
58 | static __inline | ||
59 | unsigned long prng(unsigned long state) | ||
60 | { | ||
61 | return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * NAME: dither() | ||
66 | * DESCRIPTION: dither and scale sample | ||
67 | */ | ||
68 | static __inline | ||
69 | signed int dither(mad_fixed_t sample, struct dither *dither) | ||
70 | { | ||
71 | unsigned int scalebits; | ||
72 | mad_fixed_t output, mask, random; | ||
73 | |||
74 | enum { | ||
75 | MIN = -MAD_F_ONE, | ||
76 | MAX = MAD_F_ONE - 1 | ||
77 | }; | ||
78 | |||
79 | /* noise shape */ | ||
80 | sample += dither->error[0] - dither->error[1] + dither->error[2]; | ||
81 | |||
82 | dither->error[2] = dither->error[1]; | ||
83 | dither->error[1] = dither->error[0] / 2; | ||
84 | |||
85 | /* bias */ | ||
86 | output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1)); | ||
87 | |||
88 | scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH; | ||
89 | mask = (1L << scalebits) - 1; | ||
90 | |||
91 | /* dither */ | ||
92 | random = prng(dither->random); | ||
93 | output += (random & mask) - (dither->random & mask); | ||
94 | |||
95 | dither->random = random; | ||
96 | |||
97 | /* clip */ | ||
98 | if (output > MAX) { | ||
99 | output = MAX; | ||
100 | |||
101 | if (sample > MAX) | ||
102 | sample = MAX; | ||
103 | } | ||
104 | else if (output < MIN) { | ||
105 | output = MIN; | ||
106 | |||
107 | if (sample < MIN) | ||
108 | sample = MIN; | ||
109 | } | ||
110 | |||
111 | /* quantize */ | ||
112 | output &= ~mask; | ||
113 | |||
114 | /* error feedback */ | ||
115 | dither->error[0] = sample - output; | ||
116 | |||
117 | /* scale */ | ||
118 | return output >> scalebits; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * NAME: pack_pcm() | ||
123 | * DESCRIPTION: scale and dither MAD output | ||
124 | */ | ||
125 | static | ||
126 | void pack_pcm(unsigned char **pcm, unsigned int nsamples, | ||
127 | mad_fixed_t const *ch1, mad_fixed_t const *ch2) | ||
128 | { | ||
129 | register signed int s0, s1; | ||
130 | static struct dither d0, d1; | ||
131 | |||
132 | if (ch2) { /* stereo */ | ||
133 | while (nsamples--) { | ||
134 | s0 = scale(*ch1++, &d0); | ||
135 | s1 = scale(*ch2++, &d1); | ||
136 | # if SAMPLE_DEPTH == 16 | ||
137 | (*pcm)[0 + 0] = s0 >> 0; | ||
138 | (*pcm)[0 + 1] = s0 >> 8; | ||
139 | (*pcm)[2 + 0] = s1 >> 0; | ||
140 | (*pcm)[2 + 1] = s1 >> 8; | ||
141 | |||
142 | *pcm += 2 * 2; | ||
143 | # elif SAMPLE_DEPTH == 8 | ||
144 | (*pcm)[0] = s0 ^ 0x80; | ||
145 | (*pcm)[1] = s1 ^ 0x80; | ||
146 | |||
147 | *pcm += 2; | ||
148 | # else | ||
149 | # error "bad SAMPLE_DEPTH" | ||
150 | # endif | ||
151 | } | ||
152 | } | ||
153 | else { /* mono */ | ||
154 | while (nsamples--) { | ||
155 | s0 = scale(*ch1++, &d0); | ||
156 | |||
157 | # if SAMPLE_DEPTH == 16 | ||
158 | (*pcm)[0] = s0 >> 0; | ||
159 | (*pcm)[1] = s0 >> 8; | ||
160 | |||
161 | *pcm += 2; | ||
162 | # elif SAMPLE_DEPTH == 8 | ||
163 | *(*pcm)++ = s0 ^ 0x80; | ||
164 | # endif | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | #define INPUT_BUFFER_SIZE (5*8192) | ||
170 | #define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */ | ||
171 | int mpeg_play(char* fname) | ||
172 | { | ||
173 | unsigned char InputBuffer[INPUT_BUFFER_SIZE], | ||
174 | OutputBuffer[OUTPUT_BUFFER_SIZE], | ||
175 | *OutputPtr=OutputBuffer; | ||
176 | const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE; | ||
177 | int Status=0, | ||
178 | i; | ||
179 | unsigned long FrameCount=0; | ||
180 | sound_t sound; | ||
181 | int fd; | ||
182 | mp3entry mp3; | ||
183 | register signed int s0, s1; | ||
184 | static struct dither d0, d1; | ||
185 | |||
186 | mp3info(&mp3, fname); | ||
187 | |||
188 | init_sound(&sound); | ||
189 | |||
190 | /* Configure sound device for this file - always select Stereo because | ||
191 | some sound cards don't support mono */ | ||
192 | config_sound(&sound,mp3.frequency,2); | ||
193 | |||
194 | fd=x11_open(fname,O_RDONLY); | ||
195 | if (fd < 0) { | ||
196 | fprintf(stderr,"could not open %s\n",fname); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | /* First the structures used by libmad must be initialized. */ | ||
201 | mad_stream_init(&Stream); | ||
202 | mad_frame_init(&Frame); | ||
203 | mad_synth_init(&Synth); | ||
204 | mad_timer_reset(&Timer); | ||
205 | |||
206 | do | ||
207 | { | ||
208 | if (button_get()) break; /* Return if a key is pressed */ | ||
209 | |||
210 | if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) | ||
211 | { | ||
212 | size_t ReadSize,Remaining; | ||
213 | unsigned char *ReadStart; | ||
214 | |||
215 | if(Stream.next_frame!=NULL) | ||
216 | { | ||
217 | Remaining=Stream.bufend-Stream.next_frame; | ||
218 | memmove(InputBuffer,Stream.next_frame,Remaining); | ||
219 | ReadStart=InputBuffer+Remaining; | ||
220 | ReadSize=INPUT_BUFFER_SIZE-Remaining; | ||
221 | } | ||
222 | else | ||
223 | ReadSize=INPUT_BUFFER_SIZE, | ||
224 | ReadStart=InputBuffer, | ||
225 | Remaining=0; | ||
226 | |||
227 | ReadSize=read(fd,ReadStart,ReadSize); | ||
228 | if(ReadSize<=0) | ||
229 | { | ||
230 | fprintf(stderr,"end of input stream\n"); | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining); | ||
235 | Stream.error=0; | ||
236 | } | ||
237 | |||
238 | if(mad_frame_decode(&Frame,&Stream)) { | ||
239 | if(MAD_RECOVERABLE(Stream.error)) | ||
240 | { | ||
241 | fprintf(stderr,"recoverable frame level error\n"); | ||
242 | fflush(stderr); | ||
243 | continue; | ||
244 | } | ||
245 | else | ||
246 | if(Stream.error==MAD_ERROR_BUFLEN) { | ||
247 | continue; | ||
248 | } else { | ||
249 | fprintf(stderr,"unrecoverable frame level error\n"); | ||
250 | Status=1; | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | FrameCount++; | ||
256 | mad_timer_add(&Timer,Frame.header.duration); | ||
257 | |||
258 | mad_synth_frame(&Synth,&Frame); | ||
259 | |||
260 | for(i=0;i<Synth.pcm.length;i++) | ||
261 | { | ||
262 | unsigned short Sample; | ||
263 | |||
264 | /* Left channel */ | ||
265 | Sample=scale(Synth.pcm.samples[0][i],&d0); | ||
266 | *(OutputPtr++)=Sample&0xff; | ||
267 | *(OutputPtr++)=Sample>>8; | ||
268 | |||
269 | /* Right channel. If the decoded stream is monophonic then | ||
270 | * the right output channel is the same as the left one. | ||
271 | */ | ||
272 | if(MAD_NCHANNELS(&Frame.header)==2) | ||
273 | Sample=scale(Synth.pcm.samples[1][i],&d0); | ||
274 | *(OutputPtr++)=Sample&0xff; | ||
275 | *(OutputPtr++)=Sample>>8; | ||
276 | |||
277 | /* Flush the buffer if it is full. */ | ||
278 | if(OutputPtr==OutputBufferEnd) | ||
279 | { | ||
280 | if(output_sound(&sound,OutputBuffer,OUTPUT_BUFFER_SIZE)!=OUTPUT_BUFFER_SIZE) | ||
281 | { | ||
282 | fprintf(stderr,"PCM write error.\n"); | ||
283 | Status=2; | ||
284 | break; | ||
285 | } | ||
286 | OutputPtr=OutputBuffer; | ||
287 | } | ||
288 | } | ||
289 | }while(1); | ||
290 | |||
291 | /* Mad is no longer used, the structures that were initialized must | ||
292 | * now be cleared. | ||
293 | */ | ||
294 | mad_synth_finish(&Synth); | ||
295 | mad_frame_finish(&Frame); | ||
296 | mad_stream_finish(&Stream); | ||
297 | |||
298 | /* If the output buffer is not empty and no error occured during | ||
299 | * the last write, then flush it. | ||
300 | */ | ||
301 | if(OutputPtr!=OutputBuffer && Status!=2) | ||
302 | { | ||
303 | size_t BufferSize=OutputPtr-OutputBuffer; | ||
304 | |||
305 | if(write(sound,OutputBuffer,1,BufferSize)!=BufferSize) | ||
306 | { | ||
307 | fprintf(stderr,"PCM write error\n"); | ||
308 | Status=2; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /* Accounting report if no error occured. */ | ||
313 | if(!Status) | ||
314 | { | ||
315 | char Buffer[80]; | ||
316 | |||
317 | mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u", | ||
318 | MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0); | ||
319 | fprintf(stderr,"%lu frames decoded (%s).\n",FrameCount,Buffer); | ||
320 | } | ||
321 | |||
322 | close_sound(&sound); | ||
323 | /* That's the end of the world (in the H. G. Wells way). */ | ||
324 | return(Status); | ||
325 | } | ||
326 | |||
327 | |||
328 | #endif | ||
diff --git a/uisimulator/common/mpegplay.h b/uisimulator/common/mpegplay.h new file mode 100644 index 0000000000..cde9fe183f --- /dev/null +++ b/uisimulator/common/mpegplay.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2002 Dave Chapman | ||
10 | * | ||
11 | * All files in this archive are subject to the GNU General Public License. | ||
12 | * See the file COPYING in the source tree root for full license agreement. | ||
13 | * | ||
14 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
15 | * KIND, either express or implied. | ||
16 | * | ||
17 | ****************************************************************************/ | ||
18 | |||
19 | #ifdef MPEG_PLAY | ||
20 | |||
21 | int mpeg_play(char* fname); | ||
22 | |||
23 | #endif | ||