diff options
Diffstat (limited to 'evc/src/codec')
-rw-r--r-- | evc/src/codec/compress.rs | 151 | ||||
-rw-r--r-- | evc/src/codec/decode.rs | 6 | ||||
-rw-r--r-- | evc/src/codec/encode/mod.rs | 29 | ||||
-rw-r--r-- | evc/src/codec/mod.rs | 1 |
4 files changed, 173 insertions, 14 deletions
diff --git a/evc/src/codec/compress.rs b/evc/src/codec/compress.rs new file mode 100644 index 0000000..e011669 --- /dev/null +++ b/evc/src/codec/compress.rs @@ -0,0 +1,151 @@ +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.push(ch[i] as u8) + } + } + 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] + .iter() + .map(|v| *v as f32) + .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 + } +} + +fn norm_idct_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_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) + } + + let scale = 2. / (w as f32 * h as f32).sqrt(); + for (i, v) in values_trans.iter().enumerate() { + values[i] = *v * scale + } +} + +fn transpose(w: usize, h: usize, values: &[f32]) -> Vec<f32> { + let mut i = 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[i]; + i += 1; + it += h; + } + } + transposed +} diff --git a/evc/src/codec/decode.rs b/evc/src/codec/decode.rs index 61234da..087483c 100644 --- a/evc/src/codec/decode.rs +++ b/evc/src/codec/decode.rs @@ -2,6 +2,8 @@ use crate::{ block::Block, frame::Frame, helpers::threading::both_par, refsampler::Sampler, view::View, }; +use super::compress::lit_decompress; + pub struct DecodeConfig { pub max_threads: usize, } @@ -29,7 +31,9 @@ pub fn decode_block( config.max_threads, ); } - Block::CompressedLiteral(_) => todo!(), + 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/mod.rs b/evc/src/codec/encode/mod.rs index 336f298..76fb481 100644 --- a/evc/src/codec/encode/mod.rs +++ b/evc/src/codec/encode/mod.rs @@ -30,7 +30,7 @@ pub enum EncodeMode { AdvancedPartial, } -pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfig) -> Block { +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, @@ -57,10 +57,10 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi (diff - irrelevance, refblock) }; if diff < config.ref_thres { - refblock + (diff, refblock) } else { if view.size.x < config.min_block_size || view.size.y < config.min_block_size { - Block::Literal(view.pixels()) + (0.0, Block::Literal(view.pixels())) } else { let [av, bv] = unsafe { std::mem::transmute::<_, [View<&'static Frame>; 2]>(view.split()) }; @@ -69,7 +69,7 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi let config = unsafe { std::mem::transmute::<_, &'static EncodeConfig>(config) }; // only bother to do multithreading, when the block is big. - let (a, b) = if view.area() > 100 { + let ((ad, a), (bd, b)) = if view.area() > 100 { both_par( || encode_block(av, ap, config), || encode_block(bv, bp, config), @@ -79,15 +79,18 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi (encode_block(av, ap, config), encode_block(bv, bp, config)) }; - 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])) - } + ( + 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])) + }, + ) } } } diff --git a/evc/src/codec/mod.rs b/evc/src/codec/mod.rs index 1c80d24..3203e6e 100644 --- a/evc/src/codec/mod.rs +++ b/evc/src/codec/mod.rs @@ -1,2 +1,3 @@ pub mod decode; pub mod encode; +pub mod compress; |