codecs: alac: Improve resume accuracy and clean up rounding errors
Resume by offset was obviously inaccurate for ALAC -- it tried to convert the offset to an elapsed time using the approximate bitrate, which is going to be wrong for VBR files. This became a problem since commit26ffcd8f9f
restored the ability to resume by offset. It turns out that m4a_seek_raw() has terrible resolution since it can only seek to chunk boundaries, and lies about the real sample position; basically the same issue that affected seeking described in commit4dd3c2b33e
. Resuming by offset is still not very accurate because of this. Prefer to resume by time first, which is normally highly accurate (and never worse than offset) but use the file offset if it's the only thing we have. There were a couple time calculations still using 32-bit math, so clean those up too to reduce issues due to rounding errors. Change-Id: Idd3bccd67505f4e59e784d92e45ea80a273975bb
This commit is contained in:
parent
ea61347a0b
commit
2f278af760
1 changed files with 32 additions and 30 deletions
|
@ -31,6 +31,12 @@ CODEC_HEADER
|
|||
|
||||
static int32_t outputbuffer[ALAC_MAX_CHANNELS][ALAC_BLOCKSIZE] IBSS_ATTR;
|
||||
|
||||
static void set_elapsed_samples(uint32_t samplesdone)
|
||||
{
|
||||
uint32_t elapsedtime = (uint64_t)samplesdone * 1000ULL / ci->id3->frequency;
|
||||
ci->set_elapsed(elapsedtime);
|
||||
}
|
||||
|
||||
/* this is the codec entry point */
|
||||
enum codec_status codec_main(enum codec_entry_call_reason reason)
|
||||
{
|
||||
|
@ -50,12 +56,14 @@ enum codec_status codec_run(void)
|
|||
demux_res_t demux_res;
|
||||
stream_t input_stream;
|
||||
uint32_t samplesdone;
|
||||
uint32_t elapsedtime;
|
||||
int samplesdecoded;
|
||||
unsigned int i;
|
||||
unsigned char* buffer;
|
||||
alac_file alac;
|
||||
intptr_t param;
|
||||
unsigned long resume_time;
|
||||
uint32_t resume_offset;
|
||||
unsigned int did_resume;
|
||||
|
||||
/* Clean and initialize decoder structures */
|
||||
memset(&demux_res , 0, sizeof(demux_res));
|
||||
|
@ -71,10 +79,10 @@ enum codec_status codec_run(void)
|
|||
|
||||
stream_create(&input_stream,ci);
|
||||
|
||||
/* Read resume info before calling qtmovie_read. */
|
||||
elapsedtime = ci->id3->elapsed;
|
||||
samplesdone = ci->id3->offset;
|
||||
|
||||
/* Save resume info because qtmovie_read() can modify it. */
|
||||
resume_time = ci->id3->elapsed;
|
||||
resume_offset = ci->id3->offset;
|
||||
|
||||
/* if qtmovie_read returns successfully, the stream is up to
|
||||
* the movie data, which can be used directly by the decoder */
|
||||
if (!qtmovie_read(&input_stream, &demux_res)) {
|
||||
|
@ -84,28 +92,24 @@ enum codec_status codec_run(void)
|
|||
|
||||
/* initialise the sound converter */
|
||||
alac_set_info(&alac, demux_res.codecdata);
|
||||
|
||||
/* Set i for first frame, seek to desired sample position for resuming. */
|
||||
i=0;
|
||||
|
||||
if (elapsedtime || samplesdone) {
|
||||
if (samplesdone) {
|
||||
samplesdone =
|
||||
(uint32_t)((uint64_t)samplesdone*ci->id3->frequency /
|
||||
(ci->id3->bitrate*128));
|
||||
}
|
||||
else {
|
||||
samplesdone = (elapsedtime/10) * (ci->id3->frequency/100);
|
||||
}
|
||||
if (resume_time)
|
||||
did_resume = m4a_seek(&demux_res, &input_stream,
|
||||
(uint64_t)resume_time * ci->id3->frequency / 1000ULL,
|
||||
&samplesdone, (int *) &i);
|
||||
else if (resume_offset)
|
||||
did_resume = m4a_seek_raw(&demux_res, &input_stream, resume_offset,
|
||||
&samplesdone, (int *) &i);
|
||||
else
|
||||
did_resume = 0;
|
||||
|
||||
if (!m4a_seek(&demux_res, &input_stream, samplesdone,
|
||||
&samplesdone, (int*) &i)) {
|
||||
samplesdone = 0;
|
||||
}
|
||||
/* Start from the beginning if we did not resume. */
|
||||
if (!did_resume) {
|
||||
i = 0;
|
||||
samplesdone = 0;
|
||||
}
|
||||
|
||||
elapsedtime = samplesdone * 1000LL / ci->id3->frequency;
|
||||
ci->set_elapsed(elapsedtime);
|
||||
set_elapsed_samples(samplesdone);
|
||||
|
||||
/* The main decoding loop */
|
||||
while (i < demux_res.num_sample_byte_sizes) {
|
||||
|
@ -117,11 +121,10 @@ enum codec_status codec_run(void)
|
|||
/* Deal with any pending seek requests */
|
||||
if (action == CODEC_ACTION_SEEK_TIME) {
|
||||
if (m4a_seek(&demux_res, &input_stream,
|
||||
(param/10) * (ci->id3->frequency/100),
|
||||
&samplesdone, (int *)&i)) {
|
||||
elapsedtime=samplesdone*1000LL/ci->id3->frequency;
|
||||
}
|
||||
ci->set_elapsed(elapsedtime);
|
||||
(uint64_t)param * ci->id3->frequency / 1000ULL,
|
||||
&samplesdone, (int *) &i))
|
||||
set_elapsed_samples(samplesdone);
|
||||
|
||||
ci->seek_complete();
|
||||
}
|
||||
|
||||
|
@ -140,8 +143,7 @@ enum codec_status codec_run(void)
|
|||
|
||||
/* Update the elapsed-time indicator */
|
||||
samplesdone+=samplesdecoded;
|
||||
elapsedtime=samplesdone*1000LL/ci->id3->frequency;
|
||||
ci->set_elapsed(elapsedtime);
|
||||
set_elapsed_samples(samplesdone);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue