Implement time-based resume and playback start.

This complements offset-based resume and playback start funcionality.
The implementation is global on both HWCODEC and SWCODEC.

Basically, if either the specified elapsed or offset are non-zero,
it indicates a mid-track resume.

To resume by time only, set elapsed to nonzero and offset to zero.
To resume by offset only, set offset to nonzero and elapsed to zero.

Which one the codec uses and which has priority is up to the codec;
however, using an elapsed time covers more cases:

* Codecs not able to use an offset such as VGM or other atomic
formats

* Starting playback at a nonzero elapsed time from a source that
contains no offset, such as a cuesheet

The change re-versions pretty much everything from tagcache to nvram.

Change-Id: Ic7aebb24e99a03ae99585c5e236eba960d163f38
Reviewed-on: http://gerrit.rockbox.org/516
Reviewed-by: Michael Sevakis <jethead71@rockbox.org>
Tested: Michael Sevakis <jethead71@rockbox.org>
This commit is contained in:
Michael Sevakis 2013-07-14 07:59:39 -04:00
parent dda54b85da
commit 31b7122867
65 changed files with 724 additions and 297 deletions

View File

@ -972,7 +972,7 @@ static bool play_bookmark(const char* bookmark)
if (!warn_on_pl_erase())
return false;
return bookmark_play(global_temp_buffer, bm.resume_index,
bm.resume_offset, bm.resume_seed, global_filename);
bm.resume_time, bm.resume_offset, bm.resume_seed, global_filename);
}
return false;

View File

@ -118,7 +118,7 @@ bool ft_play_playlist(char* pathname, char* dirname, char* filename)
playlist_shuffle(current_tick, -1);
}
playlist_start(0, 0);
playlist_start(0, 0, 0);
return true;
}
@ -498,7 +498,7 @@ int ft_enter(struct tree_context* c)
start_index = 0;
}
playlist_start(start_index, 0);
playlist_start(start_index, 0, 0);
play = true;
}
break;
@ -705,6 +705,7 @@ int ft_enter(struct tree_context* c)
global_status.resume_index = start_index;
global_status.resume_crc32 =
playlist_get_filename_crc32(NULL, start_index);
global_status.resume_elapsed = 0;
global_status.resume_offset = 0;
status_save();
rc = GO_TO_WPS;

View File

@ -2414,10 +2414,12 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
(((wps_data->last_albumart_height != aa->height) ||
(wps_data->last_albumart_width != aa->width)))))
{
long offset = audio_current_track()->offset;
struct mp3entry *id3 = audio_current_track();
unsigned long elapsed = id3->elapsed;
unsigned long offset = id3->offset;
audio_stop();
if (!(status & AUDIO_STATUS_PAUSE))
audio_play(offset);
audio_play(elapsed, offset);
}
}
#endif

View File

@ -177,6 +177,7 @@ int skin_get_touchaction(struct wps_data *data, int* edge_offset,
if (playlist_resume() != -1)
{
playlist_start(global_status.resume_index,
global_status.resume_elapsed,
global_status.resume_offset);
}
}

View File

@ -618,6 +618,7 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
if (resume && playlist_resume() != -1)
{
playlist_start(global_status.resume_index,
global_status.resume_elapsed,
global_status.resume_offset);
}
resume = false;
@ -657,6 +658,7 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
if (playlist_resume() != -1)
{
playlist_start(global_status.resume_index,
global_status.resume_elapsed,
global_status.resume_offset);
}
return event;

View File

@ -177,6 +177,13 @@ static long low_watermark; /* Dynamic low watermark level */
static long low_watermark_margin = 0; /* Extra time in seconds for watermark */
static long lowest_watermark_level; /* Debug value to observe the buffer
usage */
struct audio_resume_info
{
unsigned long elapsed;
unsigned long offset;
};
#if CONFIG_CODEC == MAS3587F
static char recording_filename[MAX_PATH]; /* argument to thread */
static char delayed_filename[MAX_PATH]; /* internal copy of above */
@ -430,10 +437,9 @@ static void set_elapsed(struct mp3entry* id3)
id3->elapsed = id3->offset / (id3->bitrate / 8);
}
int audio_get_file_pos(void)
static int audio_get_file_pos_int(struct mp3entry *id3)
{
int pos = -1;
struct mp3entry *id3 = audio_current_track();
if (id3->vbr)
{
@ -490,6 +496,12 @@ int audio_get_file_pos(void)
return pos;
}
int audio_get_file_pos(void)
{
struct mp3entry *id3 = audio_current_track();
return id3 ? audio_get_file_pos_int(id3) : 0;
}
unsigned long mpeg_get_last_header(void)
{
#ifdef SIMULATOR
@ -545,7 +557,13 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
}
/* TODO: Do it without stopping playback, if possible */
bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY;
long offset = audio_current_track()->offset;
struct mp3entry *id3 = audio_current_track();
unsigned long elapsed = 0, offset = 0;
if (id3)
{
elapsed = id3->elapsed;
offset = id3->offset;
}
/* don't call audio_hard_stop() as it frees this handle */
if (thread_self() == audio_thread_id)
{ /* inline case MPEG_STOP (audio_stop()) response
@ -574,7 +592,7 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
}
if (playing)
{ /* safe to call even from the audio thread (due to queue_post()) */
audio_play(offset);
audio_play(elapsed, offset);
}
return BUFLIB_CB_OK;
@ -1274,7 +1292,7 @@ static void mpeg_thread(void)
int unplayed_space_left;
int amount_to_read;
int t1, t2;
int start_offset;
unsigned long start_elapsed, start_offset;
#if CONFIG_CODEC == MAS3587F
int amount_to_save;
int save_endpos = 0;
@ -1337,9 +1355,16 @@ static void mpeg_thread(void)
break;
}
start_offset = (int)ev.data;
start_elapsed = ((struct audio_resume_info *)ev.data)->elapsed;
start_offset = ((struct audio_resume_info *)ev.data)->offset;
/* mid-song resume? */
if (!start_offset && start_elapsed) {
struct mp3entry *id3 = &get_trackdata(0)->id3;
id3->elapsed = start_elapsed;
start_offset = audio_get_file_pos_int(id3);
}
if (start_offset) {
struct mp3entry* id3 = &get_trackdata(0)->id3;
lseek(mpeg_file, start_offset, SEEK_SET);
@ -1506,7 +1531,7 @@ static void mpeg_thread(void)
id3->elapsed = newtime;
newpos = audio_get_file_pos();
newpos = audio_get_file_pos_int(id3);
if(newpos < 0)
{
id3->elapsed = oldtime;
@ -2765,7 +2790,7 @@ static void audio_reset_buffer(void)
audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize);
}
void audio_play(long offset)
void audio_play(unsigned long elapsed, unsigned long offset)
{
audio_reset_buffer();
#ifdef SIMULATOR
@ -2789,15 +2814,28 @@ void audio_play(long offset)
real_mpeg_play(trackname);
#endif
playlist_next(steps);
taginfo.offset = offset;
set_elapsed(&taginfo);
if (!offset && elapsed)
{
/* has an elapsed time but no offset; elapsed may take
precedence in this case */
taginfo.elapsed = elapsed;
taginfo.offset = audio_get_file_pos_int(&taginfo);
}
else
{
taginfo.offset = offset;
set_elapsed(&taginfo);
}
is_playing = true;
playing = true;
break;
} while(1);
#else /* !SIMULATOR */
static struct audio_resume_info resume;
is_playing = true;
queue_post(&mpeg_queue, MPEG_PLAY, offset);
resume.elapsed = elapsed;
resume.offset = offset;
queue_post(&mpeg_queue, MPEG_PLAY, (intptr_t)&resume);
#endif /* !SIMULATOR */
mpeg_errno = 0;

View File

@ -223,7 +223,7 @@ static bool add_to_playlist(int position, bool queue)
inserted */
if (global_settings.playlist_shuffle)
playlist_shuffle(current_tick, -1);
playlist_start(0,0);
playlist_start(0, 0, 0);
onplay_result = ONPLAY_START_PLAY;
}

View File

