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.tar.gz
rockbox-c4b7c671f92b4dab028c45091c94e40dcead3443.zip
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 353b90fb0b..561fbb4601 100644
--- a/apps/codecs/vorbis.c
+++ b/apps/codecs/vorbis.c
@@ -25,6 +25,8 @@
25#include "dsp.h" 25#include "dsp.h"
26#include "lib/codeclib.h" 26#include "lib/codeclib.h"
27 27
28#define TEST_RESUME
29
28static struct codec_api* rb; 30static struct codec_api* rb;
29 31
30/* Some standard functions and variables needed by Tremor */ 32/* Some standard functions and variables needed by Tremor */
@@ -88,6 +90,38 @@ long tell_handler(void *datasource)
88 return rb->curpos; 90 return rb->curpos;
89} 91}
90 92
93/* This sets the DSP parameters based on the current logical bitstream
94 * (sampling rate, number of channels, etc). It also tries to guess
95 * reasonable buffer parameters based on the current quality setting.
96 */
97bool vorbis_set_codec_parameters(OggVorbis_File *vf)
98{
99 vorbis_info* vi;
100
101 vi=ov_info(vf,-1);
102
103 if (vi==NULL) {
104 //rb->splash(HZ*2, true, "Vorbis Error");
105 return false;
106 }
107
108 if (rb->id3->frequency != NATIVE_FREQUENCY) {
109 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
110 } else {
111 rb->configure(CODEC_DSP_ENABLE, (bool *)false);
112 }
113
114 rb->configure(DSP_SET_FREQUENCY, (int *)rb->id3->frequency);
115
116 if (vi->channels == 2) {
117 rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
118 } else if (vi->channels == 1) {
119 rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_MONO);
120 }
121
122 return true;
123}
124
91#ifdef USE_IRAM 125#ifdef USE_IRAM
92extern char iramcopy[]; 126extern char iramcopy[];
93extern char iramstart[]; 127extern char iramstart[];
@@ -103,17 +137,16 @@ enum codec_status codec_start(struct codec_api* api)
103{ 137{
104 ov_callbacks callbacks; 138 ov_callbacks callbacks;
105 OggVorbis_File vf; 139 OggVorbis_File vf;
106 vorbis_info* vi;
107 140
108 int error; 141 int error;
109 long n; 142 long n;
110 int current_section; 143 int current_section;
144 int previous_section = -1;
111 int eof; 145 int eof;
112 ogg_int64_t vf_offsets[2]; 146 ogg_int64_t vf_offsets[2];
113 ogg_int64_t vf_dataoffsets; 147 ogg_int64_t vf_dataoffsets;
114 ogg_uint32_t vf_serialnos; 148 ogg_uint32_t vf_serialnos;
115 ogg_int64_t vf_pcmlengths[2]; 149 ogg_int64_t vf_pcmlengths[2];
116 int current_stereo_mode = -1;
117 150
118 TEST_CODEC_API(api); 151 TEST_CODEC_API(api);
119 152
@@ -125,11 +158,19 @@ enum codec_status codec_start(struct codec_api* api)
125 rb->memcpy(iramstart, iramcopy, iramend-iramstart); 158 rb->memcpy(iramstart, iramcopy, iramend-iramstart);
126 #endif 159 #endif
127 160
128 rb->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
129 rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*64));
130
131 rb->configure(DSP_DITHER, (bool *)false); 161 rb->configure(DSP_DITHER, (bool *)false);
132 rb->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16)); 162 rb->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
163
164 /* Note: These are sane defaults for these values. Perhaps
165 * they should be set differently based on quality setting
166 */
167 rb->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
168
169 /* The chunk size below is magic. If set any lower, resume
170 * doesn't work properly (ov_raw_seek() does the wrong thing).
171 */
172 rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));
173
133 174
134/* We need to flush reserver memory every track load. */ 175/* We need to flush reserver memory every track load. */
135 next_track: 176 next_track:
@@ -139,14 +180,7 @@ enum codec_status codec_start(struct codec_api* api)
139 180
140 while (!*rb->taginfo_ready && !rb->stop_codec) 181 while (!*rb->taginfo_ready && !rb->stop_codec)
141 rb->yield(); 182 rb->yield();
142 183
143 if (rb->id3->frequency != NATIVE_FREQUENCY) {
144 rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
145 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
146 } else {
147 rb->configure(CODEC_DSP_ENABLE, (bool *)false);
148 }
149
150 /* Create a decoder instance */ 184 /* Create a decoder instance */
151 callbacks.read_func=read_handler; 185 callbacks.read_func=read_handler;
152 callbacks.seek_func=initial_seek_handler; 186 callbacks.seek_func=initial_seek_handler;
@@ -158,7 +192,7 @@ enum codec_status codec_start(struct codec_api* api)
158 192
159 /* If the non-seekable open was successful, we need to supply the missing 193 /* If the non-seekable open was successful, we need to supply the missing
160 * data to make it seekable. This is a hack, but it's reasonable since we 194 * data to make it seekable. This is a hack, but it's reasonable since we
161 * don't want to read the whole file into the buffer before we start 195 * don't want to run the whole file through the buffer before we start
162 * playing. Using Tremor's seekable open routine would cause us to do 196 * playing. Using Tremor's seekable open routine would cause us to do
163 * this, so we pretend not to be seekable at first. Then we fill in the 197 * this, so we pretend not to be seekable at first. Then we fill in the
164 * missing fields of vf with 1) information in rb->id3, and 2) info 198 * 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)
169 * get here. 203 * get here.
170 */ 204 */
171 if ( !error ) { 205 if ( !error ) {
172 //rb->logf("no error"); 206 vf.offsets = vf_offsets;
173 /* FIXME Should these be dynamically allocated? */ 207 vf.dataoffsets = &vf_dataoffsets;
174 vf.offsets = vf_offsets; 208 vf.serialnos = &vf_serialnos;
175 vf.dataoffsets = &vf_dataoffsets; 209 vf.pcmlengths = vf_pcmlengths;
176 vf.serialnos = &vf_serialnos; 210
177 vf.pcmlengths = vf_pcmlengths; 211 vf.offsets[0] = 0;
178 212 vf.offsets[1] = rb->id3->filesize;
179 vf.offsets[0] = 0; 213 vf.dataoffsets[0] = vf.offset;
180 vf.offsets[1] = rb->id3->filesize; 214 vf.pcmlengths[0] = 0;
181 vf.dataoffsets[0] = vf.offset; 215 vf.pcmlengths[1] = rb->id3->samples;
182 vf.pcmlengths[0] = 0; 216 vf.serialnos[0] = vf.current_serialno;
183 vf.pcmlengths[1] = rb->id3->samples; 217 vf.callbacks.seek_func=seek_handler;
184 vf.serialnos[0] = vf.current_serialno; 218 vf.seekable = 1;
185 vf.callbacks.seek_func=seek_handler; 219 vf.end = rb->id3->filesize;
186 vf.seekable = 1; 220 vf.ready_state = OPENED;
187 vf.offset = 58; /* length of Ogg header */ 221 vf.links = 1;
188 vf.end = rb->id3->filesize;
189 vf.ready_state = OPENED;
190 vf.links = 1;
191
192 /*if(ov_raw_seek(&vf,0)){
193 rb->logf("seek err");
194 }
195 */
196
197 } else { 222 } else {
198 //rb->logf("ov_open: %d", error); 223 //rb->logf("ov_open: %d", error);
199 } 224 return CODEC_ERROR;
200
201 vi=ov_info(&vf,-1);
202
203 if (vi==NULL) {
204 //rb->splash(HZ*2, true, "Vorbis Error");
205 return CODEC_ERROR;
206 } 225 }
207 226
208 rb->configure(DSP_SET_FREQUENCY, (int *)rb->id3->frequency); 227 if ( rb->id3->offset ) {
209 228 rb->advance_buffer(rb->id3->offset);
210 if (vi->channels == 2) { 229 ov_raw_seek(&vf,rb->id3->offset);
211 if (current_stereo_mode != STEREO_INTERLEAVED) { 230 rb->id3->offset = ov_raw_tell(&vf);
212 rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); 231 rb->set_elapsed(ov_time_tell(&vf));
213 current_stereo_mode = STEREO_INTERLEAVED;
214 }
215 } else if (vi->channels == 1) {
216 if (current_stereo_mode != STEREO_MONO) {
217 rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_MONO);
218 current_stereo_mode = STEREO_MONO;
219 }
220 } 232 }
221 233
222 eof=0; 234 eof=0;
@@ -226,9 +238,9 @@ enum codec_status codec_start(struct codec_api* api)
226 break ; 238 break ;
227 239
228 if (rb->seek_time) { 240 if (rb->seek_time) {
229 241
230 if (ov_time_seek(&vf, rb->seek_time)) { 242 if (ov_time_seek(&vf, rb->seek_time)) {
231 //rb->logf("ov_time_seek failed"); 243 //rb->logf("ov_time_seek failed");
232 } 244 }
233 rb->seek_time = 0; 245 rb->seek_time = 0;
234 } 246 }
@@ -236,6 +248,15 @@ enum codec_status codec_start(struct codec_api* api)
236 /* Read host-endian signed 16 bit PCM samples */ 248 /* Read host-endian signed 16 bit PCM samples */
237 n=ov_read(&vf,pcmbuf,sizeof(pcmbuf),&current_section); 249 n=ov_read(&vf,pcmbuf,sizeof(pcmbuf),&current_section);
238 250
251 /* Change DSP and buffer settings for this bitstream */
252 if ( current_section != previous_section ) {
253 if (!vorbis_set_codec_parameters(&vf)) {
254 return CODEC_ERROR;
255 } else {
256 previous_section = current_section;
257 }
258 }
259
239 if (n==0) { 260 if (n==0) {
240 eof=1; 261 eof=1;
241 } else if (n < 0) { 262 } else if (n < 0) {
@@ -243,29 +264,31 @@ enum codec_status codec_start(struct codec_api* api)
243 } else { 264 } else {
244 while (!rb->audiobuffer_insert(pcmbuf, n)) { 265 while (!rb->audiobuffer_insert(pcmbuf, n)) {
245 rb->yield(); 266 rb->yield();
246 if ( rb->seek_time ) { 267 if ( rb->seek_time ) {
247 /* Hmmm, a seek was requested. Throw out the 268 /* Hmmm, a seek was requested. Throw out the
248 * buffer and go back to the top of the loop. 269 * buffer and go back to the top of the loop.
249 */ 270 */
250 break; 271 break;
251 } 272 }
252 } 273 }
253 if ( !rb->seek_time ) { 274 if ( !rb->seek_time ) {
254 rb->set_elapsed(ov_time_tell(&vf)); 275 rb->id3->offset = ov_raw_tell(&vf);
255 rb->yield(); 276 rb->set_elapsed(ov_time_tell(&vf));
256 } 277 rb->yield();
278 }
257 } 279 }
258 } 280 }
259 281
260 if (rb->request_next_track()) { 282 if (rb->request_next_track()) {
261 /* Clean things up for the next track */ 283 /* Clean things up for the next track */
262 vf.dataoffsets = NULL; 284 vf.dataoffsets = NULL;
263 vf.offsets = NULL; 285 vf.offsets = NULL;
264 vf.serialnos = NULL; 286 vf.serialnos = NULL;
265 vf.pcmlengths = NULL; 287 vf.pcmlengths = NULL;
266 ov_clear(&vf); 288 ov_clear(&vf);
267 goto next_track; 289 goto next_track;
268 } 290 }
269 291
270 return CODEC_OK; 292 return CODEC_OK;
271} 293}
294
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)
477 if (ci.stop_codec) 477 if (ci.stop_codec)
478 return false; 478 return false;
479 } 479 }
480 480
481 return true; 481 return true;
482} 482}
483 483
@@ -962,6 +962,9 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
962 ci.curpos = offset; 962 ci.curpos = offset;
963 tracks[track_widx].start_pos = offset; 963 tracks[track_widx].start_pos = offset;
964 break; 964 break;
965 case AFMT_OGG_VORBIS:
966 tracks[track_widx].id3.offset = offset;
967 break;
965 } 968 }
966 } 969 }
967 970