diff options
-rwxr-xr-x | evc/scripts/bench_modes | 5 | ||||
-rwxr-xr-x | evc/scripts/bench_out | 10 | ||||
-rw-r--r-- | evc/src/bin/encode.rs | 2 | ||||
-rw-r--r-- | evc/src/bin/info.rs | 11 | ||||
-rw-r--r-- | evc/src/block.rs | 28 | ||||
-rw-r--r-- | evc/src/codec/decode.rs | 1 | ||||
-rw-r--r-- | evc/src/codec/encode/mod.rs | 16 | ||||
-rw-r--r-- | evc/src/codec/encode/simple.rs | 5 | ||||
-rw-r--r-- | evc/src/debug.rs | 2 | ||||
-rw-r--r-- | evc/src/frame.rs | 7 | ||||
-rw-r--r-- | evc/src/helpers/matrix.rs | 2 | ||||
-rw-r--r-- | evc/src/helpers/pixel.rs | 9 |
12 files changed, 63 insertions, 35 deletions
diff --git a/evc/scripts/bench_modes b/evc/scripts/bench_modes index 7cc6abd..9fa17f6 100755 --- a/evc/scripts/bench_modes +++ b/evc/scripts/bench_modes @@ -4,14 +4,15 @@ set h $argv[2] set t $argv[3] ffmpeg -hide_banner -i $argv[4] -to {$t} -vf scale={$w}x{$h},fps=30,format=rgb24 -f rawvideo pipe:1 >samples/raw -ffmpeg -hide_banner -y -i $argv[4] -to {$t} -vf scale={$w}x{$h},fps=30,format=rgb24 -c:v vp9 samples/reference.webm +# ffmpeg -hide_banner -y -i $argv[4] -to {$t} -vf scale={$w}x{$h},fps=30,format=rgb24 -c:v vp9 samples/reference.webm echo echo "file: "$argv[4] echo "resolution: "{$w}x{$h} echo "frames: "(math $t \* 30) echo "reference (raw): "(du -h samples/raw | cut -f 1) -echo "reference (vp8): "(du -h samples/reference.webm | cut -f 1) +echo "reference (input): "(du -h $argv[4] | cut -f 1) +# echo "reference (vp8): "(du -h samples/reference.webm | cut -f 1) for mode in trivial simple-exhaustive simple-fast advanced advanced-partial echo ----------- echo "mode: $mode" diff --git a/evc/scripts/bench_out b/evc/scripts/bench_out new file mode 100755 index 0000000..5bb0639 --- /dev/null +++ b/evc/scripts/bench_out @@ -0,0 +1,10 @@ +#!/bin/fish +set w $argv[1] +set h $argv[2] + +for mode in trivial simple-exhaustive simple-fast advanced advanced-partial + cargo run --release --bin decode -- --debug < samples/encoded-$mode | + ffmpeg -y -hide_banner -framerate 25 -video_size {$w}x{$h} -pixel_format rgb24 -f rawvideo -i pipe:0 samples/decoded-$mode-debug.mp4 + cargo run --release --bin decode -- < samples/encoded-$mode | + ffmpeg -y -hide_banner -framerate 25 -video_size {$w}x{$h} -pixel_format rgb24 -f rawvideo -i pipe:0 samples/decoded-$mode.mp4 +end diff --git a/evc/src/bin/encode.rs b/evc/src/bin/encode.rs index c9d8792..32af242 100644 --- a/evc/src/bin/encode.rs +++ b/evc/src/bin/encode.rs @@ -26,7 +26,7 @@ pub struct EncodeArgs { #[arg(short, long, default_value = "8")] jobs: usize, - #[arg(short, long, default_value = "8")] + #[arg(short, long, default_value = "4")] min_block_size: isize, #[arg(short = 't', long, default_value = "200")] diff --git a/evc/src/bin/info.rs b/evc/src/bin/info.rs new file mode 100644 index 0000000..1e1472a --- /dev/null +++ b/evc/src/bin/info.rs @@ -0,0 +1,11 @@ +use std::io::BufReader; + +use anyhow::Context; +use evc::format::{header::Header, ser::Source}; + +fn main() { + env_logger::init_from_env("LOG"); + let mut input = BufReader::new(std::io::stdin()); + let header = input.get::<Header>().context("reading header").unwrap(); + eprintln!("{header:#?}") +} diff --git a/evc/src/block.rs b/evc/src/block.rs index 8d7686f..cbf69bf 100644 --- a/evc/src/block.rs +++ b/evc/src/block.rs @@ -5,15 +5,16 @@ use crate::{ }; use anyhow::bail; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub enum Block { Literal(Vec<Pixel>), + CompressedLiteral(Vec<Pixel>), Split(Box<[Block; 2]>), Reference { translation: Vec2<isize> }, AdvancedReference(AdvancedReference), } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct AdvancedReference { pub translation: Vec2<i8>, pub transform: Mat2<i8>, @@ -31,14 +32,15 @@ impl Block { sink.put(0u8)?; pixels.write_const_size(sink, size.area() as usize)?; } + Block::CompressedLiteral(_) => bail!("compressed literal is not supported"), Block::Split(box [a, b]) => { - sink.put(1u8)?; + sink.put(2u8)?; let [asize, bsize] = split_size(size); a.write(sink, asize)?; b.write(sink, bsize)?; } Block::Reference { translation } => { - sink.put(2u8)?; + sink.put(3u8)?; sink.put(Small(*translation))?; } Block::AdvancedReference(AdvancedReference { @@ -46,7 +48,7 @@ impl Block { transform, value_scale, }) => { - sink.put(3u8)?; + sink.put(4u8)?; sink.put((*translation, *transform, *value_scale))?; } } @@ -56,16 +58,17 @@ impl Block { pub fn read(source: &mut impl std::io::Read, size: Vec2<isize>) -> anyhow::Result<Self> { Ok(match source.get::<u8>()? { 0 => Block::Literal(Vec::read_const_size(source, size.area() as usize)?), - 1 => Block::Split(Box::new({ + 1 => bail!("compressed literal is not supported"), + 2 => Block::Split(Box::new({ let [asize, bsize] = split_size(size); let a = Block::read(source, asize)?; let b = Block::read(source, bsize)?; [a, b] })), - 2 => Block::Reference { + 3 => Block::Reference { translation: source.get::<Small<Vec2<isize>>>()?.0, }, - 3 => Block::AdvancedReference(AdvancedReference { + 4 => Block::AdvancedReference(AdvancedReference { translation: source.get()?, transform: source.get()?, value_scale: source.get()?, @@ -95,13 +98,8 @@ impl Block { pub fn is_literal(&self) -> bool { matches!(self, Block::Literal(..)) } - pub fn is_ref_without_translation(&self) -> bool { - matches!( - self, - Block::Reference { - translation: Vec2::<isize>::ZERO - } - ) + pub fn identical_ref(a: &Self, b: &Self) -> bool { + matches!(a, Block::Reference { .. }) && a == b } } diff --git a/evc/src/codec/decode.rs b/evc/src/codec/decode.rs index 197028c..61234da 100644 --- a/evc/src/codec/decode.rs +++ b/evc/src/codec/decode.rs @@ -29,6 +29,7 @@ pub fn decode_block( config.max_threads, ); } + Block::CompressedLiteral(_) => todo!(), 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 2ccac64..336f298 100644 --- a/evc/src/codec/encode/mod.rs +++ b/evc/src/codec/encode/mod.rs @@ -69,15 +69,19 @@ 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) = both_par( - || encode_block(av, ap, config), - || encode_block(bv, bp, config), - config.max_threads, - ); + let (a, b) = if view.area() > 100 { + 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)) + }; if a.is_literal() && b.is_literal() { Block::Literal(view.pixels()) - } else if a.is_ref_without_translation() && b.is_ref_without_translation() { + } else if Block::identical_ref(&a, &b) { Block::Reference { translation: Vec2::<isize>::ZERO, } diff --git a/evc/src/codec/encode/simple.rs b/evc/src/codec/encode/simple.rs index cabbc15..2a971af 100644 --- a/evc/src/codec/encode/simple.rs +++ b/evc/src/codec/encode/simple.rs @@ -45,6 +45,11 @@ pub fn fast( } }; + 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 }); diff --git a/evc/src/debug.rs b/evc/src/debug.rs index 99723b8..c3ea7d0 100644 --- a/evc/src/debug.rs +++ b/evc/src/debug.rs @@ -64,7 +64,7 @@ impl Pixel { pub fn draw_debug(block: &Block, mut target: View<&mut Frame>) { match &block { - Block::Literal(_) => { + Block::Literal(_) | Block::CompressedLiteral(_) => { target.draw_box(Pixel::GREEN); } Block::Split(box [a, b]) => { diff --git a/evc/src/frame.rs b/evc/src/frame.rs index 81fdf3b..78d0e73 100644 --- a/evc/src/frame.rs +++ b/evc/src/frame.rs @@ -63,11 +63,8 @@ impl Index<Vec2<isize>> for Frame { type Output = Pixel; #[inline] fn index(&self, Vec2 { x, y }: Vec2<isize>) -> &Self::Output { - if x >= 0 && y >= 0 && x < self.size.x && y < self.size.y { - &self.buffer[(x + y * self.size.x) as usize] - } else { - &Pixel::BLACK - } + &self.buffer + [(x.clamp(0, self.size.x - 1) + y.clamp(0, self.size.y - 1) * self.size.x) as usize] } } impl IndexMut<Vec2<isize>> for Frame { diff --git a/evc/src/helpers/matrix.rs b/evc/src/helpers/matrix.rs index 87c0e7d..c3c120b 100644 --- a/evc/src/helpers/matrix.rs +++ b/evc/src/helpers/matrix.rs @@ -1,6 +1,6 @@ use crate::helpers::vector::Vec2; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Mat2<T> { pub a: T, pub b: T, diff --git a/evc/src/helpers/pixel.rs b/evc/src/helpers/pixel.rs index 816d7dc..39fe98c 100644 --- a/evc/src/helpers/pixel.rs +++ b/evc/src/helpers/pixel.rs @@ -1,6 +1,6 @@ use crate::format::ser::{Ser, Sink, Source}; -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct Pixel { pub r: u8, pub g: u8, @@ -24,11 +24,12 @@ impl Pixel { pub fn distance(a: Pixel, b: Pixel) -> usize { let (rd, gd, bd) = ( a.r.abs_diff(b.r) as usize, - a.r.abs_diff(b.r) as usize, - a.r.abs_diff(b.r) as usize, + a.g.abs_diff(b.g) as usize, + a.b.abs_diff(b.b) as usize, ); // fast_sqrt(rd * rd + gd * gd + bd * bd) - SQRT[rd + gd + bd] + // SQRT[rd + gd + bd] + rd + gd + bd } #[inline] |