use std::io::{Read, Seek, SeekFrom}; use crate::{ FlacBlock, FlacDecodeError, blocks::{FlacAudioFrame, FlacMetablockHeader, FlacMetablockType}, }; // TODO: quickly skip blocks we do not need /// The next block we expect to read enum ReaderState { MagicBits, MetablockHeader { is_first: bool }, MetaBlock { header: FlacMetablockHeader }, AudioData, Done, } pub struct FlacReader { inner: R, state: ReaderState, } impl FlacReader { const MIN_AUDIO_FRAME_LEN: usize = 5000; pub fn new(inner: R) -> Self { Self { inner, state: ReaderState::MagicBits, } } } impl Iterator for FlacReader { type Item = Result; fn next(&mut self) -> Option { loop { match &mut self.state { ReaderState::Done => return None, ReaderState::MagicBits => { let mut data = [0u8; 4]; if let Err(e) = self.inner.read_exact(&mut data[..4]) { self.state = ReaderState::Done; return Some(Err(e.into())); } if data != [0x66, 0x4C, 0x61, 0x43] { self.state = ReaderState::Done; return Some(Err(FlacDecodeError::BadMagicBytes)); } self.state = ReaderState::MetablockHeader { is_first: true }; } ReaderState::MetablockHeader { is_first } => { let mut data = [0u8; 4]; if let Err(e) = self.inner.read_exact(&mut data[..]) { self.state = ReaderState::Done; return Some(Err(e.into())); } let header = match FlacMetablockHeader::decode(&data) { Ok(h) => h, Err(e) => { self.state = ReaderState::Done; return Some(Err(e)); } }; if *is_first && !matches!(header.block_type, FlacMetablockType::Streaminfo) { self.state = ReaderState::Done; return Some(Err(FlacDecodeError::BadFirstBlock)); } self.state = ReaderState::MetaBlock { header }; } ReaderState::MetaBlock { header } => { let mut data = vec![0u8; header.length as usize]; if let Err(e) = self.inner.read_exact(&mut data) { self.state = ReaderState::Done; return Some(Err(e.into())); } let block = match FlacBlock::decode(header.block_type, &data) { Ok(b) => b, Err(e) => { self.state = ReaderState::Done; return Some(Err(e)); } }; if header.is_last { self.state = ReaderState::AudioData; } else { self.state = ReaderState::MetablockHeader { is_first: false }; } return Some(Ok(block)); } ReaderState::AudioData => { let mut data = Vec::new(); loop { let mut byte = [0u8; 1]; match self.inner.read_exact(&mut byte) { Ok(_) => { data.push(byte[0]); if data.len() >= Self::MIN_AUDIO_FRAME_LEN + 2 { let len = data.len(); if data[len - 2] == 0b1111_1111 && data[len - 1] & 0b1111_1100 == 0b1111_1000 { let frame_data = data[..len - 2].to_vec(); if frame_data.len() < 2 || frame_data[0] != 0b1111_1111 || frame_data[1] & 0b1111_1100 != 0b1111_1000 { self.state = ReaderState::Done; return Some(Err(FlacDecodeError::BadSyncBytes)); } let audio_frame = match FlacAudioFrame::decode(&frame_data) { Ok(f) => f, Err(e) => { self.state = ReaderState::Done; return Some(Err(e)); } }; // Seek back 2 bytes so the next frame starts with the sync bytes if let Err(e) = self.inner.seek(SeekFrom::Current(-2)) { self.state = ReaderState::Done; return Some(Err(e.into())); } self.state = ReaderState::AudioData; return Some(Ok(FlacBlock::AudioFrame(audio_frame))); } } } Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => { if data.len() > 2 { if data[0] != 0b1111_1111 || data[1] & 0b1111_1100 != 0b1111_1000 { self.state = ReaderState::Done; return Some(Err(FlacDecodeError::BadSyncBytes)); } let audio_frame = match FlacAudioFrame::decode(&data) { Ok(f) => f, Err(e) => { self.state = ReaderState::Done; return Some(Err(e)); } }; self.state = ReaderState::Done; return Some(Ok(FlacBlock::AudioFrame(audio_frame))); } else { self.state = ReaderState::Done; return None; } } Err(e) => { self.state = ReaderState::Done; return Some(Err(e.into())); } } } } } } } }