rv20: validate slice start
[nihav.git] / nihav-realmedia / src / codecs / rv20.rs
index 7f24650298c68ad701393a3d5b352f47c8338f08..0e743969d306795bfe5ebeb4aaec9833229ca282 100644 (file)
@@ -131,19 +131,63 @@ impl BlockDSP for RV20BlockDSP {
             idct!(&tmp[i..], 8, &mut blk[i..], 8, 1 << 19, 20, i16);
         }
     }
-    fn copy_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) {
-        let srcx = ((mv.x >> 1) as isize) + (xpos as isize);
-        let srcy = ((mv.y >> 1) as isize) + (ypos as isize);
+    fn copy_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mv: MV) {
         let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
+        let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 });
 
-        blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_FUNCS);
+        let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
+
+        blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_FUNCS);
+        blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS);
+        blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS);
+    }
+    fn copy_blocks8x8(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mvs: &[MV; 4]) {
+        let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
+
+        for i in 0..4 {
+            let xadd = (i & 1) * 8;
+            let yadd = (i & 2) * 4;
+            let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize;
+
+            blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS);
+        }
+
+        let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
+        let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize];
+        let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize];
+        let mode = ((cmx & 1) + (cmy & 1) * 2) as usize;
+        for plane in 1..3 {
+            blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS);
+        }
     }
-    fn avg_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) {
-        let srcx = ((mv.x >> 1) as isize) + (xpos as isize);
-        let srcy = ((mv.y >> 1) as isize) + (ypos as isize);
+    fn avg_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mv: MV) {
         let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
+        let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 });
 
-        blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_AVG_FUNCS);
+        let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
+
+        blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_AVG_FUNCS);
+        blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS);
+        blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS);
+    }
+    fn avg_blocks8x8(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mvs: &[MV; 4]) {
+        let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
+
+        for i in 0..4 {
+            let xadd = (i & 1) * 8;
+            let yadd = (i & 2) * 4;
+            let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize;
+
+            blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS);
+        }
+
+        let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
+        let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize];
+        let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize];
+        let mode = ((cmx & 1) + (cmy & 1) * 2) as usize;
+        for plane in 1..3 {
+            blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS);
+        }
     }
     fn filter_row(&self, buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
         h263_filter_row(buf, mb_y, mb_w, cbpi)
@@ -309,6 +353,7 @@ impl<'a> BlockDecoder for RealVideo20BR<'a> {
         if self.slice_no < self.num_slices {
             let pos = self.br.tell();
             let shdr2 = self.read_slice_header()?;
+            validate!(shdr2.mb_pos > shdr.mb_pos);
             mb_count = shdr2.mb_pos - shdr.mb_pos;
             self.br.seek(pos as u32)?;
         } else {
@@ -640,7 +685,29 @@ mod test {
         let mut dec_reg = RegisteredDecoders::new();
         realmedia_register_all_codecs(&mut dec_reg);
 
-        test_file_decoding("realmedia", "assets/RV/rv20_svt_atrc_640x352_realproducer_plus_8.51.rm", /*None*/Some(3000), true, false, None/*Some("rv20")*/, &dmx_reg, &dec_reg);
-//        test_file_decoding("realmedia", "assets/RV/rv20_cook_640x352_realproducer_plus_8.51.rm", /*None*/Some(1000), true, false, Some("rv20"));
+        test_decoding("realmedia", "realvideo2",
+                      "assets/RV/rv20_svt_atrc_640x352_realproducer_plus_8.51.rm",
+                      Some(1000), &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x8ce88686, 0x03ca3bb9, 0x0d18347b, 0xccdb0bc5],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0x319d142d, 0x607a7c28, 0x526a2794, 0xa6e7864f],
+                        [0xa2008d4c, 0xf4684b3a, 0xecd0526c, 0xf0742a77],
+                        [0xafe0df5b, 0x29cd2418, 0x29a265c7, 0x9b4f2218],
+                        [0x0e0529df, 0xf1cc3f03, 0x03986b0d, 0xd2033c08],
+                        [0x4662b5ab, 0xaca5ca35, 0x4d089fb2, 0xc6a3df1e],
+                        [0x22c978cf, 0x6887a9ba, 0xe74c9316, 0x8cbdd29b],
+                        [0x12d8b88f, 0x59ebe632, 0xbcfaa336, 0xadbdd9ad],
+                        [0x0d99c67b, 0x3231302f, 0x3612b0d0, 0x38b5414d],
+                        [0x2f65b75e, 0x1239d563, 0x832ce096, 0x568a9bc2]]));
     }
 }