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