@ -151,6 +151,12 @@ enum audio_id3_types
};
static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */
struct audio_resume_info
{
unsigned long elapsed;
unsigned long offset;
};
/* Peeking functions can yield and mess us up */
static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/
@ -325,7 +331,8 @@ enum audio_start_playback_flags
AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */
};
static void audio_start_playback(size_t offset, unsigned int flags);
static void audio_start_playback(const struct audio_resume_info *resume_info,
unsigned int flags);
static void audio_stop_playback(void);
static void buffer_event_buffer_low_callback(void *data);
static void buffer_event_rebuffer_callback(void *data);
@ -792,7 +799,11 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
/* codec messages */
{ Q_AUDIO_PLAY, Q_AUDIO_PLAY },
};
static struct audio_resume_info resume;
bool give_up = false;
/* filebuflen is, at this point, the buffering.c buffer size,
* i.e. the audiobuf except voice, scratch mem, pcm, ... */
ssize_t extradata_size = old_size - filebuflen;
@ -813,7 +824,9 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
/* TODO: Do it without stopping playback, if possible */
long offset = audio_current_track()->offset;
struct mp3entry *id3 = audio_current_track();
unsigned long elapsed = id3->elapsed;
unsigned long offset = id3->offset;
/* resume if playing */
bool playing = (audio_status() == AUDIO_STATUS_PLAY);
/* There's one problem with stoping and resuming: If it happens in a too
@ -825,10 +838,20 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
* queue_post from the last call to get the correct offset. This also
* lets us conviniently remove the queue event so Q_AUDIO_PLAY is only
* processed once. */
bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, filter_list);
bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS,
filter_list);
if (playing && offset > 0) /* current id3->offset is king */
ev.data = offset;
if (playing && ev.data != (intptr_t)&resume)
{
resume = *(struct audio_resume_info *)ev.data;
/* current id3->elapsed/offset are king */
if (elapsed > 0)
resume.elapsed = elapsed;
if (offset > 0)
resume.offset = offset;
}
/* don't call audio_hard_stop() as it frees this handle */
if (thread_self() == audio_thread_id)
@ -867,7 +890,7 @@ static int shrink_callback(int handle, unsigned hints, void* start, size_t old_s
if (playing || play_queued)
{
/* post, to make subsequent calls not break the resume position */
audio_queue_post(Q_AUDIO_PLAY, ev.data);
audio_queue_post(Q_AUDIO_PLAY, (intptr_t)&resume);
}
return BUFLIB_CB_OK;
@ -1099,7 +1122,8 @@ static void audio_update_and_announce_next_track(const struct mp3entry *id3_next
/* Bring the user current mp3entry up to date and set a new offset for the
buffered metadata */
static void playing_id3_sync(struct track_info *user_info, off_t offset)
static void playing_id3_sync(struct track_info *user_info,
unsigned long elapsed, unsigned long offset)
{
id3_mutex_lock();
@ -1113,9 +1137,14 @@ static void playing_id3_sync(struct track_info *user_info, off_t offset)
id3_write(PLAYING_ID3, id3);
if (offset < 0)
if (elapsed == (unsigned long)-1)
{
playing_id3->elapsed = e;
elapsed = 0;
}
if (offset == (unsigned long)-1)
{
playing_id3->offset = o;
offset = 0;
}
@ -1123,7 +1152,10 @@ static void playing_id3_sync(struct track_info *user_info, off_t offset)
pcm_play_unlock();
if (id3)
{
id3->elapsed = elapsed;
id3->offset = offset;
}
id3_mutex_unlock();
}
@ -1299,19 +1331,16 @@ static bool audio_get_track_metadata(int offset, struct mp3entry *id3)
return false;
}
/* Get a resume rewind adjusted offset from the ID3 */
static unsigned long resume_rewind_adjusted_offset(const struct mp3entry *id3)
/* Get resume rewind adjusted progress from the ID3 */
static void resume_rewind_adjust_progress(const struct mp3entry *id3,
unsigned long *elapsed,
unsigned long *offset)
{
unsigned long offset = id3->offset;
size_t resume_rewind = global_settings.resume_rewind *
id3->bitrate * (1000/8);
if (offset < resume_rewind)
offset = 0;
else
offset -= resume_rewind;
return offset;
unsigned int rewind = MAX(global_settings.resume_rewind, 0);
unsigned long d_e = rewind*1000;
*elapsed = id3->elapsed - MIN(id3->elapsed, d_e);
unsigned long d_o = rewind * id3->bitrate * (1000/8);
*offset = id3->offset - MIN(id3->offset, d_o);
}
/* Get the codec into ram and initialize it - keep it if it's ready */
@ -1436,7 +1465,7 @@ static bool audio_start_codec(bool auto_skip)
#ifdef HAVE_TAGCACHE
bool autoresume_enable = global_settings.autoresume_enable;
if (autoresume_enable && !cur_id3->offset)
if (autoresume_enable && !(cur_id3->elapsed || cur_id3->offset))
{
/* Resume all manually selected tracks */
bool resume = !auto_skip;
@ -1466,10 +1495,13 @@ static bool audio_start_codec(bool auto_skip)
}
if (!resume)
{
cur_id3->elapsed = 0;
cur_id3->offset = 0;
}
logf("%s: Set offset for %s to %lX\n", __func__,
cur_id3->title, cur_id3->offset);
logf("%s: Set resume for %s to %lu %lX", __func__,
cur_id3->title, cur_id3->elapsed, cur_id3->offset);
}
#endif /* HAVE_TAGCACHE */
@ -1481,7 +1513,8 @@ static bool audio_start_codec(bool auto_skip)
and back again will cause accumulation of silent rewinds - that's not
our job to track directly nor could it be in any reasonable way
*/
cur_id3->offset = resume_rewind_adjusted_offset(cur_id3);
resume_rewind_adjust_progress(cur_id3, &cur_id3->elapsed,
&cur_id3->offset);
/* Update the codec API with the metadata and track info */
id3_write(CODEC_ID3, cur_id3);
@ -1494,7 +1527,7 @@ static bool audio_start_codec(bool auto_skip)
codec_go();
#ifdef HAVE_TAGCACHE
if (!autoresume_enable || cur_id3->offset)
if (!autoresume_enable || cur_id3->elapsed || cur_id3->offset)
#endif
{
/* Send the "buffer" event now */
@ -1923,7 +1956,9 @@ static int audio_finish_load_track(struct track_info *info)
/** Finally, load the audio **/
size_t file_offset = 0;
track_id3->elapsed = 0;
if (track_id3->elapsed > track_id3->length)
track_id3->elapsed = 0;
if (track_id3->offset >= info->filesize)
track_id3->offset = 0;
@ -1933,7 +1968,11 @@ static int audio_finish_load_track(struct track_info *info)
/* Adjust for resume rewind so we know what to buffer - starting the codec
calls it again, so we don't save it (and they shouldn't accumulate) */
size_t offset = resume_rewind_adjusted_offset(track_id3);
unsigned long elapsed, offset;
resume_rewind_adjust_progress(track_id3, &elapsed, &offset);
logf("%s: Set resume for %s to %lu %lX", __func__,
id3->title, elapsed, offset);
enum data_type audiotype = rbcodec_format_is_atomic(track_id3->codectype) ?
TYPE_ATOMIC_AUDIO : TYPE_PACKET_AUDIO;
@ -2168,7 +2207,7 @@ static void audio_on_finish_load_track(int id3_hid)
change otherwise */
bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3));
playing_id3_sync(info, -1);
playing_id3_sync(info, -1, -1);
if (!was_valid)
{
@ -2306,7 +2345,7 @@ static void audio_begin_track_change(enum pcm_track_change_type type,
if (audio_start_codec(auto_skip))
{
if (!auto_skip)
playing_id3_sync(info, -1);
playing_id3_sync(info, -1, -1);
return;
}
@ -2455,8 +2494,11 @@ static void audio_on_track_changed(void)
/* Begin playback from an idle state, transition to a new playlist or
invalidate the buffer and resume (if playing).
(usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */
static void audio_start_playback(size_t offset, unsigned int flags)
static void audio_start_playback(const struct audio_resume_info *resume_info,
unsigned int flags)
{
struct audio_resume_info resume =
*(resume_info ?: &(struct audio_resume_info){ 0, 0 } );
enum play_status old_status = play_status;
if (flags & AUDIO_START_NEWBUF)
@ -2469,7 +2511,8 @@ static void audio_start_playback(size_t offset, unsigned int flags)
if (old_status != PLAY_STOPPED)
{
logf("%s(%lu): skipping", __func__, (unsigned long)offset);
logf("%s(%lu, %lu): skipping", __func__, resume.elapsed,
resume.offset);
halt_decoding_track(true);
@ -2481,7 +2524,8 @@ static void audio_start_playback(size_t offset, unsigned int flags)
/* Clear out some stuff to resume the current track where it
left off */
pcmbuf_play_stop();
offset = id3_get(PLAYING_ID3)->offset;
resume.elapsed = id3_get(PLAYING_ID3)->elapsed;
resume.offset = id3_get(PLAYING_ID3)->offset;
track_list_clear(TRACK_LIST_CLEAR_ALL);
}
else
@ -2505,7 +2549,8 @@ static void audio_start_playback(size_t offset, unsigned int flags)
return; /* Must already be playing */
/* Cold playback start from a stopped state */
logf("%s(%lu): starting", __func__, offset);
logf("%s(%lu, %lu): starting", __func__, resume.elapsed,
resume.offset);
/* Set audio parameters */
#if INPUT_SRC_CAPS != 0
@ -2555,7 +2600,7 @@ static void audio_start_playback(size_t offset, unsigned int flags)
if (trackstat >= LOAD_TRACK_OK)
{
/* This is the currently playing track - get metadata, stat */
playing_id3_sync(track_list_current(0), offset);
playing_id3_sync(track_list_current(0), resume.elapsed, resume.offset);
if (valid_mp3entry(id3_get(PLAYING_ID3)))
{
@ -2892,7 +2937,9 @@ static void audio_on_ff_rewind(long time)
if (!haltres)
{
/* If codec must be (re)started, reset the offset */
/* If codec must be (re)started, reset the resume info so that
it doesn't execute resume procedures */
ci_id3->elapsed = 0;
ci_id3->offset = 0;
}
@ -2970,7 +3017,7 @@ static void audio_on_audio_flush(void)
not possible so a restart is required in order to continue the
currently playing track without the now invalid future track
playing */
audio_start_playback(0, AUDIO_START_RESTART);
audio_start_playback(NULL, AUDIO_START_RESTART);
break;
default: /* Nothing else is a state */
@ -3008,7 +3055,7 @@ void audio_playback_handler(struct queue_event *ev)
/** Control messages **/
case Q_AUDIO_PLAY:
LOGFQUEUE("playback < Q_AUDIO_PLAY");
audio_start_playback(ev->data, 0);
audio_start_playback((struct audio_resume_info *)ev->data, 0);
break;
#ifdef HAVE_RECORDING
@ -3082,7 +3129,7 @@ void audio_playback_handler(struct queue_event *ev)
case Q_AUDIO_REMAKE_AUDIO_BUFFER:
/* buffer needs to be reinitialized */
LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER");
audio_start_playback(0, AUDIO_START_RESTART | AUDIO_START_NEWBUF);
audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF);
if (play_status == PLAY_STOPPED)
return; /* just need to change buffer state */
break;
@ -3368,8 +3415,8 @@ struct mp3entry * audio_next_track(void)
return id3;
}
/* Start playback at the specified offset */
void audio_play(long offset)
/* Start playback at the specified elapsed time or offset */
void audio_play(unsigned long elapsed, unsigned long offset)
{
logf("audio_play");
@ -3379,8 +3426,9 @@ void audio_play(long offset)
talk_force_shutup();
#endif
LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
audio_queue_send(Q_AUDIO_PLAY, offset);
LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %lu %lX", elapsed, offset);
audio_queue_send(Q_AUDIO_PLAY,
(intptr_t)&(struct audio_resume_info){ elapsed, offset });
}
/* Stop playback if playing */
@ -3582,11 +3630,10 @@ void playback_release_aa_slot(int slot)
}
#endif /* HAVE_ALBUMART */
/* Would normally calculate byte offset from an elapsed time but is not
used on SWCODEC */
/* Return file byte offset */
int audio_get_file_pos(void)
{
return 0;
return id3_get(PLAYING_ID3)->offset;
}
/* Return total file buffer length after accounting for the talk buf */

View File

@ -621,7 +621,7 @@ static int create_and_play_dir(int direction, bool play_last)
#if (CONFIG_CODEC == SWCODEC)
current_playlist.started = true;
#else
playlist_start(index, 0);
playlist_start(index, 0, 0);
#endif
}
@ -2565,7 +2565,8 @@ unsigned int playlist_get_filename_crc32(struct playlist_info *playlist,
}
/* resume a playlist track with the given crc_32 of the track name. */
void playlist_resume_track(int start_index, unsigned int crc, int offset)
void playlist_resume_track(int start_index, unsigned int crc,
unsigned long elapsed, unsigned long offset)
{
int i;
unsigned int tmp_crc;
@ -2573,7 +2574,7 @@ void playlist_resume_track(int start_index, unsigned int crc, int offset)
tmp_crc = playlist_get_filename_crc32(playlist, start_index);
if (tmp_crc == crc)
{
playlist_start(start_index, offset);
playlist_start(start_index, elapsed, offset);
return;
}
@ -2582,17 +2583,18 @@ void playlist_resume_track(int start_index, unsigned int crc, int offset)
tmp_crc = playlist_get_filename_crc32(playlist, i);
if (tmp_crc == crc)
{
playlist_start(i, offset);
playlist_start(i, elapsed, offset);
return;
}
}
/* If we got here the file wasnt found, so start from the beginning */
playlist_start(0,0);
playlist_start(0, 0, 0);
}
/* start playing current playlist at specified index/offset */
void playlist_start(int start_index, int offset)
void playlist_start(int start_index, unsigned long elapsed,
unsigned long offset)
{
struct playlist_info* playlist = &current_playlist;
@ -2605,7 +2607,7 @@ void playlist_start(int start_index, int offset)
playlist->started = true;
sync_control(playlist, false);
audio_play(offset);
audio_play(elapsed, offset);
}
/* Returns false if 'steps' is out of bounds, else true */
@ -2723,7 +2725,7 @@ int playlist_next(int steps)
#if CONFIG_CODEC == SWCODEC
playlist->started = true;
#else
playlist_start(0, 0);
playlist_start(0, 0, 0);
#endif
playlist->index = 0;
index = 0;
@ -2801,11 +2803,13 @@ int playlist_update_resume_info(const struct mp3entry* id3)
if (id3)
{
if (global_status.resume_index != playlist->index ||
global_status.resume_elapsed != id3->elapsed ||
global_status.resume_offset != id3->offset)
{
unsigned int crc = crc_32(id3->path, strlen(id3->path), -1);
global_status.resume_index = playlist->index;
global_status.resume_crc32 = crc;
global_status.resume_elapsed = id3->elapsed;
global_status.resume_offset = id3->offset;
status_save();
}
@ -2814,6 +2818,7 @@ int playlist_update_resume_info(const struct mp3entry* id3)
{
global_status.resume_index = -1;
global_status.resume_crc32 = -1;
global_status.resume_elapsed = -1;
global_status.resume_offset = -1;
status_save();
}

View File

@ -133,8 +133,10 @@ int playlist_add(const char *filename);
int playlist_shuffle(int random_seed, int start_index);
unsigned int playlist_get_filename_crc32(struct playlist_info *playlist,
int index);
void playlist_resume_track(int start_index, unsigned int crc, int offset);
void playlist_start(int start_index, int offset);
void playlist_resume_track(int start_index, unsigned int crc,
unsigned long elapsed, unsigned long offset);
void playlist_start(int start_index, unsigned long elapsed,
unsigned long offset);
bool playlist_check(int steps);
const char *playlist_peek(int steps, char* buf, size_t buf_size);
int playlist_next(int steps);

View File

@ -458,6 +458,7 @@ static bool update_playlist(bool force)
{
global_status.resume_index = -1;
global_status.resume_offset = -1;
global_status.resume_elapsed = -1;
return false;
}
playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD,
@ -466,6 +467,7 @@ static bool update_playlist(bool force)
{
global_status.resume_index = -1;
global_status.resume_offset = -1;
global_status.resume_elapsed = -1;
return false;
}
}
@ -526,7 +528,7 @@ static int onplay_menu(int index)
if (current_track->display_index!=viewer.num_tracks ||
global_settings.repeat_mode == REPEAT_ALL)
{
audio_play(0);
audio_play(0, 0);
viewer.current_playing_track = -1;
}
}
@ -773,7 +775,7 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename)
/* play new track */
if (!global_settings.party_mode)
{
playlist_start(current_track->index, 0);
playlist_start(current_track->index, 0, 0);
update_playlist(false);
}
}
@ -790,7 +792,7 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename)
goto exit;
if (global_settings.playlist_shuffle)
start_index = playlist_shuffle(current_tick, start_index);
playlist_start(start_index, 0);
playlist_start(start_index, 0, 0);
/* Our playlist is now the current list */
if (!playlist_viewer_init(&viewer, NULL, true))
@ -937,7 +939,7 @@ bool search_playlist(void)
case ACTION_STD_OK:
{
int sel = gui_synclist_get_sel_pos(&playlist_lists);
playlist_start(found_indicies[sel], 0);
playlist_start(found_indicies[sel], 0, 0);
exit = 1;
}
break;

