me.rs 15.5 KB
Newer Older
1 2 3 4 5 6 7 8 9
// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

Raphaël Zumer's avatar
Raphaël Zumer committed
10 11 12 13
#[cfg(all(target_arch = "x86_64", not(windows), feature = "nasm"))]
pub use self::nasm::get_sad;
#[cfg(any(not(target_arch = "x86_64"), windows, not(feature = "nasm")))]
pub use self::native::get_sad;
Raphaël Zumer's avatar
Raphaël Zumer committed
14 15 16 17 18 19
use crate::context::{BlockOffset, BLOCK_TO_PLANE_SHIFT, MI_SIZE};
use crate::FrameInvariants;
use crate::FrameState;
use crate::partition::*;
use crate::plane::*;
use crate::rdo::get_lambda_sqrt;
20

21 22
#[cfg(all(target_arch = "x86_64", not(windows), feature = "nasm"))]
mod nasm {
Raphaël Zumer's avatar
Raphaël Zumer committed
23 24
  use crate::plane::*;
  use crate::util::*;
Luca Barbato's avatar
Luca Barbato committed
25

Raphaël Zumer's avatar
Raphaël Zumer committed
26 27
  use libc;

Luca Barbato's avatar
Luca Barbato committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
  extern {
    fn rav1e_sad_4x4_hbd_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_8x8_hbd10_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_16x16_hbd_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_32x32_hbd10_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_64x64_hbd10_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_128x128_hbd10_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;
  }
Kyle Siefring's avatar
Kyle Siefring committed
59

Luca Barbato's avatar
Luca Barbato committed
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
  #[target_feature(enable = "ssse3")]
  unsafe fn sad_ssse3(
    plane_org: &PlaneSlice, plane_ref: &PlaneSlice, blk_h: usize,
    blk_w: usize, bit_depth: usize
  ) -> u32 {
    let mut sum = 0 as u32;
    // TODO: stride *2??? What is the correct way to do this?
    let org_stride = plane_org.plane.cfg.stride as libc::ptrdiff_t * 2;
    let ref_stride = plane_ref.plane.cfg.stride as libc::ptrdiff_t * 2;
    assert!(blk_h >= 4 && blk_w >= 4);
    let step_size =
      blk_h.min(blk_w).min(if bit_depth <= 10 { 128 } else { 4 });
    let func = match step_size.ilog() {
      3 => rav1e_sad_4x4_hbd_ssse3,
      4 => rav1e_sad_8x8_hbd10_ssse3,
      5 => rav1e_sad_16x16_hbd_ssse3,
      6 => rav1e_sad_32x32_hbd10_ssse3,
      7 => rav1e_sad_64x64_hbd10_ssse3,
      8 => rav1e_sad_128x128_hbd10_ssse3,
      _ => rav1e_sad_128x128_hbd10_ssse3
    };
    for r in (0..blk_h).step_by(step_size) {
      for c in (0..blk_w).step_by(step_size) {
        let org_slice = plane_org.subslice(c, r);
        let ref_slice = plane_ref.subslice(c, r);
        let org_ptr = org_slice.as_slice().as_ptr();
        let ref_ptr = ref_slice.as_slice().as_ptr();
        sum += func(org_ptr, org_stride, ref_ptr, ref_stride);
      }
Kyle Siefring's avatar
Kyle Siefring committed
89
    }
90
    sum
Kyle Siefring's avatar
Kyle Siefring committed
91 92
  }

Luca Barbato's avatar
Luca Barbato committed
93 94 95 96 97 98 99 100 101 102 103 104
  #[inline(always)]
  pub fn get_sad(
    plane_org: &PlaneSlice, plane_ref: &PlaneSlice, blk_h: usize,
    blk_w: usize, bit_depth: usize
  ) -> u32 {
    #[cfg(all(target_arch = "x86_64", not(windows), feature = "nasm"))]
    {
      if is_x86_feature_detected!("ssse3") && blk_h >= 4 && blk_w >= 4 {
        return unsafe {
          sad_ssse3(plane_org, plane_ref, blk_h, blk_w, bit_depth)
        };
      }
Kyle Siefring's avatar
Kyle Siefring committed
105
    }
Luca Barbato's avatar
Luca Barbato committed
106
    super::native::get_sad(plane_org, plane_ref, blk_h, blk_w, bit_depth)
Kyle Siefring's avatar
Kyle Siefring committed
107
  }
108 109 110
}

