summaryrefslogtreecommitdiff
path: root/apps/codecs/libm4a/m4a.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libm4a/m4a.c')
-rw-r--r--apps/codecs/libm4a/m4a.c380
1 files changed, 258 insertions, 122 deletions
diff --git a/apps/codecs/libm4a/m4a.c b/apps/codecs/libm4a/m4a.c
index f914f4e4d1..0a87ec35ea 100644
--- a/apps/codecs/libm4a/m4a.c
+++ b/apps/codecs/libm4a/m4a.c
@@ -21,6 +21,13 @@
21#include <inttypes.h> 21#include <inttypes.h>
22#include "m4a.h" 22#include "m4a.h"
23 23
24#if defined(DEBUG) || defined(SIMULATOR)
25extern struct codec_api* rb;
26#define DEBUGF rb->debugf
27#else
28#define DEBUGF(...)
29#endif
30
24/* Implementation of the stream.h functions used by libalac */ 31/* Implementation of the stream.h functions used by libalac */
25 32
26#define _Swap32(v) do { \ 33#define _Swap32(v) do { \
@@ -101,15 +108,7 @@ uint8_t stream_read_uint8(stream_t *stream)
101 108
102void stream_skip(stream_t *stream, size_t skip) 109void stream_skip(stream_t *stream, size_t skip)
103{ 110{
104 (void)stream; 111 stream->ci->advance_buffer(skip);
105#if 1
106 char buf;
107 while (skip > 0) {
108 stream->ci->read_filebuf(&buf,1);
109 skip--;
110 }
111#endif
112 //stream->ci->advance_buffer(skip);
113} 112}
114 113
115int stream_eof(stream_t *stream) 114int stream_eof(stream_t *stream)
@@ -158,136 +157,273 @@ int get_sample_info(demux_res_t *demux_res, uint32_t samplenum,
158 return 1; 157 return 1;
159} 158}
160 159
161/* Seek to sample_loc (or close to it). Return 1 on success (and 160unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample)
162 modify samplesdone and currentblock), 0 if failed 161{
162 uint32_t chunk = 1;
163 uint32_t range_samples = 0;
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 }
163 181
164 Seeking uses the following two arrays: 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;
165 186
166 1) the sample_byte_size array contains the length in bytes of 187 for (i = 1; i < demux_res->num_sample_to_chunks; i++)
167 each block ("sample" in Applespeak). 188 {
189 chunk = demux_res->sample_to_chunk[i].first_chunk;
190 range_samples = (chunk - prev_chunk) * prev_chunk_samples;
168 191
169 2) the time_to_sample array contains the duration (in samples) of 192 if (sample < total_samples + range_samples)
170 each block of data. 193 {
194 break;
195 }
171 196
172 So we just find the block number we are going to seek to (using 197 total_samples += range_samples;
173 time_to_sample) and then find the offset in the file (using 198 prev_chunk = demux_res->sample_to_chunk[i].first_chunk;
174 sample_byte_size). 199 prev_chunk_samples = demux_res->sample_to_chunk[i].num_samples;
200 }
175 201
176 Each ALAC block seems to be independent of all the others. 202 if (demux_res->num_sample_to_chunks > 1)
177 */ 203 {
204 chunk = prev_chunk + (sample - total_samples) / prev_chunk_samples;
205 }
206 else
207 {
208 chunk = 1;
209 }
210
211 /* Get sample of the first sample in the chunk */
212
213 chunk_sample = total_samples + (chunk - prev_chunk) * prev_chunk_samples;
214
215 /* Get offset in file */
216
217 if (chunk > demux_res->num_chunk_offsets)
218 {
219 file_offset = demux_res->chunk_offset[demux_res->num_chunk_offsets - 1];
220 }
221 else
222 {
223 file_offset = demux_res->chunk_offset[chunk - 1];
224 }
225
226 if (chunk_sample > sample) {
227 return 0;
228 }
229
230 for (i = chunk_sample; i < sample; i++)
231 {
232 file_offset += demux_res->sample_byte_size[i];
233 }
234
235 if (file_offset > demux_res->mdat_offset + demux_res->mdat_len)
236 {
237 return 0;
238 }
239
240 return file_offset;
241}
178 242
179unsigned int alac_seek (demux_res_t* demux_res, 243/* Seek to the sample containing sound_sample_loc. Return 1 on success
180 stream_t* stream, 244 * (and modify sound_samples_done and current_sample), 0 if failed.
181 unsigned int sample_loc, 245 *
182 uint32_t* samplesdone, int* currentblock) 246 * Seeking uses the following arrays:
247 *
248 * 1) the time_to_sample array contains the duration (in sound samples)
249 * of each sample of data.
250 *
251 * 2) the sample_byte_size array contains the length in bytes of each
252 * sample.
253 *
254 * 3) the sample_to_chunk array contains information about which chunk
255 * of samples each sample belongs to.
256 *
257 * 4) the chunk_offset array contains the file offset of each chunk.
258 *
259 * So find the sample number we are going to seek to (using time_to_sample)
260 * and then find the offset in the file (using sample_to_chunk,
261 * chunk_offset sample_byte_size, in that order.).
262 *
263 */
264unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream,
265 uint32_t sound_sample_loc, uint32_t* sound_samples_done,
266 int* current_sample)
183{ 267{
184 int flag; 268 uint32_t i;
185 unsigned int i,j; 269 uint32_t j;
186 unsigned int newblock; 270 uint32_t new_sample;
187 unsigned int newsample; 271 uint32_t new_sound_sample;
188 unsigned int newpos; 272 uint32_t new_pos;
189 273
190 /* First check we have the appropriate metadata - we should always 274 /* First check we have the appropriate metadata - we should always
191 have it. */ 275 * have it.
192 if ((demux_res->num_time_to_samples==0) || 276 */
193 (demux_res->num_sample_byte_sizes==0)) { return 0; } 277
194 278 if ((demux_res->num_time_to_samples==0) ||
195 /* Find the destination block from time_to_sample array */ 279 (demux_res->num_sample_byte_sizes==0))
196 i=0; 280 {
197 newblock=0; 281 return 0;
198 newsample=0; 282 }
199 flag=0; 283
200 284 /* Find the destination block from time_to_sample array */
201 while ((i<demux_res->num_time_to_samples) && (flag==0) &&
202 (newsample < sample_loc)) {
203 j=(sample_loc-newsample) /
204 demux_res->time_to_sample[i].sample_duration;
205 285
206 if (j <= demux_res->time_to_sample[i].sample_count) { 286 i = 0;
207 newblock+=j; 287 new_sample = 0;
208 newsample+=j*demux_res->time_to_sample[i].sample_duration; 288 new_sound_sample = 0;
209 flag=1; 289
210 } else { 290 while ((i < demux_res->num_time_to_samples) &&
211 newsample+=(demux_res->time_to_sample[i].sample_duration 291 (new_sound_sample < sound_sample_loc))
212 * demux_res->time_to_sample[i].sample_count); 292 {
213 newblock+=demux_res->time_to_sample[i].sample_count; 293 j = (sound_sample_loc - new_sound_sample) /
214 i++; 294 demux_res->time_to_sample[i].sample_duration;
295
296 if (j <= demux_res->time_to_sample[i].sample_count)
297 {
298 new_sample += j;
299 new_sound_sample += j *
300 demux_res->time_to_sample[i].sample_duration;
301 break;
302 }
303 else
304 {
305 new_sound_sample += (demux_res->time_to_sample[i].sample_duration
306 * demux_res->time_to_sample[i].sample_count);
307 new_sample += demux_res->time_to_sample[i].sample_count;
308 i++;
309 }
215 } 310 }
216 } 311
217 312 /* We know the new block, now calculate the file position. */
218 /* We know the new block, now calculate the file position */ 313
219 newpos=demux_res->mdat_offset; 314 new_pos = get_sample_offset(demux_res, new_sample);
220 for (i=0;i<newblock;i++) { 315
221 newpos+=demux_res->sample_byte_size[i]; 316 /* We know the new file position, so let's try to seek to it */
222 } 317
223 318 if (stream->ci->seek_buffer(new_pos))
224 /* We know the new file position, so let's try to seek to it */ 319 {
225 if (stream->ci->seek_buffer(newpos)) { 320 *sound_samples_done = new_sound_sample;
226 *samplesdone=newsample; 321 *current_sample = new_sample;
227 *currentblock=newblock; 322 return 1;
228 return 1; 323 }
229 } else { 324
230 return 0; 325 return 0;
231 }
232} 326}
233 327
234/* Seek to file_loc (or close to it). Return 1 on success (and 328/* Seek to the sample containing file_loc. Return 1 on success (and modify
235 modify samplesdone and currentblock), 0 if failed 329 * sound_samples_done and current_sample), 0 if failed.
236 330 *
237 Seeking uses the following array: 331 * Seeking uses the following arrays:
332 *
333 * 1) the chunk_offset array contains the file offset of each chunk.
334 *
335 * 2) the sample_to_chunk array contains information about which chunk
336 * of samples each sample belongs to.
337 *
338 * 3) the sample_byte_size array contains the length in bytes of each
339 * sample.
340 *
341 * 4) the time_to_sample array contains the duration (in sound samples)
342 * of each sample of data.
343 *
344 * Locate the chunk containing location (using chunk_offset), find the
345 * sample of that chunk (using sample_to_chunk) and finally the location
346 * of that sample (using sample_byte_size). Then use time_to_sample to
347 * calculate the sound_samples_done value.
348 */
349unsigned int alac_seek_raw(demux_res_t* demux_res, stream_t* stream,
350 uint32_t file_loc, uint32_t* sound_samples_done,
351 int* current_sample)
352{
353 uint32_t chunk_sample = 0;
354 uint32_t total_samples = 0;
355 uint32_t new_sound_sample = 0;
356 uint32_t new_pos;
357 uint32_t chunk;
358 uint32_t i;
359
360 if (!demux_res->num_chunk_offsets ||
361 !demux_res->num_sample_to_chunks)
362 {
363 return 0;
364 }
238 365
239 the sample_byte_size array contains the length in bytes of 366 /* Locate the chunk containing file_loc. */
240 each block ("sample" in Applespeak).
241 367
242 So we just find the last block before (or at) the requested position. 368 for (i = 0; i < demux_res->num_chunk_offsets &&
369 file_loc < demux_res->chunk_offset[i]; i++)
370 {
371 }
372
373 chunk = i + 1;
374 new_pos = demux_res->chunk_offset[chunk - 1];
243 375
244 Each ALAC block seems to be independent of all the others. 376 /* Get the first sample of the chunk. */
245 */ 377
378 for (i = 1; i < demux_res->num_sample_to_chunks &&
379 chunk < demux_res->sample_to_chunk[i - 1].first_chunk; i++)
380 {
381 chunk_sample += demux_res->sample_to_chunk[i - 1].num_samples *
382 (demux_res->sample_to_chunk[i].first_chunk -
383 demux_res->sample_to_chunk[i - 1].first_chunk);
384 }
385
386 chunk_sample += (chunk - demux_res->sample_to_chunk[i - 1].first_chunk) *
387 demux_res->sample_to_chunk[i - 1].num_samples;
246 388
247unsigned int alac_seek_raw (demux_res_t* demux_res, 389 /* Get the position within the chunk. */
248 stream_t* stream, 390
249 unsigned int file_loc, 391 for (; chunk_sample < demux_res->num_sample_byte_sizes; chunk_sample++)
250 uint32_t* samplesdone, int* currentblock) 392 {
251{ 393 if (file_loc < new_pos + demux_res->sample_byte_size[chunk_sample])
252 unsigned int i; 394 {
253 unsigned int j; 395 break;
254 unsigned int newblock; 396 }
255 unsigned int newsample; 397
256 unsigned int newpos; 398 new_pos += demux_res->sample_byte_size[chunk_sample];
257 399 }
258 /* First check we have the appropriate metadata - we should always 400
259 have it. */ 401 /* Get sound sample offset. */
260 if ((demux_res->num_time_to_samples==0) || 402
261 (demux_res->num_sample_byte_sizes==0)) { return 0; } 403 for (i = 0; i < demux_res->num_time_to_samples; i++)
262 404 {
263 /* Find the destination block from the sample_byte_size array. */ 405 if (chunk_sample <
264 newpos=demux_res->mdat_offset; 406 total_samples + demux_res->time_to_sample[i].sample_count)
265 for (i=0;(i<demux_res->num_sample_byte_sizes) && 407 {
266 (newpos+demux_res->sample_byte_size[i]<=file_loc);i++) { 408 break;
267 newpos+=demux_res->sample_byte_size[i]; 409 }
268 } 410
269 411 total_samples += demux_res->time_to_sample[i].sample_count;
270 newblock=i; 412 new_sound_sample += demux_res->time_to_sample[i].sample_count
271 newsample=0; 413 * demux_res->time_to_sample[i].sample_duration;
272
273 /* Get the sample offset of the block */
274 for (i=0,j=0;(i<demux_res->num_time_to_samples) && (j<newblock);
275 i++,j+=demux_res->time_to_sample[i].sample_count) {
276 if (newblock-j < demux_res->time_to_sample[i].sample_count) {
277 newsample+=(newblock-j)*demux_res->time_to_sample[i].sample_duration;
278 break;
279 } else {
280 newsample+=(demux_res->time_to_sample[i].sample_duration
281 * demux_res->time_to_sample[i].sample_count);
282 } 414 }
283 } 415
416 new_sound_sample += (chunk_sample - total_samples)
417 * demux_res->time_to_sample[i].sample_duration;
418
419 /* Go to the new file position. */
420
421 if (stream->ci->seek_buffer(new_pos))
422 {
423 *sound_samples_done = new_sound_sample;
424 *current_sample = chunk_sample;
425 return 1;
426 }
284 427
285 /* We know the new file position, so let's try to seek to it */
286 if (stream->ci->seek_buffer(newpos)) {
287 *samplesdone=newsample;
288 *currentblock=newblock;
289 return 1;
290 } else {
291 return 0; 428 return 0;
292 }
293} 429}