View File

@ -160,12 +160,12 @@ void* plugin_get_buffer(size_t *buffer_size);
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 226
#define PLUGIN_API_VERSION 227
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
#define PLUGIN_MIN_API_VERSION 226
#define PLUGIN_MIN_API_VERSION 227
/* plugin return codes */
/* internal returns start at 0x100 to make exit(1..255) work */
@ -723,8 +723,10 @@ struct plugin_api {
/* playback control */
int (*playlist_amount)(void);
int (*playlist_resume)(void);
void (*playlist_resume_track)(int start_index, unsigned int crc, int offset);
void (*playlist_start)(int start_index, int offset);
void (*playlist_resume_track)(int start_index, unsigned int crc,
unsigned long elapsed, unsigned long offset);
void (*playlist_start)(int start_index, unsigned long elapsed,
unsigned long offset);
int (*playlist_add)(const char *filename);
void (*playlist_sync)(struct playlist_info* playlist);
int (*playlist_remove_all_tracks)(struct playlist_info *playlist);
@ -735,7 +737,7 @@ struct plugin_api {
const char *dirname, int position, bool queue,
bool recurse);
int (*playlist_shuffle)(int random_seed, int start_index);
void (*audio_play)(long offset);
void (*audio_play)(unsigned long elapsed, unsigned long offset);
void (*audio_stop)(void);
void (*audio_pause)(void);
void (*audio_resume)(void);

View File

@ -109,6 +109,7 @@ static void resume_audio(void)
if (rb->playlist_resume() != -1) {
rb->playlist_resume_track(rb->global_status->resume_index,
rb->global_status->resume_crc32,
rb->global_status->resume_elapsed,
rb->global_status->resume_offset);
}
}

View File

@ -997,8 +997,8 @@ void set_play(void)
}
else
{
print_scroll("audio_play(0)");
rb->audio_play(0);
print_scroll("audio_play(0, 0)");
rb->audio_play(0, 0);
}
}

View File

@ -39,6 +39,7 @@ static bool play(void)
{
rb->playlist_resume_track(rb->global_status->resume_index,
rb->global_status->resume_crc32,
rb->global_status->resume_elapsed,
rb->global_status->resume_offset);
}
}

View File

@ -2684,6 +2684,7 @@ static int handle_button(void)
{
rb->playlist_resume_track(rb->global_status->resume_index,
rb->global_status->resume_crc32,
rb->global_status->resume_elapsed,
rb->global_status->resume_offset);
}
}

View File

@ -2580,7 +2580,7 @@ play:
* if shuffle, we can't predict the playing track easily, and for either
* case the track list doesn't get auto scrolled*/
if(!append)
rb->playlist_start(position, 0);
rb->playlist_start(position, 0, 0);
old_playlist = center_slide.slide_index;
old_shuffle = shuffle;
}

View File

@ -541,7 +541,7 @@ static int start_shuffled_play(void)
}
}
rb->splash(HZ, "Done");
rb->playlist_start(0,0);
rb->playlist_start(0, 0, 0);
return 1;
}

View File

@ -306,6 +306,7 @@ static int wpsscrn(void* param)
{
playlist_resume_track(global_status.resume_index,
global_status.resume_crc32,
global_status.resume_elapsed,
global_status.resume_offset);
ret_val = gui_wps_show();
}

View File

@ -738,12 +738,17 @@ void settings_apply_play_freq(int value, bool playback)
bool changed = value != prev_setting;
prev_setting = value;
long offset = 0;
unsigned long elapsed = 0;
unsigned long offset = 0;
bool playing = changed && !playback &&
audio_status() == AUDIO_STATUS_PLAY;
if (playing)
offset = audio_current_track()->offset;
{
struct mp3entry *id3 = audio_current_track();
elapsed = id3->elapsed;
offset = id3->offset;
}
if (changed && !playback)
audio_hard_stop();
@ -752,7 +757,7 @@ void settings_apply_play_freq(int value, bool playback)
mixer_set_frequency(play_sampr[value]);
if (playing)
audio_play(offset);
audio_play(elapsed, offset);
}
#endif /* HAVE_PLAY_FREQ */

