diff options
author | Miika Pekkarinen <miipekk@ihme.org> | 2005-06-08 10:33:01 +0000 |
---|---|---|
committer | Miika Pekkarinen <miipekk@ihme.org> | 2005-06-08 10:33:01 +0000 |
commit | 5899ed5870d5554b154657ecef33db8c3c933c2c (patch) | |
tree | ff0cff7def8d6b0d94bb86449530ae3717b4e5a7 | |
parent | cff83c78c7ddce36bd42ec992e201f947f7b4a0a (diff) | |
download | rockbox-5899ed5870d5554b154657ecef33db8c3c933c2c.tar.gz rockbox-5899ed5870d5554b154657ecef33db8c3c933c2c.zip |
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
-rw-r--r-- | apps/playback.c | 143 |
1 files changed, 110 insertions, 33 deletions
diff --git a/apps/playback.c b/apps/playback.c index 1593b586fa..fef65f1e7d 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -135,6 +135,7 @@ struct track_info { | |||
135 | volatile int available; | 135 | volatile int available; |
136 | bool taginfo_ready; | 136 | bool taginfo_ready; |
137 | int playlist_offset; | 137 | int playlist_offset; |
138 | int elapsed_start; | ||
138 | }; | 139 | }; |
139 | 140 | ||
140 | /* Track information (count in file buffer, read/write indexes for | 141 | /* Track information (count in file buffer, read/write indexes for |
@@ -144,9 +145,6 @@ static volatile int track_ridx; | |||
144 | static volatile int track_widx; | 145 | static volatile int track_widx; |
145 | static bool track_changed; | 146 | static bool track_changed; |
146 | 147 | ||
147 | /* Playlist position to tell the next track. */ | ||
148 | static int last_offset; | ||
149 | |||
150 | /* Partially loaded song's file handle to continue buffering later. */ | 148 | /* Partially loaded song's file handle to continue buffering later. */ |
151 | static int current_fd; | 149 | static int current_fd; |
152 | 150 | ||
@@ -168,6 +166,9 @@ static int new_track; | |||
168 | 166 | ||
169 | static bool v1first = false; | 167 | static bool v1first = false; |
170 | 168 | ||
169 | static void mp3_set_elapsed(struct mp3entry* id3); | ||
170 | int mp3_get_file_pos(void); | ||
171 | |||
171 | #ifdef SIMULATOR | 172 | #ifdef SIMULATOR |
172 | bool audiobuffer_insert_sim(char *buf, size_t length) | 173 | bool audiobuffer_insert_sim(char *buf, size_t length) |
173 | { | 174 | { |
@@ -193,6 +194,7 @@ void codec_set_elapsed_callback(unsigned int value) | |||
193 | #else | 194 | #else |
194 | latency = 0; | 195 | latency = 0; |
195 | #endif | 196 | #endif |
197 | value += cur_ti->elapsed_start; | ||
196 | if (value < latency) { | 198 | if (value < latency) { |
197 | cur_ti->id3.elapsed = 0; | 199 | cur_ti->id3.elapsed = 0; |
198 | } else if (value - latency > cur_ti->id3.elapsed | 200 | } else if (value - latency > cur_ti->id3.elapsed |
@@ -252,7 +254,6 @@ void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) | |||
252 | } | 254 | } |
253 | 255 | ||
254 | while ((int)*realsize > cur_ti->available) { | 256 | while ((int)*realsize > cur_ti->available) { |
255 | // logf("Buffer wait: %d", cur_ti->available); | ||
256 | yield(); | 257 | yield(); |
257 | if (ci.stop_codec) { | 258 | if (ci.stop_codec) { |
258 | return NULL; | 259 | return NULL; |
@@ -273,15 +274,24 @@ void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) | |||
273 | 274 | ||
274 | void codec_advance_buffer_callback(size_t amount) | 275 | void codec_advance_buffer_callback(size_t amount) |
275 | { | 276 | { |
276 | if ((int)amount > cur_ti->available) | 277 | if ((int)amount > cur_ti->available + cur_ti->filerem) |
277 | amount = cur_ti->available; | 278 | amount = cur_ti->available + cur_ti->filerem; |
278 | 279 | ||
279 | cur_ti->available -= amount; | 280 | if ((int)amount > cur_ti->available) { |
280 | codecbufused -= amount; | 281 | codecbufused = 0; |
281 | buf_ridx += amount; | 282 | buf_ridx = buf_widx; |
282 | if (buf_ridx >= codecbuflen) | 283 | cur_ti->available = 0; |
283 | buf_ridx -= codecbuflen; | 284 | while ((int)amount < cur_ti->available) |
285 | yield(); | ||
286 | } else { | ||
287 | cur_ti->available -= amount; | ||
288 | codecbufused -= amount; | ||
289 | buf_ridx += amount; | ||
290 | if (buf_ridx >= codecbuflen) | ||
291 | buf_ridx -= codecbuflen; | ||
292 | } | ||
284 | ci.curpos += amount; | 293 | ci.curpos += amount; |
294 | cur_ti->id3.offset = ci.curpos; | ||
285 | } | 295 | } |
286 | 296 | ||
287 | void codec_advance_buffer_loc_callback(void *ptr) | 297 | void codec_advance_buffer_loc_callback(void *ptr) |
@@ -292,8 +302,6 @@ void codec_advance_buffer_loc_callback(void *ptr) | |||
292 | codec_advance_buffer_callback(amount); | 302 | codec_advance_buffer_callback(amount); |
293 | } | 303 | } |
294 | 304 | ||
295 | int mp3_get_file_pos(void); | ||
296 | |||
297 | off_t codec_mp3_get_filepos_callback(int newtime) | 305 | off_t codec_mp3_get_filepos_callback(int newtime) |
298 | { | 306 | { |
299 | off_t newpos; | 307 | off_t newpos; |
@@ -361,6 +369,8 @@ int probe_file_format(const char *filename) | |||
361 | return AFMT_MPA_L1; | 369 | return AFMT_MPA_L1; |
362 | else if (!strcmp("mp2", suffix)) | 370 | else if (!strcmp("mp2", suffix)) |
363 | return AFMT_MPA_L2; | 371 | return AFMT_MPA_L2; |
372 | else if (!strcmp("mpa", suffix)) | ||
373 | return AFMT_MPA_L2; | ||
364 | else if (!strcmp("mp3", suffix)) | 374 | else if (!strcmp("mp3", suffix)) |
365 | return AFMT_MPA_L3; | 375 | return AFMT_MPA_L3; |
366 | else if (!strcmp("ogg", suffix)) | 376 | else if (!strcmp("ogg", suffix)) |
@@ -465,8 +475,9 @@ bool loadcodec(const char *trackname, bool start_play) | |||
465 | logf("Codec: Vorbis"); | 475 | logf("Codec: Vorbis"); |
466 | codec_path = CODEC_VORBIS; | 476 | codec_path = CODEC_VORBIS; |
467 | break; | 477 | break; |
478 | case AFMT_MPA_L2: | ||
468 | case AFMT_MPA_L3: | 479 | case AFMT_MPA_L3: |
469 | logf("Codec: MPA L3"); | 480 | logf("Codec: MPA L2/L3"); |
470 | codec_path = CODEC_MPA_L3; | 481 | codec_path = CODEC_MPA_L3; |
471 | break; | 482 | break; |
472 | case AFMT_PCM_WAV: | 483 | case AFMT_PCM_WAV: |
@@ -561,11 +572,12 @@ bool audio_load_track(int offset, bool start_play) | |||
561 | off_t size; | 572 | off_t size; |
562 | int rc, i; | 573 | int rc, i; |
563 | int copy_n; | 574 | int copy_n; |
575 | int last_offset = 0; | ||
564 | 576 | ||
565 | if (track_count >= MAX_TRACK) | 577 | if (track_count >= MAX_TRACK) |
566 | return false; | 578 | return false; |
567 | 579 | ||
568 | trackname = playlist_peek(offset); | 580 | trackname = playlist_peek(last_offset); |
569 | if (!trackname) { | 581 | if (!trackname) { |
570 | return false; | 582 | return false; |
571 | } | 583 | } |
@@ -573,7 +585,7 @@ bool audio_load_track(int offset, bool start_play) | |||
573 | fd = open(trackname, O_RDONLY); | 585 | fd = open(trackname, O_RDONLY); |
574 | if (fd < 0) | 586 | if (fd < 0) |
575 | return false; | 587 | return false; |
576 | 588 | ||
577 | size = filesize(fd); | 589 | size = filesize(fd); |
578 | tracks[track_widx].filerem = size; | 590 | tracks[track_widx].filerem = size; |
579 | tracks[track_widx].filesize = size; | 591 | tracks[track_widx].filesize = size; |
@@ -608,6 +620,17 @@ bool audio_load_track(int offset, bool start_play) | |||
608 | mp3info(&tracks[track_widx].id3, trackname, v1first); | 620 | mp3info(&tracks[track_widx].id3, trackname, v1first); |
609 | lseek(fd, 0, SEEK_SET); | 621 | lseek(fd, 0, SEEK_SET); |
610 | get_mp3file_info(fd, &tracks[track_widx].mp3data); | 622 | get_mp3file_info(fd, &tracks[track_widx].mp3data); |
623 | if (offset) { | ||
624 | lseek(fd, offset, SEEK_SET); | ||
625 | tracks[track_widx].id3.offset = offset; | ||
626 | mp3_set_elapsed(&tracks[track_widx].id3); | ||
627 | tracks[track_widx].elapsed_start = tracks[track_widx].id3.elapsed; | ||
628 | tracks[track_widx].filepos = offset; | ||
629 | tracks[track_widx].filerem = tracks[track_widx].filesize - offset; | ||
630 | ci.curpos = offset; | ||
631 | } else { | ||
632 | lseek(fd, 0, SEEK_SET); | ||
633 | } | ||
611 | logf("T:%s", tracks[track_widx].id3.title); | 634 | logf("T:%s", tracks[track_widx].id3.title); |
612 | logf("L:%d", tracks[track_widx].id3.length); | 635 | logf("L:%d", tracks[track_widx].id3.length); |
613 | logf("O:%d", tracks[track_widx].id3.first_frame_offset); | 636 | logf("O:%d", tracks[track_widx].id3.first_frame_offset); |
@@ -616,11 +639,9 @@ bool audio_load_track(int offset, bool start_play) | |||
616 | break ; | 639 | break ; |
617 | } | 640 | } |
618 | 641 | ||
619 | playlist_next(0); | ||
620 | last_offset++; | 642 | last_offset++; |
621 | track_count++; | 643 | track_count++; |
622 | lseek(fd, 0, SEEK_SET); | 644 | i = tracks[track_widx].filepos; |
623 | i = 0; | ||
624 | while (i < size) { | 645 | while (i < size) { |
625 | /* Give codecs some processing time to prevent glitches. */ | 646 | /* Give codecs some processing time to prevent glitches. */ |
626 | yield_codecs(); | 647 | yield_codecs(); |
@@ -671,12 +692,13 @@ bool audio_load_track(int offset, bool start_play) | |||
671 | return true; | 692 | return true; |
672 | } | 693 | } |
673 | 694 | ||
674 | void audio_insert_tracks(bool start_playing) | 695 | void audio_insert_tracks(int offset, bool start_playing) |
675 | { | 696 | { |
676 | fill_bytesleft = codecbuflen - codecbufused; | 697 | fill_bytesleft = codecbuflen - codecbufused; |
677 | filling = true; | 698 | filling = true; |
678 | while (audio_load_track(last_offset, start_playing)) { | 699 | while (audio_load_track(offset, start_playing)) { |
679 | start_playing = false; | 700 | start_playing = false; |
701 | offset = 0; | ||
680 | } | 702 | } |
681 | filling = false; | 703 | filling = false; |
682 | } | 704 | } |
@@ -695,8 +717,7 @@ void audio_play_start(int offset) | |||
695 | #ifndef SIMULATOR | 717 | #ifndef SIMULATOR |
696 | pcm_set_boost_mode(true); | 718 | pcm_set_boost_mode(true); |
697 | #endif | 719 | #endif |
698 | last_offset = offset; | 720 | audio_insert_tracks(offset, true); |
699 | audio_insert_tracks(true); | ||
700 | #ifndef SIMULATOR | 721 | #ifndef SIMULATOR |
701 | pcm_set_boost_mode(false); | 722 | pcm_set_boost_mode(false); |
702 | ata_sleep(); | 723 | ata_sleep(); |
@@ -748,7 +769,7 @@ void audio_check_buffer(void) | |||
748 | 769 | ||
749 | /* Load new files to fill the entire buffer. */ | 770 | /* Load new files to fill the entire buffer. */ |
750 | if (tracks[track_widx].filerem == 0) | 771 | if (tracks[track_widx].filerem == 0) |
751 | audio_insert_tracks(false); | 772 | audio_insert_tracks(0, false); |
752 | 773 | ||
753 | #ifndef SIMULATOR | 774 | #ifndef SIMULATOR |
754 | pcm_set_boost_mode(false); | 775 | pcm_set_boost_mode(false); |
@@ -813,35 +834,35 @@ bool codec_request_next_track_callback(void) | |||
813 | 834 | ||
814 | /* Advance to next track. */ | 835 | /* Advance to next track. */ |
815 | if (ci.reload_codec && new_track > 0) { | 836 | if (ci.reload_codec && new_track > 0) { |
837 | playlist_next(1); | ||
816 | if (++track_ridx == MAX_TRACK) | 838 | if (++track_ridx == MAX_TRACK) |
817 | track_ridx = 0; | 839 | track_ridx = 0; |
818 | if (tracks[track_ridx].filesize == 0) { | 840 | if (tracks[track_ridx].filesize == 0) { |
819 | logf("Loading from disk..."); | 841 | logf("Loading from disk..."); |
820 | new_track = 0; | 842 | new_track = 0; |
821 | queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset)); | 843 | queue_post(&audio_queue, AUDIO_PLAY, 0); |
822 | return false; | 844 | return false; |
823 | } | 845 | } |
824 | } | 846 | } |
825 | 847 | ||
826 | /* Advance to previous track. */ | 848 | /* Advance to previous track. */ |
827 | else if (ci.reload_codec && new_track < 0) { | 849 | else if (ci.reload_codec && new_track < 0) { |
850 | playlist_next(-1); | ||
828 | if (--track_ridx < 0) | 851 | if (--track_ridx < 0) |
829 | track_ridx = MAX_TRACK-1; | 852 | track_ridx = MAX_TRACK-1; |
830 | if (tracks[track_ridx].filesize == 0 || | 853 | if (tracks[track_ridx].filesize == 0 || |
831 | codecbufused+ci.curpos+tracks[track_ridx].filesize | 854 | codecbufused+ci.curpos+tracks[track_ridx].filesize |
832 | /*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) { | 855 | /*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) { |
833 | logf("Loading from disk..."); | 856 | logf("Loading from disk..."); |
834 | last_offset -= track_count; | ||
835 | if (last_offset < 0) | ||
836 | last_offset = 0; | ||
837 | new_track = 0; | 857 | new_track = 0; |
838 | queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset)); | 858 | queue_post(&audio_queue, AUDIO_PLAY, 0); |
839 | return false; | 859 | return false; |
840 | } | 860 | } |
841 | } | 861 | } |
842 | 862 | ||
843 | /* Codec requested track change (next track). */ | 863 | /* Codec requested track change (next track). */ |
844 | else { | 864 | else { |
865 | playlist_next(1); | ||
845 | if (++track_ridx >= MAX_TRACK) | 866 | if (++track_ridx >= MAX_TRACK) |
846 | track_ridx = 0; | 867 | track_ridx = 0; |
847 | 868 | ||
@@ -1085,9 +1106,10 @@ void audio_next(void) | |||
1085 | 1106 | ||
1086 | /* Detect if disk is spinning.. */ | 1107 | /* Detect if disk is spinning.. */ |
1087 | if (filling) { | 1108 | if (filling) { |
1109 | playlist_next(1); | ||
1088 | playing = false; | 1110 | playing = false; |
1089 | ci.stop_codec = true; | 1111 | ci.stop_codec = true; |
1090 | queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset)); | 1112 | queue_post(&audio_queue, AUDIO_PLAY, 0); |
1091 | } | 1113 | } |
1092 | } | 1114 | } |
1093 | 1115 | ||
@@ -1101,11 +1123,10 @@ void audio_prev(void) | |||
1101 | #endif | 1123 | #endif |
1102 | 1124 | ||
1103 | if (filling) { | 1125 | if (filling) { |
1126 | playlist_next(-1); | ||
1104 | playing = false; | 1127 | playing = false; |
1105 | ci.stop_codec = true; | 1128 | ci.stop_codec = true; |
1106 | if (--last_offset < 0) | 1129 | queue_post(&audio_queue, AUDIO_PLAY, 0); |
1107 | last_offset = 0; | ||
1108 | queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset)); | ||
1109 | } | 1130 | } |
1110 | //queue_post(&audio_queue, AUDIO_PREV, 0); | 1131 | //queue_post(&audio_queue, AUDIO_PREV, 0); |
1111 | } | 1132 | } |
@@ -1147,6 +1168,62 @@ int audio_get_file_pos(void) | |||
1147 | 1168 | ||
1148 | 1169 | ||
1149 | /* Copied from mpeg.c. Should be moved somewhere else. */ | 1170 | /* Copied from mpeg.c. Should be moved somewhere else. */ |
1171 | static void mp3_set_elapsed(struct mp3entry* id3) | ||
1172 | { | ||
1173 | if ( id3->vbr ) { | ||
1174 | if ( id3->has_toc ) { | ||
1175 | /* calculate elapsed time using TOC */ | ||
1176 | int i; | ||
1177 | unsigned int remainder, plen, relpos, nextpos; | ||
1178 | |||
1179 | /* find wich percent we're at */ | ||
1180 | for (i=0; i<100; i++ ) | ||
1181 | { | ||
1182 | if ( id3->offset < (int)(id3->toc[i] * (id3->filesize / 256)) ) | ||
1183 | { | ||
1184 | break; | ||
1185 | } | ||
1186 | } | ||
1187 | |||
1188 | i--; | ||
1189 | if (i < 0) | ||
1190 | i = 0; | ||
1191 | |||
1192 | relpos = id3->toc[i]; | ||
1193 | |||
1194 | if (i < 99) | ||
1195 | { | ||
1196 | nextpos = id3->toc[i+1]; | ||
1197 | } | ||
1198 | else | ||
1199 | { | ||
1200 | nextpos = 256; | ||
1201 | } | ||
1202 | |||
1203 | remainder = id3->offset - (relpos * (id3->filesize / 256)); | ||
1204 | |||
1205 | /* set time for this percent (divide before multiply to prevent | ||
1206 | overflow on long files. loss of precision is negligible on | ||
1207 | short files) */ | ||
1208 | id3->elapsed = i * (id3->length / 100); | ||
1209 | |||
1210 | /* calculate remainder time */ | ||
1211 | plen = (nextpos - relpos) * (id3->filesize / 256); | ||
1212 | id3->elapsed += (((remainder * 100) / plen) * | ||
1213 | (id3->length / 10000)); | ||
1214 | } | ||
1215 | else { | ||
1216 | /* no TOC exists. set a rough estimate using average bitrate */ | ||
1217 | int tpk = id3->length / (id3->filesize / 1024); | ||
1218 | id3->elapsed = id3->offset / 1024 * tpk; | ||
1219 | } | ||
1220 | } | ||
1221 | else | ||
1222 | /* constant bitrate == simple frame calculation */ | ||
1223 | id3->elapsed = id3->offset / id3->bpf * id3->tpf; | ||
1224 | } | ||
1225 | |||
1226 | /* Copied from mpeg.c. Should be moved somewhere else. */ | ||
1150 | int mp3_get_file_pos(void) | 1227 | int mp3_get_file_pos(void) |
1151 | { | 1228 | { |
1152 | int pos = -1; | 1229 | int pos = -1; |