summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2005-07-11 06:47:35 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2005-07-11 06:47:35 +0000
commitc4b7c671f92b4dab028c45091c94e40dcead3443 (patch)
treee4d3c4b57c4864884e60defbf5d13c4246db44c3
parentb1ecc8319d3691d839b2469a91847a189a768874 (diff)
downloadrockbox-c4b7c671f92b4dab028c45091c94e40dcead3443.zip
rockbox-c4b7c671f92b4dab028c45091c94e40dcead3443.tar.gz
rockbox-c4b7c671f92b4dab028c45091c94e40dcead3443.tar.bz2
rockbox-c4b7c671f92b4dab028c45091c94e40dcead3443.tar.xz
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
-rw-r--r--apps/codecs/vorbis.c171
-rw-r--r--apps/playback.c5
2 files changed, 101 insertions, 75 deletions
diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c
index 353b90f..561fbb4 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),&current_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 8bc2f3b..9393b8f 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;
}
}