1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
// Symphonia
// Copyright (c) 2020 The Project Symphonia Developers.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::io::{Seek, SeekFrom};

use symphonia_core::support_format;

use symphonia_core::codecs::{CODEC_TYPE_FLAC, CodecParameters};
use symphonia_core::errors::{Result, decode_error, seek_error, unsupported_error, SeekErrorKind};
use symphonia_core::formats::prelude::*;
use symphonia_core::formats::util::{SeekIndex, SeekSearchResult};
use symphonia_core::io::*;
use symphonia_core::meta::{MetadataQueue, MetadataBuilder};
use symphonia_core::probe::{Descriptor, Instantiate, QueryDescriptor};

use symphonia_utils_xiph::flac::metadata::*;

use log::{debug, info};

use super::frame::*;
use super::parser::PacketParser;

/// The FLAC start of stream marker: "fLaC" in ASCII.
const FLAC_STREAM_MARKER: [u8; 4] = *b"fLaC";

/// `Free Lossless Audio Codec (FLAC) native frame reader.
pub struct FlacReader {
    reader: MediaSourceStream,
    metadata: MetadataQueue,
    streams: Vec<Stream>,
    cues: Vec<Cue>,
    index: Option<SeekIndex>,
    first_frame_offset: u64,
    parser: PacketParser,
}

impl QueryDescriptor for FlacReader {
    fn query() -> &'static [Descriptor] {
        &[
            support_format!(
                "flac",
                "Free Lossless Audio Codec Native",
                &[ "flac" ],
                &[ "audio/flac" ],
                &[ b"fLaC" ]
            ),
        ]
    }

    fn score(_context: &[u8]) -> u8 {
        255
    }
}

impl FormatReader for FlacReader {

    fn try_new(mut source: MediaSourceStream, _options: &FormatOptions) -> Result<Self> {
        // Read the first 4 bytes of the stream. Ideally this will be the FLAC stream marker.
        let marker = source.read_quad_bytes()?;

        if marker != FLAC_STREAM_MARKER {
            return unsupported_error("missing flac stream marker");
        }

        let mut flac = FlacReader {
            reader: source,
            streams: Vec::new(),
            cues: Vec::new(),
            metadata: Default::default(),
            index: None,
            first_frame_offset: 0,
            parser: Default::default(),
        };

        // Strictly speaking, the first metadata block must be a StreamInfo block. There is
        // no technical need for this from the reader's point of view. Additionally, if the
        // reader is fed a stream mid-way there is no StreamInfo block. Therefore, just read
        // all metadata blocks and handle the StreamInfo block as it comes.
        read_all_metadata_blocks(&mut flac)?;

        // Make sure that there is atleast one StreamInfo block.
        if flac.streams.is_empty() {
            return decode_error("no stream info block");
        }

        // The first frame offset is the byte offset from the beginning of the stream after all the
        // metadata blocks have been read.
        flac.first_frame_offset = flac.reader.pos();

        Ok(flac)
    }

    fn next_packet(&mut self) -> Result<Packet> {
        let data = self.parser.parse(&mut self.reader)?;
        Ok(Packet::new_from_boxed_slice(0, 0, 0, data))
    }

    fn metadata(&self) -> &MetadataQueue {
        &self.metadata
    }

    fn cues(&self) -> &[Cue] {
        &self.cues
    }

    fn streams(&self) -> &[Stream] {
        &self.streams
    }

