vmd: handle IMA ADPCM chunks with odd number of samples correctly
[nihav.git] / nihav-game / src / codecs / vmd.rs
CommitLineData
9895bd7b
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
979faef7 3use nihav_codec_support::codecs::imaadpcm::*;
9895bd7b 4use std::str::FromStr;
f45dfcf7 5use std::sync::Arc;
9895bd7b
KS
6
7macro_rules! lz_op {
8 (read; $dst:ident, $dpos:expr, $window:ident, $wpos:expr, $br:expr, $dst_size:expr) => {
9 validate!($dpos < $dst_size);
10 let b = $br.read_byte()?;
11 $dst[$dpos] = b;
12 $dpos += 1;
13 $window[$wpos] = b;
14 $wpos = ($wpos + 1) & 0xFFF;
15 };
16 (copy; $dst:ident, $dpos:expr, $window:ident, $wpos:expr, $off:expr, $dst_size:expr) => {
17 let b = $window[$off];
18 validate!($dpos < $dst_size);
19 $dst[$dpos] = b;
20 $dpos += 1;
21 $window[$wpos] = b;
22 $wpos = ($wpos + 1) & 0xFFF;
23 $off = ($off + 1) & 0xFFF;
24 };
25}
26fn lz_unpack(br: &mut ByteReader, dst: &mut [u8]) -> DecoderResult<()> {
27 let mut window: [u8; 0x1000] = [0x20; 0x1000];
28
29 let dst_size = br.read_u32le()? as usize;
30 validate!(dst_size <= dst.len());
31 let mut pos;
32 let esc_len;
33 if br.peek_u32le()? == 0x56781234 {
34 br.read_skip(4)?;
35 pos = 0x111;
36 esc_len = 15;
37 } else {
38 pos = 0xFEE;
39 esc_len = 255;
40 }
41
42 let mut opos = 0;
43 while br.left() > 0 && opos < dst_size {
44 let op = br.read_byte()?;
45 if (op == 0xFF) && (br.left() > 8) {
46 for _ in 0..8 {
47 lz_op!(read; dst, opos, window, pos, br, dst_size);
48 }
49 } else {
50 for i in 0..8 {
51 if opos == dst_size { break; }
52 let is_literal = ((op >> i) & 1) != 0;
53 if is_literal {
54 lz_op!(read; dst, opos, window, pos, br, dst_size);
55 } else {
56 let b0 = br.read_byte()? as usize;
57 let b1 = br.read_byte()? as usize;
58 let mut off = b0 | ((b1 & 0xF0) << 4);
59 let mut len = b1 & 0xF;
60 if len == esc_len {
61 len = (br.read_byte()? as usize) + esc_len;
62 }
63 for _ in 0..len+3 {
64 lz_op!(copy; dst, opos, window, pos, off, dst_size);
65 }
66 }
67 }
68 }
69 }
70 Ok(())
71}
72
73fn rle_unpack(br: &mut ByteReader, len: usize, dst: &mut [u8]) -> DecoderResult<()> {
74 let end = br.tell() + (len as u64);
75 let mut dpos = 0;
76 if (len & 1) != 0 {
77 dst[dpos] = br.read_byte()?;
78 dpos += 1;
79 }
80 while dpos < dst.len() && br.tell() < end {
81 let val = br.read_byte()?;
82 let len = ((val & 0x7F) as usize) * 2;
83 validate!(dpos + len <= dst.len());
84 if (val & 0x80) != 0 {
85 let dst = &mut dst[dpos..][..len];
86 br.read_buf(dst)?;
87 } else {
771e522a
KS
88 let val1 = br.read_byte()?;
89 let val2 = br.read_byte()?;
90 for i in (0..len).step_by(2) {
91 dst[dpos + i] = val1;
92 dst[dpos + i + 1] = val2;
9895bd7b
KS
93 }
94 }
95 dpos += len;
96 }
97 Ok(())
98}
99
100fn decode_frame_data(br: &mut ByteReader, dst: &mut [u8], mut dpos: usize, stride: usize, w: usize, h: usize, method: u8) -> DecoderResult<bool> {
101 match method {
102 1 => {
103 for _ in 0..h {
104 let mut x = 0;
105 while x < w {
106 let val = br.read_byte()?;
107 let len = ((val & 0x7F) as usize) + 1;
108 validate!(x + len <= w);
109 if (val & 0x80) != 0 {
110 let pix = &mut dst[dpos + x..][..len];
111 br.read_buf(pix)?;
112 } // otherwise skip already existing data
113 x += len;
114 }
115 dpos += stride;
116 }
117 Ok(false)
118 },
119 2 => {
120 for _ in 0..h {
121 let pix = &mut dst[dpos..][..w];
122 br.read_buf(pix)?;
123 dpos += stride;
124 }
125 Ok(true)
126 },
127 3 => {
128 for _ in 0..h {
129 let mut x = 0;
130 while x < w {
131 let val = br.read_byte()?;
132 let len = ((val & 0x7F) as usize) + 1;
133 validate!(x + len <= w);
134 if (val & 0x80) != 0 {
135 let pix = &mut dst[dpos + x..][..len];
136 if br.peek_byte()? == 0xFF {
137 br.read_skip(1)?;
138 rle_unpack(br, len, pix)?;
139 } else {
140 br.read_buf(pix)?;
141 }
142 } // otherwise data is already there
143 x += len;
144 }
145 dpos += stride;
146 }
147 Ok(false)
148 },
e69b1148 149 _ => Err(DecoderError::InvalidData),
9895bd7b
KS
150 }
151}
152
153struct VMDVideoDecoder {
2422d969 154 info: NACodecInfoRef,
9895bd7b
KS
155 pal: [u8; 768],
156 buf: Vec<u8>,
a5e655a7 157 framebuf: Vec<u8>,
9895bd7b
KS
158 width: usize,
159 height: usize,
73a1eecd
KS
160 xoff: usize,
161 yoff: usize,
a5e655a7
KS
162 is_16bit: bool,
163 is_24bit: bool,
164 ver1: u8,
165 ver2: u8,
9895bd7b
KS
166}
167
168impl VMDVideoDecoder {
169 fn new() -> Self {
170 Self {
2422d969 171 info: NACodecInfoRef::default(),
9895bd7b
KS
172 pal: [0; 768],
173 buf: Vec::new(),
a5e655a7 174 framebuf: Vec::new(),
9895bd7b
KS
175 width: 0,
176 height: 0,
73a1eecd
KS
177 xoff: 0,
178 yoff: 0,
a5e655a7
KS
179 is_16bit: false,
180 is_24bit: false,
181 ver1: 0,
182 ver2: 0,
9895bd7b
KS
183 }
184 }
a5e655a7 185 fn decode_frame(&mut self, br: &mut ByteReader) -> DecoderResult<bool> {
9895bd7b
KS
186 let frame_x = br.read_u16le()? as usize;
187 let frame_y = br.read_u16le()? as usize;
02c01d44 188 let frame_r = br.read_u16le()? as usize;
9895bd7b
KS
189 let frame_d = br.read_u16le()? as usize;
190 br.read_skip(1)?;
191 let flags = br.read_byte()?;
a5e655a7 192 let has_pal = (flags & 0x02) != 0 && !self.is_16bit && !self.is_24bit;
02c01d44 193 if (frame_x == 0xFFFF) && (frame_y == 0xFFFF) && (frame_r == 0xFFFF) && (frame_d == 0xFFFF) {
5961ae1d
KS
194 return Ok(false);
195 }
73a1eecd 196 validate!(frame_x >= self.xoff && frame_y >= self.yoff);
02c01d44
KS
197 validate!(frame_r >= frame_x && frame_d >= frame_y);
198 validate!(frame_r - self.xoff < self.width && frame_d - self.yoff < self.height);
9895bd7b
KS
199
200 if has_pal {
201 br.read_skip(2)?;
202 for e in self.pal.iter_mut() {
203 let val = br.read_byte()?;
204 *e = (val << 2) | (val >> 4);
205 }
206 }
207
9895bd7b
KS
208 if br.left() == 0 { return Ok(false); }
209
a5e655a7
KS
210 let bpp = if (!self.is_16bit && !self.is_24bit) || self.ver1 < 2 {
211 1
212 } else if self.is_16bit {
213 2
214 } else {
215 3
216 };
02c01d44 217 let w = (frame_r + 1 - frame_x) * bpp;
9895bd7b 218 let h = frame_d + 1 - frame_y;
a5e655a7
KS
219 let stride = self.width;
220 let dpos = (frame_x - self.xoff) * bpp + (frame_y - self.yoff) * stride;
9895bd7b
KS
221
222 let method = br.read_byte()?;
223 let is_intra;
224 if (method & 0x80) != 0 {
e69b1148 225 validate!(!self.buf.is_empty());
9895bd7b
KS
226 lz_unpack(br, &mut self.buf)?;
227 let mut mr = MemoryReader::new_read(&self.buf);
228 let mut buf_br = ByteReader::new(&mut mr);
a5e655a7 229 is_intra = decode_frame_data(&mut buf_br, &mut self.framebuf, dpos, stride, w, h, method & 0x7F)?;
9895bd7b 230 } else {
a5e655a7 231 is_intra = decode_frame_data(br, &mut self.framebuf, dpos, stride, w, h, method & 0x7F)?;
9895bd7b
KS
232 }
233 Ok(is_intra && frame_x == 0 && frame_y == 0 && w == self.width && h == self.height)
234 }
235}
236
a5e655a7
KS
237const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
238 comp_info: [
239 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
240 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 1, next_elem: 2 }),
241 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 2, next_elem: 2 }),
242 None, None],
243 elem_size: 2, be: false, alpha: false, palette: false };
244
9895bd7b 245impl NADecoder for VMDVideoDecoder {
01613464 246 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
9895bd7b
KS
247 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
248 self.width = vinfo.get_width();
249 self.height = vinfo.get_height();
9895bd7b
KS
250 validate!(info.get_extradata().is_some());
251
252 if let Some(ref edata) = info.get_extradata() {
253 validate!(edata.len() == 0x330);
254 let unp_size = read_u32le(&edata[800..])? as usize;
ed6c9f8a 255 validate!(unp_size < self.width * self.height * 4 + 64); // just for sanity
9895bd7b
KS
256 self.buf.resize(unp_size, 0);
257 for i in 0..768 {
258 let el = edata[28 + i];
259 self.pal[i] = (el << 2) | (el >> 4);
260 }
73a1eecd
KS
261 self.xoff = read_u16le(&edata[8..])? as usize;
262 self.yoff = read_u16le(&edata[10..])? as usize;
a5e655a7
KS
263 self.ver1 = edata[2];
264 self.ver2 = edata[4];
265 } else {
266 unreachable!();
9895bd7b 267 }
a5e655a7
KS
268 let (disp_width, fmt) = if self.ver2 < 5 {
269 (self.width, PAL8_FORMAT)
270 } else if self.ver2 < 13 {
271 self.is_24bit = true;
272 if self.ver1 >= 2 {
273 self.width *= 3;
274 }
275 validate!(self.width % 3 == 0);
276 (self.width / 3, RGB24_FORMAT)
277 } else {
278 self.is_16bit = true;
279 if self.ver1 >= 2 {
280 self.width *= 2;
281 }
282 (self.width / 2, RGB555_FORMAT)
283 };
284 self.framebuf = vec!(0; self.width * self.height);
285
286 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(disp_width, self.height, false, fmt));
287 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
9895bd7b
KS
288
289 Ok(())
290 } else {
291 Err(DecoderError::InvalidData)
292 }
293 }
01613464 294 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
9895bd7b
KS
295 let src = pkt.get_buffer();
296 validate!(src.len() >= 10);
297
298 let mut mr = MemoryReader::new_read(&src);
299 let mut br = ByteReader::new(&mut mr);
300
a5e655a7
KS
301 let is_intra = self.decode_frame(&mut br)?;
302
303 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
304 let videobuf;
305 if !self.is_16bit {
306 let mut buf = bufinfo.get_vbuf().unwrap();
307 let stride = buf.get_stride(0);
308 let paloff = buf.get_offset(1);
309 let data = buf.get_data_mut().unwrap();
310 for (inrow, outrow) in self.framebuf.chunks(self.width).zip(data.chunks_mut(stride)) {
311 (&mut outrow[..self.width]).copy_from_slice(inrow);
312 }
313 if !self.is_24bit {
314 (&mut data[paloff..][..768]).copy_from_slice(&self.pal);
315 }
316 videobuf = if !self.is_24bit { NABufferType::Video(buf) } else { NABufferType::VideoPacked(buf) };
9895bd7b 317 } else {
a5e655a7
KS
318 let mut buf = bufinfo.get_vbuf16().unwrap();
319 let stride = buf.get_stride(0);
320 let data = buf.get_data_mut().unwrap();
321 for (inrow, outrow) in self.framebuf.chunks(self.width).zip(data.chunks_mut(stride)) {
322 for i in (0..self.width).step_by(2) {
323 outrow[i >> 1] = read_u16le(&inrow[i..])?;
324 }
325 }
326 videobuf = NABufferType::Video16(buf);
9895bd7b
KS
327 }
328
a5e655a7 329 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), videobuf);
9895bd7b
KS
330 frm.set_keyframe(is_intra);
331 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
171860fc 332 Ok(frm.into_ref())
9895bd7b 333 }
f9be4e75 334 fn flush(&mut self) {
f9be4e75 335 }
9895bd7b
KS
336}
337
338
08a1fab7 339pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
9895bd7b
KS
340 Box::new(VMDVideoDecoder::new())
341}
342
f45dfcf7
KS
343#[derive(Clone,Copy,PartialEq)]
344enum VMDAudioMode {
345 U8,
346 DPCM,
347 StereoDPCM,
979faef7 348 ADPCM,
f45dfcf7
KS
349}
350
9895bd7b
KS
351struct VMDAudioDecoder {
352 ainfo: NAAudioInfo,
f45dfcf7 353 info: Arc<NACodecInfo>,
9895bd7b 354 chmap: NAChannelMap,
9895bd7b
KS
355 blk_align: usize,
356 blk_size: usize,
f45dfcf7
KS
357 mode: VMDAudioMode,
358 pred: [i32; 2],
359 last_byte: Option<u8>,
360 is_odd: bool,
361 ch: usize,
9895bd7b
KS
362}
363
364const SOL_AUD_STEPS16: [i16; 128] = [
365 0x00, 0x08, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
366 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
367 0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160,
368 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0,
369 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
370 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270,
371 0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0,
372 0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0,
373 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330,
374 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
375 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0,
376 0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0,
377 0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580,
378 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780,
379 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
380 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
381];
382
383impl VMDAudioDecoder {
384 fn new() -> Self {
385 Self {
386 ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
f45dfcf7 387 info: NACodecInfo::new_dummy(),
9895bd7b 388 chmap: NAChannelMap::new(),
9895bd7b
KS
389 blk_align: 0,
390 blk_size: 0,
f45dfcf7
KS
391 mode: VMDAudioMode::U8,
392 pred: [0; 2],
393 last_byte: None,
394 is_odd: false,
395 ch: 0,
9895bd7b
KS
396 }
397 }
398 fn decode_16bit(&self, dst: &mut [i16], off1: usize, br: &mut ByteReader, nblocks: usize, mut mask: u32) -> DecoderResult<()> {
399 let channels = self.chmap.num_channels();
400 let mut off = [0, off1];
401 for _ in 0..nblocks {
402 if (mask & 1) != 0 {
403 for ch in 0..channels {
404 for i in 0..self.blk_align {
405 dst[off[ch] + i] = 0;
406 }
407 off[ch] += self.blk_align;
408 }
409 } else {
410 let mut pred: [i32; 2] = [0; 2];
411 for ch in 0..channels {
e69b1148 412 pred[ch] = i32::from(br.read_u16le()?);
9895bd7b
KS
413 dst[off[ch]] = pred[ch] as i16;
414 off[ch] += 1;
415 }
416 let mut ch = 0;
417 let flip_ch = if channels == 2 { 1 } else { 0 };
aa7e65d2 418 for _ in channels..self.blk_align*channels {
f45dfcf7 419 pred[ch] = Self::pred16(pred[ch], br.read_byte()?);
9895bd7b
KS
420 //pred[ch] = pred[ch].max(-32768).min(32767);
421 dst[off[ch]] = pred[ch] as i16;
422 off[ch] += 1;
423 ch ^= flip_ch;
424 }
425 }
426 mask >>= 1;
427 }
428 validate!(br.left() == 0);
429 Ok(())
430 }
f45dfcf7
KS
431 fn pred16(pred: i32, val: u8) -> i32 {
432 if (val & 0x80) != 0 {
433 pred - i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
434 } else {
435 pred + i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
436 }
437 }
438 fn cvt_u8(val: u8) -> u8 {
6eda3136 439 val ^ 0x80
f45dfcf7 440 }
9895bd7b
KS
441}
442
443impl NADecoder for VMDAudioDecoder {
01613464 444 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
9895bd7b
KS
445 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
446 let fmt;
f45dfcf7
KS
447 let channels = ainfo.get_channels() as usize;
448 let edata = info.get_extradata();
449 let flags = if let Some(ref buf) = edata {
450 validate!(buf.len() >= 2);
451 (buf[0] as u16) | ((buf[1] as u16) << 8)
452 } else {
453 0
454 };
455 validate!((channels == 1) ^ ((flags & 0x8200) != 0));
9895bd7b 456 if ainfo.get_format().get_bits() == 8 {
9895bd7b 457 self.blk_size = ainfo.get_block_len();
f45dfcf7
KS
458 self.blk_align = ainfo.get_block_len() / channels;
459 if (flags & 0x8000) == 0 {
460 fmt = SND_U8_FORMAT;
461 self.mode = VMDAudioMode::U8;
462 } else {
463 fmt = SND_S16_FORMAT;
464 self.mode = VMDAudioMode::StereoDPCM;
465 self.is_odd = (channels == 2) && ((self.blk_size & 1) != 0);
466 }
9895bd7b
KS
467 } else {
468 fmt = SND_S16P_FORMAT;
aa7e65d2 469 self.blk_align = ainfo.get_block_len();
979faef7
KS
470 if (flags & 0x10) == 0 {
471 self.blk_size = (ainfo.get_block_len() + 1) * channels;
472 self.mode = VMDAudioMode::DPCM;
473 } else {
3e91c67b 474 self.blk_size = (ainfo.get_block_len() + 1) / 2 + 3;
979faef7
KS
475 self.mode = VMDAudioMode::ADPCM;
476 }
9895bd7b 477 };
9895bd7b 478 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, ainfo.get_block_len());
f45dfcf7
KS
479 self.info = info.replace_info(NACodecTypeInfo::Audio(self.ainfo.clone()));
480 self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
9895bd7b
KS
481 Ok(())
482 } else {
483 Err(DecoderError::InvalidData)
484 }
485 }
01613464 486 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
9895bd7b
KS
487 let info = pkt.get_stream().get_info();
488 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
489 let pktbuf = pkt.get_buffer();
490 validate!(pktbuf.len() >= 6);
491 let mut mr = MemoryReader::new_read(&pktbuf);
492 let mut br = ByteReader::new(&mut mr);
493 let blk_type = br.read_byte()?;
494 br.read_skip(9)?;
495 let mask;
496 let nblocks;
497 if blk_type == 2 { // initial
498 mask = br.read_u32le()?;
499 nblocks = (mask.count_ones() as usize) + (pktbuf.len() - 14) / self.blk_size;
500 } else if blk_type == 3 { // silence
501 mask = 1;
502 nblocks = 1;
503 } else {
504 mask = 0;
505 nblocks = 1;
506 }
f45dfcf7
KS
507 let mut samples = nblocks * self.blk_align;
508 if self.mode == VMDAudioMode::StereoDPCM && self.is_odd {
509 samples += (nblocks + if self.last_byte.is_some() { 1 } else { 0 }) / 2;
510 }
9895bd7b 511 let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
f45dfcf7
KS
512 match self.mode {
513 VMDAudioMode::DPCM => {
514 let mut adata = abuf.get_abuf_i16().unwrap();
515 let off1 = adata.get_offset(1);
516 let mut dst = adata.get_data_mut().unwrap();
517 self.decode_16bit(&mut dst, off1, &mut br, nblocks, mask)?;
518 },
519 VMDAudioMode::U8 => {
520 let mut adata = abuf.get_abuf_u8().unwrap();
521 let dst = adata.get_data_mut().unwrap();
522 let mut doff = 0;
523 let mut mask = mask;
524 let channels = self.chmap.num_channels();
525 for _ in 0..nblocks {
526 if (mask & 1) != 0 {
527 for i in 0..self.blk_align * channels {
528 dst[doff + i] = 128;
529 }
530 } else if channels == 1 {
531 for i in 0..self.blk_size {
532 dst[doff + i] = br.read_byte()?;
533 }
534 } else {
535 for i in 0..self.blk_size {
536 let val = Self::cvt_u8(br.read_byte()?);
537 dst[doff + i] = val;
538 }
9895bd7b 539 }
f45dfcf7
KS
540 doff += self.blk_align * channels;
541 mask >>= 1;
542 }
543 },
544 VMDAudioMode::StereoDPCM => {
545 let mut adata = abuf.get_abuf_i16().unwrap();
546 let dst = adata.get_data_mut().unwrap();
547 let mut doff = 0;
548 let mut mask = mask;
549 let mut ch = self.ch;
550 for _ in 0..nblocks {
551 let put_sample = self.last_byte.is_some();
552 if let (true, Some(val)) = (self.is_odd, self.last_byte) {
553 self.pred[ch] = Self::pred16(self.pred[ch], val);
554 dst[doff] = self.pred[ch] as i16;
555 doff += 1;
556 ch ^= 1;
557 self.last_byte = None;
9895bd7b 558 }
f45dfcf7
KS
559 if (mask & 1) != 0 {
560 for i in 0..self.blk_align {
561 dst[doff + i * 2 + 0] = self.pred[ch] as i16;
562 dst[doff + i * 2 + 1] = self.pred[ch ^ 1] as i16;
563 }
564 if self.is_odd {
565 if put_sample {
566 dst[doff + self.blk_align * 2] = self.pred[ch] as i16;
567 doff += 1;
568 ch ^= 1;
569 } else {
570 self.last_byte = Some(0);
571 }
572 }
573 } else {
574 for i in 0..self.blk_align {
575 self.pred[ch] = Self::pred16(self.pred[ch], br.read_byte()?);
576 dst[doff + i * 2] = self.pred[ch] as i16;
577 self.pred[ch ^ 1] = Self::pred16(self.pred[ch ^ 1], br.read_byte()?);
578 dst[doff + i * 2 + 1] = self.pred[ch ^ 1] as i16;
579 }
580 if self.is_odd {
581 let val = br.read_byte()?;
582 if put_sample {
583 self.pred[ch] = Self::pred16(self.pred[ch], val);
584 dst[doff + self.blk_align * 2] = self.pred[ch] as i16;
585 doff += 1;
586 ch ^= 1;
587 } else {
588 self.last_byte = Some(val);
589 }
aa7e65d2
KS
590 }
591 }
f45dfcf7
KS
592 doff += self.blk_align * 2;
593 mask >>= 1;
9895bd7b 594 }
f45dfcf7
KS
595 self.ch = ch;
596 },
979faef7
KS
597 VMDAudioMode::ADPCM => {
598 let mut adata = abuf.get_abuf_i16().unwrap();
599 let dst = adata.get_data_mut().unwrap();
600 let mut doff = 0;
601 if self.chmap.num_channels() == 1 {
602 let mut mask = mask;
603 let mut ima = IMAState::new();
604 for _ in 0..nblocks {
605 if (mask & 1) != 0 {
3e91c67b 606 doff += self.blk_align;
979faef7
KS
607 mask >>= 1;
608 continue;
609 }
610 let pred = br.read_u16le()? as i16;
611 let step = br.read_byte()?;
612 validate!((step as usize) < IMA_STEP_TABLE.len());
613 ima.reset(pred, step);
3e91c67b
KS
614 let mut b = 0;
615 for i in 0..self.blk_align {
616 if (i & 1) == 0 {
617 b = br.read_byte()?;
618 dst[doff] = ima.expand_sample(b >> 4);
619 } else {
620 dst[doff] = ima.expand_sample(b & 0xF);
621 }
979faef7
KS
622 doff += 1;
623 }
624 mask >>= 1;
625 }
626 } else {
627 return Err(DecoderError::InvalidData);
628 }
629 },
f45dfcf7 630 };
9895bd7b 631
f45dfcf7 632 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
9895bd7b
KS
633 frm.set_duration(Some(samples as u64));
634 frm.set_keyframe(true);
171860fc 635 Ok(frm.into_ref())
9895bd7b
KS
636 } else {
637 Err(DecoderError::InvalidData)
638 }
639 }
f9be4e75
KS
640 fn flush(&mut self) {
641 }
9895bd7b
KS
642}
643
08a1fab7 644pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
9895bd7b
KS
645 Box::new(VMDAudioDecoder::new())
646}
647
648#[cfg(test)]
649mod test {
650 use nihav_core::codecs::RegisteredDecoders;
651 use nihav_core::demuxers::RegisteredDemuxers;
ce742854 652 use nihav_codec_support::test::dec_video::*;
e64739f8
KS
653 use crate::game_register_all_codecs;
654 use crate::game_register_all_demuxers;
9895bd7b
KS
655 #[test]
656 fn test_vmd_video() {
657 let mut dmx_reg = RegisteredDemuxers::new();
658 game_register_all_demuxers(&mut dmx_reg);
659 let mut dec_reg = RegisteredDecoders::new();
660 game_register_all_codecs(&mut dec_reg);
661
fe435580
KS
662 test_decoding("vmd", "vmd-video", "assets/Game/2832.VMD", Some(10), &dmx_reg, &dec_reg,
663 ExpectedTestResult::MD5Frames(vec![
664 [0xd29e0214, 0xf38ad154, 0xccbd381f, 0x3de1109c],
665 [0x904074eb, 0x202b1d6f, 0xe3f68538, 0xf0db641c],
666 [0x9c8b1b6c, 0xe205b8dc, 0xbfb07406, 0x993ace41],
667 [0x71ce4220, 0x8747fd05, 0x854dd86d, 0x2664cde5],
668 [0x3bc65fa4, 0xebb95292, 0xe0a0fea6, 0x0acfdea1],
669 [0x33982045, 0x8d11b69b, 0xac254a75, 0x63896a21],
670 [0xa667db33, 0x90e122d3, 0x2243da15, 0xcc4bffd2],
671 [0x518621c1, 0xb91412bc, 0x12312869, 0x141ef647],
672 [0x3069977e, 0x68fd3fa0, 0x2bfdb00d, 0x1e694684],
673 [0x246c12aa, 0x15137fb0, 0xa4b0fc3e, 0x626a2676],
674 [0x72cce7e3, 0x98506d04, 0xd4d8bbaf, 0x3cc5e32d]]));
9895bd7b
KS
675 }
676 #[test]
40e5d0b8
KS
677 fn test_vmd_video_16bpp() {
678 let mut dmx_reg = RegisteredDemuxers::new();
679 game_register_all_demuxers(&mut dmx_reg);
680 let mut dec_reg = RegisteredDecoders::new();
681 game_register_all_codecs(&mut dec_reg);
682
683 test_decoding("vmd", "vmd-video", "assets/Game/HLP1000.VMD", Some(10), &dmx_reg, &dec_reg,
684 ExpectedTestResult::MD5Frames(vec![
685 [0x03d77d51, 0x8670ae24, 0x86184cc8, 0x9c928700],
686 [0xf4796f1b, 0x0f75a120, 0x62056509, 0xc83f1a2c],
687 [0xd9e6db4d, 0x7af82082, 0xac6a335c, 0x19b8438f],
688 [0x03d77d51, 0x8670ae24, 0x86184cc8, 0x9c928700],
689 [0xd9e6db4d, 0x7af82082, 0xac6a335c, 0x19b8438f],
690 [0xf4796f1b, 0x0f75a120, 0x62056509, 0xc83f1a2c]]));
691 }
692 #[test]
693 fn test_vmd_video_24bpp() {
694 let mut dmx_reg = RegisteredDemuxers::new();
695 game_register_all_demuxers(&mut dmx_reg);
696 let mut dec_reg = RegisteredDecoders::new();
697 game_register_all_codecs(&mut dec_reg);
698
699 test_decoding("vmd", "vmd-video", "assets/Game/02C.VMD", None, &dmx_reg, &dec_reg,
700 ExpectedTestResult::MD5([0xb580782c, 0xd7fb98c0, 0xaf9b83cc, 0xaea0846b]));
701 }
702 #[test]
fe435580 703 fn test_vmd_audio_u8() {
9895bd7b
KS
704 let mut dmx_reg = RegisteredDemuxers::new();
705 game_register_all_demuxers(&mut dmx_reg);
706 let mut dec_reg = RegisteredDecoders::new();
707 game_register_all_codecs(&mut dec_reg);
708
fe435580
KS
709 test_decoding("vmd", "vmd-audio", "assets/Game/1491.VMD", None, &dmx_reg, &dec_reg,
710 ExpectedTestResult::MD5([0x75037601, 0xbc7b3976, 0x6e1c948b, 0xf05a3d6c]));
711 }
712 #[test]
713 fn test_vmd_audio_s16_old() {
714 let mut dmx_reg = RegisteredDemuxers::new();
715 game_register_all_demuxers(&mut dmx_reg);
716 let mut dec_reg = RegisteredDecoders::new();
717 game_register_all_codecs(&mut dec_reg);
718
719 test_decoding("vmd", "vmd-audio", "assets/Game/2832.VMD", None, &dmx_reg, &dec_reg,
720 ExpectedTestResult::MD5([0x32dcdf0e, 0xee058684, 0x43ed5bf1, 0x2ff18b5a]));
721 }
722 #[test]
723 fn test_vmd_audio_s16_new() {
724 let mut dmx_reg = RegisteredDemuxers::new();
725 game_register_all_demuxers(&mut dmx_reg);
726 let mut dec_reg = RegisteredDecoders::new();
727 game_register_all_codecs(&mut dec_reg);
728
729 test_decoding("vmd", "vmd-audio", "assets/Game/1000.VMD", None, &dmx_reg, &dec_reg,
730 ExpectedTestResult::MD5([0xc36215d3, 0x96530a80, 0x89f1fa8e, 0x49da302b]));
9895bd7b 731 }
40e5d0b8
KS
732 #[test]
733 fn test_vmd_audio_ima_adpcm() {
734 let mut dmx_reg = RegisteredDemuxers::new();
735 game_register_all_demuxers(&mut dmx_reg);
736 let mut dec_reg = RegisteredDecoders::new();
737 game_register_all_codecs(&mut dec_reg);
738
739 test_decoding("vmd", "vmd-audio", "assets/Game/HLP1000.VMD", None, &dmx_reg, &dec_reg,
740 ExpectedTestResult::MD5([0x76a00405, 0xe4e5378d, 0x495b2a68, 0x4dffe042]));
741 }
9895bd7b 742}