diff options
author | metamuffin <metamuffin@disroot.org> | 2023-11-15 20:03:59 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-11-15 20:03:59 +0100 |
commit | 9e1a836f663c03e462fbf1bcff444a20aaf56eaf (patch) | |
tree | 90b3fa998cdda4c7d2c22a58b42cdb5a4369f547 /difftree | |
parent | 0196cc1a12cf787a4c5bfc3645b0364eb5daf93a (diff) | |
download | video-codec-experiments-9e1a836f663c03e462fbf1bcff444a20aaf56eaf.tar video-codec-experiments-9e1a836f663c03e462fbf1bcff444a20aaf56eaf.tar.bz2 video-codec-experiments-9e1a836f663c03e462fbf1bcff444a20aaf56eaf.tar.zst |
a
Diffstat (limited to 'difftree')
-rw-r--r-- | difftree/Cargo.toml | 4 | ||||
-rw-r--r-- | difftree/src/main.rs | 157 | ||||
-rwxr-xr-x | difftree/test | 4 |
3 files changed, 63 insertions, 102 deletions
diff --git a/difftree/Cargo.toml b/difftree/Cargo.toml index 2c19efb..0aae03b 100644 --- a/difftree/Cargo.toml +++ b/difftree/Cargo.toml @@ -1,8 +1,10 @@ [package] -name = "tweak" +name = "difftree" version = "0.1.0" edition = "2021" [dependencies] rayon = "1.8.0" rand = "0.8.5" + +framework = { path = "../framework" } diff --git a/difftree/src/main.rs b/difftree/src/main.rs index b2144a3..36faa44 100644 --- a/difftree/src/main.rs +++ b/difftree/src/main.rs @@ -1,40 +1,38 @@ -use rayon::join; -use std::{ - io::{stdin, stdout, Read, Write}, - time::Instant, +use framework::{ + vector::{UVec2, Vec2}, + Frame, Framework, Pixel, }; +use rayon::join; const WIDTH: usize = 1920; const HEIGHT: usize = 1080; fn main() { - let mut oframe = Frame::new(); - let mut dframe = Frame::new(); - let mut out = Vec::<u8>::new(); - let do_debug = false; - loop { - let timer = Instant::now(); - let iframe = Frame::read(stdin()); + let (mut framework, params) = Framework::init(); - let t = encode(&oframe, &iframe, Area::root()); - decode(&mut oframe, Area::root(), &t); + match params.mode { + framework::CodecMode::Encode => { + let mut oframe = Frame::new(params.width, params.height); + let mut dframe = Frame::new(params.width, params.height); + let mut out = Vec::<u8>::new(); + while let Some(iframe) = framework.next_frame() { + let t = encode(&oframe, &iframe, Area::root()); + decode(&mut oframe, Area::root(), &t); - write(&mut out, &t); + write(&mut out, &t); - if do_debug { - dframe.0.copy_from_slice(&oframe.0); - debug(&mut dframe, Area::root(), &t); - dframe.write(stdout()); - } else { - oframe.write(stdout()); - } + if params.debug > 0 { + dframe.pixels.copy_from_slice(&oframe.pixels); + debug(&mut dframe, Area::root(), &t); + framework.decode_done(&dframe); + } else { + framework.decode_done(&oframe) + } - eprintln!( - "compression={:.01} time={:?}", - (WIDTH * HEIGHT * 3) as f64 / out.len() as f64, - timer.elapsed() - ); - out.clear(); + out.clear(); + } + } + framework::CodecMode::Decode => todo!(), } } @@ -45,7 +43,7 @@ pub fn write(w: &mut Vec<u8>, t: &DiffTree) { write(w, a); write(w, b); } - DiffTree::Diff(d) => w.extend([1, d.0[0] as u8, d.0[1] as u8, d.0[2] as u8]), + DiffTree::Diff(d) => w.extend([1, d.r as u8, d.g as u8, d.b as u8]), } } @@ -57,7 +55,7 @@ pub fn decode(f: &mut Frame, area: Area, tree: &DiffTree) { decode(f, ab, tb); } DiffTree::Diff(diff) => { - f.apply_area_diff(area, *diff); + apply_area_diff(f, area, *diff); } } } @@ -72,10 +70,7 @@ pub fn debug(f: &mut Frame, area: Area, tree: &DiffTree) { let Area { x1, y1, x2, y2 } = area; for x in x1..x2 { for y in y1..y2 { - let o = (x + y * WIDTH) * 3; - f.0[o + 0] = 255; - f.0[o + 1] = 0; - f.0[o + 2] = 255; + f[(x, y)] = Pixel { r: 0, g: 0, b: 255 } } } } @@ -84,24 +79,31 @@ pub fn debug(f: &mut Frame, area: Area, tree: &DiffTree) { pub fn encode(a: &Frame, b: &Frame, area: Area) -> DiffTree { if area.area() == 1 { - DiffTree::Diff(Frame::diff_pixel(a, b, area.x1, area.y1)) + DiffTree::Diff(diff_pixel( + a, + b, + Vec2 { + x: area.x1, + y: area.y1, + }, + )) } else { let (aa, ba) = area.split(); let (at, bt) = join(|| encode(a, b, aa), || encode(a, b, ba)); match (&at, &bt) { (DiffTree::Diff(ad), DiffTree::Diff(bd)) => { - let d_r = ad.0[0].abs_diff(bd.0[0]); - let d_g = ad.0[1].abs_diff(bd.0[1]); - let d_b = ad.0[2].abs_diff(bd.0[2]); + let d_r = ad.r.abs_diff(bd.r); + let d_g = ad.g.abs_diff(bd.g); + let d_b = ad.b.abs_diff(bd.b); let visdiff = (d_r as usize + d_g as usize + d_b as usize) * aa.area(); if visdiff < 100 { - return DiffTree::Diff(PixelDiff([ - ((ad.0[0] as i16 + bd.0[0] as i16) / 2) as i8, - ((ad.0[1] as i16 + bd.0[1] as i16) / 2) as i8, - ((ad.0[2] as i16 + bd.0[2] as i16) / 2) as i8, - ])); + return DiffTree::Diff(Pixel { + r: ((ad.r as i16 + bd.r as i16) / 2) as i8, + g: ((ad.g as i16 + bd.g as i16) / 2) as i8, + b: ((ad.b as i16 + bd.b as i16) / 2) as i8, + }); } } _ => (), @@ -112,13 +114,9 @@ pub fn encode(a: &Frame, b: &Frame, area: Area) -> DiffTree { pub enum DiffTree { Split([Box<DiffTree>; 2]), - Diff(PixelDiff), + Diff(Pixel<i8>), } -#[derive(Debug)] -pub struct Frame(Vec<u8>); -#[derive(Debug, Clone, Copy)] -pub struct PixelDiff([i8; 3]); #[derive(Debug, Clone, Copy)] pub struct Area { x1: usize, @@ -135,61 +133,26 @@ fn diff_clamp(x: u8, y: u8) -> i8 { -((x - y).min(128) as i8) } } - -impl Frame { - pub fn new() -> Self { - Self(vec![0u8; WIDTH * HEIGHT * 3]) - } - pub fn read(mut r: impl Read) -> Self { - let mut f = Frame::new(); - r.read_exact(&mut f.0).unwrap(); - f - } - pub fn write(&self, mut w: impl Write) { - w.write_all(&self.0).unwrap() - } - - pub fn diff_pixel(a: &Frame, b: &Frame, x: usize, y: usize) -> PixelDiff { - let o = (x + y * WIDTH) * 3; - PixelDiff([ - diff_clamp(a.0[o + 0], b.0[o + 0]), - diff_clamp(a.0[o + 1], b.0[o + 1]), - diff_clamp(a.0[o + 2], b.0[o + 2]), - ]) +pub fn diff_pixel(a: &Frame, b: &Frame, p: UVec2) -> Pixel<i8> { + let (ap, bp) = (a[p], b[p]); + Pixel { + r: diff_clamp(ap.r, bp.r), + g: diff_clamp(ap.g, bp.g), + b: diff_clamp(ap.b, bp.b), } +} - pub fn apply_area_diff(&mut self, Area { x1, y1, x2, y2 }: Area, p: PixelDiff) { - for x in x1..x2 { - for y in y1..y2 { - let o = (x + y * WIDTH) * 3; - self.0[o + 0] = self.0[o + 0].saturating_add_signed(p.0[0]); - self.0[o + 1] = self.0[o + 1].saturating_add_signed(p.0[1]); - self.0[o + 2] = self.0[o + 2].saturating_add_signed(p.0[2]); - } +pub fn apply_area_diff(frame: &mut Frame, Area { x1, y1, x2, y2 }: Area, diff: Pixel<i8>) { + for x in x1..x2 { + for y in y1..y2 { + let p = &mut frame[(x, y)]; + p.r = p.r.saturating_add_signed(diff.r); + p.g = p.g.saturating_add_signed(diff.g); + p.b = p.b.saturating_add_signed(diff.b); } } - // pub fn average_area_diff( - // &self, - // other: &Frame, - // area @ Area { x1, y1, x2, y2 }: Area, - // ) -> PixelDiff { - // let (mut r, mut g, mut b) = (0i32, 0i32, 0i32); - // for x in x1..x2 { - // for y in y1..y2 { - // let o = (x + y * WIDTH) * 3; - // r += other.0[o + 0] as i32 - self.0[o + 0] as i32; - // g += other.0[o + 1] as i32 - self.0[o + 1] as i32; - // b += other.0[o + 2] as i32 - self.0[o + 2] as i32; - // } - // } - // let a = area.area() as i32; - // PixelDiff([ - // (r / a).clamp(i8::MIN as i32, i8::MAX as i32) as i8, - // (g / a).clamp(i8::MIN as i32, i8::MAX as i32) as i8, - // (b / a).clamp(i8::MIN as i32, i8::MAX as i32) as i8, - // ]) - // } } + impl Area { pub fn area(&self) -> usize { self.width() as usize * self.height() as usize diff --git a/difftree/test b/difftree/test deleted file mode 100755 index 4bfc7d8..0000000 --- a/difftree/test +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/fish -ffmpeg -loglevel quiet -i $argv[1] -vf 'scale=1920x1080,format=rgb24' -f rawvideo pipe:1 \ - | cargo run --release \ - | ffplay -loglevel quiet -video_size 1920x1080 -pixel_format rgb24 -f rawvideo pipe:0 |