1 use nihav_core::frame::*;
2 use nihav_core::demuxers::*;
4 const SAMPLE_RATES: [u32; 15] = [
5 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
6 32000, 44100, 48000, 64000, 88200, 96000, 192000
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;
23 const WV_STREAM_FLAGS: u32 = 0x8000008B;
25 #[derive(Clone,Copy,Default)]
36 const WV_HEADER_SIZE: usize = 32;
39 #[allow(clippy::field_reassign_with_default)]
40 fn parse(src: &[u8]) -> DemuxerResult<Self> {
41 let mut mr = MemoryReader::new_read(src);
42 let mut br = ByteReader::new(&mut mr);
43 let tag = br.read_tag()?;
44 validate!(&tag == b"wvpk");
45 let mut hdr = Self::default();
46 hdr.size = br.read_u32le()? as usize;
47 validate!(hdr.size >= 24);
48 hdr.ver = br.read_u16le()?;
49 validate!(hdr.ver >= 0x402 || hdr.ver <= 0x410);
50 let top_idx = br.read_byte()?;
51 let top_samps = br.read_byte()?;
52 hdr.tot_samples = u64::from(br.read_u32le()?) | (u64::from(top_samps) << 32);
53 hdr.block_index = u64::from(br.read_u32le()?) | (u64::from(top_idx) << 32);
54 hdr.block_samples = br.read_u32le()?;
55 hdr.flags = br.read_u32le()?;
56 hdr.crc = br.read_u32le()?;
59 fn stream_eq(&self, rval: &Self) -> bool {
60 self.ver == rval.ver &&
61 (self.flags & WV_STREAM_FLAGS) == (rval.flags & WV_STREAM_FLAGS)
63 fn block_eq(&self, rval: &Self) -> bool {
64 self.stream_eq(rval) && self.tot_samples == rval.tot_samples &&
65 self.block_index == rval.block_index &&
66 self.block_samples == rval.block_samples
68 fn is_start_block(&self) -> bool {
69 (self.flags & WV_FLAG_START_BLOCK) != 0
71 fn is_end_block(&self) -> bool {
72 (self.flags & WV_FLAG_END_BLOCK) != 0
74 fn get_num_channels(&self) -> u8 {
75 if (self.flags & WV_FLAG_MONO) != 0 && (self.flags & WV_FLAG_FALSE_STEREO) == 0 { 1 } else { 2 }
77 fn get_sample_rate(&self) -> u32 {
78 let idx = ((self.flags >> 23) & 0xF) as usize;
85 fn get_size(&self) -> usize {
86 self.size - (WV_HEADER_SIZE - 8)
90 #[derive(Clone,Copy,Default)]
91 struct FrameSeekInfo {
96 struct WavPackDemuxer<'a> {
97 src: &'a mut ByteReader<'a>,
100 first_blocks: Option<(WVHeader, Vec<u8>)>,
102 known_frames: Vec<FrameSeekInfo>,
105 impl<'a> WavPackDemuxer<'a> {
106 fn new(io: &'a mut ByteReader<'a>) -> Self {
113 known_frames: Vec::new(),
116 fn read_blocks(&mut self) -> DemuxerResult<(WVHeader, Vec<u8>)> {
117 let mut hdrbuf = [0u8; WV_HEADER_SIZE];
118 let mut buf: Vec<u8> = Vec::new();
119 let mut first = true;
120 let mut refhdr = WVHeader::default();
122 self.src.read_buf(&mut hdrbuf)?;
123 let hdr = WVHeader::parse(&hdrbuf)?;
125 validate!(hdr.is_start_block());
129 validate!(refhdr.block_eq(&hdr));
131 buf.extend_from_slice(&hdrbuf);
133 buf.resize(pos + hdr.get_size(), 0);
134 self.src.read_buf(&mut buf[pos..])?;
136 if hdr.is_end_block() {
144 impl<'a> DemuxCore<'a> for WavPackDemuxer<'a> {
145 fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
147 let (hdr, buf) = self.read_blocks()?;
149 let srate = hdr.get_sample_rate();
150 validate!(srate != 0);
151 let channels = if !hdr.is_end_block() {
152 let mut ch_count = 0;
155 let hdr = WVHeader::parse(&buf[off..]).unwrap();
156 off += WV_HEADER_SIZE + hdr.get_size();
157 ch_count += hdr.get_num_channels();
158 if hdr.is_end_block() {
164 hdr.get_num_channels()
167 self.nsamples = hdr.tot_samples;
169 let mut fmt = SND_S16P_FORMAT;
170 if (hdr.flags & WV_FLAG_FLOATS) != 0 {
173 fmt.bits = (((hdr.flags & 3) + 1) * 8) as u8;
176 let ahdr = NAAudioInfo::new(srate, channels, SND_S16P_FORMAT, 1);
177 let ainfo = NACodecInfo::new("wavpack", NACodecTypeInfo::Audio(ahdr), Some(buf.clone()));
178 strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, srate, hdr.tot_samples)).unwrap();
179 seek_index.mode = SeekIndexMode::Automatic;
181 self.known_frames = Vec::with_capacity(((self.nsamples + u64::from(srate) - 1) / u64::from(srate)) as usize);
182 self.known_frames.push(FrameSeekInfo { off: 0, samplepos: hdr.block_index });
184 self.first_blocks = Some((hdr, buf));
187 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
188 if self.first_blocks.is_some() {
190 std::mem::swap(&mut fb, &mut self.first_blocks);
191 let (refhdr, buf) = fb.unwrap();
192 let stream = strmgr.get_stream(0).unwrap();
193 let ts = stream.make_ts(Some(self.samplepos), None, None);
194 let pkt = NAPacket::new(stream, ts, true, buf);
196 self.samplepos += u64::from(refhdr.block_samples);
200 if self.samplepos == self.nsamples {
201 return Err(DemuxerError::EOF);
203 let cur_off = self.src.tell();
204 let cur_spos = self.samplepos;
205 let (refhdr, buf) = self.read_blocks()?;
207 let stream = strmgr.get_stream(0).unwrap();
208 let ts = stream.make_ts(Some(self.samplepos), None, None);
209 let pkt = NAPacket::new(stream, ts, true, buf);
211 self.samplepos += u64::from(refhdr.block_samples);
212 if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos < cur_spos {
213 self.known_frames.push(FrameSeekInfo{off: cur_off, samplepos: cur_spos });
218 fn seek(&mut self, time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
219 self.first_blocks = None;
220 if let NATimePoint::Milliseconds(ms) = time {
221 let samppos = ms * u64::from(self.srate) / 1000;
222 if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos >= samppos {
223 for point in self.known_frames.iter().rev() {
224 if point.samplepos <= samppos {
225 self.src.seek(SeekFrom::Start(point.off))?;
226 self.samplepos = point.samplepos;
231 let mut hdrbuf = [0u8; WV_HEADER_SIZE];
232 let lastoff = self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).off;
233 self.src.seek(SeekFrom::Start(lastoff))?;
235 self.src.peek_buf(&mut hdrbuf)?;
236 let hdr = WVHeader::parse(&hdrbuf)?;
237 if hdr.is_start_block() {
238 self.known_frames.push(FrameSeekInfo{off: self.src.tell(), samplepos: hdr.block_index });
239 if hdr.block_index <= samppos && hdr.block_index + u64::from(hdr.block_samples) > samppos {
240 self.samplepos = hdr.block_index;
243 if hdr.block_index > samppos {
247 self.src.read_skip(WV_HEADER_SIZE + hdr.get_size())?
250 Err(DemuxerError::SeekError)
252 Err(DemuxerError::NotPossible)
255 fn get_duration(&self) -> u64 { 0 }
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 }
265 pub struct WavPackDemuxerCreator { }
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))
271 fn get_name(&self) -> &'static str { "wavpack" }
280 fn test_wavpack_demux() {
281 // sample from the official WavPack test samples set
282 let mut file = File::open("assets/LLaudio/wv/false_stereo.wv").unwrap();
283 let mut fr = FileReader::new_read(&mut file);
284 let mut br = ByteReader::new(&mut fr);
285 let mut dmx = WavPackDemuxer::new(&mut br);
286 let mut sm = StreamManager::new();
287 let mut si = SeekIndex::new();
288 dmx.open(&mut sm, &mut si).unwrap();
290 let pktres = dmx.get_frame(&mut sm);
291 if let Err(e) = pktres {
292 if (e as i32) == (DemuxerError::EOF as i32) { break; }
295 let pkt = pktres.unwrap();
296 println!("Got {}", pkt);