X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-duck%2Fsrc%2Fcodecs%2Fvpenc%2Fmotion_est.rs;fp=nihav-duck%2Fsrc%2Fcodecs%2Fvpenc%2Fmotion_est.rs;h=005780c530ce78bc0f2eaaf9705ab2c724424a4e;hp=128633f01e8760a2cf8e5c993bc636e01db0e7ee;hb=c5d5793c1fd18882a32acabb8141a221b0a97b61;hpb=b922b48d3b003b2f4b84755541fd9dc4be8f22f6 diff --git a/nihav-duck/src/codecs/vpenc/motion_est.rs b/nihav-duck/src/codecs/vpenc/motion_est.rs index 128633f..005780c 100644 --- a/nihav-duck/src/codecs/vpenc/motion_est.rs +++ b/nihav-duck/src/codecs/vpenc/motion_est.rs @@ -3,10 +3,13 @@ use nihav_codec_support::codecs::{MV, ZERO_MV}; use std::str::FromStr; #[derive(Debug,Clone,Copy,PartialEq)] +#[allow(dead_code)] pub enum MVSearchMode { Full, + SEA, Diamond, Hexagon, + EPZS, } impl Default for MVSearchMode { @@ -22,8 +25,10 @@ impl FromStr for MVSearchMode { fn from_str(s: &str) -> Result { match s { "full" => Ok(MVSearchMode::Full), + "sea" => Ok(MVSearchMode::SEA), "dia" => Ok(MVSearchMode::Diamond), "hex" => Ok(MVSearchMode::Hexagon), + "epzs" => Ok(MVSearchMode::EPZS), _ => Err(ParseError{}), } } @@ -33,8 +38,10 @@ impl std::fmt::Display for MVSearchMode { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { MVSearchMode::Full => write!(f, "full"), + MVSearchMode::SEA => write!(f, "sea"), MVSearchMode::Diamond => write!(f, "dia"), MVSearchMode::Hexagon => write!(f, "hex"), + MVSearchMode::EPZS => write!(f, "epzs"), } } } @@ -80,58 +87,63 @@ pub const REFINEMENT: [MV; 4] = [ #[macro_export] 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; + ($self: expr, $mv_est: expr, $cur_blk: expr, $mb_x: expr, $mb_y: expr, $sad_func: ident, $threshold: expr) => ({ + search_template!($self, $mv_est, $cur_blk, $mb_x, $mb_y, $sad_func, $threshold, ZERO_MV, MAX_DIST, true) + }); + ($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) => ({ + let mut best_dist = $best_dist; + let mut best_mv = $start_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; + if $fullpel_stage { + $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 <= $threshold { + 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; + 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 <= $threshold { + 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; + 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 { + break; + } + best_dist = min_dist; + $self.update($self.steps[min_idx]); } 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 = $self.point[min_idx]; + if best_dist <= $threshold { + 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 <= $threshold { + return (best_mv, best_dist); } - } - best_mv = best_mv.from_pixels(); - if best_dist <= DIST_THRESH { - return (best_mv, best_dist); } // subpel refinement @@ -142,7 +154,7 @@ macro_rules! search_template { 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 { + if *dist <= $threshold { break; } } @@ -153,12 +165,12 @@ macro_rules! search_template { if dist < min_dist { min_dist = dist; min_idx = i; - if dist <= DIST_THRESH { + if dist <= $threshold { 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 { + 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 { break; } best_dist = min_dist; @@ -166,7 +178,7 @@ macro_rules! search_template { } best_dist = min_dist; best_mv = $self.point[min_idx]; - if best_dist <= DIST_THRESH { + if best_dist <= $threshold { return (best_mv, best_dist); } for &step in REFINEMENT.iter() { @@ -178,5 +190,5 @@ macro_rules! search_template { } } (best_mv, best_dist) - }) + }); }