use super::satd_avg::{satd_avg_w16, satd_avg_w8};
type WelsSatd = unsafe extern "C" fn(*const u8, i32, *const u8, i32) -> i32;
type AvgSatd = unsafe fn(*const u8, usize, *const u8, *const u8, usize, usize) -> u32;
const PF: usize = 0;
const PH: usize = 1;
const PV: usize = 2;
const PC: usize = 3;
pub struct MeCtx<'a> {
src: &'a [u8],
cw: usize,
planes: [&'a [u8]; 4], stride: usize,
pad: isize,
px_max: isize,
py_max: isize,
lx: isize,
ly: isize,
w: usize,
h: usize,
satd: WelsSatd,
avg: AvgSatd,
}
impl<'a> MeCtx<'a> {
#[allow(clippy::too_many_arguments)]
pub fn new(
src: &'a [u8],
cw: usize,
f: &'a [u8],
h_pl: &'a [u8],
v: &'a [u8],
c: &'a [u8],
stride: usize,
pad: usize,
pw: usize,
ph: usize,
lx: usize,
ly: usize,
w: usize,
h: usize,
) -> Option<Self> {
if !super::has_avx2() || stride != pw {
return None;
}
let (satd, avg): (WelsSatd, AvgSatd) = match (w, h) {
(16, 16) => (crate::satd_sad::cshim::satd16x16 as WelsSatd, satd_avg_w16 as AvgSatd),
(16, 8) => (crate::satd_sad::cshim::satd16x8 as WelsSatd, satd_avg_w16 as AvgSatd),
(8, 16) => (crate::satd_sad::cshim::satd8x16 as WelsSatd, satd_avg_w8 as AvgSatd),
(8, 8) => (crate::satd_sad::cshim::satd8x8 as WelsSatd, satd_avg_w8 as AvgSatd),
_ => return None,
};
if src.len() < (h - 1) * cw + w {
return None;
}
let need = pw.checked_mul(ph)?;
if f.len() < need || h_pl.len() < need || v.len() < need || c.len() < need {
return None;
}
let px_max = pw as isize - w as isize - 1;
let py_max = ph as isize - h as isize - 1;
if px_max < 0 || py_max < 0 {
return None;
}
Some(MeCtx {
src,
cw,
planes: [f, h_pl, v, c],
stride,
pad: pad as isize,
px_max,
py_max,
lx: lx as isize,
ly: ly as isize,
w,
h,
satd,
avg,
})
}
#[inline]
pub fn eval(&self, mvx: i32, mvy: i32) -> Option<u32> {
let px = self.lx + (mvx >> 2) as isize + self.pad;
let py = self.ly + (mvy >> 2) as isize + self.pad;
if px < 0 || py < 0 || px > self.px_max || py > self.py_max {
return None;
}
let base = py as usize * self.stride + px as usize;
let (fx, fy) = (mvx & 3, mvy & 3);
let st = self.stride;
unsafe {
if fx & 1 == 0 && fy & 1 == 0 {
let p = match (fx, fy) {
(0, 0) => self.planes[PF],
(2, 0) => self.planes[PH],
(0, 2) => self.planes[PV],
_ => self.planes[PC], };
let v = (self.satd)(
self.src.as_ptr(),
self.cw as i32,
p.as_ptr().add(base),
st as i32,
);
return Some(2 * v as u32);
}
let (pa, oa, pb, ob) = match (fx, fy) {
(1, 0) => (PF, 0, PH, 0),
(3, 0) => (PF, 1, PH, 0),
(0, 1) => (PF, 0, PV, 0),
(0, 3) => (PF, st, PV, 0),
(1, 1) => (PH, 0, PV, 0),
(3, 1) => (PH, 0, PV, 1),
(1, 3) => (PH, st, PV, 0),
(3, 3) => (PH, st, PV, 1),
(2, 1) => (PH, 0, PC, 0),
(2, 3) => (PH, st, PC, 0),
(1, 2) => (PV, 0, PC, 0),
_ => (PV, 1, PC, 0), };
Some((self.avg)(
self.src.as_ptr(),
self.cw,
self.planes[pa].as_ptr().add(base + oa),
self.planes[pb].as_ptr().add(base + ob),
st,
self.h,
))
}
}
}