From 2c55663472f50f5e50ea0a605a9f15bf90822fb0 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 29 Apr 2019 11:39:30 +0200 Subject: [PATCH] movies: allow seeking compressed Ogg Vorbis file to beginning --- panda/src/movies/vorbisAudioCursor.cxx | 43 +++++++++++++++++++++----- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/panda/src/movies/vorbisAudioCursor.cxx b/panda/src/movies/vorbisAudioCursor.cxx index 97666d0056..80c5613b0c 100644 --- a/panda/src/movies/vorbisAudioCursor.cxx +++ b/panda/src/movies/vorbisAudioCursor.cxx @@ -91,19 +91,46 @@ seek(double t) { t = std::max(t, 0.0); // Use ov_time_seek_lap if cross-lapping is enabled. + int result; if (vorbis_seek_lap) { - if (ov_time_seek_lap(&_ov, t) != 0) { - movies_cat.error() - << "Seek failed. Ogg Vorbis stream may not be seekable.\n"; - return; - } + result = ov_time_seek_lap(&_ov, t); } else { - if (ov_time_seek(&_ov, t) != 0) { - movies_cat.error() - << "Seek failed. Ogg Vorbis stream may not be seekable.\n"; + result = ov_time_seek(&_ov, t); + } + + // Special case for seeking to the beginning; if normal seek fails, we may + // be able to explicitly seek to the beginning of the file and call ov_open + // again. This allows looping compressed .ogg files. + if (result == OV_ENOSEEK && t == 0.0) { + std::istream *stream = (std::istream *)_ov.datasource; + + if (stream->rdbuf()->pubseekpos(0, std::ios::in) == 0) { + // Back up the callbacks, then destroy the stream, making sure to first + // unset the datasource so that it won't close the file. + ov_callbacks callbacks = _ov.callbacks; + _ov.datasource = nullptr; + ov_clear(&_ov); + + if (ov_open_callbacks((void *)stream, &_ov, nullptr, 0, callbacks) != 0) { + movies_cat.error() + << "Failed to reopen Ogg Vorbis file to seek to beginning.\n"; + return; + } + + // Reset these fields for good measure, just in case the file changed. + vorbis_info *vi = ov_info(&_ov, -1); + _audio_channels = vi->channels; + _audio_rate = vi->rate; + + _last_seek = 0.0; + _samples_read = 0; return; } } + if (result != 0) { + movies_cat.error() + << "Seek failed. Ogg Vorbis stream may not be seekable.\n"; + } _last_seek = ov_time_tell(&_ov); _samples_read = 0;