From 57409f52d5da3665a91c6cf2cbcef86ea1004ccf Mon Sep 17 00:00:00 2001 From: "roman.artiukhin" Date: Tue, 5 Sep 2023 00:45:32 +0300 Subject: Codecs: mp4: Accurate seek in large files with small lookup_table Read sample_byte_sizes table on demand when it can't be cached Change-Id: I2191be63ceebfd8b16e1e973e13c5b51986b6564 --- lib/rbcodec/codecs/libm4a/demux.c | 11 ++++++++++- lib/rbcodec/codecs/libm4a/m4a.c | 19 ++++++++++++++----- lib/rbcodec/codecs/libm4a/m4a.h | 1 + 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/lib/rbcodec/codecs/libm4a/demux.c b/lib/rbcodec/codecs/libm4a/demux.c index 25462db030..8a424c5187 100644 --- a/lib/rbcodec/codecs/libm4a/demux.c +++ b/lib/rbcodec/codecs/libm4a/demux.c @@ -400,7 +400,8 @@ static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) } else { - DEBUGF("stsz too large, ignoring it\n"); + qtmovie->res->sample_byte_sizes_offset = stream_tell(qtmovie->stream); + DEBUGF("stsz too large: %u, save sample_byte_sizes_offset\n", numsizes); } if (size_remaining) @@ -481,6 +482,14 @@ static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len) return false; } + // Reading sample_byte_sizes data on seek can lead to additional re-buffering. + // So skip it if we have good enough seek accuracy via lookup_table (3000 ms) + if (qtmovie->res->sample_byte_sizes_offset && ci->id3->length / fit_numentries <= 3000) + { + qtmovie->res->sample_byte_sizes_offset = 0; + DEBUGF("lookup_table seek accuracy %ld ms, ignoring sample_byte_sizes_offset \n", ci->id3->length / fit_numentries); + } + /* Build up lookup table. The lookup table contains the sample index and * byte position in the file for each chunk. This table is used to seek * and resume (see m4a_seek() and m4a_seek_raw() in libm4a/m4a.c) and diff --git a/lib/rbcodec/codecs/libm4a/m4a.c b/lib/rbcodec/codecs/libm4a/m4a.c index 295c39c5ff..b63b8bad2c 100644 --- a/lib/rbcodec/codecs/libm4a/m4a.c +++ b/lib/rbcodec/codecs/libm4a/m4a.c @@ -211,11 +211,13 @@ unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream, sound_sample_i += time_cnt * time_dur; } - DEBUGF("seek chunk=%lu, sample=%lu, soundsample=%lu, offset=%lu\n", - (unsigned long)chunk, (unsigned long)chunk_first_sample, - sound_sample_i, (unsigned long)offset); + if (demux_res->sample_byte_sizes_offset) + { + stream->ci->seek_buffer(demux_res->sample_byte_sizes_offset + chunk_first_sample * 4); + } - if (tsz_tab) { + if (tsz_tab || demux_res->sample_byte_sizes_offset) + { /* We have a sample-to-bytes table available so we can do accurate * seeking. Move one sample at a time and update the file offset and * PCM sample offset as we go. */ @@ -229,7 +231,7 @@ unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream, time_dur = tts_tab[time].sample_duration; } - offset += tsz_tab[i]; + offset += tsz_tab ? tsz_tab[i] : stream_read_uint32(stream); sound_sample_i += time_dur; time_cnt--; } @@ -239,6 +241,13 @@ unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream, sample_i = chunk_first_sample; } + DEBUGF("seek chunk=%lu, chunk_first_sample=%lu, sample_i=%u, soundsample=%lu, offset=%lu\n", + (unsigned long)chunk, + (unsigned long)chunk_first_sample, + sample_i, + (unsigned long)sound_sample_i, + (unsigned long)offset); + if (stream->ci->seek_buffer(offset)) { *sound_samples_done = sound_sample_i; diff --git a/lib/rbcodec/codecs/libm4a/m4a.h b/lib/rbcodec/codecs/libm4a/m4a.h index 7120f8b4c6..14b22f5dbf 100644 --- a/lib/rbcodec/codecs/libm4a/m4a.h +++ b/lib/rbcodec/codecs/libm4a/m4a.h @@ -82,6 +82,7 @@ typedef struct uint32_t *sample_byte_sizes; uint32_t num_sample_byte_sizes; + int32_t sample_byte_sizes_offset; uint32_t codecdata_len; uint8_t codecdata[MAX_CODECDATA_SIZE]; -- cgit v1.2.3