d07a5a2844cace2f49ebb82a10374986d074dc97
[nihav.git] / nihav-llaudio / src / demuxers / wavpack.rs
1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
3
4 const SAMPLE_RATES: [u32; 15] = [
5 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
6 32000, 44100, 48000, 64000, 88200, 96000, 192000
7 ];
8 const WV_FLAG_MONO: u32 = 1 << 2;
9 //const WV_FLAG_HYBRID: u32 = 1 << 3;
10 //const WV_FLAG_JSTEREO: u32 = 1 << 4;
11 //const WV_FLAG_CH_DECORR: u32 = 1 << 5;
12 //const WV_FLAG_HYB_NOISE_SHAPING: u32 = 1 << 6;
13 const WV_FLAG_FLOATS: u32 = 1 << 7;
14 //const WV_FLAG_EXT_INTEGERS: u32 = 1 << 8;
15 //const WV_FLAG_HYB_BITRATE: u32 = 1 << 9;
16 //const WV_FLAG_HYB_BALANCED_NOISE: u32 = 1 << 10;
17 const WV_FLAG_START_BLOCK: u32 = 1 << 11;
18 const WV_FLAG_END_BLOCK: u32 = 1 << 12;
19 //const WV_FLAG_HAS_CRC: u32 = 1 << 28;
20 const WV_FLAG_FALSE_STEREO: u32 = 1 << 30;
21 //const WV_FLAG_DSD_AUDIO: u32 = 1 << 31;
22
23 const WV_STREAM_FLAGS: u32 = 0x8000018B;
24
25 #[derive(Clone,Copy,Default)]
26 struct WVHeader {
27 size: usize,
28 ver: u16,
29 tot_samples: u64,
30 block_index: u64,
31 block_samples: u32,
32 flags: u32,
33 crc: u32,
34 }
35
36 const WV_HEADER_SIZE: usize = 32;
37
38 impl WVHeader {
39 fn parse(src: &[u8]) -> DemuxerResult<Self> {
40 let mut mr = MemoryReader::new_read(src);
41 let mut br = ByteReader::new(&mut mr);
42 let tag = br.read_tag()?;
43 validate!(&tag == b"wvpk");
44 let mut hdr = Self::default();
45 hdr.size = br.read_u32le()? as usize;
46 validate!(hdr.size >= 24);
47 hdr.ver = br.read_u16le()?;
48 validate!(hdr.ver >= 0x402 || hdr.ver <= 0x410);
49 let top_idx = br.read_byte()?;
50 let top_samps = br.read_byte()?;
51 hdr.tot_samples = u64::from(br.read_u32le()?) | (u64::from(top_samps) << 32);
52 hdr.block_index = u64::from(br.read_u32le()?) | (u64::from(top_idx) << 32);
53 hdr.block_samples = br.read_u32le()?;
54 hdr.flags = br.read_u32le()?;
55 hdr.crc = br.read_u32le()?;
56 Ok(hdr)
57 }
58 fn stream_eq(&self, rval: &Self) -> bool {
59 self.ver == rval.ver &&
60 (self.flags & WV_STREAM_FLAGS) == (rval.flags & WV_STREAM_FLAGS)
61 }
62 fn block_eq(&self, rval: &Self) -> bool {
63 self.stream_eq(rval) && self.tot_samples == rval.tot_samples &&
64 self.block_index == rval.block_index &&
65 self.block_samples == rval.block_samples
66 }
67 fn is_start_block(&self) -> bool {
68 (self.flags & WV_FLAG_START_BLOCK) != 0
69 }
70 fn is_end_block(&self) -> bool {
71 (self.flags & WV_FLAG_END_BLOCK) != 0
72 }
73 fn get_num_channels(&self) -> u8 {
74 if (self.flags & WV_FLAG_MONO) != 0 && (self.flags & WV_FLAG_FALSE_STEREO) == 0 { 1 } else { 2 }
75 }
76 fn get_sample_rate(&self) -> u32 {
77 let idx = ((self.flags >> 23) & 0xF) as usize;
78 if idx != 15 {
79 SAMPLE_RATES[idx]
80 } else {
81 0
82 }
83 }
84 fn get_size(&self) -> usize {
85 self.size - (WV_HEADER_SIZE - 8)
86 }
87 }
88
89 #[derive(Clone,Copy,Default)]
90 struct FrameSeekInfo {
91 off: u64,
92 samplepos: u64,
93 }
94
95 struct WavPackDemuxer<'a> {
96 src: &'a mut ByteReader<'a>,
97 samplepos: u64,
98 nsamples: u64,
99 first_blocks: Option<(WVHeader, Vec<u8>)>,
100 srate: u32,
101 known_frames: Vec<FrameSeekInfo>,
102 }
103
104 impl<'a> WavPackDemuxer<'a> {
105 fn new(io: &'a mut ByteReader<'a>) -> Self {
106 Self {
107 src: io,
108 samplepos: 0,
109 nsamples: 0,
110 first_blocks: None,
111 srate: 0,
112 known_frames: Vec::new(),
113 }
114 }
115 fn read_blocks(&mut self) -> DemuxerResult<(WVHeader, Vec<u8>)> {
116 let mut hdrbuf = [0u8; WV_HEADER_SIZE];
117 let mut buf: Vec<u8> = Vec::new();
118 let mut first = true;
119 let mut refhdr = WVHeader::default();
120 loop {
121 self.src.read_buf(&mut hdrbuf)?;
122 let hdr = WVHeader::parse(&hdrbuf)?;
123 if first {
124 validate!(hdr.is_start_block());
125 refhdr = hdr;
126 first = false;
127 } else {
128 validate!(refhdr.block_eq(&hdr));
129 }
130 buf.extend_from_slice(&hdrbuf);
131 let pos = buf.len();
132 buf.resize(pos + hdr.get_size(), 0);
133 self.src.read_buf(&mut buf[pos..])?;
134
135 if hdr.is_end_block() {
136 break;
137 }
138 }
139 Ok((refhdr, buf))
140 }
141 }
142
143 impl<'a> DemuxCore<'a> for WavPackDemuxer<'a> {
144 fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
145
146 let (hdr, buf) = self.read_blocks()?;
147
148 let srate = hdr.get_sample_rate();
149 validate!(srate != 0);
150 let channels = if !hdr.is_end_block() {
151 let mut ch_count = 0;
152 let mut off = 0;
153 loop {
154 let hdr = WVHeader::parse(&buf[off..]).unwrap();
155 off += WV_HEADER_SIZE + hdr.get_size();
156 ch_count += hdr.get_num_channels();
157 if hdr.is_end_block() {
158 break;
159 }
160 }
161 ch_count
162 } else {
163 hdr.get_num_channels()
164 };
165
166 self.nsamples = hdr.tot_samples;
167
168 let mut fmt = SND_S16P_FORMAT;
169 if (hdr.flags & WV_FLAG_FLOATS) != 0 {
170 fmt.float = true;
171 } else {
172 fmt.bits = (((hdr.flags & 3) + 1) * 8) as u8;
173 }
174
175 let ahdr = NAAudioInfo::new(srate, channels, SND_S16P_FORMAT, 1);
176 let ainfo = NACodecInfo::new("wavpack", NACodecTypeInfo::Audio(ahdr), Some(buf.clone()));
177 strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, srate)).unwrap();
178 seek_index.mode = SeekIndexMode::Automatic;
179 self.srate = srate;
180 self.known_frames = Vec::with_capacity(((self.nsamples + u64::from(srate) - 1) / u64::from(srate)) as usize);
181 self.known_frames.push(FrameSeekInfo { off: 0, samplepos: hdr.block_index });
182
183 self.first_blocks = Some((hdr, buf));
184 Ok(())
185 }
186 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
187 if self.first_blocks.is_some() {
188 let mut fb = None;
189 std::mem::swap(&mut fb, &mut self.first_blocks);
190 let (refhdr, buf) = fb.unwrap();
191 let stream = strmgr.get_stream(0).unwrap();
192 let (tb_num, tb_den) = stream.get_timebase();
193 let ts = NATimeInfo::new(Some(self.samplepos), None, None, tb_num, tb_den);
194 let pkt = NAPacket::new(stream, ts, true, buf);
195
196 self.samplepos += u64::from(refhdr.block_samples);
197
198 return Ok(pkt);
199 }
200 if self.samplepos == self.nsamples {
201 return Err(DemuxerError::EOF);
202 }
203 let cur_off = self.src.tell();
204 let cur_spos = self.samplepos;
205 let (refhdr, buf) = self.read_blocks()?;
206
207 let stream = strmgr.get_stream(0).unwrap();
208 let (tb_num, tb_den) = stream.get_timebase();
209 let ts = NATimeInfo::new(Some(self.samplepos), None, None, tb_num, tb_den);
210 let pkt = NAPacket::new(stream, ts, true, buf);
211
212 self.samplepos += u64::from(refhdr.block_samples);
213 if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos < cur_spos {
214 self.known_frames.push(FrameSeekInfo{off: cur_off, samplepos: cur_spos });
215 }
216
217 Ok(pkt)
218 }
219 fn seek(&mut self, time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
220 self.first_blocks = None;
221 if let NATimePoint::Milliseconds(ms) = time {
222 let samppos = ms * u64::from(self.srate) / 1000;
223 if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos >= samppos {
224 for point in self.known_frames.iter().rev() {
225 if point.samplepos <= samppos {
226 self.src.seek(SeekFrom::Start(point.off))?;
227 self.samplepos = point.samplepos;
228 return Ok(());
229 }
230 }
231 } else {
232 let mut hdrbuf = [0u8; WV_HEADER_SIZE];
233 let lastoff = self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).off;
234 self.src.seek(SeekFrom::Start(lastoff))?;
235 loop {
236 self.src.peek_buf(&mut hdrbuf)?;
237 let hdr = WVHeader::parse(&hdrbuf)?;
238 if hdr.is_start_block() {
239 self.known_frames.push(FrameSeekInfo{off: self.src.tell(), samplepos: hdr.block_index });
240 if hdr.block_index <= samppos && hdr.block_index + u64::from(hdr.block_samples) > samppos {
241 self.samplepos = hdr.block_index;
242 return Ok(());
243 }
244 if hdr.block_index > samppos {
245 break;
246 }
247 }
248 self.src.read_skip(WV_HEADER_SIZE + hdr.get_size())?
249 }
250 }
251 Err(DemuxerError::SeekError)
252 } else {
253 Err(DemuxerError::NotPossible)
254 }
255 }
256 }
257
258 impl<'a> NAOptionHandler for WavPackDemuxer<'a> {
259 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
260 fn set_options(&mut self, _options: &[NAOption]) { }
261 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
262 }
263
264
265 pub struct WavPackDemuxerCreator { }
266
267 impl DemuxerCreator for WavPackDemuxerCreator {
268 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
269 Box::new(WavPackDemuxer::new(br))
270 }
271 fn get_name(&self) -> &'static str { "wavpack" }
272 }
273
274 #[cfg(test)]
275 mod test {
276 use super::*;
277 use std::fs::File;
278
279 #[test]
280 fn test_wavpack_demux() {
281 let mut file = File::open("assets/LLaudio/wv/false_stereo.wv").unwrap();
282 let mut fr = FileReader::new_read(&mut file);
283 let mut br = ByteReader::new(&mut fr);
284 let mut dmx = WavPackDemuxer::new(&mut br);
285 let mut sm = StreamManager::new();
286 let mut si = SeekIndex::new();
287 dmx.open(&mut sm, &mut si).unwrap();
288 loop {
289 let pktres = dmx.get_frame(&mut sm);
290 if let Err(e) = pktres {
291 if (e as i32) == (DemuxerError::EOF as i32) { break; }
292 panic!("error");
293 }
294 let pkt = pktres.unwrap();
295 println!("Got {}", pkt);
296 }
297 }
298 }