codecs: mpa: Improve seek & resume accuracy for VBR files
The codec used 32-bit math for elapsed time <-> file position calculations. The rounding errors seem to be the cause of poor seek/resume accuracy on long VBR files; switching to 64-bit math makes things much better. Change-Id: Iba638d9e031a891022510c31c141cc4541e3f149
This commit is contained in:
parent
26ffcd8f9f
commit
4e60fb77e0
1 changed files with 32 additions and 55 deletions
|
@ -176,38 +176,27 @@ static int get_file_pos(int newtime)
|
||||||
struct mp3entry *id3 = ci->id3;
|
struct mp3entry *id3 = ci->id3;
|
||||||
|
|
||||||
if (id3->vbr) {
|
if (id3->vbr) {
|
||||||
/* Convert newtime and id3->length to seconds to
|
|
||||||
* avoid overflow */
|
|
||||||
unsigned int newtime_s = newtime/1000;
|
|
||||||
unsigned int length_s = id3->length/1000;
|
|
||||||
|
|
||||||
if (id3->has_toc) {
|
if (id3->has_toc) {
|
||||||
/* Use the TOC to find the new position */
|
/* Use the TOC to find the new position */
|
||||||
unsigned int percent, remainder;
|
unsigned int percent = ((uint64_t)newtime * 100) / id3->length;
|
||||||
int curtoc, nexttoc, plen;
|
|
||||||
|
|
||||||
percent = (newtime_s*100) / length_s;
|
|
||||||
if (percent > 99)
|
if (percent > 99)
|
||||||
percent = 99;
|
percent = 99;
|
||||||
|
|
||||||
curtoc = id3->toc[percent];
|
unsigned int pct_timestep = id3->length / 100;
|
||||||
|
unsigned int toc_sizestep = id3->filesize / 256;
|
||||||
|
unsigned int cur_toc = id3->toc[percent];
|
||||||
|
unsigned int next_toc = percent < 99 ? id3->toc[percent+1] : 256;
|
||||||
|
unsigned int plength = (next_toc - cur_toc) * toc_sizestep;
|
||||||
|
|
||||||
if (percent < 99) {
|
/* Seek to TOC mark */
|
||||||
nexttoc = id3->toc[percent+1];
|
pos = cur_toc * toc_sizestep;
|
||||||
} else {
|
|
||||||
nexttoc = 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = (id3->filesize/256)*curtoc;
|
/* Interpolate between this TOC mark and the next TOC mark */
|
||||||
|
newtime -= percent * pct_timestep;
|
||||||
/* Use the remainder to get a more accurate position */
|
pos += (uint64_t)plength * newtime / pct_timestep;
|
||||||
remainder = (newtime_s*100) % length_s;
|
|
||||||
remainder = (remainder*100) / length_s;
|
|
||||||
plen = (nexttoc - curtoc)*(id3->filesize/256);
|
|
||||||
pos += (plen/100)*remainder;
|
|
||||||
} else {
|
} else {
|
||||||
/* No TOC exists, estimate the new position */
|
/* No TOC exists, estimate the new position */
|
||||||
pos = (id3->filesize / length_s) * newtime_s;
|
pos = (uint64_t)newtime * id3->filesize / id3->length;
|
||||||
}
|
}
|
||||||
} else if (id3->bitrate) {
|
} else if (id3->bitrate) {
|
||||||
pos = newtime * (id3->bitrate / 8);
|
pos = newtime * (id3->bitrate / 8);
|
||||||
|
@ -234,43 +223,31 @@ static void set_elapsed(struct mp3entry* id3)
|
||||||
|
|
||||||
if ( id3->vbr ) {
|
if ( id3->vbr ) {
|
||||||
if ( id3->has_toc ) {
|
if ( id3->has_toc ) {
|
||||||
/* calculate elapsed time using TOC */
|
unsigned int pct_timestep = id3->length / 100;
|
||||||
int i;
|
unsigned int toc_sizestep = id3->filesize / 256;
|
||||||
unsigned int remainder, plen, relpos, nextpos;
|
|
||||||
|
|
||||||
/* find wich percent we're at */
|
int percent;
|
||||||
for (i=0; i<100; i++ )
|
for (percent = 0; percent < 100; ++percent)
|
||||||
if ( offset < id3->toc[i] * (id3->filesize / 256) )
|
if (offset < id3->toc[percent] * toc_sizestep)
|
||||||
break;
|
break;
|
||||||
|
if (percent > 0)
|
||||||
|
--percent;
|
||||||
|
|
||||||
i--;
|
unsigned int cur_toc = id3->toc[percent];
|
||||||
if (i < 0)
|
unsigned int next_toc = percent < 99 ? id3->toc[percent+1] : 256;
|
||||||
i = 0;
|
unsigned int plength = (next_toc - cur_toc) * toc_sizestep;
|
||||||
|
|
||||||
relpos = id3->toc[i];
|
/* Set elapsed time to the TOC mark */
|
||||||
|
elapsed = percent * pct_timestep;
|
||||||
|
|
||||||
if (i < 99)
|
/* Interpolate between this TOC mark and the next TOC mark */
|
||||||
nextpos = id3->toc[i+1];
|
offset -= cur_toc * toc_sizestep;
|
||||||
else
|
elapsed += (uint64_t)pct_timestep * offset / plength;
|
||||||
nextpos = 256;
|
} else {
|
||||||
|
/* No TOC, use an approximation (this'll be wildly inaccurate) */
|
||||||
remainder = offset - (relpos * (id3->filesize / 256));
|
uint64_t data_size = id3->filesize -
|
||||||
|
id3->first_frame_offset - id3->id3v1len;
|
||||||
/* set time for this percent (divide before multiply to prevent
|
elapsed = (uint64_t)id3->length * offset / data_size;
|
||||||
overflow on long files. loss of precision is negligible on
|
|
||||||
short files) */
|
|
||||||
elapsed = i * (id3->length / 100);
|
|
||||||
|
|
||||||
/* calculate remainder time */
|
|
||||||
plen = (nextpos - relpos) * (id3->filesize / 256);
|
|
||||||
elapsed += (((remainder * 100) / plen) * (id3->length / 10000));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* no TOC exists. set a rough estimate using average bitrate */
|
|
||||||
int tpk = id3->length /
|
|
||||||
((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
|
|
||||||
1024);
|
|
||||||
elapsed = offset / 1024 * tpk;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue