]> git.nihav.org Git - nihav.git/blobdiff - nihav-game/src/codecs/vmd.rs
move IMA ADPCM decoder into codec_support
[nihav.git] / nihav-game / src / codecs / vmd.rs
index 0e9aa5b90c618277fd096c85e7a1a5f4d86db3c2..520b57ce8ef6af3a7f7da8866ac4c967ac903570 100644 (file)
@@ -85,9 +85,11 @@ fn rle_unpack(br: &mut ByteReader, len: usize, dst: &mut [u8]) -> DecoderResult<
             let dst = &mut dst[dpos..][..len];
             br.read_buf(dst)?;
         } else {
-            let val = br.read_byte()?;
-            for i in 0..len {
-                dst[dpos + i] = val;
+            let val1 = br.read_byte()?;
+            let val2 = br.read_byte()?;
+            for i in (0..len).step_by(2) {
+                dst[dpos + i] = val1;
+                dst[dpos + i + 1] = val2;
             }
         }
         dpos += len;
@@ -154,6 +156,8 @@ struct VMDVideoDecoder {
     buf:        Vec<u8>,
     width:      usize,
     height:     usize,
+    xoff:       usize,
+    yoff:       usize,
     hams:       HAMShuffler,
 }
 
@@ -165,6 +169,8 @@ impl VMDVideoDecoder {
             buf:        Vec::new(),
             width:      0,
             height:     0,
+            xoff:       0,
+            yoff:       0,
             hams:       HAMShuffler::default(),
         }
     }
@@ -184,8 +190,9 @@ impl VMDVideoDecoder {
         if (frame_x == 0xFFFF) && (frame_y == 0xFFFF) && (frame_l == 0xFFFF) && (frame_d == 0xFFFF) {
             return Ok(false);
         }
+        validate!(frame_x >= self.xoff && frame_y >= self.yoff);
         validate!(frame_l >= frame_x && frame_d >= frame_y);
-        validate!(frame_l < self.width && frame_d < self.height);
+        validate!(frame_l - self.xoff < self.width && frame_d - self.yoff < self.height);
 
         if has_pal {
                                                   br.read_skip(2)?;
@@ -202,7 +209,7 @@ impl VMDVideoDecoder {
 
         let w = frame_l + 1 - frame_x;
         let h = frame_d + 1 - frame_y;
-        let dpos = frame_x + frame_y * stride;
+        let dpos = frame_x - self.xoff + (frame_y - self.yoff) * stride;
 
         let method                              = br.read_byte()?;
         let is_intra;
@@ -231,12 +238,14 @@ impl NADecoder for VMDVideoDecoder {
             if let Some(ref edata) = info.get_extradata() {
                 validate!(edata.len() == 0x330);
                 let unp_size = read_u32le(&edata[800..])? as usize;
-                validate!(unp_size < self.width * self.height * 3 + 64); // just for sanity
+                validate!(unp_size < self.width * self.height * 4 + 64); // just for sanity
                 self.buf.resize(unp_size, 0);
                 for i in 0..768 {
                     let el = edata[28 + i];
                     self.pal[i] = (el << 2) | (el >> 4);
                 }
+                self.xoff = read_u16le(&edata[8..])? as usize;
+                self.yoff = read_u16le(&edata[10..])? as usize;
             }
 
             Ok(())
@@ -374,11 +383,7 @@ impl VMDAudioDecoder {
         }
     }
     fn cvt_u8(val: u8) -> u8 {
-        if val < 128 {
-            127 - val
-        } else {
-            val
-        }
+        val ^ 0x80
     }
 }
 
@@ -563,21 +568,48 @@ mod test {
         let mut dec_reg = RegisteredDecoders::new();
         game_register_all_codecs(&mut dec_reg);
 
-//        let file = "assets/Game/1491.VMD";
-        let file = "assets/Game/128.vmd";
-        test_file_decoding("vmd", file, Some(10), true, false, None/*Some("vmd")*/, &dmx_reg, &dec_reg);
+        test_decoding("vmd", "vmd-video", "assets/Game/2832.VMD", Some(10), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0xd29e0214, 0xf38ad154, 0xccbd381f, 0x3de1109c],
+                            [0x904074eb, 0x202b1d6f, 0xe3f68538, 0xf0db641c],
+                            [0x9c8b1b6c, 0xe205b8dc, 0xbfb07406, 0x993ace41],
+                            [0x71ce4220, 0x8747fd05, 0x854dd86d, 0x2664cde5],
+                            [0x3bc65fa4, 0xebb95292, 0xe0a0fea6, 0x0acfdea1],
+                            [0x33982045, 0x8d11b69b, 0xac254a75, 0x63896a21],
+                            [0xa667db33, 0x90e122d3, 0x2243da15, 0xcc4bffd2],
+                            [0x518621c1, 0xb91412bc, 0x12312869, 0x141ef647],
+                            [0x3069977e, 0x68fd3fa0, 0x2bfdb00d, 0x1e694684],
+                            [0x246c12aa, 0x15137fb0, 0xa4b0fc3e, 0x626a2676],
+                            [0x72cce7e3, 0x98506d04, 0xd4d8bbaf, 0x3cc5e32d]]));
+    }
+    #[test]
+    fn test_vmd_audio_u8() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        game_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        game_register_all_codecs(&mut dec_reg);
+
+        test_decoding("vmd", "vmd-audio", "assets/Game/1491.VMD", None, &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0x75037601, 0xbc7b3976, 0x6e1c948b, 0xf05a3d6c]));
+    }
+    #[test]
+    fn test_vmd_audio_s16_old() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        game_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        game_register_all_codecs(&mut dec_reg);
+
+        test_decoding("vmd", "vmd-audio", "assets/Game/2832.VMD", None, &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0x32dcdf0e, 0xee058684, 0x43ed5bf1, 0x2ff18b5a]));
     }
     #[test]
-    fn test_vmd_audio() {
+    fn test_vmd_audio_s16_new() {
         let mut dmx_reg = RegisteredDemuxers::new();
         game_register_all_demuxers(&mut dmx_reg);
         let mut dec_reg = RegisteredDecoders::new();
         game_register_all_codecs(&mut dec_reg);
 
-//        let file = "assets/Game/1491.VMD";
-        let file = "assets/Game/128.vmd";
-//        let file = "assets/Game/1000.VMD";
-//        let file = "assets/Game/235.VMD";
-        test_decode_audio("vmd", file, None, None/*Some("vmd")*/, &dmx_reg, &dec_reg);
+        test_decoding("vmd", "vmd-audio", "assets/Game/1000.VMD", None, &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xc36215d3, 0x96530a80, 0x89f1fa8e, 0x49da302b]));
     }
 }