claxon/lib.rs
1// Claxon -- A FLAC decoding library in Rust
2// Copyright 2014 Ruud van Asseldonk
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// A copy of the License has been included in the root of the repository.
7
8//! Claxon, a FLAC decoding library.
9//!
10//! Examples
11//! ========
12//!
13//! The following example computes the root mean square (RMS) of a FLAC file.
14//!
15//! ```
16//! # use claxon;
17//! let mut reader = claxon::FlacReader::open("testsamples/pop.flac").unwrap();
18//! let mut sqr_sum = 0.0;
19//! let mut count = 0;
20//! for sample in reader.samples() {
21//! let s = sample.unwrap() as f64;
22//! sqr_sum += s * s;
23//! count += 1;
24//! }
25//! println!("RMS is {}", (sqr_sum / count as f64).sqrt());
26//! ```
27//!
28//! A simple way to decode a file to wav with Claxon and
29//! [Hound](https://github.com/ruuda/hound):
30//!
31//! ```
32//! # extern crate hound;
33//! # extern crate claxon;
34//! # use std::path::Path;
35//! # fn decode_file(fname: &Path) {
36//! let mut reader = claxon::FlacReader::open(fname).expect("failed to open FLAC stream");
37//!
38//! let spec = hound::WavSpec {
39//! channels: reader.streaminfo().channels as u16,
40//! sample_rate: reader.streaminfo().sample_rate,
41//! bits_per_sample: reader.streaminfo().bits_per_sample as u16,
42//! sample_format: hound::SampleFormat::Int,
43//! };
44//!
45//! let fname_wav = fname.with_extension("wav");
46//! let opt_wav_writer = hound::WavWriter::create(fname_wav, spec);
47//! let mut wav_writer = opt_wav_writer.expect("failed to create wav file");
48//!
49//! for opt_sample in reader.samples() {
50//! let sample = opt_sample.expect("failed to decode FLAC stream");
51//! wav_writer.write_sample(sample).expect("failed to write wav file");
52//! }
53//! # }
54//! ```
55//!
56//! Retrieving the artist metadata:
57//!
58//! ```
59//! # use claxon;
60//! let reader = claxon::FlacReader::open("testsamples/pop.flac").unwrap();
61//! for artist in reader.get_tag("ARTIST") {
62//! println!("{}", artist);
63//! }
64//! ```
65//!
66//! For more examples, see the [examples](https://github.com/ruuda/claxon/tree/master/examples)
67//! directory in the crate.
68
69#![warn(missing_docs)]
70
71use std::fs;
72use std::io;
73use std::mem;
74use std::path;
75use error::fmt_err;
76use frame::FrameReader;
77use input::{BufferedReader, ReadBytes};
78use metadata::{MetadataBlock, MetadataBlockReader, StreamInfo, VorbisComment};
79
80mod crc;
81mod error;
82pub mod frame;
83pub mod input;
84pub mod metadata;
85pub mod subframe;
86
87pub use error::{Error, Result};
88pub use frame::Block;
89
90/// A FLAC decoder that can decode the stream from the underlying reader.
91///
92/// TODO: Add an example.
93pub struct FlacReader<R: io::Read> {
94 streaminfo: StreamInfo,
95 vorbis_comment: Option<VorbisComment>,
96 input: FlacReaderState<BufferedReader<R>>,
97}
98
99enum FlacReaderState<T> {
100 /// When the reader is positioned at the beginning of a frame.
101 Full(T),
102 /// When the reader might not be positioned at the beginning of a frame.
103 MetadataOnly(T),
104}
105
106/// Controls what metadata `FlacReader` reads when constructed.
107///
108/// The FLAC format contains a number of metadata blocks before the start of
109/// audio data. Reading these is wasteful if the data is never used. The
110/// `FlacReaderOptions` indicate which blocks to look for. As soon as all
111/// desired blocks have been read, `FlacReader::new_ext()` returns without
112/// reading remaining metadata blocks.
113///
114/// A few use cases:
115///
116/// * To read only the streaminfo, as quickly as possible, set `metadata_only`
117/// to true and `read_vorbis_comment` to false. The resulting reader cannot be
118/// used to read audio data.
119/// * To read only the streaminfo and tags, set `metadata_only` and
120/// `read_vorbis_comment` both to true. The resulting reader cannot be used to
121/// read audio data.
122#[derive(Copy, Clone, Debug, Eq, PartialEq)]
123pub struct FlacReaderOptions {
124 /// When true, return a reader as soon as all desired metadata has been read.
125 ///
126 /// If this is set, the `FlacReader` will not be able to read audio samples.
127 /// When reading audio is not desired anyway, enabling `metadata_only` can
128 /// save a lot of expensive reads.
129 ///
130 /// Defaults to false.
131 pub metadata_only: bool,
132
133 /// When true, read metadata blocks at least until a Vorbis comment block is found.
134 ///
135 /// When false, the `FlacReader` will be constructed without reading a
136 /// Vorbis comment block, even if the stream contains one. Consequently,
137 /// `FlacReader::tags()` and other tag-related methods will not return tag
138 /// data.
139 ///
140 /// Defaults to true.
141 pub read_vorbis_comment: bool,
142}
143
144impl Default for FlacReaderOptions {
145 fn default() -> FlacReaderOptions {
146 FlacReaderOptions {
147 read_vorbis_comment: true,
148 metadata_only: false,
149 }
150 }
151}
152
153impl FlacReaderOptions {
154 /// Return whether any metadata blocks need to be read.
155 fn has_desired_blocks(&self) -> bool {
156 // If we do not want only metadata, we want everything. Hence there are
157 // desired blocks left.
158 if !self.metadata_only {
159 return true
160 }
161
162 // Should be the or of all read_* fields, of which vorbis_comment is the
163 // only one at the moment.
164 self.read_vorbis_comment
165 }
166}
167
168/// An iterator that yields samples read from a `FlacReader`.
169pub struct FlacSamples<R: ReadBytes> {
170 frame_reader: FrameReader<R>,
171 block: Block,
172 sample: u32,
173 channel: u32,
174
175 /// If reading ever failed, this flag is set, so that the iterator knows not
176 /// to return any new values.
177 has_failed: bool,
178}
179
180// TODO: Add a `FlacIntoSamples`.
181
182fn read_stream_header<R: ReadBytes>(input: &mut R) -> Result<()> {
183 // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
184 const FLAC_HEADER: u32 = 0x66_4c_61_43;
185
186 // Some files start with ID3 tag data. The reference decoder supports this
187 // for convenience. Claxon does not, but we can at least generate a helpful
188 // error message if a file starts like this.
189 const ID3_HEADER: u32 = 0x49_44_33_00;
190
191 let header = try!(input.read_be_u32());
192 if header != FLAC_HEADER {
193 if (header & 0xff_ff_ff_00) == ID3_HEADER {
194 fmt_err("stream starts with ID3 header rather than FLAC header")
195 } else {
196 fmt_err("invalid stream header")
197 }
198 } else {
199 Ok(())
200 }
201}
202
203impl<R: io::Read> FlacReader<R> {
204 /// Create a reader that reads the FLAC format.
205 ///
206 /// The header and metadata blocks are read immediately. Audio frames
207 /// will be read on demand.
208 ///
209 /// Claxon rejects files that claim to contain excessively large metadata
210 /// blocks, to protect against denial of service attacks where a
211 /// small damaged or malicous file could cause gigabytes of memory
212 /// to be allocated. `Error::Unsupported` is returned in that case.
213 pub fn new(reader: R) -> Result<FlacReader<R>> {
214 FlacReader::new_ext(reader, FlacReaderOptions::default())
215 }
216
217 /// Create a reader that reads the FLAC format, with reader options.
218 ///
219 /// The header and metadata blocks are read immediately, but only as much as
220 /// specified in the options. See `FlacReaderOptions` for more details.
221 ///
222 /// Claxon rejects files that claim to contain excessively large metadata
223 /// blocks, to protect against denial of service attacks where a
224 /// small damaged or malicous file could cause gigabytes of memory
225 /// to be allocated. `Error::Unsupported` is returned in that case.
226 pub fn new_ext(reader: R, options: FlacReaderOptions) -> Result<FlacReader<R>> {
227 let mut buf_reader = BufferedReader::new(reader);
228 let mut opts_current = options;
229
230 // A flac stream first of all starts with a stream header.
231 try!(read_stream_header(&mut buf_reader));
232
233 // Start a new scope, because the input reader must be available again
234 // for the frame reader next.
235 let (streaminfo, vorbis_comment) = {
236 // Next are one or more metadata blocks. The flac specification
237 // dictates that the streaminfo block is the first block. The metadata
238 // block reader will yield at least one element, so the unwrap is safe.
239 let mut metadata_iter = MetadataBlockReader::new(&mut buf_reader);
240 let streaminfo_block = try!(metadata_iter.next().unwrap());
241 let streaminfo = match streaminfo_block {
242 MetadataBlock::StreamInfo(info) => info,
243 _ => return fmt_err("streaminfo block missing"),
244 };
245
246 let mut vorbis_comment = None;
247
248 // There might be more metadata blocks, read and store them.
249 for block_result in metadata_iter {
250 match try!(block_result) {
251 MetadataBlock::VorbisComment(vc) => {
252 // The Vorbis comment block need not be present, but
253 // when it is, it must be unique.
254 if vorbis_comment.is_some() {
255 return fmt_err("encountered second Vorbis comment block")
256 } else {
257 vorbis_comment = Some(vc);
258 }
259
260 // We have one, no new one is desired.
261 opts_current.read_vorbis_comment = false;
262 }
263 MetadataBlock::StreamInfo(..) => {
264 return fmt_err("encountered second streaminfo block")
265 }
266 // Other blocks are currently not handled.
267 _block => {}
268 }
269
270 // Early-out reading metadata once all desired blocks have been
271 // collected.
272 if !opts_current.has_desired_blocks() {
273 break
274 }
275 }
276
277 // TODO: Rather than discarding afterwards, never parse it in the
278 // first place; treat it like padding in the MetadataBlockReader.
279 if !options.read_vorbis_comment {
280 vorbis_comment = None;
281 }
282
283 (streaminfo, vorbis_comment)
284 };
285
286 // Even if we might have read all metadata blocks, only set the state to
287 // "full" if `metadata_only` was false: this results in more predictable
288 // behavior.
289 let state = if options.metadata_only {
290 FlacReaderState::MetadataOnly(buf_reader)
291 } else {
292 FlacReaderState::Full(buf_reader)
293 };
294
295 // The flac reader will contain the reader that will read frames.
296 let flac_reader = FlacReader {
297 streaminfo: streaminfo,
298 vorbis_comment: vorbis_comment,
299 input: state,
300 };
301
302 Ok(flac_reader)
303 }
304
305 /// Returns the streaminfo metadata.
306 ///
307 /// This contains information like the sample rate and number of channels.
308 pub fn streaminfo(&self) -> StreamInfo {
309 self.streaminfo
310 }
311
312 /// Returns the vendor string of the Vorbis comment block, if present.
313 ///
314 /// This string usually contains the name and version of the program that
315 /// encoded the FLAC stream, such as `reference libFLAC 1.3.2 20170101`
316 /// or `Lavf57.25.100`.
317 pub fn vendor(&self) -> Option<&str> {
318 self.vorbis_comment.as_ref().map(|vc| &vc.vendor[..])
319 }
320
321 /// Returns name-value pairs of Vorbis comments, such as `("ARTIST", "Queen")`.
322 ///
323 /// The name is supposed to be interpreted case-insensitively, and is
324 /// guaranteed to consist of ASCII characters. Claxon does not normalize
325 /// the casing of the name. Use `get_tag()` to do a case-insensitive lookup.
326 ///
327 /// Names need not be unique. For instance, multiple `ARTIST` comments might
328 /// be present on a collaboration track.
329 ///
330 /// See <https://www.xiph.org/vorbis/doc/v-comment.html> for more details.
331 pub fn tags<'a>(&'a self) -> metadata::Tags<'a> {
332 match self.vorbis_comment.as_ref() {
333 Some(vc) => metadata::Tags::new(&vc.comments[..]),
334 None => metadata::Tags::new(&[]),
335 }
336 }
337
338 /// Look up a Vorbis comment such as `ARTIST` in a case-insensitive way.
339 ///
340 /// Returns an iterator, because tags may occur more than once. There could
341 /// be multiple `ARTIST` tags on a collaboration track, for instance.
342 ///
343 /// Note that tag names are ASCII and never contain `'='`; trying to look up
344 /// a non-ASCII tag will return no results. Furthermore, the Vorbis comment
345 /// spec dictates that tag names should be handled case-insensitively, so
346 /// this method performs a case-insensitive lookup.
347 ///
348 /// See also `tags()` for access to the raw tags.
349 /// See <https://www.xiph.org/vorbis/doc/v-comment.html> for more details.
350 pub fn get_tag<'a>(&'a self, tag_name: &'a str) -> metadata::GetTag<'a> {
351 match self.vorbis_comment.as_ref() {
352 Some(vc) => metadata::GetTag::new(&vc.comments[..], tag_name),
353 None => metadata::GetTag::new(&[], tag_name),
354 }
355 }
356
357 /// Returns an iterator that decodes a single frame on every iteration.
358 /// TODO: It is not an iterator.
359 ///
360 /// This is a low-level primitive that gives you control over when decoding
361 /// happens. The representation of the decoded audio is somewhat specific to
362 /// the FLAC format. For a higher-level interface, see `samples()`.
363 pub fn blocks<'r>(&'r mut self) -> FrameReader<&'r mut BufferedReader<R>> {
364 match self.input {
365 FlacReaderState::Full(ref mut inp) => FrameReader::new(inp),
366 FlacReaderState::MetadataOnly(..) =>
367 panic!("FlacReaderOptions::metadata_only must be false \
368 to be able to use FlacReader::blocks()"),
369 }
370 }
371
372 /// Returns an iterator over all samples.
373 ///
374 /// The channel data is is interleaved. The iterator is streaming. That is,
375 /// if you call this method once, read a few samples, and call this method
376 /// again, the second iterator will not start again from the beginning of
377 /// the file. It will continue somewhere after where the first iterator
378 /// stopped, and it might skip some samples. (This is because FLAC divides
379 /// a stream into blocks, which have to be decoded entirely. If you drop the
380 /// iterator, you lose the unread samples in that block.)
381 ///
382 /// This is a user-friendly interface that trades performance for ease of
383 /// use. If performance is an issue, consider using `blocks()` instead.
384 ///
385 /// This is a high-level interface to the decoder. The cost of retrieving
386 /// the next sample can vary significantly, as sometimes a new block has to
387 /// be decoded. Additionally, there is a cost to every iteration returning a
388 /// `Result`. When a block has been decoded, iterating the samples in that
389 /// block can never fail, but a match on every sample is required
390 /// nonetheless. For more control over when decoding happens, and less error
391 /// handling overhead, use `blocks()`.
392 pub fn samples<'r>(&'r mut self) -> FlacSamples<&'r mut BufferedReader<R>> {
393 match self.input {
394 FlacReaderState::Full(ref mut inp) => {
395 FlacSamples {
396 frame_reader: frame::FrameReader::new(inp),
397 block: Block::empty(),
398 sample: 0,
399 channel: 0,
400 has_failed: false,
401 }
402 }
403 FlacReaderState::MetadataOnly(..) => {
404 panic!("FlacReaderOptions::metadata_only must be false \
405 to be able to use FlacReader::samples()")
406 }
407 }
408 }
409
410 /// Destroys the FLAC reader and returns the underlying reader.
411 ///
412 /// Because the reader employs buffering internally, anything in the buffer
413 /// will be lost.
414 pub fn into_inner(self) -> R {
415 match self.input {
416 FlacReaderState::Full(inp) => inp.into_inner(),
417 FlacReaderState::MetadataOnly(inp) => inp.into_inner(),
418 }
419 }
420}
421
422impl FlacReader<fs::File> {
423 /// Attempts to create a reader that reads from the specified file.
424 ///
425 /// This is a convenience constructor that opens a `File`, and constructs a
426 /// `FlacReader` from it. There is no need to wrap the file in a
427 /// `BufReader`, as the `FlacReader` employs buffering already.
428 pub fn open<P: AsRef<path::Path>>(filename: P) -> Result<FlacReader<fs::File>> {
429 let file = try!(fs::File::open(filename));
430 FlacReader::new(file)
431 }
432
433 /// Attemps to create a reader that reads from the specified file.
434 ///
435 /// This is a convenience constructor that opens a `File`, and constructs a
436 /// `FlacReader` from it. There is no need to wrap the file in a
437 /// `BufReader`, as the `FlacReader` employs buffering already.
438 pub fn open_ext<P: AsRef<path::Path>>(filename: P,
439 options: FlacReaderOptions)
440 -> Result<FlacReader<fs::File>> {
441 let file = try!(fs::File::open(filename));
442 FlacReader::new_ext(file, options)
443 }
444}
445
446impl<R: ReadBytes> Iterator for FlacSamples<R> {
447 type Item = Result<i32>;
448
449 fn next(&mut self) -> Option<Result<i32>> {
450 // If the previous read failed, end iteration.
451 if self.has_failed {
452 return None;
453 }
454
455 // Iterate the samples channel interleaved, so first increment the
456 // channel.
457 self.channel += 1;
458
459 // If that was the last channel, increment the sample number.
460 if self.channel >= self.block.channels() {
461 self.channel = 0;
462 self.sample += 1;
463
464 // If that was the last sample in the block, decode the next block.
465 if self.sample >= self.block.duration() {
466 self.sample = 0;
467
468 // Replace the current block with an empty one so that we may
469 // reuse the current buffer to decode again.
470 let current_block = mem::replace(&mut self.block, Block::empty());
471
472 match self.frame_reader.read_next_or_eof(current_block.into_buffer()) {
473 Ok(Some(next_block)) => {
474 self.block = next_block;
475 }
476 Ok(None) => {
477 // The stream ended with EOF.
478 // TODO: If a number of samples was specified in the
479 // streaminfo metadata block, verify that we did not
480 // read more or less samples.
481 return None;
482 }
483 Err(error) => {
484 self.has_failed = true;
485 return Some(Err(error));
486 }
487 }
488 }
489 }
490
491 Some(Ok(self.block.sample(self.channel, self.sample)))
492 }
493}