X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-llaudio%2Fsrc%2Fdemuxers%2Fflac.rs;h=215a1e9527c00508b48802ef71466d9f31953278;hb=6bd5b458d9889f092abe9b582bd531ed08a8dc51;hp=3d6bca2c49b74ca7967d78b5feda444a9072c2d2;hpb=1fb2da784666ce932a2a59e55f0ba8f1cba2e841;p=nihav.git diff --git a/nihav-llaudio/src/demuxers/flac.rs b/nihav-llaudio/src/demuxers/flac.rs index 3d6bca2..215a1e9 100644 --- a/nihav-llaudio/src/demuxers/flac.rs +++ b/nihav-llaudio/src/demuxers/flac.rs @@ -21,6 +21,17 @@ struct FLACDemuxer<'a> { srate: u32, known_frames: Vec, build_index: bool, + frame_hdr: u32, +} + +fn common_header_word(mut val: u32) -> u32 { + val &= !0x1F000; // blocking strategy and block size + let ch_map = (val >> 4) & 0xF; + if matches!(ch_map, 0x1 | 0x8 | 0x9 | 0xA) { // stereo coding modes + val &= !0xF0; + val |= 0x10; + } + val } impl<'a> FLACDemuxer<'a> { @@ -37,6 +48,7 @@ impl<'a> FLACDemuxer<'a> { srate: 0, known_frames: Vec::new(), build_index: false, + frame_hdr: 0, } } fn read_frame(&mut self) -> DemuxerResult<(Vec, u64, u64)> { @@ -49,6 +61,9 @@ impl<'a> FLACDemuxer<'a> { buf.push(byte); crc = update_crc16(crc, byte); } + if self.frame_hdr == 0 { + self.frame_hdr = read_u32be(&buf).unwrap_or(0); + } let mut ref_crc = self.src.read_u16be()?; loop { let byte = self.src.read_byte()?; @@ -56,9 +71,9 @@ impl<'a> FLACDemuxer<'a> { 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) { + if buf.len() + 4 >= self.min_size && crc == ref_crc { + let ret = self.src.peek_u32be(); + if ret.is_err() || (common_header_word(ret.unwrap_or(0)) == common_header_word(self.frame_hdr)) { buf.push((ref_crc >> 8) as u8); buf.push(ref_crc as u8); break; @@ -78,9 +93,31 @@ impl<'a> FLACDemuxer<'a> { 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 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 }; @@ -177,7 +214,7 @@ impl<'a> DemuxCore<'a> for FLACDemuxer<'a> { 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(()) } @@ -185,8 +222,7 @@ impl<'a> DemuxCore<'a> for FLACDemuxer<'a> { 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 ts = stream.make_ts(Some(pts), None, Some(duration)); let pkt = NAPacket::new(stream, ts, true, buf); Ok(pkt) @@ -202,7 +238,7 @@ impl<'a> DemuxCore<'a> for FLACDemuxer<'a> { 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, self.srate, 1); + 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 { @@ -239,6 +275,7 @@ impl<'a> DemuxCore<'a> for FLACDemuxer<'a> { Err(DemuxerError::NotPossible) } } + fn get_duration(&self) -> u64 { self.tot_samples * 1000 / u64::from(self.srate) } } impl<'a> NAOptionHandler for FLACDemuxer<'a> { @@ -263,6 +300,7 @@ mod test { #[test] fn test_flac_demux() { + // sample: https://samples.mplayerhq.hu/A-codecs/lossless/luckynight.flac let mut file = File::open("assets/LLaudio/luckynight.flac").unwrap(); let mut fr = FileReader::new_read(&mut file); let mut br = ByteReader::new(&mut fr);