diff options
Diffstat (limited to 'apps/codecs')
-rw-r--r-- | apps/codecs/aac.c | 15 | ||||
-rw-r--r-- | apps/codecs/alac.c | 14 | ||||
-rw-r--r-- | apps/codecs/libm4a/demux.c | 92 | ||||
-rw-r--r-- | apps/codecs/libm4a/m4a.c | 237 | ||||
-rw-r--r-- | apps/codecs/libm4a/m4a.h | 16 |
5 files changed, 133 insertions, 241 deletions
diff --git a/apps/codecs/aac.c b/apps/codecs/aac.c index 849d87bedf..6bb5ac50ae 100644 --- a/apps/codecs/aac.c +++ b/apps/codecs/aac.c | |||
@@ -27,6 +27,11 @@ | |||
27 | 27 | ||
28 | CODEC_HEADER | 28 | CODEC_HEADER |
29 | 29 | ||
30 | /* The maximum buffer size handled by faad. 12 bytes are required by libfaad | ||
31 | * as headroom (see libfaad/bits.c). FAAD_BYTE_BUFFER_SIZE bytes are buffered | ||
32 | * for each frame. */ | ||
33 | #define FAAD_BYTE_BUFFER_SIZE (2048-12) | ||
34 | |||
30 | /* Global buffers to be used in the mdct synthesis. This way the arrays can | 35 | /* Global buffers to be used in the mdct synthesis. This way the arrays can |
31 | * be moved to IRAM for some targets */ | 36 | * be moved to IRAM for some targets */ |
32 | #define GB_BUF_SIZE 1024 | 37 | #define GB_BUF_SIZE 1024 |
@@ -159,7 +164,7 @@ next_track: | |||
159 | /* Resume the desired (byte) position. Important: When resuming SBR | 164 | /* Resume the desired (byte) position. Important: When resuming SBR |
160 | * upsampling files the resulting sound_samples_done must be expanded | 165 | * upsampling files the resulting sound_samples_done must be expanded |
161 | * by a factor of 2. This is done via using sbr_fac. */ | 166 | * by a factor of 2. This is done via using sbr_fac. */ |
162 | if (alac_seek_raw(&demux_res, &input_stream, file_offset, | 167 | if (m4a_seek_raw(&demux_res, &input_stream, file_offset, |
163 | &sound_samples_done, (int*) &i)) { | 168 | &sound_samples_done, (int*) &i)) { |
164 | sound_samples_done *= sbr_fac; | 169 | sound_samples_done *= sbr_fac; |
165 | elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); | 170 | elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); |
@@ -188,9 +193,9 @@ next_track: | |||
188 | if (ci->seek_time) { | 193 | if (ci->seek_time) { |
189 | /* Seek to the desired time position. Important: When seeking in SBR | 194 | /* Seek to the desired time position. Important: When seeking in SBR |
190 | * upsampling files the seek_time must be divided by 2 when calling | 195 | * upsampling files the seek_time must be divided by 2 when calling |
191 | * alac_seek and the resulting sound_samples_done must be expanded | 196 | * m4a_seek and the resulting sound_samples_done must be expanded |
192 | * by a factor 2. This is done via using sbr_fac. */ | 197 | * by a factor 2. This is done via using sbr_fac. */ |
193 | if (alac_seek(&demux_res, &input_stream, | 198 | if (m4a_seek(&demux_res, &input_stream, |
194 | ((ci->seek_time-1)/10/sbr_fac)*(ci->id3->frequency/100), | 199 | ((ci->seek_time-1)/10/sbr_fac)*(ci->id3->frequency/100), |
195 | &sound_samples_done, (int*) &i)) { | 200 | &sound_samples_done, (int*) &i)) { |
196 | sound_samples_done *= sbr_fac; | 201 | sound_samples_done *= sbr_fac; |
@@ -211,7 +216,7 @@ next_track: | |||
211 | * that an good question (but files with gaps do exist, so who | 216 | * that an good question (but files with gaps do exist, so who |
212 | * knows?), so we don't support that - for now, at least. | 217 | * knows?), so we don't support that - for now, at least. |
213 | */ | 218 | */ |
214 | file_offset = get_sample_offset(&demux_res, i); | 219 | file_offset = m4a_check_sample_offset(&demux_res, i); |
215 | 220 | ||
216 | if (file_offset > ci->curpos) | 221 | if (file_offset > ci->curpos) |
217 | { | 222 | { |
@@ -225,7 +230,7 @@ next_track: | |||
225 | } | 230 | } |
226 | 231 | ||
227 | /* Request the required number of bytes from the input buffer */ | 232 | /* Request the required number of bytes from the input buffer */ |
228 | buffer=ci->request_buffer(&n, demux_res.sample_byte_size[i]); | 233 | buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); |
229 | 234 | ||
230 | /* Decode one block - returned samples will be host-endian */ | 235 | /* Decode one block - returned samples will be host-endian */ |
231 | ret = NeAACDecDecode(decoder, &frame_info, buffer, n); | 236 | ret = NeAACDecDecode(decoder, &frame_info, buffer, n); |
diff --git a/apps/codecs/alac.c b/apps/codecs/alac.c index 428fc59836..cd9129a278 100644 --- a/apps/codecs/alac.c +++ b/apps/codecs/alac.c | |||
@@ -25,6 +25,10 @@ | |||
25 | 25 | ||
26 | CODEC_HEADER | 26 | CODEC_HEADER |
27 | 27 | ||
28 | /* The maximum buffer size handled. This amount of bytes is buffered for each | ||
29 | * frame. */ | ||
30 | #define ALAC_BYTE_BUFFER_SIZE 32768 | ||
31 | |||
28 | static int32_t outputbuffer[ALAC_MAX_CHANNELS][ALAC_BLOCKSIZE] IBSS_ATTR; | 32 | static int32_t outputbuffer[ALAC_MAX_CHANNELS][ALAC_BLOCKSIZE] IBSS_ATTR; |
29 | 33 | ||
30 | /* this is the codec entry point */ | 34 | /* this is the codec entry point */ |
@@ -83,7 +87,7 @@ enum codec_status codec_main(void) | |||
83 | /* Set i for first frame, seek to desired sample position for resuming. */ | 87 | /* Set i for first frame, seek to desired sample position for resuming. */ |
84 | i=0; | 88 | i=0; |
85 | if (samplesdone > 0) { | 89 | if (samplesdone > 0) { |
86 | if (alac_seek(&demux_res, &input_stream, samplesdone, | 90 | if (m4a_seek(&demux_res, &input_stream, samplesdone, |
87 | &samplesdone, (int*) &i)) { | 91 | &samplesdone, (int*) &i)) { |
88 | elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100); | 92 | elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100); |
89 | ci->set_elapsed(elapsedtime); | 93 | ci->set_elapsed(elapsedtime); |
@@ -101,7 +105,7 @@ enum codec_status codec_main(void) | |||
101 | 105 | ||
102 | /* Deal with any pending seek requests */ | 106 | /* Deal with any pending seek requests */ |
103 | if (ci->seek_time) { | 107 | if (ci->seek_time) { |
104 | if (alac_seek(&demux_res, &input_stream, | 108 | if (m4a_seek(&demux_res, &input_stream, |
105 | ((ci->seek_time-1)/10) * (ci->id3->frequency/100), | 109 | ((ci->seek_time-1)/10) * (ci->id3->frequency/100), |
106 | &samplesdone, (int *)&i)) { | 110 | &samplesdone, (int *)&i)) { |
107 | elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); | 111 | elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); |
@@ -111,11 +115,7 @@ enum codec_status codec_main(void) | |||
111 | } | 115 | } |
112 | 116 | ||
113 | /* Request the required number of bytes from the input buffer */ | 117 | /* Request the required number of bytes from the input buffer */ |
114 | buffer=ci->request_buffer(&n, demux_res.sample_byte_size[i]); | 118 | buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE); |
115 | if (n!=demux_res.sample_byte_size[i]) { | ||
116 | retval = CODEC_ERROR; | ||
117 | goto done; | ||
118 | } | ||
119 | 119 | ||
120 | /* Decode one block - returned samples will be host-endian */ | 120 | /* Decode one block - returned samples will be host-endian */ |
121 | ci->yield(); | 121 | ci->yield(); |
diff --git a/apps/codecs/libm4a/demux.c b/apps/codecs/libm4a/demux.c index e584c37858..1b8deab602 100644 --- a/apps/codecs/libm4a/demux.c +++ b/apps/codecs/libm4a/demux.c | |||
@@ -354,8 +354,6 @@ static bool read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len) | |||
354 | 354 | ||
355 | static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) | 355 | static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) |
356 | { | 356 | { |
357 | unsigned int i; | ||
358 | uint32_t numentries; | ||
359 | size_t size_remaining = chunk_len - 8; | 357 | size_t size_remaining = chunk_len - 8; |
360 | 358 | ||
361 | /* version */ | 359 | /* version */ |
@@ -377,35 +375,11 @@ static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) | |||
377 | } | 375 | } |
378 | size_remaining -= 4; | 376 | size_remaining -= 4; |
379 | 377 | ||
380 | numentries = stream_read_uint32(qtmovie->stream); | 378 | qtmovie->res->num_sample_byte_sizes = stream_read_uint32(qtmovie->stream); |
381 | size_remaining -= 4; | 379 | size_remaining -= 4; |
382 | 380 | ||
383 | qtmovie->res->num_sample_byte_sizes = numentries; | ||
384 | qtmovie->res->sample_byte_size = malloc(numentries * sizeof(*qtmovie->res->sample_byte_size)); | ||
385 | |||
386 | if (!qtmovie->res->sample_byte_size) | ||
387 | { | ||
388 | DEBUGF("stsz too large\n"); | ||
389 | return false; | ||
390 | } | ||
391 | |||
392 | for (i = 0; i < numentries; i++) | ||
393 | { | ||
394 | uint32_t v = stream_read_uint32(qtmovie->stream); | ||
395 | |||
396 | if (v > 0x0000ffff) | ||
397 | { | ||
398 | DEBUGF("stsz[%d] > 65 kB (%ld)\n", i, (long)v); | ||
399 | return false; | ||
400 | } | ||
401 | |||
402 | qtmovie->res->sample_byte_size[i] = v; | ||
403 | size_remaining -= 4; | ||
404 | } | ||
405 | |||
406 | if (size_remaining) | 381 | if (size_remaining) |
407 | { | 382 | { |
408 | DEBUGF("ehm, size remianing?\n"); | ||
409 | stream_skip(qtmovie->stream, size_remaining); | 383 | stream_skip(qtmovie->stream, size_remaining); |
410 | } | 384 | } |
411 | 385 | ||
@@ -426,8 +400,7 @@ static bool read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len) | |||
426 | size_remaining -= 4; | 400 | size_remaining -= 4; |
427 | 401 | ||
428 | qtmovie->res->num_sample_to_chunks = numentries; | 402 | qtmovie->res->num_sample_to_chunks = numentries; |
429 | qtmovie->res->sample_to_chunk = malloc(numentries * | 403 | qtmovie->res->sample_to_chunk = malloc(numentries * sizeof(sample_to_chunk_t)); |
430 | sizeof(*qtmovie->res->sample_to_chunk)); | ||
431 | 404 | ||
432 | if (!qtmovie->res->sample_to_chunk) | 405 | if (!qtmovie->res->sample_to_chunk) |
433 | { | 406 | { |
@@ -456,8 +429,14 @@ static bool read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len) | |||
456 | 429 | ||
457 | static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len) | 430 | static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len) |
458 | { | 431 | { |
459 | unsigned int i; | 432 | uint32_t i, k; |
460 | uint32_t numentries; | 433 | uint32_t numentries; |
434 | int32_t idx = 0; | ||
435 | int32_t frame; | ||
436 | int32_t offset; | ||
437 | int32_t old_first; | ||
438 | int32_t new_first; | ||
439 | int32_t old_frame; | ||
461 | size_t size_remaining = chunk_len - 8; | 440 | size_t size_remaining = chunk_len - 8; |
462 | 441 | ||
463 | /* version + flags */ | 442 | /* version + flags */ |
@@ -466,20 +445,57 @@ static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len) | |||
466 | 445 | ||
467 | numentries = stream_read_uint32(qtmovie->stream); | 446 | numentries = stream_read_uint32(qtmovie->stream); |
468 | size_remaining -= 4; | 447 | size_remaining -= 4; |
448 | |||
449 | qtmovie->res->num_lookup_table = numentries; | ||
450 | qtmovie->res->lookup_table = malloc(numentries * sizeof(*qtmovie->res->lookup_table)); | ||
469 | 451 | ||
470 | qtmovie->res->num_chunk_offsets = numentries; | 452 | if (!qtmovie->res->lookup_table) |
471 | qtmovie->res->chunk_offset = malloc(numentries * | ||
472 | sizeof(*qtmovie->res->chunk_offset)); | ||
473 | |||
474 | if (!qtmovie->res->chunk_offset) | ||
475 | { | 453 | { |
476 | DEBUGF("stco too large\n"); | 454 | DEBUGF("stco too large to allocate lookup_table[]\n"); |
477 | return false; | 455 | return false; |
478 | } | 456 | } |
479 | 457 | ||
480 | for (i = 0; i < numentries; i++) | 458 | /* read first offset */ |
459 | offset = stream_read_uint32(qtmovie->stream); | ||
460 | size_remaining -= 4; | ||
461 | |||
462 | /* Build up lookup table. The lookup table contains the sample index and | ||
463 | * byte position in the file for each chunk. This table is used to seek | ||
464 | * and resume (see m4a_seek() and m4a_seek_raw() in libm4a/m4a.c) and | ||
465 | * to skip empty chunks (see m4a_check_sample_offset() in codecs/aac.c and | ||
466 | * libm4a/m4a.c). | ||
467 | * The seek/resume precision is lower than using sample_byte_size[] and | ||
468 | * depends on numentries. Typically the resolution is ~1/10 of all frames | ||
469 | * which equals about 1/4-1/2 seconds. The loss of seek precision is | ||
470 | * accepted to be able to avoid allocation of the large sample_byte_size[] | ||
471 | * table. This reduces the memory consumption by a factor of 2 or even | ||
472 | * more. */ | ||
473 | i = 1; | ||
474 | frame = 0; | ||
475 | old_frame = qtmovie->res->sample_to_chunk[0].num_samples; | ||
476 | old_first = qtmovie->res->sample_to_chunk[0].first_chunk; | ||
477 | for (k = 1; k < numentries; ++k) | ||
481 | { | 478 | { |
482 | qtmovie->res->chunk_offset[i] = stream_read_uint32(qtmovie->stream); | 479 | for (; i < qtmovie->res->num_sample_to_chunks; ++i) |
480 | { | ||
481 | old_frame = qtmovie->res->sample_to_chunk[i-1].num_samples; | ||
482 | old_first = qtmovie->res->sample_to_chunk[i-1].first_chunk; | ||
483 | new_first = qtmovie->res->sample_to_chunk[i ].first_chunk; | ||
484 | |||
485 | if (qtmovie->res->sample_to_chunk[i].first_chunk > k) | ||
486 | break; | ||
487 | |||
488 | frame += (new_first - old_first) * old_frame; | ||
489 | } | ||
490 | frame += (k - old_first) * old_frame; | ||
491 | |||
492 | qtmovie->res->lookup_table[idx].sample = frame; | ||
493 | qtmovie->res->lookup_table[idx].offset = offset; | ||
494 | idx++; | ||
495 | |||
496 | frame -= (k - old_first) * old_frame; | ||
497 | |||
498 | offset = stream_read_uint32(qtmovie->stream); | ||
483 | size_remaining -= 4; | 499 | size_remaining -= 4; |
484 | } | 500 | } |
485 | 501 | ||
diff --git a/apps/codecs/libm4a/m4a.c b/apps/codecs/libm4a/m4a.c index 8c4b172bc2..836cdafda3 100644 --- a/apps/codecs/libm4a/m4a.c +++ b/apps/codecs/libm4a/m4a.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2005 Dave Chapman | 10 | * Copyright (C) 2005 Dave Chapman, 2011 Andree Buschmann |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 13 | * modify it under the terms of the GNU General Public License |
@@ -122,148 +122,46 @@ void stream_create(stream_t *stream,struct codec_api* ci) | |||
122 | stream->eof=0; | 122 | stream->eof=0; |
123 | } | 123 | } |
124 | 124 | ||
125 | /* This function was part of the original alac decoder implementation */ | 125 | /* Check if there is a dedicated byte position contained for the given frame. |
126 | 126 | * Return this byte position in case of success or return -1. This allows to | |
127 | int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, | 127 | * skip empty samples. */ |
128 | uint32_t *sample_duration, | 128 | int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame) |
129 | uint32_t *sample_byte_size) | ||
130 | { | 129 | { |
131 | unsigned int duration_index_accum = 0; | 130 | uint32_t i = 0; |
132 | unsigned int duration_cur_index = 0; | 131 | for (i=0; i<demux_res->num_lookup_table; ++i) |
133 | 132 | { | |
134 | if (samplenum >= demux_res->num_sample_byte_sizes) { | 133 | if (demux_res->lookup_table[i].sample > frame || |
135 | return 0; | 134 | demux_res->lookup_table[i].offset == 0) |
136 | } | 135 | return -1; |
137 | 136 | if (demux_res->lookup_table[i].sample == frame) | |
138 | if (!demux_res->num_time_to_samples) { | 137 | break; |
139 | return 0; | ||
140 | } | ||
141 | |||
142 | while ((demux_res->time_to_sample[duration_cur_index].sample_count | ||
143 | + duration_index_accum) <= samplenum) { | ||
144 | duration_index_accum += | ||
145 | demux_res->time_to_sample[duration_cur_index].sample_count; | ||
146 | |||
147 | duration_cur_index++; | ||
148 | if (duration_cur_index >= demux_res->num_time_to_samples) { | ||
149 | return 0; | ||
150 | } | ||
151 | } | 138 | } |
152 | 139 | return demux_res->lookup_table[i].offset; | |
153 | *sample_duration = | ||
154 | demux_res->time_to_sample[duration_cur_index].sample_duration; | ||
155 | *sample_byte_size = demux_res->sample_byte_size[samplenum]; | ||
156 | |||
157 | return 1; | ||
158 | } | 140 | } |
159 | 141 | ||
160 | unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample) | 142 | /* Find the exact or preceding frame in lookup_table[]. Return both frame |
143 | * and byte position of this match. */ | ||
144 | static void gather_offset(demux_res_t *demux_res, uint32_t *frame, uint32_t *offset) | ||
161 | { | 145 | { |
162 | uint32_t chunk = 1; | 146 | uint32_t i = 0; |
163 | uint32_t range_samples = 0; | 147 | for (i=0; i<demux_res->num_lookup_table; ++i) |
164 | uint32_t total_samples = 0; | ||
165 | uint32_t chunk_sample; | ||
166 | uint32_t prev_chunk; | ||
167 | uint32_t prev_chunk_samples; | ||
168 | uint32_t file_offset; | ||
169 | uint32_t i; | ||
170 | |||
171 | /* First check we have the appropriate metadata - we should always | ||
172 | * have it. | ||
173 | */ | ||
174 | |||
175 | if (sample >= demux_res->num_sample_byte_sizes || | ||
176 | !demux_res->num_sample_to_chunks || | ||
177 | !demux_res->num_chunk_offsets) | ||
178 | { | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* Locate the chunk containing the sample */ | ||
183 | |||
184 | prev_chunk = demux_res->sample_to_chunk[0].first_chunk; | ||
185 | prev_chunk_samples = demux_res->sample_to_chunk[0].num_samples; | ||
186 | |||
187 | for (i = 1; i < demux_res->num_sample_to_chunks; i++) | ||
188 | { | 148 | { |
189 | chunk = demux_res->sample_to_chunk[i].first_chunk; | 149 | if (demux_res->lookup_table[i].offset == 0) |
190 | range_samples = (chunk - prev_chunk) * prev_chunk_samples; | 150 | break; |
191 | 151 | if (demux_res->lookup_table[i].sample > *frame) | |
192 | if (sample < total_samples + range_samples) | ||
193 | { | ||
194 | break; | 152 | break; |
195 | } | ||
196 | |||
197 | total_samples += range_samples; | ||
198 | prev_chunk = demux_res->sample_to_chunk[i].first_chunk; | ||
199 | prev_chunk_samples = demux_res->sample_to_chunk[i].num_samples; | ||
200 | } | ||
201 | |||
202 | if (prev_chunk_samples > 0 && | ||
203 | sample >= demux_res->sample_to_chunk[0].num_samples) | ||
204 | { | ||
205 | chunk = prev_chunk + (sample - total_samples) / prev_chunk_samples; | ||
206 | } | ||
207 | else | ||
208 | { | ||
209 | chunk = 1; | ||
210 | } | ||
211 | |||
212 | /* Get sample of the first sample in the chunk */ | ||
213 | |||
214 | chunk_sample = total_samples + (chunk - prev_chunk) * prev_chunk_samples; | ||
215 | |||
216 | /* Get offset in file */ | ||
217 | |||
218 | if (chunk > demux_res->num_chunk_offsets) | ||
219 | { | ||
220 | file_offset = demux_res->chunk_offset[demux_res->num_chunk_offsets - 1]; | ||
221 | } | ||
222 | else | ||
223 | { | ||
224 | file_offset = demux_res->chunk_offset[chunk - 1]; | ||
225 | } | ||
226 | |||
227 | if (chunk_sample > sample) | ||
228 | { | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | for (i = chunk_sample; i < sample; i++) | ||
233 | { | ||
234 | file_offset += demux_res->sample_byte_size[i]; | ||
235 | } | ||
236 | |||
237 | if (file_offset > demux_res->mdat_offset + demux_res->mdat_len) | ||
238 | { | ||
239 | return 0; | ||
240 | } | 153 | } |
241 | 154 | i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ *frame. */ | |
242 | return file_offset; | 155 | *frame = demux_res->lookup_table[i].sample; |
156 | *offset = demux_res->lookup_table[i].offset; | ||
243 | } | 157 | } |
244 | 158 | ||
245 | /* Seek to the sample containing sound_sample_loc. Return 1 on success | 159 | /* Seek to desired sound sample location. Return 1 on success (and modify |
246 | * (and modify sound_samples_done and current_sample), 0 if failed. | 160 | * sound_samples_done and current_sample), 0 if failed. |
247 | * | ||
248 | * Seeking uses the following arrays: | ||
249 | * | ||
250 | * 1) the time_to_sample array contains the duration (in sound samples) | ||
251 | * of each sample of data. | ||
252 | * | ||
253 | * 2) the sample_byte_size array contains the length in bytes of each | ||
254 | * sample. | ||
255 | * | ||
256 | * 3) the sample_to_chunk array contains information about which chunk | ||
257 | * of samples each sample belongs to. | ||
258 | * | ||
259 | * 4) the chunk_offset array contains the file offset of each chunk. | ||
260 | * | ||
261 | * So find the sample number we are going to seek to (using time_to_sample) | ||
262 | * and then find the offset in the file (using sample_to_chunk, | ||
263 | * chunk_offset sample_byte_size, in that order.). | ||
264 | * | 161 | * |
265 | */ | 162 | * Find the sample (=frame) that contains the given sound sample, find a best |
266 | unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream, | 163 | * fit for this sample in the lookup_table[], seek to the byte position. */ |
164 | unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream, | ||
267 | uint32_t sound_sample_loc, uint32_t* sound_samples_done, | 165 | uint32_t sound_sample_loc, uint32_t* sound_samples_done, |
268 | int* current_sample) | 166 | int* current_sample) |
269 | { | 167 | { |
@@ -300,8 +198,8 @@ unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream, | |||
300 | ++i; | 198 | ++i; |
301 | } | 199 | } |
302 | 200 | ||
303 | /* We know the new block, now calculate the file position. */ | 201 | /* We know the new sample (=frame), now calculate the file position. */ |
304 | new_pos = get_sample_offset(demux_res, new_sample); | 202 | gather_offset(demux_res, &new_sample, &new_pos); |
305 | 203 | ||
306 | /* We know the new file position, so let's try to seek to it */ | 204 | /* We know the new file position, so let's try to seek to it */ |
307 | if (stream->ci->seek_buffer(new_pos)) | 205 | if (stream->ci->seek_buffer(new_pos)) |
@@ -319,71 +217,38 @@ unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream, | |||
319 | * | 217 | * |
320 | * Seeking uses the following arrays: | 218 | * Seeking uses the following arrays: |
321 | * | 219 | * |
322 | * 1) the chunk_offset array contains the file offset of each chunk. | 220 | * 1) the lookup_table array contains the file offset for the first sample |
323 | * | 221 | * of each chunk. |
324 | * 2) the sample_to_chunk array contains information about which chunk | ||
325 | * of samples each sample belongs to. | ||
326 | * | ||
327 | * 3) the sample_byte_size array contains the length in bytes of each | ||
328 | * sample. | ||
329 | * | 222 | * |
330 | * 4) the time_to_sample array contains the duration (in sound samples) | 223 | * 2) the time_to_sample array contains the duration (in sound samples) |
331 | * of each sample of data. | 224 | * of each sample of data. |
332 | * | 225 | * |
333 | * Locate the chunk containing location (using chunk_offset), find the | 226 | * Locate the chunk containing location (using lookup_table), find the first |
334 | * sample of that chunk (using sample_to_chunk) and finally the location | 227 | * sample of that chunk (using lookup_table). Then use time_to_sample to |
335 | * of that sample (using sample_byte_size). Then use time_to_sample to | ||
336 | * calculate the sound_samples_done value. | 228 | * calculate the sound_samples_done value. |
337 | */ | 229 | */ |
338 | unsigned int alac_seek_raw(demux_res_t* demux_res, stream_t* stream, | 230 | unsigned int m4a_seek_raw(demux_res_t* demux_res, stream_t* stream, |
339 | uint32_t file_loc, uint32_t* sound_samples_done, | 231 | uint32_t file_loc, uint32_t* sound_samples_done, |
340 | int* current_sample) | 232 | int* current_sample) |
341 | { | 233 | { |
342 | uint32_t chunk_sample = 0; /* Holds the chunk/frame index. */ | 234 | uint32_t i; |
343 | uint32_t total_samples = 0; /* Sums up total amount of chunks/frames. */ | 235 | uint32_t chunk_sample = 0; |
344 | uint32_t new_sound_sample = 0; /* Sums up total amount of samples. */ | 236 | uint32_t total_samples = 0; |
237 | uint32_t new_sound_sample = 0; | ||
238 | uint32_t tmp_dur; | ||
239 | uint32_t tmp_cnt; | ||
345 | uint32_t new_pos; | 240 | uint32_t new_pos; |
346 | uint32_t chunk; | ||
347 | uint32_t i, tmp_dur, tmp_cnt; | ||
348 | |||
349 | /* There is no metadata available to perform raw seek. */ | ||
350 | if (!demux_res->num_chunk_offsets || !demux_res->num_sample_to_chunks) | ||
351 | { | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /* Locate the chunk containing file_loc. */ | ||
356 | chunk = 0; | ||
357 | while (chunk < demux_res->num_chunk_offsets) | ||
358 | { | ||
359 | if (file_loc < demux_res->chunk_offset[chunk]) | ||
360 | { | ||
361 | break; | ||
362 | } | ||
363 | ++chunk; | ||
364 | } | ||
365 | new_pos = demux_res->chunk_offset[chunk > 0 ? chunk - 1 : 0]; | ||
366 | 241 | ||
367 | /* Get the first sample of the chunk. */ | 242 | /* We know the desired byte offset, search for the chunk right before. |
368 | i = 1; | 243 | * Return the associated sample to this chunk as chunk_sample. */ |
369 | sample_to_chunk_t *tab1 = demux_res->sample_to_chunk; | 244 | for (i=0; i < demux_res->num_lookup_table; ++i) |
370 | while (i < demux_res->num_sample_to_chunks) | ||
371 | { | 245 | { |
372 | if (chunk <= tab1[i].first_chunk) | 246 | if (demux_res->lookup_table[i].offset > file_loc) |
373 | { | ||
374 | break; | 247 | break; |
375 | } | ||
376 | chunk_sample += tab1[i-1].num_samples * (tab1[i].first_chunk - tab1[i-1].first_chunk); | ||
377 | ++i; | ||
378 | } | ||
379 | chunk_sample += (chunk - tab1[i-1].first_chunk) * tab1[i-1].num_samples; | ||
380 | |||
381 | /* Get the position within the chunk. */ | ||
382 | while (chunk_sample < demux_res->num_sample_byte_sizes && | ||
383 | file_loc >= new_pos + demux_res->sample_byte_size[chunk_sample]) | ||
384 | { | ||
385 | new_pos += demux_res->sample_byte_size[chunk_sample++]; | ||
386 | } | 248 | } |
249 | i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ file_loc. */ | ||
250 | chunk_sample = demux_res->lookup_table[i].sample; | ||
251 | new_pos = demux_res->lookup_table[i].offset; | ||
387 | 252 | ||
388 | /* Get sound sample offset. */ | 253 | /* Get sound sample offset. */ |
389 | i = 0; | 254 | i = 0; |
diff --git a/apps/codecs/libm4a/m4a.h b/apps/codecs/libm4a/m4a.h index 2b361e8784..e49d14b832 100644 --- a/apps/codecs/libm4a/m4a.h +++ b/apps/codecs/libm4a/m4a.h | |||
@@ -59,6 +59,12 @@ typedef struct | |||
59 | 59 | ||
60 | typedef struct | 60 | typedef struct |
61 | { | 61 | { |
62 | uint32_t sample; | ||
63 | uint32_t offset; | ||
64 | } sample_offset_t; | ||
65 | |||
66 | typedef struct | ||
67 | { | ||
62 | uint16_t num_channels; | 68 | uint16_t num_channels; |
63 | uint16_t sound_sample_size; | 69 | uint16_t sound_sample_size; |
64 | uint32_t sound_sample_rate; | 70 | uint32_t sound_sample_rate; |
@@ -68,13 +74,12 @@ typedef struct | |||
68 | sample_to_chunk_t *sample_to_chunk; | 74 | sample_to_chunk_t *sample_to_chunk; |
69 | uint32_t num_sample_to_chunks; | 75 | uint32_t num_sample_to_chunks; |
70 | 76 | ||
71 | uint32_t *chunk_offset; | 77 | sample_offset_t *lookup_table; |
72 | uint32_t num_chunk_offsets; | 78 | uint32_t num_lookup_table; |
73 | 79 | ||
74 | time_to_sample_t *time_to_sample; | 80 | time_to_sample_t *time_to_sample; |
75 | uint32_t num_time_to_samples; | 81 | uint32_t num_time_to_samples; |
76 | 82 | ||
77 | uint16_t *sample_byte_size; | ||
78 | uint32_t num_sample_byte_sizes; | 83 | uint32_t num_sample_byte_sizes; |
79 | 84 | ||
80 | uint32_t codecdata_len; | 85 | uint32_t codecdata_len; |
@@ -127,10 +132,11 @@ void stream_create(stream_t *stream,struct codec_api* ci); | |||
127 | int get_sample_info(demux_res_t *demux_res, uint32_t sample, | 132 | int get_sample_info(demux_res_t *demux_res, uint32_t sample, |
128 | uint32_t *sample_duration, uint32_t *sample_byte_size); | 133 | uint32_t *sample_duration, uint32_t *sample_byte_size); |
129 | unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample); | 134 | unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample); |
130 | unsigned int alac_seek (demux_res_t* demux_res, stream_t* stream, | 135 | unsigned int m4a_seek (demux_res_t* demux_res, stream_t* stream, |
131 | uint32_t sound_sample_loc, uint32_t* sound_samples_done, | 136 | uint32_t sound_sample_loc, uint32_t* sound_samples_done, |
132 | int* current_sample); | 137 | int* current_sample); |
133 | unsigned int alac_seek_raw (demux_res_t* demux_res, stream_t* stream, | 138 | unsigned int m4a_seek_raw (demux_res_t* demux_res, stream_t* stream, |
134 | uint32_t file_loc, uint32_t* sound_samples_done, int* current_sample); | 139 | uint32_t file_loc, uint32_t* sound_samples_done, int* current_sample); |
140 | int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame); | ||
135 | 141 | ||
136 | #endif /* STREAM_H */ | 142 | #endif /* STREAM_H */ |