X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-llaudio%2Fsrc%2Fdemuxers%2Fflacraw.rs;fp=nihav-llaudio%2Fsrc%2Fdemuxers%2Fflacraw.rs;h=d86d14e1eb3efb6c7901a1c1ecc174c7e49786d0;hp=0000000000000000000000000000000000000000;hb=2cd9d8a600ef475711646fea5a3617e030440068;hpb=051abe1fcd6b3ad59c2a2d11f2dd48bb880b7743 diff --git a/nihav-llaudio/src/demuxers/flacraw.rs b/nihav-llaudio/src/demuxers/flacraw.rs new file mode 100644 index 0000000..d86d14e --- /dev/null +++ b/nihav-llaudio/src/demuxers/flacraw.rs @@ -0,0 +1,183 @@ +use nihav_core::frame::*; +use nihav_core::demuxers::*; + +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, + build_index: bool, +} + +impl<'a> FLACDemuxer<'a> { + fn new(io: &'a mut ByteReader<'a>) -> Self { + Self { + src: io, + data_start: 0, + tot_samples: 0, + cur_samples: 0, + blk_samples: 0, + min_samples: 0, + min_size: 0, + max_size: 0, + srate: 0, + build_index: false, + } + } +} + +impl<'a> RawDemuxCore<'a> for FLACDemuxer<'a> { + fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> { + let tag = self.src.read_tag()?; + validate!(&tag == b"fLaC"); + let mut streaminfo: Vec = Vec::new(); + let mut srate = 0u32; + let mut channels = 0u8; + loop { + let id1 = self.src.read_byte()?; + let len = self.src.read_u24be()? as usize; + let id = id1 & 0x7F; + + match id { + 0x00 => { + validate!(len >= 34); + streaminfo = vec![0u8; len]; + self.src.read_buf(&mut streaminfo)?; + let min_bs = read_u16be(&streaminfo[0..])?; + let max_bs = read_u16be(&streaminfo[2..])?; + 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..])?; + srate = word >> 4; + channels = (((word >> 1) & 7) + 1) as u8; + self.tot_samples = (u64::from(streaminfo[13] & 0xF) << 32) | u64::from(read_u32be(&streaminfo[14..])?); + }, + 0x03 => { + validate!((len % 18) == 0); + seek_index.mode = SeekIndexMode::Present; + for _ in 0..len / 18 { + let sample = self.src.read_u64be()?; + let offset = self.src.read_u64be()?; + let _nsamps = self.src.read_u16be()?; + let time = sample * 1000 / u64::from(srate.max(1000)); + seek_index.add_entry(0, SeekEntry { time, pts: sample, pos: offset }); + } + }, + _ => self.src.read_skip(len)?, + }; + + if (id1 & 0x80) != 0 { + break; + } + } + if seek_index.mode != SeekIndexMode::Present { + 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, 0)).unwrap(); + + Ok(()) + } + fn get_data(&mut self, strmgr: &mut StreamManager) -> DemuxerResult { + let stream = strmgr.get_stream(0).unwrap(); + let mut buf = vec![0; 8192]; + let size = self.src.read_buf_some(&mut buf)?; + buf.truncate(size); + Ok(NARawData::new(stream, buf)) + } + fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> { + 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 { + Err(DemuxerError::NotPossible) + } + } + fn get_duration(&self) -> u64 { self.tot_samples * 1000 / u64::from(self.srate) } +} + +impl<'a> NAOptionHandler for FLACDemuxer<'a> { + fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } + fn set_options(&mut self, _options: &[NAOption]) { } + fn query_option_value(&self, _name: &str) -> Option { None } +} + +pub struct FLACDemuxerCreator { } + +impl RawDemuxerCreator for FLACDemuxerCreator { + fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box + 'a> { + Box::new(FLACDemuxer::new(br)) + } + fn get_name(&self) -> &'static str { "flac" } + fn check_format(&self, br: &mut ByteReader) -> bool { + if br.seek(SeekFrom::Start(0)).is_err() { + return false; + } + if let Ok([b'f', b'L', b'a', b'C']) = br.read_tag() { + true + } else { + false + } + } +} + +#[cfg(test)] +mod test { + use nihav_core::codecs::*; + use super::*; + use crate::llaudio_register_all_packetisers; + use std::fs::File; + + #[test] + fn test_flac_raw_demux() { + 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); + let mut dmx = FLACDemuxer::new(&mut br); + let mut sm = StreamManager::new(); + let mut si = SeekIndex::new(); + dmx.open(&mut sm, &mut si).unwrap(); + let stream = sm.get_stream(0).unwrap(); + let mut pkt_reg = RegisteredPacketisers::new(); + llaudio_register_all_packetisers(&mut pkt_reg); + let creator = pkt_reg.find_packetiser("flac").unwrap(); + let mut pkts = (creator)(); + let mut tot_size = 0; + while let Ok(pkt) = dmx.get_data(&mut sm) { + tot_size += pkt.get_buffer().len(); + pkts.add_data(&pkt.get_buffer()); + } + let mut tot_size2 = 0; + let mut npkts = 0; + while let Ok(Some(pkt)) = pkts.get_packet(stream.clone()) { + tot_size2 += pkt.get_buffer().len(); + npkts += 1; + } + assert_eq!(npkts, 579); + assert_eq!(tot_size, tot_size2); + } +}