chore: drop third party lib for reading flac header

This commit is contained in:
Jan
2024-02-10 16:33:26 +01:00
parent 05ce73049d
commit 4591787989
9 changed files with 295 additions and 139 deletions

View File

@ -15,7 +15,6 @@ function ObjCommon:link(links)
links:linkto(Utils)
links:linkto(Common)
links:linkto(minizip)
links:linkto(flac)
end
function ObjCommon:use()
@ -49,5 +48,4 @@ function ObjCommon:project()
self:include(includes)
Utils:include(includes)
flac:include(includes)
end

View File

@ -1,77 +1,245 @@
#include "FlacDecoder.h"
#include <foxen/flac.h>
#include "Utils/Alignment.h"
#include "Utils/Endianness.h"
#include "Utils/FileUtils.h"
class fx_flac_raii
#include <cassert>
#include <iostream>
#include <sstream>
namespace
{
public:
fx_flac_raii()
constexpr auto FLAC_MAGIC = FileUtils::MakeMagic32('f', 'L', 'a', 'C');
enum class MetaDataBlockType : unsigned
{
ptr = FX_FLAC_ALLOC_DEFAULT();
}
STREAMINFO = 0,
PADDING = 1,
APPLICATION = 2,
SEEKTABLE = 3,
VORBIS_COMMENT = 4,
CUESHEET = 5,
PICTURE = 6
};
~fx_flac_raii()
struct MetaDataBlockHeader
{
free(ptr);
}
uint8_t isLastMetaDataBlock;
MetaDataBlockType blockType;
uint32_t blockLength;
};
operator fx_flac_t*()
constexpr auto STREAM_INFO_BLOCK_SIZE = 34;
class FlacReadingException final : public std::exception
{
return ptr;
}
private:
fx_flac_t* ptr;
};
class FlacDecoderImpl : public FlacDecoder
{
private:
void* m_data;
size_t m_length;
std::unique_ptr<fx_flac_raii> m_flac;
public:
explicit FlacDecoderImpl(void* data, size_t length)
: m_data(data),
m_length(length)
{
}
unsigned int GetFrameCount() override
{
return static_cast<unsigned int>(fx_flac_get_streaminfo(*m_flac.get(), FLAC_KEY_N_SAMPLES));
}
unsigned int GetFrameRate() override
{
return static_cast<unsigned int>(fx_flac_get_streaminfo(*m_flac.get(), FLAC_KEY_SAMPLE_RATE));
}
unsigned int GetNumChannels() override
{
return static_cast<unsigned int>(fx_flac_get_streaminfo(*m_flac.get(), FLAC_KEY_N_CHANNELS));
}
bool Decode() override
{
m_flac = std::make_unique<fx_flac_raii>();
while (true)
public:
explicit FlacReadingException(std::string message)
: m_message(std::move(message))
{
auto res = fx_flac_process(*m_flac.get(), reinterpret_cast<uint8_t*>(m_data), &m_length, nullptr, nullptr);
if (res == FLAC_ERR)
return false;
if (res == FLAC_END_OF_METADATA)
break;
}
return true;
}
};
_NODISCARD char const* what() const noexcept override
{
return m_message.c_str();
}
std::unique_ptr<FlacDecoder> FlacDecoder::Create(void* data, size_t length)
private:
std::string m_message;
};
class FlacBitReader
{
public:
explicit FlacBitReader(std::istream& stream)
: m_stream(stream),
m_last_byte(0u),
m_remaining_bits_last_byte(0u)
{
}
template<typename T> T ReadBits(const size_t bitCount)
{
union
{
uint8_t buffer[sizeof(T)];
T result;
} data{};
const auto byteCount = utils::Align(bitCount, 8u) / 8u;
assert(byteCount <= sizeof(T));
const auto shiftCount = (8u - bitCount % 8) % 8;
auto remainingBits = bitCount;
#if HOST_ENDIANNESS == LITTLE_ENDIAN_ENDIANNESS
auto offset = byteCount - 1;
#else
auto offset = 0u;
#endif
while (remainingBits > 0)
{
const auto curBits = static_cast<uint8_t>(std::min(remainingBits, 8u));
if (m_remaining_bits_last_byte > 0)
{
if (m_remaining_bits_last_byte < curBits)
{
const auto bitsFromFirstByte = m_remaining_bits_last_byte;
data.buffer[offset] = static_cast<uint8_t>(m_last_byte << (8u - bitsFromFirstByte));
m_stream.read(reinterpret_cast<char*>(&m_last_byte), sizeof(m_last_byte));
if (m_stream.gcount() != sizeof(m_last_byte))
throw FlacReadingException("Unexpected eof");
const auto bitsFromSecondByte = static_cast<uint8_t>(curBits - m_remaining_bits_last_byte);
m_remaining_bits_last_byte = 8u - bitsFromSecondByte;
const auto maskForSecondByte = static_cast<uint8_t>(0xFF << (8u - bitsFromSecondByte));
data.buffer[offset] |= (m_last_byte & maskForSecondByte) >> bitsFromFirstByte;
}
else if (m_remaining_bits_last_byte == curBits)
{
data.buffer[offset] = static_cast<uint8_t>(m_last_byte << (8u - curBits));
m_remaining_bits_last_byte = 0u;
}
else // m_remaining_bits_last_byte > curBits
{
const auto maskForCurBits = 0xFF >> (8u - curBits);
const auto maskForCurBitsInRemainingBits = static_cast<uint8_t>(maskForCurBits << (m_remaining_bits_last_byte - curBits));
const auto selectedData = static_cast<uint8_t>(m_last_byte & maskForCurBitsInRemainingBits);
data.buffer[offset] = static_cast<uint8_t>(selectedData << (8u - m_remaining_bits_last_byte));
m_remaining_bits_last_byte -= curBits;
}
}
else if (curBits >= 8u)
{
m_stream.read(reinterpret_cast<char*>(&data.buffer[offset]), sizeof(uint8_t));
if (m_stream.gcount() != sizeof(uint8_t))
throw FlacReadingException("Unexpected eof");
}
else
{
m_stream.read(reinterpret_cast<char*>(&m_last_byte), sizeof(m_last_byte));
if (m_stream.gcount() != sizeof(m_last_byte))
throw FlacReadingException("Unexpected eof");
data.buffer[offset] = m_last_byte & (0xFF << (8u - curBits));
m_remaining_bits_last_byte = static_cast<uint8_t>(8u - curBits);
}
remainingBits -= curBits;
#if HOST_ENDIANNESS == LITTLE_ENDIAN_ENDIANNESS
--offset;
#else
++offset;
#endif
}
data.result >>= shiftCount;
return data.result;
}
void ReadBuffer(void* buffer, const size_t bitCount)
{
assert(m_remaining_bits_last_byte == 0);
assert(bitCount % 8 == 0);
m_remaining_bits_last_byte = 0;
m_stream.read(static_cast<char*>(buffer), bitCount / 8);
}
void Seek(const size_t offset)
{
assert(m_remaining_bits_last_byte == 0);
m_remaining_bits_last_byte = 0;
m_stream.seekg(offset, std::ios::cur);
}
private:
std::istream& m_stream;
uint8_t m_last_byte;
uint8_t m_remaining_bits_last_byte;
};
} // namespace
namespace flac
{
return std::make_unique<FlacDecoderImpl>(data, length);
}
FlacMetaData::FlacMetaData()
: m_minimum_block_size(),
m_maximum_block_size(),
m_minimum_frame_size(),
m_maximum_frame_size(),
m_sample_rate(),
m_number_of_channels(),
m_bits_per_sample(),
m_total_samples(),
m_md5_signature{}
{
}
void FlacReadStreamInfo(FlacBitReader& reader, FlacMetaData& metaData)
{
metaData.m_minimum_block_size = reader.ReadBits<uint16_t>(16);
metaData.m_maximum_block_size = reader.ReadBits<uint16_t>(16);
metaData.m_minimum_frame_size = reader.ReadBits<uint32_t>(24);
metaData.m_maximum_frame_size = reader.ReadBits<uint32_t>(24);
metaData.m_sample_rate = reader.ReadBits<uint32_t>(20);
metaData.m_number_of_channels = static_cast<uint8_t>(reader.ReadBits<uint8_t>(3) + 1);
metaData.m_bits_per_sample = static_cast<uint8_t>(reader.ReadBits<uint8_t>(5) + 1);
metaData.m_total_samples = reader.ReadBits<uint64_t>(36);
reader.ReadBuffer(metaData.m_md5_signature, 128);
}
bool GetFlacMetaData(std::istream& stream, FlacMetaData& metaData)
{
try
{
uint32_t readMagic;
stream.read(reinterpret_cast<char*>(&readMagic), sizeof(readMagic));
if (stream.gcount() != sizeof(readMagic) || readMagic != FLAC_MAGIC)
throw FlacReadingException("Invalid flac magic");
FlacBitReader reader(stream);
while (true)
{
const MetaDataBlockHeader header{
reader.ReadBits<uint8_t>(1),
static_cast<MetaDataBlockType>(reader.ReadBits<uint8_t>(7)),
reader.ReadBits<uint32_t>(24),
};
if (header.blockType == MetaDataBlockType::STREAMINFO)
{
if (header.blockLength != STREAM_INFO_BLOCK_SIZE)
throw FlacReadingException("Flac stream info block size invalid");
FlacReadStreamInfo(reader, metaData);
return true;
}
reader.Seek(header.blockLength * 8u);
if (header.isLastMetaDataBlock)
break;
}
throw FlacReadingException("Missing flac stream info block");
}
catch (const FlacReadingException& e)
{
std::cerr << e.what() << "\n";
}
return false;
}
bool GetFlacMetaData(const void* data, const size_t dataSize, FlacMetaData& metaData)
{
std::istringstream ss(std::string(static_cast<const char*>(data), dataSize));
return GetFlacMetaData(ss, metaData);
}
} // namespace flac