    fn seek(&mut self, to: SeekTo) -> Result<SeekedTo> {
        if self.streams.is_empty() {
            return seek_error(SeekErrorKind::Unseekable);
        }

        let params = &self.streams[0].codec_params;

        // Get the timestamp of the desired audio frame.
        let ts = match to {
            // Frame timestamp given.
            SeekTo::TimeStamp { ts, .. } => ts,
            // Time value given, calculate frame timestamp from sample rate.
            SeekTo::Time { time } => {
                // Use the sample rate to calculate the frame timestamp. If sample rate is not
                // known, the seek cannot be completed.
                if let Some(sample_rate) = params.sample_rate {
                    TimeBase::new(1, sample_rate).calc_timestamp(time)
                }
                else {
                    return seek_error(SeekErrorKind::Unseekable);
                }
            }
        };

        debug!("seeking to frame_ts={}", ts);

        // If the total number of frames in the stream is known, verify the desired frame timestamp
        // does not exceed it.
        if let Some(n_frames) = params.n_frames {
            if ts > n_frames {
                return seek_error(SeekErrorKind::OutOfRange);
            }
        }

        // If the reader supports seeking, coarsely seek to the nearest packet with a timestamp
        // lower than the desired timestamp using a binary search.
        if self.reader.is_seekable() {
            // The range formed by start_byte_offset..end_byte_offset defines an area where the
            // binary search for the packet containing the desired timestamp will be performed. The
            // lower bound is set to the byte offset of the first frame, while the upper bound is
            // set to the length of the stream.
            let mut start_byte_offset = self.first_frame_offset;
            let mut end_byte_offset = self.reader.seek(SeekFrom::End(0))?;

            // If there is an index, use it to refine the binary search range.
            if let Some(ref index) = self.index {
                // Search the index for the timestamp. Adjust the search based on the result.
                match index.search(ts) {
                    // Search from the start of stream up-to an ending point.
                    SeekSearchResult::Upper(upper) => {
                        end_byte_offset = self.first_frame_offset + upper.byte_offset;
                    },
                    // Search from a starting point up-to the end of the stream.
                    SeekSearchResult::Lower(lower) => {
                        start_byte_offset = self.first_frame_offset + lower.byte_offset;
                    },
                    // Search between two points of the stream.
                    SeekSearchResult::Range(lower, upper) => {
                        start_byte_offset = self.first_frame_offset + lower.byte_offset;
                        end_byte_offset = self.first_frame_offset + upper.byte_offset;
                    },
                    // Search the entire stream (default behaviour, so do nothing).
                    SeekSearchResult::Stream => (),
                }
            }

            // Binary search the range of bytes formed by start_by_offset..end_byte_offset for the
            // desired frame timestamp. When the difference of the range reaches 2x the maximum
            // frame size, exit the loop and search from the start_byte_offset linearly. The binary
            // search becomes inefficient when the range is small.
            while end_byte_offset - start_byte_offset > 2 * 8096 {
                let mid_byte_offset = (start_byte_offset + end_byte_offset) / 2;
                self.reader.seek(SeekFrom::Start(mid_byte_offset))?;

                let packet = next_frame(&mut self.reader)?;

                if ts < packet.packet_ts {
                    end_byte_offset = mid_byte_offset;
                }
                else if ts > packet.packet_ts
                    && ts < (packet.packet_ts + u64::from(packet.n_frames))
                {
                    // Rewind the stream back to the beginning of the frame.
                    self.reader.rewind(packet.parsed_len);

                    debug!("seeked to packet_ts={} (delta={})",
                        packet.packet_ts, packet.packet_ts as i64 - ts as i64);

                    return Ok(SeekedTo::TimeStamp{ ts: packet.packet_ts, stream: 0 });
                }
                else {
                    start_byte_offset = mid_byte_offset;
                }
            }

            // The binary search did not find an exact frame, but the range has been narrowed. Seek
            // to the start of the range, and continue with a linear search.
            self.reader.seek(SeekFrom::Start(start_byte_offset))?;
        }

        // Linearly search the stream packet-by-packet for the packet that contains the desired
        // timestamp. This search is used to find the exact packet containing the desired timestamp
        // after the search range was narrowed by the binary search. It is also the ONLY way for a
        // unseekable stream to be "seeked" forward.
        loop {
            let packet = next_frame(&mut self.reader)?;

            // The desired timestamp preceeds the current packet's timestamp.
            if ts < packet.packet_ts {
                // Rewind the stream back to the beginning of the frame.
                self.reader.rewind(packet.parsed_len);

                // Attempted to seek backwards on an unseekable stream.
                if !self.reader.is_seekable() {
                    return seek_error(SeekErrorKind::ForwardOnly);
                }
                // Overshot a regular seek, or the stream is corrupted, not necessarily an error
                // per-say.
                else {
                    debug!("seeked to packet_ts={} (delta={})",
                        packet.packet_ts, packet.packet_ts as i64 - ts as i64);

                    return Ok(SeekedTo::TimeStamp{ ts: packet.packet_ts, stream: 0 });
                }
            }
            // The desired timestamp is contained within the current packet.
            else if ts >= packet.packet_ts
                && ts < (packet.packet_ts + u64::from(packet.n_frames))
            {
                // Rewind the stream back to the beginning of the frame.
                self.reader.rewind(packet.parsed_len);

                debug!("seeked to packet_ts={} (delta={})",
                    packet.packet_ts, packet.packet_ts as i64 - ts as i64);

                return Ok(SeekedTo::TimeStamp{ ts: packet.packet_ts, stream: 0 });
            }
        }
    }

}

