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}