1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 09:14:58 +00:00

LibAudio: Write FLAC metadata

This includes a generalization of the metadata block infrastructure, so
adding and writing blocks is handled in a generalized fashion.
This commit is contained in:
kleines Filmröllchen 2023-08-18 22:38:01 +02:00 committed by Andrew Kaster
parent fc2301c23c
commit bf3fa19314
2 changed files with 61 additions and 5 deletions

View file

@ -11,6 +11,8 @@
#include <AK/IntegralMath.h>
#include <AK/MemoryStream.h>
#include <AK/Statistics.h>
#include <LibAudio/Metadata.h>
#include <LibAudio/VorbisComment.h>
#include <LibCrypto/Checksum/ChecksummingStream.h>
namespace Audio {
@ -107,11 +109,23 @@ ErrorOr<void> FlacWriter::set_bits_per_sample(u16 bits_per_sample)
return {};
}
ErrorOr<void> FlacWriter::set_metadata(Metadata const& metadata)
{
AllocatingMemoryStream vorbis_stream;
TRY(write_vorbis_comment(metadata, vorbis_stream));
auto vorbis_data = TRY(vorbis_stream.read_until_eof());
FlacRawMetadataBlock vorbis_block {
.is_last_block = false,
.type = FlacMetadataBlockType::VORBIS_COMMENT,
.length = static_cast<u32>(vorbis_data.size()),
.data = move(vorbis_data),
};
return add_metadata_block(move(vorbis_block), 0);
}
ErrorOr<void> FlacWriter::write_header()
{
TRY(m_stream->write_until_depleted(flac_magic.bytes()));
m_streaminfo_start_index = TRY(m_stream->tell());
ByteBuffer data;
// STREAMINFO is always exactly 34 bytes long.
TRY(data.try_resize(34));
@ -140,13 +154,44 @@ ErrorOr<void> FlacWriter::write_header()
.is_last_block = true,
.type = FlacMetadataBlockType::STREAMINFO,
.length = static_cast<u32>(data.size()),
.data = data,
.data = move(data),
};
TRY(add_metadata_block(move(streaminfo_block), 0));
TRY(m_stream->write_value(streaminfo_block));
TRY(m_stream->write_until_depleted(flac_magic.bytes()));
m_streaminfo_start_index = TRY(m_stream->tell());
for (size_t i = 0; i < m_cached_metadata_blocks.size(); ++i) {
auto& block = m_cached_metadata_blocks[i];
// Correct is_last_block flag here to avoid index shenanigans in add_metadata_block.
auto const is_last_block = i == m_cached_metadata_blocks.size() - 1;
block.is_last_block = is_last_block;
TRY(write_metadata_block(block));
}
m_cached_metadata_blocks.clear();
return {};
}
ErrorOr<void> FlacWriter::add_metadata_block(FlacRawMetadataBlock block, Optional<size_t> insertion_index)
{
if (m_state != WriteState::HeaderUnwritten)
return Error::from_string_view("Metadata blocks can only be added before the header is finalized"sv);
if (insertion_index.has_value())
TRY(m_cached_metadata_blocks.try_insert(insertion_index.value(), move(block)));
else
TRY(m_cached_metadata_blocks.try_append(move(block)));
return {};
}
ErrorOr<void> FlacWriter::write_metadata_block(FlacRawMetadataBlock const& block)
{
return m_stream->write_value(block);
}
ErrorOr<void> FlacRawMetadataBlock::write_to_stream(Stream& stream) const
{
BigEndianOutputBitStream bit_stream { MaybeOwned<Stream> { stream } };

View file

@ -13,6 +13,8 @@
#include <AK/StringView.h>
#include <LibAudio/Encoder.h>
#include <LibAudio/FlacTypes.h>
#include <LibAudio/Forward.h>
#include <LibAudio/GenericTypes.h>
#include <LibAudio/Sample.h>
#include <LibAudio/SampleFormats.h>
#include <LibCore/Forward.h>
@ -80,6 +82,9 @@ public:
ErrorOr<void> set_num_channels(u8 num_channels);
ErrorOr<void> set_sample_rate(u32 sample_rate);
ErrorOr<void> set_bits_per_sample(u16 bits_per_sample);
virtual ErrorOr<void> set_metadata(Metadata const& metadata) override;
ErrorOr<void> finalize_header_format();
private:
@ -98,6 +103,9 @@ private:
// In this case, an empty Optional is returned.
ErrorOr<Optional<FlacLPCEncodedSubframe>> encode_fixed_lpc(FlacFixedLPC order, ReadonlySpan<i64> subframe, size_t current_min_cost, u8 bits_per_sample);
ErrorOr<void> add_metadata_block(FlacRawMetadataBlock block, Optional<size_t> insertion_index = {});
ErrorOr<void> write_metadata_block(FlacRawMetadataBlock const& block);
NonnullOwnPtr<SeekableStream> m_stream;
WriteState m_state { WriteState::HeaderUnwritten };
@ -114,6 +122,9 @@ private:
size_t m_sample_count { 0 };
// Remember where the STREAMINFO block was written in the stream.
size_t m_streaminfo_start_index;
// Raw metadata blocks that will be written out before header finalization.
Vector<FlacRawMetadataBlock> m_cached_metadata_blocks;
};
}