X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-llaudio%2Fsrc%2Fmuxers%2Fflac.rs;fp=nihav-llaudio%2Fsrc%2Fmuxers%2Fflac.rs;h=5c649a592839f912f310b5e9b1f18fbb4fa555ab;hp=0000000000000000000000000000000000000000;hb=c11ad64e877fcf2e47c7bbb04bfb8d7764465dab;hpb=8d7cb844e69aa03fb6667681a5b06a3370c72eeb diff --git a/nihav-llaudio/src/muxers/flac.rs b/nihav-llaudio/src/muxers/flac.rs new file mode 100644 index 0000000..5c649a5 --- /dev/null +++ b/nihav-llaudio/src/muxers/flac.rs @@ -0,0 +1,131 @@ +use nihav_core::muxers::*; + +struct FLACMuxer<'a> { + bw: &'a mut ByteWriter<'a>, + maxpkt: usize, + minpkt: usize, + duration: u64, + maxblk: u16, + minblk: u16, + bits: u8, +} + +impl<'a> FLACMuxer<'a> { + fn new(bw: &'a mut ByteWriter<'a>) -> Self { + Self { + bw, + maxpkt: std::usize::MAX, minpkt: 0, + maxblk: std::u16::MAX, minblk: 0, + duration: 0, + bits: 0, + } + } +} + +impl<'a> MuxCore<'a> for FLACMuxer<'a> { + fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> { + if strmgr.get_num_streams() == 0 { + return Err(MuxerError::InvalidArgument); + } + let stream = strmgr.get_stream(0).unwrap(); + if let NACodecTypeInfo::Audio(ref ainfo) = stream.get_info().get_properties() { + self.bw.write_buf(b"fLaC")?; + self.bw.write_byte(0x80)?; // last metadata block - streaminfo + self.bw.write_u24be(34)?; // streaminfo size + self.bw.write_u16be(2)?; // minimum block size + self.bw.write_u16be(ainfo.block_len as u16)?; + self.bw.write_u24be(0)?; // minimum frame size + self.bw.write_u24be(0)?; // maximum frame size + + let bits = ainfo.format.bits - 1; + self.bits = bits; + self.bw.write_u24be(ainfo.sample_rate * 16 + u32::from(ainfo.channels - 1) * 2 + u32::from(bits >> 4))?; + self.bw.write_byte(bits << 4)?; + self.bw.write_u32be(0)?;//total samples low 32 bits + self.bw.write_u64be(0)?;self.bw.write_u64be(0)?; //MD5 + + Ok(()) + } else { + Err(MuxerError::InvalidArgument) + } + } + fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> { + let pktlen = pkt.get_buffer().len(); + let slen = pkt.ts.duration.unwrap_or(0); + let samples = if slen != 1 { slen } else { u64::from(pkt.ts.tb_den) }; + + self.maxpkt = self.maxpkt.max(pktlen); + self.minpkt = self.minpkt.min(pktlen); + self.maxblk = self.maxblk.max(samples as u16); + self.minblk = self.minblk.min(samples as u16); + self.duration += samples; + + self.bw.write_buf(&pkt.get_buffer())?; + Ok(()) + } + fn flush(&mut self) -> MuxerResult<()> { + Ok(()) + } + fn end(&mut self) -> MuxerResult<()> { +//todo: write MD5 somehow? + self.bw.seek(SeekFrom::Start(8))?; + self.bw.write_u16be(self.minblk)?; + self.bw.write_u16be(self.maxblk)?; + self.bw.write_u24be(self.minpkt as u32)?; + self.bw.write_u24be(self.maxpkt as u32)?; + self.bw.seek(SeekFrom::Current(3))?; + self.bw.write_byte((self.bits << 4) | (((self.duration >> 32) as u8) & 0xF))?; + self.bw.write_u32be(self.duration as u32)?; + Ok(()) + } +} + +impl<'a> NAOptionHandler for FLACMuxer<'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 FLACMuxerCreator {} + +impl MuxerCreator for FLACMuxerCreator { + fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box + 'a> { + Box::new(FLACMuxer::new(bw)) + } + fn get_name(&self) -> &'static str { "flac" } + fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::SingleAudio("flac") } +} + +#[cfg(test)] +mod test { + use nihav_core::codecs::*; + use nihav_core::demuxers::*; + use nihav_core::muxers::*; + use nihav_codec_support::test::enc_video::*; + use crate::*; + + #[test] + fn test_flac_muxer() { + let mut dmx_reg = RegisteredDemuxers::new(); + llaudio_register_all_demuxers(&mut dmx_reg); + let dec_config = DecoderTestParams { + demuxer: "flac", + in_name: "assets/LLaudio/luckynight.flac", + limit: None, + stream_type: StreamType::None, + dmx_reg, dec_reg: RegisteredDecoders::new(), + }; + let mut mux_reg = RegisteredMuxers::new(); + llaudio_register_all_muxers(&mut mux_reg); +/* let enc_config = EncoderTestParams { + muxer: "flac", + enc_name: "", + out_name: "muxed.flac", + mux_reg, enc_reg: RegisteredEncoders::new(), + }; + test_remuxing(&dec_config, &enc_config);*/ + test_remuxing_md5(&dec_config, "flac", &mux_reg, + [0x77afb7c0, 0x84d2bd87, 0x6e028092, 0x7db7c72e]); + } +} +