1
0
Fork 0
forked from len0rd/rockbox

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

@ -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);