diff options
author | metamuffin <metamuffin@disroot.org> | 2022-12-08 20:13:27 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2022-12-08 20:13:27 +0100 |
commit | 1b3835a38ed38d377ce337836a4b32ee89ca0289 (patch) | |
tree | 6e07407031984b989c35c581a10e857ef1f66b07 /evc/src/codec/encode/mod.rs | |
parent | a92c9958a539eccd545b4947202a1c9b39953851 (diff) | |
download | video-codec-experiments-1b3835a38ed38d377ce337836a4b32ee89ca0289.tar video-codec-experiments-1b3835a38ed38d377ce337836a4b32ee89ca0289.tar.bz2 video-codec-experiments-1b3835a38ed38d377ce337836a4b32ee89ca0289.tar.zst |
rename modes
Diffstat (limited to 'evc/src/codec/encode/mod.rs')
-rw-r--r-- | evc/src/codec/encode/mod.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/evc/src/codec/encode/mod.rs b/evc/src/codec/encode/mod.rs new file mode 100644 index 0000000..2ccac64 --- /dev/null +++ b/evc/src/codec/encode/mod.rs @@ -0,0 +1,105 @@ +pub mod advanced; +pub mod simple; + +use crate::{ + block::Block, + frame::Frame, + helpers::{pixel::Pixel, threading::both_par, 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 max_threads: usize, + pub weight_factor: f64, + pub do_value_scale: bool, + pub do_matrix_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) -> 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 { + refblock + } 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) = both_par( + || encode_block(av, ap, config), + || encode_block(bv, bp, config), + config.max_threads, + ); + + if a.is_literal() && b.is_literal() { + Block::Literal(view.pixels()) + } else if a.is_ref_without_translation() && b.is_ref_without_translation() { + 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 +} |