WAV muxer
authorKostya Shishkov <kostya.shishkov@gmail.com>
Wed, 27 May 2020 12:02:20 +0000 (14:02 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Wed, 27 May 2020 15:25:08 +0000 (17:25 +0200)
nihav-commonfmt/Cargo.toml
nihav-commonfmt/src/muxers/mod.rs
nihav-commonfmt/src/muxers/wav.rs [new file with mode: 0644]

index f50fa5a789167ab591d2dd120d27811df28262a2..5bd89901063b422dc3da361ec963fbd5fa1953d1 100644 (file)
@@ -26,8 +26,9 @@ all_demuxers = ["demuxer_avi", "demuxer_mov", "demuxer_wav"]
 demuxer_avi = ["demuxers"]
 demuxer_mov = ["demuxers"]
 demuxer_wav = ["demuxers"]
-all_muxers = ["muxer_avi"]
+all_muxers = ["muxer_avi", "muxer_wav"]
 muxer_avi = ["muxers"]
+muxer_wav = ["muxers"]
 
 all_decoders = ["all_video_decoders", "all_audio_decoders"]
 
index 6d898067ca6f18d123797d16f5cb3e0d1a1846b9..5865172d8ede3518d418ab8a7a988ff2104096e7 100644 (file)
@@ -2,10 +2,14 @@ use nihav_core::muxers::*;
 
 #[cfg(feature="muxer_avi")]
 mod avi;
+#[cfg(feature="muxer_wav")]
+mod wav;
 
 const MUXERS: &[&MuxerCreator] = &[
 #[cfg(feature="muxer_avi")]
     &avi::AVIMuxerCreator {},
+#[cfg(feature="muxer_wav")]
+    &wav::WAVMuxerCreator {},
 ];
 
 pub fn generic_register_all_muxers(rm: &mut RegisteredMuxers) {
diff --git a/nihav-commonfmt/src/muxers/wav.rs b/nihav-commonfmt/src/muxers/wav.rs
new file mode 100644 (file)
index 0000000..163a977
--- /dev/null
@@ -0,0 +1,163 @@
+use nihav_core::muxers::*;
+use nihav_registry::register::*;
+
+struct WAVMuxer<'a> {
+    bw:         &'a mut ByteWriter<'a>,
+    data_pos:   u64,
+}
+
+impl<'a> WAVMuxer<'a> {
+    fn new(bw: &'a mut ByteWriter<'a>) -> Self {
+        Self {
+            bw,
+            data_pos:   0,
+        }
+    }
+}
+
+fn patch_size(bw: &mut ByteWriter, pos: u64) -> MuxerResult<()> {
+    let size = bw.tell() - pos;
+    bw.seek(SeekFrom::Current(-((size + 4) as i64)))?;
+    bw.write_u32le(size as u32)?;
+    bw.seek(SeekFrom::End(0))?;
+    Ok(())
+}
+
+impl<'a> MuxCore<'a> for WAVMuxer<'a> {
+    fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> {
+        if strmgr.get_num_streams() != 1 {
+            return Err(MuxerError::InvalidArgument);
+        }
+
+        let stream = strmgr.get_stream(0).unwrap();
+
+        if stream.get_info().get_properties().get_audio_info().is_none() {
+            return Err(MuxerError::InvalidArgument);
+        }
+        let ainfo = stream.get_info().get_properties().get_audio_info().unwrap();
+
+        let edata_len = if let Some(ref buf) = stream.get_info().get_extradata() { buf.len() } else { 0 };
+        if edata_len >= (1 << 16) {
+            return Err(MuxerError::UnsupportedFormat);
+        }
+
+        let twocc = find_wav_twocc(stream.get_info().get_name());
+        if twocc.is_none() {
+            return Err(MuxerError::UnsupportedFormat);
+        }
+        let twocc = if stream.get_info().get_name() == "pcm" {
+                if !ainfo.format.float { 0x0001 } else { 0x0003 }
+            } else {
+                twocc.unwrap_or(0)
+            };
+        let avg_bytes_per_sec = if stream.get_info().get_name() == "pcm" {
+                u32::from(ainfo.channels) * ainfo.sample_rate * u32::from(ainfo.format.bits) >> 3
+            } else {
+                0
+            };
+
+        self.bw.write_buf(b"RIFF\0\0\0\0WAVEfmt ")?;
+        self.bw.write_u32le(if edata_len == 0 { 16 } else { 18 + edata_len } as u32)?;
+        self.bw.write_u16le(twocc)?;
+        self.bw.write_u16le(ainfo.channels as u16)?;
+        self.bw.write_u32le(ainfo.sample_rate)?;
+        self.bw.write_u32le(avg_bytes_per_sec)?;
+        self.bw.write_u16le(ainfo.block_len as u16)?;
+        self.bw.write_u16le(ainfo.format.bits as u16)?;
+        if let Some(ref buf) = stream.get_info().get_extradata() {
+            self.bw.write_u16le(edata_len as u16)?;
+            self.bw.write_buf(buf.as_slice())?;
+        }
+        self.bw.write_buf(b"data\0\0\0\0")?;
+        self.data_pos = self.bw.tell();
+
+        Ok(())
+    }
+    fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
+        if self.data_pos == 0 {
+            return Err(MuxerError::NotCreated);
+        }
+
+        let stream = pkt.get_stream();
+        if stream.get_num() != 0 {
+            return Err(MuxerError::UnsupportedFormat);
+        }
+
+        self.bw.write_buf(pkt.get_buffer().as_slice())?;
+        Ok(())
+    }
+    fn flush(&mut self) -> MuxerResult<()> {
+        Ok(())
+    }
+    fn end(&mut self) -> MuxerResult<()> {
+        patch_size(&mut self.bw, self.data_pos)?;
+        patch_size(&mut self.bw, 8)?;
+        // todo patch avg_bytes_per_second if calculated
+        // todo write fact value if calculated
+        Ok(())
+    }
+}
+
+pub struct WAVMuxerCreator {}
+
+impl MuxerCreator for WAVMuxerCreator {
+    fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
+        Box::new(WAVMuxer::new(bw))
+    }
+    fn get_name(&self) -> &'static str { "wav" }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::fs::File;
+    use nihav_core::demuxers::*;
+    use crate::demuxers::*;
+
+    #[test]
+    fn test_wav_muxer() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut file = File::open("assets/Indeo/laser05.avi").unwrap();
+        let mut fr = FileReader::new_read(&mut file);
+        let mut br = ByteReader::new(&mut fr);
+        let dmx_f = dmx_reg.find_demuxer("avi").unwrap();
+        let mut dmx = create_demuxer(dmx_f, &mut br).unwrap();
+
+        let mut out_sm = StreamManager::new();
+        let mut out_streamno = 0;
+        for stream in dmx.get_streams() {
+            if stream.get_media_type() == StreamType::Audio {
+                let mut stream = NAStream::clone(&stream);
+                out_streamno = stream.id;
+                stream.id = 0;
+                out_sm.add_stream(stream);
+            }
+        }
+
+        let ofile = File::create("assets/test_out/muxed.wav").unwrap();
+        let mut fw = FileWriter::new_write(ofile);
+        let mut bw = ByteWriter::new(&mut fw);
+        let mut mux = WAVMuxer::new(&mut bw);
+
+        mux.create(&out_sm).unwrap();
+
+        loop {
+            let pktres = dmx.get_frame();
+            if let Err(e) = pktres {
+                if e == DemuxerError::EOF { break; }
+                panic!("error");
+            }
+            let mut pkt = pktres.unwrap();
+            println!("Got {}", pkt);
+            let pkt_str = pkt.get_stream();
+            if pkt_str.id == out_streamno {
+                pkt.reassign(out_sm.get_stream(0).unwrap(), pkt.get_time_information());
+                mux.mux_frame(&out_sm, pkt).unwrap();
+            }
+        }
+
+        mux.end().unwrap();
+panic!("end");
+    }
+}