From 9896fd1adef70e77b2e226d5e44fabd23192266d Mon Sep 17 00:00:00 2001 From: Magnus Holmgren Date: Wed, 11 Oct 2006 17:02:23 +0000 Subject: 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 --- apps/codecs/libm4a/demux.c | 155 +++++++++++------- apps/codecs/libm4a/m4a.c | 380 ++++++++++++++++++++++++++++++--------------- apps/codecs/libm4a/m4a.h | 32 ++-- 3 files changed, 373 insertions(+), 194 deletions(-) (limited to 'apps/codecs/libm4a') 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) { fourcc_t type; uint32_t minor_ver; - size_t size_remaining = chunk_len - 8; /* FIXME: can't hardcode 8, size may be 64bit */ + size_t size_remaining = chunk_len - 8; type = stream_read_uint32(qtmovie->stream); size_remaining-=4; if ((type != MAKEFOURCC('M','4','A',' ')) && - (type != MAKEFOURCC('m','p','4','2'))) + (type != MAKEFOURCC('m','p','4','2')) && + (type != MAKEFOURCC('3','g','p','6')) && + (type != MAKEFOURCC('q','t',' ',' '))) { DEBUGF("not M4A file\n"); return; @@ -80,7 +82,7 @@ static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len) static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; stream_skip(qtmovie->stream, size_remaining); } @@ -88,7 +90,7 @@ static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len) static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; stream_skip(qtmovie->stream, size_remaining); } @@ -97,7 +99,7 @@ static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len) static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len) { fourcc_t comptype, compsubtype; - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; int strlen; char str[256] = {0}; @@ -196,7 +198,6 @@ static bool read_chunk_esds(qtmovie_t *qtmovie, size_t chunk_len) temp=stream_read_int32(qtmovie->stream);//0x15000414 ???? maxBitrate = stream_read_int32(qtmovie->stream); avgBitrate = stream_read_int32(qtmovie->stream); - DEBUGF("audioType=%d, maxBitrate=%d, avgBitrate=%d\n",audioType,maxBitrate,avgBitrate); /* get and verify DecSpecificInfoTag */ @@ -224,7 +225,7 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len) unsigned int i; int j; uint32_t numentries; - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; /* version */ stream_read_uint8(qtmovie->stream); @@ -247,7 +248,6 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len) for (i = 0; i < numentries; i++) { uint32_t entry_size; - uint16_t version; uint32_t entry_remaining; @@ -259,43 +259,20 @@ static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len) /* sound info: */ - stream_skip(qtmovie->stream, 6); /* reserved */ - entry_remaining -= 6; - - version = stream_read_uint16(qtmovie->stream); - // if (version != 1) - //fprintf(stderr, "unknown version??\n"); - entry_remaining -= 2; - - /* revision level */ - stream_read_uint16(qtmovie->stream); - /* vendor */ - stream_read_uint32(qtmovie->stream); - entry_remaining -= 6; - - /* EH?? spec doesn't say theres an extra 16 bits here.. but there is! */ - stream_read_uint16(qtmovie->stream); - entry_remaining -= 2; + /* reserved + data reference index + sound version + reserved */ + stream_skip(qtmovie->stream, 6 + 2 + 2 + 6); + entry_remaining -= 6 + 2 + 2 + 6; qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream); - - qtmovie->res->sample_size = stream_read_uint16(qtmovie->stream); + qtmovie->res->sound_sample_size = stream_read_uint16(qtmovie->stream); entry_remaining -= 4; - /* compression id */ - stream_read_uint16(qtmovie->stream); /* packet size */ - stream_read_uint16(qtmovie->stream); - entry_remaining -= 4; - - /* sample rate - 32bit fixed point = 16bit?? */ - qtmovie->res->sample_rate = stream_read_uint16(qtmovie->stream); - entry_remaining -= 2; - - /* skip 2 */ stream_skip(qtmovie->stream, 2); - entry_remaining -= 2; - + qtmovie->res->sound_sample_rate = stream_read_uint32(qtmovie->stream); + /* reserved size */ + stream_skip(qtmovie->stream, 2); + entry_remaining -= 8; /* remaining is codec data */ @@ -372,7 +349,7 @@ static void read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len) { unsigned int i; uint32_t numentries; - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; /* version */ stream_read_uint8(qtmovie->stream); @@ -407,7 +384,7 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) { unsigned int i; uint32_t numentries; - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; /* version */ stream_read_uint8(qtmovie->stream); @@ -447,9 +424,73 @@ static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) } } +static void read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len) +{ + unsigned int i; + uint32_t numentries; + size_t size_remaining = chunk_len - 8; + + /* version + flags */ + stream_read_uint32(qtmovie->stream); + size_remaining -= 4; + + numentries = stream_read_uint32(qtmovie->stream); + size_remaining -= 4; + + qtmovie->res->num_sample_to_chunks = numentries; + qtmovie->res->sample_to_chunk = malloc(numentries * + sizeof(*qtmovie->res->sample_to_chunk)); + + for (i = 0; i < numentries; i++) + { + qtmovie->res->sample_to_chunk[i].first_chunk = + stream_read_uint32(qtmovie->stream); + qtmovie->res->sample_to_chunk[i].num_samples = + stream_read_uint32(qtmovie->stream); + stream_read_uint32(qtmovie->stream); + size_remaining -= 12; + } + + if (size_remaining) + { + DEBUGF("ehm, size remianing?\n"); + stream_skip(qtmovie->stream, size_remaining); + } +} + +static void read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len) +{ + unsigned int i; + uint32_t numentries; + size_t size_remaining = chunk_len - 8; + + /* version + flags */ + stream_read_uint32(qtmovie->stream); + size_remaining -= 4; + + numentries = stream_read_uint32(qtmovie->stream); + size_remaining -= 4; + + qtmovie->res->num_chunk_offsets = numentries; + qtmovie->res->chunk_offset = malloc(numentries * + sizeof(*qtmovie->res->chunk_offset)); + + for (i = 0; i < numentries; i++) + { + qtmovie->res->chunk_offset[i] = stream_read_uint32(qtmovie->stream); + size_remaining -= 4; + } + + if (size_remaining) + { + DEBUGF("ehm, size remianing?\n"); + stream_skip(qtmovie->stream, size_remaining); + } +} + static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) { - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; while (size_remaining) { @@ -479,14 +520,15 @@ static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) read_chunk_stsz(qtmovie, sub_chunk_len); break; case MAKEFOURCC('s','t','s','c'): + read_chunk_stsc(qtmovie, sub_chunk_len); + break; case MAKEFOURCC('s','t','c','o'): - /* skip these, no indexing for us! */ - stream_skip(qtmovie->stream, sub_chunk_len - 8); + read_chunk_stco(qtmovie, sub_chunk_len); break; default: DEBUGF("(stbl) unknown chunk id: %c%c%c%c\n", SPLITFOURCC(sub_chunk_id)); - stream_skip(qtmovie->stream, sub_chunk_len - 8); /* FIXME not 8 */ + stream_skip(qtmovie->stream, sub_chunk_len - 8); } size_remaining -= sub_chunk_len; @@ -497,7 +539,7 @@ static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) { size_t dinf_size, stbl_size; - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; uint32_t i; /**** SOUND HEADER CHUNK ****/ @@ -553,7 +595,7 @@ static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len) { - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; while (size_remaining) { @@ -597,7 +639,7 @@ static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len) /* 'trak' - a movie track - contains other atoms */ static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len) { - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; while (size_remaining) { @@ -639,7 +681,7 @@ static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len) static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; stream_skip(qtmovie->stream, size_remaining); } @@ -648,7 +690,7 @@ static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len) static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; stream_skip(qtmovie->stream, size_remaining); } @@ -656,7 +698,7 @@ static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len) /* 'moov' movie atom - contains other atoms */ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) { - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; while (size_remaining) { @@ -688,7 +730,7 @@ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) default: DEBUGF("(moov) unknown chunk id: %c%c%c%c\n", SPLITFOURCC(sub_chunk_id)); - stream_skip(qtmovie->stream, sub_chunk_len - 8); /* FIXME not 8 */ + stream_skip(qtmovie->stream, sub_chunk_len - 8); } size_remaining -= sub_chunk_len; @@ -698,14 +740,9 @@ static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len) { - size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ + size_t size_remaining = chunk_len - 8; qtmovie->res->mdat_len = size_remaining; -#if 0 - qtmovie->res->mdat = malloc(size_remaining); - - stream_read(qtmovie->stream, size_remaining, qtmovie->res->mdat); -#endif } 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) /* these following atoms can be skipped !!!! */ case MAKEFOURCC('f','r','e','e'): - stream_skip(qtmovie.stream, chunk_len - 8); /* FIXME not 8 */ + stream_skip(qtmovie.stream, chunk_len - 8); break; default: //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 @@ #include #include "m4a.h" +#if defined(DEBUG) || defined(SIMULATOR) +extern struct codec_api* rb; +#define DEBUGF rb->debugf +#else +#define DEBUGF(...) +#endif + /* Implementation of the stream.h functions used by libalac */ #define _Swap32(v) do { \ @@ -101,15 +108,7 @@ uint8_t stream_read_uint8(stream_t *stream) void stream_skip(stream_t *stream, size_t skip) { - (void)stream; -#if 1 - char buf; - while (skip > 0) { - stream->ci->read_filebuf(&buf,1); - skip--; - } -#endif - //stream->ci->advance_buffer(skip); + stream->ci->advance_buffer(skip); } int stream_eof(stream_t *stream) @@ -158,136 +157,273 @@ int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, return 1; } -/* Seek to sample_loc (or close to it). Return 1 on success (and - modify samplesdone and currentblock), 0 if failed +unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample) +{ + uint32_t chunk = 1; + uint32_t range_samples = 0; + uint32_t total_samples = 0; + uint32_t chunk_sample; + uint32_t prev_chunk; + uint32_t prev_chunk_samples; + uint32_t file_offset; + uint32_t i; + + /* First check we have the appropriate metadata - we should always + * have it. + */ + + if (sample >= demux_res->num_sample_byte_sizes || + !demux_res->num_sample_to_chunks || + !demux_res->num_chunk_offsets) + { + return 0; + } - Seeking uses the following two arrays: + /* Locate the chunk containing the sample */ + + prev_chunk = demux_res->sample_to_chunk[0].first_chunk; + prev_chunk_samples = demux_res->sample_to_chunk[0].num_samples; - 1) the sample_byte_size array contains the length in bytes of - each block ("sample" in Applespeak). + for (i = 1; i < demux_res->num_sample_to_chunks; i++) + { + chunk = demux_res->sample_to_chunk[i].first_chunk; + range_samples = (chunk - prev_chunk) * prev_chunk_samples; - 2) the time_to_sample array contains the duration (in samples) of - each block of data. + if (sample < total_samples + range_samples) + { + break; + } - So we just find the block number we are going to seek to (using - time_to_sample) and then find the offset in the file (using - sample_byte_size). + total_samples += range_samples; + prev_chunk = demux_res->sample_to_chunk[i].first_chunk; + prev_chunk_samples = demux_res->sample_to_chunk[i].num_samples; + } - Each ALAC block seems to be independent of all the others. - */ + if (demux_res->num_sample_to_chunks > 1) + { + chunk = prev_chunk + (sample - total_samples) / prev_chunk_samples; + } + else + { + chunk = 1; + } + + /* Get sample of the first sample in the chunk */ + + chunk_sample = total_samples + (chunk - prev_chunk) * prev_chunk_samples; + + /* Get offset in file */ + + if (chunk > demux_res->num_chunk_offsets) + { + file_offset = demux_res->chunk_offset[demux_res->num_chunk_offsets - 1]; + } + else + { + file_offset = demux_res->chunk_offset[chunk - 1]; + } + + if (chunk_sample > sample) { + return 0; + } + + for (i = chunk_sample; i < sample; i++) + { + file_offset += demux_res->sample_byte_size[i]; + } + + if (file_offset > demux_res->mdat_offset + demux_res->mdat_len) + { + return 0; + } + + return file_offset; +} -unsigned int alac_seek (demux_res_t* demux_res, - stream_t* stream, - unsigned int sample_loc, - uint32_t* samplesdone, int* currentblock) +/* Seek to the sample containing sound_sample_loc. Return 1 on success + * (and modify sound_samples_done and current_sample), 0 if failed. + * + * Seeking uses the following arrays: + * + * 1) the time_to_sample array contains the duration (in sound samples) + * of each sample of data. + * + * 2) the sample_byte_size array contains the length in bytes of each + * sample. + * + * 3) the sample_to_chunk array contains information about which chunk + * of samples each sample belongs to. + * + * 4) the chunk_offset array contains the file offset of each chunk. + * + * So find the sample number we are going to seek to (using time_to_sample) + * and then find the offset in the file (using sample_to_chunk, + * chunk_offset sample_byte_size, in that order.). + * + */ +unsigned int alac_seek(demux_res_t* demux_res, stream_t* stream, + uint32_t sound_sample_loc, uint32_t* sound_samples_done, + int* current_sample) { - int flag; - unsigned int i,j; - unsigned int newblock; - unsigned int newsample; - unsigned int newpos; - - /* First check we have the appropriate metadata - we should always - have it. */ - if ((demux_res->num_time_to_samples==0) || - (demux_res->num_sample_byte_sizes==0)) { return 0; } - - /* Find the destination block from time_to_sample array */ - i=0; - newblock=0; - newsample=0; - flag=0; - - while ((inum_time_to_samples) && (flag==0) && - (newsample < sample_loc)) { - j=(sample_loc-newsample) / - demux_res->time_to_sample[i].sample_duration; + uint32_t i; + uint32_t j; + uint32_t new_sample; + uint32_t new_sound_sample; + uint32_t new_pos; + + /* First check we have the appropriate metadata - we should always + * have it. + */ + + if ((demux_res->num_time_to_samples==0) || + (demux_res->num_sample_byte_sizes==0)) + { + return 0; + } + + /* Find the destination block from time_to_sample array */ - if (j <= demux_res->time_to_sample[i].sample_count) { - newblock+=j; - newsample+=j*demux_res->time_to_sample[i].sample_duration; - flag=1; - } else { - newsample+=(demux_res->time_to_sample[i].sample_duration - * demux_res->time_to_sample[i].sample_count); - newblock+=demux_res->time_to_sample[i].sample_count; - i++; + i = 0; + new_sample = 0; + new_sound_sample = 0; + + while ((i < demux_res->num_time_to_samples) && + (new_sound_sample < sound_sample_loc)) + { + j = (sound_sample_loc - new_sound_sample) / + demux_res->time_to_sample[i].sample_duration; + + if (j <= demux_res->time_to_sample[i].sample_count) + { + new_sample += j; + new_sound_sample += j * + demux_res->time_to_sample[i].sample_duration; + break; + } + else + { + new_sound_sample += (demux_res->time_to_sample[i].sample_duration + * demux_res->time_to_sample[i].sample_count); + new_sample += demux_res->time_to_sample[i].sample_count; + i++; + } } - } - - /* We know the new block, now calculate the file position */ - newpos=demux_res->mdat_offset; - for (i=0;isample_byte_size[i]; - } - - /* We know the new file position, so let's try to seek to it */ - if (stream->ci->seek_buffer(newpos)) { - *samplesdone=newsample; - *currentblock=newblock; - return 1; - } else { + + /* We know the new block, now calculate the file position. */ + + new_pos = get_sample_offset(demux_res, new_sample); + + /* We know the new file position, so let's try to seek to it */ + + if (stream->ci->seek_buffer(new_pos)) + { + *sound_samples_done = new_sound_sample; + *current_sample = new_sample; + return 1; + } + return 0; - } } -/* Seek to file_loc (or close to it). Return 1 on success (and - modify samplesdone and currentblock), 0 if failed - - Seeking uses the following array: +/* Seek to the sample containing file_loc. Return 1 on success (and modify + * sound_samples_done and current_sample), 0 if failed. + * + * Seeking uses the following arrays: + * + * 1) the chunk_offset array contains the file offset of each chunk. + * + * 2) the sample_to_chunk array contains information about which chunk + * of samples each sample belongs to. + * + * 3) the sample_byte_size array contains the length in bytes of each + * sample. + * + * 4) the time_to_sample array contains the duration (in sound samples) + * of each sample of data. + * + * Locate the chunk containing location (using chunk_offset), find the + * sample of that chunk (using sample_to_chunk) and finally the location + * of that sample (using sample_byte_size). Then use time_to_sample to + * calculate the sound_samples_done value. + */ +unsigned int alac_seek_raw(demux_res_t* demux_res, stream_t* stream, + uint32_t file_loc, uint32_t* sound_samples_done, + int* current_sample) +{ + uint32_t chunk_sample = 0; + uint32_t total_samples = 0; + uint32_t new_sound_sample = 0; + uint32_t new_pos; + uint32_t chunk; + uint32_t i; + + if (!demux_res->num_chunk_offsets || + !demux_res->num_sample_to_chunks) + { + return 0; + } - the sample_byte_size array contains the length in bytes of - each block ("sample" in Applespeak). + /* Locate the chunk containing file_loc. */ - So we just find the last block before (or at) the requested position. + for (i = 0; i < demux_res->num_chunk_offsets && + file_loc < demux_res->chunk_offset[i]; i++) + { + } + + chunk = i + 1; + new_pos = demux_res->chunk_offset[chunk - 1]; - Each ALAC block seems to be independent of all the others. - */ + /* Get the first sample of the chunk. */ + + for (i = 1; i < demux_res->num_sample_to_chunks && + chunk < demux_res->sample_to_chunk[i - 1].first_chunk; i++) + { + chunk_sample += demux_res->sample_to_chunk[i - 1].num_samples * + (demux_res->sample_to_chunk[i].first_chunk - + demux_res->sample_to_chunk[i - 1].first_chunk); + } + + chunk_sample += (chunk - demux_res->sample_to_chunk[i - 1].first_chunk) * + demux_res->sample_to_chunk[i - 1].num_samples; -unsigned int alac_seek_raw (demux_res_t* demux_res, - stream_t* stream, - unsigned int file_loc, - uint32_t* samplesdone, int* currentblock) -{ - unsigned int i; - unsigned int j; - unsigned int newblock; - unsigned int newsample; - unsigned int newpos; - - /* First check we have the appropriate metadata - we should always - have it. */ - if ((demux_res->num_time_to_samples==0) || - (demux_res->num_sample_byte_sizes==0)) { return 0; } - - /* Find the destination block from the sample_byte_size array. */ - newpos=demux_res->mdat_offset; - for (i=0;(inum_sample_byte_sizes) && - (newpos+demux_res->sample_byte_size[i]<=file_loc);i++) { - newpos+=demux_res->sample_byte_size[i]; - } - - newblock=i; - newsample=0; - - /* Get the sample offset of the block */ - for (i=0,j=0;(inum_time_to_samples) && (jtime_to_sample[i].sample_count) { - if (newblock-j < demux_res->time_to_sample[i].sample_count) { - newsample+=(newblock-j)*demux_res->time_to_sample[i].sample_duration; - break; - } else { - newsample+=(demux_res->time_to_sample[i].sample_duration - * demux_res->time_to_sample[i].sample_count); + /* Get the position within the chunk. */ + + for (; chunk_sample < demux_res->num_sample_byte_sizes; chunk_sample++) + { + if (file_loc < new_pos + demux_res->sample_byte_size[chunk_sample]) + { + break; + } + + new_pos += demux_res->sample_byte_size[chunk_sample]; + } + + /* Get sound sample offset. */ + + for (i = 0; i < demux_res->num_time_to_samples; i++) + { + if (chunk_sample < + total_samples + demux_res->time_to_sample[i].sample_count) + { + break; + } + + total_samples += demux_res->time_to_sample[i].sample_count; + new_sound_sample += demux_res->time_to_sample[i].sample_count + * demux_res->time_to_sample[i].sample_duration; } - } + + new_sound_sample += (chunk_sample - total_samples) + * demux_res->time_to_sample[i].sample_duration; + + /* Go to the new file position. */ + + if (stream->ci->seek_buffer(new_pos)) + { + *sound_samples_done = new_sound_sample; + *current_sample = chunk_sample; + return 1; + } - /* We know the new file position, so let's try to seek to it */ - if (stream->ci->seek_buffer(newpos)) { - *samplesdone=newsample; - *currentblock=newblock; - return 1; - } else { return 0; - } } 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,11 +33,20 @@ typedef uint32_t fourcc_t; typedef struct { uint16_t num_channels; - uint16_t sample_size; - uint32_t sample_rate; + uint16_t sound_sample_size; + uint32_t sound_sample_rate; fourcc_t format; void *buf; + struct { + uint32_t first_chunk; + uint32_t num_samples; + } *sample_to_chunk; + uint32_t num_sample_to_chunks; + + uint32_t *chunk_offset; + uint32_t num_chunk_offsets; + struct { uint32_t sample_count; uint32_t sample_duration; @@ -93,16 +102,13 @@ void stream_skip(stream_t *stream, size_t skip); int stream_eof(stream_t *stream); void stream_create(stream_t *stream,struct codec_api* ci); -int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, - uint32_t *sample_duration, - uint32_t *sample_byte_size); -unsigned int alac_seek (demux_res_t* demux_res, - stream_t* stream, - unsigned int sample_loc, - uint32_t* samplesdone, int* currentblock); -unsigned int alac_seek_raw (demux_res_t* demux_res, - stream_t* stream, - unsigned int file_loc, - uint32_t* samplesdone, int* currentblock); +int get_sample_info(demux_res_t *demux_res, uint32_t sample, + uint32_t *sample_duration, uint32_t *sample_byte_size); +unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample); +unsigned int alac_seek (demux_res_t* demux_res, stream_t* stream, + uint32_t sound_sample_loc, uint32_t* sound_samples_done, + int* current_sample); +unsigned int alac_seek_raw (demux_res_t* demux_res, stream_t* stream, + uint32_t file_loc, uint32_t* sound_samples_done, int* current_sample); #endif /* STREAM_H */ -- cgit v1.2.3