mod native {
Raphaël Zumer's avatar
Raphaël Zumer committed
111
  use crate::plane::*;
112

Luca Barbato's avatar
Luca Barbato committed
113 114 115 116 117 118
  #[inline(always)]
  pub fn get_sad(
    plane_org: &PlaneSlice, plane_ref: &PlaneSlice, blk_h: usize,
    blk_w: usize, _bit_depth: usize
  ) -> u32 {
    let mut sum = 0 as u32;
119

Luca Barbato's avatar
Luca Barbato committed
120 121
    let org_iter = plane_org.iter_width(blk_w);
    let ref_iter = plane_ref.iter_width(blk_w);
122

Luca Barbato's avatar
Luca Barbato committed
123
    for (slice_org, slice_ref) in org_iter.take(blk_h).zip(ref_iter) {
124 125 126 127 128
      sum += slice_org
        .iter()
        .zip(slice_ref)
        .map(|(&a, &b)| (a as i32 - b as i32).abs() as u32)
        .sum::<u32>();
Luca Barbato's avatar
Luca Barbato committed
129
    }
130

Luca Barbato's avatar
Luca Barbato committed
131 132
    sum
  }
133 134
}

135 136 137
fn get_mv_range(
  fi: &FrameInvariants, bo: &BlockOffset, blk_w: usize, blk_h: usize
) -> (isize, isize, isize, isize) {
138 139 140 141 142 143 144 145 146 147
  let border_w = 128 + blk_w as isize * 8;
  let border_h = 128 + blk_h as isize * 8;
  let mvx_min = -(bo.x as isize) * (8 * MI_SIZE) as isize - border_w;
  let mvx_max = (fi.w_in_b - bo.x - blk_w / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_w;
  let mvy_min = -(bo.y as isize) * (8 * MI_SIZE) as isize - border_h;
  let mvy_max = (fi.h_in_b - bo.y - blk_h / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_h;

  (mvx_min, mvx_max, mvy_min, mvy_max)
}

148
pub fn motion_estimation(
Kyle Siefring's avatar
Kyle Siefring committed
149
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, bo: &BlockOffset,
150
  ref_frame: usize, cmv: MotionVector, pmv: &[MotionVector; 2]
151
) -> MotionVector {
152
  match fi.rec_buffer.frames[fi.ref_frames[ref_frame - LAST_FRAME] as usize] {
153
    Some(ref rec) => {
154 155 156 157
      let po = PlaneOffset {
        x: (bo.x as isize) << BLOCK_TO_PLANE_SHIFT,
        y: (bo.y as isize) << BLOCK_TO_PLANE_SHIFT
      };
158
      let range = 16;
159 160
      let blk_w = bsize.width();
      let blk_h = bsize.height();
161
      let (mvx_min, mvx_max, mvy_min, mvy_max) = get_mv_range(fi, bo, blk_w, blk_h);
162 163 164 165
      let x_lo = po.x + ((-range + (cmv.col / 8) as isize).max(mvx_min / 8).min(mvx_max / 8));
      let x_hi = po.x + ((range + (cmv.col / 8) as isize).max(mvx_min / 8).min(mvx_max / 8));
      let y_lo = po.y + ((-range + (cmv.row / 8) as isize).max(mvy_min / 8).min(mvy_max / 8));
      let y_hi = po.y + ((range + (cmv.row / 8) as isize).max(mvy_min / 8).min(mvy_max / 8));
166

Frank Bossen's avatar
Frank Bossen committed
167
      let mut lowest_cost = std::u32::MAX;
168 169
      let mut best_mv = MotionVector { row: 0, col: 0 };

Frank Bossen's avatar
Frank Bossen committed
170
      // 0.5 is a fudge factor
171
      let lambda = (get_lambda_sqrt(fi) * 256.0 * 0.5) as u32;
Frank Bossen's avatar
Frank Bossen committed
172

173
      full_search(
Kyle Siefring's avatar
Kyle Siefring committed
174 175 176 177 178 179 180 181 182
        x_lo,
        x_hi,
        y_lo,
        y_hi,
        blk_h,
        blk_w,
        &fs.input.planes[0],
        &rec.frame.planes[0],
        &mut best_mv,
Frank Bossen's avatar
Frank Bossen committed
183
        &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
184 185
        &po,
        2,
186
        fi.sequence.bit_depth,
Frank Bossen's avatar
Frank Bossen committed
187 188 189
        lambda,
        pmv,
        fi.allow_high_precision_mv
190
      );
Frank Bossen's avatar
Frank Bossen committed
191 192

      let mode = PredictionMode::NEWMV;
fbossen's avatar
fbossen committed
193
      let mut tmp_plane = Plane::new(blk_w, blk_h, 0, 0, 0, 0);
Frank Bossen's avatar
Frank Bossen committed
194

195
      let mut steps = vec![8, 4, 2];
196 197 198 199 200
      if fi.allow_high_precision_mv {
        steps.push(1);
      }

      for step in steps {
Frank Bossen's avatar
Frank Bossen committed
201 202 203 204
        let center_mv_h = best_mv;
        for i in 0..3 {
          for j in 0..3 {
            // Skip the center point that was already tested
205 206 207
            if i == 1 && j == 1 {
              continue;
            }
Frank Bossen's avatar
Frank Bossen committed
208

209 210 211 212
            let cand_mv = MotionVector {
              row: center_mv_h.row + step * (i as i16 - 1),
              col: center_mv_h.col + step * (j as i16 - 1)
            };
Frank Bossen's avatar
Frank Bossen committed
213

214
            if (cand_mv.col as isize) < mvx_min || (cand_mv.col as isize) > mvx_max {
215 216
              continue;
            }
217
            if (cand_mv.row as isize) < mvy_min || (cand_mv.row as isize) > mvy_max {
218 219 220
              continue;
            }

Frank Bossen's avatar
Frank Bossen committed
221
            {
222 223
              let tmp_slice =
                &mut tmp_plane.mut_slice(&PlaneOffset { x: 0, y: 0 });
Frank Bossen's avatar
Frank Bossen committed
224

225
              mode.predict_inter(
226 227 228 229 230 231 232
                fi,
                0,
                &po,
                tmp_slice,
                blk_w,
                blk_h,
                [ref_frame, NONE_FRAME],
233
                [cand_mv, MotionVector { row: 0, col: 0 }]
234
              );
Frank Bossen's avatar
Frank Bossen committed
235 236
            }

237 238
            let plane_org = fs.input.planes[0].slice(&po);
            let plane_ref = tmp_plane.slice(&PlaneOffset { x: 0, y: 0 });
Frank Bossen's avatar
Frank Bossen committed
239

240
            let sad = get_sad(&plane_org, &plane_ref, blk_h, blk_w, fi.sequence.bit_depth);
Frank Bossen's avatar
Frank Bossen committed
241

Frank Bossen's avatar
Frank Bossen committed
242 243 244 245 246 247 248
            let rate1 = get_mv_rate(cand_mv, pmv[0], fi.allow_high_precision_mv);
            let rate2 = get_mv_rate(cand_mv, pmv[1], fi.allow_high_precision_mv);
            let rate = rate1.min(rate2 + 1);
            let cost = 256 * sad + rate * lambda;

            if cost < lowest_cost {
              lowest_cost = cost;
Frank Bossen's avatar
Frank Bossen committed
249 250 251 252 253 254
              best_mv = cand_mv;
            }
          }
        }
      }

255
      best_mv
256
    }
257

258
    None => MotionVector { row: 0, col: 0 }
259 260
  }
}
261

Kyle Siefring's avatar
Kyle Siefring committed
262 263 264
fn full_search(
  x_lo: isize, x_hi: isize, y_lo: isize, y_hi: isize, blk_h: usize,
  blk_w: usize, p_org: &Plane, p_ref: &Plane, best_mv: &mut MotionVector,
Frank Bossen's avatar
Frank Bossen committed
265 266
  lowest_cost: &mut u32, po: &PlaneOffset, step: usize, bit_depth: usize,
  lambda: u32, pmv: &[MotionVector; 2], allow_high_precision_mv: bool
Kyle Siefring's avatar
Kyle Siefring committed
267
) {
268 269
  for y in (y_lo..=y_hi).step_by(step) {
    for x in (x_lo..=x_hi).step_by(step) {
270 271 272
      let plane_org = p_org.slice(po);
      let plane_ref = p_ref.slice(&PlaneOffset { x, y });

Kyle Siefring's avatar
Kyle Siefring committed
273
      let sad = get_sad(&plane_org, &plane_ref, blk_h, blk_w, bit_depth);
274

Frank Bossen's avatar
Frank Bossen committed
275 276 277 278 279 280 281 282 283 284 285 286 287
      let mv = MotionVector {
        row: 8 * (y as i16 - po.y as i16),
        col: 8 * (x as i16 - po.x as i16)
      };

      let rate1 = get_mv_rate(mv, pmv[0], allow_high_precision_mv);
      let rate2 = get_mv_rate(mv, pmv[1], allow_high_precision_mv);
      let rate = rate1.min(rate2 + 1);
      let cost = 256 * sad + rate * lambda;

      if cost < *lowest_cost {
        *lowest_cost = cost;
        *best_mv = mv;
288 289 290 291 292 293 294 295 296 297 298 299 300
      }
    }
  }
}

// Adjust block offset such that entire block lies within frame boundaries
fn adjust_bo(bo: &BlockOffset, fi: &FrameInvariants, blk_w: usize, blk_h: usize) -> BlockOffset {
  BlockOffset {
    x: (bo.x as isize).min(fi.w_in_b as isize - blk_w as isize / 4).max(0) as usize,
    y: (bo.y as isize).min(fi.h_in_b as isize - blk_h as isize / 4).max(0) as usize
  }
}

Frank Bossen's avatar
Frank Bossen committed
301 302 303 304 305 306 307 308 309 310 311 312 313
fn get_mv_rate(a: MotionVector, b: MotionVector, allow_high_precision_mv: bool) -> u32 {
  fn diff_to_rate(diff: i16, allow_high_precision_mv: bool) -> u32 {
    let d = if allow_high_precision_mv { diff } else { diff >> 1 };
    if d == 0 {
      0
    } else {
      2 * (16 - d.abs().leading_zeros())
    }
  }

  diff_to_rate(a.row - b.row, allow_high_precision_mv) + diff_to_rate(a.col - b.col, allow_high_precision_mv)
}

314
pub fn estimate_motion_ss4(
Kyle Siefring's avatar
Kyle Siefring committed
315
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, ref_idx: usize,
316
  bo: &BlockOffset
317 318 319 320 321 322 323 324 325
) -> Option<MotionVector> {
  if let Some(ref rec) = fi.rec_buffer.frames[ref_idx] {
    let blk_w = bsize.width();
    let blk_h = bsize.height();
    let bo_adj = adjust_bo(bo, fi, blk_w, blk_h);
    let po = PlaneOffset {
      x: (bo_adj.x as isize) << BLOCK_TO_PLANE_SHIFT >> 2,
      y: (bo_adj.y as isize) << BLOCK_TO_PLANE_SHIFT >> 2
    };
326 327
    let range_x = 192 * fi.me_range_scale as isize;
    let range_y = 64 * fi.me_range_scale as isize;
328
    let (mvx_min, mvx_max, mvy_min, mvy_max) = get_mv_range(fi, &bo_adj, blk_w, blk_h);
329 330 331 332
    let x_lo = po.x + (((-range_x).max(mvx_min / 8)) >> 2);
    let x_hi = po.x + (((range_x).min(mvx_max / 8)) >> 2);
    let y_lo = po.y + (((-range_y).max(mvy_min / 8)) >> 2);
    let y_hi = po.y + (((range_y).min(mvy_max / 8)) >> 2);
333

Frank Bossen's avatar
Frank Bossen committed
334
    let mut lowest_cost = std::u32::MAX;
335 336
    let mut best_mv = MotionVector { row: 0, col: 0 };

Frank Bossen's avatar
Frank Bossen committed
337
    // Divide by 16 to account for subsampling, 0.125 is a fudge factor
338
    let lambda = (get_lambda_sqrt(fi) * 256.0 / 16.0 * 0.125) as u32;
Frank Bossen's avatar
Frank Bossen committed
339

340
    full_search(
Kyle Siefring's avatar
Kyle Siefring committed
341 342 343 344 345 346 347 348 349
      x_lo,
      x_hi,
      y_lo,
      y_hi,
      blk_h >> 2,
      blk_w >> 2,
      &fs.input_qres,
      &rec.input_qres,
      &mut best_mv,
Frank Bossen's avatar
Frank Bossen committed
350
      &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
351 352
      &po,
      1,
353
      fi.sequence.bit_depth,
Frank Bossen's avatar
Frank Bossen committed
354 355 356
      lambda,
      &[MotionVector { row: 0, col: 0 }; 2],
      fi.allow_high_precision_mv
357 358 359 360 361 362 363 364 365
    );

    Some(MotionVector { row: best_mv.row * 4, col: best_mv.col * 4 })
  } else {
    None
  }
}

pub fn estimate_motion_ss2(
Kyle Siefring's avatar
Kyle Siefring committed
366
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, ref_idx: usize,
367
  bo: &BlockOffset, pmvs: &[Option<MotionVector>; 3]
368 369 370 371 372 373 374 375 376 377 378 379
) -> Option<MotionVector> {
  if let Some(ref rec) = fi.rec_buffer.frames[ref_idx] {
    let blk_w = bsize.width();
    let blk_h = bsize.height();
    let bo_adj = adjust_bo(bo, fi, blk_w, blk_h);
    let po = PlaneOffset {
      x: (bo_adj.x as isize) << BLOCK_TO_PLANE_SHIFT >> 1,
      y: (bo_adj.y as isize) << BLOCK_TO_PLANE_SHIFT >> 1
    };
    let range = 16;
    let (mvx_min, mvx_max, mvy_min, mvy_max) = get_mv_range(fi, &bo_adj, blk_w, blk_h);

Frank Bossen's avatar
Frank Bossen committed
380
    let mut lowest_cost = std::u32::MAX;
381 382
    let mut best_mv = MotionVector { row: 0, col: 0 };

Frank Bossen's avatar
Frank Bossen committed
383
    // Divide by 4 to account for subsampling, 0.125 is a fudge factor
384
    let lambda = (get_lambda_sqrt(fi) * 256.0 / 4.0 * 0.125) as u32;
Frank Bossen's avatar
Frank Bossen committed
385

386 387
    for omv in pmvs.iter() {
      if let Some(pmv) = omv {
388 389 390 391
        let x_lo = po.x + (((pmv.col as isize / 8 - range).max(mvx_min / 8).min(mvx_max / 8)) >> 1);
        let x_hi = po.x + (((pmv.col as isize / 8 + range).max(mvx_min / 8).min(mvx_max / 8)) >> 1);
        let y_lo = po.y + (((pmv.row as isize / 8 - range).max(mvy_min / 8).min(mvy_max / 8)) >> 1);
        let y_hi = po.y + (((pmv.row as isize / 8 + range).max(mvy_min / 8).min(mvy_max / 8)) >> 1);
392 393

        full_search(
Kyle Siefring's avatar
Kyle Siefring committed
394 395 396 397 398 399 400 401 402
          x_lo,
          x_hi,
          y_lo,
          y_hi,
          blk_h >> 1,
          blk_w >> 1,
          &fs.input_hres,
          &rec.input_hres,
          &mut best_mv,
Frank Bossen's avatar
Frank Bossen committed
403
          &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
404 405
          &po,
          1,
406
          fi.sequence.bit_depth,
Frank Bossen's avatar
Frank Bossen committed
407 408 409
          lambda,
          &[MotionVector { row: 0, col: 0 }; 2],
          fi.allow_high_precision_mv
410 411 412 413 414 415 416 417 418 419
        );
      }
    }

    Some(MotionVector { row: best_mv.row * 2, col: best_mv.col * 2 })
  } else {
    None
  }
}

420 421 422
#[cfg(test)]
pub mod test {
  use super::*;
Raphaël Zumer's avatar
Raphaël Zumer committed
423 424
  use crate::partition::BlockSize;
  use crate::partition::BlockSize::*;
425 426 427 428 429

  // Generate plane data for get_sad_same()
  fn setup_sad() -> (Plane, Plane) {
    let mut input_plane = Plane::new(640, 480, 0, 0, 128 + 8, 128 + 8);
    let mut rec_plane = input_plane.clone();
Luca Barbato's avatar
Luca Barbato committed
430

431
    for (i, row) in input_plane.data.chunks_mut(input_plane.cfg.stride).enumerate() {
432
      for (j, pixel) in row.into_iter().enumerate() {
433
        let val = ((j + i) as i32 & 255i32) as u16;
Luca Barbato's avatar
Luca Barbato committed
434
        assert!(val >= u8::min_value().into() &&
435 436
            val <= u8::max_value().into());
        *pixel = val;
437 438 439 440
      }
    }

    for (i, row) in rec_plane.data.chunks_mut(rec_plane.cfg.stride).enumerate() {
441
      for (j, pixel) in row.into_iter().enumerate() {
442
        let val = (j as i32 - i as i32 & 255i32) as u16;
Luca Barbato's avatar
Luca Barbato committed
443
        assert!(val >= u8::min_value().into() &&
444 445
            val <= u8::max_value().into());
        *pixel = val;
446 447 448 449 450 451 452 453 454 455
      }
    }

    (input_plane, rec_plane)
  }

  // Regression and validation test for SAD computation
  #[test]
  fn get_sad_same() {
    let blocks: Vec<(BlockSize, u32)> = vec![
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
      (BLOCK_4X4, 1912),
      (BLOCK_4X8, 3496),
      (BLOCK_8X4, 4296),
      (BLOCK_8X8, 7824),
      (BLOCK_8X16, 14416),
      (BLOCK_16X8, 16592),
      (BLOCK_16X16, 31136),
      (BLOCK_16X32, 59552),
      (BLOCK_32X16, 60064),
      (BLOCK_32X32, 120128),
      (BLOCK_32X64, 250176),
      (BLOCK_64X32, 186688),
      (BLOCK_64X64, 438912),
      (BLOCK_64X128, 1016768),
      (BLOCK_128X64, 654272),
      (BLOCK_128X128, 1689792),
      (BLOCK_4X16, 6664),
      (BLOCK_16X4, 8680),
      (BLOCK_8X32, 27600),
      (BLOCK_32X8, 31056),
      (BLOCK_16X64, 116384),
      (BLOCK_64X16, 93344),
478 479
    ];

Kyle Siefring's avatar
Kyle Siefring committed
480
    let bit_depth: usize = 8;
481 482 483
    let (input_plane, rec_plane) = setup_sad();

    for block in blocks {
Kyle Siefring's avatar
Kyle Siefring committed
484 485 486
      let bsw = block.0.width();
      let bsh = block.0.height();
      let po = PlaneOffset { x: 40, y: 40 };
487

Kyle Siefring's avatar
Kyle Siefring committed
488 489
      let mut input_slice = input_plane.slice(&po);
      let mut rec_slice = rec_plane.slice(&po);
490

Kyle Siefring's avatar
Kyle Siefring committed
491 492 493 494
      assert_eq!(
        block.1,
        get_sad(&mut input_slice, &mut rec_slice, bsw, bsh, bit_depth)
      );
495 496 497
    }
  }
}