flac_codec/
lib.rs

1// Copyright 2025 Brian Langenberger
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! A library for reading, writing, and editing the metadata
10//! of FLAC-formatted audio files.
11//!
12//! # What Is FLAC?
13//!
14//! FLAC is the **F**ree **L**ossless **A**udio **C**odec,
15//! a popular audio codec which losslessly compresses audio
16//! such that the original data can always be restored.
17//!
18//! Its notable qualities include:
19//!
20//! - Broad support on a wide array of players and devices
21//! - A design that allows for extremely fast decoding speed
22//! - Metadata support for text and images (e.g. cover artwork)
23//! - Data integrity checks including checksummed input and hashed output
24//!
25//! # What Can This Crate Do?
26//!
27//! Intended to provide comprehensive support for the FLAC format,
28//! this crate allows the user to:
29//!
30//! - Read and edit FLAC file metadata, via the [`metadata`] module
31//! - Decode FLAC files to PCM samples or bytes, via the [`decode`] module
32//! - Verify FLAC files for correctness via the [`decode::verify`] function
33//! - Encode FLAC files from PCM samples or bytes, via the [`encode`] module
34//! - Analyze the raw structure of FLAC frames, via the [`stream`] module
35//!
36//! It is based heavily on the
37//! [official FLAC specification (RFC 9639)](https://datatracker.ietf.org/doc/rfc9639/)
38//! and verified against the
39//! [reference implementation](https://www.xiph.org/flac/index.html).
40//!
41//! Check the `examples/` directory in the source code
42//! repository for several examples of using this crate for common
43//! FLAC management tasks.
44
45#![warn(missing_docs)]
46#![forbid(unsafe_code)]
47
48mod audio;
49pub mod byteorder;
50mod crc;
51pub mod decode;
52pub mod encode;
53pub mod metadata;
54pub mod stream;
55
56/// A unified FLAC error
57#[derive(Debug)]
58#[non_exhaustive]
59pub enum Error {
60    /// A general I/O error from the underlying stream
61    Io(std::io::Error),
62    /// A UTF-8 formatting error
63    Utf8(Box<std::string::FromUtf8Error>),
64    /// A FLAC file missing its initial "fLaC" file tag
65    MissingFlacTag,
66    /// A FLAC file missing its initial STREAMINFO block
67    MissingStreaminfo,
68    /// A FLAC file containing multiple STREAMINFO blocks
69    MultipleStreaminfo,
70    /// A FLAC file containing multiple SEEKTABLE blocks
71    MultipleSeekTable,
72    /// A FLAC file containing multiple VORBIS_COMMENT blocks
73    MultipleVorbisComment,
74    /// A SEEKTABLE block whose size isn't evenly divisible
75    /// by a whole of number of seek points.
76    InvalidSeekTableSize,
77    /// A SEEKTABLE point whose offset does not increment properly
78    InvalidSeekTablePoint,
79    /// A CUESHEET-specific error
80    Cuesheet(metadata::CuesheetError),
81    /// An undefined PICTURE type
82    InvalidPictureType,
83    /// Multiple 32x32 PNG icons defined
84    MultiplePngIcon,
85    /// Multiple general file icons defined
86    MultipleGeneralIcon,
87    /// A reserved metadata block encountered
88    ReservedMetadataBlock,
89    /// An invalid metadata block encountered
90    InvalidMetadataBlock,
91    /// A metadata block's contents are smaller than the size
92    /// indicated in the metadata block header.
93    InvalidMetadataBlockSize,
94    /// An APPLICATION metadata block which is not large enough
95    /// to hold any contents beyond its ID.
96    InsufficientApplicationBlock,
97    /// A `VorbisComment` struct with more entries that can fit in a `u32`
98    ExcessiveVorbisEntries,
99    /// A `VorbisComment` or `Picture` struct with strings longer than a `u32`
100    ExcessiveStringLength,
101    /// A `Picture` struct whose data is larger than a `u32`
102    ExcessivePictureSize,
103    /// A block size less than 15 that's not the last block
104    ShortBlock,
105    /// A metadata block larger than its 24-bit size field can hold
106    ExcessiveBlockSize,
107    /// Invalid frame sync code
108    InvalidSyncCode,
109    /// Invalid frame block size
110    InvalidBlockSize,
111    /// Block size in frame is larger than maximum block size in STREAMINFO
112    BlockSizeMismatch,
113    /// Invalid frame sample rate
114    InvalidSampleRate,
115    /// Non-subset frame sample rate
116    NonSubsetSampleRate,
117    /// Non-subset frame bits-per-sample
118    NonSubsetBitsPerSample,
119    /// Mismatch between frame sample rate and STREAMINFO sample rate
120    SampleRateMismatch,
121    /// Excessive channel count
122    ExcessiveChannels,
123    /// Invalid frame channel assignment
124    InvalidChannels,
125    /// Channel count in frame differs from channel count in STREAMINFO
126    ChannelsMismatch,
127    /// Invalid frame bits-per-sample
128    InvalidBitsPerSample,
129    /// Excessive number of bits-per-sample
130    ExcessiveBps,
131    /// Bits-per-sample in frame differs from bits-per-sample in STREAMINFO
132    BitsPerSampleMismatch,
133    /// Invalid frame number
134    InvalidFrameNumber,
135    /// Seeking beyond end of file
136    InvalidSeek,
137    /// Excessive frame number
138    ExcessiveFrameNumber,
139    /// CRC-8 mismatch in frame header
140    Crc8Mismatch,
141    /// CRC-16 mismatch in frame footer
142    Crc16Mismatch,
143    /// Invalid subframe header
144    InvalidSubframeHeader,
145    /// Invalid subframe header type
146    InvalidSubframeHeaderType,
147    /// Excessive number of wasted bits-per-sample
148    ExcessiveWastedBits,
149    /// Insufficient number of residuals in residuals block
150    MissingResiduals,
151    /// Invalid residual coding method
152    InvalidCodingMethod,
153    /// Invalid residual partition order
154    InvalidPartitionOrder,
155    /// Invalid FIXED subframe predictor order
156    InvalidFixedOrder,
157    /// Invalid LPC subframe predictor order
158    InvalidLpcOrder,
159    /// Invalid coefficient precision bits
160    InvalidQlpPrecision,
161    /// Negative shift value in LPC subframe
162    NegativeLpcShift,
163    /// Unable to determine best LPC order
164    NoBestLpcOrder,
165    /// Insufficient samples for LPC subframe
166    InsufficientLpcSamples,
167    /// LP coefficients are all 0
168    ZeroLpCoefficients,
169    /// Excessive negative shift in LP quantization
170    LpNegativeShiftError,
171    /// Accumulator overflow in LPC subframe
172    AccumulatorOverflow,
173    /// Too many samples encountered in stream
174    TooManySamples,
175    /// Too many samples requested by encoder
176    ExcessiveTotalSamples,
177    /// No samples written by encoder
178    NoSamples,
179    /// Number of samples written to stream differs from expected
180    SampleCountMismatch,
181    /// Residual overflow
182    ResidualOverflow,
183    /// Number of samples not evenly divisible by number of channels
184    SamplesNotDivisibleByChannels,
185    /// Invalid total byte count
186    InvalidTotalBytes,
187    /// Invalid total samples count
188    InvalidTotalSamples,
189    /// Number of channels sent to encoder is incorrect
190    ChannelCountMismatch,
191    /// Channels sent to encoder are not all the same length
192    ChannelLengthMismatch,
193}
194
195impl From<std::io::Error> for Error {
196    #[inline]
197    fn from(error: std::io::Error) -> Self {
198        Self::Io(error)
199    }
200}
201
202impl From<std::string::FromUtf8Error> for Error {
203    #[inline]
204    fn from(error: std::string::FromUtf8Error) -> Self {
205        Self::Utf8(Box::new(error))
206    }
207}
208
209impl From<metadata::CuesheetError> for Error {
210    fn from(error: metadata::CuesheetError) -> Self {
211        Self::Cuesheet(error)
212    }
213}
214
215impl std::error::Error for Error {}
216
217impl std::fmt::Display for Error {
218    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
219        match self {
220            Self::Io(e) => e.fmt(f),
221            Self::Utf8(e) => e.fmt(f),
222            Self::Cuesheet(e) => e.fmt(f),
223            Self::MissingFlacTag => "missing FLAC tag".fmt(f),
224            Self::MissingStreaminfo => "STREAMINFO block not first in file".fmt(f),
225            Self::MultipleStreaminfo => "multiple STREAMINFO blocks found in file".fmt(f),
226            Self::MultipleSeekTable => "multiple SEEKTABLE blocks found in file".fmt(f),
227            Self::MultipleVorbisComment => "multiple VORBIS_COMMENT blocks found in file".fmt(f),
228            Self::InvalidSeekTableSize => "invalid SEEKTABLE block size".fmt(f),
229            Self::InvalidSeekTablePoint => "invalid SEEKTABLE point".fmt(f),
230            Self::InvalidPictureType => "reserved PICTURE type".fmt(f),
231            Self::MultiplePngIcon => "multiple PNG icons in PICTURE blocks".fmt(f),
232            Self::MultipleGeneralIcon => "multiple general file icons in PICTURE blocks".fmt(f),
233            Self::ReservedMetadataBlock => "reserved metadata block".fmt(f),
234            Self::InvalidMetadataBlock => "invalid metadata block".fmt(f),
235            Self::InvalidMetadataBlockSize => "invalid metadata block size".fmt(f),
236            Self::InsufficientApplicationBlock => "APPLICATION block too small for data".fmt(f),
237            Self::ExcessiveVorbisEntries => "excessive number of VORBIS_COMMENT entries".fmt(f),
238            Self::ExcessiveStringLength => "excessive string length".fmt(f),
239            Self::ExcessivePictureSize => "excessive PICTURE data size".fmt(f),
240            Self::ExcessiveBlockSize => "excessive metadata block size".fmt(f),
241            Self::InvalidSyncCode => "invalid frame sync code".fmt(f),
242            Self::InvalidBlockSize => "invalid frame block size".fmt(f),
243            Self::ShortBlock => "block size <= 14 must be last in stream".fmt(f),
244            Self::BlockSizeMismatch => {
245                "block size in frame larger than maximum block size in STREAMINFO".fmt(f)
246            }
247            Self::InvalidSampleRate => "invalid frame sample rate".fmt(f),
248            Self::NonSubsetSampleRate => "sample rate undefined for subset stream".fmt(f),
249            Self::NonSubsetBitsPerSample => "bits-per-sample undefined for subset stream".fmt(f),
250            Self::SampleRateMismatch => {
251                "sample rate in frame differs from sample rate in STREAMINFO".fmt(f)
252            }
253            Self::ExcessiveChannels => "excessive channel count".fmt(f),
254            Self::InvalidChannels => "invalid frame channel assignment".fmt(f),
255            Self::ChannelsMismatch => {
256                "channel count in frame differs from channel count in STREAMINFO".fmt(f)
257            }
258            Self::InvalidBitsPerSample => "invalid frame bits-per-sample".fmt(f),
259            Self::ExcessiveBps => "bits-per-sample higher than 32".fmt(f),
260            Self::BitsPerSampleMismatch => {
261                "bits-per-sample in frame differs from bits-per-sample in STREAMINFO".fmt(f)
262            }
263            Self::InvalidFrameNumber => "invalid frame number".fmt(f),
264            Self::InvalidSeek => "seeking beyond end of stream".fmt(f),
265            Self::ExcessiveFrameNumber => "excessive frame number".fmt(f),
266            Self::Crc8Mismatch => "CRC-8 mismatch in frame header".fmt(f),
267            Self::Crc16Mismatch => "CRC-16 mismatch in frame footer".fmt(f),
268            Self::InvalidSubframeHeader => "invalid subframe header".fmt(f),
269            Self::InvalidSubframeHeaderType => "invalid subframe header type".fmt(f),
270            Self::ExcessiveWastedBits => "excessive number of wasted BPS".fmt(f),
271            Self::MissingResiduals => "insufficient number of residuals".fmt(f),
272            Self::InvalidCodingMethod => "invalid residual coding method".fmt(f),
273            Self::InvalidPartitionOrder => "invalid residual partition order".fmt(f),
274            Self::InvalidFixedOrder => "invalid FIXED subframe predictor order".fmt(f),
275            Self::InvalidLpcOrder => "invalid LPC subframe predictor order".fmt(f),
276            Self::InvalidQlpPrecision => "invalid QLP precision bits".fmt(f),
277            Self::NegativeLpcShift => "negative shift in LPC subframe".fmt(f),
278            Self::NoBestLpcOrder => "no best LPC order found".fmt(f),
279            Self::InsufficientLpcSamples => {
280                "insufficient samples to calculate LPC parameters".fmt(f)
281            }
282            Self::ZeroLpCoefficients => "LP coefficients are all 0".fmt(f),
283            Self::LpNegativeShiftError => "excessive negative shift in LP quantization".fmt(f),
284            Self::AccumulatorOverflow => "accumulator overflow in LPC subframe".fmt(f),
285            Self::TooManySamples => "more samples in stream than indicated in STREAMINFO".fmt(f),
286            Self::ExcessiveTotalSamples => "too many samples requested".fmt(f),
287            Self::NoSamples => "no samples written to encoder".fmt(f),
288            Self::SampleCountMismatch => "samples written to stream differ from expected".fmt(f),
289            Self::ResidualOverflow => "residual value too large".fmt(f),
290            Self::SamplesNotDivisibleByChannels => {
291                "number of samples not divisible number number of channels".fmt(f)
292            }
293            Self::InvalidTotalBytes => "invalid total byte count".fmt(f),
294            Self::InvalidTotalSamples => "invalid total samples count".fmt(f),
295            Self::ChannelCountMismatch => {
296                "number of written channels differs from encoder's channel count".fmt(f)
297            }
298            Self::ChannelLengthMismatch => "number of written channels are not consistent".fmt(f),
299        }
300    }
301}
302
303impl From<Error> for std::io::Error {
304    fn from(err: Error) -> Self {
305        match err {
306            Error::Io(io) => io,
307            Error::Utf8(e) => std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()),
308            other => std::io::Error::new(std::io::ErrorKind::InvalidData, other.to_string()),
309        }
310    }
311}
312
313struct Counter<F> {
314    stream: F,
315    count: u64,
316}
317
318impl<F> Counter<F> {
319    fn new(stream: F) -> Self {
320        Self { stream, count: 0 }
321    }
322
323    fn stream(&mut self) -> &mut F {
324        &mut self.stream
325    }
326}
327
328impl<F: std::io::Read> std::io::Read for Counter<F> {
329    #[inline]
330    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
331        self.stream.read(buf).inspect(|bytes| {
332            self.count += u64::try_from(*bytes).unwrap();
333        })
334    }
335}
336
337impl<F: std::io::Write> std::io::Write for Counter<F> {
338    #[inline]
339    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
340        self.stream.write(buf).inspect(|bytes| {
341            self.count += u64::try_from(*bytes).unwrap();
342        })
343    }
344
345    #[inline]
346    fn flush(&mut self) -> std::io::Result<()> {
347        self.stream.flush()
348    }
349}