View File

@ -266,6 +266,7 @@ struct system_status
{
int resume_index; /* index in playlist (-1 for no active resume) */
uint32_t resume_crc32; /* crc32 of the name of the file */
uint32_t resume_elapsed; /* elapsed time in last file */
uint32_t resume_offset; /* byte offset in mp3 file */
int runtime; /* current runtime since last charge */
int topruntime; /* top known runtime */
@ -282,6 +283,7 @@ struct system_status
#ifdef HAVE_LCD_BITMAP
int font_id[NB_SCREENS]; /* font id of the settings font for each screen */
#endif
};
struct user_settings

View File

@ -818,6 +818,7 @@ const struct settings_list settings[] = {
OFFON_SETTING(0, playlist_shuffle, LANG_SHUFFLE, false, "shuffle", NULL),
SYSTEM_SETTING(NVRAM(4), resume_index, -1),
SYSTEM_SETTING(NVRAM(4), resume_crc32, -1),
SYSTEM_SETTING(NVRAM(4), resume_elapsed, -1),
SYSTEM_SETTING(NVRAM(4), resume_offset, -1),
CHOICE_SETTING(0, repeat_mode, LANG_REPEAT, REPEAT_OFF, "repeat",
"off,all,one,shuffle"

View File

@ -142,7 +142,7 @@ struct custom_setting {
#define F_NVRAM_BYTES_MASK 0xE0000 /*0-4 bytes can be stored */
#define F_NVRAM_MASK_SHIFT 17
#define NVRAM_CONFIG_VERSION 7
#define NVRAM_CONFIG_VERSION 8
/* Above define should be bumped if
- a new NVRAM setting is added between 2 other NVRAM settings
- number of bytes for a NVRAM setting is changed

View File

@ -130,7 +130,7 @@ static long tempbuf_pos;
static const char *tags_str[] = { "artist", "album", "genre", "title",
"filename", "composer", "comment", "albumartist", "grouping", "year",
"discnumber", "tracknumber", "bitrate", "length", "playcount", "rating",
"playtime", "lastplayed", "commitid", "mtime", "lastoffset" };
"playtime", "lastplayed", "commitid", "mtime", "lastelapsed", "lastoffset" };
/* Status information of the tagcache. */
static struct tagcache_stat tc_stat;
@ -196,7 +196,7 @@ static const char * const tagfile_entry_ec = "ll";
/**
Note: This should be (1 + TAG_COUNT) amount of l's.
*/
static const char * const index_entry_ec = "llllllllllllllllllllll";
static const char * const index_entry_ec = "lllllllllllllllllllllll";
static const char * const tagcache_header_ec = "lll";
static const char * const master_header_ec = "llllll";
@ -1752,6 +1752,10 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
#if CONFIG_CODEC == SWCODEC
if (global_settings.autoresume_enable)
{
id3->elapsed = get_tag_numeric(entry, tag_lastelapsed, idx_id);
logf("tagcache_fill_tags: Set elapsed for %s to %lX\n",
id3->title, id3->elapsed);
id3->offset = get_tag_numeric(entry, tag_lastoffset, idx_id);
logf("tagcache_fill_tags: Set offset for %s to %lX\n",
id3->title, id3->offset);
@ -2348,6 +2352,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
tmpdb_copy_tag(tag_playtime);
tmpdb_copy_tag(tag_lastplayed);
tmpdb_copy_tag(tag_commitid);
tmpdb_copy_tag(tag_lastelapsed);
tmpdb_copy_tag(tag_lastoffset);
/* Avoid processing this entry again. */
@ -3419,7 +3424,8 @@ static int parse_changelog_line(int line_n, char *buf, void *parameters)
int idx_id;
long masterfd = (long)parameters;
const int import_tags[] = { tag_playcount, tag_rating, tag_playtime,
tag_lastplayed, tag_commitid, tag_lastoffset };
tag_lastplayed, tag_commitid, tag_lastelapsed,
tag_lastoffset };
int i;
(void)line_n;

View File

@ -33,7 +33,8 @@
enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year,
tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating,
tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastoffset,
tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastelapsed,
tag_lastoffset,
/* Real tags end here, count them. */
TAG_COUNT,
/* Virtual tags */
@ -51,7 +52,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
#define IDX_BUF_DEPTH 64
/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */
#define TAGCACHE_MAGIC 0x5443480e
#define TAGCACHE_MAGIC 0x5443480f
/* Dump store/restore header version 'TCSxx'. */
#define TAGCACHE_STATEFILE_MAGIC 0x54435301
@ -107,10 +108,11 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
(1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \
(1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \
(1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \
(1LU << tag_lastoffset) | (1LU << tag_virt_basename) | \
(1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \
(1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \
(1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore))
(1LU << tag_lastelapsed) | (1LU << tag_lastoffset) | \
(1LU << tag_virt_basename) | (1LU << tag_virt_length_min) | \
(1LU << tag_virt_length_sec) | (1LU << tag_virt_playtime_min) | \
(1LU << tag_virt_playtime_sec) | (1LU << tag_virt_entryage) | \
(1LU << tag_virt_autoscore))
#define TAGCACHE_IS_NUMERIC(tag) (BIT_N(tag) & TAGCACHE_NUMERIC_TAGS)

View File

@ -330,6 +330,7 @@ static int get_tag(int *tag)
{"playcount", tag_playcount},
{"rating", tag_rating},
{"lastplayed", tag_lastplayed},
{"lastelapsed", tag_lastelapsed},
{"lastoffset", tag_lastoffset},
{"commitid", tag_commitid},
{"entryage", tag_virt_entryage},
@ -841,8 +842,16 @@ static void tagtree_buffer_event(void *data)
#if CONFIG_CODEC == SWCODEC
if (autoresume)
{
/* Load current file resume offset if not already defined (by
/* Load current file resume info if not already defined (by
another resume mechanism) */
if (id3->elapsed == 0)
{
id3->elapsed = tagcache_get_numeric(&tcs, tag_lastelapsed);
logf("tagtree_buffer_event: Set elapsed for %s to %lX\n",
str_or_empty(id3->title), id3->elapsed);
}
if (id3->offset == 0)
{
id3->offset = tagcache_get_numeric(&tcs, tag_lastoffset);
@ -940,12 +949,13 @@ static void tagtree_track_finish_event(void *data)
#if CONFIG_CODEC == SWCODEC
if (autoresume)
{
unsigned long elapsed = auto_skip ? 0 : id3->elapsed;
unsigned long offset = auto_skip ? 0 : id3->offset;
tagcache_update_numeric(tagcache_idx, tag_lastelapsed, elapsed);
tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset);
logf("tagtree_track_finish_event: Save offset for %s: %lX",
str_or_empty(id3->title), offset);
logf("tagtree_track_finish_event: Save resume for %s: %lX %lX",
str_or_empty(id3->title), elapsed, offset);
}
#endif
}
@ -2034,7 +2044,7 @@ static int tagtree_play_folder(struct tree_context* c)
c->selected_item = 0;
gui_synclist_select_item(&tree_lists, c->selected_item);
playlist_start(c->selected_item,0);
playlist_start(c->selected_item, 0, 0);
playlist_get_current()->num_inserted_tracks = 0; /* make warn on playlist erase work */
return 0;
}

View File

@ -1052,8 +1052,8 @@ void tree_mem_init(void)
tree_get_filetypes(&filetypes, &filetypes_count);
}
bool bookmark_play(char *resume_file, int index, int offset, int seed,
char *filename)
bool bookmark_play(char *resume_file, int index, unsigned long elapsed,
unsigned long offset, int seed, char *filename)
{
int i;
char* suffix = strrchr(resume_file, '.');
@ -1082,7 +1082,7 @@ bool bookmark_play(char *resume_file, int index, int offset, int seed,
{
if (global_settings.playlist_shuffle)
playlist_shuffle(seed, -1);
playlist_start(index,offset);
playlist_start(index, elapsed, offset);
started = true;
}
*slash='/';
@ -1133,7 +1133,7 @@ bool bookmark_play(char *resume_file, int index, int offset, int seed,
else
return false;
}
playlist_start(index,offset);
playlist_start(index, elapsed, offset);
started = true;
}
}

View File

@ -139,8 +139,8 @@ struct tree_context* tree_get_context(void);
void tree_flush(void);
void tree_restore(void);
bool bookmark_play(char* resume_file, int index, int offset, int seed,
char *filename);
bool bookmark_play(char* resume_file, int index, unsigned long elapsed,
unsigned long offset, int seed, char *filename);
extern struct gui_synclist tree_lists;
#endif

View File

@ -49,7 +49,7 @@
void audio_init(void) INIT_ATTR;
void audio_play(long offset);
void audio_play(unsigned long elapsed, unsigned long offset);
void audio_stop(void);
/* Stops audio from serving playback and frees resources*/
void audio_hard_stop(void);

View File

@ -150,19 +150,28 @@ enum codec_status codec_run(void)
samplesdone = 0;
/* The main decoding loop */
if (ci->id3->offset) {
if (ci->seek_buffer(ci->id3->offset)) {
samplesdone = (ci->id3->offset / ci->id3->bytesperframe) *
A52_SAMPLESPERFRAME;
ci->set_elapsed(samplesdone/(ci->id3->frequency / 1000));
}
sample_loc = (ci->id3->offset / ci->id3->bytesperframe) *
A52_SAMPLESPERFRAME;
param = ci->id3->offset;
}
else if (ci->id3->elapsed) {
sample_loc = ci->id3->elapsed/1000 * ci->id3->frequency;
param = sample_loc/A52_SAMPLESPERFRAME*ci->id3->bytesperframe;
}
else {
ci->seek_buffer(ci->id3->first_frame_offset);
ci->set_elapsed(0);
sample_loc = 0;
param = ci->id3->first_frame_offset;
}
if (ci->seek_buffer(param)) {
samplesdone = sample_loc;
}
ci->set_elapsed(samplesdone/(ci->id3->frequency/1000));
/* The main decoding loop */
while (1) {
enum codec_command_action action = ci->get_command(&param);
@ -172,7 +181,8 @@ enum codec_status codec_run(void)
if (action == CODEC_ACTION_SEEK_TIME) {
sample_loc = param/1000 * ci->id3->frequency;
if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) {
if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*
ci->id3->bytesperframe)) {
samplesdone = sample_loc;
ci->set_elapsed(samplesdone/(ci->id3->frequency/1000));
}

View File

@ -148,13 +148,15 @@ enum codec_status codec_run(void)
int consumed, packet_offset;
int playback_on = -1;
size_t resume_offset;
enum codec_command_action action;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
if (codec_init()) {
return CODEC_ERROR;
}
action = CODEC_ACTION_NULL;
param = ci->id3->elapsed;
resume_offset = ci->id3->offset;
ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
@ -171,11 +173,14 @@ enum codec_status codec_run(void)
samplesdone = 0;
/* check for a mid-track resume and force a seek time accordingly */
if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) {
resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
if (resume_offset) {
resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE);
/* put number of subpackets to skip in resume_offset */
resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE);
param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
}
if (param > 0) {
action = CODEC_ACTION_SEEK_TIME;
}
else {

View File

@ -72,6 +72,7 @@ enum codec_status codec_run(void)
uint32_t sbr_fac = 1;
unsigned char c = 0;
void *ret;
enum codec_command_action action;
intptr_t param;
bool empty_first_frame = false;
@ -82,6 +83,8 @@ enum codec_status codec_run(void)
return CODEC_ERROR;
}
action = CODEC_ACTION_NULL;
param = ci->id3->elapsed;
file_offset = ci->id3->offset;
ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
@ -138,11 +141,16 @@ enum codec_status codec_run(void)
sound_samples_done = 0;
}
NeAACDecPostSeekReset(decoder, i);
elapsed_time = (sound_samples_done * 10) /
(ci->id3->frequency / 100);
} else if (param) {
elapsed_time = param;
action = CODEC_ACTION_SEEK_TIME;
} else {
elapsed_time = 0;
sound_samples_done = 0;
}
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
ci->set_elapsed(elapsed_time);
if (i == 0)
@ -152,7 +160,8 @@ enum codec_status codec_run(void)
/* The main decoding loop */
while (i < demux_res.num_sample_byte_sizes) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
@ -180,6 +189,8 @@ enum codec_status codec_run(void)
ci->seek_complete();
}
action = CODEC_ACTION_NULL;
/* There can be gaps between chunks, so skip ahead if needed. It
* doesn't seem to happen much, but it probably means that a
* "proper" file can have chunks out of order. Why one would want

View File

@ -99,6 +99,7 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
param = ci->id3->elapsed;
bytesdone = ci->id3->offset;
/* assume the AIFF header is less than 1024 bytes */
@ -270,10 +271,20 @@ enum codec_status codec_run(void)
ci->advance_buffer(firstblockposn);
/* make sure we're at the correct offset */
if (bytesdone > (uint32_t) firstblockposn) {
if (bytesdone > (uint32_t) firstblockposn || param) {
uint32_t seek_val;
int seek_mode;
if (bytesdone) {
seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone);
seek_mode = PCM_SEEK_POS;
} else {
seek_val = param;
seek_mode = PCM_SEEK_TIME;
}
/* Round down to previous block */
struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
PCM_SEEK_POS, NULL);
struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, NULL);
if (newpos->pos > format.numbytes)
return CODEC_OK;

