diff options
Diffstat (limited to 'evc/src/codec')
-rw-r--r-- | evc/src/codec/compress.rs | 155 | ||||
-rw-r--r-- | evc/src/codec/decode.rs | 34 | ||||
-rw-r--r-- | evc/src/codec/encode/advanced.rs | 115 | ||||
-rw-r--r-- | evc/src/codec/encode/mod.rs | 112 | ||||
-rw-r--r-- | evc/src/codec/encode/simple.rs | 65 | ||||
-rw-r--r-- | evc/src/codec/mod.rs | 3 |
6 files changed, 0 insertions, 484 deletions
diff --git a/evc/src/codec/compress.rs b/evc/src/codec/compress.rs deleted file mode 100644 index 09d1f29..0000000 --- a/evc/src/codec/compress.rs +++ /dev/null @@ -1,155 +0,0 @@ -use crate::{ - block::Block, - frame::Frame, - helpers::{pixel::Pixel, vector::Vec2}, - view::View, -}; -use rustdct::DctPlanner; - -pub fn compress_block(block: &mut Block, size: Vec2<usize>) { - match block { - Block::Literal(p) => { - let comp = lit_compress(size.x, size.y, &p); - *block = Block::CompressedLiteral(comp) - } - Block::Split(box [a, b]) => { - let vert = size.x > size.y; - compress_block( - a, - if vert { - Vec2 { - x: size.x / 2, - y: size.y, - } - } else { - Vec2 { - x: size.x, - y: size.y / 2, - } - }, - ); - compress_block( - b, - if vert { - Vec2 { - x: size.x - size.x / 2, - y: size.y, - } - } else { - Vec2 { - x: size.x, - y: size.y - size.y / 2, - } - }, - ); - } - _ => (), - } -} - -pub fn lit_compress(w: usize, h: usize, pixels: &[Pixel]) -> Vec<u8> { - let mut out = vec![]; - for ci in 0..3 { - let mut ch = vec![0.; w * h]; - for y in 0..h { - for x in 0..w { - let p = pixels[x + y * w]; - ch[x + y * w] = match ci { - 0 => p.r, - 1 => p.g, - 2 => p.b, - _ => unreachable!(), - } as f32 - } - } - - norm_dct_channel(w, h, &mut ch); - for i in 0..w * h { - out.extend(unsafe { std::mem::transmute::<_, [u8; 4]>(ch[i]) }); - } - } - out -} - -pub fn lit_decompress(compressed: &[u8], mut target: View<&mut Frame>) { - let (w, h) = (target.size.x as usize, target.size.y as usize); - for ci in 0..3 { - let mut ch = compressed[ci * w * h..(ci + 1) * w * h] - .chunks_exact(4) - .map(|v| unsafe { - std::mem::transmute::<_, f32>(TryInto::<[u8; 4]>::try_into(v).unwrap()) - }) - .collect::<Vec<_>>(); - norm_idct_channel(w, h, &mut ch); - for y in 0..h { - for x in 0..w { - let p = &mut target[Vec2 { - x: x as isize, - y: y as isize, - }]; - *(match ci { - 0 => &mut p.r, - 1 => &mut p.g, - 2 => &mut p.b, - _ => unreachable!(), - }) = ch[x + y * w] as u8 - } - } - } -} - -fn norm_dct_channel(w: usize, h: usize, values: &mut [f32]) { - let d = DctPlanner::new().plan_dct2(w); - let mut temp = vec![0.; d.get_scratch_len()]; - for c in values.chunks_exact_mut(w) { - d.process_dct2_with_scratch(c, &mut temp) - } - - let mut values_trans = transpose(w, h, values); - let d = DctPlanner::new().plan_dct2(h); - let mut temp = vec![0.; d.get_scratch_len()]; - for c in values_trans.chunks_exact_mut(h) { - d.process_dct2_with_scratch(c, &mut temp) - } - - let scale = 2. / (w as f32 * h as f32).sqrt(); - for (i, v) in values_trans.iter().enumerate() { - values[i] = *v * scale * 127.0 - } -} - -fn norm_idct_channel(h: usize, w: usize, values: &mut [f32]) { - let scale = 2. / (w as f32 * h as f32).sqrt(); - for v in values.iter_mut() { - *v /= scale * 127.0 - } - - let d = DctPlanner::new().plan_dct2(w); - let mut temp = vec![0.; d.get_scratch_len()]; - for c in values.chunks_exact_mut(w) { - d.process_dct3_with_scratch(c, &mut temp) - } - - let mut values_trans = transpose(w, h, values); - let d = DctPlanner::new().plan_dct2(h); - let mut temp = vec![0.; d.get_scratch_len()]; - for c in values_trans.chunks_exact_mut(h) { - d.process_dct3_with_scratch(c, &mut temp) - } - values.copy_from_slice(&values_trans) -} - -fn transpose(w: usize, h: usize, values: &[f32]) -> Vec<f32> { - let mut io = 0; - let mut it; - let mut transposed = vec![0.; values.len()]; - for row in 0..h { - it = row; - for _ in 0..w { - transposed[it] = values[io]; - io += 1; - it += h; - } - } - transposed -} diff --git a/evc/src/codec/decode.rs b/evc/src/codec/decode.rs deleted file mode 100644 index c042278..0000000 --- a/evc/src/codec/decode.rs +++ /dev/null @@ -1,34 +0,0 @@ -use super::compress::lit_decompress; -use crate::{block::Block, frame::Frame, refsampler::Sampler, view::View}; - -pub struct DecodeConfig {} - -pub fn decode_block( - block: &Block, - mut target: View<&mut Frame>, - prev: View<&Frame>, - config: &DecodeConfig, -) { - match &block { - Block::Literal(pixels) => target.set_pixels(pixels), - Block::Split(box [a, b]) => { - let [a, b] = unsafe { std::mem::transmute::<_, [&'static Block; 2]>([a, b]) }; - let [at, bt] = unsafe { - std::mem::transmute::<_, [View<&'static mut Frame>; 2]>(target.split_mut_unsafe()) - }; - let [ap, bp] = - unsafe { std::mem::transmute::<_, [View<&'static Frame>; 2]>(prev.split()) }; - let config = unsafe { std::mem::transmute::<_, &'static DecodeConfig>(config) }; - - rayon::join( - move || decode_block(a, at, ap, config), - move || decode_block(b, bt, bp, config), - ); - } - Block::CompressedLiteral(data) => { - lit_decompress(&data, target); - } - Block::Reference { translation } => target.copy_from(&prev.offset(*translation)), - Block::AdvancedReference(r) => target.copy_from_sampler(&Sampler::from_refblock(prev, r)), - } -} diff --git a/evc/src/codec/encode/advanced.rs b/evc/src/codec/encode/advanced.rs deleted file mode 100644 index 0e45176..0000000 --- a/evc/src/codec/encode/advanced.rs +++ /dev/null @@ -1,115 +0,0 @@ -use super::EncodeConfig; -use crate::{ - block::{AdvancedReference, Block}, - frame::Frame, - refsampler::Sampler, - view::View, -}; - -pub fn default( - view: &View<&Frame>, - prev: &View<&Frame>, - config: &EncodeConfig, - max_diff: f64, -) -> (f64, Block) { - let mut pm = AdvancedReference::default(); - let sampler = Sampler::from_refblock(prev.clone(), &pm); - let mut diff = View::diff_sampler(&view, &sampler); - if diff < max_diff { - (diff, Block::REFZERO) - } else { - loop { - let (mut d, mut p) = (diff, pm.clone()); - - if config.do_translate { - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 4); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 4); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 4); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 4); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 2); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 2); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 2); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 2); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 1); - } - if config.do_value_scale { - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.value_scale += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.value_scale -= 1); - } - if config.do_linear_transform { - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.a -= 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.a += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.b -= 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.b += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.c -= 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.c += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.d -= 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.d += 1); - } - - if d >= diff { - break (diff, Block::AdvancedReference(pm)); - } - - diff = d; - pm = p; - } - } -} - -pub fn partial( - view: &View<&Frame>, - prev: &View<&Frame>, - _config: &EncodeConfig, - max_diff: f64, -) -> (f64, Block) { - let mut pm = AdvancedReference::default(); - let sampler = Sampler::from_refblock(prev.clone(), &pm); - let mut diff = View::diff_sampler(&view, &sampler); - if diff < max_diff { - (diff, Block::REFZERO) - } else { - loop { - let (mut d, mut p) = (diff, pm.clone()); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 2); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 2); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 2); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 2); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 1); - - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.value_scale += 1); - pk(&view, &prev, &mut d, &mut p, &pm, |p| p.value_scale -= 1); - - if d >= diff { - break (diff, Block::AdvancedReference(pm)); - } - diff = d; - pm = p; - } - } -} - -#[inline] -fn pk<F: FnMut(&mut AdvancedReference) -> ()>( - view: &View<&Frame>, - prev: &View<&Frame>, - diff: &mut f64, - params: &mut AdvancedReference, - initial_params: &AdvancedReference, - mut f: F, -) { - let mut p = initial_params.clone(); - f(&mut p); - let sampler = Sampler::from_refblock(prev.clone(), &p); - let d = View::diff_sampler(view, &sampler); - if d < *diff { - *diff = d; - *params = p; - } -} diff --git a/evc/src/codec/encode/mod.rs b/evc/src/codec/encode/mod.rs deleted file mode 100644 index 30342f0..0000000 --- a/evc/src/codec/encode/mod.rs +++ /dev/null @@ -1,112 +0,0 @@ -pub mod advanced; -pub mod simple; - -use crate::{ - block::Block, - frame::Frame, - helpers::{pixel::Pixel, vector::Vec2}, - view::View, -}; -use clap::ValueEnum; - -#[derive(Debug, Clone)] -pub struct EncodeConfig { - pub mode: EncodeMode, - pub ref_thres: f64, - pub max_diff_area: isize, - pub min_block_size: isize, - pub weight_factor: f64, - - pub do_translate: bool, - pub do_value_scale: bool, - pub do_linear_transform: bool, -} - -#[derive(Debug, Clone, ValueEnum)] -pub enum EncodeMode { - Trivial, - SimpleFast, - SimpleExhaustive, - Advanced, - AdvancedPartial, -} - -pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfig) -> (f64, Block) { - let (diff, refblock) = if view.area() > config.max_diff_area { - ( - f64::INFINITY, - Block::Reference { - translation: Vec2::<isize>::ZERO, - }, - ) - } else { - let weight = importance(&view).max(0.5); - let irrelevance = config.weight_factor / weight; - let max_diff = config.ref_thres - irrelevance; - let (diff, refblock) = match config.mode { - EncodeMode::Trivial => ( - View::diff(&view, &prev), - Block::Reference { - translation: Vec2::<isize>::ZERO, - }, - ), - EncodeMode::SimpleExhaustive => simple::exhaustive(&view, &prev, config, max_diff), - EncodeMode::SimpleFast => simple::fast(&view, &prev, config, max_diff), - EncodeMode::Advanced => advanced::default(&view, &prev, config, max_diff), - EncodeMode::AdvancedPartial => advanced::partial(&view, &prev, config, max_diff), - }; - (diff - irrelevance, refblock) - }; - if diff < config.ref_thres { - (diff, refblock) - } else { - if view.size.x < config.min_block_size || view.size.y < config.min_block_size { - (0.0, 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 ((ad, a), (bd, b)) = if view.area() > 100 { - rayon::join( - || encode_block(av, ap, config), - || encode_block(bv, bp, config), - ) - } else { - (encode_block(av, ap, config), encode_block(bv, bp, config)) - }; - - ( - ad + bd, - if a.is_literal() && b.is_literal() { - Block::Literal(view.pixels()) - } else if Block::identical_ref(&a, &b) { - Block::Reference { - translation: Vec2::<isize>::ZERO, - } - } 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::<isize>::LEFT]); - } - if y > 0 { - acc += Pixel::distance(view[p], view[p + Vec2::<isize>::UP]); - } - } - } - (acc / view.area() as usize) as f64 -} diff --git a/evc/src/codec/encode/simple.rs b/evc/src/codec/encode/simple.rs deleted file mode 100644 index 2a971af..0000000 --- a/evc/src/codec/encode/simple.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::{block::Block, frame::Frame, helpers::vector::Vec2, view::View}; - -use super::EncodeConfig; - -pub fn exhaustive( - view: &View<&Frame>, - prev: &View<&Frame>, - _config: &EncodeConfig, - _max_diff: f64, -) -> (f64, Block) { - let mut diff = f64::INFINITY; - let mut translation = Vec2::<isize>::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 t = Vec2 { x: *x, y: *y }; - let d = View::diff(&view, &prev.offset(t)); - if d < diff { - translation = t; - diff = d; - } - } - } - (diff, Block::Reference { translation }) -} - -pub fn fast( - view: &View<&Frame>, - prev: &View<&Frame>, - _config: &EncodeConfig, - max_diff: f64, -) -> (f64, Block) { - let mut offset = Vec2::<isize>::ZERO; - let mut diff = View::diff(&view, &prev); - if diff < max_diff { - (diff, Block::REFZERO) - } else { - loop { - let (mut d, mut o) = (diff, offset); - let mut probe = |test_o: Vec2<isize>| { - let test_d = View::diff(&prev.clone().offset(test_o), &view); - if test_d < d { - d = test_d; - o = test_o; - } - }; - - probe(offset + Vec2 { x: 8, y: 0 }); - probe(offset + Vec2 { x: -8, y: 0 }); - probe(offset + Vec2 { x: 0, y: 8 }); - probe(offset + Vec2 { x: 0, y: -8 }); - - probe(offset + Vec2 { x: 1, y: 0 }); - probe(offset + Vec2 { x: -1, y: 0 }); - probe(offset + Vec2 { x: 0, y: 1 }); - probe(offset + Vec2 { x: 0, y: -1 }); - - if d >= diff { - break (diff, Block::Reference { translation: o }); - } - diff = d; - offset = o; - } - } -} diff --git a/evc/src/codec/mod.rs b/evc/src/codec/mod.rs deleted file mode 100644 index 3203e6e..0000000 --- a/evc/src/codec/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod decode; -pub mod encode; -pub mod compress; |