]> git.nihav.org Git - nihav.git/blobdiff - nihav-game/src/codecs/vmd.rs
vmd: fix RLE decoding
[nihav.git] / nihav-game / src / codecs / vmd.rs
index 32041cebe3bf4a9b77adf4dd338181ad625c7d79..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(())