/// Reads a StreamInfo block and populates the reader with stream information.
fn read_stream_info_block<B : ByteStream>(
    block_stream: &mut B,
    streams: &mut Vec<Stream>,
    parser: &mut PacketParser,
) -> Result<()> {
    // Only one StreamInfo block, and therefore ony one Stream, is allowed per media source stream.
    if streams.is_empty() {
        let info = StreamInfo::read(block_stream)?;

        info!("stream md5 = {:x?}", info.md5);

        // Populate the codec parameters with the parameters from the stream information block.
        let mut codec_params = CodecParameters::new();

        codec_params
            .for_codec(CODEC_TYPE_FLAC)
            .with_sample_rate(info.sample_rate)
            .with_bits_per_sample(info.bits_per_sample)
            .with_max_frames_per_packet(u64::from(info.block_len_max))
            .with_channels(info.channels)
            .with_packet_data_integrity(true);

        // Total samples (per channel) aka frames may or may not be stated in StreamInfo.
        if let Some(n_frames) = info.n_samples {
            codec_params.with_n_frames(n_frames);
        }

        // Reset the packet parser.
        parser.reset(info);

        // Add the stream.
        streams.push(Stream::new(0, codec_params));
    }
    else {
        return decode_error("found more than one stream info block");
    }

    Ok(())
}

/// Reads all the metadata blocks.
fn read_all_metadata_blocks(flac: &mut FlacReader) -> Result<()> {
    let mut metadata_builder = MetadataBuilder::new();

    loop {
        let header = MetadataBlockHeader::read(&mut flac.reader)?;

        // Create a scoped bytestream to error if the metadata block read functions exceed the
        // stated length of the block.
        let mut block_stream = ScopedStream::new(&mut flac.reader, u64::from(header.block_len));

        match header.block_type {
            MetadataBlockType::Application => {
                // TODO: Store vendor data.
                read_application_block(&mut block_stream, header.block_len)?;
            },
            // SeekTable blocks are parsed into a SeekIndex.
            MetadataBlockType::SeekTable => {
                // Check if a SeekTable has already be parsed. If one has, then the file is
                // invalid, atleast for seeking. Either way, it's a violation of the
                // specification.
                if flac.index.is_none() {
                    let mut index = SeekIndex::new();
                    read_seek_table_block(&mut block_stream, header.block_len, &mut index)?;
                    flac.index = Some(index);
                }
                else {
                    return decode_error("found more than one seek table block");
                }
            },
            // VorbisComment blocks are parsed into Tags.
            MetadataBlockType::VorbisComment => {
                read_comment_block(&mut block_stream, &mut metadata_builder)?;
            },
            // Cuesheet blocks are parsed into Cues.
            MetadataBlockType::Cuesheet => {
                read_cuesheet_block(&mut block_stream, &mut flac.cues)?;
            },
            // Picture blocks are read as Visuals.
            MetadataBlockType::Picture => {
                read_picture_block(&mut block_stream, &mut metadata_builder)?;
            },
            // StreamInfo blocks are parsed into Streams.
            MetadataBlockType::StreamInfo => {
                read_stream_info_block(&mut block_stream, &mut flac.streams, &mut flac.parser)?;
            },
            // Padding blocks are skipped.
            MetadataBlockType::Padding => {
                block_stream.ignore_bytes(u64::from(header.block_len))?;
            },
            // Unknown block encountered. Skip these blocks as they may be part of a future
            // version of FLAC, but  print a message.
            MetadataBlockType::Unknown(id) => {
                block_stream.ignore_bytes(u64::from(header.block_len))?;
                info!("ignoring {} bytes of block width id={}.", header.block_len, id);
            }
        }

        // If the stated block length is longer than the number of bytes from the block read,
        // ignore the remaining unread data.
        let block_unread_len = block_stream.bytes_available();

        if block_unread_len > 0 {
            info!("under read block by {} bytes.", block_unread_len);
            block_stream.ignore_bytes(block_unread_len)?;
        }

        // Exit when the last header is read.
        if header.is_last {
            break;
        }
    }

    // Commit any read metadata to the metadata queue.
    flac.metadata.push(metadata_builder.metadata());

    Ok(())
}