-const DIA_PATTERN: [MV; 9] = [
- ZERO_MV,
- MV {x: -2, y: 0},
- MV {x: -1, y: 1},
- MV {x: 0, y: 2},
- MV {x: 1, y: 1},
- MV {x: 2, y: 0},
- MV {x: 1, y: -1},
- MV {x: 0, y: -2},
- MV {x: -1, y: -1}
-];
-
-const HEX_PATTERN: [MV; 7] = [
- ZERO_MV,
- MV {x: -2, y: 0},
- MV {x: -1, y: 2},
- MV {x: 1, y: 2},
- MV {x: 2, y: 0},
- MV {x: 1, y: -2},
- MV {x: -1, y: -2}
-];
-
-const REFINEMENT: [MV; 4] = [
- MV {x: -1, y: 0},
- MV {x: 0, y: 1},
- MV {x: 1, y: 0},
- MV {x: 0, y: -1}
-];
-
-macro_rules! search_template {
- ($self: expr, $mv_est: expr, $cur_blk: expr, $mb_x: expr, $mb_y: expr, $sad_func: ident) => ({
- let mut best_dist = MAX_DIST;
- let mut best_mv;
-
- let mut min_dist;
- let mut min_idx;
-
- $self.reset();
- loop {
- let mut cur_best_dist = best_dist;
- for (dist, &point) in $self.dist.iter_mut().zip($self.point.iter()) {
- if *dist == MAX_DIST {
- *dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, point.from_pixels(), cur_best_dist);
- cur_best_dist = cur_best_dist.min(*dist);
- if *dist <= DIST_THRESH {
- break;
- }
- }
- }
- min_dist = $self.dist[0];
- min_idx = 0;
- for (i, &dist) in $self.dist.iter().enumerate().skip(1) {
- if dist < min_dist {
- min_dist = dist;
- min_idx = i;
- if dist <= DIST_THRESH {
- break;
- }
- }
- }
- if min_dist <= DIST_THRESH || min_idx == 0 || best_dist == min_dist || $self.point[min_idx].x.abs() >= $mv_est.mv_range || $self.point[min_idx].y.abs() >= $mv_est.mv_range {
- break;
- }
- best_dist = min_dist;
- $self.update($self.steps[min_idx]);
- }
- best_dist = min_dist;
- best_mv = $self.point[min_idx];
- if best_dist <= DIST_THRESH {
- return (best_mv.from_pixels(), best_dist);
- }
- for &step in REFINEMENT.iter() {
- let mv = best_mv + step;
- let dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, mv.from_pixels(), MAX_DIST);
- if best_dist > dist {
- best_dist = dist;
- best_mv = mv;
- }
- }
- best_mv = best_mv.from_pixels();
- if best_dist <= DIST_THRESH {
- return (best_mv, best_dist);
- }
-
- // subpel refinement
- $self.set_new_point(best_mv, best_dist);
- loop {
- let mut cur_best_dist = best_dist;
- for (dist, &point) in $self.dist.iter_mut().zip($self.point.iter()) {
- if *dist == MAX_DIST {
- *dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, point, cur_best_dist);
- cur_best_dist = cur_best_dist.min(*dist);
- if *dist <= DIST_THRESH {
- break;
- }
- }
- }
- min_dist = $self.dist[0];
- min_idx = 0;
- for (i, &dist) in $self.dist.iter().enumerate().skip(1) {
- if dist < min_dist {
- min_dist = dist;
- min_idx = i;
- if dist <= DIST_THRESH {
- break;
- }
- }
- }
- if min_dist <= DIST_THRESH || min_idx == 0 || best_dist == min_dist || $self.point[min_idx].x.abs() >= $mv_est.mv_range * 4 || $self.point[min_idx].y.abs() >= $mv_est.mv_range * 4 {
- break;
- }
- best_dist = min_dist;
- $self.update($self.steps[min_idx]);
- }
- best_dist = min_dist;
- best_mv = $self.point[min_idx];
- if best_dist <= DIST_THRESH {
- return (best_mv, best_dist);
- }
- for &step in REFINEMENT.iter() {
- let mv = best_mv + step;
- let dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, mv, MAX_DIST);
- if best_dist > dist {
- best_dist = dist;
- best_mv = mv;
- }
- }
- (best_mv, best_dist)
- })
-}
-