Redo my previous segfault fix in a better way.
[Rockbox.git] / apps / codecs / mpa.c
blob3de7684b2b0cb2780ee015196fedc06d0db083ab
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Dave Chapman
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "codeclib.h"
21 #include <codecs/libmad/mad.h>
22 #include <inttypes.h>
24 CODEC_HEADER
26 struct mad_stream stream IBSS_ATTR;
27 struct mad_frame frame IBSS_ATTR;
28 struct mad_synth synth IBSS_ATTR;
30 /* The following function is used inside libmad - let's hope it's never
31 called.
34 void abort(void) {
37 #define INPUT_CHUNK_SIZE 8192
39 mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR;
40 unsigned char mad_main_data[MAD_BUFFER_MDLEN] IBSS_ATTR;
41 /* TODO: what latency does layer 1 have? */
42 int mpeg_latency[3] = { 0, 481, 529 };
43 int mpeg_framesize[3] = {384, 1152, 1152};
45 void init_mad(void)
47 ci->memset(&stream, 0, sizeof(struct mad_stream));
48 ci->memset(&frame, 0, sizeof(struct mad_frame));
49 ci->memset(&synth, 0, sizeof(struct mad_synth));
51 mad_stream_init(&stream);
52 mad_frame_init(&frame);
53 mad_synth_init(&synth);
55 /* We do this so libmad doesn't try to call codec_calloc() */
56 ci->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap));
57 frame.overlap = &mad_frame_overlap;
58 stream.main_data = &mad_main_data;
61 /* this is the codec entry point */
62 enum codec_status codec_main(void)
64 int status;
65 size_t size;
66 int file_end;
67 int samples_to_skip; /* samples to skip in total for this file (at start) */
68 char *inputbuffer;
69 int64_t samplesdone;
70 int stop_skip, start_skip;
71 int current_stereo_mode = -1;
72 unsigned long current_frequency = 0;
73 int framelength;
74 int padding = MAD_BUFFER_GUARD; /* to help mad decode the last frame */
76 if (codec_init())
77 return CODEC_ERROR;
79 /* Create a decoder instance */
81 ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
83 next_track:
84 status = CODEC_OK;
86 /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */
87 init_mad();
89 file_end = 0;
90 while (!*ci->taginfo_ready && !ci->stop_codec)
91 ci->sleep(1);
93 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
94 current_frequency = ci->id3->frequency;
95 codec_set_replaygain(ci->id3);
97 if (ci->id3->offset)
98 ci->seek_buffer(ci->id3->offset);
99 else
100 ci->seek_buffer(ci->id3->first_frame_offset);
102 if (ci->id3->lead_trim >= 0 && ci->id3->tail_trim >= 0) {
103 stop_skip = ci->id3->tail_trim - mpeg_latency[ci->id3->layer];
104 if (stop_skip < 0) stop_skip = 0;
105 start_skip = ci->id3->lead_trim + mpeg_latency[ci->id3->layer];
106 } else {
107 stop_skip = 0;
108 /* We want to skip this amount anyway */
109 start_skip = mpeg_latency[ci->id3->layer];
112 /* Libmad will not decode the last frame without 8 bytes of extra padding
113 in the buffer. So, we can trick libmad into not decoding the last frame
114 if we are to skip it entirely and then cut the appropriate samples from
115 final frame that we did decode. Note, if all tags (ID3, APE) are not
116 properly stripped from the end of the file, this trick will not work. */
117 if (stop_skip >= mpeg_framesize[ci->id3->layer]) {
118 padding = 0;
119 stop_skip -= mpeg_framesize[ci->id3->layer];
120 } else {
121 padding = MAD_BUFFER_GUARD;
124 samplesdone = ((int64_t)ci->id3->elapsed) * current_frequency / 1000;
126 /* Don't skip any samples unless we start at the beginning. */
127 if (samplesdone > 0)
128 samples_to_skip = 0;
129 else
130 samples_to_skip = start_skip;
132 framelength = 0;
134 /* This is the decoding loop. */
135 while (1) {
136 ci->yield();
137 if (ci->stop_codec || ci->new_track)
138 break;
140 if (ci->seek_time) {
141 int newpos;
143 samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000;
145 if (ci->seek_time-1 == 0) {
146 newpos = ci->id3->first_frame_offset;
147 samples_to_skip = start_skip;
148 } else {
149 newpos = ci->mp3_get_filepos(ci->seek_time-1);
150 samples_to_skip = 0;
153 if (!ci->seek_buffer(newpos))
154 break;
155 ci->seek_complete();
156 init_mad();
157 framelength = 0;
160 /* Lock buffers */
161 if (stream.error == 0) {
162 inputbuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE);
163 if (size == 0 || inputbuffer == NULL)
164 break;
165 mad_stream_buffer(&stream, (unsigned char *)inputbuffer,
166 size + padding);
169 if (mad_frame_decode(&frame, &stream)) {
170 if (stream.error == MAD_FLAG_INCOMPLETE
171 || stream.error == MAD_ERROR_BUFLEN) {
172 /* This makes the codec support partially corrupted files */
173 if (file_end == 30)
174 break;
176 /* Fill the buffer */
177 if (stream.next_frame)
178 ci->advance_buffer_loc((void *)stream.next_frame);
179 else
180 ci->advance_buffer(size);
181 stream.error = 0;
182 file_end++;
183 continue;
184 } else if (MAD_RECOVERABLE(stream.error)) {
185 continue;
186 } else {
187 /* Some other unrecoverable error */
188 status = CODEC_ERROR;
189 break;
191 break;
194 file_end = 0;
196 /* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm
197 data (not the one just decoded above). When we exit the decoding
198 loop we will need to process the final frame that was decoded. */
199 if (framelength > 0) {
200 /* In case of a mono file, the second array will be ignored. */
201 ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip],
202 &synth.pcm.samples[1][samples_to_skip],
203 framelength);
205 /* Only skip samples for the first frame added. */
206 samples_to_skip = 0;
209 mad_synth_frame(&synth, &frame);
211 /* Check if sample rate and stereo settings changed in this frame. */
212 if (frame.header.samplerate != current_frequency) {
213 current_frequency = frame.header.samplerate;
214 ci->configure(DSP_SWITCH_FREQUENCY, current_frequency);
216 if (MAD_NCHANNELS(&frame.header) == 2) {
217 if (current_stereo_mode != STEREO_NONINTERLEAVED) {
218 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
219 current_stereo_mode = STEREO_NONINTERLEAVED;
221 } else {
222 if (current_stereo_mode != STEREO_MONO) {
223 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
224 current_stereo_mode = STEREO_MONO;
228 if (stream.next_frame)
229 ci->advance_buffer_loc((void *)stream.next_frame);
230 else
231 ci->advance_buffer(size);
233 framelength = synth.pcm.length - samples_to_skip;
234 if (framelength < 0) {
235 framelength = 0;
236 samples_to_skip -= synth.pcm.length;
239 samplesdone += framelength;
240 ci->set_elapsed(samplesdone / (current_frequency / 1000));
243 /* Finish the remaining decoded frame.
244 Cut the required samples from the end. */
245 if (framelength > stop_skip)
246 ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1],
247 framelength - stop_skip);
249 stream.error = 0;
251 if (ci->request_next_track())
252 goto next_track;
254 return status;