Index: apps/codecs/aac.c =================================================================== --- apps/codecs/aac.c (revision 29727) +++ apps/codecs/aac.c (working copy) @@ -211,7 +211,7 @@ * that an good question (but files with gaps do exist, so who * knows?), so we don't support that - for now, at least. */ - file_offset = get_sample_offset(&demux_res, i); + file_offset = check_sample_offset(&demux_res, i); if (file_offset > ci->curpos) { @@ -225,7 +225,7 @@ } /* Request the required number of bytes from the input buffer */ - buffer=ci->request_buffer(&n, demux_res.sample_byte_size[i]); + buffer=ci->request_buffer(&n, demux_res.max_sample_byte_size); /* Decode one block - returned samples will be host-endian */ ret = NeAACDecDecode(decoder, &frame_info, buffer, n); Index: apps/codecs/alac.c =================================================================== --- apps/codecs/alac.c (revision 29726) +++ apps/codecs/alac.c (working copy) @@ -111,8 +111,8 @@ } /* Request the required number of bytes from the input buffer */ - buffer=ci->request_buffer(&n, demux_res.sample_byte_size[i]); - if (n!=demux_res.sample_byte_size[i]) { + buffer=ci->request_buffer(&n, demux_res.max_sample_byte_size); + if (n!=demux_res.max_sample_byte_size) { retval = CODEC_ERROR; goto done; } Index: apps/codecs/libm4a/m4a.c =================================================================== --- apps/codecs/libm4a/m4a.c (revision 29726) +++ apps/codecs/libm4a/m4a.c (working copy) @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2005 Dave Chapman + * Copyright (C) 2005 Dave Chapman, 2011 Andree Buschmann * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -122,147 +122,35 @@ stream->eof=0; } -/* This function was part of the original alac decoder implementation */ - -int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, - uint32_t *sample_duration, - uint32_t *sample_byte_size) +int check_sample_offset(demux_res_t *demux_res, uint32_t frame) { - unsigned int duration_index_accum = 0; - unsigned int duration_cur_index = 0; - - if (samplenum >= demux_res->num_sample_byte_sizes) { - return 0; + unsigned int i = 0; + for (i=0; inum_lookup_table; ++i) + { + if (demux_res->lookup_table[i].sample > frame || + demux_res->lookup_table[i].offset == 0) + return -1; + if (demux_res->lookup_table[i].sample == frame) + break; } - - if (!demux_res->num_time_to_samples) { - return 0; - } - - while ((demux_res->time_to_sample[duration_cur_index].sample_count - + duration_index_accum) <= samplenum) { - duration_index_accum += - demux_res->time_to_sample[duration_cur_index].sample_count; - - duration_cur_index++; - if (duration_cur_index >= demux_res->num_time_to_samples) { - return 0; - } - } - - *sample_duration = - demux_res->time_to_sample[duration_cur_index].sample_duration; - *sample_byte_size = demux_res->sample_byte_size[samplenum]; - - return 1; + return demux_res->lookup_table[i].offset; } -unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample) +static void gather_offset(demux_res_t *demux_res, uint32_t *frame, int *offset) { - 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) + uint32_t i = 0; + for (i=0; inum_lookup_table; ++i) { - return 0; - } - - /* 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; - - 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; - - if (sample < total_samples + range_samples) - { + if (demux_res->lookup_table[i].offset == 0) break; - } - - 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; + if (demux_res->lookup_table[i].sample > *frame) + break; } - - if (prev_chunk_samples > 0 && - sample >= demux_res->sample_to_chunk[0].num_samples) - { - 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; + i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ *frame. */ + *frame = demux_res->lookup_table[i].sample; + *offset = demux_res->lookup_table[i].offset; } -/* 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) @@ -300,10 +188,11 @@ ++i; } - /* We know the new block, now calculate the file position. */ - new_pos = get_sample_offset(demux_res, new_sample); + /* We know the new sample (=frame), now calculate the file position. */ + gather_offset(demux_res, &new_sample, &new_pos); /* We know the new file position, so let's try to seek to it */ + printf("-- alac_seek to %d -> %d %d\n", sound_sample_loc, new_sample, new_pos); if (stream->ci->seek_buffer(new_pos)) { *sound_samples_done = new_sound_sample; @@ -339,52 +228,25 @@ uint32_t file_loc, uint32_t* sound_samples_done, int* current_sample) { - uint32_t chunk_sample = 0; /* Holds the chunk/frame index. */ - uint32_t total_samples = 0; /* Sums up total amount of chunks/frames. */ - uint32_t new_sound_sample = 0; /* Sums up total amount of samples. */ + uint32_t i; + uint32_t chunk_sample = 0; + uint32_t total_samples = 0; + uint32_t new_sound_sample = 0; + uint32_t tmp_dur; + uint32_t tmp_cnt; uint32_t new_pos; - uint32_t chunk; - uint32_t i, tmp_dur, tmp_cnt; - /* There is no metadata available to perform raw seek. */ - if (!demux_res->num_chunk_offsets || !demux_res->num_sample_to_chunks) + /* Gather sample index. */ + for (i=0; i < demux_res->num_lookup_table; ++i) { - return 0; - } - - /* Locate the chunk containing file_loc. */ - chunk = 0; - while (chunk < demux_res->num_chunk_offsets) - { - if (file_loc < demux_res->chunk_offset[chunk]) - { + if (demux_res->lookup_table[i].offset > file_loc) break; - } - ++chunk; } - new_pos = demux_res->chunk_offset[chunk > 0 ? chunk - 1 : 0]; - - /* Get the first sample of the chunk. */ - i = 1; - sample_to_chunk_t *tab1 = demux_res->sample_to_chunk; - while (i < demux_res->num_sample_to_chunks) - { - if (chunk <= tab1[i].first_chunk) - { - break; - } - chunk_sample += tab1[i-1].num_samples * (tab1[i].first_chunk - tab1[i-1].first_chunk); - ++i; - } - chunk_sample += (chunk - tab1[i-1].first_chunk) * tab1[i-1].num_samples; + i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ file_loc. */ + chunk_sample = demux_res->lookup_table[i].sample; + new_pos = demux_res->lookup_table[i].offset; + printf("-- alac_seek_raw to %d -> (%d) %d %d\n", file_loc, i, chunk_sample, new_pos); - /* Get the position within the chunk. */ - while (chunk_sample < demux_res->num_sample_byte_sizes && - file_loc >= new_pos + demux_res->sample_byte_size[chunk_sample]) - { - new_pos += demux_res->sample_byte_size[chunk_sample++]; - } - /* Get sound sample offset. */ i = 0; time_to_sample_t *tab2 = demux_res->time_to_sample; Index: apps/codecs/libm4a/demux.c =================================================================== --- apps/codecs/libm4a/demux.c (revision 29726) +++ apps/codecs/libm4a/demux.c (working copy) @@ -381,31 +381,16 @@ size_remaining -= 4; qtmovie->res->num_sample_byte_sizes = numentries; - qtmovie->res->sample_byte_size = malloc(numentries * sizeof(*qtmovie->res->sample_byte_size)); - - if (!qtmovie->res->sample_byte_size) - { - DEBUGF("stsz too large\n"); - return false; - } - for (i = 0; i < numentries; i++) { uint32_t v = stream_read_uint32(qtmovie->stream); - - if (v > 0x0000ffff) - { - DEBUGF("stsz[%d] > 65 kB (%ld)\n", i, (long)v); - return false; - } - - qtmovie->res->sample_byte_size[i] = v; + if (v > qtmovie->res->max_sample_byte_size) + qtmovie->res->max_sample_byte_size = v; size_remaining -= 4; } if (size_remaining) { - DEBUGF("ehm, size remianing?\n"); stream_skip(qtmovie->stream, size_remaining); } @@ -426,8 +411,7 @@ size_remaining -= 4; qtmovie->res->num_sample_to_chunks = numentries; - qtmovie->res->sample_to_chunk = malloc(numentries * - sizeof(*qtmovie->res->sample_to_chunk)); + qtmovie->res->sample_to_chunk = malloc(numentries * sizeof(*qtmovie->res->sample_to_chunk)); if (!qtmovie->res->sample_to_chunk) { @@ -456,8 +440,11 @@ static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len) { - unsigned int i; + uint32_t i, k; uint32_t numentries; + int32_t idx = 0; + int32_t frame; + int32_t offset; size_t size_remaining = chunk_len - 8; /* version + flags */ @@ -466,20 +453,42 @@ numentries = stream_read_uint32(qtmovie->stream); size_remaining -= 4; + + qtmovie->res->num_lookup_table = numentries; + qtmovie->res->lookup_table = malloc(numentries * sizeof(*qtmovie->res->lookup_table)); - qtmovie->res->num_chunk_offsets = numentries; - qtmovie->res->chunk_offset = malloc(numentries * - sizeof(*qtmovie->res->chunk_offset)); - - if (!qtmovie->res->chunk_offset) + if (!qtmovie->res->lookup_table) { - DEBUGF("stco too large\n"); + DEBUGF("stco too large to allocate lookup_table[]\n"); return false; } - for (i = 0; i < numentries; i++) + /* read first offset */ + offset = stream_read_uint32(qtmovie->stream); + size_remaining -= 4; + + /* Build up lookup table. The lookup table contains the sample index and + * byte position in the file for each chunk. */ + for (k = 1; k < numentries; ++k) { - qtmovie->res->chunk_offset[i] = stream_read_uint32(qtmovie->stream); + frame = 0; + for (i = 1; i < qtmovie->res->num_sample_to_chunks; ++i) + { + int old_first = qtmovie->res->sample_to_chunk[i-1].first_chunk; + int new_first = qtmovie->res->sample_to_chunk[i ].first_chunk; + + if (qtmovie->res->sample_to_chunk[i].first_chunk > k) + break; + + frame += (new_first - old_first) * qtmovie->res->sample_to_chunk[i-1].num_samples; + } + frame += (k - qtmovie->res->sample_to_chunk[i-1].first_chunk)*qtmovie->res->sample_to_chunk[i-1].num_samples; + + qtmovie->res->lookup_table[idx].sample = frame; + qtmovie->res->lookup_table[idx].offset = offset; + idx++; + + offset = stream_read_uint32(qtmovie->stream); size_remaining -= 4; } Index: apps/codecs/libm4a/m4a.h =================================================================== --- apps/codecs/libm4a/m4a.h (revision 29726) +++ apps/codecs/libm4a/m4a.h (working copy) @@ -59,6 +59,12 @@ typedef struct { + uint32_t sample; + uint32_t offset; +} sample_offset_t; + +typedef struct +{ uint16_t num_channels; uint16_t sound_sample_size; uint32_t sound_sample_rate; @@ -68,14 +74,14 @@ sample_to_chunk_t *sample_to_chunk; uint32_t num_sample_to_chunks; - uint32_t *chunk_offset; - uint32_t num_chunk_offsets; + sample_offset_t *lookup_table; + uint32_t num_lookup_table; time_to_sample_t *time_to_sample; uint32_t num_time_to_samples; - uint16_t *sample_byte_size; uint32_t num_sample_byte_sizes; + uint32_t max_sample_byte_size; uint32_t codecdata_len; uint8_t codecdata[MAX_CODECDATA_SIZE]; @@ -132,5 +138,6 @@ 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); +int check_sample_offset(demux_res_t *demux_res, uint32_t frame); #endif /* STREAM_H */