summaryrefslogtreecommitdiff
path: root/apps/codecs/libm4a
diff options
context:
space:
mode:
authorMagnus Holmgren <magnushol@gmail.com>2006-10-11 17:02:23 +0000
committerMagnus Holmgren <magnushol@gmail.com>2006-10-11 17:02:23 +0000
commit9896fd1adef70e77b2e226d5e44fabd23192266d (patch)
treeb006fed80eadb14e1d8849b8a4cc01263bbc47c2 /apps/codecs/libm4a
parentca3d872699d56905c7edf875fdec80472c832942 (diff)
downloadrockbox-9896fd1adef70e77b2e226d5e44fabd23192266d.tar.gz
rockbox-9896fd1adef70e77b2e226d5e44fabd23192266d.zip
AAC codec: Improved MP4 file parsing. Should now handle most streamable files. Also some code cleanup and policing.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11187 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libm4a')
-rw-r--r--apps/codecs/libm4a/demux.c155
-rw-r--r--apps/codecs/libm4a/m4a.c380
-rw-r--r--apps/codecs/libm4a/m4a.h32
3 files changed, 373 insertions, 194 deletions
diff --git a/apps/codecs/libm4a/demux.c b/apps/codecs/libm4a/demux.c
index 1beeced8e6..44261fdef6 100644
--- a/apps/codecs/libm4a/demux.c
+++ b/apps/codecs/libm4a/demux.c
@@ -55,12 +55,14 @@ static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len)
55{ 55{
56 fourcc_t type; 56 fourcc_t type;
57 uint32_t minor_ver; 57 uint32_t minor_ver;
58 size_t size_remaining = chunk_len - 8; /* FIXME: can't hardcode 8, size may be 64bit */ 58 size_t size_remaining = chunk_len - 8;
59 59
60 type = stream_read_uint32(qtmovie->stream); 60 type = stream_read_uint32(qtmovie->stream);
61 size_remaining-=4; 61 size_remaining-=4;
62 if ((type != MAKEFOURCC('M','4','A',' ')) && 62 if ((type != MAKEFOURCC('M','4','A',' ')) &&
63 (type != MAKEFOURCC('m','p','4','2'))) 63 (type != MAKEFOURCC('m','p','4','2')) &&
64 (type != MAKEFOURCC('3','g','p','6')) &&
65 (type != MAKEFOURCC('q','t',' ',' ')))
64 { 66 {
65 DEBUGF("not M4A file\n"); 67 DEBUGF("not M4A file\n");
66 return; 68 return;
@@ -80,7 +82,7 @@ static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len)
80static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len) 82static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len)
81{ 83{
82 /* don't need anything from here atm, skip */ 84 /* don't need anything from here atm, skip */
83 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 85 size_t size_remaining = chunk_len - 8;
84 86
85 stream_skip(qtmovie->stream, size_remaining); 87 stream_skip(qtmovie->stream, size_remaining);
86} 88}
@@ -88,7 +90,7 @@ static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len)
88static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len) 90static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len)
89{ 91{
90 /* don't need anything from here atm, skip */ 92 /* don't need anything from here atm, skip */
91 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 93 size_t size_remaining = chunk_len - 8;
92 94
93 stream_skip(qtmovie->stream, size_remaining); 95 stream_skip(qtmovie->stream, size_remaining);
94} 96}
@@ -97,7 +99,7 @@ static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len)
97static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len) 99static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len)
98{ 100{
99 fourcc_t comptype, compsubtype; 101 fourcc_t comptype, compsubtype;
100 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 102 size_t size_remaining = chunk_len - 8;
101 103
102 int strlen; 104 int strlen;
103 char str[256] = {0}; 105 char str[256] = {0};
@@ -196,7 +198,6 @@ static bool read_chunk_esds(qtmovie_t *qtmovie, size_t chunk_len)
196 temp=stream_read_int32(qtmovie->stream);//0x15000414 ???? 198 temp=stream_read_int32(qtmovie->stream);//0x15000414 ????
197 maxBitrate = stream_read_int32(qtmovie->stream); 199 maxBitrate = stream_read_int32(qtmovie->stream);
198 avgBitrate = stream_read_int32(qtmovie->stream); 200 avgBitrate = stream_read_int32(qtmovie->stream);
199
200 DEBUGF("audioType=%d, maxBitrate=%d, avgBitrate=%d\n",audioType,maxBitrate,avgBitrate); 201 DEBUGF("audioType=%d, maxBitrate=%d, avgBitrate=%d\n",audioType,maxBitrate,avgBitrate);
201 202
202 /* get and verify DecSpecificInfoTag */ 203 /* get and verify DecSpecificInfoTag */
@@ -224,7 +225,7 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
224 unsigned int i; 225 unsigned int i;
225 int j; 226 int j;
226 uint32_t numentries; 227 uint32_t numentries;
227 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 228 size_t size_remaining = chunk_len - 8;
228 229
229 /* version */ 230 /* version */
230 stream_read_uint8(qtmovie->stream); 231 stream_read_uint8(qtmovie->stream);
@@ -247,7 +248,6 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
247 for (i = 0; i < numentries; i++) 248 for (i = 0; i < numentries; i++)
248 { 249 {
249 uint32_t entry_size; 250 uint32_t entry_size;
250 uint16_t version;
251 251
252 uint32_t entry_remaining; 252 uint32_t entry_remaining;
253 253
@@ -259,43 +259,20 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
259 259
260 /* sound info: */ 260 /* sound info: */
261 261
262 stream_skip(qtmovie->stream, 6); /* reserved */ 262 /* reserved + data reference index + sound version + reserved */
263 entry_remaining -= 6; 263 stream_skip(qtmovie->stream, 6 + 2 + 2 + 6);
264 264 entry_remaining -= 6 + 2 + 2 + 6;
265 version = stream_read_uint16(qtmovie->stream);
266 // if (version != 1)
267 //fprintf(stderr, "unknown version??\n");
268 entry_remaining -= 2;
269
270 /* revision level */
271 stream_read_uint16(qtmovie->stream);
272 /* vendor */
273 stream_read_uint32(qtmovie->stream);
274 entry_remaining -= 6;
275
276 /* EH?? spec doesn't say theres an extra 16 bits here.. but there is! */
277 stream_read_uint16(qtmovie->stream);
278 entry_remaining -= 2;
279 265
280 qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream); 266 qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream);
281 267 qtmovie->res->sound_sample_size = stream_read_uint16(qtmovie->stream);
282 qtmovie->res->sample_size = stream_read_uint16(qtmovie->stream);
283 entry_remaining -= 4; 268 entry_remaining -= 4;
284 269
285 /* compression id */
286 stream_read_uint16(qtmovie->stream);
287 /* packet size */ 270 /* packet size */
288 stream_read_uint16(qtmovie->stream);
289 entry_remaining -= 4;
290
291 /* sample rate - 32bit fixed point = 16bit?? */
292 qtmovie->res->sample_rate = stream_read_uint16(qtmovie->stream);
293 entry_remaining -= 2;
294
295 /* skip 2 */
296 stream_skip(qtmovie->stream, 2); 271 stream_skip(qtmovie->stream, 2);
297 entry_remaining -= 2; 272 qtmovie->res->sound_sample_rate = stream_read_uint32(qtmovie->stream);
298 273 /* reserved size */
274 stream_skip(qtmovie->stream, 2);
275 entry_remaining -= 8;
299 276
300 /* remaining is codec data */ 277 /* remaining is codec data */
301 278
@@ -372,7 +349,7 @@ static void read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
372{ 349{
373 unsigned int i; 350 unsigned int i;
374 uint32_t numentries; 351 uint32_t numentries;
375 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 352 size_t size_remaining = chunk_len - 8;
376 353
377 /* version */ 354 /* version */
378 stream_read_uint8(qtmovie->stream); 355 stream_read_uint8(qtmovie->stream);
@@ -407,7 +384,7 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
407{ 384{
408 unsigned int i; 385 unsigned int i;
409 uint32_t numentries; 386 uint32_t numentries;
410 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 387 size_t size_remaining = chunk_len - 8;
411 388
412 /* version */ 389 /* version */
413 stream_read_uint8(qtmovie->stream); 390 stream_read_uint8(qtmovie->stream);
@@ -447,9 +424,73 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
447 } 424 }
448} 425}
449 426
427static void read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len)
428{
429 unsigned int i;
430 uint32_t numentries;
431 size_t size_remaining = chunk_len - 8;
432
433 /* version + flags */
434 stream_read_uint32(qtmovie->stream);
435 size_remaining -= 4;
436
437 numentries = stream_read_uint32(qtmovie->stream);
438 size_remaining -= 4;
439
440 qtmovie->res->num_sample_to_chunks = numentries;
441 qtmovie->res->sample_to_chunk = malloc(numentries *
442 sizeof(*qtmovie->res->sample_to_chunk));
443
444 for (i = 0; i < numentries; i++)
445 {
446 qtmovie->res->sample_to_chunk[i].first_chunk =
447 stream_read_uint32(qtmovie->stream);
448 qtmovie->res->sample_to_chunk[i].num_samples =
449 stream_read_uint32(qtmovie->stream);
450 stream_read_uint32(qtmovie->stream);
451 size_remaining -= 12;
452 }
453
454 if (size_remaining)
455 {
456 DEBUGF("ehm, size remianing?\n");
457 stream_skip(qtmovie->stream, size_remaining);
458 }
459}
460
461static void read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
462{
463 unsigned int i;
464 uint32_t numentries;
465 size_t size_remaining = chunk_len - 8;
466
467 /* version + flags */
468 stream_read_uint32(qtmovie->stream);
469 size_remaining -= 4;
470
471 numentries = stream_read_uint32(qtmovie->stream);
472 size_remaining -= 4;
473
474 qtmovie->res->num_chunk_offsets = numentries;
475 qtmovie->res->chunk_offset = malloc(numentries *
476 sizeof(*qtmovie->res->chunk_offset));
477
478 for (i = 0; i < numentries; i++)
479 {
480 qtmovie->res->chunk_offset[i] = stream_read_uint32(qtmovie->stream);
481 size_remaining -= 4;
482 }
483
484 if (size_remaining)
485 {
486 DEBUGF("ehm, size remianing?\n");
487 stream_skip(qtmovie->stream, size_remaining);
488 }
489}
490
450static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) 491static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
451{ 492{
452 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 493 size_t size_remaining = chunk_len - 8;
453 494
454 while (size_remaining) 495 while (size_remaining)
455 { 496 {
@@ -479,14 +520,15 @@ static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
479 read_chunk_stsz(qtmovie, sub_chunk_len); 520 read_chunk_stsz(qtmovie, sub_chunk_len);
480 break; 521 break;
481 case MAKEFOURCC('s','t','s','c'): 522 case MAKEFOURCC('s','t','s','c'):
523 read_chunk_stsc(qtmovie, sub_chunk_len);
524 break;
482 case MAKEFOURCC('s','t','c','o'): 525 case MAKEFOURCC('s','t','c','o'):
483 /* skip these, no indexing for us! */ 526 read_chunk_stco(qtmovie, sub_chunk_len);
484 stream_skip(qtmovie->stream, sub_chunk_len - 8);
485 break; 527 break;
486 default: 528 default:
487 DEBUGF("(stbl) unknown chunk id: %c%c%c%c\n", 529 DEBUGF("(stbl) unknown chunk id: %c%c%c%c\n",
488 SPLITFOURCC(sub_chunk_id)); 530 SPLITFOURCC(sub_chunk_id));
489 stream_skip(qtmovie->stream, sub_chunk_len - 8); /* FIXME not 8 */ 531 stream_skip(qtmovie->stream, sub_chunk_len - 8);
490 } 532 }
491 533
492 size_remaining -= sub_chunk_len; 534 size_remaining -= sub_chunk_len;
@@ -497,7 +539,7 @@ static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
497static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) 539static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len)
498{ 540{
499 size_t dinf_size, stbl_size; 541 size_t dinf_size, stbl_size;
500 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 542 size_t size_remaining = chunk_len - 8;
501 uint32_t i; 543 uint32_t i;
502 544
503 /**** SOUND HEADER CHUNK ****/ 545 /**** SOUND HEADER CHUNK ****/
@@ -553,7 +595,7 @@ static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len)
553 595
554static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len) 596static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len)
555{ 597{
556 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 598 size_t size_remaining = chunk_len - 8;
557 599
558 while (size_remaining) 600 while (size_remaining)
559 { 601 {
@@ -597,7 +639,7 @@ static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len)
597/* 'trak' - a movie track - contains other atoms */ 639/* 'trak' - a movie track - contains other atoms */
598static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len) 640static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len)
599{ 641{
600 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 642 size_t size_remaining = chunk_len - 8;
601 643
602 while (size_remaining) 644 while (size_remaining)
603 { 645 {
@@ -639,7 +681,7 @@ static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len)
639static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len) 681static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len)
640{ 682{
641 /* don't need anything from here atm, skip */ 683 /* don't need anything from here atm, skip */
642 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 684 size_t size_remaining = chunk_len - 8;
643 685
644 stream_skip(qtmovie->stream, size_remaining); 686 stream_skip(qtmovie->stream, size_remaining);
645} 687}
@@ -648,7 +690,7 @@ static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len)
648static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len) 690static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
649{ 691{
650 /* don't need anything from here atm, skip */ 692 /* don't need anything from here atm, skip */
651 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 693 size_t size_remaining = chunk_len - 8;
652 694
653 stream_skip(qtmovie->stream, size_remaining); 695 stream_skip(qtmovie->stream, size_remaining);
654} 696}
@@ -656,7 +698,7 @@ static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
656/* 'moov' movie atom - contains other atoms */ 698/* 'moov' movie atom - contains other atoms */
657static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) 699static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
658{ 700{
659 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 701 size_t size_remaining = chunk_len - 8;
660 702
661 while (size_remaining) 703 while (size_remaining)
662 { 704 {
@@ -688,7 +730,7 @@ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
688 default: 730 default:
689 DEBUGF("(moov) unknown chunk id: %c%c%c%c\n", 731 DEBUGF("(moov) unknown chunk id: %c%c%c%c\n",
690 SPLITFOURCC(sub_chunk_id)); 732 SPLITFOURCC(sub_chunk_id));
691 stream_skip(qtmovie->stream, sub_chunk_len - 8); /* FIXME not 8 */ 733 stream_skip(qtmovie->stream, sub_chunk_len - 8);
692 } 734 }
693 735
694 size_remaining -= sub_chunk_len; 736 size_remaining -= sub_chunk_len;
@@ -698,14 +740,9 @@ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
698 740
699static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len) 741static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len)
700{ 742{
701 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ 743 size_t size_remaining = chunk_len - 8;
702 744
703 qtmovie->res->mdat_len = size_remaining; 745 qtmovie->res->mdat_len = size_remaining;
704#if 0
705 qtmovie->res->mdat = malloc(size_remaining);
706
707 stream_read(qtmovie->stream, size_remaining, qtmovie->res->mdat);
708#endif
709} 746}
710 747
711int qtmovie_read(stream_t *file, demux_res_t *demux_res) 748int qtmovie_read(stream_t *file, demux_res_t *demux_res)
@@ -760,7 +797,7 @@ int qtmovie_read(stream_t *file, demux_res_t *demux_res)
760 797
761 /* these following atoms can be skipped !!!! */ 798 /* these following atoms can be skipped !!!! */
762 case MAKEFOURCC('f','r','e','e'): 799 case MAKEFOURCC('f','r','e','e'):
763 stream_skip(qtmovie.stream, chunk_len - 8); /* FIXME not 8 */ 800 stream_skip(qtmovie.stream, chunk_len - 8);
764 break; 801 break;
765 default: 802 default:
766 //DEBUGF("(top) unknown chunk id: %c%c%c%c\n",SPLITFOURCC(chunk_id)); 803 //DEBUGF("(top) unknown chunk id: %c%c%c%c\n",SPLITFOURCC(chunk_id));
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}
diff --git a/apps/codecs/libm4a/m4a.h b/apps/codecs/libm4a/m4a.h
index 7fea37513d..17f54c0146 100644
--- a/apps/codecs/libm4a/m4a.h
+++ b/apps/codecs/libm4a/m4a.h
@@ -33,12 +33,21 @@ typedef uint32_t fourcc_t;
33typedef struct 33typedef struct
34{ 34{
35 uint16_t num_channels; 35 uint16_t num_channels;
36 uint16_t sample_size; 36 uint16_t sound_sample_size;
37 uint32_t sample_rate; 37 uint32_t sound_sample_rate;
38 fourcc_t format; 38 fourcc_t format;
39 void *buf; 39 void *buf;
40 40
41 struct { 41 struct {
42 uint32_t first_chunk;
43 uint32_t num_samples;
44 } *sample_to_chunk;
45 uint32_t num_sample_to_chunks;
46
47 uint32_t *chunk_offset;
48 uint32_t num_chunk_offsets;
49
50 struct {
42 uint32_t sample_count; 51 uint32_t sample_count;
43 uint32_t sample_duration; 52 uint32_t sample_duration;
44 } *time_to_sample; 53 } *time_to_sample;
@@ -93,16 +102,13 @@ void stream_skip(stream_t *stream, size_t skip);
93int stream_eof(stream_t *stream); 102int stream_eof(stream_t *stream);
94 103
95void stream_create(stream_t *stream,struct codec_api* ci); 104void stream_create(stream_t *stream,struct codec_api* ci);
96int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, 105int get_sample_info(demux_res_t *demux_res, uint32_t sample,
97 uint32_t *sample_duration, 106 uint32_t *sample_duration, uint32_t *sample_byte_size);
98 uint32_t *sample_byte_size); 107unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample);
99unsigned int alac_seek (demux_res_t* demux_res, 108unsigned int alac_seek (demux_res_t* demux_res, stream_t* stream,
100 stream_t* stream, 109 uint32_t sound_sample_loc, uint32_t* sound_samples_done,
101 unsigned int sample_loc, 110 int* current_sample);
102 uint32_t* samplesdone, int* currentblock); 111unsigned int alac_seek_raw (demux_res_t* demux_res, stream_t* stream,
103unsigned int alac_seek_raw (demux_res_t* demux_res, 112 uint32_t file_loc, uint32_t* sound_samples_done, int* current_sample);
104 stream_t* stream,
105 unsigned int file_loc,
106 uint32_t* samplesdone, int* currentblock);
107 113
108#endif /* STREAM_H */ 114#endif /* STREAM_H */