mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-07-10 13:29:52 -04:00
Codecs: mp4: Improve support for long files
Load stts (time to sample) table on demand if it doesn't fit in RAM. Fixes FS#13889 (in most cases I've seen files with single element in this table and problematic one has 111200 elements) Change-Id: I719f92a4512a45472739587e81861b9bc545f349
This commit is contained in:
parent
aae46a822a
commit
69b6c97e58
4 changed files with 76 additions and 18 deletions
|
|
@ -249,7 +249,8 @@ enum codec_status codec_run(void)
|
|||
if (i == demux_res.num_sample_byte_sizes - 1)
|
||||
{
|
||||
// Size of the last frame
|
||||
const uint32_t sample_duration = (demux_res.num_time_to_samples > 0) ?
|
||||
// Currently ignored if time_to_sample table fails to fit.
|
||||
const uint32_t sample_duration = (demux_res.num_time_to_samples > 0 && demux_res.time_to_sample) ?
|
||||
demux_res.time_to_sample[demux_res.num_time_to_samples - 1].sample_duration :
|
||||
frame_samples;
|
||||
|
||||
|
|
|
|||
|
|
@ -317,13 +317,29 @@ static bool read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
|
|||
|
||||
qtmovie->res->num_time_to_samples = numentries;
|
||||
qtmovie->res->time_to_sample = malloc(numentries * sizeof(*qtmovie->res->time_to_sample));
|
||||
|
||||
if (qtmovie->res->time_to_sample && numentries > 1)
|
||||
{
|
||||
//Make sure we leave space for at least 100 records in lookup table
|
||||
void* enough_mem = malloc(sizeof(*qtmovie->res->lookup_table)*100);
|
||||
if (!enough_mem)
|
||||
{
|
||||
free(qtmovie->res->time_to_sample);
|
||||
qtmovie->res->time_to_sample = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(enough_mem);
|
||||
}
|
||||
}
|
||||
if (!qtmovie->res->time_to_sample)
|
||||
{
|
||||
DEBUGF("stts too large\n");
|
||||
return false;
|
||||
qtmovie->res->time_to_sample_offset = stream_tell(qtmovie->stream);
|
||||
stream_skip(qtmovie->stream, size_remaining);
|
||||
DEBUGF("stts too large %ld, save time_to_sample_offset\n", size_remaining);
|
||||
return true;
|
||||
}
|
||||
|
||||
DEBUGF("stts numentires %d, size: %ld\n", numentries, numentries * sizeof(*qtmovie->res->time_to_sample));
|
||||
for (i = 0; i < numentries; i++)
|
||||
{
|
||||
qtmovie->res->time_to_sample[i].sample_count = stream_read_uint32(qtmovie->stream);
|
||||
|
|
@ -465,7 +481,7 @@ static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
|
|||
fit_numentries = numentries / accuracy_divider;
|
||||
}
|
||||
}
|
||||
DEBUGF("lookup_table numentries %d, fit_numentries %d\n", numentries, fit_numentries);
|
||||
DEBUGF("lookup_table numentries %d, fit_numentries %ld\n", numentries, fit_numentries);
|
||||
qtmovie->res->num_lookup_table = fit_numentries;
|
||||
|
||||
if (!qtmovie->res->lookup_table)
|
||||
|
|
|
|||
|
|
@ -137,6 +137,12 @@ int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame, uint32_t *st
|
|||
return -1;
|
||||
}
|
||||
|
||||
static inline void read_time_to_sample_entry(stream_t* stream, uint32_t* time_cnt, uint32_t* time_dur)
|
||||
{
|
||||
*time_cnt = stream_read_uint32(stream);
|
||||
*time_dur = stream_read_uint32(stream);
|
||||
}
|
||||
|
||||
/* Seek to desired sound sample location. Return 1 on success (and modify
|
||||
* sound_samples_done and current_sample), 0 if failed. */
|
||||
unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
|
||||
|
|
@ -161,10 +167,21 @@ unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
|
|||
/* The 'sound_sample_loc' we have is PCM-based and not directly usable.
|
||||
* We need to convert it to an MP4 sample number 'sample_i' first. */
|
||||
sample_i = sound_sample_i = 0;
|
||||
if (tts_tab == NULL)
|
||||
{
|
||||
stream_seek(stream, demux_res->time_to_sample_offset);
|
||||
}
|
||||
for (time = 0; time < demux_res->num_time_to_samples; ++time)
|
||||
{
|
||||
time_cnt = tts_tab[time].sample_count;
|
||||
time_dur = tts_tab[time].sample_duration;
|
||||
if (tts_tab)
|
||||
{
|
||||
time_dur = tts_tab[time].sample_duration;
|
||||
time_cnt = tts_tab[time].sample_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_time_to_sample_entry(stream, &time_cnt, &time_dur);
|
||||
}
|
||||
uint32_t time_var = time_cnt * time_dur;
|
||||
|
||||
if (sound_sample_loc < sound_sample_i + time_var)
|
||||
|
|
@ -194,10 +211,22 @@ unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
|
|||
/* Compute the PCM sample number of the chunk's first sample
|
||||
* to get an accurate base for sound_sample_i. */
|
||||
i = sound_sample_i = 0;
|
||||
if (tts_tab == NULL)
|
||||
{
|
||||
stream_seek(stream, demux_res->time_to_sample_offset);
|
||||
}
|
||||
|
||||
for (time = 0; time < demux_res->num_time_to_samples; ++time)
|
||||
{
|
||||
time_cnt = tts_tab[time].sample_count;
|
||||
time_dur = tts_tab[time].sample_duration;
|
||||
if (tts_tab)
|
||||
{
|
||||
time_dur = tts_tab[time].sample_duration;
|
||||
time_cnt = tts_tab[time].sample_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_time_to_sample_entry(stream, &time_cnt, &time_dur);
|
||||
}
|
||||
|
||||
if (chunk_first_sample < i + time_cnt)
|
||||
{
|
||||
|
|
@ -223,7 +252,7 @@ unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
|
|||
i < sample_i && i < demux_res->num_sample_byte_sizes; ++i)
|
||||
{
|
||||
/* this could be unnecessary */
|
||||
if (time_cnt == 0 && ++time < demux_res->num_time_to_samples)
|
||||
if (time_cnt == 0 && tts_tab && ++time < demux_res->num_time_to_samples)
|
||||
{
|
||||
time_cnt = tts_tab[time].sample_count;
|
||||
time_dur = tts_tab[time].sample_duration;
|
||||
|
|
@ -279,8 +308,8 @@ unsigned int m4a_seek_raw(demux_res_t* demux_res, stream_t* stream,
|
|||
uint32_t chunk_sample = 0;
|
||||
uint32_t total_samples = 0;
|
||||
uint64_t new_sound_sample = 0;
|
||||
uint32_t tmp_dur;
|
||||
uint32_t tmp_cnt;
|
||||
uint32_t time_dur;
|
||||
uint32_t time_cnt;
|
||||
uint32_t new_pos;
|
||||
|
||||
/* We know the desired byte offset, search for the chunk right before.
|
||||
|
|
@ -297,16 +326,27 @@ unsigned int m4a_seek_raw(demux_res_t* demux_res, stream_t* stream,
|
|||
|
||||
/* Get sound sample offset. */
|
||||
i = 0;
|
||||
time_to_sample_t *tab2 = demux_res->time_to_sample;
|
||||
time_to_sample_t *tts_tab = demux_res->time_to_sample;
|
||||
if (tts_tab == NULL)
|
||||
{
|
||||
stream_seek(stream, demux_res->time_to_sample_offset);
|
||||
}
|
||||
while (i < demux_res->num_time_to_samples)
|
||||
{
|
||||
tmp_dur = tab2[i].sample_duration;
|
||||
tmp_cnt = tab2[i].sample_count;
|
||||
total_samples += tmp_cnt;
|
||||
new_sound_sample += tmp_cnt * tmp_dur;
|
||||
if (tts_tab)
|
||||
{
|
||||
time_dur = tts_tab[i].sample_duration;
|
||||
time_cnt = tts_tab[i].sample_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_time_to_sample_entry(stream, &time_cnt, &time_dur);
|
||||
}
|
||||
total_samples += time_cnt;
|
||||
new_sound_sample += time_cnt * time_dur;
|
||||
if (chunk_sample <= total_samples)
|
||||
{
|
||||
new_sound_sample -= (total_samples - chunk_sample) * tmp_dur;
|
||||
new_sound_sample -= (total_samples - chunk_sample) * time_dur;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ typedef struct
|
|||
|
||||
time_to_sample_t *time_to_sample;
|
||||
uint32_t num_time_to_samples;
|
||||
uint32_t time_to_sample_offset;
|
||||
|
||||
uint32_t *sample_byte_sizes;
|
||||
uint32_t num_sample_byte_sizes;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue