diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/mpa.c | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) | |
download | rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.gz rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.zip |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/mpa.c')
-rw-r--r-- | lib/rbcodec/codecs/mpa.c | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/mpa.c b/lib/rbcodec/codecs/mpa.c new file mode 100644 index 0000000000..f9bf7e600f --- /dev/null +++ b/lib/rbcodec/codecs/mpa.c | |||
@@ -0,0 +1,521 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Dave Chapman | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "codeclib.h" | ||
23 | #include <codecs/libmad/mad.h> | ||
24 | #include <inttypes.h> | ||
25 | |||
26 | CODEC_HEADER | ||
27 | |||
28 | #if NUM_CORES > 1 && !defined(MPEGPLAYER) | ||
29 | #define MPA_SYNTH_ON_COP | ||
30 | #endif | ||
31 | |||
32 | static struct mad_stream stream IBSS_ATTR; | ||
33 | static struct mad_frame frame IBSS_ATTR; | ||
34 | static struct mad_synth synth IBSS_ATTR; | ||
35 | |||
36 | #ifdef MPA_SYNTH_ON_COP | ||
37 | static volatile short die IBSS_ATTR = 0; /*thread should die*/ | ||
38 | |||
39 | #if (CONFIG_CPU == PP5024) || (CONFIG_CPU == PP5022) | ||
40 | static mad_fixed_t sbsample_prev[2][36][32] IBSS_ATTR; | ||
41 | #else | ||
42 | static mad_fixed_t sbsample_prev[2][36][32] SHAREDBSS_ATTR; | ||
43 | #endif | ||
44 | |||
45 | static struct semaphore synth_done_sem IBSS_ATTR; | ||
46 | static struct semaphore synth_pending_sem IBSS_ATTR; | ||
47 | #endif | ||
48 | |||
49 | #define INPUT_CHUNK_SIZE 8192 | ||
50 | |||
51 | static mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR; | ||
52 | static mad_fixed_t sbsample[2][36][32] IBSS_ATTR; | ||
53 | |||
54 | static unsigned char mad_main_data[MAD_BUFFER_MDLEN] IBSS_ATTR; | ||
55 | /* TODO: what latency does layer 1 have? */ | ||
56 | static int mpeg_latency[3] = { 0, 481, 529 }; | ||
57 | static int mpeg_framesize[3] = {384, 1152, 1152}; | ||
58 | |||
59 | static void init_mad(void) | ||
60 | { | ||
61 | ci->memset(&stream, 0, sizeof(struct mad_stream)); | ||
62 | ci->memset(&frame , 0, sizeof(struct mad_frame)); | ||
63 | ci->memset(&synth , 0, sizeof(struct mad_synth)); | ||
64 | |||
65 | #ifdef MPA_SYNTH_ON_COP | ||
66 | frame.sbsample_prev = &sbsample_prev; | ||
67 | frame.sbsample = &sbsample; | ||
68 | #else | ||
69 | frame.sbsample_prev = &sbsample; | ||
70 | frame.sbsample = &sbsample; | ||
71 | #endif | ||
72 | |||
73 | /* We do this so libmad doesn't try to call codec_calloc(). This needs to | ||
74 | * be called before mad_stream_init(), mad_frame_inti() and | ||
75 | * mad_synth_init(). */ | ||
76 | frame.overlap = &mad_frame_overlap; | ||
77 | stream.main_data = &mad_main_data; | ||
78 | |||
79 | /* Call mad initialization. Those will zero the arrays frame.overlap, | ||
80 | * frame.sbsample and frame.sbsample_prev. Therefore there is no need to | ||
81 | * zero them here. */ | ||
82 | mad_stream_init(&stream); | ||
83 | mad_frame_init(&frame); | ||
84 | mad_synth_init(&synth); | ||
85 | } | ||
86 | |||
87 | static int get_file_pos(int newtime) | ||
88 | { | ||
89 | int pos = -1; | ||
90 | struct mp3entry *id3 = ci->id3; | ||
91 | |||
92 | if (id3->vbr) { | ||
93 | /* Convert newtime and id3->length to seconds to | ||
94 | * avoid overflow */ | ||
95 | unsigned int newtime_s = newtime/1000; | ||
96 | unsigned int length_s = id3->length/1000; | ||
97 | |||
98 | if (id3->has_toc) { | ||
99 | /* Use the TOC to find the new position */ | ||
100 | unsigned int percent, remainder; | ||
101 | int curtoc, nexttoc, plen; | ||
102 | |||
103 | percent = (newtime_s*100) / length_s; | ||
104 | if (percent > 99) | ||
105 | percent = 99; | ||
106 | |||
107 | curtoc = id3->toc[percent]; | ||
108 | |||
109 | if (percent < 99) { | ||
110 | nexttoc = id3->toc[percent+1]; | ||
111 | } else { | ||
112 | nexttoc = 256; | ||
113 | } | ||
114 | |||
115 | pos = (id3->filesize/256)*curtoc; | ||
116 | |||
117 | /* Use the remainder to get a more accurate position */ | ||
118 | remainder = (newtime_s*100) % length_s; | ||
119 | remainder = (remainder*100) / length_s; | ||
120 | plen = (nexttoc - curtoc)*(id3->filesize/256); | ||
121 | pos += (plen/100)*remainder; | ||
122 | } else { | ||
123 | /* No TOC exists, estimate the new position */ | ||
124 | pos = (id3->filesize / length_s) * newtime_s; | ||
125 | } | ||
126 | } else if (id3->bitrate) { | ||
127 | pos = newtime * (id3->bitrate / 8); | ||
128 | } else { | ||
129 | return -1; | ||
130 | } | ||
131 | |||
132 | /* Don't seek right to the end of the file so that we can | ||
133 | transition properly to the next song */ | ||
134 | if (pos >= (int)(id3->filesize - id3->id3v1len)) | ||
135 | pos = id3->filesize - id3->id3v1len - 1; | ||
136 | |||
137 | /* id3->filesize excludes id3->first_frame_offset, so add it now */ | ||
138 | pos += id3->first_frame_offset; | ||
139 | |||
140 | return pos; | ||
141 | } | ||
142 | |||
143 | static void set_elapsed(struct mp3entry* id3) | ||
144 | { | ||
145 | unsigned long offset = id3->offset > id3->first_frame_offset ? | ||
146 | id3->offset - id3->first_frame_offset : 0; | ||
147 | unsigned long elapsed = id3->elapsed; | ||
148 | |||
149 | if ( id3->vbr ) { | ||
150 | if ( id3->has_toc ) { | ||
151 | /* calculate elapsed time using TOC */ | ||
152 | int i; | ||
153 | unsigned int remainder, plen, relpos, nextpos; | ||
154 | |||
155 | /* find wich percent we're at */ | ||
156 | for (i=0; i<100; i++ ) | ||
157 | if ( offset < id3->toc[i] * (id3->filesize / 256) ) | ||
158 | break; | ||
159 | |||
160 | i--; | ||
161 | if (i < 0) | ||
162 | i = 0; | ||
163 | |||
164 | relpos = id3->toc[i]; | ||
165 | |||
166 | if (i < 99) | ||
167 | nextpos = id3->toc[i+1]; | ||
168 | else | ||
169 | nextpos = 256; | ||
170 | |||
171 | remainder = offset - (relpos * (id3->filesize / 256)); | ||
172 | |||
173 | /* set time for this percent (divide before multiply to prevent | ||
174 | overflow on long files. loss of precision is negligible on | ||
175 | short files) */ | ||
176 | elapsed = i * (id3->length / 100); | ||
177 | |||
178 | /* calculate remainder time */ | ||
179 | plen = (nextpos - relpos) * (id3->filesize / 256); | ||
180 | elapsed += (((remainder * 100) / plen) * (id3->length / 10000)); | ||
181 | } | ||
182 | else { | ||
183 | /* no TOC exists. set a rough estimate using average bitrate */ | ||
184 | int tpk = id3->length / | ||
185 | ((id3->filesize - id3->first_frame_offset - id3->id3v1len) / | ||
186 | 1024); | ||
187 | elapsed = offset / 1024 * tpk; | ||
188 | } | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | /* constant bitrate, use exact calculation */ | ||
193 | if (id3->bitrate != 0) | ||
194 | elapsed = offset / (id3->bitrate / 8); | ||
195 | } | ||
196 | |||
197 | ci->set_elapsed(elapsed); | ||
198 | } | ||
199 | |||
200 | #ifdef MPA_SYNTH_ON_COP | ||
201 | |||
202 | /* | ||
203 | * Run the synthesis filter on the COProcessor | ||
204 | */ | ||
205 | |||
206 | static int mad_synth_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)] IBSS_ATTR; | ||
207 | |||
208 | static const unsigned char * const mad_synth_thread_name = "mp3dec"; | ||
209 | static unsigned int mad_synth_thread_id = 0; | ||
210 | |||
211 | |||
212 | static void mad_synth_thread(void) | ||
213 | { | ||
214 | while(1) { | ||
215 | ci->semaphore_release(&synth_done_sem); | ||
216 | ci->semaphore_wait(&synth_pending_sem, TIMEOUT_BLOCK); | ||
217 | |||
218 | if(die) | ||
219 | break; | ||
220 | |||
221 | mad_synth_frame(&synth, &frame); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /* wait for the synth thread to go idle which indicates a PCM frame has been | ||
226 | * synthesized */ | ||
227 | static inline void mad_synth_thread_wait_pcm(void) | ||
228 | { | ||
229 | ci->semaphore_wait(&synth_done_sem, TIMEOUT_BLOCK); | ||
230 | } | ||
231 | |||
232 | /* increment the done semaphore - used after a wait for idle to preserve the | ||
233 | * semaphore count */ | ||
234 | static inline void mad_synth_thread_unwait_pcm(void) | ||
235 | { | ||
236 | ci->semaphore_release(&synth_done_sem); | ||
237 | } | ||
238 | |||
239 | /* after synth thread has gone idle - switch decoded frames and commence | ||
240 | * synthesis on it */ | ||
241 | static void mad_synth_thread_ready(void) | ||
242 | { | ||
243 | mad_fixed_t (*temp)[2][36][32]; | ||
244 | |||
245 | /*circular buffer that holds 2 frames' samples*/ | ||
246 | temp=frame.sbsample; | ||
247 | frame.sbsample = frame.sbsample_prev; | ||
248 | frame.sbsample_prev=temp; | ||
249 | |||
250 | ci->semaphore_release(&synth_pending_sem); | ||
251 | } | ||
252 | |||
253 | static bool mad_synth_thread_create(void) | ||
254 | { | ||
255 | ci->semaphore_init(&synth_done_sem, 1, 0); | ||
256 | ci->semaphore_init(&synth_pending_sem, 1, 0); | ||
257 | |||
258 | mad_synth_thread_id = ci->create_thread(mad_synth_thread, | ||
259 | mad_synth_thread_stack, | ||
260 | sizeof(mad_synth_thread_stack), 0, | ||
261 | mad_synth_thread_name | ||
262 | IF_PRIO(, PRIORITY_PLAYBACK) | ||
263 | IF_COP(, COP)); | ||
264 | |||
265 | if (mad_synth_thread_id == 0) | ||
266 | return false; | ||
267 | |||
268 | return true; | ||
269 | } | ||
270 | |||
271 | static void mad_synth_thread_quit(void) | ||
272 | { | ||
273 | /* mop up COP thread */ | ||
274 | die = 1; | ||
275 | ci->semaphore_release(&synth_pending_sem); | ||
276 | ci->thread_wait(mad_synth_thread_id); | ||
277 | ci->commit_discard_dcache(); | ||
278 | } | ||
279 | #else | ||
280 | static inline void mad_synth_thread_ready(void) | ||
281 | { | ||
282 | mad_synth_frame(&synth, &frame); | ||
283 | } | ||
284 | |||
285 | static inline bool mad_synth_thread_create(void) | ||
286 | { | ||
287 | return true; | ||
288 | } | ||
289 | |||
290 | static inline void mad_synth_thread_quit(void) | ||
291 | { | ||
292 | } | ||
293 | |||
294 | static inline void mad_synth_thread_wait_pcm(void) | ||
295 | { | ||
296 | } | ||
297 | |||
298 | static inline void mad_synth_thread_unwait_pcm(void) | ||
299 | { | ||
300 | } | ||
301 | #endif /* MPA_SYNTH_ON_COP */ | ||
302 | |||
303 | /* this is the codec entry point */ | ||
304 | enum codec_status codec_main(enum codec_entry_call_reason reason) | ||
305 | { | ||
306 | if (reason == CODEC_LOAD) { | ||
307 | /* Create a decoder instance */ | ||
308 | if (codec_init()) | ||
309 | return CODEC_ERROR; | ||
310 | |||
311 | ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); | ||
312 | |||
313 | /* does nothing on 1 processor systems except return true */ | ||
314 | if(!mad_synth_thread_create()) | ||
315 | return CODEC_ERROR; | ||
316 | } | ||
317 | else if (reason == CODEC_UNLOAD) { | ||
318 | /* mop up COP thread - MT only */ | ||
319 | mad_synth_thread_quit(); | ||
320 | } | ||
321 | |||
322 | return CODEC_OK; | ||
323 | } | ||
324 | |||
325 | /* this is called for each file to process */ | ||
326 | enum codec_status codec_run(void) | ||
327 | { | ||
328 | size_t size; | ||
329 | int file_end; | ||
330 | int samples_to_skip; /* samples to skip in total for this file (at start) */ | ||
331 | char *inputbuffer; | ||
332 | int64_t samplesdone; | ||
333 | int stop_skip, start_skip; | ||
334 | int current_stereo_mode = -1; | ||
335 | unsigned long current_frequency = 0; | ||
336 | int framelength; | ||
337 | int padding = MAD_BUFFER_GUARD; /* to help mad decode the last frame */ | ||
338 | intptr_t param; | ||
339 | |||
340 | /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */ | ||
341 | init_mad(); | ||
342 | |||
343 | file_end = 0; | ||
344 | |||
345 | ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); | ||
346 | current_frequency = ci->id3->frequency; | ||
347 | codec_set_replaygain(ci->id3); | ||
348 | |||
349 | if (ci->id3->offset) { | ||
350 | ci->seek_buffer(ci->id3->offset); | ||
351 | set_elapsed(ci->id3); | ||
352 | } | ||
353 | else | ||
354 | ci->seek_buffer(ci->id3->first_frame_offset); | ||
355 | |||
356 | if (ci->id3->lead_trim >= 0 && ci->id3->tail_trim >= 0) { | ||
357 | stop_skip = ci->id3->tail_trim - mpeg_latency[ci->id3->layer]; | ||
358 | if (stop_skip < 0) stop_skip = 0; | ||
359 | start_skip = ci->id3->lead_trim + mpeg_latency[ci->id3->layer]; | ||
360 | } else { | ||
361 | stop_skip = 0; | ||
362 | /* We want to skip this amount anyway */ | ||
363 | start_skip = mpeg_latency[ci->id3->layer]; | ||
364 | } | ||
365 | |||
366 | /* Libmad will not decode the last frame without 8 bytes of extra padding | ||
367 | in the buffer. So, we can trick libmad into not decoding the last frame | ||
368 | if we are to skip it entirely and then cut the appropriate samples from | ||
369 | final frame that we did decode. Note, if all tags (ID3, APE) are not | ||
370 | properly stripped from the end of the file, this trick will not work. */ | ||
371 | if (stop_skip >= mpeg_framesize[ci->id3->layer]) { | ||
372 | padding = 0; | ||
373 | stop_skip -= mpeg_framesize[ci->id3->layer]; | ||
374 | } else { | ||
375 | padding = MAD_BUFFER_GUARD; | ||
376 | } | ||
377 | |||
378 | samplesdone = ((int64_t)ci->id3->elapsed) * current_frequency / 1000; | ||
379 | |||
380 | /* Don't skip any samples unless we start at the beginning. */ | ||
381 | if (samplesdone > 0) | ||
382 | samples_to_skip = 0; | ||
383 | else | ||
384 | samples_to_skip = start_skip; | ||
385 | |||
386 | framelength = 0; | ||
387 | |||
388 | /* This is the decoding loop. */ | ||
389 | while (1) { | ||
390 | enum codec_command_action action = ci->get_command(¶m); | ||
391 | |||
392 | if (action == CODEC_ACTION_HALT) | ||
393 | break; | ||
394 | |||
395 | if (action == CODEC_ACTION_SEEK_TIME) { | ||
396 | int newpos; | ||
397 | |||
398 | /*make sure the synth thread is idle before seeking - MT only*/ | ||
399 | mad_synth_thread_wait_pcm(); | ||
400 | mad_synth_thread_unwait_pcm(); | ||
401 | |||
402 | samplesdone = ((int64_t)param)*current_frequency/1000; | ||
403 | |||
404 | if (param == 0) { | ||
405 | newpos = ci->id3->first_frame_offset; | ||
406 | samples_to_skip = start_skip; | ||
407 | } else { | ||
408 | newpos = get_file_pos(param); | ||
409 | samples_to_skip = 0; | ||
410 | } | ||
411 | |||
412 | if (!ci->seek_buffer(newpos)) | ||
413 | { | ||
414 | ci->seek_complete(); | ||
415 | break; | ||
416 | } | ||
417 | |||
418 | ci->set_elapsed((samplesdone * 1000) / current_frequency); | ||
419 | ci->seek_complete(); | ||
420 | init_mad(); | ||
421 | framelength = 0; | ||
422 | } | ||
423 | |||
424 | /* Lock buffers */ | ||
425 | if (stream.error == 0) { | ||
426 | inputbuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE); | ||
427 | if (size == 0 || inputbuffer == NULL) | ||
428 | break; | ||
429 | mad_stream_buffer(&stream, (unsigned char *)inputbuffer, | ||
430 | size + padding); | ||
431 | } | ||
432 | |||
433 | if (mad_frame_decode(&frame, &stream)) { | ||
434 | if (stream.error == MAD_ERROR_BUFLEN) { | ||
435 | /* This makes the codec support partially corrupted files */ | ||
436 | if (file_end == 30) | ||
437 | break; | ||
438 | |||
439 | /* Fill the buffer */ | ||
440 | if (stream.next_frame) | ||
441 | ci->advance_buffer(stream.next_frame - stream.buffer); | ||
442 | else | ||
443 | ci->advance_buffer(size); | ||
444 | stream.error = 0; /* Must get new inputbuffer next time */ | ||
445 | file_end++; | ||
446 | continue; | ||
447 | } else if (MAD_RECOVERABLE(stream.error)) { | ||
448 | /* Probably syncing after a seek */ | ||
449 | continue; | ||
450 | } else { | ||
451 | /* Some other unrecoverable error */ | ||
452 | return CODEC_ERROR; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | /* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm | ||
457 | data (not the one just decoded above). When we exit the decoding | ||
458 | loop we will need to process the final frame that was decoded. */ | ||
459 | mad_synth_thread_wait_pcm(); | ||
460 | |||
461 | if (framelength > 0) { | ||
462 | |||
463 | /* In case of a mono file, the second array will be ignored. */ | ||
464 | ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip], | ||
465 | &synth.pcm.samples[1][samples_to_skip], | ||
466 | framelength); | ||
467 | |||
468 | /* Only skip samples for the first frame added. */ | ||
469 | samples_to_skip = 0; | ||
470 | } | ||
471 | |||
472 | /* Initiate PCM synthesis on the COP (MT) or perform it here (ST) */ | ||
473 | mad_synth_thread_ready(); | ||
474 | |||
475 | /* Check if sample rate and stereo settings changed in this frame. */ | ||
476 | if (frame.header.samplerate != current_frequency) { | ||
477 | current_frequency = frame.header.samplerate; | ||
478 | ci->configure(DSP_SWITCH_FREQUENCY, current_frequency); | ||
479 | } | ||
480 | if (MAD_NCHANNELS(&frame.header) == 2) { | ||
481 | if (current_stereo_mode != STEREO_NONINTERLEAVED) { | ||
482 | ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); | ||
483 | current_stereo_mode = STEREO_NONINTERLEAVED; | ||
484 | } | ||
485 | } else { | ||
486 | if (current_stereo_mode != STEREO_MONO) { | ||
487 | ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); | ||
488 | current_stereo_mode = STEREO_MONO; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | if (stream.next_frame) | ||
493 | ci->advance_buffer(stream.next_frame - stream.buffer); | ||
494 | else | ||
495 | ci->advance_buffer(size); | ||
496 | stream.error = 0; /* Must get new inputbuffer next time */ | ||
497 | file_end = 0; | ||
498 | |||
499 | framelength = synth.pcm.length - samples_to_skip; | ||
500 | if (framelength < 0) { | ||
501 | framelength = 0; | ||
502 | samples_to_skip -= synth.pcm.length; | ||
503 | } | ||
504 | |||
505 | samplesdone += framelength; | ||
506 | ci->set_elapsed((samplesdone * 1000) / current_frequency); | ||
507 | } | ||
508 | |||
509 | /* wait for synth idle - MT only*/ | ||
510 | mad_synth_thread_wait_pcm(); | ||
511 | mad_synth_thread_unwait_pcm(); | ||
512 | |||
513 | /* Finish the remaining decoded frame. | ||
514 | Cut the required samples from the end. */ | ||
515 | if (framelength > stop_skip){ | ||
516 | ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1], | ||
517 | framelength - stop_skip); | ||
518 | } | ||
519 | |||
520 | return CODEC_OK; | ||
521 | } | ||