aboutsummaryrefslogtreecommitdiff
path: root/evc/src/codec
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2022-12-08 09:13:17 +0100
committermetamuffin <metamuffin@disroot.org>2022-12-08 09:13:17 +0100
commit6001cdeff335e12583a398acbb5a8a42c01bc077 (patch)
tree4c1c515cbf33e727f5db317880aadd425a1e0b96 /evc/src/codec
parent8b7792d6aa27578221fee7cc8be1ceb202602a5a (diff)
downloadvideo-codec-experiments-6001cdeff335e12583a398acbb5a8a42c01bc077.tar
video-codec-experiments-6001cdeff335e12583a398acbb5a8a42c01bc077.tar.bz2
video-codec-experiments-6001cdeff335e12583a398acbb5a8a42c01bc077.tar.zst
fast mode
Diffstat (limited to 'evc/src/codec')
-rw-r--r--evc/src/codec/decode.rs32
-rw-r--r--evc/src/codec/encode.rs177
2 files changed, 133 insertions, 76 deletions
diff --git a/evc/src/codec/decode.rs b/evc/src/codec/decode.rs
index b7ab8c7..197028c 100644
--- a/evc/src/codec/decode.rs
+++ b/evc/src/codec/decode.rs
@@ -1,13 +1,33 @@
-use crate::{block::Block, frame::Frame, refsampler::Sampler, view::View};
+use crate::{
+ block::Block, frame::Frame, helpers::threading::both_par, refsampler::Sampler, view::View,
+};
-pub fn decode_block(block: &Block, mut target: View<&mut Frame>, prev: View<&Frame>) {
+pub struct DecodeConfig {
+ pub max_threads: usize,
+}
+
+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 [at, bt] = target.split_mut_unsafe();
- let [ap, bp] = prev.split();
- decode_block(a, at, ap);
- decode_block(b, bt, bp);
+ 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) };
+
+ both_par(
+ move || decode_block(a, at, ap, config),
+ move || decode_block(b, bt, bp, config),
+ config.max_threads,
+ );
}
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.rs b/evc/src/codec/encode.rs
index 4eb86b5..6b6f8a3 100644
--- a/evc/src/codec/encode.rs
+++ b/evc/src/codec/encode.rs
@@ -6,7 +6,6 @@ use crate::{
view::View,
};
use clap::ValueEnum;
-use log::debug;
#[derive(Debug, Clone)]
pub struct EncodeConfig {
@@ -15,15 +14,38 @@ pub struct EncodeConfig {
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,
+ Fast,
Default,
Advanced,
}
+#[inline]
+pub 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;
+ }
+}
+
pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfig) -> Block {
let (diff, refblock) = if view.area() > config.max_diff_area {
(
@@ -33,7 +55,9 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi
},
)
} else {
- match config.mode {
+ let weight = importance(&view).max(0.5);
+ let irrelevance = config.weight_factor / weight;
+ let (diff, refblock) = match config.mode {
EncodeMode::Trivial => (
View::diff(&view, &prev) / view.area() as f64,
Block::Reference {
@@ -41,87 +65,95 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi
},
),
EncodeMode::Default => {
- let mut best_diff = f64::INFINITY;
- let mut best_translation = Vec2::<isize>::ZERO;
+ 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 translation = Vec2 { x: *x, y: *y };
- let diff = View::diff(&view, &prev.offset(translation));
- if diff < best_diff {
- best_translation = translation;
- best_diff = diff;
+ let t = Vec2 { x: *x, y: *y };
+ let d = View::diff(&view, &prev.offset(t));
+ if d < diff {
+ translation = t;
+ diff = d;
}
}
}
- (
- best_diff,
- Block::Reference {
- translation: best_translation,
- },
- )
+ (diff, Block::Reference { translation })
}
- EncodeMode::Advanced => {
- let mut params = AdvancedReference::default();
- let sampler = Sampler::from_refblock(prev.clone(), &params);
+ EncodeMode::Fast => {
+ let mut pm = AdvancedReference::default();
+ let sampler = Sampler::from_refblock(prev.clone(), &pm);
let mut diff = View::diff_sampler(&view, &sampler);
-
- loop {
- pub fn pk<F: FnMut(&mut AdvancedReference) -> ()>(
- view: &View<&Frame>,
- prev: &View<&Frame>,
- diff: &mut f64,
- params: &mut AdvancedReference,
- mut f: F,
- ) {
- let mut p = params.clone();
- f(&mut p);
- let d = View::diff_sampler(view, &Sampler::from_refblock(prev.clone(), &p));
- if d < *diff {
- *diff = d;
- *params = p;
+ if diff - irrelevance < config.ref_thres {
+ (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);
+ if d >= diff {
+ break (diff, Block::AdvancedReference(pm));
}
+ diff = d;
+ pm = p;
}
+ }
+ }
+ EncodeMode::Advanced => {
+ let mut pm = AdvancedReference::default();
+ let sampler = Sampler::from_refblock(prev.clone(), &pm);
+ let mut diff = View::diff_sampler(&view, &sampler);
+ if diff - irrelevance < config.ref_thres {
+ (diff, Block::REFZERO)
+ } else {
+ loop {
+ let (mut d, mut p) = (diff, pm.clone());
- let (mut d, mut p) = (diff, params.clone());
-
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x += 4);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x -= 4);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y += 4);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y -= 4);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x += 2);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x -= 2);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y += 2);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y -= 2);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y -= 1);
-
- pk(&view, &prev, &mut d, &mut p, |p| p.value_scale += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.value_scale -= 1);
-
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.a -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.a += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.b -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.b += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.c -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.c += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.d -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.d += 1);
+ 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_matrix_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);
+ }
- debug!("{diff} -> {d}");
+ if d >= diff {
+ break (diff, Block::AdvancedReference(pm));
+ }
- if d >= diff {
- break (diff, Block::AdvancedReference(params));
+ diff = d;
+ pm = p;
}
-
- diff = d;
- params = p;
}
}
- }
+ };
+ (diff - irrelevance, refblock)
};
if diff < config.ref_thres {
refblock
@@ -136,18 +168,23 @@ 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.size.x > 64 {
+ 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))
- };
+ // } else {
+ // (encode_block(av, ap, config), encode_block(bv, bp, config))
+ // }
+ ;
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]))
}