From c4b7c671f92b4dab028c45091c94e40dcead3443 Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Mon, 11 Jul 2005 06:47:35 +0000 Subject: Patch #1235763 by Ryan Jackson - Resume/bookmark support for Vorbis git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7098 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/vorbis.c | 171 +++++++++++++++++++++++++++++---------------------- apps/playback.c | 5 +- 2 files changed, 101 insertions(+), 75 deletions(-) diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c index 353b90fb0b..561fbb4601 100644 --- a/apps/codecs/vorbis.c +++ b/apps/codecs/vorbis.c @@ -25,6 +25,8 @@ #include "dsp.h" #include "lib/codeclib.h" +#define TEST_RESUME + static struct codec_api* rb; /* Some standard functions and variables needed by Tremor */ @@ -88,6 +90,38 @@ long tell_handler(void *datasource) return rb->curpos; } +/* This sets the DSP parameters based on the current logical bitstream + * (sampling rate, number of channels, etc). It also tries to guess + * reasonable buffer parameters based on the current quality setting. + */ +bool vorbis_set_codec_parameters(OggVorbis_File *vf) +{ + vorbis_info* vi; + + vi=ov_info(vf,-1); + + if (vi==NULL) { + //rb->splash(HZ*2, true, "Vorbis Error"); + return false; + } + + if (rb->id3->frequency != NATIVE_FREQUENCY) { + rb->configure(CODEC_DSP_ENABLE, (bool *)true); + } else { + rb->configure(CODEC_DSP_ENABLE, (bool *)false); + } + + rb->configure(DSP_SET_FREQUENCY, (int *)rb->id3->frequency); + + if (vi->channels == 2) { + rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); + } else if (vi->channels == 1) { + rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_MONO); + } + + return true; +} + #ifdef USE_IRAM extern char iramcopy[]; extern char iramstart[]; @@ -103,17 +137,16 @@ enum codec_status codec_start(struct codec_api* api) { ov_callbacks callbacks; OggVorbis_File vf; - vorbis_info* vi; int error; long n; int current_section; + int previous_section = -1; int eof; ogg_int64_t vf_offsets[2]; ogg_int64_t vf_dataoffsets; ogg_uint32_t vf_serialnos; ogg_int64_t vf_pcmlengths[2]; - int current_stereo_mode = -1; TEST_CODEC_API(api); @@ -125,11 +158,19 @@ enum codec_status codec_start(struct codec_api* api) rb->memcpy(iramstart, iramcopy, iramend-iramstart); #endif - rb->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); - rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*64)); - rb->configure(DSP_DITHER, (bool *)false); rb->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16)); + + /* Note: These are sane defaults for these values. Perhaps + * they should be set differently based on quality setting + */ + rb->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); + + /* The chunk size below is magic. If set any lower, resume + * doesn't work properly (ov_raw_seek() does the wrong thing). + */ + rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); + /* We need to flush reserver memory every track load. */ next_track: @@ -139,14 +180,7 @@ enum codec_status codec_start(struct codec_api* api) while (!*rb->taginfo_ready && !rb->stop_codec) rb->yield(); - - if (rb->id3->frequency != NATIVE_FREQUENCY) { - rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency)); - rb->configure(CODEC_DSP_ENABLE, (bool *)true); - } else { - rb->configure(CODEC_DSP_ENABLE, (bool *)false); - } - + /* Create a decoder instance */ callbacks.read_func=read_handler; callbacks.seek_func=initial_seek_handler; @@ -158,7 +192,7 @@ enum codec_status codec_start(struct codec_api* api) /* If the non-seekable open was successful, we need to supply the missing * data to make it seekable. This is a hack, but it's reasonable since we - * don't want to read the whole file into the buffer before we start + * don't want to run the whole file through the buffer before we start * playing. Using Tremor's seekable open routine would cause us to do * this, so we pretend not to be seekable at first. Then we fill in the * missing fields of vf with 1) information in rb->id3, and 2) info @@ -169,54 +203,32 @@ enum codec_status codec_start(struct codec_api* api) * get here. */ if ( !error ) { - //rb->logf("no error"); - /* FIXME Should these be dynamically allocated? */ - vf.offsets = vf_offsets; - vf.dataoffsets = &vf_dataoffsets; - vf.serialnos = &vf_serialnos; - vf.pcmlengths = vf_pcmlengths; - - vf.offsets[0] = 0; - vf.offsets[1] = rb->id3->filesize; - vf.dataoffsets[0] = vf.offset; - vf.pcmlengths[0] = 0; - vf.pcmlengths[1] = rb->id3->samples; - vf.serialnos[0] = vf.current_serialno; - vf.callbacks.seek_func=seek_handler; - vf.seekable = 1; - vf.offset = 58; /* length of Ogg header */ - vf.end = rb->id3->filesize; - vf.ready_state = OPENED; - vf.links = 1; - - /*if(ov_raw_seek(&vf,0)){ - rb->logf("seek err"); - } - */ - + vf.offsets = vf_offsets; + vf.dataoffsets = &vf_dataoffsets; + vf.serialnos = &vf_serialnos; + vf.pcmlengths = vf_pcmlengths; + + vf.offsets[0] = 0; + vf.offsets[1] = rb->id3->filesize; + vf.dataoffsets[0] = vf.offset; + vf.pcmlengths[0] = 0; + vf.pcmlengths[1] = rb->id3->samples; + vf.serialnos[0] = vf.current_serialno; + vf.callbacks.seek_func=seek_handler; + vf.seekable = 1; + vf.end = rb->id3->filesize; + vf.ready_state = OPENED; + vf.links = 1; } else { - //rb->logf("ov_open: %d", error); - } - - vi=ov_info(&vf,-1); - - if (vi==NULL) { - //rb->splash(HZ*2, true, "Vorbis Error"); - return CODEC_ERROR; + //rb->logf("ov_open: %d", error); + return CODEC_ERROR; } - rb->configure(DSP_SET_FREQUENCY, (int *)rb->id3->frequency); - - if (vi->channels == 2) { - if (current_stereo_mode != STEREO_INTERLEAVED) { - rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); - current_stereo_mode = STEREO_INTERLEAVED; - } - } else if (vi->channels == 1) { - if (current_stereo_mode != STEREO_MONO) { - rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_MONO); - current_stereo_mode = STEREO_MONO; - } + if ( rb->id3->offset ) { + rb->advance_buffer(rb->id3->offset); + ov_raw_seek(&vf,rb->id3->offset); + rb->id3->offset = ov_raw_tell(&vf); + rb->set_elapsed(ov_time_tell(&vf)); } eof=0; @@ -226,9 +238,9 @@ enum codec_status codec_start(struct codec_api* api) break ; if (rb->seek_time) { - + if (ov_time_seek(&vf, rb->seek_time)) { - //rb->logf("ov_time_seek failed"); + //rb->logf("ov_time_seek failed"); } rb->seek_time = 0; } @@ -236,6 +248,15 @@ enum codec_status codec_start(struct codec_api* api) /* Read host-endian signed 16 bit PCM samples */ n=ov_read(&vf,pcmbuf,sizeof(pcmbuf),¤t_section); + /* Change DSP and buffer settings for this bitstream */ + if ( current_section != previous_section ) { + if (!vorbis_set_codec_parameters(&vf)) { + return CODEC_ERROR; + } else { + previous_section = current_section; + } + } + if (n==0) { eof=1; } else if (n < 0) { @@ -243,29 +264,31 @@ enum codec_status codec_start(struct codec_api* api) } else { while (!rb->audiobuffer_insert(pcmbuf, n)) { rb->yield(); - if ( rb->seek_time ) { - /* Hmmm, a seek was requested. Throw out the - * buffer and go back to the top of the loop. - */ - break; - } - } - if ( !rb->seek_time ) { - rb->set_elapsed(ov_time_tell(&vf)); - rb->yield(); - } + if ( rb->seek_time ) { + /* Hmmm, a seek was requested. Throw out the + * buffer and go back to the top of the loop. + */ + break; + } + } + if ( !rb->seek_time ) { + rb->id3->offset = ov_raw_tell(&vf); + rb->set_elapsed(ov_time_tell(&vf)); + rb->yield(); + } } } if (rb->request_next_track()) { - /* Clean things up for the next track */ + /* Clean things up for the next track */ vf.dataoffsets = NULL; vf.offsets = NULL; vf.serialnos = NULL; vf.pcmlengths = NULL; - ov_clear(&vf); + ov_clear(&vf); goto next_track; } return CODEC_OK; } + diff --git a/apps/playback.c b/apps/playback.c index 8bc2f3b79e..9393b8fa75 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -477,7 +477,7 @@ static bool rebuffer_and_seek(int newpos) if (ci.stop_codec) return false; } - + return true; } @@ -962,6 +962,9 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) ci.curpos = offset; tracks[track_widx].start_pos = offset; break; + case AFMT_OGG_VORBIS: + tracks[track_widx].id3.offset = offset; + break; } } -- cgit v1.2.3