]>
Commit | Line | Data |
---|---|---|
87927c57 KS |
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 | ||
95221ccc | 23 | const WV_STREAM_FLAGS: u32 = 0x8000008B; |
87927c57 KS |
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())); | |
a480a0de | 177 | strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, srate, hdr.tot_samples)).unwrap(); |
87927c57 KS |
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]; | |
7d6bb2e8 KS |
233 | let lastoff = self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).off; |
234 | self.src.seek(SeekFrom::Start(lastoff))?; | |
87927c57 KS |
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 | } | |
a480a0de | 256 | fn get_duration(&self) -> u64 { 0 } |
87927c57 KS |
257 | } |
258 | ||
259 | impl<'a> NAOptionHandler for WavPackDemuxer<'a> { | |
260 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
261 | fn set_options(&mut self, _options: &[NAOption]) { } | |
262 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
263 | } | |
264 | ||
265 | ||
266 | pub struct WavPackDemuxerCreator { } | |
267 | ||
268 | impl DemuxerCreator for WavPackDemuxerCreator { | |
269 | fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> { | |
270 | Box::new(WavPackDemuxer::new(br)) | |
271 | } | |
272 | fn get_name(&self) -> &'static str { "wavpack" } | |
273 | } | |
274 | ||
275 | #[cfg(test)] | |
276 | mod test { | |
277 | use super::*; | |
278 | use std::fs::File; | |
279 | ||
280 | #[test] | |
281 | fn test_wavpack_demux() { | |
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(); | |
289 | loop { | |
290 | let pktres = dmx.get_frame(&mut sm); | |
291 | if let Err(e) = pktres { | |
292 | if (e as i32) == (DemuxerError::EOF as i32) { break; } | |
293 | panic!("error"); | |
294 | } | |
295 | let pkt = pktres.unwrap(); | |
296 | println!("Got {}", pkt); | |
297 | } | |
298 | } | |
299 | } |