From 5eaa748adb2a57c6d3b4343cd35b497b2dd29958 Mon Sep 17 00:00:00 2001 From: Cobaltergeist Date: Thu, 13 Oct 2016 22:01:37 -0700 Subject: [PATCH] Addressed Seeking Quirks in FLAC Reader --- src/SFML/Audio/SoundFileReaderFlac.cpp | 35 +++++++++++++++----------- src/SFML/Audio/SoundFileReaderFlac.hpp | 5 ++-- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/SFML/Audio/SoundFileReaderFlac.cpp b/src/SFML/Audio/SoundFileReaderFlac.cpp index d5cba9c1b..529354171 100644 --- a/src/SFML/Audio/SoundFileReaderFlac.cpp +++ b/src/SFML/Audio/SoundFileReaderFlac.cpp @@ -107,10 +107,6 @@ namespace { sf::priv::SoundFileReaderFlac::ClientData* data = static_cast(clientData); - // If there's no output buffer, it means that we are seeking - if (!data->buffer) - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; - // Reserve memory if we're going to use the leftovers buffer unsigned int frameSamples = frame->header.blocksize * frame->header.channels; if (data->remaining < frameSamples) @@ -142,15 +138,16 @@ namespace break; } - if (data->remaining > 0) + if (data->buffer && data->remaining > 0) { - // There's room in the output buffer, copy the sample there + // If there's room in the output buffer, copy the sample there *data->buffer++ = sample; data->remaining--; } else { - // We have decoded all the requested samples, put the sample in a temporary buffer until next call + // We are either seeking (null buffer) or have decoded all the requested samples during a + // normal read (0 remaining), so we put the sample in a temporary buffer until next call data->leftovers.push_back(sample); } } @@ -210,8 +207,7 @@ bool SoundFileReaderFlac::check(InputStream& stream) //////////////////////////////////////////////////////////// SoundFileReaderFlac::SoundFileReaderFlac() : m_decoder(NULL), -m_clientData(), -m_channelCount(0) +m_clientData() { } @@ -249,9 +245,6 @@ bool SoundFileReaderFlac::open(InputStream& stream, Info& info) // Retrieve the sound properties info = m_clientData.info; // was filled in the "metadata" callback - // We must keep the channel count for the seek function - m_channelCount = info.channelCount; - return true; } @@ -267,7 +260,21 @@ void SoundFileReaderFlac::seek(Uint64 sampleOffset) m_clientData.leftovers.clear(); // FLAC decoder expects absolute sample offset, so we take the channel count out - FLAC__stream_decoder_seek_absolute(m_decoder, sampleOffset / m_channelCount); + if (sampleOffset < m_clientData.info.sampleCount) + { + // The "write" callback will populate the leftovers buffer with the first batch of samples from the + // seek destination, and since we want that data in this typical case, we don't re-clear it afterward + FLAC__stream_decoder_seek_absolute(m_decoder, sampleOffset / m_clientData.info.channelCount); + } + else + { + // FLAC decoder can't skip straight to EOF, so we short-seek by one sample and skip the rest + FLAC__stream_decoder_seek_absolute(m_decoder, (m_clientData.info.sampleCount / m_clientData.info.channelCount) - 1); + FLAC__stream_decoder_skip_single_frame(m_decoder); + + // This was re-populated during the seek, but we're skipping everything in this, so we need it emptied + m_clientData.leftovers.clear(); + } } @@ -283,7 +290,7 @@ Uint64 SoundFileReaderFlac::read(Int16* samples, Uint64 maxCount) if (left > maxCount) { // There are more leftovers than needed - std::copy(m_clientData.leftovers.begin(), m_clientData.leftovers.end(), samples); + std::copy(m_clientData.leftovers.begin(), m_clientData.leftovers.begin() + maxCount, samples); std::vector leftovers(m_clientData.leftovers.begin() + maxCount, m_clientData.leftovers.end()); m_clientData.leftovers.swap(leftovers); return maxCount; diff --git a/src/SFML/Audio/SoundFileReaderFlac.hpp b/src/SFML/Audio/SoundFileReaderFlac.hpp index f7739a4f2..33a5b92d6 100644 --- a/src/SFML/Audio/SoundFileReaderFlac.hpp +++ b/src/SFML/Audio/SoundFileReaderFlac.hpp @@ -131,9 +131,8 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - FLAC__StreamDecoder* m_decoder; ///< FLAC decoder - ClientData m_clientData; ///< Structure passed to the decoder callbacks - unsigned int m_channelCount; ///< number of channels of the sound file + FLAC__StreamDecoder* m_decoder; ///< FLAC decoder + ClientData m_clientData; ///< Structure passed to the decoder callbacks }; } // namespace priv