Modernize memory management of FLAC pointers

This commit is contained in:
Chris Thrasher 2023-11-26 17:35:27 -07:00
parent f3341359eb
commit 95465a3359
4 changed files with 48 additions and 86 deletions

View File

@ -184,6 +184,14 @@ void streamError(const FLAC__StreamDecoder*, FLAC__StreamDecoderErrorStatus, voi
namespace sf::priv namespace sf::priv
{ {
////////////////////////////////////////////////////////////
void SoundFileReaderFlac::FlacStreamDecoderDeleter::operator()(FLAC__StreamDecoder* decoder) const
{
FLAC__stream_decoder_finish(decoder);
FLAC__stream_decoder_delete(decoder);
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundFileReaderFlac::check(InputStream& stream) bool SoundFileReaderFlac::check(InputStream& stream)
{ {
@ -218,18 +226,11 @@ bool SoundFileReaderFlac::check(InputStream& stream)
} }
////////////////////////////////////////////////////////////
SoundFileReaderFlac::~SoundFileReaderFlac()
{
close();
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundFileReaderFlac::open(InputStream& stream, Info& info) bool SoundFileReaderFlac::open(InputStream& stream, Info& info)
{ {
// Create the decoder // Create the decoder
m_decoder = FLAC__stream_decoder_new(); m_decoder.reset(FLAC__stream_decoder_new());
if (!m_decoder) if (!m_decoder)
{ {
err() << "Failed to open FLAC file (failed to allocate the decoder)" << std::endl; err() << "Failed to open FLAC file (failed to allocate the decoder)" << std::endl;
@ -238,7 +239,7 @@ bool SoundFileReaderFlac::open(InputStream& stream, Info& info)
// Initialize the decoder with our callbacks // Initialize the decoder with our callbacks
m_clientData.stream = &stream; m_clientData.stream = &stream;
FLAC__stream_decoder_init_stream(m_decoder, FLAC__stream_decoder_init_stream(m_decoder.get(),
&streamRead, &streamRead,
&streamSeek, &streamSeek,
&streamTell, &streamTell,
@ -250,9 +251,9 @@ bool SoundFileReaderFlac::open(InputStream& stream, Info& info)
&m_clientData); &m_clientData);
// Read the header // Read the header
if (!FLAC__stream_decoder_process_until_end_of_metadata(m_decoder)) if (!FLAC__stream_decoder_process_until_end_of_metadata(m_decoder.get()))
{ {
close(); m_decoder.reset();
err() << "Failed to open FLAC file (failed to read metadata)" << std::endl; err() << "Failed to open FLAC file (failed to read metadata)" << std::endl;
return false; return false;
} }
@ -279,13 +280,14 @@ void SoundFileReaderFlac::seek(std::uint64_t sampleOffset)
{ {
// The "write" callback will populate the leftovers buffer with the first batch of samples from the // 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 // 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); FLAC__stream_decoder_seek_absolute(m_decoder.get(), sampleOffset / m_clientData.info.channelCount);
} }
else else
{ {
// FLAC decoder can't skip straight to EOF, so we short-seek by one sample and skip the rest // 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_seek_absolute(m_decoder.get(),
FLAC__stream_decoder_skip_single_frame(m_decoder); (m_clientData.info.sampleCount / m_clientData.info.channelCount) - 1);
FLAC__stream_decoder_skip_single_frame(m_decoder.get());
// This was re-populated during the seek, but we're skipping everything in this, so we need it emptied // This was re-populated during the seek, but we're skipping everything in this, so we need it emptied
m_clientData.leftovers.clear(); m_clientData.leftovers.clear();
@ -331,27 +333,15 @@ std::uint64_t SoundFileReaderFlac::read(std::int16_t* samples, std::uint64_t max
{ {
// Everything happens in the "write" callback // Everything happens in the "write" callback
// This will break on any fatal error (does not include EOF) // This will break on any fatal error (does not include EOF)
if (!FLAC__stream_decoder_process_single(m_decoder)) if (!FLAC__stream_decoder_process_single(m_decoder.get()))
break; break;
// Break on EOF // Break on EOF
if (FLAC__stream_decoder_get_state(m_decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) if (FLAC__stream_decoder_get_state(m_decoder.get()) == FLAC__STREAM_DECODER_END_OF_STREAM)
break; break;
} }
return maxCount - m_clientData.remaining; return maxCount - m_clientData.remaining;
} }
////////////////////////////////////////////////////////////
void SoundFileReaderFlac::close()
{
if (m_decoder)
{
FLAC__stream_decoder_finish(m_decoder);
FLAC__stream_decoder_delete(m_decoder);
m_decoder = nullptr;
}
}
} // namespace sf::priv } // namespace sf::priv

View File

@ -30,6 +30,7 @@
#include <SFML/Audio/SoundFileReader.hpp> #include <SFML/Audio/SoundFileReader.hpp>
#include <FLAC/stream_decoder.h> #include <FLAC/stream_decoder.h>
#include <memory>
#include <vector> #include <vector>
@ -52,12 +53,6 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] static bool check(InputStream& stream); [[nodiscard]] static bool check(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
~SoundFileReaderFlac() override;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Open a sound file for reading /// \brief Open a sound file for reading
/// ///
@ -108,17 +103,15 @@ public:
}; };
private: private:
////////////////////////////////////////////////////////////
/// \brief Close the open FLAC file
///
////////////////////////////////////////////////////////////
void close();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
FLAC__StreamDecoder* m_decoder{}; //!< FLAC decoder struct FlacStreamDecoderDeleter
ClientData m_clientData; //!< Structure passed to the decoder callbacks {
void operator()(FLAC__StreamDecoder* decoder) const;
};
std::unique_ptr<FLAC__StreamDecoder, FlacStreamDecoderDeleter> m_decoder; //!< FLAC decoder
ClientData m_clientData; //!< Structure passed to the decoder callbacks
}; };
} // namespace sf::priv } // namespace sf::priv

View File

@ -39,6 +39,14 @@
namespace sf::priv namespace sf::priv
{ {
////////////////////////////////////////////////////////////
void SoundFileWriterFlac::FlacStreamEncoderDeleter::operator()(FLAC__StreamEncoder* encoder) const
{
FLAC__stream_encoder_finish(encoder);
FLAC__stream_encoder_delete(encoder);
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundFileWriterFlac::check(const std::filesystem::path& filename) bool SoundFileWriterFlac::check(const std::filesystem::path& filename)
{ {
@ -46,18 +54,11 @@ bool SoundFileWriterFlac::check(const std::filesystem::path& filename)
} }
////////////////////////////////////////////////////////////
SoundFileWriterFlac::~SoundFileWriterFlac()
{
close();
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundFileWriterFlac::open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) bool SoundFileWriterFlac::open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount)
{ {
// Create the encoder // Create the encoder
m_encoder = FLAC__stream_encoder_new(); m_encoder.reset(FLAC__stream_encoder_new());
if (!m_encoder) if (!m_encoder)
{ {
err() << "Failed to write flac file (failed to allocate encoder)\n" err() << "Failed to write flac file (failed to allocate encoder)\n"
@ -66,16 +67,16 @@ bool SoundFileWriterFlac::open(const std::filesystem::path& filename, unsigned i
} }
// Setup the encoder // Setup the encoder
FLAC__stream_encoder_set_channels(m_encoder, channelCount); FLAC__stream_encoder_set_channels(m_encoder.get(), channelCount);
FLAC__stream_encoder_set_bits_per_sample(m_encoder, 16); FLAC__stream_encoder_set_bits_per_sample(m_encoder.get(), 16);
FLAC__stream_encoder_set_sample_rate(m_encoder, sampleRate); FLAC__stream_encoder_set_sample_rate(m_encoder.get(), sampleRate);
// Initialize the output stream // Initialize the output stream
if (FLAC__stream_encoder_init_file(m_encoder, filename.string().c_str(), nullptr, nullptr) != if (FLAC__stream_encoder_init_file(m_encoder.get(), filename.string().c_str(), nullptr, nullptr) !=
FLAC__STREAM_ENCODER_INIT_STATUS_OK) FLAC__STREAM_ENCODER_INIT_STATUS_OK)
{ {
err() << "Failed to write flac file (failed to open the file)\n" << formatDebugPathInfo(filename) << std::endl; err() << "Failed to write flac file (failed to open the file)\n" << formatDebugPathInfo(filename) << std::endl;
close(); m_encoder.reset();
return false; return false;
} }
@ -98,7 +99,7 @@ void SoundFileWriterFlac::write(const std::int16_t* samples, std::uint64_t count
m_samples32.assign(samples, samples + frames * m_channelCount); m_samples32.assign(samples, samples + frames * m_channelCount);
// Write them to the FLAC stream // Write them to the FLAC stream
FLAC__stream_encoder_process_interleaved(m_encoder, m_samples32.data(), frames); FLAC__stream_encoder_process_interleaved(m_encoder.get(), m_samples32.data(), frames);
// Next chunk // Next chunk
count -= m_samples32.size(); count -= m_samples32.size();
@ -106,19 +107,4 @@ void SoundFileWriterFlac::write(const std::int16_t* samples, std::uint64_t count
} }
} }
////////////////////////////////////////////////////////////
void SoundFileWriterFlac::close()
{
if (m_encoder)
{
// Close the output stream
FLAC__stream_encoder_finish(m_encoder);
// Destroy the encoder
FLAC__stream_encoder_delete(m_encoder);
m_encoder = nullptr;
}
}
} // namespace sf::priv } // namespace sf::priv

View File

@ -31,6 +31,7 @@
#include <FLAC/stream_encoder.h> #include <FLAC/stream_encoder.h>
#include <filesystem> #include <filesystem>
#include <memory>
#include <vector> #include <vector>
@ -53,12 +54,6 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] static bool check(const std::filesystem::path& filename); [[nodiscard]] static bool check(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~SoundFileWriterFlac() override;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Open a sound file for writing /// \brief Open a sound file for writing
/// ///
@ -81,18 +76,16 @@ public:
void write(const std::int16_t* samples, std::uint64_t count) override; void write(const std::int16_t* samples, std::uint64_t count) override;
private: private:
////////////////////////////////////////////////////////////
/// \brief Close the file
///
////////////////////////////////////////////////////////////
void close();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
FLAC__StreamEncoder* m_encoder{}; //!< FLAC stream encoder struct FlacStreamEncoderDeleter
unsigned int m_channelCount{}; //!< Number of channels {
std::vector<std::int32_t> m_samples32; //!< Conversion buffer void operator()(FLAC__StreamEncoder* encoder) const;
};
std::unique_ptr<FLAC__StreamEncoder, FlacStreamEncoderDeleter> m_encoder; //!< FLAC stream encoder
unsigned int m_channelCount{}; //!< Number of channels
std::vector<std::int32_t> m_samples32; //!< Conversion buffer
}; };
} // namespace sf::priv } // namespace sf::priv