@@ -264,11 +264,10 @@ void AudioStreamPlaybackOggVorbis::seek(double p_time) {
264
264
return ;
265
265
}
266
266
267
- vorbis_synthesis_restart (&dsp_state);
268
-
269
267
if (p_time >= vorbis_stream->get_length ()) {
270
268
p_time = 0 ;
271
269
}
270
+
272
271
frames_mixed = uint32_t (vorbis_data->get_sampling_rate () * p_time);
273
272
274
273
const int64_t desired_sample = p_time * get_stream_sampling_rate ();
@@ -278,107 +277,81 @@ void AudioStreamPlaybackOggVorbis::seek(double p_time) {
278
277
return ;
279
278
}
280
279
281
- ogg_packet *packet;
282
- if (!vorbis_data_playback->next_ogg_packet (&packet)) {
283
- WARN_PRINT_ONCE (" seeking beyond limits" );
284
- return ;
280
+ // We want to start decoding before the page that we expect the sample to be in (the sample may
281
+ // be part of a partial packet across page boundaries). Otherwise, the decoder may not have
282
+ // synchronized before reaching the sample.
283
+ int64_t start_page_number = vorbis_data_playback->get_page_number () - 1 ;
284
+ if (start_page_number < 0 ) {
285
+ start_page_number = 0 ;
285
286
}
286
287
287
- // The granule position of the page we're seeking through.
288
- int64_t granule_pos = 0 ;
289
-
290
- int headers_remaining = 0 ;
291
- int samples_in_page = 0 ;
292
- int err;
293
288
while (true ) {
294
- if (vorbis_synthesis_idheader (packet)) {
295
- headers_remaining = 3 ;
296
- }
297
- if (!headers_remaining) {
298
- err = vorbis_synthesis (&block, packet);
299
- ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis synthesis " + itos (err));
300
-
301
- err = vorbis_synthesis_blockin (&dsp_state, &block);
302
- ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis block processing " + itos (err));
303
-
304
- int samples_out = vorbis_synthesis_pcmout (&dsp_state, nullptr );
305
- err = vorbis_synthesis_read (&dsp_state, samples_out);
306
- ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis read updating " + itos (err));
307
-
308
- samples_in_page += samples_out;
309
-
310
- } else {
311
- headers_remaining--;
312
- }
313
- if (packet->granulepos != -1 && headers_remaining == 0 ) {
314
- // This indicates the end of the page.
315
- granule_pos = packet->granulepos ;
316
- break ;
317
- }
318
- if (packet->e_o_s ) {
319
- break ;
320
- }
321
- if (!vorbis_data_playback->next_ogg_packet (&packet)) {
322
- // We should get an e_o_s flag before this happens.
323
- WARN_PRINT (" Vorbis file ended without warning." );
324
- break ;
325
- }
326
- }
289
+ ogg_packet *packet;
290
+ int err;
327
291
328
- int64_t samples_to_burn = samples_in_page - (granule_pos - desired_sample);
292
+ // We start at an unknown granule position.
293
+ int64_t granule_pos = -1 ;
329
294
330
- if (samples_to_burn > samples_in_page) {
331
- WARN_PRINT_ONCE (" Burning more samples than we have in this page. Check seek algorithm." );
332
- } else if (samples_to_burn < 0 ) {
333
- WARN_PRINT_ONCE (" Burning negative samples doesn't make sense. Check seek algorithm." );
334
- }
295
+ // Decode data until we get to the desired sample or notice that we have read past it.
296
+ vorbis_data_playback->set_page_number (start_page_number);
297
+ vorbis_synthesis_restart (&dsp_state);
335
298
336
- // Seek again, this time we'll burn a specific number of samples instead of all of them.
337
- if (!vorbis_data_playback->seek_page (desired_sample)) {
338
- WARN_PRINT (" seek failed" );
339
- return ;
340
- }
341
-
342
- if (!vorbis_data_playback->next_ogg_packet (&packet)) {
343
- WARN_PRINT_ONCE (" seeking beyond limits" );
344
- return ;
345
- }
346
- vorbis_synthesis_restart (&dsp_state);
299
+ while (true ) {
300
+ if (!vorbis_data_playback->next_ogg_packet (&packet)) {
301
+ WARN_PRINT_ONCE (" Seeking beyond limits" );
302
+ return ;
303
+ }
347
304
348
- while (true ) {
349
- if (vorbis_synthesis_idheader (packet)) {
350
- headers_remaining = 3 ;
351
- }
352
- if (!headers_remaining) {
353
305
err = vorbis_synthesis (&block, packet);
354
- ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis synthesis " + itos (err));
355
-
356
- err = vorbis_synthesis_blockin (&dsp_state, &block);
357
- ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis block processing " + itos (err));
358
-
359
- int samples_out = vorbis_synthesis_pcmout (&dsp_state, nullptr );
360
- int read_samples = samples_to_burn > samples_out ? samples_out : samples_to_burn;
361
- err = vorbis_synthesis_read (&dsp_state, samples_out);
362
- ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis read updating " + itos (err));
363
- samples_to_burn -= read_samples;
364
-
365
- if (samples_to_burn <= 0 ) {
366
- break ;
306
+ if (err != OV_ENOTAUDIO) {
307
+ ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis synthesis " + itos (err) + " ." );
308
+
309
+ err = vorbis_synthesis_blockin (&dsp_state, &block);
310
+ ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis block processing " + itos (err) + " ." );
311
+
312
+ int samples_out = vorbis_synthesis_pcmout (&dsp_state, nullptr );
313
+
314
+ if (granule_pos < 0 ) {
315
+ // We don't know where we are yet, so just keep on decoding.
316
+ err = vorbis_synthesis_read (&dsp_state, samples_out);
317
+ ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis read updating " + itos (err) + " ." );
318
+ } else if (granule_pos + samples_out >= desired_sample) {
319
+ // Our sample is in this block. Skip the beginning of the block up to the sample, then
320
+ // return.
321
+ int skip_samples = (int )(desired_sample - granule_pos);
322
+ err = vorbis_synthesis_read (&dsp_state, skip_samples);
323
+ ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis read updating " + itos (err) + " ." );
324
+ have_samples_left = skip_samples < samples_out;
325
+ have_packets_left = !packet->e_o_s ;
326
+ return ;
327
+ } else {
328
+ // Our sample is not in this block. Skip it.
329
+ err = vorbis_synthesis_read (&dsp_state, samples_out);
330
+ ERR_FAIL_COND_MSG (err != 0 , " Error during vorbis read updating " + itos (err) + " ." );
331
+ granule_pos += samples_out;
332
+ }
333
+ }
334
+ if (packet->granulepos != -1 ) {
335
+ // We found an update to our granule position.
336
+ granule_pos = packet->granulepos ;
337
+ if (granule_pos > desired_sample) {
338
+ // We've read past our sample. We need to start on an earlier page.
339
+ if (start_page_number == 0 ) {
340
+ // We didn't find the sample even reading from the beginning.
341
+ have_samples_left = false ;
342
+ have_packets_left = !packet->e_o_s ;
343
+ return ;
344
+ }
345
+ start_page_number--;
346
+ break ;
347
+ }
348
+ }
349
+ if (packet->e_o_s ) {
350
+ // We've reached the end of the stream and didn't find our sample.
351
+ have_samples_left = false ;
352
+ have_packets_left = false ;
353
+ return ;
367
354
}
368
- } else {
369
- headers_remaining--;
370
- }
371
- if (packet->granulepos != -1 && headers_remaining == 0 ) {
372
- // This indicates the end of the page.
373
- break ;
374
- }
375
- if (packet->e_o_s ) {
376
- break ;
377
- }
378
- if (!vorbis_data_playback->next_ogg_packet (&packet)) {
379
- // We should get an e_o_s flag before this happens.
380
- WARN_PRINT (" Vorbis file ended without warning." );
381
- break ;
382
355
}
383
356
}
384
357
}
0 commit comments