summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMagnus Holmgren <magnushol@gmail.com>2007-06-16 13:00:52 +0000
committerMagnus Holmgren <magnushol@gmail.com>2007-06-16 13:00:52 +0000
commitc3206a455a455fadb282d09f9af482c66b6bdf8e (patch)
treeebdddf413b84612d55291c8d64ee233f725dc316
parent93af4feae9f7890846934f4293d1291daa2901c7 (diff)
downloadrockbox-c3206a455a455fadb282d09f9af482c66b6bdf8e.tar.gz
rockbox-c3206a455a455fadb282d09f9af482c66b6bdf8e.zip
AAC: Add support for iTunes-style gapless playback.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13636 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/aac.c54
-rw-r--r--apps/metadata.c50
2 files changed, 102 insertions, 2 deletions
diff --git a/apps/codecs/aac.c b/apps/codecs/aac.c
index 11a9d2888d..d4f051c09c 100644
--- a/apps/codecs/aac.c
+++ b/apps/codecs/aac.c
@@ -42,6 +42,8 @@ enum codec_status codec_main(void)
42 uint32_t sample_duration; 42 uint32_t sample_duration;
43 uint32_t sample_byte_size; 43 uint32_t sample_byte_size;
44 int file_offset; 44 int file_offset;
45 int framelength;
46 int lead_trim = 0;
45 unsigned int i; 47 unsigned int i;
46 unsigned char* buffer; 48 unsigned char* buffer;
47 static NeAACDecFrameInfo frame_info; 49 static NeAACDecFrameInfo frame_info;
@@ -117,6 +119,11 @@ next_track:
117 sound_samples_done = 0; 119 sound_samples_done = 0;
118 } 120 }
119 } 121 }
122
123 if (i == 0)
124 {
125 lead_trim = ci->id3->lead_trim;
126 }
120 127
121 /* The main decoding loop */ 128 /* The main decoding loop */
122 while (i < demux_res.num_sample_byte_sizes) { 129 while (i < demux_res.num_sample_byte_sizes) {
@@ -133,6 +140,11 @@ next_track:
133 &sound_samples_done, (int*) &i)) { 140 &sound_samples_done, (int*) &i)) {
134 elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); 141 elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
135 ci->set_elapsed(elapsed_time); 142 ci->set_elapsed(elapsed_time);
143
144 if (i == 0)
145 {
146 lead_trim = ci->id3->lead_trim;
147 }
136 } 148 }
137 ci->seek_complete(); 149 ci->seek_complete();
138 } 150 }
@@ -183,8 +195,46 @@ next_track:
183 195
184 /* Output the audio */ 196 /* Output the audio */
185 ci->yield(); 197 ci->yield();
186 ci->pcmbuf_insert(decoder->time_out[0], decoder->time_out[1], 198
187 frame_info.samples >> 1); 199 framelength = (frame_info.samples >> 1) - lead_trim;
200
201 if (i == demux_res.num_sample_byte_sizes - 1 && framelength > 0)
202 {
203 /* Currently limited to at most one frame of tail_trim.
204 * Seems to be enough.
205 */
206 if (ci->id3->tail_trim == 0
207 && sample_duration < (frame_info.samples >> 1))
208 {
209 /* Subtract lead_trim just in case we decode a file with
210 * only one audio frame with actual data.
211 */
212 framelength = sample_duration - lead_trim;
213 }
214 else
215 {
216 framelength -= ci->id3->tail_trim;
217 }
218 }
219
220 if (framelength > 0)
221 {
222 ci->pcmbuf_insert(&decoder->time_out[0][lead_trim],
223 &decoder->time_out[1][lead_trim],
224 framelength);
225 }
226
227 if (lead_trim > 0)
228 {
229 /* frame_info.samples can be 0 for the first frame */
230 lead_trim -= (i > 0 || frame_info.samples)
231 ? (frame_info.samples >> 1) : sample_duration;
232
233 if (lead_trim < 0 || ci->id3->lead_trim == 0)
234 {
235 lead_trim = 0;
236 }
237 }
188 238
189 /* Update the elapsed-time indicator */ 239 /* Update the elapsed-time indicator */
190 sound_samples_done += sample_duration; 240 sound_samples_done += sample_duration;
diff --git a/apps/metadata.c b/apps/metadata.c
index 357c5e649e..a0c2f31eee 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -206,6 +206,43 @@ static long get_slong(void* buf)
206 206
207 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 207 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
208} 208}
209
210static char* skip_space(char* str)
211{
212 while (isspace(*str))
213 {
214 str++;
215 }
216
217 return str;
218}
219
220static unsigned long get_itunes_int32(char* value, int count)
221{
222 static const char hexdigits[] = "0123456789ABCDEF";
223 const char* c;
224 int r = 0;
225
226 while (count-- > 0)
227 {
228 value = skip_space(value);
229
230 while (*value && !isspace(*value))
231 {
232 value++;
233 }
234 }
235
236 value = skip_space(value);
237
238 while (*value && ((c = strchr(hexdigits, toupper(*value))) != NULL))
239 {
240 r = (r << 4) | (c - hexdigits);
241 value++;
242 }
243
244 return r;
245}
209 246
210/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly. 247/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
211 * String values to keep are written to buf. Returns number of bytes written 248 * String values to keep are written to buf. Returns number of bytes written
@@ -1520,6 +1557,19 @@ static bool read_mp4_tags(int fd, struct mp3entry* id3,
1520 { 1557 {
1521 read_mp4_tag_string(fd, size, &buffer, &buffer_left, 1558 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
1522 &id3->composer); 1559 &id3->composer);
1560 }
1561 else if (strcasecmp(tag_name, "iTunSMPB") == 0)
1562 {
1563 char value[TAG_VALUE_LENGTH];
1564 char* value_p = value;
1565 char* any;
1566 unsigned int length = sizeof(value);
1567
1568 read_mp4_tag_string(fd, size, &value_p, &length, &any);
1569 id3->lead_trim = get_itunes_int32(value, 1);
1570 id3->tail_trim = get_itunes_int32(value, 2);
1571 DEBUGF("AAC: lead_trim %d, tail_trim %d\n",
1572 id3->lead_trim, id3->tail_trim);
1523 } 1573 }
1524 else 1574 else
1525 { 1575 {