symphonia_bundle_flac/
demuxer.rs

1// Symphonia
2// Copyright (c) 2019-2022 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8use std::io::{Seek, SeekFrom};
9
10use symphonia_core::support_format;
11
12use symphonia_core::codecs::{CodecParameters, VerificationCheck, CODEC_TYPE_FLAC};
13use symphonia_core::errors::{decode_error, seek_error, unsupported_error, Result, SeekErrorKind};
14use symphonia_core::formats::prelude::*;
15use symphonia_core::formats::util::{SeekIndex, SeekSearchResult};
16use symphonia_core::io::*;
17use symphonia_core::meta::{Metadata, MetadataBuilder, MetadataLog};
18use symphonia_core::probe::{Descriptor, Instantiate, QueryDescriptor};
19
20use symphonia_utils_xiph::flac::metadata::*;
21
22use log::{debug, info};
23
24use super::parser::PacketParser;
25
26/// The FLAC start of stream marker: "fLaC" in ASCII.
27const FLAC_STREAM_MARKER: [u8; 4] = *b"fLaC";
28
29/// Free Lossless Audio Codec (FLAC) native frame reader.
30pub struct FlacReader {
31    reader: MediaSourceStream,
32    metadata: MetadataLog,
33    tracks: Vec<Track>,
34    cues: Vec<Cue>,
35    index: Option<SeekIndex>,
36    first_frame_offset: u64,
37    parser: PacketParser,
38}
39
40impl FlacReader {
41    /// Reads all the metadata blocks, returning a fully populated `FlacReader`.
42    fn init_with_metadata(source: MediaSourceStream) -> Result<Self> {
43        let mut metadata_builder = MetadataBuilder::new();
44
45        let mut reader = source;
46        let mut tracks = Vec::new();
47        let mut cues = Vec::new();
48        let mut index = None;
49        let mut parser = Default::default();
50
51        loop {
52            let header = MetadataBlockHeader::read(&mut reader)?;
53
54            // Create a scoped bytestream to error if the metadata block read functions exceed the
55            // stated length of the block.
56            let mut block_stream = ScopedStream::new(&mut reader, u64::from(header.block_len));
57
58            match header.block_type {
59                MetadataBlockType::Application => {
60                    // TODO: Store vendor data.
61                    read_application_block(&mut block_stream, header.block_len)?;
62                }
63                // SeekTable blocks are parsed into a SeekIndex.
64                MetadataBlockType::SeekTable => {
65                    // Check if a SeekTable has already be parsed. If one has, then the file is
66                    // invalid, atleast for seeking. Either way, it's a violation of the
67                    // specification.
68                    if index.is_none() {
69                        let mut new_index = SeekIndex::new();
70                        read_seek_table_block(&mut block_stream, header.block_len, &mut new_index)?;
71                        index = Some(new_index);
72                    }
73                    else {
74                        return decode_error("flac: found more than one seek table block");
75                    }
76                }
77                // VorbisComment blocks are parsed into Tags.
78                MetadataBlockType::VorbisComment => {
79                    read_comment_block(&mut block_stream, &mut metadata_builder)?;
80                }
81                // Cuesheet blocks are parsed into Cues.
82                MetadataBlockType::Cuesheet => {
83                    read_cuesheet_block(&mut block_stream, &mut cues)?;
84                }
85                // Picture blocks are read as Visuals.
86                MetadataBlockType::Picture => {
87                    read_picture_block(&mut block_stream, &mut metadata_builder)?;
88                }
89                // StreamInfo blocks are parsed into Streams.
90                MetadataBlockType::StreamInfo => {
91                    read_stream_info_block(&mut block_stream, &mut tracks, &mut parser)?;
92                }
93                // Padding blocks are skipped.
94                MetadataBlockType::Padding => {
95                    block_stream.ignore_bytes(u64::from(header.block_len))?;
96                }
97                // Unknown block encountered. Skip these blocks as they may be part of a future
98                // version of FLAC, but  print a message.
99                MetadataBlockType::Unknown(id) => {
100                    block_stream.ignore_bytes(u64::from(header.block_len))?;
101                    info!("ignoring {} bytes of block width id={}.", header.block_len, id);
102                }
103            }
104
105            // If the stated block length is longer than the number of bytes from the block read,
106            // ignore the remaining unread data.
107            let block_unread_len = block_stream.bytes_available();
108
109            if block_unread_len > 0 {
110                info!("under read block by {} bytes.", block_unread_len);
111                block_stream.ignore_bytes(block_unread_len)?;
112            }
113
114            // Exit when the last header is read.
115            if header.is_last {
116                break;
117            }
118        }
119
120        // Commit any read metadata to the metadata log.
121        let mut metadata = MetadataLog::default();
122        metadata.push(metadata_builder.metadata());
123
124        // Synchronize the packet parser to the first audio frame.
125        let _ = parser.resync(&mut reader)?;
126
127        // The first frame offset is the byte offset from the beginning of the stream after all the
128        // metadata blocks have been read.
129        let first_frame_offset = reader.pos();
130
131        Ok(FlacReader { reader, metadata, tracks, cues, index, first_frame_offset, parser })
132    }
133}
134
135impl QueryDescriptor for FlacReader {
136    fn query() -> &'static [Descriptor] {
137        &[support_format!(
138            "flac",
139            "Free Lossless Audio Codec Native",
140            &["flac"],
141            &["audio/flac"],
142            &[b"fLaC"]
143        )]
144    }
145
146    fn score(_context: &[u8]) -> u8 {
147        255
148    }
149}
150
151impl FormatReader for FlacReader {
152    fn try_new(mut source: MediaSourceStream, _options: &FormatOptions) -> Result<Self> {
153        // Read the first 4 bytes of the stream. Ideally this will be the FLAC stream marker.
154        let marker = source.read_quad_bytes()?;
155
156        if marker != FLAC_STREAM_MARKER {
157            return unsupported_error("flac: missing flac stream marker");
158        }
159
160        // Strictly speaking, the first metadata block must be a StreamInfo block. There is
161        // no technical need for this from the reader's point of view. Additionally, if the
162        // reader is fed a stream mid-way there is no StreamInfo block. Therefore, just read
163        // all metadata blocks and handle the StreamInfo block as it comes.
164        let flac = Self::init_with_metadata(source)?;
165
166        // Make sure that there is atleast one StreamInfo block.
167        if flac.tracks.is_empty() {
168            return decode_error("flac: no stream info block");
169        }
170
171        Ok(flac)
172    }
173
174    fn next_packet(&mut self) -> Result<Packet> {
175        self.parser.parse(&mut self.reader)
176    }
177
178    fn metadata(&mut self) -> Metadata<'_> {
179        self.metadata.metadata()
180    }
181
182    fn cues(&self) -> &[Cue] {
183        &self.cues
184    }
185
186    fn tracks(&self) -> &[Track] {
187        &self.tracks
188    }
189
190    fn seek(&mut self, _mode: SeekMode, to: SeekTo) -> Result<SeekedTo> {
191        if self.tracks.is_empty() {
192            return seek_error(SeekErrorKind::Unseekable);
193        }
194
195        let params = &self.tracks[0].codec_params;
196
197        // Get the timestamp of the desired audio frame.
198        let ts = match to {
199            // Frame timestamp given.
200            SeekTo::TimeStamp { ts, .. } => ts,
201            // Time value given, calculate frame timestamp from sample rate.
202            SeekTo::Time { time, .. } => {
203                // Use the sample rate to calculate the frame timestamp. If sample rate is not
204                // known, the seek cannot be completed.
205                if let Some(sample_rate) = params.sample_rate {
206                    TimeBase::new(1, sample_rate).calc_timestamp(time)
207                }
208                else {
209                    return seek_error(SeekErrorKind::Unseekable);
210                }
211            }
212        };
213
214        debug!("seeking to frame_ts={}", ts);
215
216        // If the total number of frames in the stream is known, verify the desired frame timestamp
217        // does not exceed it.
218        if let Some(n_frames) = params.n_frames {
219            if ts > n_frames {
220                return seek_error(SeekErrorKind::OutOfRange);
221            }
222        }
223
224        // If the reader supports seeking, coarsely seek to the nearest packet with a timestamp
225        // lower than the desired timestamp using a binary search.
226        if self.reader.is_seekable() {
227            // The range formed by start_byte_offset..end_byte_offset defines an area where the
228            // binary search for the packet containing the desired timestamp will be performed. The
229            // lower bound is set to the byte offset of the first frame, while the upper bound is
230            // set to the length of the stream.
231            let mut start_byte_offset = self.first_frame_offset;
232            let mut end_byte_offset = self.reader.seek(SeekFrom::End(0))?;
233
234            // If there is an index, use it to refine the binary search range.
235            if let Some(ref index) = self.index {
236                // Search the index for the timestamp. Adjust the search based on the result.
237                match index.search(ts) {
238                    // Search from the start of stream up-to an ending point.
239                    SeekSearchResult::Upper(upper) => {
240                        end_byte_offset = self.first_frame_offset + upper.byte_offset;
241                    }
242                    // Search from a starting point up-to the end of the stream.
243                    SeekSearchResult::Lower(lower) => {
244                        start_byte_offset = self.first_frame_offset + lower.byte_offset;
245                    }
246                    // Search between two points of the stream.
247                    SeekSearchResult::Range(lower, upper) => {
248                        start_byte_offset = self.first_frame_offset + lower.byte_offset;
249                        end_byte_offset = self.first_frame_offset + upper.byte_offset;
250                    }
251                    // Search the entire stream (default behaviour, so do nothing).
252                    SeekSearchResult::Stream => (),
253                }
254            }
255
256            // Binary search the range of bytes formed by start_by_offset..end_byte_offset for the
257            // desired frame timestamp. When the difference of the range reaches 2x the maximum
258            // frame size, exit the loop and search from the start_byte_offset linearly. The binary
259            // search becomes inefficient when the range is small.
260            while end_byte_offset - start_byte_offset > 2 * 8096 {
261                let mid_byte_offset = (start_byte_offset + end_byte_offset) / 2;
262                self.reader.seek(SeekFrom::Start(mid_byte_offset))?;
263
264                let sync = self.parser.resync(&mut self.reader)?;
265
266                if ts < sync.ts {
267                    end_byte_offset = mid_byte_offset;
268                }
269                else if ts >= sync.ts && ts < sync.ts + sync.dur {
270                    debug!("seeked to ts={} (delta={})", sync.ts, sync.ts as i64 - ts as i64);
271
272                    return Ok(SeekedTo { track_id: 0, actual_ts: sync.ts, required_ts: ts });
273                }
274                else {
275                    start_byte_offset = mid_byte_offset;
276                }
277            }
278
279            // The binary search did not find an exact frame, but the range has been narrowed. Seek
280            // to the start of the range, and continue with a linear search.
281            self.reader.seek(SeekFrom::Start(start_byte_offset))?;
282        }
283
284        // Linearly search the stream packet-by-packet for the packet that contains the desired
285        // timestamp. This search is used to find the exact packet containing the desired timestamp
286        // after the search range was narrowed by the binary search. It is also the ONLY way for a
287        // unseekable stream to be "seeked" forward.
288        let packet = loop {
289            let sync = self.parser.resync(&mut self.reader)?;
290
291            // The desired timestamp precedes the current packet's timestamp.
292            if ts < sync.ts {
293                // Attempted to seek backwards on an unseekable stream.
294                if !self.reader.is_seekable() {
295                    return seek_error(SeekErrorKind::ForwardOnly);
296                }
297                // Overshot a regular seek, or the stream is corrupted, not necessarily an error
298                // per-say.
299                else {
300                    break sync;
301                }
302            }
303            // The desired timestamp is contained within the current packet.
304            else if ts >= sync.ts && ts < sync.ts + sync.dur {
305                break sync;
306            }
307
308            // Advance the reader such that the next iteration will sync to a different frame.
309            self.reader.read_byte()?;
310        };
311
312        debug!("seeked to packet_ts={} (delta={})", packet.ts, packet.ts as i64 - ts as i64);
313
314        Ok(SeekedTo { track_id: 0, actual_ts: packet.ts, required_ts: ts })
315    }
316
317    fn into_inner(self: Box<Self>) -> MediaSourceStream {
318        self.reader
319    }
320}
321
322/// Reads a StreamInfo block and populates the reader with stream information.
323fn read_stream_info_block<B: ReadBytes + FiniteStream>(
324    reader: &mut B,
325    tracks: &mut Vec<Track>,
326    parser: &mut PacketParser,
327) -> Result<()> {
328    // Only one StreamInfo block, and therefore only one Track, is allowed per media source stream.
329    if tracks.is_empty() {
330        // Ensure the block length is correct for a stream information block before allocating a
331        // buffer for it.
332        if !StreamInfo::is_valid_size(reader.byte_len()) {
333            return decode_error("flac: invalid stream info block size");
334        }
335
336        // Read the stream information block as a boxed slice so that it may be attached as extra
337        // data on the codec parameters.
338        let extra_data = reader.read_boxed_slice_exact(reader.byte_len() as usize)?;
339
340        // Parse the stream info block.
341        let info = StreamInfo::read(&mut BufReader::new(&extra_data))?;
342
343        // Populate the codec parameters with the basic audio parameters of the track.
344        let mut codec_params = CodecParameters::new();
345
346        codec_params
347            .for_codec(CODEC_TYPE_FLAC)
348            .with_packet_data_integrity(true)
349            .with_extra_data(extra_data)
350            .with_sample_rate(info.sample_rate)
351            .with_time_base(TimeBase::new(1, info.sample_rate))
352            .with_bits_per_sample(info.bits_per_sample)
353            .with_channels(info.channels);
354
355        if let Some(md5) = info.md5 {
356            codec_params.with_verification_code(VerificationCheck::Md5(md5));
357        }
358
359        // Total samples per channel (the total number of frames) is optional.
360        if let Some(n_frames) = info.n_samples {
361            codec_params.with_n_frames(n_frames);
362        }
363
364        // Reset the packet parser.
365        parser.reset(info);
366
367        // Add the track.
368        tracks.push(Track::new(0, codec_params));
369    }
370    else {
371        return decode_error("flac: found more than one stream info block");
372    }
373
374    Ok(())
375}