/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 | | } |