diff options
-rw-r--r-- | apps/codecs/vorbis.c | 171 | ||||
-rw-r--r-- | 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 @@ | |||
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 | |||
28 | static struct codec_api* rb; | 30 | static 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 | */ | ||
97 | bool 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 |
92 | extern char iramcopy[]; | 126 | extern char iramcopy[]; |
93 | extern char iramstart[]; | 127 | extern 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),¤t_section); | 249 | n=ov_read(&vf,pcmbuf,sizeof(pcmbuf),¤t_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 | ||