bink2: decode KB2i flags
[nihav.git] / nihav-rad / src / codecs / bink2.rs
index 4a4f5108587761c1238fb5d2062cba1a5e15bad8..2ad9246b8946c30667a5dd390a8239086d8b6ac9 100644 (file)
@@ -85,6 +85,7 @@ fn bink2_idct(coeffs: &mut [i32; 64]) {
 
 fn bink2_idct_old(coeffs: &mut [f32; 64]) {
     let mut tmp: [f32; 64] = [0.0; 64];
+    coeffs[0] += 512.5;
     for i in 0..8 {
         idct!(float; coeffs, 8, i, tmp, 8, i, 0, 0);
     }
@@ -110,7 +111,7 @@ macro_rules! luma_filter {
             let t0 = el!($src, $off - 0 * $step) + el!($src, $off + 1 * $step);
             let t1 = el!($src, $off - 1 * $step) + el!($src, $off + 2 * $step);
             let t2 = el!($src, $off - 2 * $step) + el!($src, $off + 3 * $step);
-            clip8((((t0 * 19) >> 1) - t1 * 2 + (t2 >> 1) + 8) >> 4)
+            (((t0 * 19) >> 1) - t1 * 2 + (t2 >> 1) + 8) >> 4
         });
 }
 
@@ -133,13 +134,30 @@ macro_rules! chroma_interp {
     };
 }
 
+macro_rules! avg_tree {
+    ($a: expr, $b: expr) => (($a + $b + 1) >> 1);
+    ($a: expr, $b: expr, $c: expr, $d: expr) => (avg_tree!(avg_tree!($a, $b), avg_tree!($c, $d)));
+}
+
 impl Bink2DSP {
     fn calc_dc(src: &[u8], stride: usize) -> i32 {
+        let mut sums = [0u16; 8];
+        for i in 0..8 {
+            let s0 = src[i + stride * 0] as u16;
+            let s1 = src[i + stride * 1] as u16;
+            let s2 = src[i + stride * 2] as u16;
+            let s3 = src[i + stride * 3] as u16;
+            let s4 = src[i + stride * 4] as u16;
+            let s5 = src[i + stride * 5] as u16;
+            let s6 = src[i + stride * 6] as u16;
+            let s7 = src[i + stride * 7] as u16;
+            sums[i] = avg_tree!(avg_tree!(s0, s1, s2, s3), avg_tree!(s4, s5, s6, s7));
+        }
         let mut sum = 0;
-        for row in src.chunks(stride).take(8) {
-            for i in 0..8 { sum += row[i] as i32; }
+        for e in sums.iter() {
+            sum += e;
         }
-        sum >> 3
+        sum as i32
     }
     fn put_mb4(dst: &mut [u8], mut off: usize, stride: usize, blk: &mut [[i32; 64]; 4]) {
         bink2_idct(&mut blk[0]);
@@ -191,16 +209,16 @@ impl Bink2DSP {
         {
             let dout = &mut dst[off..];
             for (row, (b0, b1)) in dout.chunks_mut(stride).zip(blk[0].chunks(8).zip(blk[1].chunks(8))) {
-                for i in 0..8 { row[i + 0] = clip8(b0[i] as i32); }
-                for i in 0..8 { row[i + 8] = clip8(b1[i] as i32); }
+                for i in 0..8 { row[i + 0] = clip8((b0[i] as i32) - 512); }
+                for i in 0..8 { row[i + 8] = clip8((b1[i] as i32) - 512); }
             }
         }
         off += stride * 8;
         {
             let dout = &mut dst[off..];
             for (row, (b2, b3)) in dout.chunks_mut(stride).zip(blk[2].chunks(8).zip(blk[3].chunks(8))) {
-                for i in 0..8 { row[i + 0] = clip8(b2[i] as i32); }
-                for i in 0..8 { row[i + 8] = clip8(b3[i] as i32); }
+                for i in 0..8 { row[i + 0] = clip8((b2[i] as i32) - 512); }
+                for i in 0..8 { row[i + 8] = clip8((b3[i] as i32) - 512); }
             }
         }
     }
@@ -212,16 +230,16 @@ impl Bink2DSP {
         {
             let dout = &mut dst[off..];
             for (row, (b0, b1)) in dout.chunks_mut(stride).zip(blk[0].chunks(8).zip(blk[1].chunks(8))) {
-                for i in 0..8 { row[i + 0] = clip8((row[i + 0] as i32) + (b0[i] as i32)); }
-                for i in 0..8 { row[i + 8] = clip8((row[i + 8] as i32) + (b1[i] as i32)); }
+                for i in 0..8 { row[i + 0] = clip8((row[i + 0] as i32) + (b0[i] as i32) - 512); }
+                for i in 0..8 { row[i + 8] = clip8((row[i + 8] as i32) + (b1[i] as i32) - 512); }
             }
         }
         off += stride * 8;
         {
             let dout = &mut dst[off..];
             for (row, (b2, b3)) in dout.chunks_mut(stride).zip(blk[2].chunks(8).zip(blk[3].chunks(8))) {
-                for i in 0..8 { row[i + 0] = clip8((row[i + 0] as i32) + (b2[i] as i32)); }
-                for i in 0..8 { row[i + 8] = clip8((row[i + 8] as i32) + (b3[i] as i32)); }
+                for i in 0..8 { row[i + 0] = clip8((row[i + 0] as i32) + (b2[i] as i32) - 512); }
+                for i in 0..8 { row[i + 8] = clip8((row[i + 8] as i32) + (b3[i] as i32) - 512); }
             }
         }
     }
@@ -233,8 +251,10 @@ impl Bink2DSP {
         let (d_y, add_y) = if (mv.y & 1) != 0 { (2, 5) } else { (0, 0) };
 
         let (w, h) = ref_pic.get_dimensions(plane);
-        validate!((sx - d_x >= 0) && (sx - d_x + add_x + 16 <= (w as isize)));
-        validate!((sy - d_y >= 0) && (sy - d_y + add_y + 16 <= (h as isize)));
+        let align_w = ((w + 31) & !31) as isize;
+        let align_h = ((h + 31) & !31) as isize;
+        validate!((sx - d_x >= 0) && (sx - d_x + add_x + 16 <= align_w));
+        validate!((sy - d_y >= 0) && (sy - d_y + add_y + 16 <= align_h));
         let pstride = ref_pic.get_stride(plane);
         let mut poff = ref_pic.get_offset(plane) + (sx as usize) + (sy as usize) * pstride;
         let pdata = ref_pic.get_data();
@@ -252,7 +272,7 @@ impl Bink2DSP {
             1 => {
                 for out in dst.chunks_mut(stride).take(16) {
                     for i in 0..16 {
-                        out[i] = luma_filter!(ppix, poff + i, 1);
+                        out[i] = clip8(luma_filter!(ppix, poff + i, 1));
                     }
                     poff += pstride;
                 }
@@ -260,22 +280,22 @@ impl Bink2DSP {
             2 => {
                 for out in dst.chunks_mut(stride).take(16) {
                     for i in 0..16 {
-                        out[i] = luma_filter!(ppix, poff + i, pstride);
+                        out[i] = clip8(luma_filter!(ppix, poff + i, pstride));
                     }
                     poff += pstride;
                 }
             },
             3 => {
-                let mut tmp = [0u8; 21 * 16];
+                let mut tmp = [0i16; 21 * 16];
                 for out in tmp.chunks_mut(16) {
                     for i in 0..16 {
-                        out[i] = luma_filter!(ppix, poff - 2 * pstride + i, 1);
+                        out[i] = luma_filter!(ppix, poff - 2 * pstride + i, 1) as i16;
                     }
                     poff += pstride;
                 }
                 for (row, out) in dst.chunks_mut(stride).take(16).enumerate() {
                     for i in 0..16 {
-                        out[i] = luma_filter!(tmp, (row + 2) * 16 + i, 16);
+                        out[i] = clip8(luma_filter!(tmp, (row + 2) * 16 + i, 16));
                     }
                 }
             },
@@ -292,8 +312,10 @@ impl Bink2DSP {
         let add_y = if my != 0 { 1 } else { 0 };
 
         let (w, h) = ref_pic.get_dimensions(plane);
-        validate!((sx >= 0) && (sx + add_x + 8 <= (w as isize)));
-        validate!((sy >= 0) && (sy + add_y + 8 <= (h as isize)));
+        let align_w = ((w + 15) & !15) as isize;
+        let align_h = ((h + 15) & !15) as isize;
+        validate!((sx >= 0) && (sx + add_x + 8 <= align_w));
+        validate!((sy >= 0) && (sy + add_y + 8 <= align_h));
         let pstride = ref_pic.get_stride(plane);
         let poff = ref_pic.get_offset(plane) + (sx as usize) + (sy as usize) * pstride;
         let pdata = ref_pic.get_data();
@@ -994,7 +1016,7 @@ impl Bink2Decoder {
         let mut data = buf.get_data_mut();
         let dst = data.as_mut_slice();
         let bw = (width  + 31) >> 5;
-        let bh = (height + 31) >> 6;
+        let bheight = (height + 31) >> 5;
         self.cur_w = (width + 7) & !7;
         self.cur_h = ((height + 7) & !7) >> 1;
 
@@ -1004,26 +1026,39 @@ impl Bink2Decoder {
 println!("fill {:X}", frame_flags);
 unimplemented!();
         }
+        let mut row_flags: Vec<bool> = Vec::with_capacity(bheight * 4);
+        let mut col_flags: Vec<bool> = Vec::with_capacity(bw * 4);
+        if (frame_flags & 0x10000) != 0 {
+            if (frame_flags & 0x8000) == 0 {
+                decode_flags(br, &mut row_flags, 1, bheight * 4 - 1)?;
+            } else {
+                row_flags.resize(bheight * 4, false);
+            }
+            if (frame_flags & 0x4000) == 0 {
+                decode_flags(br, &mut col_flags, 1, bw * 4 - 1)?;
+            } else {
+                col_flags.resize(bw * 4, false);
+            }
+        } else {
+            row_flags.resize(bheight * 4, false);
+            col_flags.resize(bw * 4, false);
+        }
+        //store frame_flags  * 8 & 0x7F8
+
         for slice_no in 0..2 {
-            if slice_no == 1 {
+            let bh;
+            let yoff;
+            if slice_no == 0 {
+                bh = bheight >> 1;
+                yoff = 0;
+            } else {
+                bh = bheight - (bheight >> 1);
                 br.seek(offset2 * 8)?;
-                off_y = ooff_y + stride_y * bh * 32;
-                off_u = ooff_u + stride_u * bh * 16;
-                off_v = ooff_v + stride_v * bh * 16;
-            }
-            let mut row_flags: Vec<u8> = Vec::with_capacity(height >> 3);
-            let mut col_flags: Vec<u8> = Vec::with_capacity(width >> 3);
-            if (frame_flags & 0x1000) != 0 {
-                if (frame_flags & 0x8000) != 0 {
-                    decode_flags(br, &mut row_flags, 1, (height >> 3) - 1)?;
-                }
-                if (frame_flags & 0x4000) != 0 {
-                    decode_flags(br, &mut col_flags, 1, (width >> 3) - 1)?;
-                }
+                off_y = ooff_y + stride_y * (bheight >> 1) * 32;
+                off_u = ooff_u + stride_u * (bheight >> 1) * 16;
+                off_v = ooff_v + stride_v * (bheight >> 1) * 16;
+                yoff = bheight >> 1;
             }
-            row_flags.resize(height >> 3, 0);
-            col_flags.resize(width >> 3, 0);
-            //store frame_flags  * 8 & 0x7F8
 
             let mut row_state = frame_flags & 0x2E000;
             if is_intra {
@@ -1047,7 +1082,7 @@ unimplemented!();
                 let mut q_y_p = 8;
                 let mut q_u_p = 8;
                 let mut q_v_p = 8;
-                let rflags = (row_flags[by >> 1] >> (if (by & 1) != 0 { 4 } else { 0 })) as u32;
+                let rflags = (row_flags[by + yoff] as u32) * 4;
                 row_state = (row_state & 0x3FFFFFF) | ((row_state >> 4) & 0xC000000) | (rflags << 28);
                 if by == 0 {
                     row_state |= 0x80;
@@ -1072,7 +1107,7 @@ unimplemented!();
                     if (bx & 1) != 0 {
                         blk_state |= 0x200;
                     }
-                    let clflags = (col_flags[bx >> 1] >> (if (bx & 1) != 0 { 4 } else { 0 })) as u32;
+                    let clflags = (col_flags[bx] as u32) * 4;
                     let edge_state_c = ((blk_state >> 4) & 0x3C0000) | (blk_state & 0xFC03FFFF) | ((clflags & 0xF) << 22);
                     let edge_state_y = (frame_flags & 0x40000) | (blk_state & 0x3FFFF);
                     edge_state = edge_state_c;
@@ -1158,7 +1193,7 @@ unimplemented!();
                             if let Some(ref ref_pic) = self.ips.get_ref() {
                                 for blk_no in 0..4 {
                                     let xoff = bx * 32 + (blk_no & 1) * 16;
-                                    let yoff = slice_no * bh * 32 + by * 32 + (blk_no & 2) * 8;
+                                    let yoff = slice_no * (bheight >> 1) * 32 + by * 32 + (blk_no & 2) * 8;
                                     Bink2DSP::mc_luma(&mut dst[off_y..], stride_y, ref_pic, xoff, yoff, ZERO_MV, 0)?;
                                     Bink2DSP::mc_chroma(&mut dst[off_u..], stride_u, ref_pic, xoff >> 1, yoff >> 1, ZERO_MV, 1)?;
                                     Bink2DSP::mc_chroma(&mut dst[off_v..], stride_v, ref_pic, xoff >> 1, yoff >> 1, ZERO_MV, 2)?;
@@ -1177,7 +1212,7 @@ unimplemented!();
                             if let Some(ref ref_pic) = self.ips.get_ref() {
                                 for blk_no in 0..4 {
                                     let xoff = bx * 32 + (blk_no & 1) * 16;
-                                    let yoff = slice_no * bh * 32 + by * 32 + (blk_no & 2) * 8;
+                                    let yoff = slice_no * (bheight >> 1) * 32 + by * 32 + (blk_no & 2) * 8;
                                     let mv = self.mvs.get_mv(bx, blk_no);
                                     Bink2DSP::mc_luma(&mut dst[off_y..], stride_y, ref_pic, xoff, yoff, mv, 0)?;
                                     Bink2DSP::mc_chroma(&mut dst[off_u..], stride_u, ref_pic, xoff >> 1, yoff >> 1, mv, 1)?;
@@ -1196,7 +1231,7 @@ unimplemented!();
                             if let Some(ref ref_pic) = self.ips.get_ref() {
                                 for blk_no in 0..4 {
                                     let xoff = bx * 32 + (blk_no & 1) * 16;
-                                    let yoff = slice_no * bh * 32 + by * 32 + (blk_no & 2) * 8;
+                                    let yoff = slice_no * (bheight >> 1) * 32 + by * 32 + (blk_no & 2) * 8;
                                     let mv = self.mvs.get_mv(bx, blk_no);
                                     Bink2DSP::mc_luma(&mut dst[off_y..], stride_y, ref_pic, xoff, yoff, mv, 0)?;
                                     Bink2DSP::mc_chroma(&mut dst[off_u..], stride_u, ref_pic, xoff >> 1, yoff >> 1, mv, 1)?;
@@ -1279,43 +1314,33 @@ unimplemented!();
     }
 }
 
-fn decode_flags(_br: &mut BitReader, _dst: &mut Vec<u8>, _start: usize, _nbits: usize) -> DecoderResult<u32> {
-unimplemented!();
-/*    if !br.read_bool()? { // read bits into byte array?
-        if nbits == 0 { return Ok(()); }
-        if nbits < 9 {
-            shift = in_shift;
-            pfx = 0;
-        } else {
-            shift = in_shift;
-            loop {
-                pfx |= br.read(8)? << shift;
-                dst.push((pfx & 0xFF) as u8);
-                pfx >>= 8;
-                shift -= 8;
-            }
+fn decode_flags(br: &mut BitReader, dst: &mut Vec<bool>, start: usize, nbits: usize) -> DecoderResult<()> {
+    if start > 0 {
+        dst.push(false);
+    }
+    if !br.read_bool()? {
+        for _ in 0..nbits {
+            let bit                             = br.read_bool()?;
+            dst.push(bit);
         }
-        let val                                 = br.read(cur_nbits)?;
-        dst.push(pfx | (val << shift))
     } else {
         let mut cur_bits = nbits;
         let mut mode = 0;
-        let mut lastbit = 0;
+        let mut lastbit = false;
         while cur_bits > 0 {
             if !br.read_bool()? {
-                lastbit = if mode == 3 { lastbit ^ 1 } else { br.read(1)? };
-                let val1 = lastval | (lastbit << shift);
-                let val2 = br.read(if cur_bits > 4 { 4 } else { cur_bits });
-                let val = lastval | (lastbit << shift) | (val2 << (shift + 1));
-                mode = 2;
-                if oshift >= 8 {
-                    dst.push((val & 0xFF) as u8);
-                    oshift -= 8;
-                    val >>= 8;
+                lastbit = if mode == 3 { !lastbit } else { br.read_bool()? };
+                dst.push(lastbit);
+                cur_bits -= 1;
+                let len = cur_bits.min(4);
+                for _ in 0..len {
+                    let bit                     = br.read_bool()?;
+                    dst.push(bit);
                 }
-                lastval = val;
+                cur_bits -= len;
+                mode = 2;
             } else {
-                let bread;
+                let bread: u8;
                 if cur_bits < 4 {
                     bread = 2;
                 } else if cur_bits < 16 {
@@ -1323,20 +1348,21 @@ unimplemented!();
                 } else {
                     bread = 4 | 1;
                 }
-                lastbit = if mode == 3 { lastbit ^ 1 } else { br.read(1)? };
-                run = (if mode == 3 { bread + 1 } else { bread + 2 }).min(cur_bits);
-                if run == cur_bits {
-                    output lastbit x run
-                } else {
+                lastbit = if mode == 3 { !lastbit } else { br.read_bool()? };
+                let mut run = (if mode == 3 { bread + 1 } else { bread + 2 } as usize).min(cur_bits);
+                if run != cur_bits {
                     let add_run = br.read(bread)? as usize;
                     run += add_run;
-                    output lastbit x run
-                    mode = if add_run == (1 << bread) - 1 { 3 } else { 1 };
+                    mode = if add_run == (1 << bread) - 1 { 1 } else { 3 };
+                }
+                for _ in 0..run {
+                    dst.push(lastbit);
                 }
+                cur_bits -= run;
             }
         }
     }
-    Ok(())*/
+    Ok(())
 }
 
 fn get_new_quant(br: &mut BitReader, prev_q: u8) -> DecoderResult<u8> {
@@ -1794,7 +1820,7 @@ impl NADecoder for Bink2Decoder {
         let mut buf;
         self.key_frame = pkt.is_keyframe();
 
-        let bufret = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4);
+        let bufret = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 5);
         if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
         let bufinfo = bufret.unwrap();
         buf = bufinfo.get_vbuf().unwrap();
@@ -1831,7 +1857,7 @@ mod test {
         //let file = "assets/RAD/sc13_01_partial.bk2";
         let file = "assets/RAD/ge_video_86l.bk2";
         //let file = "assets/RAD/eg_club_0.bk2";
-        test_file_decoding("bink", file, Some(42), true, false, Some("bink2"), &dmx_reg, &dec_reg);
+        test_file_decoding("bink", file, Some(8), true, false, None/*Some("bink2")*/, &dmx_reg, &dec_reg);
     }
 }