simple FLAC encoder and muxer
[nihav.git] / nihav-llaudio / src / muxers / flac.rs
1 use nihav_core::muxers::*;
2
3 struct FLACMuxer<'a> {
4 bw: &'a mut ByteWriter<'a>,
5 maxpkt: usize,
6 minpkt: usize,
7 duration: u64,
8 maxblk: u16,
9 minblk: u16,
10 bits: u8,
11 }
12
13 impl<'a> FLACMuxer<'a> {
14 fn new(bw: &'a mut ByteWriter<'a>) -> Self {
15 Self {
16 bw,
17 maxpkt: std::usize::MAX, minpkt: 0,
18 maxblk: std::u16::MAX, minblk: 0,
19 duration: 0,
20 bits: 0,
21 }
22 }
23 }
24
25 impl<'a> MuxCore<'a> for FLACMuxer<'a> {
26 fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> {
27 if strmgr.get_num_streams() == 0 {
28 return Err(MuxerError::InvalidArgument);
29 }
30 let stream = strmgr.get_stream(0).unwrap();
31 if let NACodecTypeInfo::Audio(ref ainfo) = stream.get_info().get_properties() {
32 self.bw.write_buf(b"fLaC")?;
33 self.bw.write_byte(0x80)?; // last metadata block - streaminfo
34 self.bw.write_u24be(34)?; // streaminfo size
35 self.bw.write_u16be(2)?; // minimum block size
36 self.bw.write_u16be(ainfo.block_len as u16)?;
37 self.bw.write_u24be(0)?; // minimum frame size
38 self.bw.write_u24be(0)?; // maximum frame size
39
40 let bits = ainfo.format.bits - 1;
41 self.bits = bits;
42 self.bw.write_u24be(ainfo.sample_rate * 16 + u32::from(ainfo.channels - 1) * 2 + u32::from(bits >> 4))?;
43 self.bw.write_byte(bits << 4)?;
44 self.bw.write_u32be(0)?;//total samples low 32 bits
45 self.bw.write_u64be(0)?;self.bw.write_u64be(0)?; //MD5
46
47 Ok(())
48 } else {
49 Err(MuxerError::InvalidArgument)
50 }
51 }
52 fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
53 let pktlen = pkt.get_buffer().len();
54 let slen = pkt.ts.duration.unwrap_or(0);
55 let samples = if slen != 1 { slen } else { u64::from(pkt.ts.tb_den) };
56
57 self.maxpkt = self.maxpkt.max(pktlen);
58 self.minpkt = self.minpkt.min(pktlen);
59 self.maxblk = self.maxblk.max(samples as u16);
60 self.minblk = self.minblk.min(samples as u16);
61 self.duration += samples;
62
63 self.bw.write_buf(&pkt.get_buffer())?;
64 Ok(())
65 }
66 fn flush(&mut self) -> MuxerResult<()> {
67 Ok(())
68 }
69 fn end(&mut self) -> MuxerResult<()> {
70 //todo: write MD5 somehow?
71 self.bw.seek(SeekFrom::Start(8))?;
72 self.bw.write_u16be(self.minblk)?;
73 self.bw.write_u16be(self.maxblk)?;
74 self.bw.write_u24be(self.minpkt as u32)?;
75 self.bw.write_u24be(self.maxpkt as u32)?;
76 self.bw.seek(SeekFrom::Current(3))?;
77 self.bw.write_byte((self.bits << 4) | (((self.duration >> 32) as u8) & 0xF))?;
78 self.bw.write_u32be(self.duration as u32)?;
79 Ok(())
80 }
81 }
82
83 impl<'a> NAOptionHandler for FLACMuxer<'a> {
84 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
85 fn set_options(&mut self, _options: &[NAOption]) { }
86 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
87 }
88
89 pub struct FLACMuxerCreator {}
90
91 impl MuxerCreator for FLACMuxerCreator {
92 fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
93 Box::new(FLACMuxer::new(bw))
94 }
95 fn get_name(&self) -> &'static str { "flac" }
96 fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::SingleAudio("flac") }
97 }
98
99 #[cfg(test)]
100 mod test {
101 use nihav_core::codecs::*;
102 use nihav_core::demuxers::*;
103 use nihav_core::muxers::*;
104 use nihav_codec_support::test::enc_video::*;
105 use crate::*;
106
107 #[test]
108 fn test_flac_muxer() {
109 let mut dmx_reg = RegisteredDemuxers::new();
110 llaudio_register_all_demuxers(&mut dmx_reg);
111 let dec_config = DecoderTestParams {
112 demuxer: "flac",
113 in_name: "assets/LLaudio/luckynight.flac",
114 limit: None,
115 stream_type: StreamType::None,
116 dmx_reg, dec_reg: RegisteredDecoders::new(),
117 };
118 let mut mux_reg = RegisteredMuxers::new();
119 llaudio_register_all_muxers(&mut mux_reg);
120 /* let enc_config = EncoderTestParams {
121 muxer: "flac",
122 enc_name: "",
123 out_name: "muxed.flac",
124 mux_reg, enc_reg: RegisteredEncoders::new(),
125 };
126 test_remuxing(&dec_config, &enc_config);*/
127 test_remuxing_md5(&dec_config, "flac", &mux_reg,
128 [0x77afb7c0, 0x84d2bd87, 0x6e028092, 0x7db7c72e]);
129 }
130 }
131