me.rs 15.3 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 14
#[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;
use context::{BlockOffset, BLOCK_TO_PLANE_SHIFT, MI_SIZE};
15 16
use FrameInvariants;
use FrameState;
Raphaël Zumer's avatar
Raphaël Zumer committed
17 18
use partition::*;
use plane::*;
Frank Bossen's avatar
Frank Bossen committed
19
use rdo::get_lambda_sqrt;
20

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

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
    }
Luca Barbato's avatar
Luca Barbato committed
90
    return 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 {
Luca Barbato's avatar
Luca Barbato committed
111
  use 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 138 139 140 141 142 143 144 145
fn get_mv_range(fi: &FrameInvariants, bo: &BlockOffset, blk_w: usize, blk_h: usize) -> (isize, isize, isize, isize) {
  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)
}

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

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

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

171
      full_search(
Kyle Siefring's avatar
Kyle Siefring committed
172 173 174 175 176 177 178 179 180
        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
181
        &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
182 183
        &po,
        2,
Frank Bossen's avatar
Frank Bossen committed
184 185 186 187
        bit_depth,
        lambda,
        pmv,
        fi.allow_high_precision_mv
188
      );
Frank Bossen's avatar
Frank Bossen committed
189 190

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

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

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

207 208 209 210
            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
211

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

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

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

236 237
            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
238

Kyle Siefring's avatar
Kyle Siefring committed
239
            let sad = get_sad(&plane_org, &plane_ref, blk_h, blk_w, bit_depth);
Frank Bossen's avatar
Frank Bossen committed
240

Frank Bossen's avatar
Frank Bossen committed
241 242 243 244 245 246 247
            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
248 249 250 251 252 253
              best_mv = cand_mv;
            }
          }
        }
      }

254
      best_mv
255
    }
256

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

Kyle Siefring's avatar
Kyle Siefring committed
261 262 263
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
264 265
  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
266
) {
267 268 269 270 271
  for y in (y_lo..y_hi).step_by(step) {
    for x in (x_lo..x_hi).step_by(step) {
      let plane_org = p_org.slice(po);
      let plane_ref = p_ref.slice(&PlaneOffset { x, y });

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

Frank Bossen's avatar
Frank Bossen committed
274 275 276 277 278 279 280 281 282 283 284 285 286
      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;
287 288 289 290 291 292 293 294 295 296 297 298 299
      }
    }
  }
}

// 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
300 301 302 303 304 305 306 307 308 309 310 311 312
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)
}

313
pub fn estimate_motion_ss4(
Kyle Siefring's avatar
Kyle Siefring committed
314 315
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, ref_idx: usize,
  bo: &BlockOffset, bit_depth: usize
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
) -> 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
    };
    let range = 64 * fi.me_range_scale as isize;
    let (mvx_min, mvx_max, mvy_min, mvy_max) = get_mv_range(fi, &bo_adj, blk_w, blk_h);
    let x_lo = po.x + (((-range).max(mvx_min / 8)) >> 2);
    let x_hi = po.x + (((range).min(mvx_max / 8)) >> 2);
    let y_lo = po.y + (((-range).max(mvy_min / 8)) >> 2);
    let y_hi = po.y + (((range).min(mvy_max / 8)) >> 2);

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

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

338
    full_search(
Kyle Siefring's avatar
Kyle Siefring committed
339 340 341 342 343 344 345 346 347
      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
348
      &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
349 350
      &po,
      1,
Frank Bossen's avatar
Frank Bossen committed
351 352 353 354
      bit_depth,
      lambda,
      &[MotionVector { row: 0, col: 0 }; 2],
      fi.allow_high_precision_mv
355 356 357 358 359 360 361 362 363
    );

    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
364 365
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, ref_idx: usize,
  bo: &BlockOffset, pmvs: &[Option<MotionVector>; 3], bit_depth: usize
366 367 368 369 370 371 372 373 374 375 376 377
) -> 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
378
    let mut lowest_cost = std::u32::MAX;
379 380
    let mut best_mv = MotionVector { row: 0, col: 0 };

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

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

        full_search(
Kyle Siefring's avatar
Kyle Siefring committed
392 393 394 395 396 397 398 399 400
          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
401
          &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
402 403
          &po,
          1,
Frank Bossen's avatar
Frank Bossen committed
404 405 406 407
          bit_depth,
          lambda,
          &[MotionVector { row: 0, col: 0 }; 2],
          fi.allow_high_precision_mv
408 409 410 411 412 413 414 415 416 417
        );
      }
    }

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

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

  // 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
428

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

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

    (input_plane, rec_plane)
  }

  // Regression and validation test for SAD computation
  #[test]
  fn get_sad_same() {
    let blocks: Vec<(BlockSize, u32)> = vec![
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
      (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),
476 477
    ];

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

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

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

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