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:
parent
fc2301c23c
commit
bf3fa19314
2 changed files with 61 additions and 5 deletions
|
@ -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 } };
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue