RealVideo 4 encoder
[nihav.git] / nihav-realmedia / src / codecs / rv40enc / dsp / ipred.rs
diff --git a/nihav-realmedia/src/codecs/rv40enc/dsp/ipred.rs b/nihav-realmedia/src/codecs/rv40enc/dsp/ipred.rs
new file mode 100644 (file)
index 0000000..f5df3d2
--- /dev/null
@@ -0,0 +1,562 @@
+use super::super::types::{PredType8x8, PredType4x4};
+use super::RefMBData;
+
+#[derive(Default)]
+pub struct IntraPred16x16 {
+    pub top:    [u8; 17],
+    pub left:   [u8; 17],
+}
+
+impl IntraPred16x16 {
+    pub fn new() -> Self { Self::default() }
+    #[allow(clippy::many_single_char_names)]
+    pub fn apply16(&self, mode: PredType8x8, dst: &mut [u8], stride: usize) {
+        match mode {
+            PredType8x8::DC => {
+                let sumt = self.top[1..].iter().fold(0u32, |acc, &x| acc + u32::from(x));
+                let suml = self.left[1..].iter().fold(0u32, |acc, &x| acc + u32::from(x));
+                let dc = ((sumt + suml + 16) >> 5) as u8;
+                for line in dst.chunks_mut(stride).take(16) {
+                    for dst in line[..16].iter_mut() {
+                        *dst = dc;
+                    }
+                }
+            },
+            PredType8x8::Hor => {
+                for (&left, line) in self.left[1..].iter().zip(dst.chunks_mut(stride)) {
+                    for dst in line[..16].iter_mut() {
+                        *dst = left;
+                    }
+                }
+            },
+            PredType8x8::Ver => {
+                for line in dst.chunks_mut(stride).take(16) {
+                    line[..16].copy_from_slice(&self.top[1..]);
+                }
+            },
+            PredType8x8::Plane => {
+                let top0 = &self.top[9..];
+                let top1 = &self.top[..8];
+                let h = top0.iter().zip(top1.iter().rev()).enumerate().fold(
+                            0i32, |acc, (k, (&a, &b))| acc + ((k + 1) as i32) * (i32::from(a) - i32::from(b)));
+                let left0 = &self.left[9..];
+                let left1 = &self.left[..8];
+                let v = left0.iter().zip(left1.iter().rev()).enumerate().fold(
+                            0i32, |acc, (k, (&a, &b))| acc + ((k + 1) as i32) * (i32::from(a) - i32::from(b)));
+                let b = (h + (h >> 2)) >> 4;
+                let c = (v + (v >> 2)) >> 4;
+                let mut a = 16 * (i32::from(self.left[16]) + i32::from(self.top[16])) + 16 - 7 * (b + c);
+
+                for line in dst.chunks_mut(stride).take(16) {
+                    let mut oval = a;
+                    for el in line[..16].iter_mut() {
+                        *el = (oval >> 5).max(0).min(255) as u8;
+                        oval += b;
+                    }
+                    a += c;
+                }
+            },
+            PredType8x8::LeftDC => {
+                let dc = ((self.left[1..].iter().fold(0u32, |acc, &x| acc + u32::from(x)) + 8) >> 4) as u8;
+                for line in dst.chunks_mut(stride).take(16) {
+                    for dst in line[..16].iter_mut() {
+                        *dst = dc;
+                    }
+                }
+            },
+            PredType8x8::TopDC => {
+                let dc = ((self.top[1..].iter().fold(0u32, |acc, &x| acc + u32::from(x)) + 8) >> 4) as u8;
+                for line in dst.chunks_mut(stride).take(16) {
+                    for dst in line[..16].iter_mut() {
+                        *dst = dc;
+                    }
+                }
+            },
+            PredType8x8::DC128 => {
+                for line in dst.chunks_mut(stride).take(16) {
+                    for dst in line[..16].iter_mut() {
+                        *dst = 128;
+                    }
+                }
+            },
+        }
+    }
+    pub fn apply8(&self, mode: PredType8x8, dst: &mut [u8], stride: usize) {
+        match mode {
+            PredType8x8::DC | PredType8x8::Plane => {
+                let sumt = self.top[1..9].iter().fold(0u32, |acc, &x| acc + u32::from(x));
+                let suml = self.left[1..9].iter().fold(0u32, |acc, &x| acc + u32::from(x));
+                let dc = ((sumt + suml + 8) >> 4) as u8;
+                for line in dst.chunks_mut(stride).take(8) {
+                    for dst in line[..8].iter_mut() {
+                        *dst = dc;
+                    }
+                }
+            },
+            PredType8x8::Hor => {
+                for (&left, line) in self.left[1..9].iter().zip(dst.chunks_mut(stride)) {
+                    for dst in line[..8].iter_mut() {
+                        *dst = left;
+                    }
+                }
+            },
+            PredType8x8::Ver => {
+                for line in dst.chunks_mut(stride).take(8) {
+                    line[..8].copy_from_slice(&self.top[1..9]);
+                }
+            },
+            PredType8x8::LeftDC => {
+                let dc = ((self.left[1..9].iter().fold(0u32, |acc, &x| acc + u32::from(x)) + 4) >> 3) as u8;
+                for line in dst.chunks_mut(stride).take(8) {
+                    for dst in line[..8].iter_mut() {
+                        *dst = dc;
+                    }
+                }
+            },
+            PredType8x8::TopDC => {
+                let dc = ((self.top[1..9].iter().fold(0u32, |acc, &x| acc + u32::from(x)) + 4) >> 3) as u8;
+                for line in dst.chunks_mut(stride).take(8) {
+                    for dst in line[..8].iter_mut() {
+                        *dst = dc;
+                    }
+                }
+            },
+            PredType8x8::DC128 => {
+                for line in dst.chunks_mut(stride).take(8) {
+                    for dst in line[..8].iter_mut() {
+                        *dst = 128;
+                    }
+                }
+            },
+        }
+    }
+}
+
+#[derive(Default)]
+pub struct Intra4Pred {
+    pub top:  [u8; 8],
+    pub left: [u8; 8],
+    pub tl:   u8,
+}
+
+impl Intra4Pred {
+    pub fn new() -> Self { Self::default() }
+    fn load_left(&self) -> [u16; 8] {
+        let mut ret = [0; 8];
+        for (dst, &src) in ret.iter_mut().zip(self.left.iter()) {
+            *dst = u16::from(src);
+        }
+        ret
+    }
+    fn load_top(&self) -> [u16; 8] {
+        let mut ret = [0; 8];
+        for (dst, &src) in ret.iter_mut().zip(self.top.iter()) {
+            *dst = u16::from(src);
+        }
+        ret
+    }
+    fn load_left_and_top(&self) -> ([u16; 5], [u16; 5]) {
+        let mut left = [0; 5];
+        let mut top = [0; 5];
+        left[0] = u16::from(self.tl);
+        top[0] = u16::from(self.tl);
+        for (dst, &src) in left[1..].iter_mut().zip(self.left.iter()) {
+            *dst = u16::from(src);
+        }
+        for (dst, &src) in top[1..].iter_mut().zip(self.top.iter()) {
+            *dst = u16::from(src);
+        }
+        (left, top)
+    }
+    #[allow(clippy::many_single_char_names)]
+    pub fn apply(&self, ptype: PredType4x4, buf: &mut [u8], stride: usize) {
+        match ptype {
+            PredType4x4::DC => {
+                let dc_l = self.left[..4].iter().fold(0u32, |acc, &x| acc + u32::from(x));
+                let dc_t = self.top [..4].iter().fold(0u32, |acc, &x| acc + u32::from(x));
+                let dc = ((dc_t + dc_l + 4) >> 3) as u8;
+                for line in buf.chunks_mut(stride).take(4) {
+                    for el in line[..4].iter_mut() {
+                        *el = dc;
+                    }
+                }
+            },
+            PredType4x4::LeftDC => {
+                let dc_l = self.left[..4].iter().fold(0u32, |acc, &x| acc + u32::from(x));
+                let dc = ((dc_l + 2) >> 2) as u8;
+                for line in buf.chunks_mut(stride).take(4) {
+                    for el in line[..4].iter_mut() {
+                        *el = dc;
+                    }
+                }
+            },
+            PredType4x4::TopDC => {
+                let dc_t = self.top [..4].iter().fold(0u32, |acc, &x| acc + u32::from(x));
+                let dc = ((dc_t + 2) >> 2) as u8;
+                for line in buf.chunks_mut(stride).take(4) {
+                    for el in line[..4].iter_mut() {
+                        *el = dc;
+                    }
+                }
+            },
+            PredType4x4::DC128 => {
+                for line in buf.chunks_mut(stride).take(4) {
+                    for el in line[..4].iter_mut() {
+                        *el = 128;
+                    }
+                }
+            },
+            PredType4x4::Ver => {
+                for line in buf.chunks_mut(stride).take(4) {
+                    line[..4].copy_from_slice(&self.top[..4]);
+                }
+            },
+            PredType4x4::Hor => {
+                for (&left, line) in self.left[..4].iter().zip(buf.chunks_mut(stride)) {
+                    for dst in line[..4].iter_mut() {
+                        *dst = left;
+                    }
+                }
+            },
+            PredType4x4::DiagDownLeft => {
+                let l = self.load_left();
+                let t = self.load_top();
+                buf[0] = ((t[0] + t[2] + 2*t[1] + 2 + l[0] + l[2] + 2*l[1] + 2) >> 3) as u8;
+                let pix = ((t[1] + t[3] + 2*t[2] + 2 + l[1] + l[3] + 2*l[2] + 2) >> 3) as u8;
+                buf[1]      = pix;
+                buf[stride] = pix;
+                let pix = ((t[2] + t[4] + 2*t[3] + 2 + l[2] + l[4] + 2*l[3] + 2) >> 3) as u8;
+                buf[2]          = pix;
+                buf[1 + stride] = pix;
+                buf[2 * stride] = pix;
+                let pix = ((t[3] + t[5] + 2*t[4] + 2 + l[3] + l[5] + 2*l[4] + 2) >> 3) as u8;
+                buf[3]              = pix;
+                buf[2 +     stride] = pix;
+                buf[1 + 2 * stride] = pix;
+                buf[    3 * stride] = pix;
+                let pix = ((t[4] + t[6] + 2*t[5] + 2 + l[4] + l[6] + 2*l[5] + 2) >> 3) as u8;
+                buf[3 +     stride] = pix;
+                buf[2 + 2 * stride] = pix;
+                buf[1 + 3 * stride] = pix;
+                let pix = ((t[5] + t[7] + 2*t[6] + 2 + l[5] + l[7] + 2*l[6] + 2) >> 3) as u8;
+                buf[3 + 2 * stride] = pix;
+                buf[2 + 3 * stride] = pix;
+                buf[3 + 3 * stride] = ((t[6] + t[7] + 1 + l[6] + l[7] + 1) >> 2) as u8;
+            },
+            PredType4x4::DiagDownRight => {
+                let (l, t) = self.load_left_and_top();
+                for (j, line) in buf.chunks_mut(stride).take(4).enumerate() {
+                    for i in 0..j {
+                        line[i] = ((l[j - i - 1] + 2 * l[j - i] + l[j - i + 1] + 2) >> 2) as u8;
+                    }
+                    line[j] = ((l[1] + 2 * l[0] + t[1] + 2) >> 2) as u8;
+                    for i in (j + 1)..4 {
+                        line[i] = ((t[i - j - 1] + 2 * t[i - j] + t[i - j + 1] + 2) >> 2) as u8;
+                    }
+                }
+            },
+            PredType4x4::VerRight => {
+                let (l, t) = self.load_left_and_top();
+                for (j, line) in buf.chunks_mut(stride).take(4).enumerate() {
+                    for (i, pix) in line[..4].iter_mut().enumerate() {
+                        let zvr = ((2 * i) as i8) - (j as i8);
+                        *pix = if zvr >= 0 {
+                                if (zvr & 1) == 0 {
+                                    (t[i - (j >> 1)] + t[i - (j >> 1) + 1] + 1) >> 1
+                                } else {
+                                    (t[i - (j >> 1) - 1] + 2 * t[i - (j >> 1)] + t[i - (j >> 1) + 1] + 2) >> 2
+                                }
+                            } else {
+                                if zvr == -1 {
+                                    (l[1] + 2 * l[0] + t[1] + 2) >> 2
+                                } else {
+                                    (l[j] + 2 * l[j - 1] + l[j - 2] + 2) >> 2
+                                }
+                            } as u8;
+                    }
+                }
+            },
+            PredType4x4::HorDown => {
+                let (l, t) = self.load_left_and_top();
+                for (j, line) in buf.chunks_mut(stride).take(4).enumerate() {
+                    for (i, pix) in line[..4].iter_mut().enumerate() {
+                        let zhd = ((2 * j) as i8) - (i as i8);
+                        *pix = if zhd >= 0 {
+                                if (zhd & 1) == 0 {
+                                    (l[j - (i >> 1)] + l[j - (i >> 1) + 1] + 1) >> 1
+                                } else {
+                                    (l[j - (i >> 1) - 1] + 2 * l[j - (i >> 1)] + l[j - (i >> 1) + 1] + 2) >> 2
+                                }
+                            } else {
+                                if zhd == -1 {
+                                    (l[1] + 2 * l[0] + t[1] + 2) >> 2
+                                } else {
+                                    (t[i - 2] + 2 * t[i - 1] + t[i] + 2) >> 2
+                                }
+                            } as u8;
+                    }
+                }
+            },
+            PredType4x4::VerLeft => {
+                let l = self.load_left();
+                let t = self.load_top();
+                buf[0] = ((2*t[0] + 2*t[1] + l[1] + 2*l[2] + l[3] + 4) >> 3) as u8;
+                let pix = ((t[1] + t[2] + 1) >> 1) as u8;
+                buf[1]          = pix;
+                buf[2 * stride] = pix;
+                let pix = ((t[2] + t[3] + 1) >> 1) as u8;
+                buf[2]              = pix;
+                buf[1 + 2 * stride] = pix;
+                let pix = ((t[3] + t[4] + 1) >> 1) as u8;
+                buf[3]              = pix;
+                buf[2 + 2 * stride] = pix;
+                buf[3 + 2 * stride] = ((t[4] + t[5] + 1) >> 1) as u8;
+                buf[        stride] = ((t[0] + 2*t[1] + t[2] + l[2] + 2*l[3] + l[4] + 4) >> 3) as u8;
+                let pix = ((t[1] + 2*t[2] + t[3] + 2) >> 2) as u8;
+                buf[1 +     stride] = pix;
+                buf[    3 * stride] = pix;
+                let pix = ((t[2] + 2*t[3] + t[4] + 2) >> 2) as u8;
+                buf[2 +     stride] = pix;
+                buf[1 + 3 * stride] = pix;
+                let pix = ((t[3] + 2*t[4] + t[5] + 2) >> 2) as u8;
+                buf[3 +     stride] = pix;
+                buf[2 + 3 * stride] = pix;
+                buf[3 + 3 * stride] = ((t[4] + 2*t[5] + t[6] + 2) >> 2) as u8;
+            },
+            PredType4x4::HorUp => {
+                let l = self.load_left();
+                let t = self.load_top();
+                buf[0] = ((t[1] + 2*t[2] + t[3] + 2*l[0] + 2*l[1] + 4) >> 3) as u8;
+                buf[1] = ((t[2] + 2*t[3] + t[4] + l[0] + 2*l[1] + l[2] + 4) >> 3) as u8;
+                let pix = ((t[3] + 2*t[4] + t[5] + 2*l[1] + 2*l[2] + 4) >> 3) as u8;
+                buf[2]              = pix;
+                buf[        stride] = pix;
+                let pix = ((t[4] + 2*t[5] + t[6] + l[1] + 2*l[2] + l[3] + 4) >> 3) as u8;
+                buf[3]              = pix;
+                buf[1 +     stride] = pix;
+                let pix = ((t[5] + 2*t[6] + t[7] + 2*l[2] + 2*l[3] + 4) >> 3) as u8;
+                buf[2 +     stride] = pix;
+                buf[0 + 2 * stride] = pix;
+                let pix = ((t[6] + 3*t[7] + l[2] + 3*l[3] + 4) >> 3) as u8;
+                buf[3 +     stride] = pix;
+                buf[1 + 2 * stride] = pix;
+                let pix = ((l[3] + 2*l[4] + l[5] + 2) >> 2) as u8;
+                buf[3 + 2 * stride] = pix;
+                buf[1 + 3 * stride] = pix;
+                let pix = ((t[6] + t[7] + l[3] + l[4] + 2) >> 2) as u8;
+                buf[0 + 3 * stride] = pix;
+                buf[2 + 2 * stride] = pix;
+                buf[2 + 3 * stride] = ((l[4] + l[5] + 1) >> 1) as u8;
+                buf[3 + 3 * stride] = ((l[4] + 2*l[5] + l[6] + 2) >> 2) as u8;
+            },
+            PredType4x4::DiagDownLeftNoDown => {
+                let l = self.load_left();
+                let t = self.load_top();
+                buf[0] = ((t[0] + t[2] + 2*t[1] + 2 + l[0] + l[2] + 2*l[1] + 2) >> 3) as u8;
+                let pix = ((t[1] + t[3] + 2*t[2] + 2 + l[1] + l[3] + 2*l[2] + 2) >> 3) as u8;
+                buf[1]              = pix;
+                buf[0 +     stride] = pix;
+                let pix = ((t[2] + t[4] + 2*t[3] + 2 + l[2] + 3*l[3] + 2) >> 3) as u8;
+                buf[2]              = pix;
+                buf[1 +     stride] = pix;
+                buf[0 + 2 * stride] = pix;
+                let pix = ((t[3] + t[5] + 2*t[4] + 2 + l[3]*4 + 2) >> 3) as u8;
+                buf[3]              = pix;
+                buf[2 +     stride] = pix;
+                buf[1 + 2 * stride] = pix;
+                buf[0 + 3 * stride] = pix;
+                let pix = ((t[4] + t[6] + 2*t[5] + 2 + l[3]*4 + 2) >> 3) as u8;
+                buf[3 +     stride] = pix;
+                buf[2 + 2 * stride] = pix;
+                buf[1 + 3 * stride] = pix;
+                let pix = ((t[5] + t[7] + 2*t[6] + 2 + l[3]*4 + 2) >> 3) as u8;
+                buf[3 + 2 * stride] = pix;
+                buf[2 + 3 * stride] = pix;
+                buf[3 + 3 * stride] = ((t[6] + t[7] + 1 + 2*l[3] + 1) >> 2) as u8;
+            },
+            PredType4x4::HorUpNoDown => {
+                let l = self.load_left();
+                let t = self.load_top();
+                buf[0] = ((t[1] + 2*t[2] + t[3] + 2*l[0] + 2*l[1] + 4) >> 3) as u8;
+                buf[1] = ((t[2] + 2*t[3] + t[4] + l[0] + 2*l[1] + l[2] + 4) >> 3) as u8;
+                let pix = ((t[3] + 2*t[4] + t[5] + 2*l[1] + 2*l[2] + 4) >> 3) as u8;
+                buf[2]              = pix;
+                buf[        stride] = pix;
+                let pix = ((t[4] + 2*t[5] + t[6] + l[1] + 2*l[2] + l[3] + 4) >> 3) as u8;
+                buf[3]              = pix;
+                buf[1 +     stride] = pix;
+                let pix = ((t[5] + 2*t[6] + t[7] + 2*l[2] + 2*l[3] + 4) >> 3) as u8;
+                buf[2 +     stride] = pix;
+                buf[    2 * stride] = pix;
+                let pix = ((t[6] + 3*t[7] + l[2] + 3*l[3] + 4) >> 3) as u8;
+                buf[3 +     stride] = pix;
+                buf[1 + 2 * stride] = pix;
+                buf[3 + 2 * stride] = l[3] as u8;
+                buf[1 + 3 * stride] = l[3] as u8;
+                let pix = ((t[6] + t[7] + 2*l[3] + 2) >> 2) as u8;
+                buf[0 + 3 * stride] = pix;
+                buf[2 + 2 * stride] = pix;
+                buf[2 + 3 * stride] = l[3] as u8;
+                buf[3 + 3 * stride] = l[3] as u8;
+            },
+            PredType4x4::VerLeftNoDown => {
+                let l = [u16::from(self.left[0]), u16::from(self.left[1]), u16::from(self.left[2]), u16::from(self.left[3]), u16::from(self.left[3])];
+                let t = self.load_top();
+                buf[0] = ((2*t[0] + 2*t[1] + l[1] + 2*l[2] + l[3] + 4) >> 3) as u8;
+                let pix = ((t[1] + t[2] + 1) >> 1) as u8;
+                buf[1]              = pix;
+                buf[    2 * stride] = pix;
+                let pix = ((t[2] + t[3] + 1) >> 1) as u8;
+                buf[2]              = pix;
+                buf[1 + 2 * stride] = pix;
+                let pix = ((t[3] + t[4] + 1) >> 1) as u8;
+                buf[3]              = pix;
+                buf[2 + 2 * stride] = pix;
+                buf[3 + 2 * stride] = ((t[4] + t[5] + 1) >> 1) as u8;
+                buf[        stride] = ((t[0] + 2*t[1] + t[2] + l[2] + 2*l[3] + l[4] + 4) >> 3) as u8;
+                let pix = ((t[1] + 2*t[2] + t[3] + 2) >> 2) as u8;
+                buf[1 +     stride] = pix;
+                buf[    3 * stride] = pix;
+                let pix = ((t[2] + 2*t[3] + t[4] + 2) >> 2) as u8;
+                buf[2 +     stride] = pix;
+                buf[1 + 3 * stride] = pix;
+                let pix = ((t[3] + 2*t[4] + t[5] + 2) >> 2) as u8;
+                buf[3 +     stride] = pix;
+                buf[2 + 3 * stride] = pix;
+                buf[3 + 3 * stride] = ((t[4] + 2*t[5] + t[6] + 2) >> 2) as u8;
+            },
+        }
+    }
+}
+
+pub struct BlockIntra4Pred {
+    pub ipred_y:    Intra4Pred,
+    pub ipred_u:    Intra4Pred,
+    pub ipred_v:    Intra4Pred,
+    pub top_y:      [u8; 21],
+    pub top_u:      [u8; 13],
+    pub top_v:      [u8; 13],
+    pub left_y:     [u8; 16],
+    pub left_u:     [u8; 8],
+    pub left_v:     [u8; 8],
+    pub has_l:      bool,
+}
+
+impl BlockIntra4Pred {
+    pub fn new(src_y: &IntraPred16x16, src_u: &IntraPred16x16, src_v: &IntraPred16x16, tr_y: [u8; 4], tr_u: [u8; 4], tr_v: [u8; 4], has_l: bool) -> Self {
+        let mut top_y = [0; 21];
+        top_y[..17].copy_from_slice(&src_y.top);
+        top_y[17..].copy_from_slice(&tr_y);
+        let mut top_u = [0; 13];
+        top_u[..9].copy_from_slice(&src_u.top[..9]);
+        top_u[9..].copy_from_slice(&tr_u);
+        let mut top_v = [0; 13];
+        top_v[..9].copy_from_slice(&src_v.top[..9]);
+        top_v[9..].copy_from_slice(&tr_v);
+        let mut left_y = [0; 16];
+        left_y.copy_from_slice(&src_y.left[1..]);
+        let mut left_u = [0; 8];
+        left_u.copy_from_slice(&src_u.left[1..9]);
+        let mut left_v = [0; 8];
+        left_v.copy_from_slice(&src_v.left[1..9]);
+        Self {
+            ipred_y:    Intra4Pred::new(),
+            ipred_u:    Intra4Pred::new(),
+            ipred_v:    Intra4Pred::new(),
+            top_y, top_u, top_v, left_y, left_u, left_v,
+            has_l,
+        }
+    }
+    pub fn pred_block(&mut self, dst: &mut RefMBData, x: usize, y: usize, mode: PredType4x4) {
+        let do_chroma = ((x & 1) == 0) && ((y & 1) == 0);
+        if x == 0 {
+            self.ipred_y.tl = if y == 0 { self.top_y[0] } else { self.left_y[y * 4 - 1] };
+            if y != 3 {
+                self.ipred_y.left.copy_from_slice(&self.left_y[y * 4..][..8]);
+            } else {
+                self.ipred_y.left[..4].copy_from_slice(&self.left_y[12..]);
+            }
+            if y == 0 {
+                self.ipred_u.tl = self.top_u[0];
+                self.ipred_v.tl = self.top_v[0];
+                self.ipred_u.left.copy_from_slice(&self.left_u);
+                self.ipred_v.left.copy_from_slice(&self.left_v);
+            } else if y == 2 {
+                self.ipred_u.tl = self.left_u[3];
+                self.ipred_v.tl = self.left_v[3];
+                self.ipred_u.left[..4].copy_from_slice(&self.left_u[4..]);
+                self.ipred_v.left[..4].copy_from_slice(&self.left_v[4..]);
+            }
+        }
+        self.ipred_y.top.copy_from_slice(&self.top_y[x * 4 + 1..][..8]);
+        if do_chroma {
+            if x == 0 {
+                self.ipred_u.top.copy_from_slice(&self.top_u[1..9]);
+                self.ipred_v.top.copy_from_slice(&self.top_v[1..9]);
+            } else if x == 2 {
+                self.ipred_u.top.copy_from_slice(&self.top_u[5..]);
+                self.ipred_v.top.copy_from_slice(&self.top_v[5..]);
+            }
+        }
+
+        self.ipred_y.apply(mode, &mut dst.y[x * 4 + y * 4 * 16..], 16);
+        if do_chroma {
+            let has_ld = if (x == 0) && (y == 0) { self.has_l } else { false };
+            let off = x * 2 + y * 2 * 8;
+            let cmode = match mode {
+                    PredType4x4::DiagDownLeft if !has_ld => PredType4x4::DiagDownLeftNoDown,
+                    PredType4x4::VerLeft if !has_ld => PredType4x4::VerLeftNoDown,
+                    PredType4x4::HorUp if !has_ld => PredType4x4::HorUpNoDown,
+                    _ => mode,
+                };
+            self.ipred_u.apply(cmode, &mut dst.u[off..], 8);
+            self.ipred_v.apply(cmode, &mut dst.v[off..], 8);
+        }
+    }
+    pub fn update_from(&mut self, src: &RefMBData, x: usize, y: usize) {
+        let do_chroma = ((x & 1) == 0) && ((y & 1) == 0);
+        let y_off = x * 4 + y * 4 * 16;
+        let c_off = x * 2 + y * 2 * 8;
+
+        if x != 3 {
+            self.ipred_y.tl = self.ipred_y.top[3];
+            for (left, src) in self.ipred_y.left[..4].iter_mut().zip(src.y[y_off + 3..].chunks(16)) {
+                *left = src[0];
+            }
+        }
+        if do_chroma && x != 2 {
+            self.ipred_u.tl = self.ipred_u.top[3];
+            self.ipred_v.tl = self.ipred_v.top[3];
+            for (left, src) in self.ipred_u.left[..4].iter_mut().zip(src.u[c_off + 3..].chunks(8)) {
+                *left = src[0];
+            }
+            for (left, src) in self.ipred_v.left[..4].iter_mut().zip(src.v[c_off + 3..].chunks(8)) {
+                *left = src[0];
+            }
+        }
+        if x == 0 {
+            self.top_y[0] = self.left_y[x * 4 + 3];
+            if y == 0 {
+                self.top_u[0] = self.left_u[3];
+                self.top_v[0] = self.left_v[3];
+            }
+        }
+        self.top_y[x * 4 + 1..][..4].copy_from_slice(&src.y[y_off + 3 * 16..][..4]);
+        if x == 3 {
+            let (head, tail) = self.top_y.split_at_mut(17);
+            for el in tail.iter_mut() {
+                *el = head[16];
+            }
+        }
+        if do_chroma && y != 2 {
+            self.top_u[x * 2 + 1..][..4].copy_from_slice(&src.u[c_off + 3 * 8..][..4]);
+            self.top_v[x * 2 + 1..][..4].copy_from_slice(&src.v[c_off + 3 * 8..][..4]);
+            if x == 2 {
+                for i in 9..13 {
+                    self.top_u[i] = self.top_u[8];
+                    self.top_v[i] = self.top_v[8];
+                }
+            }
+        }
+    }
+}