Coverage Report

Created: 2026-02-16 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibAudio/FlacLoader.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, kleines Filmröllchen <filmroellchen@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include "FlacTypes.h"
10
#include "Loader.h"
11
#include <AK/BitStream.h>
12
#include <AK/Error.h>
13
#include <AK/Span.h>
14
#include <AK/Types.h>
15
16
namespace Audio {
17
18
ALWAYS_INLINE u8 frame_channel_type_to_channel_count(FlacFrameChannelType channel_type);
19
// Decodes the sign representation method used in Rice coding.
20
// Numbers alternate between positive and negative: 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, ...
21
ALWAYS_INLINE i32 rice_to_signed(u32 x);
22
23
// decoders
24
// read a UTF-8 encoded number, even if it is not a valid codepoint
25
ALWAYS_INLINE ErrorOr<u64> read_utf8_char(BigEndianInputBitStream& input);
26
// decode a single number encoded with exponential golomb encoding of the specified order
27
ALWAYS_INLINE ErrorOr<i32> decode_unsigned_exp_golomb(u8 order, BigEndianInputBitStream& bit_input);
28
29
// Loader for the Free Lossless Audio Codec (FLAC)
30
// This loader supports all audio features of FLAC, although audio from more than two channels is discarded.
31
// The loader currently supports the STREAMINFO, PADDING, and SEEKTABLE metadata blocks.
32
// See: https://xiph.org/flac/documentation_format_overview.html
33
//      https://xiph.org/flac/format.html (identical to IETF draft version 2)
34
//      https://datatracker.ietf.org/doc/html/draft-ietf-cellar-flac-02 (all section numbers refer to this specification)
35
//      https://datatracker.ietf.org/doc/html/draft-ietf-cellar-flac-03 (newer IETF draft that uses incompatible numberings and names)
36
class FlacLoaderPlugin : public LoaderPlugin {
37
public:
38
    explicit FlacLoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
39
293
    virtual ~FlacLoaderPlugin() override = default;
40
41
    static bool sniff(SeekableStream& stream);
42
    static ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> create(NonnullOwnPtr<SeekableStream>);
43
44
    virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
45
46
    virtual MaybeLoaderError reset() override;
47
    virtual MaybeLoaderError seek(int sample_index) override;
48
49
0
    virtual int loaded_samples() override { return static_cast<int>(m_loaded_samples); }
50
0
    virtual int total_samples() override { return static_cast<int>(m_total_samples); }
51
0
    virtual u32 sample_rate() override { return m_sample_rate; }
52
0
    virtual u16 num_channels() override { return m_num_channels; }
53
0
    virtual ByteString format_name() override { return "FLAC (.flac)"; }
54
0
    virtual PcmSampleFormat pcm_format() override { return m_sample_format; }
55
56
66.6k
    bool is_fixed_blocksize_stream() const { return m_min_block_size == m_max_block_size; }
57
0
    bool sample_count_unknown() const { return m_total_samples == 0; }
58
59
private:
60
    MaybeLoaderError initialize();
61
    MaybeLoaderError parse_header();
62
    // Either returns the metadata block or sets error message.
63
    // Additionally, increments m_data_start_location past the read meta block.
64
    ErrorOr<FlacRawMetadataBlock, LoaderError> next_meta_block(BigEndianInputBitStream& bit_input);
65
    // Fetches and returns the next FLAC frame.
66
    LoaderSamples next_frame();
67
    // Helper of next_frame that fetches a sub frame's header
68
    ErrorOr<FlacSubframeHeader, LoaderError> next_subframe_header(BigEndianInputBitStream& bit_input, u8 channel_index);
69
    // Helper of next_frame that decompresses a subframe
70
    ErrorOr<void, LoaderError> parse_subframe(Vector<i64>& samples, FlacSubframeHeader& subframe_header, BigEndianInputBitStream& bit_input);
71
    // Subframe-internal data decoders (heavy lifting)
72
    ErrorOr<Vector<i64>, LoaderError> decode_fixed_lpc(FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input);
73
    ErrorOr<Vector<i64>, LoaderError> decode_verbatim(FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input);
74
    ErrorOr<void, LoaderError> decode_custom_lpc(Vector<i64>& decoded, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input);
75
    MaybeLoaderError decode_residual(Vector<i64>& decoded, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input);
76
    // decode a single rice partition that has its own rice parameter
77
    ALWAYS_INLINE ErrorOr<Vector<i64>, LoaderError> decode_rice_partition(u8 partition_type, u32 partitions, u32 partition_index, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input);
78
    MaybeLoaderError load_seektable(FlacRawMetadataBlock&);
79
    // Note that failing to read a Vorbis comment block is not treated as an error of the FLAC loader, since metadata is optional.
80
    void load_vorbis_comment(FlacRawMetadataBlock&);
81
    MaybeLoaderError load_picture(FlacRawMetadataBlock&);
82
83
    // Converters for special coding used in frame headers
84
    ALWAYS_INLINE ErrorOr<u32, LoaderError> convert_sample_count_code(u8 sample_count_code);
85
    ALWAYS_INLINE ErrorOr<u32, LoaderError> convert_sample_rate_code(u8 sample_rate_code);
86
    ALWAYS_INLINE ErrorOr<u8, LoaderError> convert_bit_depth_code(u8 bit_depth_code);
87
88
    bool should_insert_seekpoint_at(u64 sample_index) const;
89
90
    // Data obtained directly from the FLAC metadata: many values have specific bit counts
91
    u32 m_sample_rate { 0 };    // 20 bit
92
    u8 m_num_channels { 0 };    // 3 bit
93
    u8 m_bits_per_sample { 0 }; // 5 bits for the integer bit depth
94
    // Externally visible format; the smallest integer format that's larger than the precise bit depth.
95
    PcmSampleFormat m_sample_format;
96
    // Blocks are units of decoded audio data
97
    u16 m_min_block_size { 0 };
98
    u16 m_max_block_size { 0 };
99
    // Frames are units of encoded audio data, both of these are 24-bit
100
    u32 m_min_frame_size { 0 }; // 24 bit
101
    u32 m_max_frame_size { 0 }; // 24 bit
102
    u64 m_total_samples { 0 };  // 36 bit
103
    u8 m_md5_checksum[128 / 8]; // 128 bit (!)
104
    size_t m_loaded_samples { 0 };
105
106
    // keep track of the start of the data in the FLAC stream to seek back more easily
107
    u64 m_data_start_location { 0 };
108
    Optional<FlacFrameHeader> m_current_frame;
109
    u64 m_current_sample_or_frame { 0 };
110
    SeekTable m_seektable;
111
112
    // Keep around a few temporary buffers whose allocated space can be reused.
113
    // This is an empirical optimization since allocations and deallocations take a lot of time in the decoder.
114
    mutable Vector<Vector<i64>, 2> m_subframe_buffers;
115
};
116
117
}