1 use nihav_codec_support::codecs::{MV, ZERO_MV};
5 #[derive(Debug,Clone,Copy,PartialEq,Default)]
6 pub enum MVSearchMode {
15 pub struct ParseError{}
17 impl FromStr for MVSearchMode {
18 type Err = ParseError;
20 fn from_str(s: &str) -> Result<Self, Self::Err> {
22 "full" => Ok(MVSearchMode::Full),
23 "sea" => Ok(MVSearchMode::SEA),
24 "dia" => Ok(MVSearchMode::Diamond),
25 "hex" => Ok(MVSearchMode::Hexagon),
26 "epzs" => Ok(MVSearchMode::EPZS),
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::SEA => write!(f, "sea"),
37 MVSearchMode::Diamond => write!(f, "dia"),
38 MVSearchMode::Hexagon => write!(f, "hex"),
39 MVSearchMode::EPZS => write!(f, "epzs"),
44 pub const DIA_PATTERN: [MV; 9] = [
56 pub const HEX_PATTERN: [MV; 7] = [
66 pub const REFINEMENT: [MV; 4] = [
74 macro_rules! search_template {
75 ($self: expr, $mv_est: expr, $cur_blk: expr, $mb_x: expr, $mb_y: expr, $sad_func: ident, $threshold: expr) => ({
76 search_template!($self, $mv_est, $cur_blk, $mb_x, $mb_y, $sad_func, $threshold, ZERO_MV, MAX_DIST, true)
78 ($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) => ({
79 let mut best_dist = $best_dist;
80 let mut best_mv = $start_mv;
88 let mut cur_best_dist = best_dist;
89 for (dist, &point) in $self.dist.iter_mut().zip($self.point.iter()) {
90 if *dist == MAX_DIST {
91 *dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, point.from_pixels(), cur_best_dist);
92 cur_best_dist = cur_best_dist.min(*dist);
93 if *dist <= $threshold {
98 min_dist = $self.dist[0];
100 for (i, &dist) in $self.dist.iter().enumerate().skip(1) {
104 if dist <= $threshold {
109 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 {
112 best_dist = min_dist;
113 $self.update($self.steps[min_idx]);
115 best_dist = min_dist;
116 best_mv = $self.point[min_idx];
117 if best_dist <= $threshold {
118 return (best_mv.from_pixels(), best_dist);
120 for &step in REFINEMENT.iter() {
121 let mv = best_mv + step;
122 let dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, mv.from_pixels(), MAX_DIST);
123 if best_dist > dist {
128 best_mv = best_mv.from_pixels();
129 if best_dist <= $threshold {
130 return (best_mv, best_dist);
135 $self.set_new_point(best_mv, best_dist);
137 let mut cur_best_dist = best_dist;
138 for (dist, &point) in $self.dist.iter_mut().zip($self.point.iter()) {
139 if *dist == MAX_DIST {
140 *dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, point, cur_best_dist);
141 cur_best_dist = cur_best_dist.min(*dist);
142 if *dist <= $threshold {
147 min_dist = $self.dist[0];
149 for (i, &dist) in $self.dist.iter().enumerate().skip(1) {
153 if dist <= $threshold {
158 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 {
161 best_dist = min_dist;
162 $self.update($self.steps[min_idx]);
164 best_dist = min_dist;
165 best_mv = $self.point[min_idx];
166 if best_dist <= $threshold {
167 return (best_mv, best_dist);
169 for &step in REFINEMENT.iter() {
170 let mv = best_mv + step;
171 let dist = $mv_est.$sad_func($cur_blk, $mb_x, $mb_y, mv, MAX_DIST);
172 if best_dist > dist {