Fixed: MP3 resume, forward seeking and some playlist bugs with

next/prev track change.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6605 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2005-06-08 10:33:01 +00:00
parent cff83c78c7
commit 5899ed5870

View file

@ -135,6 +135,7 @@ struct track_info {
volatile int available; volatile int available;
bool taginfo_ready; bool taginfo_ready;
int playlist_offset; int playlist_offset;
int elapsed_start;
}; };
/* Track information (count in file buffer, read/write indexes for /* Track information (count in file buffer, read/write indexes for
@ -144,9 +145,6 @@ static volatile int track_ridx;
static volatile int track_widx; static volatile int track_widx;
static bool track_changed; static bool track_changed;
/* Playlist position to tell the next track. */
static int last_offset;
/* Partially loaded song's file handle to continue buffering later. */ /* Partially loaded song's file handle to continue buffering later. */
static int current_fd; static int current_fd;
@ -168,6 +166,9 @@ static int new_track;
static bool v1first = false; static bool v1first = false;
static void mp3_set_elapsed(struct mp3entry* id3);
int mp3_get_file_pos(void);
#ifdef SIMULATOR #ifdef SIMULATOR
bool audiobuffer_insert_sim(char *buf, size_t length) bool audiobuffer_insert_sim(char *buf, size_t length)
{ {
@ -193,6 +194,7 @@ void codec_set_elapsed_callback(unsigned int value)
#else #else
latency = 0; latency = 0;
#endif #endif
value += cur_ti->elapsed_start;
if (value < latency) { if (value < latency) {
cur_ti->id3.elapsed = 0; cur_ti->id3.elapsed = 0;
} else if (value - latency > cur_ti->id3.elapsed } else if (value - latency > cur_ti->id3.elapsed
@ -252,7 +254,6 @@ void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
} }
while ((int)*realsize > cur_ti->available) { while ((int)*realsize > cur_ti->available) {
// logf("Buffer wait: %d", cur_ti->available);
yield(); yield();
if (ci.stop_codec) { if (ci.stop_codec) {
return NULL; return NULL;
@ -273,15 +274,24 @@ void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
void codec_advance_buffer_callback(size_t amount) void codec_advance_buffer_callback(size_t amount)
{ {
if ((int)amount > cur_ti->available) if ((int)amount > cur_ti->available + cur_ti->filerem)
amount = cur_ti->available; amount = cur_ti->available + cur_ti->filerem;
if ((int)amount > cur_ti->available) {
codecbufused = 0;
buf_ridx = buf_widx;
cur_ti->available = 0;
while ((int)amount < cur_ti->available)
yield();
} else {
cur_ti->available -= amount; cur_ti->available -= amount;
codecbufused -= amount; codecbufused -= amount;
buf_ridx += amount; buf_ridx += amount;
if (buf_ridx >= codecbuflen) if (buf_ridx >= codecbuflen)
buf_ridx -= codecbuflen; buf_ridx -= codecbuflen;
}
ci.curpos += amount; ci.curpos += amount;
cur_ti->id3.offset = ci.curpos;
} }
void codec_advance_buffer_loc_callback(void *ptr) void codec_advance_buffer_loc_callback(void *ptr)
@ -292,8 +302,6 @@ void codec_advance_buffer_loc_callback(void *ptr)
codec_advance_buffer_callback(amount); codec_advance_buffer_callback(amount);
} }
int mp3_get_file_pos(void);
off_t codec_mp3_get_filepos_callback(int newtime) off_t codec_mp3_get_filepos_callback(int newtime)
{ {
off_t newpos; off_t newpos;
@ -361,6 +369,8 @@ int probe_file_format(const char *filename)
return AFMT_MPA_L1; return AFMT_MPA_L1;
else if (!strcmp("mp2", suffix)) else if (!strcmp("mp2", suffix))
return AFMT_MPA_L2; return AFMT_MPA_L2;
else if (!strcmp("mpa", suffix))
return AFMT_MPA_L2;
else if (!strcmp("mp3", suffix)) else if (!strcmp("mp3", suffix))
return AFMT_MPA_L3; return AFMT_MPA_L3;
else if (!strcmp("ogg", suffix)) else if (!strcmp("ogg", suffix))
@ -465,8 +475,9 @@ bool loadcodec(const char *trackname, bool start_play)
logf("Codec: Vorbis"); logf("Codec: Vorbis");
codec_path = CODEC_VORBIS; codec_path = CODEC_VORBIS;
break; break;
case AFMT_MPA_L2:
case AFMT_MPA_L3: case AFMT_MPA_L3:
logf("Codec: MPA L3"); logf("Codec: MPA L2/L3");
codec_path = CODEC_MPA_L3; codec_path = CODEC_MPA_L3;
break; break;
case AFMT_PCM_WAV: case AFMT_PCM_WAV:
@ -561,11 +572,12 @@ bool audio_load_track(int offset, bool start_play)
off_t size; off_t size;
int rc, i; int rc, i;
int copy_n; int copy_n;
int last_offset = 0;
if (track_count >= MAX_TRACK) if (track_count >= MAX_TRACK)
return false; return false;
trackname = playlist_peek(offset); trackname = playlist_peek(last_offset);
if (!trackname) { if (!trackname) {
return false; return false;
} }
@ -608,6 +620,17 @@ bool audio_load_track(int offset, bool start_play)
mp3info(&tracks[track_widx].id3, trackname, v1first); mp3info(&tracks[track_widx].id3, trackname, v1first);
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
get_mp3file_info(fd, &tracks[track_widx].mp3data); get_mp3file_info(fd, &tracks[track_widx].mp3data);
if (offset) {
lseek(fd, offset, SEEK_SET);
tracks[track_widx].id3.offset = offset;
mp3_set_elapsed(&tracks[track_widx].id3);
tracks[track_widx].elapsed_start = tracks[track_widx].id3.elapsed;
tracks[track_widx].filepos = offset;
tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
ci.curpos = offset;
} else {
lseek(fd, 0, SEEK_SET);
}
logf("T:%s", tracks[track_widx].id3.title); logf("T:%s", tracks[track_widx].id3.title);
logf("L:%d", tracks[track_widx].id3.length); logf("L:%d", tracks[track_widx].id3.length);
logf("O:%d", tracks[track_widx].id3.first_frame_offset); logf("O:%d", tracks[track_widx].id3.first_frame_offset);
@ -616,11 +639,9 @@ bool audio_load_track(int offset, bool start_play)
break ; break ;
} }
playlist_next(0);
last_offset++; last_offset++;
track_count++; track_count++;
lseek(fd, 0, SEEK_SET); i = tracks[track_widx].filepos;
i = 0;
while (i < size) { while (i < size) {
/* Give codecs some processing time to prevent glitches. */ /* Give codecs some processing time to prevent glitches. */
yield_codecs(); yield_codecs();
@ -671,12 +692,13 @@ bool audio_load_track(int offset, bool start_play)
return true; return true;
} }
void audio_insert_tracks(bool start_playing) void audio_insert_tracks(int offset, bool start_playing)
{ {
fill_bytesleft = codecbuflen - codecbufused; fill_bytesleft = codecbuflen - codecbufused;
filling = true; filling = true;
while (audio_load_track(last_offset, start_playing)) { while (audio_load_track(offset, start_playing)) {
start_playing = false; start_playing = false;
offset = 0;
} }
filling = false; filling = false;
} }
@ -695,8 +717,7 @@ void audio_play_start(int offset)
#ifndef SIMULATOR #ifndef SIMULATOR
pcm_set_boost_mode(true); pcm_set_boost_mode(true);
#endif #endif
last_offset = offset; audio_insert_tracks(offset, true);
audio_insert_tracks(true);
#ifndef SIMULATOR #ifndef SIMULATOR
pcm_set_boost_mode(false); pcm_set_boost_mode(false);
ata_sleep(); ata_sleep();
@ -748,7 +769,7 @@ void audio_check_buffer(void)
/* Load new files to fill the entire buffer. */ /* Load new files to fill the entire buffer. */
if (tracks[track_widx].filerem == 0) if (tracks[track_widx].filerem == 0)
audio_insert_tracks(false); audio_insert_tracks(0, false);
#ifndef SIMULATOR #ifndef SIMULATOR
pcm_set_boost_mode(false); pcm_set_boost_mode(false);
@ -813,35 +834,35 @@ bool codec_request_next_track_callback(void)
/* Advance to next track. */ /* Advance to next track. */
if (ci.reload_codec && new_track > 0) { if (ci.reload_codec && new_track > 0) {
playlist_next(1);
if (++track_ridx == MAX_TRACK) if (++track_ridx == MAX_TRACK)
track_ridx = 0; track_ridx = 0;
if (tracks[track_ridx].filesize == 0) { if (tracks[track_ridx].filesize == 0) {
logf("Loading from disk..."); logf("Loading from disk...");
new_track = 0; new_track = 0;
queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset)); queue_post(&audio_queue, AUDIO_PLAY, 0);
return false; return false;
} }
} }
/* Advance to previous track. */ /* Advance to previous track. */
else if (ci.reload_codec && new_track < 0) { else if (ci.reload_codec && new_track < 0) {
playlist_next(-1);
if (--track_ridx < 0) if (--track_ridx < 0)
track_ridx = MAX_TRACK-1; track_ridx = MAX_TRACK-1;
if (tracks[track_ridx].filesize == 0 || if (tracks[track_ridx].filesize == 0 ||
codecbufused+ci.curpos+tracks[track_ridx].filesize codecbufused+ci.curpos+tracks[track_ridx].filesize
/*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) { /*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) {
logf("Loading from disk..."); logf("Loading from disk...");
last_offset -= track_count;
if (last_offset < 0)
last_offset = 0;
new_track = 0; new_track = 0;
queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset)); queue_post(&audio_queue, AUDIO_PLAY, 0);
return false; return false;
} }
} }
/* Codec requested track change (next track). */ /* Codec requested track change (next track). */
else { else {
playlist_next(1);
if (++track_ridx >= MAX_TRACK) if (++track_ridx >= MAX_TRACK)
track_ridx = 0; track_ridx = 0;
@ -1085,9 +1106,10 @@ void audio_next(void)
/* Detect if disk is spinning.. */ /* Detect if disk is spinning.. */
if (filling) { if (filling) {
playlist_next(1);
playing = false; playing = false;
ci.stop_codec = true; ci.stop_codec = true;
queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset)); queue_post(&audio_queue, AUDIO_PLAY, 0);
} }
} }
@ -1101,11 +1123,10 @@ void audio_prev(void)
#endif #endif
if (filling) { if (filling) {
playlist_next(-1);
playing = false; playing = false;
ci.stop_codec = true; ci.stop_codec = true;
if (--last_offset < 0) queue_post(&audio_queue, AUDIO_PLAY, 0);
last_offset = 0;
queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset));
} }
//queue_post(&audio_queue, AUDIO_PREV, 0); //queue_post(&audio_queue, AUDIO_PREV, 0);
} }
@ -1146,6 +1167,62 @@ int audio_get_file_pos(void)
} }
/* Copied from mpeg.c. Should be moved somewhere else. */
static void mp3_set_elapsed(struct mp3entry* id3)
{
if ( id3->vbr ) {
if ( id3->has_toc ) {
/* calculate elapsed time using TOC */
int i;
unsigned int remainder, plen, relpos, nextpos;
/* find wich percent we're at */
for (i=0; i<100; i++ )
{
if ( id3->offset < (int)(id3->toc[i] * (id3->filesize / 256)) )
{
break;
}
}
i--;
if (i < 0)
i = 0;
relpos = id3->toc[i];
if (i < 99)
{
nextpos = id3->toc[i+1];
}
else
{
nextpos = 256;
}
remainder = id3->offset - (relpos * (id3->filesize / 256));
/* set time for this percent (divide before multiply to prevent
overflow on long files. loss of precision is negligible on
short files) */
id3->elapsed = i * (id3->length / 100);
/* calculate remainder time */
plen = (nextpos - relpos) * (id3->filesize / 256);
id3->elapsed += (((remainder * 100) / plen) *
(id3->length / 10000));
}
else {
/* no TOC exists. set a rough estimate using average bitrate */
int tpk = id3->length / (id3->filesize / 1024);
id3->elapsed = id3->offset / 1024 * tpk;
}
}
else
/* constant bitrate == simple frame calculation */
id3->elapsed = id3->offset / id3->bpf * id3->tpf;
}
/* Copied from mpeg.c. Should be moved somewhere else. */ /* Copied from mpeg.c. Should be moved somewhere else. */
int mp3_get_file_pos(void) int mp3_get_file_pos(void)
{ {