@@ -264,11 +264,10 @@ void AudioStreamPlaybackOggVorbis::seek(double p_time) {
264264 return ;
265265 }
266266
267- vorbis_synthesis_restart (&dsp_state);
268-
269267 if (p_time >= vorbis_stream->get_length ()) {
270268 p_time = 0 ;
271269 }
270+
272271 frames_mixed = uint32_t (vorbis_data->get_sampling_rate () * p_time);
273272
274273 const int64_t desired_sample = p_time * get_stream_sampling_rate ();
@@ -278,107 +277,81 @@ void AudioStreamPlaybackOggVorbis::seek(double p_time) {
278277 return ;
279278 }
280279
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 ;
285286 }
286287
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;
293288 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;
327291
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 ;
329294
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);
335298
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+ }
347304
348- while (true ) {
349- if (vorbis_synthesis_idheader (packet)) {
350- headers_remaining = 3 ;
351- }
352- if (!headers_remaining) {
353305 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 ;
367354 }
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 ;
382355 }
383356 }
384357}
0 commit comments