1 use nihav_codec_support::codecs::{MV, ZERO_MV};
5 #[derive(Debug,Clone,Copy,PartialEq)]
6 pub enum MVSearchMode {
12 impl Default for MVSearchMode {
13 fn default() -> Self { MVSearchMode::Hexagon }
16 pub struct ParseError{}
18 impl FromStr for MVSearchMode {
19 type Err = ParseError;
21 #[allow(clippy::single_match)]
22 fn from_str(s: &str) -> Result<Self, Self::Err> {
24 "full" => Ok(MVSearchMode::Full),
25 "dia" => Ok(MVSearchMode::Diamond),
26 "hex" => Ok(MVSearchMode::Hexagon),
27 _ => Err(ParseError{}),
32 impl std::fmt::Display for MVSearchMode {
33 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
35 MVSearchMode::Full => write!(f, "full"),
36 MVSearchMode::Diamond => write!(f, "dia"),
37 MVSearchMode::Hexagon => write!(f, "hex"),
43 fn from_pixels(self) -> Self;
46 impl FromPixels for MV {
47 fn from_pixels(self) -> MV {
48 MV { x: self.x * 4, y: self.y * 4 }
52 pub const DIA_PATTERN: [MV; 9] = [
64 pub const HEX_PATTERN: [MV; 7] = [
74 pub const REFINEMENT: [MV; 4] = [
82 macro_rules! search_template {
83 ($self: expr, $mv_est: expr, $cur_blk: expr, $mb_x: expr, $mb_y: expr, $sad_func: ident) => ({
84 let mut best_dist = MAX_DIST;
92 let mut cur_best_dist = best_dist;
93 for (dist, &point) in $self.dist.iter_mut().zip($self.point.iter()) {
94 if *dist == MAX_DIST {
95 *dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, point.from_pixels(), cur_best_dist);
96 cur_best_dist = cur_best_dist.min(*dist);
97 if *dist <= DIST_THRESH {
102 min_dist = $self.dist[0];
104 for (i, &dist) in $self.dist.iter().enumerate().skip(1) {
108 if dist <= DIST_THRESH {
113 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 {
116 best_dist = min_dist;
117 $self.update($self.steps[min_idx]);
119 best_dist = min_dist;
120 best_mv = $self.point[min_idx];
121 if best_dist <= DIST_THRESH {
122 return (best_mv.from_pixels(), best_dist);
124 for &step in REFINEMENT.iter() {
125 let mv = best_mv + step;
126 let dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, mv.from_pixels(), MAX_DIST);
127 if best_dist > dist {
132 best_mv = best_mv.from_pixels();
133 if best_dist <= DIST_THRESH {
134 return (best_mv, best_dist);
138 $self.set_new_point(best_mv, best_dist);
140 let mut cur_best_dist = best_dist;
141 for (dist, &point) in $self.dist.iter_mut().zip($self.point.iter()) {
142 if *dist == MAX_DIST {
143 *dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, point, cur_best_dist);
144 cur_best_dist = cur_best_dist.min(*dist);
145 if *dist <= DIST_THRESH {
150 min_dist = $self.dist[0];
152 for (i, &dist) in $self.dist.iter().enumerate().skip(1) {
156 if dist <= DIST_THRESH {
161 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 {
164 best_dist = min_dist;
165 $self.update($self.steps[min_idx]);
167 best_dist = min_dist;
168 best_mv = $self.point[min_idx];
169 if best_dist <= DIST_THRESH {
170 return (best_mv, best_dist);
172 for &step in REFINEMENT.iter() {
173 let mv = best_mv + step;
174 let dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, mv, MAX_DIST);
175 if best_dist > dist {