summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2006-05-20 09:57:55 +0000
committerDave Chapman <dave@dchapman.com>2006-05-20 09:57:55 +0000
commitfa5caa0b5b2bce6ec56a99d716584405854ede76 (patch)
treee4130e1d2092a6d9161afed571f104c88f2ce3b6
parent965e824923e63b6fd53113ed4c4c2c04692b2fe4 (diff)
downloadrockbox-fa5caa0b5b2bce6ec56a99d716584405854ede76.tar.gz
rockbox-fa5caa0b5b2bce6ec56a99d716584405854ede76.zip
Patch from bug report #5200 by Mark Arigo - attempt to fix gapless playback after seeking in an MP3 file. It works for me, but needs more testing with a wider range of files before we can close the bug report - please post feedback on the tracker.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9962 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/mpa.c163
1 files changed, 75 insertions, 88 deletions
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c
index 4c3784a5f7..81604de08a 100644
--- a/apps/codecs/mpa.c
+++ b/apps/codecs/mpa.c
@@ -40,6 +40,7 @@ mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR;
40unsigned char mad_main_data[MAD_BUFFER_MDLEN] IBSS_ATTR; 40unsigned char mad_main_data[MAD_BUFFER_MDLEN] IBSS_ATTR;
41/* TODO: what latency does layer 1 have? */ 41/* TODO: what latency does layer 1 have? */
42int mpeg_latency[3] = { 0, 481, 529 }; 42int mpeg_latency[3] = { 0, 481, 529 };
43int mpeg_framesize[3] = {384, 1152, 1152};
43 44
44#ifdef USE_IRAM 45#ifdef USE_IRAM
45extern char iramcopy[]; 46extern char iramcopy[];
@@ -50,34 +51,13 @@ extern char iend[];
50#endif 51#endif
51 52
52struct codec_api *ci; 53struct codec_api *ci;
53int64_t samplecount;
54int64_t samplesdone;
55int stop_skip, start_skip;
56int current_stereo_mode = -1;
57unsigned long current_frequency = 0;
58
59void recalc_samplecount(void)
60{
61 /* NOTE: currently this doesn't work, the below calculated samples_count
62 seems to be right, but sometimes we just don't have all the data we
63 need... */
64 if (ci->id3->frame_count) {
65 /* TODO: 1152 is the frame size in samples for MPEG1 layer 2 and layer 3,
66 it's probably not correct at all for MPEG2 and layer 1 */
67 samplecount = ((int64_t)ci->id3->frame_count) * 1152;
68 } else {
69 samplecount = ((int64_t)ci->id3->length) * current_frequency / 1000;
70 }
71
72 samplecount -= start_skip + stop_skip;
73}
74 54
75void init_mad(void) 55void init_mad(void)
76{ 56{
77 ci->memset(&stream, 0, sizeof(struct mad_stream)); 57 ci->memset(&stream, 0, sizeof(struct mad_stream));
78 ci->memset(&frame, 0, sizeof(struct mad_frame)); 58 ci->memset(&frame, 0, sizeof(struct mad_frame));
79 ci->memset(&synth, 0, sizeof(struct mad_synth)); 59 ci->memset(&synth, 0, sizeof(struct mad_synth));
80 60
81 mad_stream_init(&stream); 61 mad_stream_init(&stream);
82 mad_frame_init(&frame); 62 mad_frame_init(&frame);
83 mad_synth_init(&synth); 63 mad_synth_init(&synth);
@@ -94,14 +74,14 @@ enum codec_status codec_start(struct codec_api *api)
94 int status; 74 int status;
95 size_t size; 75 size_t size;
96 int file_end; 76 int file_end;
97 int frame_skip; /* samples to skip current frame */
98 int samples_to_skip; /* samples to skip in total for this file (at start) */ 77 int samples_to_skip; /* samples to skip in total for this file (at start) */
99 char *inputbuffer; 78 char *inputbuffer;
100 /* If we know the position isn't exact (i.e., we have seeked to a 79 int64_t samplesdone;
101 * position that isn't the start of the file), we can't reliably do 80 int stop_skip, start_skip;
102 * end-of-file trimming for gapless playback. 81 int current_stereo_mode = -1;
103 */ 82 unsigned long current_frequency = 0;
104 bool exact_position = true; 83 int framelength;
84 int padding = MAD_BUFFER_GUARD; /* to help mad decode the last frame */
105 85
106 ci = api; 86 ci = api;
107 87
@@ -120,20 +100,17 @@ enum codec_status codec_start(struct codec_api *api)
120 ci->configure(DSP_SET_CLIP_MIN, (int *)-MAD_F_ONE); 100 ci->configure(DSP_SET_CLIP_MIN, (int *)-MAD_F_ONE);
121 ci->configure(DSP_SET_CLIP_MAX, (int *)(MAD_F_ONE - 1)); 101 ci->configure(DSP_SET_CLIP_MAX, (int *)(MAD_F_ONE - 1));
122 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); 102 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
123 103
124 /** This label might need to be moved above all the init code, but I don't 104next_track:
125 * think reiniting the codec is necessary for MPEG. It might even be unwanted
126 * for gapless playback.
127 * Reinitializing seems to be necessary to avoid playback quircks when seeking. */
128 next_track:
129 status = CODEC_OK; 105 status = CODEC_OK;
130 106
107 /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */
131 init_mad(); 108 init_mad();
132 109
133 file_end = 0; 110 file_end = 0;
134 while (!*ci->taginfo_ready && !ci->stop_codec) 111 while (!*ci->taginfo_ready && !ci->stop_codec)
135 ci->sleep(1); 112 ci->sleep(1);
136 113
137 ci->configure(DSP_SET_FREQUENCY, (int *)ci->id3->frequency); 114 ci->configure(DSP_SET_FREQUENCY, (int *)ci->id3->frequency);
138 current_frequency = ci->id3->frequency; 115 current_frequency = ci->id3->frequency;
139 codec_set_replaygain(ci->id3); 116 codec_set_replaygain(ci->id3);
@@ -151,35 +128,52 @@ enum codec_status codec_start(struct codec_api *api)
151 start_skip = mpeg_latency[ci->id3->layer]; 128 start_skip = mpeg_latency[ci->id3->layer];
152 } 129 }
153 130
131 /* Libmad will not decode the last frame without 8 bytes of extra padding
132 in the buffer. So, we can trick libmad into not decoding the last frame
133 if we are to skip it entirely and then cut the appropriate samples from
134 final frame that we did decode. Note, if all tags (ID3, APE) are not
135 properly stripped from the end of the file, this trick will not work. */
136 if (stop_skip >= mpeg_framesize[ci->id3->layer]) {
137 padding = 0;
138 stop_skip -= mpeg_framesize[ci->id3->layer];
139 } else {
140 padding = MAD_BUFFER_GUARD;
141 }
142
154 samplesdone = ((int64_t)ci->id3->elapsed) * current_frequency / 1000; 143 samplesdone = ((int64_t)ci->id3->elapsed) * current_frequency / 1000;
155 exact_position = samplesdone == 0; 144
156 samples_to_skip = start_skip; 145 /* Don't skip any samples unless we start at the beginning. */
157 recalc_samplecount(); 146 if (samplesdone > 0)
158 147 samples_to_skip = 0;
148 else
149 samples_to_skip = start_skip;
150
151 framelength = 0;
152
159 /* This is the decoding loop. */ 153 /* This is the decoding loop. */
160 while (1) { 154 while (1) {
161 int framelength;
162
163 ci->yield(); 155 ci->yield();
164 if (ci->stop_codec || ci->new_track) 156 if (ci->stop_codec || ci->new_track)
165 break; 157 break;
166 158
167 if (ci->seek_time) { 159 if (ci->seek_time) {
168 int newpos; 160 int newpos;
169
170 samplesdone = ((int64_t) (ci->seek_time - 1))
171 * current_frequency / 1000;
172 exact_position = samplesdone == 0;
173 161
174 if (ci->seek_time-1 == 0) 162 samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000;
163
164 if (ci->seek_time-1 == 0) {
175 newpos = ci->id3->first_frame_offset; 165 newpos = ci->id3->first_frame_offset;
176 else 166 samples_to_skip = start_skip;
167 } else {
177 newpos = ci->mp3_get_filepos(ci->seek_time-1); 168 newpos = ci->mp3_get_filepos(ci->seek_time-1);
169 samples_to_skip = 0;
170 }
178 171
179 if (!ci->seek_buffer(newpos)) 172 if (!ci->seek_buffer(newpos))
180 break; 173 break;
181 ci->seek_complete(); 174 ci->seek_complete();
182 init_mad(); 175 init_mad();
176 framelength = 0;
183 } 177 }
184 178
185 /* Lock buffers */ 179 /* Lock buffers */
@@ -187,18 +181,17 @@ enum codec_status codec_start(struct codec_api *api)
187 inputbuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE); 181 inputbuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE);
188 if (size == 0 || inputbuffer == NULL) 182 if (size == 0 || inputbuffer == NULL)
189 break; 183 break;
190 /* size + MAD_BUFFER_GUARD to help mad decode the last frame */
191 mad_stream_buffer(&stream, (unsigned char *)inputbuffer, 184 mad_stream_buffer(&stream, (unsigned char *)inputbuffer,
192 size + MAD_BUFFER_GUARD); 185 size + padding);
193 } 186 }
194 187
195 if (mad_frame_decode(&frame, &stream)) { 188 if (mad_frame_decode(&frame, &stream)) {
196 if (stream.error == MAD_FLAG_INCOMPLETE 189 if (stream.error == MAD_FLAG_INCOMPLETE
197 || stream.error == MAD_ERROR_BUFLEN) { 190 || stream.error == MAD_ERROR_BUFLEN) {
198 /* This makes the codec support partially corrupted files */ 191 /* This makes the codec support partially corrupted files */
199 if (file_end == 30) 192 if (file_end == 30)
200 break; 193 break;
201 194
202 /* Fill the buffer */ 195 /* Fill the buffer */
203 if (stream.next_frame) 196 if (stream.next_frame)
204 ci->advance_buffer_loc((void *)stream.next_frame); 197 ci->advance_buffer_loc((void *)stream.next_frame);
@@ -216,39 +209,28 @@ enum codec_status codec_start(struct codec_api *api)
216 } 209 }
217 break; 210 break;
218 } 211 }
219 212
220 file_end = 0; 213 file_end = 0;
221 214
222 mad_synth_frame(&synth, &frame); 215 /* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm
223 216 data (not the one just decoded above). When we exit the decoding
224 /* We need to skip samples_to_skip samples from the start of every file 217 loop we will need to process the final frame that was decoded. */
225 to properly support LAME style gapless MP3 files. samples_to_skip 218 if (framelength > 0) {
226 might be larger than one frame. */ 219 /* In case of a mono file, the second array will be ignored. */
227 if (samples_to_skip < synth.pcm.length) { 220 ci->pcmbuf_insert_split(&synth.pcm.samples[0][samples_to_skip],
228 /* skip just part of the frame */ 221 &synth.pcm.samples[1][samples_to_skip],
229 frame_skip = samples_to_skip; 222 framelength * 4);
223
224 /* Only skip samples for the first frame added. */
230 samples_to_skip = 0; 225 samples_to_skip = 0;
231 } else {
232 /* we need to skip an entire frame */
233 frame_skip = synth.pcm.length;
234 samples_to_skip -= synth.pcm.length;
235 }
236
237 framelength = synth.pcm.length - frame_skip;
238
239 if (exact_position && (stop_skip > 0)) {
240 int64_t max = samplecount - samplesdone;
241
242 if (max < 0) max = 0;
243 if (max < framelength) framelength = (int)max;
244 if (framelength == 0 && frame_skip == 0) break;
245 } 226 }
246 227
228 mad_synth_frame(&synth, &frame);
229
247 /* Check if sample rate and stereo settings changed in this frame. */ 230 /* Check if sample rate and stereo settings changed in this frame. */
248 if (frame.header.samplerate != current_frequency) { 231 if (frame.header.samplerate != current_frequency) {
249 current_frequency = frame.header.samplerate; 232 current_frequency = frame.header.samplerate;
250 ci->configure(DSP_SWITCH_FREQUENCY, (int *)current_frequency); 233 ci->configure(DSP_SWITCH_FREQUENCY, (int *)current_frequency);
251 recalc_samplecount();
252 } 234 }
253 if (MAD_NCHANNELS(&frame.header) == 2) { 235 if (MAD_NCHANNELS(&frame.header) == 2) {
254 if (current_stereo_mode != STEREO_NONINTERLEAVED) { 236 if (current_stereo_mode != STEREO_NONINTERLEAVED) {
@@ -261,27 +243,32 @@ enum codec_status codec_start(struct codec_api *api)
261 current_stereo_mode = STEREO_MONO; 243 current_stereo_mode = STEREO_MONO;
262 } 244 }
263 } 245 }
264 246
265 /* Check if we can just skip the entire frame. */
266 if (frame_skip < synth.pcm.length) {
267 /* In case of a mono file, the second array will be ignored. */
268 ci->pcmbuf_insert_split(&synth.pcm.samples[0][frame_skip],
269 &synth.pcm.samples[1][frame_skip],
270 framelength * 4);
271 }
272
273 if (stream.next_frame) 247 if (stream.next_frame)
274 ci->advance_buffer_loc((void *)stream.next_frame); 248 ci->advance_buffer_loc((void *)stream.next_frame);
275 else 249 else
276 ci->advance_buffer(size); 250 ci->advance_buffer(size);
277 251
252 framelength = synth.pcm.length - samples_to_skip;
253 if (framelength < 0) {
254 framelength = 0;
255 samples_to_skip -= synth.pcm.length;
256 }
257
278 samplesdone += framelength; 258 samplesdone += framelength;
279 ci->set_elapsed(samplesdone / (current_frequency / 1000)); 259 ci->set_elapsed(samplesdone / (current_frequency / 1000));
280 } 260 }
261
262 /* Finish the remaining decoded frame.
263 Cut the required samples from the end. */
264 if (framelength > stop_skip)
265 ci->pcmbuf_insert_split(synth.pcm.samples[0], synth.pcm.samples[1],
266 (framelength - stop_skip) * 4);
267
281 stream.error = 0; 268 stream.error = 0;
282 269
283 if (ci->request_next_track()) 270 if (ci->request_next_track())
284 goto next_track; 271 goto next_track;
285 272
286 return status; 273 return status;
287} 274}