Addressed Seeking Quirks in FLAC Reader

This commit is contained in:
Cobaltergeist 2016-10-13 22:01:37 -07:00
parent 746bb9c8ca
commit 5eaa748adb
2 changed files with 23 additions and 17 deletions

View File

@ -107,10 +107,6 @@ namespace
{ {
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData); sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(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 // Reserve memory if we're going to use the leftovers buffer
unsigned int frameSamples = frame->header.blocksize * frame->header.channels; unsigned int frameSamples = frame->header.blocksize * frame->header.channels;
if (data->remaining < frameSamples) if (data->remaining < frameSamples)
@ -142,15 +138,16 @@ namespace
break; 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->buffer++ = sample;
data->remaining--; data->remaining--;
} }
else 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); data->leftovers.push_back(sample);
} }
} }
@ -210,8 +207,7 @@ bool SoundFileReaderFlac::check(InputStream& stream)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundFileReaderFlac::SoundFileReaderFlac() : SoundFileReaderFlac::SoundFileReaderFlac() :
m_decoder(NULL), m_decoder(NULL),
m_clientData(), m_clientData()
m_channelCount(0)
{ {
} }
@ -249,9 +245,6 @@ bool SoundFileReaderFlac::open(InputStream& stream, Info& info)
// Retrieve the sound properties // Retrieve the sound properties
info = m_clientData.info; // was filled in the "metadata" callback 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; return true;
} }
@ -267,7 +260,21 @@ void SoundFileReaderFlac::seek(Uint64 sampleOffset)
m_clientData.leftovers.clear(); m_clientData.leftovers.clear();
// FLAC decoder expects absolute sample offset, so we take the channel count out // 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) if (left > maxCount)
{ {
// There are more leftovers than needed // 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<Int16> leftovers(m_clientData.leftovers.begin() + maxCount, m_clientData.leftovers.end()); std::vector<Int16> leftovers(m_clientData.leftovers.begin() + maxCount, m_clientData.leftovers.end());
m_clientData.leftovers.swap(leftovers); m_clientData.leftovers.swap(leftovers);
return maxCount; return maxCount;

View File

@ -131,9 +131,8 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
FLAC__StreamDecoder* m_decoder; ///< FLAC decoder FLAC__StreamDecoder* m_decoder; ///< FLAC decoder
ClientData m_clientData; ///< Structure passed to the decoder callbacks ClientData m_clientData; ///< Structure passed to the decoder callbacks
unsigned int m_channelCount; ///< number of channels of the sound file
}; };
} // namespace priv } // namespace priv