View File

@ -1,22 +1,26 @@
#pragma once
#include <cstdint>
#include <istream>
#include <memory>
class FlacDecoder
namespace flac
{
public:
FlacDecoder() = default;
virtual ~FlacDecoder() = default;
class FlacMetaData
{
public:
uint16_t m_minimum_block_size;
uint16_t m_maximum_block_size;
uint32_t m_minimum_frame_size;
uint32_t m_maximum_frame_size;
uint32_t m_sample_rate;
uint8_t m_number_of_channels;
uint8_t m_bits_per_sample;
uint64_t m_total_samples;
uint8_t m_md5_signature[16];
FlacDecoder(const FlacDecoder& other) = default;
FlacDecoder(FlacDecoder&& other) noexcept = default;
FlacDecoder& operator=(const FlacDecoder& other) = default;
FlacDecoder& operator=(FlacDecoder&& other) noexcept = default;
FlacMetaData();
};
virtual bool Decode() = 0;
virtual unsigned int GetFrameCount() = 0;
virtual unsigned int GetFrameRate() = 0;
virtual unsigned int GetNumChannels() = 0;
static std::unique_ptr<FlacDecoder> Create(void* data, size_t length);
};
bool GetFlacMetaData(std::istream& stream, FlacMetaData& metaData);
bool GetFlacMetaData(const void* data, size_t dataSize, FlacMetaData& metaData);
} // namespace flac

View File

@ -159,17 +159,17 @@ public:
soundData = std::make_unique<char[]>(soundSize);
flacFile.m_stream->read(soundData.get(), soundSize);
const auto decoder = FlacDecoder::Create(soundData.get(), soundSize);
if (decoder->Decode())
flac::FlacMetaData metaData;
if (flac::GetFlacMetaData(soundData.get(), soundSize, metaData))
{
const auto frameRateIndex = INDEX_FOR_FRAMERATE[decoder->GetFrameRate()];
const auto frameRateIndex = INDEX_FOR_FRAMERATE[metaData.m_sample_rate];
SoundAssetBankEntry entry{
soundId,
soundSize,
static_cast<size_t>(m_current_offset),
decoder->GetFrameCount(),
static_cast<unsigned>(metaData.m_total_samples),
frameRateIndex,
static_cast<unsigned char>(decoder->GetNumChannels()),
metaData.m_number_of_channels,
sound.m_looping,
8,
};