1 use nihav_codec_support::codecs::{MV, ZERO_MV};
5 #[derive(Debug,Clone,Copy,PartialEq)]
7 pub enum MVSearchMode {
15 impl Default for MVSearchMode {
16 fn default() -> Self { MVSearchMode::Hexagon }
19 pub struct ParseError{}
21 impl FromStr for MVSearchMode {
22 type Err = ParseError;
24 #[allow(clippy::single_match)]
25 fn from_str(s: &str) -> Result<Self, Self::Err> {
27 "full" => Ok(MVSearchMode::Full),
28 "sea" => Ok(MVSearchMode::SEA),
29 "dia" => Ok(MVSearchMode::Diamond),
30 "hex" => Ok(MVSearchMode::Hexagon),
31 "epzs" => Ok(MVSearchMode::EPZS),
32 _ => Err(ParseError{}),
37 impl std::fmt::Display for MVSearchMode {
38 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
40 MVSearchMode::Full => write!(f, "full"),
41 MVSearchMode::SEA => write!(f, "sea"),
42 MVSearchMode::Diamond => write!(f, "dia"),
43 MVSearchMode::Hexagon => write!(f, "hex"),
44 MVSearchMode::EPZS => write!(f, "epzs"),
50 fn from_pixels(self) -> Self;
53 impl FromPixels for MV {
54 fn from_pixels(self) -> MV {
55 MV { x: self.x * 4, y: self.y * 4 }
59 pub const DIA_PATTERN: [MV; 9] = [
71 pub const HEX_PATTERN: [MV; 7] = [
81 pub const REFINEMENT: [MV; 4] = [
89 macro_rules! search_template {
90 ($self: expr, $mv_est: expr, $cur_blk: expr, $mb_x: expr, $mb_y: expr, $sad_func: ident, $threshold: expr) => ({
91 search_template!($self, $mv_est, $cur_blk, $mb_x, $mb_y, $sad_func, $threshold, ZERO_MV, MAX_DIST, true)
93 ($self: expr, $mv_est: expr, $cur_blk: expr, $mb_x: expr, $mb_y: expr, $sad_func: ident, $threshold: expr, $start_mv: expr, $best_dist: expr, $fullpel_stage: expr) => ({
94 let mut best_dist = $best_dist;
95 let mut best_mv = $start_mv;
103 let mut cur_best_dist = best_dist;
104 for (dist, &point) in $self.dist.iter_mut().zip($self.point.iter()) {
105 if *dist == MAX_DIST {
106 *dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, point.from_pixels(), cur_best_dist);
107 cur_best_dist = cur_best_dist.min(*dist);
108 if *dist <= $threshold {
113 min_dist = $self.dist[0];
115 for (i, &dist) in $self.dist.iter().enumerate().skip(1) {
119 if dist <= $threshold {
124 if min_dist <= $threshold || 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 {
127 best_dist = min_dist;
128 $self.update($self.steps[min_idx]);
130 best_dist = min_dist;
131 best_mv = $self.point[min_idx];
132 if best_dist <= $threshold {
133 return (best_mv.from_pixels(), best_dist);
135 for &step in REFINEMENT.iter() {
136 let mv = best_mv + step;
137 let dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, mv.from_pixels(), MAX_DIST);
138 if best_dist > dist {
143 best_mv = best_mv.from_pixels();
144 if best_dist <= $threshold {
145 return (best_mv, best_dist);
150 $self.set_new_point(best_mv, best_dist);
152 let mut cur_best_dist = best_dist;
153 for (dist, &point) in $self.dist.iter_mut().zip($self.point.iter()) {
154 if *dist == MAX_DIST {
155 *dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, point, cur_best_dist);
156 cur_best_dist = cur_best_dist.min(*dist);
157 if *dist <= $threshold {
162 min_dist = $self.dist[0];
164 for (i, &dist) in $self.dist.iter().enumerate().skip(1) {
168 if dist <= $threshold {
173 if min_dist <= $threshold || min_idx == 0 || best_dist == min_dist || $self.point[min_idx].x.abs() >= $mv_est.mv_range * 8 || $self.point[min_idx].y.abs() >= $mv_est.mv_range * 8 {
176 best_dist = min_dist;
177 $self.update($self.steps[min_idx]);
179 best_dist = min_dist;
180 best_mv = $self.point[min_idx];
181 if best_dist <= $threshold {
182 return (best_mv, best_dist);
184 for &step in REFINEMENT.iter() {
185 let mv = best_mv + step;
186 let dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, mv, MAX_DIST);
187 if best_dist > dist {