X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-llaudio%2Fsrc%2Fdemuxers%2Fflac.rs;h=83208c406cf9034446bf36c9d12364c0c891ddf3;hp=f19ce5639e6a9a6a6fd3029e2b9d05cc0489df56;hb=cc0a023d906149db2f406d5596cd400e6a118ce2;hpb=87927c5732b39bb23209486bed8d7bb7fc56b92e diff --git a/nihav-llaudio/src/demuxers/flac.rs b/nihav-llaudio/src/demuxers/flac.rs index f19ce56..83208c4 100644 --- a/nihav-llaudio/src/demuxers/flac.rs +++ b/nihav-llaudio/src/demuxers/flac.rs @@ -1,14 +1,26 @@ use nihav_core::frame::*; use nihav_core::demuxers::*; +#[derive(Clone,Copy,Default)] +struct FrameSeekInfo { + off: u64, + size: u64, + samplepos: u64, + sampleend: u64, +} + struct FLACDemuxer<'a> { src: &'a mut ByteReader<'a>, data_start: u64, tot_samples: u64, cur_samples: u64, blk_samples: u16, + min_samples: u16, min_size: usize, max_size: usize, + srate: u32, + known_frames: Vec, + build_index: bool, } impl<'a> FLACDemuxer<'a> { @@ -19,9 +31,89 @@ impl<'a> FLACDemuxer<'a> { tot_samples: 0, cur_samples: 0, blk_samples: 0, + min_samples: 0, min_size: 0, max_size: 0, + srate: 0, + known_frames: Vec::new(), + build_index: false, + } + } + fn read_frame(&mut self) -> DemuxerResult<(Vec, u64, u64)> { + if self.src.is_eof() || (self.tot_samples != 0 && self.cur_samples == self.tot_samples) { return Err(DemuxerError::EOF); } + let mut buf = Vec::with_capacity(self.min_size); + let mut crc = 0; + let frame_start = self.src.tell(); + for _ in 0..5 { + let byte = self.src.read_byte()?; + buf.push(byte); + crc = update_crc16(crc, byte); + } + let mut ref_crc = self.src.read_u16be()?; + loop { + let byte = self.src.read_byte()?; + let old_byte = (ref_crc >> 8) as u8; + buf.push(old_byte); + ref_crc = (ref_crc << 8) | u16::from(byte); + crc = update_crc16(crc, old_byte); + if buf.len() + 2 >= self.min_size && crc == ref_crc { + let ret = self.src.peek_u16be(); + if ret.is_err() || ((ret.unwrap_or(0) & 0xFFFE) == 0xFFF8) { + buf.push((ref_crc >> 8) as u8); + buf.push(ref_crc as u8); + break; + } + } + if (self.max_size > 0) && (buf.len() > self.max_size) { + return Err(DemuxerError::InvalidData); + } + if buf.len() > (1 << 23) { + return Err(DemuxerError::InvalidData); + } + } + + let (duration, pts) = if self.blk_samples != 0 { + validate!((buf[1] & 1) == 0); + let blkno = u64::from(read_utf8(&buf[4..])?); + self.cur_samples = blkno * u64::from(self.blk_samples); + (u64::from(self.blk_samples), blkno) + } else { + let mut idx = 5; + while idx < buf.len() && (buf[idx] & 0x80) != 0 { + idx += 1; + } + + let bsz_id = buf[2] >> 4; + let blksamps = match bsz_id { + 0 => return Err(DemuxerError::InvalidData), + 1 => 192, + 2..=5 => 576 << (bsz_id - 2), + 6 => { + validate!(idx < buf.len()); + u64::from(buf[idx]) + 1 + }, + 7 => { + validate!(idx + 2 <= buf.len()); + u64::from(buf[idx]) * 256 + u64::from(buf[idx + 1]) + 1 + }, + _ => 256 << (bsz_id - 8), + }; + let pts = u64::from(read_utf8(&buf[4..])?); + + validate!(idx < buf.len()); + + (blksamps, pts) + }; + + let spos = if self.blk_samples != 0 { pts * u64::from(self.blk_samples) } else { pts }; + if self.build_index && (self.known_frames.is_empty() || self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos < spos) { + let sampleend = spos + duration; + self.known_frames.push(FrameSeekInfo{off: frame_start, size: buf.len() as u64, samplepos: spos, sampleend }); } + + self.cur_samples += duration; + + Ok((buf, pts, duration)) } } @@ -65,6 +157,7 @@ impl<'a> DemuxCore<'a> for FLACDemuxer<'a> { if min_bs == max_bs { self.blk_samples = max_bs; } + self.min_samples = min_bs; self.min_size = read_u24be(&streaminfo[4..])? as usize; self.max_size = read_u24be(&streaminfo[7..])? as usize; let word = read_u24be(&streaminfo[10..])?; @@ -90,79 +183,85 @@ impl<'a> DemuxCore<'a> for FLACDemuxer<'a> { break; } } + if seek_index.mode != SeekIndexMode::Present { + let min_size = if self.min_samples != 0 { self.min_samples } else { 2048 }; + let nframes = self.tot_samples as usize / (min_size as usize); + self.known_frames = Vec::with_capacity(nframes.max(1)); + seek_index.mode = SeekIndexMode::Automatic; + self.build_index = true; + } else { + self.build_index = false; + } self.data_start = self.src.tell(); validate!(srate != 0); + self.srate = srate; let base = if self.blk_samples != 0 { u32::from(self.blk_samples) } else { 1 }; let ahdr = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, base as usize); let ainfo = NACodecInfo::new("flac", NACodecTypeInfo::Audio(ahdr), Some(streaminfo)); - strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, base, srate)).unwrap(); + strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, base, srate, 0)).unwrap(); Ok(()) } fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult { - if self.src.is_eof() || (self.tot_samples != 0 && self.cur_samples == self.tot_samples) { return Err(DemuxerError::EOF); } - let mut buf = Vec::with_capacity(self.min_size); - let mut crc = 0; - for _ in 0..5 { - let byte = self.src.read_byte()?; - buf.push(byte); - crc = update_crc16(crc, byte); - } - let mut ref_crc = self.src.read_u16be()?; - loop { - let byte = self.src.read_byte()?; - let old_byte = (ref_crc >> 8) as u8; - buf.push(old_byte); - ref_crc = (ref_crc << 8) | u16::from(byte); - crc = update_crc16(crc, old_byte); - if buf.len() + 2 >= self.min_size && crc == ref_crc { - let ret = self.src.peek_u16be(); - if ret.is_err() || ((ret.unwrap_or(0) & 0xFFFE) == 0xFFF8) { - buf.push((ref_crc >> 8) as u8); - buf.push(ref_crc as u8); - break; - } - } - if (self.max_size > 0) && (buf.len() > self.max_size) { - return Err(DemuxerError::InvalidData); - } - if buf.len() > (1 << 23) { - return Err(DemuxerError::InvalidData); - } - } - - let (duration, pts) = if self.blk_samples != 0 { - validate!((buf[1] & 1) == 0); - let blkno = u64::from(read_utf8(&buf[4..])?); - self.cur_samples = blkno * u64::from(self.blk_samples); - (u64::from(self.blk_samples), blkno) - } else { - validate!((buf[1] & 1) != 0); - let blksamps = u64::from(read_utf8(&buf[4..])?); - (blksamps, self.cur_samples) - }; + let (buf, pts, duration) = self.read_frame()?; let stream = strmgr.get_stream(0).unwrap(); let (tb_num, tb_den) = stream.get_timebase(); let ts = NATimeInfo::new(Some(pts), None, Some(duration), tb_num, tb_den); let pkt = NAPacket::new(stream, ts, true, buf); - self.cur_samples += duration; - Ok(pkt) } fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> { - let ret = seek_index.find_pos(time); - if ret.is_none() { - return Err(DemuxerError::SeekError); - } - let seek_info = ret.unwrap(); - self.cur_samples = seek_info.pts; - self.src.seek(SeekFrom::Start(self.data_start + seek_info.pos))?; + if seek_index.mode == SeekIndexMode::Present { + let ret = seek_index.find_pos(time); + if ret.is_none() { + return Err(DemuxerError::SeekError); + } + let seek_info = ret.unwrap(); + self.cur_samples = seek_info.pts; + self.src.seek(SeekFrom::Start(self.data_start + seek_info.pos))?; + Ok(()) + } else if let NATimePoint::Milliseconds(ms) = time { + let samppos = NATimeInfo::time_to_ts(ms, 1000, 1, self.srate); + if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).sampleend >= samppos { + for point in self.known_frames.iter().rev() { + if point.samplepos <= samppos { + self.src.seek(SeekFrom::Start(point.off))?; + self.cur_samples = point.samplepos; + return Ok(()); + } + } + } else { + let startinfo = FrameSeekInfo { off: self.data_start, size: 0, samplepos: 0, sampleend: 0 }; + let lentry = self.known_frames.last().unwrap_or(&startinfo); - Ok(()) + self.src.seek(SeekFrom::Start(lentry.off + lentry.size))?; + self.cur_samples = lentry.sampleend; + loop { + let frame_start = self.src.tell(); + let ret = self.read_frame(); + if ret.is_err() { + return Err(DemuxerError::SeekError); + } + let (_, pts, duration) = ret.unwrap(); + self.cur_samples = pts; + if self.blk_samples != 0 { + self.cur_samples *= u64::from(self.blk_samples); + } + if self.cur_samples <= samppos && self.cur_samples + duration >= samppos { + self.src.seek(SeekFrom::Start(frame_start))?; + return Ok(()); + } + } + } + Err(DemuxerError::SeekError) + } else { + Err(DemuxerError::NotPossible) + } } + fn get_duration(&self) -> u64 { self.tot_samples * 1000 / u64::from(self.srate) } } impl<'a> NAOptionHandler for FLACDemuxer<'a> {