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