View File

@ -50,7 +50,7 @@ enum codec_status codec_run(void)
demux_res_t demux_res;
stream_t input_stream;
uint32_t samplesdone;
uint32_t elapsedtime = 0;
uint32_t elapsedtime;
int samplesdecoded;
unsigned int i;
unsigned char* buffer;
@ -71,9 +71,9 @@ enum codec_status codec_run(void)
stream_create(&input_stream,ci);
/* Read from ci->id3->offset before calling qtmovie_read. */
samplesdone = (uint32_t)(((uint64_t)(ci->id3->offset) * ci->id3->frequency) /
(ci->id3->bitrate*128));
/* Read resume info before calling qtmovie_read. */
elapsedtime = ci->id3->elapsed;
samplesdone = ci->id3->offset;
/* if qtmovie_read returns successfully, the stream is up to
* the movie data, which can be used directly by the decoder */
@ -87,16 +87,24 @@ enum codec_status codec_run(void)
/* Set i for first frame, seek to desired sample position for resuming. */
i=0;
if (samplesdone > 0) {
if (m4a_seek(&demux_res, &input_stream, samplesdone,
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 (!m4a_seek(&demux_res, &input_stream, samplesdone,
&samplesdone, (int*) &i)) {
elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100);
ci->set_elapsed(elapsedtime);
} else {
samplesdone = 0;
}
}
elapsedtime = (samplesdone*10)/(ci->id3->frequency/100);
ci->set_elapsed(elapsedtime);
/* The main decoding loop */
@ -106,9 +114,6 @@ enum codec_status codec_run(void)
if (action == CODEC_ACTION_HALT)
break;
/* Request the required number of bytes from the input buffer */
buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE);
/* Deal with any pending seek requests */
if (action == CODEC_ACTION_SEEK_TIME) {
if (m4a_seek(&demux_res, &input_stream,

View File

@ -155,6 +155,7 @@ enum codec_status codec_run(void)
int res;
int firstbyte;
size_t resume_offset;
enum codec_command_action action;
intptr_t param;
if (codec_init()) {
@ -162,8 +163,12 @@ enum codec_status codec_run(void)
return CODEC_ERROR;
}
action = CODEC_ACTION_NULL;
param = 0;
/* Remember the resume position - when the codec is opened, the
playback engine will reset it. */
elapsedtime = ci->id3->elapsed;
resume_offset = ci->id3->offset;
ci->seek_buffer(0);
@ -213,14 +218,21 @@ enum codec_status codec_run(void)
ape_resume(&ape_ctx, resume_offset,
&currentframe, &samplesdone, &samplestoskip, &firstbyte);
} else {
elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
}
else {
currentframe = 0;
samplesdone = 0;
samplestoskip = 0;
firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
if (elapsedtime) {
/* Resume by simulated seeking */
param = elapsedtime;
action = CODEC_ACTION_SEEK_TIME;
}
}
elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
ci->set_elapsed(elapsedtime);
/* Initialise the buffer */
@ -247,36 +259,44 @@ frame_start:
/* Decode the frame a chunk at a time */
while (nblocks > 0)
{
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
goto done;
if (action != CODEC_ACTION_NULL) {
if (action == CODEC_ACTION_HALT)
goto done;
/* Deal with any pending seek requests */
if (action == CODEC_ACTION_SEEK_TIME)
{
if (ape_calc_seekpos(&ape_ctx,
(param/10) * (ci->id3->frequency/100),
&currentframe,
&newfilepos,
&samplestoskip))
/* Deal with any pending seek requests */
if (action == CODEC_ACTION_SEEK_TIME)
{
samplesdone = currentframe * ape_ctx.blocksperframe;
if (ape_calc_seekpos(&ape_ctx,
(param/10) * (ci->id3->frequency/100),
&currentframe,
&newfilepos,
&samplestoskip))
{
samplesdone = currentframe * ape_ctx.blocksperframe;
/* APE's bytestream is weird... */
firstbyte = 3 - (newfilepos & 3);
newfilepos &= ~3;
/* APE's bytestream is weird... */
firstbyte = 3 - (newfilepos & 3);
newfilepos &= ~3;
ci->seek_buffer(newfilepos);
inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
ci->seek_buffer(newfilepos);
inbuffer = ci->request_buffer(&bytesleft,
INPUT_CHUNKSIZE);
elapsedtime = (samplesdone*10)/
(ape_ctx.samplerate/100);
ci->set_elapsed(elapsedtime);
ci->seek_complete();
action = CODEC_ACTION_NULL;
goto frame_start; /* Sorry... */
}
elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
ci->set_elapsed(elapsedtime);
ci->seek_complete();
goto frame_start; /* Sorry... */
}
ci->seek_complete();
action = CODEC_ACTION_NULL;
}
blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks);

View File

@ -52,6 +52,8 @@ enum codec_status codec_run(void)
return CODEC_ERROR;
}
param = ci->id3->elapsed;
codec_set_replaygain(ci->id3);
int bytes_done =0;
@ -86,8 +88,6 @@ enum codec_status codec_run(void)
ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
bytesPerSample = 4;
}
/* reset eleapsed */
ci->set_elapsed(0);
song = asap.module_info->default_song;
duration = asap.module_info->durations[song];
@ -100,6 +100,11 @@ enum codec_status codec_run(void)
ASAP_PlaySong(&asap, song, duration);
ASAP_MutePokeyChannels(&asap, 0);
if (param)
goto resume_start;
ci->set_elapsed(0);
/* The main decoder loop */
while (1) {
enum codec_command_action action = ci->get_command(&param);
@ -108,6 +113,7 @@ enum codec_status codec_run(void)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
resume_start:
/* New time is ready in param */
/* seek to pos */

View File

@ -50,13 +50,15 @@ enum codec_status codec_run(void)
int elapsed = 0;
size_t resume_offset;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
enum codec_command_action action;
if (codec_init()) {
DEBUGF("codec init failed\n");
return CODEC_ERROR;
}
action = CODEC_ACTION_NULL;
param = ci->id3->elapsed;
resume_offset = ci->id3->offset;
codec_set_replaygain(ci->id3);
@ -79,11 +81,13 @@ enum codec_status codec_run(void)
frame_counter = 0;
/* check for a mid-track resume and force a seek time accordingly */
if(resume_offset > ci->id3->first_frame_offset) {
resume_offset -= ci->id3->first_frame_offset;
if (resume_offset) {
resume_offset -= MIN(resume_offset, ci->id3->first_frame_offset);
/* calculate resume_offset in frames */
resume_offset = (int)resume_offset / FRAMESIZE;
param = (int)resume_offset * ((FRAMESIZE * 8)/BITRATE);
param = (resume_offset/FRAMESIZE) * ((FRAMESIZE * 8)/BITRATE);
}
if ((unsigned long)param) {
action = CODEC_ACTION_SEEK_TIME;
}
else {
@ -100,11 +104,9 @@ enum codec_status codec_run(void)
if (action == CODEC_ACTION_HALT)
break;
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
if (action == CODEC_ACTION_SEEK_TIME) {
/* Do not allow seeking beyond the file's length */
if ((unsigned) param > ci->id3->length) {
if ((unsigned long) param > ci->id3->length) {
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
break;
@ -123,7 +125,6 @@ enum codec_status codec_run(void)
seek_frame_offset = (param * BITRATE) / (8 * FRAMESIZE);
frame_counter = seek_frame_offset;
ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE);
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
elapsed = param;
ci->set_elapsed(elapsed);
ci->seek_complete();
@ -131,6 +132,8 @@ enum codec_status codec_run(void)
action = CODEC_ACTION_NULL;
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
res = atrac3_decode_frame(FRAMESIZE, &q, &datasize, bit_buffer, FRAMESIZE);
if(res != (int)FRAMESIZE) {

View File

@ -57,17 +57,19 @@ enum codec_status codec_run(void)
uint8_t *bit_buffer;
uint16_t fs,sps,h;
uint32_t packet_count;
int scrambling_unit_size, num_units, elapsed = 0;
int scrambling_unit_size, num_units, elapsed;
int playback_on = -1;
size_t resume_offset;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
enum codec_command_action action;
if (codec_init()) {
DEBUGF("codec init failed\n");
return CODEC_ERROR;
}
action = CODEC_ACTION_NULL;
elapsed = ci->id3->elapsed;
resume_offset = ci->id3->offset;
codec_set_replaygain(ci->id3);
@ -98,15 +100,20 @@ enum codec_status codec_run(void)
}
/* check for a mid-track resume and force a seek time accordingly */
if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) {
resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
if(resume_offset) {
resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE);
num_units = (int)resume_offset / scrambling_unit_size;
/* put number of subpackets to skip in resume_offset */
resume_offset /= (sps + PACKET_HEADER_SIZE);
param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
elapsed = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
}
if (elapsed > 0) {
param = elapsed;
action = CODEC_ACTION_SEEK_TIME;
}
else {
elapsed = 0;
ci->set_elapsed(0);
}
@ -151,6 +158,7 @@ seek_start :
/* Seek to the start of the track */
if (param == 0) {
elapsed = 0;
ci->set_elapsed(0);
ci->seek_complete();
action = CODEC_ACTION_NULL;

View File

@ -139,6 +139,7 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
param = ci->id3->elapsed;
bytesdone = ci->id3->offset;
ci->memset(&format, 0, sizeof(struct pcm_format));
@ -236,10 +237,20 @@ enum codec_status codec_run(void)
}
/* make sure we're at the correct offset */
if (bytesdone > (uint32_t) firstblockposn) {
if (bytesdone > (uint32_t) firstblockposn || param) {
uint32_t seek_val;
int seek_mode;
if (bytesdone) {
seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone);
seek_mode = PCM_SEEK_POS;
} else {
seek_val = param;
seek_mode = PCM_SEEK_TIME;
}
/* Round down to previous block */
struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
PCM_SEEK_POS, NULL);
struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode, NULL);
if (newpos->pos > format.numbytes)
goto done;

View File

@ -56,6 +56,7 @@ enum codec_status codec_run(void)
/* reset values */
track = is_multitrack = 0;
elapsed_time = 0;
param = ci->id3->elapsed;
DEBUGF("AY: next_track\n");
if (codec_init()) {
@ -87,6 +88,10 @@ enum codec_status codec_run(void)
is_multitrack = 1;
}
if (param) {
goto resume_start;
}
next_track:
set_codec_track(track, is_multitrack);
@ -98,6 +103,7 @@ next_track:
break;
if (action == CODEC_ACTION_SEEK_TIME) {
resume_start:
if (is_multitrack) {
track = param/1000;
ci->seek_complete();

View File

@ -56,14 +56,16 @@ enum codec_status codec_run(void)
uint32_t packet_count;
int scrambling_unit_size, num_units;
size_t resume_offset;
intptr_t param = 0;
enum codec_command_action action = CODEC_ACTION_NULL;
intptr_t param;
enum codec_command_action action;
if (codec_init()) {
DEBUGF("codec init failed\n");
return CODEC_ERROR;
}
action = CODEC_ACTION_NULL;
param = ci->id3->elapsed;
resume_offset = ci->id3->offset;
codec_set_replaygain(ci->id3);
@ -97,12 +99,15 @@ enum codec_status codec_run(void)
}
/* check for a mid-track resume and force a seek time accordingly */
if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) {
resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
if(resume_offset) {
resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE);
num_units = (int)resume_offset / scrambling_unit_size;
/* put number of subpackets to skip in resume_offset */
resume_offset /= (sps + PACKET_HEADER_SIZE);
param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
}
if (param) {
action = CODEC_ACTION_SEEK_TIME;
}
else {

View File

@ -468,7 +468,8 @@ enum codec_status codec_run(void)
return CODEC_ERROR;
}
/* Need to save offset for later use (cleared indirectly by flac_init) */
/* Need to save resume for later use (cleared indirectly by flac_init) */
elapsedtime = ci->id3->elapsed;
samplesdone = ci->id3->offset;
if (!flac_init(&fc,ci->id3->first_frame_offset)) {
@ -481,9 +482,16 @@ enum codec_status codec_run(void)
STEREO_MONO : STEREO_NONINTERLEAVED);
codec_set_replaygain(ci->id3);
flac_seek_offset(&fc, samplesdone);
samplesdone=fc.samplenumber+fc.blocksize;
elapsedtime=((uint64_t)samplesdone*1000)/(ci->id3->frequency);
if (samplesdone || !elapsedtime) {
flac_seek_offset(&fc, samplesdone);
samplesdone=fc.samplenumber+fc.blocksize;
elapsedtime=((uint64_t)samplesdone*1000)/(ci->id3->frequency);
}
else if (!flac_seek(&fc,(uint32_t)((uint64_t)elapsedtime
*ci->id3->frequency/1000))) {
elapsedtime = 0;
}
ci->set_elapsed(elapsedtime);
/* The main decoding loop */

View File

@ -76,6 +76,11 @@ enum codec_status codec_run(void)
if (gbs_emu.m3u.size > 0)
gbs_emu.track_count = gbs_emu.m3u.size;
if (ci->id3->elapsed) {
track = ci->id3->elapsed/1000;
if (track >= gbs_emu.track_count) return CODEC_OK;
}
next_track:
set_codec_track(track);

View File

@ -76,6 +76,11 @@ enum codec_status codec_run(void)
if (hes_emu.m3u.size > 0)
hes_emu.track_count = hes_emu.m3u.size;
if (ci->id3->elapsed) {
track = ci->id3->elapsed/1000;
if (track >= hes_emu.track_count) return CODEC_OK;
}
next_track:
set_codec_track(track);

View File

@ -79,6 +79,11 @@ enum codec_status codec_run(void)
if (kss_emu.m3u.size > 0)
kss_emu.track_count = kss_emu.m3u.size;
if (ci->id3->elapsed) {
track = ci->id3->elapsed/1000;
if (track >= kss_emu.track_count) return CODEC_OK;
}
next_track:
set_codec_track(track);

View File

@ -1319,7 +1319,16 @@ enum codec_status codec_run(void)
loadmod(modfile);
/* The main decoder loop */
ci->set_elapsed(0);
#if 0
/* Needs to be a bit more elaborate or critical stuff is missed */
if (ci->id3->elapsed) {
modplayer.patterntableposition = ci->id3->elapsed/1000;
modplayer.currentline = 0;
}
#endif
ci->set_elapsed(modplayer.patterntableposition*1000);
bytesdone = 0;
old_patterntableposition = 0;

View File

@ -346,6 +346,11 @@ enum codec_status codec_run(void)
current_frequency = ci->id3->frequency;
codec_set_replaygain(ci->id3);
if (!ci->id3->offset && ci->id3->elapsed) {
/* Have elapsed time but not offset */
ci->id3->offset = get_file_pos(ci->id3->elapsed);
}
if (ci->id3->offset) {
ci->seek_buffer(ci->id3->offset);
set_elapsed(ci->id3);

View File

@ -108,6 +108,7 @@ enum codec_status codec_run(void)
* sample seek position from the file offset, the sampling frequency and
* the bitrate. As the saved position is exactly calculated the reverse way
* there is no loss of information except rounding. */
elapsed_time = ci->id3->elapsed;
samplesdone = 100 * (((mpc_uint64_t)ci->id3->offset * frequency) / byterate);
/* Set up digital signal processing for correct number of channels */
@ -122,19 +123,24 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
/* Resume to saved sample offset. */
elapsed_time = 0;
if (samplesdone > 0)
if (samplesdone > 0 || elapsed_time)
{
if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK)
mpc_int64_t new_offset = samplesdone;
if (new_offset <= 0)
new_offset = (elapsed_time/10)*frequency; /* by time */
/* Resume to sample offset. */
if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK)
{
elapsed_time = (samplesdone*10)/frequency;
samplesdone = new_offset;
}
else
{
samplesdone = 0;
}
elapsed_time = (samplesdone*10)/frequency;
}
ci->set_elapsed(elapsed_time);

View File

@ -57,6 +57,7 @@ enum codec_status codec_run(void)
track = is_multitrack = 0;
elapsed_time = 0;
param = ci->id3->elapsed;
DEBUGF("NSF: next_track\n");
if (codec_init()) {
@ -85,6 +86,10 @@ enum codec_status codec_run(void)
if (nsf_emu.track_count > 1) is_multitrack = 1;
if (param) {
goto resume_start;
}
next_track:
set_codec_track(track, is_multitrack);
@ -96,6 +101,7 @@ next_track:
break;
if (action == CODEC_ACTION_SEEK_TIME) {
resume_start:
if (is_multitrack) {
track = param/1000;
ci->seek_complete();

View File

@ -314,6 +314,7 @@ enum codec_status codec_main(enum codec_entry_call_reason reason)
enum codec_status codec_run(void)
{
int error = CODEC_ERROR;
enum codec_command_action action;
intptr_t param;
ogg_sync_state oy;
ogg_page og;
@ -325,13 +326,17 @@ enum codec_status codec_run(void)
OpusDecoder *st = NULL;
OpusHeader header;
int ret;
unsigned long strtoffset = ci->id3->offset;
unsigned long strtoffset;
int skip = 0;
int64_t seek_target;
uint64_t granule_pos;
ogg_malloc_init();
action = CODEC_ACTION_NULL;
param = ci->id3->elapsed;
strtoffset = ci->id3->offset;
global_stack = 0;
#if defined(CPU_COLDFIRE)
@ -351,28 +356,40 @@ enum codec_status codec_run(void)
ci->seek_buffer(0);
ci->set_elapsed(0);
if (!strtoffset && param) {
action = CODEC_ACTION_SEEK_TIME;
}
goto next_page;
while (1) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (action != CODEC_ACTION_NULL) {
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
if (st != NULL) {
/* calculate granule to seek to (including seek rewind) */
seek_target = (48LL * param) + header.preskip;
skip = MIN(seek_target, SEEK_REWIND);
seek_target -= skip;
if (action == CODEC_ACTION_SEEK_TIME) {
if (st != NULL) {
/* calculate granule to seek to (including seek rewind) */
seek_target = (48LL * param) + header.preskip;
skip = MIN(seek_target, SEEK_REWIND);
seek_target -= skip;
LOGF("Opus seek page:%lld,%lld,%ld\n",
seek_target, page_granule, (long)param);
speex_seek_page_granule(seek_target, page_granule, &oy, &os);
LOGF("Opus seek page:%lld,%lld,%ld\n",
seek_target, page_granule, (long)param);
speex_seek_page_granule(seek_target, page_granule, &oy, &os);
}
ci->set_elapsed(param);
ci->seek_complete();
}
ci->set_elapsed(param);
ci->seek_complete();
action = CODEC_ACTION_NULL;
}
next_page:
/*Get the ogg buffer for writing*/
if (get_more_data(&oy) < 1) {
goto done;

View File

@ -63,14 +63,16 @@ enum codec_status codec_run(void)
unsigned char c = 0; /* channels */
int playback_on = -1;
size_t resume_offset;
enum codec_command_action action;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
if (codec_init()) {
DEBUGF("FAAD: Codec init error\n");
return CODEC_ERROR;
}
action = CODEC_ACTION_NULL;
param = ci->id3->elapsed;
resume_offset = ci->id3->offset;
ci->memset(&rmctx,0,sizeof(RMContext));
@ -104,15 +106,21 @@ enum codec_status codec_run(void)
}
/* check for a mid-track resume and force a seek time accordingly */
if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) {
resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
if (resume_offset) {
resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE);
/* put number of subpackets to skip in resume_offset */
resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE);
param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
}
if (param > 0) {
action = CODEC_ACTION_SEEK_TIME;
}
ci->set_elapsed(0);
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
else {
/* Seek to the first packet */
ci->set_elapsed(0);
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
}
/* The main decoding loop */
while (1) {
@ -124,7 +132,7 @@ enum codec_status codec_run(void)
if (action == CODEC_ACTION_SEEK_TIME) {
/* Do not allow seeking beyond the file's length */
if ((unsigned) param > ci->id3->length) {
if ((unsigned long)param > ci->id3->length) {
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
break;
@ -164,6 +172,7 @@ enum codec_status codec_run(void)
ci->advance_buffer(pkt.length);
}
ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE);
buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000);
NeAACDecPostSeekReset(decoder, decoder->frame);

View File

@ -91,6 +91,11 @@ enum codec_status codec_run(void)
if (sgc_emu.m3u.size > 0)
sgc_emu.track_count = sgc_emu.m3u.size;
if (ci->id3->elapsed) {
track = ci->id3->elapsed/1000;
if (track >= sgc_emu.track_count) return CODEC_OK;
}
next_track:
set_codec_track(track);

View File

@ -1253,6 +1253,7 @@ enum codec_status codec_run(void)
unsigned char subSongsMax, subSong, song_speed;
unsigned char *sidfile = NULL;
intptr_t param;
bool resume;
if (codec_init()) {
return CODEC_ERROR;
@ -1269,15 +1270,10 @@ enum codec_status codec_run(void)
return CODEC_ERROR;
}
c64Init(SAMPLE_RATE);
LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
&subSongsMax, &subSong, &song_speed, (unsigned short)filesize);
sidPoke(24, 15); /* Turn on full volume */
cpuJSR(init_addr, subSong); /* Start the song initialize */
param = ci->id3->elapsed;
resume = param != 0;
/* Set the elapsed time to the current subsong (in seconds) */
ci->set_elapsed(subSong*1000);
goto sid_start;
/* The main decoder loop */
while (1) {
@ -1287,20 +1283,26 @@ enum codec_status codec_run(void)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
sid_start:
/* New time is ready in param */
/* Start playing from scratch */
c64Init(SAMPLE_RATE);
LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
&subSongsMax, &subSong, &song_speed, (unsigned short)filesize);
&subSongsMax, &subSong, &song_speed,
(unsigned short)filesize);
sidPoke(24, 15); /* Turn on full volume */
subSong = param / 1000; /* Now use the current seek time in seconds as subsong */
if (!resume || (resume && param))
subSong = param / 1000; /* Now use the current seek time in
seconds as subsong */
cpuJSR(init_addr, subSong); /* Start the song initialize */
nSamplesToRender = 0; /* Start the rendering from scratch */
/* Set the elapsed time to the current subsong (in seconds) */
ci->set_elapsed(subSong*1000);
ci->seek_complete();
resume = false;
}
nSamplesRendered = 0;

View File

@ -360,7 +360,8 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
/* Need to save resume for later use (cleared indirectly by advance_buffer) */
param = ci->id3->elapsed;
bytesdone = ci->id3->offset;
decodedsamples = 0;
@ -408,11 +409,21 @@ enum codec_status codec_run(void)
ci->seek_buffer(firstblockposn);
/* make sure we're at the correct offset */
if (bytesdone > (uint32_t) firstblockposn)
{
if (bytesdone > (uint32_t) firstblockposn || param) {
uint32_t seek_val;
int seek_mode;
if (bytesdone) {
seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone);
seek_mode = PCM_SEEK_POS;
} else {
seek_val = param;
seek_mode = PCM_SEEK_TIME;
}
/* Round down to previous block */
struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
PCM_SEEK_POS, &read_buffer);
struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode,
&read_buffer);
if (newpos->pos > format.numbytes)
return CODEC_OK;

View File

@ -381,7 +381,6 @@ enum codec_status codec_run(void)
int error = CODEC_ERROR;
SpeexBits bits;
int eof = 0;
spx_ogg_sync_state oy;
spx_ogg_page og;
spx_ogg_packet op;
@ -403,9 +402,10 @@ enum codec_status codec_run(void)
int packet_count = 0;
int lookahead;
int headerssize = 0;
unsigned long strtoffset = ci->id3->offset;
unsigned long strtoffset;
void *st = NULL;
int j = 0;
enum codec_command_action action;
intptr_t param;
memset(&bits, 0, sizeof(bits));
@ -416,6 +416,10 @@ enum codec_status codec_run(void)
goto exit;
}
action = CODEC_ACTION_NULL;
param = ci->id3->elapsed;
strtoffset = ci->id3->offset;
ci->seek_buffer(0);
ci->set_elapsed(0);
@ -425,29 +429,39 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
eof = 0;
while (!eof) {
enum codec_command_action action = ci->get_command(&param);
if (!strtoffset && param) {
action = CODEC_ACTION_SEEK_TIME;
}
if (action == CODEC_ACTION_HALT)
break;
goto next_page;
/*seek (seeks to the page before the position) */
if (action == CODEC_ACTION_SEEK_TIME) {
if(samplerate!=0&&packet_count>1){
LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n",
((spx_int64_t)param/1000) *
(spx_int64_t)samplerate,
page_granule, (long)param,
(page_granule/samplerate)*1000, samplerate);
while (1) {
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
speex_seek_page_granule(((spx_int64_t)param/1000) *
(spx_int64_t)samplerate,
page_granule, &oy, headerssize);
if (action != CODEC_ACTION_NULL) {
if (action == CODEC_ACTION_HALT)
break;
/*seek (seeks to the page before the position) */
if (action == CODEC_ACTION_SEEK_TIME) {
if(samplerate!=0&&packet_count>1){
LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n",
((spx_int64_t)param/1000) *
(spx_int64_t)samplerate,
page_granule, (long)param,
(page_granule/samplerate)*1000, samplerate);
speex_seek_page_granule(((spx_int64_t)param/1000) *
(spx_int64_t)samplerate,
page_granule, &oy, headerssize);
}
ci->set_elapsed(param);
ci->seek_complete();
}
ci->set_elapsed(param);
ci->seek_complete();
action = CODEC_ACTION_NULL;
}
next_page:

View File

@ -82,10 +82,20 @@ enum codec_status codec_run(void)
decodedsamples = 0;
endofstream = 0;
if (ci->id3->offset > 0)
if (ci->id3->offset || ci->id3->elapsed)
{
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
new_pos = set_position(ci->id3->offset, TTA_SEEK_POS);
/* Need to save offset for later use (cleared indirectly by
advance_buffer) */
unsigned int pos = ci->id3->offset;
enum tta_seek_type type = TTA_SEEK_POS;
if (!pos) {
pos = ci->id3->elapsed / SEEK_STEP;
type = TTA_SEEK_TIME;
}
new_pos = set_position(pos, type);
if (new_pos >= 0)
decodedsamples = new_pos;
}

View File

@ -127,7 +127,10 @@ enum codec_status codec_run(void)
Vgm_start_track(&vgm_emu);
ci->set_elapsed(0);
if (ci->id3->elapsed != 0)
Track_seek(&vgm_emu, ci->id3->elapsed);
codec_update_elapsed();
codec_update_fade();
/* The main decoder loop */

View File

@ -126,7 +126,6 @@ enum codec_status codec_run(void)
long n;
int current_section;
int previous_section;
int eof;
ogg_int64_t vf_offsets[2];
ogg_int64_t vf_dataoffsets;
ogg_uint32_t vf_serialnos;
@ -193,16 +192,17 @@ enum codec_status codec_run(void)
if (ci->id3->offset) {
ci->seek_buffer(ci->id3->offset);
ov_raw_seek(&vf, ci->id3->offset);
ci->set_elapsed(ov_time_tell(&vf));
ci->set_offset(ov_raw_tell(&vf));
}
else {
ci->set_elapsed(0);
else if (ci->id3->elapsed) {
ov_time_seek(&vf, ci->id3->elapsed);
}
ci->set_elapsed(ov_time_tell(&vf));
previous_section = -1;
eof = 0;
while (!eof) {
while (1) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
@ -230,7 +230,7 @@ enum codec_status codec_run(void)
}
if (n == 0) {
eof = 1;
break;
} else if (n < 0) {
DEBUGF("Vorbis: Error decoding frame\n");
} else {

View File

@ -73,7 +73,8 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
/* Need to save resume for later use (cleared indirectly by advance_buffer) */
param = ci->id3->elapsed;
bytesdone = ci->id3->offset;
ci->seek_buffer(0);
@ -123,10 +124,21 @@ enum codec_status codec_run(void)
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
/* make sure we're at the correct offset */
if (bytesdone > (uint32_t) firstblockposn) {
if (bytesdone > (uint32_t) firstblockposn || param) {
uint32_t seek_val;
int seek_mode;
if (bytesdone) {
seek_val = bytesdone - MIN((uint32_t )firstblockposn, bytesdone);
seek_mode = PCM_SEEK_POS;
} else {
seek_val = param;
seek_mode = PCM_SEEK_TIME;
}
/* Round down to previous block */
struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
PCM_SEEK_POS, &read_buffer);
struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode,
&read_buffer);
if (newpos->pos > format.numbytes) {
return CODEC_OK;

View File

@ -182,7 +182,8 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
/* Need to save resume for later use (cleared indirectly by advance_buffer) */
param = ci->id3->elapsed;
bytesdone = ci->id3->offset;
/* get RIFF chunk header */
@ -361,10 +362,21 @@ enum codec_status codec_run(void)
}
/* make sure we're at the correct offset */
if (bytesdone > (uint32_t) firstblockposn) {
if (bytesdone > (uint32_t) firstblockposn || param) {
uint32_t seek_val;
int seek_mode;
if (bytesdone) {
seek_val = bytesdone - MIN((uint32_t) firstblockposn, bytesdone);
seek_mode = PCM_SEEK_POS;
} else {
seek_val = param;
seek_mode = PCM_SEEK_TIME;
}
/* Round down to previous block */
struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
PCM_SEEK_POS, &read_buffer);
struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode,
&read_buffer);
if (newpos->pos > format.numbytes)
return CODEC_OK;

View File

@ -191,6 +191,7 @@ enum codec_status codec_run(void)
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
param = ci->id3->elapsed;
bytesdone = ci->id3->offset;
/* get RIFF chunk header */
@ -363,10 +364,22 @@ enum codec_status codec_run(void)
}
/* make sure we're at the correct offset */
if (bytesdone > (uint32_t) firstblockposn) {
if (bytesdone > (uint32_t) firstblockposn || param) {
uint32_t seek_val;
int seek_mode;
/* we prefer offset resume */
if (bytesdone > (uint32_t) firstblockposn) {
seek_val = bytesdone - firstblockposn;
seek_mode = PCM_SEEK_POS;
} else {
seek_val = param;
seek_mode = PCM_SEEK_TIME;
}
/* Round down to previous block */
struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
PCM_SEEK_POS, &read_buffer);
struct pcm_pos *newpos = codec->get_seek_pos(seek_val, seek_mode,
&read_buffer);
if (newpos->pos > format.numbytes) {
return CODEC_OK;

View File

@ -55,12 +55,16 @@ enum codec_status codec_run(void)
int bps;
*/
int nchans, sr_100;
unsigned long offset;
intptr_t param;
if (codec_init())
return CODEC_ERROR;
ci->seek_buffer (ci->id3->offset);
param = ci->id3->elapsed;
offset = ci->id3->offset;
ci->seek_buffer (offset);
/* Create a decoder instance */
wpc = WavpackOpenFileInput (read_callback, error);
@ -75,7 +79,12 @@ enum codec_status codec_run(void)
ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO);
sr_100 = ci->id3->frequency / 100;
ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
if (!offset && param) {
goto resume_start; /* resume by elapsed */
}
else {
ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
}
/* The main decoder loop */
@ -87,6 +96,7 @@ enum codec_status codec_run(void)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
resume_start:;
int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10;
int n, d, skip;

View File

@ -52,13 +52,16 @@ enum codec_status codec_run(void)
int audiobufsize;
int packetlength = 0;
int errcount = 0;
enum codec_command_action action;
intptr_t param;
/* Remember the resume position - when the codec is opened, the
playback engine will reset it. */
elapsedtime = ci->id3->elapsed;
resume_offset = ci->id3->offset;
restart_track:
action = CODEC_ACTION_NULL;
/* Proper reset of the decoder context. */
memset(&wmadec, 0, sizeof(wmadec));
@ -78,13 +81,20 @@ restart_track:
return CODEC_ERROR;
}
if (resume_offset > ci->id3->first_frame_offset)
if (resume_offset > ci->id3->first_frame_offset || elapsedtime)
{
/* Get start of current packet */
int packet_offset = (resume_offset - ci->id3->first_frame_offset)
% wfx.packet_size;
ci->seek_buffer(resume_offset - packet_offset);
elapsedtime = asf_get_timestamp(&i);
if (resume_offset) {
/* Get start of current packet */
int packet_offset = (resume_offset -
MIN(resume_offset, ci->id3->first_frame_offset))
% wfx.packet_size;
ci->seek_buffer(resume_offset - packet_offset);
elapsedtime = asf_get_timestamp(&i);
}
else {
param = elapsedtime;
action = CODEC_ACTION_SEEK_TIME;
}
}
else
{
@ -104,7 +114,8 @@ restart_track:
/* The main decoding loop */
while (res >= 0)
{
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (action != CODEC_ACTION_NULL) {
@ -126,6 +137,7 @@ restart_track:
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
elapsedtime = 0;
goto restart_track; /* Pretend you never saw this... */
}
@ -140,6 +152,8 @@ restart_track:
ci->set_elapsed(elapsedtime);
ci->seek_complete();
}
action = CODEC_ACTION_NULL;
}
errcount = 0;

View File

@ -55,6 +55,8 @@ enum codec_status codec_run(void)
int size; /* Size of the input frame to the decoder */
intptr_t param;
elapsedtime = ci->id3->elapsed;
restart_track:
if (codec_init()) {
LOGF("(WMA PRO) Error: Error initialising codec\n");
@ -75,11 +77,17 @@ restart_track:
return CODEC_ERROR;
}
/* Now advance the file position to the first frame */
ci->seek_buffer(ci->id3->first_frame_offset);
if (elapsedtime) {
elapsedtime = asf_seek(elapsedtime, &wfx);
if (elapsedtime < 1)
return CODEC_OK;
}
else {
/* Now advance the file position to the first frame */
ci->seek_buffer(ci->id3->first_frame_offset);
}
elapsedtime = 0;
ci->set_elapsed(0);
ci->set_elapsed(elapsedtime);
/* The main decoding loop */
@ -95,6 +103,7 @@ restart_track:
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
elapsedtime = 0;
goto restart_track; /* Pretend you never saw this... */
}

View File

@ -67,7 +67,6 @@ enum codec_status codec_run(void)
{
uint32_t elapsedtime;
asf_waveformatex_t wfx; /* Holds the stream properties */
size_t resume_offset;
int res; /* Return values from asf_read_packet() and decode_packet() */
uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */
int audiobufsize; /* Payload size */
@ -76,8 +75,8 @@ enum codec_status codec_run(void)
int pktcnt = 0; /* Count of the packets played */
intptr_t param;
/* Remember the resume position */
resume_offset = ci->id3->offset;
elapsedtime = ci->id3->elapsed;
restart_track:
if (codec_init()) {
LOGF("(WMA Voice) Error: Error initialising codec\n");
@ -105,13 +104,17 @@ restart_track:
return CODEC_ERROR;
}
/* Now advance the file position to the first frame */
ci->seek_buffer(ci->id3->first_frame_offset);
elapsedtime = 0;
ci->set_elapsed(0);
if (elapsedtime) {
elapsedtime = asf_seek(elapsedtime, &wfx);
if (elapsedtime < 1)
return CODEC_OK;
}
else {
/* Now advance the file position to the first frame */
ci->seek_buffer(ci->id3->first_frame_offset);
}
resume_offset = 0;
ci->set_elapsed(elapsedtime);
/* The main decoding loop */
@ -129,6 +132,7 @@ restart_track:
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
elapsedtime = 0;
goto restart_track; /* Pretend you never saw this... */
}
@ -136,7 +140,7 @@ restart_track:
if (elapsedtime < 1){
ci->set_elapsed(0);
ci->seek_complete();
goto next_track;
break;
}
ci->set_elapsed(elapsedtime);