diff options
Diffstat (limited to 'evc')
-rw-r--r-- | evc/src/bin/encode.rs | 17 | ||||
-rw-r--r-- | evc/src/block.rs | 6 | ||||
-rw-r--r-- | evc/src/codec/encode.rs | 46 | ||||
-rw-r--r-- | evc/src/debug.rs | 24 | ||||
-rw-r--r-- | evc/src/lib.rs | 3 | ||||
-rw-r--r-- | evc/src/pixel.rs | 30 | ||||
-rw-r--r-- | evc/src/view.rs | 4 |
7 files changed, 100 insertions, 30 deletions
diff --git a/evc/src/bin/encode.rs b/evc/src/bin/encode.rs index 05ebd24..d6029aa 100644 --- a/evc/src/bin/encode.rs +++ b/evc/src/bin/encode.rs @@ -1,7 +1,10 @@ use anyhow::Context; use clap::Parser; use evc::{ - codec::{decode::decode_block, encode::encode_block}, + codec::{ + decode::decode_block, + encode::{encode_block, EncodeConfig}, + }, frame::Frame, header::Header, ser::Sink, @@ -17,6 +20,11 @@ pub struct EncodeArgs { width: usize, #[arg(short = 'H', long)] height: usize, + + #[arg(short = 't', long, default_value = "0.9")] + ref_thres: f64, + #[arg(short = 'T', long)] + no_translation: bool, } fn main() -> anyhow::Result<()> { @@ -26,6 +34,11 @@ fn main() -> anyhow::Result<()> { let mut input = BufReader::new(std::io::stdin()); let mut output = BufWriter::new(std::io::stdout()); + let config = EncodeConfig { + translate: !args.no_translation, + ref_thres: args.ref_thres, + }; + let size = Vec2 { x: args.width as isize, y: args.height as isize, @@ -47,7 +60,7 @@ fn main() -> anyhow::Result<()> { let v1 = frame.view(); let v2 = prev_frame.view(); - let root = encode_block(v1, v2); + let root = encode_block(v1, v2, &config); root.write(&mut output).context("writing encoded frame")?; decode_block(&root, frame.view_mut(), prev_frame.view()); diff --git a/evc/src/block.rs b/evc/src/block.rs index d0dd4d5..024adb6 100644 --- a/evc/src/block.rs +++ b/evc/src/block.rs @@ -25,9 +25,9 @@ impl Block { a.write(sink)?; b.write(sink)?; } - Block::Reference { translation: _ } => { + Block::Reference { translation } => { sink.put(2u8)?; - // sink.put(*translation)?; + sink.put(*translation)?; } } Ok(()) @@ -54,7 +54,7 @@ impl Block { [a, b] })), 2 => Block::Reference { - translation: Vec2::ZERO, //source.get()?, + translation: source.get()?, }, x => bail!("corrupt block type ({})", x), }) diff --git a/evc/src/codec/encode.rs b/evc/src/codec/encode.rs index 7256265..a5cb94b 100644 --- a/evc/src/codec/encode.rs +++ b/evc/src/codec/encode.rs @@ -1,28 +1,40 @@ -use crate::{block::Block, frame::Frame, view::View, vec2::Vec2}; +use crate::{block::Block, frame::Frame, vec2::Vec2, view::View}; -pub fn encode_block(view: View<&Frame>, prev: View<&Frame>) -> Block { - // let mut best_diff = f64::INFINITY; - // for x in [-32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32] { - // for y in [-32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32] { - // let diff = View::diff(&view, &prev) / view.area() as f64; - // if diff < best_diff { - // } - // } - // } - let diff = View::diff(&view, &prev) / view.area() as f64; - // if best_diff < 0.9 { - if diff < 0.9 { - Block::Reference { - translation: Vec2::ZERO, +#[derive(Debug, Clone)] +pub struct EncodeConfig { + pub translate: bool, + pub ref_thres: f64, +} + +pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfig) -> Block { + let (diff, translation) = if view.area() > 10_000 { + (f64::INFINITY, Vec2::ZERO) + } else if config.translate { + let mut best_diff = f64::INFINITY; + let mut best_translation = Vec2::ZERO; + for x in [-32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32] { + for y in [-32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32] { + let diff = View::diff(&view, &prev) / view.area() as f64; + if diff < best_diff { + best_translation = Vec2 { x, y }; + best_diff = diff; + } + } } + (best_diff, best_translation) + } else { + (View::diff(&view, &prev) / view.area() as f64, Vec2::ZERO) + }; + if diff < config.ref_thres { + Block::Reference { translation } } else { if view.size.x < 16 { Block::Literal(view.pixels()) } else { let [av, bv] = view.split(); let [ap, bp] = prev.split(); - let a = encode_block(av, ap); - let b = encode_block(bv, bp); + let a = encode_block(av, ap, config); + let b = encode_block(bv, bp, config); if a.is_literal() && b.is_literal() { Block::Literal(view.pixels()) } else { diff --git a/evc/src/debug.rs b/evc/src/debug.rs index 7b27b83..cbc598e 100644 --- a/evc/src/debug.rs +++ b/evc/src/debug.rs @@ -1,4 +1,4 @@ -use crate::{frame::Frame, pixel::Pixel, view::View}; +use crate::{frame::Frame, pixel::Pixel, vec2::Vec2, view::View}; impl View<&mut Frame> { pub fn draw_box(&mut self, color: Pixel) { @@ -14,6 +14,28 @@ impl View<&mut Frame> { } } } + +impl Frame { + pub fn draw_line(&mut self, start: Vec2, end: Vec2, color: Pixel) { + let (sx, sy) = (start.x as f32, start.y as f32); + let (ex, ey) = (end.x as f32, end.y as f32); + let (dx, dy) = (ex - sx, ey - sy); + let len = (dx * dx + dy * dy).sqrt(); + let (nx, ny) = (dx / len, dy / len); + let (mut cx, mut cy) = (sx, sy); + let mut lc = 0.0; + while lc < len { + self[Vec2 { + x: cx as isize, + y: cy as isize, + }] = color; + lc += 0.5; + cx += nx * 0.5; + cy += ny * 0.5; + } + } +} + impl Pixel { pub const RED: Pixel = Pixel { r: 255, g: 0, b: 0 }; pub const GREEN: Pixel = Pixel { r: 0, g: 255, b: 0 }; diff --git a/evc/src/lib.rs b/evc/src/lib.rs index ee242e6..22866e1 100644 --- a/evc/src/lib.rs +++ b/evc/src/lib.rs @@ -1,4 +1,7 @@ #![feature(box_patterns)] +#![feature(const_fn_floating_point_arithmetic)] +// #![feature(const_for)] +// #![feature(const_mut_refs)] pub mod block; pub mod codec; diff --git a/evc/src/pixel.rs b/evc/src/pixel.rs index b3ef841..4fb6772 100644 --- a/evc/src/pixel.rs +++ b/evc/src/pixel.rs @@ -21,12 +21,32 @@ impl Ser for Pixel { impl Pixel { pub const BLACK: Pixel = Pixel { r: 0, g: 0, b: 0 }; #[inline] - pub fn distance(a: Pixel, b: Pixel) -> f64 { + pub fn distance(a: Pixel, b: Pixel) -> usize { let (rd, gd, bd) = ( - a.r.abs_diff(b.r) as f64, - a.r.abs_diff(b.r) as f64, - a.r.abs_diff(b.r) as f64, + a.r.abs_diff(b.r) as usize, + a.r.abs_diff(b.r) as usize, + a.r.abs_diff(b.r) as usize, ); - (rd * rd + gd * gd + bd * bd).sqrt() + SQRT[rd + gd + bd] } } + +const SQRT: [usize; 256 * 3] = gen_sqrt_lookup(); + +const fn gen_sqrt_lookup<const N: usize>() -> [usize; N] { + let mut arr = [0; N]; + let mut i = 0; + while i < N { + arr[i] = sqrt(i as f32) as usize; + i += 1; + } + arr +} + +const fn sqrt(x: f32) -> f32 { + let a = 1.0; + let a = (a + x / a) * 0.5; + let a = (a + x / a) * 0.5; + let a = (a + x / a) * 0.5; + a +} diff --git a/evc/src/view.rs b/evc/src/view.rs index 4cd4a45..45c1728 100644 --- a/evc/src/view.rs +++ b/evc/src/view.rs @@ -124,7 +124,7 @@ impl<T: Copy> View<T> { impl<T: Index<Vec2, Output = Pixel>> View<&T> { pub fn diff(va: &Self, vb: &Self) -> f64 { assert_eq!(va.size, vb.size); - let mut acc = 0.0; + let mut acc = 0; for x in 0..va.size.x { for y in 0..va.size.y { let a = va[(x, y)]; @@ -132,7 +132,7 @@ impl<T: Index<Vec2, Output = Pixel>> View<&T> { acc += Pixel::distance(a, b); } } - acc + acc as f64 } pub fn pixels(&self) -> Vec<Pixel> { let mut v = vec![]; |