use crate::{ block::Block, frame::Frame, pixel::Pixel, threading::both_par, vec2::Vec2, view::View, }; #[derive(Debug, Clone)] pub struct EncodeConfig { pub translate: bool, pub ref_thres: f64, pub max_diff_size: isize, pub min_block_size: isize, pub max_threads: usize, // pub importance_k: f64, // pub importance_scale: f64, } pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfig) -> Block { // let importance = importance(&view); let (diff, translation) = if view.area() > config.max_diff_size { (f64::INFINITY, Vec2::ZERO) } else if config.translate { let mut best_diff = f64::INFINITY; let mut best_translation = Vec2::ZERO; const OFFSETS: &[isize] = &[-64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64]; for x in OFFSETS { for y in OFFSETS { let translation = Vec2 { x: *x, y: *y }; let diff = View::diff(&view, &prev.offset(translation)) / view.area() as f64; if diff < best_diff { best_translation = translation; best_diff = diff; } } } (best_diff, best_translation) } else { (View::diff(&view, &prev) / view.area() as f64, Vec2::ZERO) }; // config.importance_k) // / (config.importance_k + importance * config.importance_scale) if diff < (config.ref_thres) { Block::Reference { translation } } else { if view.size.x < config.min_block_size || view.size.y < config.min_block_size { Block::Literal(view.pixels()) } else { let [av, bv] = unsafe { std::mem::transmute::<_, [View<&'static Frame>; 2]>(view.split()) }; let [ap, bp] = unsafe { std::mem::transmute::<_, [View<&'static Frame>; 2]>(prev.split()) }; let config = unsafe { std::mem::transmute::<_, &'static EncodeConfig>(config) }; // only bother to do multithreading, when the block is big. let (a, b) = if view.size.x > 64 { both_par( || encode_block(av, ap, config), || encode_block(bv, bp, config), config.max_threads, ) } else { (encode_block(av, ap, config), encode_block(bv, bp, config)) }; if a.is_literal() && b.is_literal() { Block::Literal(view.pixels()) } else { Block::Split(Box::new([a, b])) } } } } pub fn importance(view: &View<&Frame>) -> f64 { let mut acc = 0; for x in 0..view.size.x { for y in 0..view.size.y { let p = Vec2 { x, y }; if x > 0 { acc += Pixel::distance(view[p], view[p + Vec2::LEFT]); } if y > 0 { acc += Pixel::distance(view[p], view[p + Vec2::UP]); } } } (acc / view.area() as usize) as f64 }