]> git.nihav.org Git - nihav.git/blob - nihav-commonfmt/src/demuxers/wav.rs
avi: fix wrong variable in seek code
[nihav.git] / nihav-commonfmt / src / demuxers / wav.rs
1 use nihav_core::demuxers::*;
2 use nihav_registry::register;
3 use nihav_core::demuxers::DemuxerError::*;
4
5 macro_rules! mktag {
6 ($a:expr, $b:expr, $c:expr, $d:expr) => {
7 (u32::from($a) << 24) | (u32::from($b) << 16) | (u32::from($c) << 8) | u32::from($d)
8 };
9 ($arr:expr) => {
10 (u32::from($arr[0]) << 24) | (u32::from($arr[1]) << 16) | (u32::from($arr[2]) << 8) | u32::from($arr[3])
11 };
12 }
13
14 struct WAVDemuxer<'a> {
15 src: &'a mut ByteReader<'a>,
16 data_pos: u64,
17 data_end: u64,
18 srate: u32,
19 block_size: usize,
20 is_pcm: bool,
21 avg_bytes: u32,
22 duration: u64,
23 }
24
25 impl<'a> DemuxCore<'a> for WAVDemuxer<'a> {
26 fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
27 let riff = self.src.read_u32be()?;
28 let riff_size = self.src.read_u32le()? as usize;
29 let riff_end = self.src.tell() + if riff_size > 0 { riff_size as u64 } else { u64::from(std::u32::MAX) };
30 let wave = self.src.read_u32be()?;
31 validate!(riff == mktag!(b"RIFF"));
32 validate!(wave == mktag!(b"WAVE"));
33
34 seek_index.mode = SeekIndexMode::Automatic;
35
36 let mut fmt_parsed = false;
37 let mut duration = 0;
38 while self.src.tell() < riff_end {
39 let ctype = self.src.read_tag()?;
40 let csize = self.src.read_u32le()? as usize;
41 match &ctype {
42 b"fmt " => {
43 validate!(!fmt_parsed);
44 self.parse_fmt(strmgr, csize)?;
45 fmt_parsed = true;
46 },
47 b"fact" => {
48 validate!(csize == 4);
49 duration = self.src.read_u32le()? as usize;
50 },
51 b"data" => {
52 validate!(fmt_parsed);
53 self.data_pos = self.src.tell();
54 self.data_end = self.data_pos + (csize as u64);
55
56 if duration != 0 {
57 self.duration = (duration as u64) * 1000 / u64::from(self.srate);
58 } else if self.avg_bytes > 0 {
59 self.duration = (self.data_end - self.data_pos) * 1000 / u64::from(self.avg_bytes);
60 } else {
61 self.duration = 0;
62 }
63
64 return Ok(());
65 },
66 _ => {
67 self.src.read_skip(csize)?;
68 },
69 };
70 }
71 Err(DemuxerError::InvalidData)
72 }
73
74 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
75 if self.src.tell() >= self.data_end {
76 return Err(DemuxerError::EOF);
77 }
78 let strm = strmgr.get_stream(0);
79 if strm.is_none() { return Err(InvalidData); }
80 let stream = strm.unwrap();
81 let pts = if self.avg_bytes != 0 {
82 let pos = self.src.tell() - self.data_pos;
83 Some(pos * u64::from(self.srate) / u64::from(self.avg_bytes))
84 } else {
85 None
86 };
87 let ts = NATimeInfo::new(pts, None, None, 1, self.srate);
88 if self.is_pcm {
89 let mut bsize = self.block_size;
90 while bsize < 256 {
91 bsize <<= 1;
92 }
93 let mut buf = vec![0; bsize];
94 let size = self.src.read_buf_some(buf.as_mut_slice())?;
95 buf.truncate(size);
96 Ok(NAPacket::new(stream, ts, true, buf))
97 } else {
98 self.src.read_packet(stream, ts, true, self.block_size)
99 }
100 }
101
102 fn seek(&mut self, time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
103 if self.block_size != 0 && self.avg_bytes != 0 {
104 let seek_off = match time {
105 NATimePoint::Milliseconds(ms) => {
106 let seek_dst = u64::from(self.avg_bytes) * ms / 1000;
107 seek_dst / (self.block_size as u64) * (self.block_size as u64)
108 },
109 NATimePoint::PTS(pts) => (self.block_size as u64) * pts,
110 NATimePoint::None => return Ok(()),
111 };
112 self.src.seek(SeekFrom::Start(self.data_pos + seek_off))?;
113 Ok(())
114 } else {
115 Err(DemuxerError::NotImplemented)
116 }
117 }
118
119 fn get_duration(&self) -> u64 { self.duration }
120 }
121
122 impl<'a> NAOptionHandler for WAVDemuxer<'a> {
123 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
124 fn set_options(&mut self, _options: &[NAOption]) { }
125 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
126 }
127
128 impl<'a> WAVDemuxer<'a> {
129 fn new(io: &'a mut ByteReader<'a>) -> Self {
130 WAVDemuxer {
131 src: io,
132 data_pos: 0,
133 data_end: 0,
134 srate: 0,
135 block_size: 0,
136 is_pcm: false,
137 avg_bytes: 0,
138 duration: 0,
139 }
140 }
141 fn parse_fmt(&mut self, strmgr: &mut StreamManager, csize: usize) -> DemuxerResult<()> {
142 validate!(csize >= 14);
143 let format_tag = self.src.read_u16le()?;
144 let channels = self.src.read_u16le()?;
145 validate!(channels < 256);
146 let samples_per_sec = self.src.read_u32le()?;
147 let avg_bytes_per_sec = self.src.read_u32le()?;
148 let block_align = self.src.read_u16le()? as usize;
149 if block_align == 0 {
150 return Err(DemuxerError::NotImplemented);
151 }
152 let bits_per_sample = if csize >= 16 { self.src.read_u16le()? } else { 8 };
153 validate!(channels < 256);
154
155 let edata = if csize > 16 {
156 validate!(csize >= 18);
157 let cb_size = self.src.read_u16le()? as usize;
158 let mut buf = vec![0; cb_size];
159 self.src.read_buf(buf.as_mut_slice())?;
160 Some(buf)
161 } else {
162 None
163 };
164
165 let cname = register::find_codec_from_wav_twocc(format_tag).unwrap_or("unknown");
166 let soniton = if cname == "pcm" {
167 if format_tag != 0x0003 {
168 if bits_per_sample == 8 {
169 NASoniton::new(8, 0)
170 } else {
171 NASoniton::new(bits_per_sample as u8, SONITON_FLAG_SIGNED)
172 }
173 } else {
174 NASoniton::new(bits_per_sample as u8, SONITON_FLAG_FLOAT)
175 }
176 } else {
177 NASoniton::new(bits_per_sample as u8, SONITON_FLAG_SIGNED)
178 };
179 let ahdr = NAAudioInfo::new(samples_per_sec, channels as u8, soniton, block_align);
180 let ainfo = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata);
181 let res = strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, samples_per_sec, 0));
182 if res.is_none() { return Err(MemoryError); }
183
184 self.srate = samples_per_sec;
185 self.block_size = block_align;
186 self.avg_bytes = avg_bytes_per_sec;
187 self.is_pcm = cname == "pcm";
188 if self.is_pcm && self.avg_bytes == 0 {
189 self.avg_bytes = self.block_size as u32 * self.srate;
190 }
191
192 Ok(())
193 }
194 }
195
196 pub struct WAVDemuxerCreator { }
197
198 impl DemuxerCreator for WAVDemuxerCreator {
199 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
200 Box::new(WAVDemuxer::new(br))
201 }
202 fn get_name(&self) -> &'static str { "wav" }
203 }
204
205 #[cfg(test)]
206 mod test {
207 use super::*;
208 use std::fs::File;
209
210 #[test]
211 fn test_wav_demux() {
212 // sample: https://samples.mplayerhq.hu/A-codecs/msadpcm-stereo/scatter.wav
213 let mut file = File::open("assets/MS/scatter.wav").unwrap();
214 let mut fr = FileReader::new_read(&mut file);
215 let mut br = ByteReader::new(&mut fr);
216 let mut dmx = WAVDemuxer::new(&mut br);
217 let mut sm = StreamManager::new();
218 let mut si = SeekIndex::new();
219 dmx.open(&mut sm, &mut si).unwrap();
220
221 loop {
222 let pktres = dmx.get_frame(&mut sm);
223 if let Err(e) = pktres {
224 if e == DemuxerError::EOF { break; }
225 panic!("error");
226 }
227 let pkt = pktres.unwrap();
228 println!("Got {}", pkt);
229 }
230 }
231 }