diff options
author | Magnus Holmgren <magnushol@gmail.com> | 2006-10-11 17:02:23 +0000 |
---|---|---|
committer | Magnus Holmgren <magnushol@gmail.com> | 2006-10-11 17:02:23 +0000 |
commit | 9896fd1adef70e77b2e226d5e44fabd23192266d (patch) | |
tree | b006fed80eadb14e1d8849b8a4cc01263bbc47c2 /apps/codecs/libm4a | |
parent | ca3d872699d56905c7edf875fdec80472c832942 (diff) | |
download | rockbox-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.c | 155 | ||||
-rw-r--r-- | apps/codecs/libm4a/m4a.c | 380 | ||||
-rw-r--r-- | apps/codecs/libm4a/m4a.h | 32 |
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) | |||
80 | static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len) | 82 | static 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) | |||
88 | static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len) | 90 | static 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) | |||
97 | static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len) | 99 | static 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 | ||
427 | static 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 | |||
461 | static 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 | |||
450 | static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) | 491 | static 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) | |||
497 | static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) | 539 | static 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 | ||
554 | static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len) | 596 | static 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 */ |
598 | static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len) | 640 | static 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) | |||
639 | static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len) | 681 | static 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) | |||
648 | static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len) | 690 | static 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 */ |
657 | static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) | 699 | static 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 | ||
699 | static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len) | 741 | static 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 | ||
711 | int qtmovie_read(stream_t *file, demux_res_t *demux_res) | 748 | int 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) | ||
25 | extern 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 | ||
102 | void stream_skip(stream_t *stream, size_t skip) | 109 | void 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 | ||
115 | int stream_eof(stream_t *stream) | 114 | int 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 | 160 | unsigned 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 | ||
179 | unsigned 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 | */ | ||
264 | unsigned 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 | */ | ||
349 | unsigned 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 | ||
247 | unsigned 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; | |||
33 | typedef struct | 33 | typedef 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); | |||
93 | int stream_eof(stream_t *stream); | 102 | int stream_eof(stream_t *stream); |
94 | 103 | ||
95 | void stream_create(stream_t *stream,struct codec_api* ci); | 104 | void stream_create(stream_t *stream,struct codec_api* ci); |
96 | int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, | 105 | int 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); | 107 | unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample); |
99 | unsigned int alac_seek (demux_res_t* demux_res, | 108 | unsigned 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); | 111 | unsigned int alac_seek_raw (demux_res_t* demux_res, stream_t* stream, |
103 | unsigned 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 */ |