From 736ebd6102eb5df134acbda8aac94f034d5bebe4 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Wed, 7 May 2025 15:10:30 +0200 Subject: test2 --- Cargo.lock | 9 ++ Cargo.toml | 2 +- mtree-test/src/bin/decode.rs | 66 ----------- mtree-test/src/bin/encode.rs | 276 ------------------------------------------- mtree-test/src/decode.rs | 62 ++++++++++ mtree-test/src/encode.rs | 272 ++++++++++++++++++++++++++++++++++++++++++ mtree-test/src/lib.rs | 100 ---------------- mtree-test/src/main.rs | 114 ++++++++++++++++++ test2/Cargo.toml | 9 ++ test2/src/decode.rs | 20 ++++ test2/src/encode.rs | 155 ++++++++++++++++++++++++ test2/src/main.rs | 17 +++ 12 files changed, 659 insertions(+), 443 deletions(-) delete mode 100644 mtree-test/src/bin/decode.rs delete mode 100644 mtree-test/src/bin/encode.rs create mode 100644 mtree-test/src/decode.rs create mode 100644 mtree-test/src/encode.rs delete mode 100644 mtree-test/src/lib.rs create mode 100644 mtree-test/src/main.rs create mode 100644 test2/Cargo.toml create mode 100644 test2/src/decode.rs create mode 100644 test2/src/encode.rs create mode 100644 test2/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 44cff8c..2152237 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,3 +79,12 @@ dependencies = [ "crossbeam-deque", "crossbeam-utils", ] + +[[package]] +name = "test2" +version = "0.1.0" +dependencies = [ + "framework", + "glam", + "rayon", +] diff --git a/Cargo.toml b/Cargo.toml index eccbbe0..fc8ad92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["framework", "mtree-test"] +members = ["framework", "mtree-test", "test2"] resolver = "3" diff --git a/mtree-test/src/bin/decode.rs b/mtree-test/src/bin/decode.rs deleted file mode 100644 index 992bebc..0000000 --- a/mtree-test/src/bin/decode.rs +++ /dev/null @@ -1,66 +0,0 @@ -use framework::{BitstreamFilter, bitstream_filter_main}; -use glam::{I16Vec2, i16vec2}; -use mtree_test::{BLOCK_SIZE, Frame, LastFrames, frame_to_frame_rect_copy}; -use std::{collections::VecDeque, io::Result}; - -fn main() -> Result<()> { - bitstream_filter_main::() -} - -struct Dec { - res: I16Vec2, - last: LastFrames, -} -impl BitstreamFilter for Dec { - const INPUT_CODEC_ID: &str = "V_VCEMTREE"; - const OUTPUT_CODEC_ID: &str = "V_UNCOMPRESSED"; - - fn new(width: u32, height: u32) -> Self { - Self { - res: i16vec2(width as i16, height as i16), - last: LastFrames { - frame_offset: 0, - frames: VecDeque::new(), - }, - } - } - fn process_block(&mut self, a: Vec) -> Vec { - let mut a = a.as_slice(); - let mut frame = Frame::new(self.res); - - for bx in 0..self.res.x / BLOCK_SIZE { - for by in 0..self.res.y / BLOCK_SIZE { - let boff = i16vec2(bx * BLOCK_SIZE, by * BLOCK_SIZE); - let brect = boff..boff + I16Vec2::splat(BLOCK_SIZE); - let kind = a[0]; - a = &a[1..]; - if kind == 0 { - let size = frame.import_rect(self.res, brect, &a); - a = &a[size..]; - } else { - let rframeindex = - u64::from_le_bytes([a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]]); - a = &a[8..]; - let offx = i16::from_le_bytes([a[0], a[1]]); - a = &a[2..]; - let offy = i16::from_le_bytes([a[0], a[1]]); - a = &a[2..]; - - let rframe = &self.last.frames[(rframeindex - self.last.frame_offset) as usize]; - frame_to_frame_rect_copy( - self.res, - &mut frame, - rframe, - I16Vec2::splat(BLOCK_SIZE), - boff, - i16vec2(offx, offy), - ); - } - } - } - - self.last.frames.push_back(frame.clone()); - - frame.0 - } -} diff --git a/mtree-test/src/bin/encode.rs b/mtree-test/src/bin/encode.rs deleted file mode 100644 index 80f3499..0000000 --- a/mtree-test/src/bin/encode.rs +++ /dev/null @@ -1,276 +0,0 @@ -use framework::{BitstreamFilter, bitstream_filter_main}; -use glam::{I16Vec2, i16vec2}; -use mtree_test::{AbsRef, BLOCK_SIZE, Frame, LastFrames, frame_to_frame_rect_copy}; -use rayon::{ - iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}, - join, -}; -use std::{collections::VecDeque, io::Result, time::Instant}; - -fn main() -> Result<()> { - bitstream_filter_main::() -} - -struct Enc { - res: I16Vec2, - last: LastFrames, - tree: MTree, - frame_num: u64, - - use_bulk_insert: bool, -} -impl BitstreamFilter for Enc { - const INPUT_CODEC_ID: &str = "V_UNCOMPRESSED"; - const OUTPUT_CODEC_ID: &str = "V_VCEMTREE"; - - fn new(width: u32, height: u32) -> Self { - Self { - res: i16vec2(width as i16, height as i16), - last: LastFrames { - frame_offset: 0, - frames: VecDeque::new(), - }, - tree: MTree::Leaf(AbsRef { - off: i16vec2(0, 0), - frame: u64::MAX, - }), - frame_num: 0, - use_bulk_insert: true, - } - } - fn process_block(&mut self, frame: Vec) -> Vec { - let mut frame = Frame(frame); - let mut out = Vec::new(); - let mut num_refs = 0; - - let t = Instant::now(); - for bx in 0..self.res.x / BLOCK_SIZE { - for by in 0..self.res.y / BLOCK_SIZE { - let boff = i16vec2(bx * BLOCK_SIZE, by * BLOCK_SIZE); - let r = self.tree.search(self.res, &self.last, &frame, boff); - - let rdist = if r.frame == u64::MAX { - u32::MAX - } else { - distance( - self.res, - &self.last.frames[(r.frame - self.last.frame_offset) as usize], - &frame, - r.off, - boff, - ) - }; - if rdist < BLOCK_SIZE as u32 * BLOCK_SIZE as u32 * 50 { - out.push(1); - out.extend(r.frame.to_le_bytes()); - out.extend(r.off.x.to_le_bytes()); - out.extend(r.off.y.to_le_bytes()); - frame_to_frame_rect_copy( - self.res, - &mut frame, - &self.last.frames[(r.frame - self.last.frame_offset) as usize], - I16Vec2::splat(BLOCK_SIZE), - boff, - r.off, - ); - num_refs += 1; - } else { - out.push(0); - frame.export_rect(self.res, boff..boff + I16Vec2::splat(BLOCK_SIZE), &mut out); - } - } - } - eprintln!("search\t{:?}", t.elapsed()); - - self.last.frames.push_back(frame); - let frame_index = self.last.frame_offset + self.last.frames.len() as u64 - 1; - - if self.frame_num % 30 == 0 { - let t = Instant::now(); - if self.use_bulk_insert { - let mut rs = Vec::new(); - for xo in 0..self.res.x - BLOCK_SIZE { - for yo in 0..self.res.y - BLOCK_SIZE { - rs.push(AbsRef { - frame: frame_index, - off: i16vec2(xo, yo), - }); - } - } - self.tree.bulk_insert(self.res, &self.last, rs); - } else { - for xo in 0..self.res.x - BLOCK_SIZE { - for yo in 0..self.res.y - BLOCK_SIZE { - self.tree.insert( - self.res, - &self.last, - AbsRef { - frame: frame_index, - off: i16vec2(xo, yo), - }, - ) - } - } - } - eprintln!("insert\t{:?}", t.elapsed()); - } - - eprintln!("depth={} refs={num_refs}", self.tree.depth()); - - self.frame_num += 1; - out - } -} - -enum MTree { - Branch(Box<[MTree; 2]>), - Leaf(AbsRef), -} -impl MTree { - pub fn depth(&self) -> usize { - (match self { - MTree::Branch(b) => b[0].depth().max(b[1].depth()), - MTree::Leaf(_) => 0, - }) + 1 - } - pub fn center(&self) -> AbsRef { - match self { - MTree::Branch(b) => b[0].center(), - MTree::Leaf(r) => *r, - } - } - pub fn bulk_insert(&mut self, res: I16Vec2, last: &LastFrames, mut rs: Vec) { - match self { - MTree::Branch(b) => { - let dirs = rs - .par_iter() - .map(|r| { - distance_absref(res, last, b[0].center(), *r) - < distance_absref(res, last, b[1].center(), *r) - }) - .collect::>(); - - let mut rs0 = Vec::new(); - let mut rs1 = Vec::new(); - for (r, d) in rs.into_iter().zip(dirs) { - if d { - rs0.push(r); - } else { - rs1.push(r); - } - } - let [b0, b1] = b.as_mut(); - join( - || b0.bulk_insert(res, last, rs0), - || b1.bulk_insert(res, last, rs1), - ); - } - MTree::Leaf(l) => { - if rs.is_empty() { - return; - } - if l.frame == u64::MAX { - *l = rs.pop().unwrap(); - if rs.is_empty() { - return; - } - } - let mut b = - MTree::Branch(Box::new([MTree::Leaf(*l), MTree::Leaf(rs.pop().unwrap())])); - b.bulk_insert(res, last, rs); - *self = b; - } - } - } - pub fn insert(&mut self, res: I16Vec2, last: &LastFrames, r: AbsRef) { - match self { - MTree::Branch(b) => { - if distance_absref(res, last, b[0].center(), r) - < distance_absref(res, last, b[1].center(), r) - { - b[0].insert(res, last, r) - } else { - b[1].insert(res, last, r) - } - } - MTree::Leaf(l) => { - if l.frame == u64::MAX { - *l = r - } else { - *self = MTree::Branch(Box::new([MTree::Leaf(*l), MTree::Leaf(r)])) - } - } - } - } - pub fn search( - &mut self, - res: I16Vec2, - last: &LastFrames, - frame: &Frame, - off: I16Vec2, - ) -> AbsRef { - match self { - MTree::Branch(b) => { - let acenter = b[0].center(); - let bcenter = b[1].center(); - let adist = distance( - res, - &last.frames[(acenter.frame - last.frame_offset) as usize], - frame, - acenter.off, - off, - ); - let bdist = distance( - res, - &last.frames[(bcenter.frame - last.frame_offset) as usize], - frame, - bcenter.off, - off, - ); - if adist < bdist { - b[0].search(res, last, frame, off) - } else { - b[1].search(res, last, frame, off) - } - } - MTree::Leaf(l) => *l, - } - } -} - -fn distance_absref(res: I16Vec2, last: &LastFrames, a: AbsRef, b: AbsRef) -> u32 { - let aframe = &last.frames[(a.frame - last.frame_offset) as usize]; - let bframe = &last.frames[(b.frame - last.frame_offset) as usize]; - distance(res, aframe, bframe, a.off, b.off) -} -fn distance(res: I16Vec2, aframe: &Frame, bframe: &Frame, aoff: I16Vec2, boff: I16Vec2) -> u32 { - let mut diff = 0; - for yo in 0..BLOCK_SIZE { - // for xo in 0..BLOCK_SIZE { - // let off = i16vec2(xo, yo); - // let asample = aframe.get(res, aoff + off); - // let bsample = bframe.get(res, boff + off); - - // diff += asample[0].abs_diff(bsample[0]) as u32; - // diff += asample[1].abs_diff(bsample[1]) as u32; - // diff += asample[2].abs_diff(bsample[2]) as u32; - // } - - let aslice = aframe.slice(res, yo + aoff.y, aoff.x..aoff.x + BLOCK_SIZE); - let bslice = bframe.slice(res, yo + boff.y, boff.x..boff.x + BLOCK_SIZE); - - for i in 0..BLOCK_SIZE as usize { - diff += aslice[0][i].abs_diff(bslice[0][i]) as u32; - diff += aslice[0][i].abs_diff(bslice[0][i]) as u32; - } - for i in 0..BLOCK_SIZE as usize / 2 { - diff += aslice[1][i].abs_diff(bslice[1][i]) as u32; - diff += aslice[1][i].abs_diff(bslice[1][i]) as u32; - } - for i in 0..BLOCK_SIZE as usize / 2 { - diff += aslice[2][i].abs_diff(bslice[2][i]) as u32; - diff += aslice[2][i].abs_diff(bslice[2][i]) as u32; - } - } - diff -} diff --git a/mtree-test/src/decode.rs b/mtree-test/src/decode.rs new file mode 100644 index 0000000..9c29717 --- /dev/null +++ b/mtree-test/src/decode.rs @@ -0,0 +1,62 @@ +use crate::{BLOCK_SIZE, Frame, LastFrames, frame_to_frame_rect_copy}; +use framework::BitstreamFilter; +use glam::{I16Vec2, i16vec2}; +use std::collections::VecDeque; + +pub struct Dec { + res: I16Vec2, + last: LastFrames, +} +impl BitstreamFilter for Dec { + const INPUT_CODEC_ID: &str = "V_VCEMTREE"; + const OUTPUT_CODEC_ID: &str = "V_UNCOMPRESSED"; + + fn new(width: u32, height: u32) -> Self { + Self { + res: i16vec2(width as i16, height as i16), + last: LastFrames { + frame_offset: 0, + frames: VecDeque::new(), + }, + } + } + fn process_block(&mut self, a: Vec) -> Vec { + let mut a = a.as_slice(); + let mut frame = Frame::new(self.res); + + for bx in 0..self.res.x / BLOCK_SIZE { + for by in 0..self.res.y / BLOCK_SIZE { + let boff = i16vec2(bx * BLOCK_SIZE, by * BLOCK_SIZE); + let brect = boff..boff + I16Vec2::splat(BLOCK_SIZE); + let kind = a[0]; + a = &a[1..]; + if kind == 0 { + let size = frame.import_rect(self.res, brect, &a); + a = &a[size..]; + } else { + let rframeindex = + u64::from_le_bytes([a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]]); + a = &a[8..]; + let offx = i16::from_le_bytes([a[0], a[1]]); + a = &a[2..]; + let offy = i16::from_le_bytes([a[0], a[1]]); + a = &a[2..]; + + let rframe = &self.last.frames[(rframeindex - self.last.frame_offset) as usize]; + frame_to_frame_rect_copy( + self.res, + &mut frame, + rframe, + I16Vec2::splat(BLOCK_SIZE), + boff, + i16vec2(offx, offy), + ); + } + } + } + + self.last.frames.push_back(frame.clone()); + + frame.0 + } +} diff --git a/mtree-test/src/encode.rs b/mtree-test/src/encode.rs new file mode 100644 index 0000000..d746e7f --- /dev/null +++ b/mtree-test/src/encode.rs @@ -0,0 +1,272 @@ +use crate::{AbsRef, BLOCK_SIZE, Frame, LastFrames, frame_to_frame_rect_copy}; +use framework::BitstreamFilter; +use glam::{I16Vec2, i16vec2}; +use rayon::{ + iter::{IntoParallelRefIterator, ParallelIterator}, + join, +}; +use std::{collections::VecDeque, time::Instant}; + +pub struct Enc { + res: I16Vec2, + last: LastFrames, + tree: MTree, + frame_num: u64, + + use_bulk_insert: bool, +} +impl BitstreamFilter for Enc { + const INPUT_CODEC_ID: &str = "V_UNCOMPRESSED"; + const OUTPUT_CODEC_ID: &str = "V_VCEMTREE"; + + fn new(width: u32, height: u32) -> Self { + Self { + res: i16vec2(width as i16, height as i16), + last: LastFrames { + frame_offset: 0, + frames: VecDeque::new(), + }, + tree: MTree::Leaf(AbsRef { + off: i16vec2(0, 0), + frame: u64::MAX, + }), + frame_num: 0, + use_bulk_insert: true, + } + } + fn process_block(&mut self, frame: Vec) -> Vec { + let mut frame = Frame(frame); + let mut out = Vec::new(); + let mut num_refs = 0; + + let t = Instant::now(); + for bx in 0..self.res.x / BLOCK_SIZE { + for by in 0..self.res.y / BLOCK_SIZE { + let boff = i16vec2(bx * BLOCK_SIZE, by * BLOCK_SIZE); + let r = self.tree.search(self.res, &self.last, &frame, boff); + + let rdist = if r.frame == u64::MAX { + u32::MAX + } else { + distance( + self.res, + &self.last.frames[(r.frame - self.last.frame_offset) as usize], + &frame, + r.off, + boff, + ) + }; + if rdist < BLOCK_SIZE as u32 * BLOCK_SIZE as u32 * 50 { + out.push(1); + out.extend(r.frame.to_le_bytes()); + out.extend(r.off.x.to_le_bytes()); + out.extend(r.off.y.to_le_bytes()); + frame_to_frame_rect_copy( + self.res, + &mut frame, + &self.last.frames[(r.frame - self.last.frame_offset) as usize], + I16Vec2::splat(BLOCK_SIZE), + boff, + r.off, + ); + num_refs += 1; + } else { + out.push(0); + frame.export_rect(self.res, boff..boff + I16Vec2::splat(BLOCK_SIZE), &mut out); + } + } + } + eprintln!("search\t{:?}", t.elapsed()); + + self.last.frames.push_back(frame); + let frame_index = self.last.frame_offset + self.last.frames.len() as u64 - 1; + + if self.frame_num % 30 == 0 { + let t = Instant::now(); + if self.use_bulk_insert { + let mut rs = Vec::new(); + for xo in 0..self.res.x - BLOCK_SIZE { + for yo in 0..self.res.y - BLOCK_SIZE { + rs.push(AbsRef { + frame: frame_index, + off: i16vec2(xo, yo), + }); + } + } + self.tree.bulk_insert(self.res, &self.last, rs); + } else { + for xo in 0..self.res.x - BLOCK_SIZE { + for yo in 0..self.res.y - BLOCK_SIZE { + self.tree.insert( + self.res, + &self.last, + AbsRef { + frame: frame_index, + off: i16vec2(xo, yo), + }, + ) + } + } + } + eprintln!("insert\t{:?}", t.elapsed()); + } + + eprintln!("depth={} refs={num_refs}", self.tree.depth()); + + self.frame_num += 1; + out + } +} + +enum MTree { + Branch(Box<[MTree; 2]>), + Leaf(AbsRef), +} +impl MTree { + pub fn depth(&self) -> usize { + (match self { + MTree::Branch(b) => b[0].depth().max(b[1].depth()), + MTree::Leaf(_) => 0, + }) + 1 + } + pub fn center(&self) -> AbsRef { + match self { + MTree::Branch(b) => b[0].center(), + MTree::Leaf(r) => *r, + } + } + pub fn bulk_insert(&mut self, res: I16Vec2, last: &LastFrames, mut rs: Vec) { + match self { + MTree::Branch(b) => { + let dirs = rs + .par_iter() + .map(|r| { + distance_absref(res, last, b[0].center(), *r) + < distance_absref(res, last, b[1].center(), *r) + }) + .collect::>(); + + let mut rs0 = Vec::new(); + let mut rs1 = Vec::new(); + for (r, d) in rs.into_iter().zip(dirs) { + if d { + rs0.push(r); + } else { + rs1.push(r); + } + } + let [b0, b1] = b.as_mut(); + join( + || b0.bulk_insert(res, last, rs0), + || b1.bulk_insert(res, last, rs1), + ); + } + MTree::Leaf(l) => { + if rs.is_empty() { + return; + } + if l.frame == u64::MAX { + *l = rs.pop().unwrap(); + if rs.is_empty() { + return; + } + } + let mut b = + MTree::Branch(Box::new([MTree::Leaf(*l), MTree::Leaf(rs.pop().unwrap())])); + b.bulk_insert(res, last, rs); + *self = b; + } + } + } + pub fn insert(&mut self, res: I16Vec2, last: &LastFrames, r: AbsRef) { + match self { + MTree::Branch(b) => { + if distance_absref(res, last, b[0].center(), r) + < distance_absref(res, last, b[1].center(), r) + { + b[0].insert(res, last, r) + } else { + b[1].insert(res, last, r) + } + } + MTree::Leaf(l) => { + if l.frame == u64::MAX { + *l = r + } else { + *self = MTree::Branch(Box::new([MTree::Leaf(*l), MTree::Leaf(r)])) + } + } + } + } + pub fn search( + &mut self, + res: I16Vec2, + last: &LastFrames, + frame: &Frame, + off: I16Vec2, + ) -> AbsRef { + match self { + MTree::Branch(b) => { + let acenter = b[0].center(); + let bcenter = b[1].center(); + let adist = distance( + res, + &last.frames[(acenter.frame - last.frame_offset) as usize], + frame, + acenter.off, + off, + ); + let bdist = distance( + res, + &last.frames[(bcenter.frame - last.frame_offset) as usize], + frame, + bcenter.off, + off, + ); + if adist < bdist { + b[0].search(res, last, frame, off) + } else { + b[1].search(res, last, frame, off) + } + } + MTree::Leaf(l) => *l, + } + } +} + +fn distance_absref(res: I16Vec2, last: &LastFrames, a: AbsRef, b: AbsRef) -> u32 { + let aframe = &last.frames[(a.frame - last.frame_offset) as usize]; + let bframe = &last.frames[(b.frame - last.frame_offset) as usize]; + distance(res, aframe, bframe, a.off, b.off) +} +fn distance(res: I16Vec2, aframe: &Frame, bframe: &Frame, aoff: I16Vec2, boff: I16Vec2) -> u32 { + let mut diff = 0; + for yo in 0..BLOCK_SIZE { + // for xo in 0..BLOCK_SIZE { + // let off = i16vec2(xo, yo); + // let asample = aframe.get(res, aoff + off); + // let bsample = bframe.get(res, boff + off); + + // diff += asample[0].abs_diff(bsample[0]) as u32; + // diff += asample[1].abs_diff(bsample[1]) as u32; + // diff += asample[2].abs_diff(bsample[2]) as u32; + // } + + let aslice = aframe.slice(res, yo + aoff.y, aoff.x..aoff.x + BLOCK_SIZE); + let bslice = bframe.slice(res, yo + boff.y, boff.x..boff.x + BLOCK_SIZE); + + for i in 0..BLOCK_SIZE as usize { + diff += aslice[0][i].abs_diff(bslice[0][i]) as u32; + diff += aslice[0][i].abs_diff(bslice[0][i]) as u32; + } + for i in 0..BLOCK_SIZE as usize / 2 { + diff += aslice[1][i].abs_diff(bslice[1][i]) as u32; + diff += aslice[1][i].abs_diff(bslice[1][i]) as u32; + } + for i in 0..BLOCK_SIZE as usize / 2 { + diff += aslice[2][i].abs_diff(bslice[2][i]) as u32; + diff += aslice[2][i].abs_diff(bslice[2][i]) as u32; + } + } + diff +} diff --git a/mtree-test/src/lib.rs b/mtree-test/src/lib.rs deleted file mode 100644 index fd282db..0000000 --- a/mtree-test/src/lib.rs +++ /dev/null @@ -1,100 +0,0 @@ -use glam::{I16Vec2, i16vec2}; -use std::{collections::VecDeque, ops::Range}; - -pub const BLOCK_SIZE: i16 = 8; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AbsRef { - pub off: I16Vec2, - pub frame: u64, -} - -#[derive(Clone)] -pub struct Frame(pub Vec); - -impl Frame { - pub fn new(res: I16Vec2) -> Self { - let res = res.as_usizevec2(); - Self(vec![0; res.x * res.y + 2 * (res.x / 2 * res.y / 2)]) - } - - pub fn index(&self, res: I16Vec2, p: I16Vec2) -> [usize; 3] { - let res = res.as_usizevec2(); - let p = p.as_usizevec2(); - - let ystride = res.y; - let ysize = res.x * ystride; - let uvstride = res.x / 2; - let usize = uvstride * (res.y / 2); - let puv = p / 2; - [ - p.x + p.y * ystride, - ysize + puv.x + puv.y * uvstride, - ysize + usize + puv.x + puv.y * uvstride, - ] - } - pub fn slice(&self, res: I16Vec2, y: i16, x: Range) -> [&[u8]; 3] { - let start = self.index(res, i16vec2(x.start, y)); - let end = self.index(res, i16vec2(x.end, y)); - [ - &self.0[start[0]..end[0]], - &self.0[start[1]..end[1]], - &self.0[start[2]..end[2]], - ] - } - pub fn get(&self, res: I16Vec2, p: I16Vec2) -> [u8; 3] { - self.index(res, p).map(|i| self.0[i]) - } - - pub fn export_rect(&self, res: I16Vec2, r: Range, out: &mut Vec) { - for y in r.start.y..r.end.y { - let slices = self.slice(res, y, r.start.x..r.end.x); - out.extend(slices[0]); - out.extend(slices[1]); - out.extend(slices[2]); - } - } - pub fn import_rect(&mut self, res: I16Vec2, r: Range, mut data: &[u8]) -> usize { - let mut off = 0; - for y in r.start.y..r.end.y { - let start = self.index(res, i16vec2(r.start.x, y)); - let end = self.index(res, i16vec2(r.end.x, y)); - - let mut do_slice = |s: &mut [u8]| { - s.copy_from_slice(&data[..s.len()]); - data = &data[s.len()..]; - off += s.len(); - }; - - do_slice(&mut self.0[start[0]..end[0]]); - do_slice(&mut self.0[start[1]..end[1]]); - do_slice(&mut self.0[start[2]..end[2]]); - } - off - } -} - -pub fn frame_to_frame_rect_copy( - res: I16Vec2, - aframe: &mut Frame, - bframe: &Frame, - size: I16Vec2, - aoff: I16Vec2, - boff: I16Vec2, -) { - for y in 0..size.y { - let astart = aframe.index(res, i16vec2(aoff.x, aoff.y + y)); - let aend = aframe.index(res, i16vec2(aoff.x + size.x, aoff.y + y)); - let bstart = bframe.index(res, i16vec2(boff.x, boff.y + y)); - let bend = bframe.index(res, i16vec2(boff.x + size.x, boff.y + y)); - - aframe.0[astart[0]..aend[0]].copy_from_slice(&bframe.0[bstart[0]..bend[0]]); - aframe.0[astart[1]..aend[1]].copy_from_slice(&bframe.0[bstart[1]..bend[1]]); - aframe.0[astart[2]..aend[2]].copy_from_slice(&bframe.0[bstart[2]..bend[2]]); - } -} - -pub struct LastFrames { - pub frame_offset: u64, - pub frames: VecDeque, -} diff --git a/mtree-test/src/main.rs b/mtree-test/src/main.rs new file mode 100644 index 0000000..3952722 --- /dev/null +++ b/mtree-test/src/main.rs @@ -0,0 +1,114 @@ +pub mod decode; +pub mod encode; + +use decode::Dec; +use encode::Enc; +use framework::bitstream_filter_main; +use glam::{I16Vec2, i16vec2}; +use std::{collections::VecDeque, env::args, ops::Range}; + +fn main() -> Result<(), std::io::Error> { + match args().nth(1).unwrap().as_str() { + "enc" => bitstream_filter_main::(), + "dec" => bitstream_filter_main::(), + _ => panic!("unknown mode"), + } +} + +pub const BLOCK_SIZE: i16 = 8; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AbsRef { + pub off: I16Vec2, + pub frame: u64, +} + +#[derive(Clone)] +pub struct Frame(pub Vec); + +impl Frame { + pub fn new(res: I16Vec2) -> Self { + let res = res.as_usizevec2(); + Self(vec![0; res.x * res.y + 2 * (res.x / 2 * res.y / 2)]) + } + + pub fn index(&self, res: I16Vec2, p: I16Vec2) -> [usize; 3] { + let res = res.as_usizevec2(); + let p = p.as_usizevec2(); + + let ystride = res.y; + let ysize = res.x * ystride; + let uvstride = res.x / 2; + let usize = uvstride * (res.y / 2); + let puv = p / 2; + [ + p.x + p.y * ystride, + ysize + puv.x + puv.y * uvstride, + ysize + usize + puv.x + puv.y * uvstride, + ] + } + pub fn slice(&self, res: I16Vec2, y: i16, x: Range) -> [&[u8]; 3] { + let start = self.index(res, i16vec2(x.start, y)); + let end = self.index(res, i16vec2(x.end, y)); + [ + &self.0[start[0]..end[0]], + &self.0[start[1]..end[1]], + &self.0[start[2]..end[2]], + ] + } + pub fn get(&self, res: I16Vec2, p: I16Vec2) -> [u8; 3] { + self.index(res, p).map(|i| self.0[i]) + } + + pub fn export_rect(&self, res: I16Vec2, r: Range, out: &mut Vec) { + for y in r.start.y..r.end.y { + let slices = self.slice(res, y, r.start.x..r.end.x); + out.extend(slices[0]); + out.extend(slices[1]); + out.extend(slices[2]); + } + } + pub fn import_rect(&mut self, res: I16Vec2, r: Range, mut data: &[u8]) -> usize { + let mut off = 0; + for y in r.start.y..r.end.y { + let start = self.index(res, i16vec2(r.start.x, y)); + let end = self.index(res, i16vec2(r.end.x, y)); + + let mut do_slice = |s: &mut [u8]| { + s.copy_from_slice(&data[..s.len()]); + data = &data[s.len()..]; + off += s.len(); + }; + + do_slice(&mut self.0[start[0]..end[0]]); + do_slice(&mut self.0[start[1]..end[1]]); + do_slice(&mut self.0[start[2]..end[2]]); + } + off + } +} + +pub fn frame_to_frame_rect_copy( + res: I16Vec2, + aframe: &mut Frame, + bframe: &Frame, + size: I16Vec2, + aoff: I16Vec2, + boff: I16Vec2, +) { + for y in 0..size.y { + let astart = aframe.index(res, i16vec2(aoff.x, aoff.y + y)); + let aend = aframe.index(res, i16vec2(aoff.x + size.x, aoff.y + y)); + let bstart = bframe.index(res, i16vec2(boff.x, boff.y + y)); + let bend = bframe.index(res, i16vec2(boff.x + size.x, boff.y + y)); + + aframe.0[astart[0]..aend[0]].copy_from_slice(&bframe.0[bstart[0]..bend[0]]); + aframe.0[astart[1]..aend[1]].copy_from_slice(&bframe.0[bstart[1]..bend[1]]); + aframe.0[astart[2]..aend[2]].copy_from_slice(&bframe.0[bstart[2]..bend[2]]); + } +} + +pub struct LastFrames { + pub frame_offset: u64, + pub frames: VecDeque, +} diff --git a/test2/Cargo.toml b/test2/Cargo.toml new file mode 100644 index 0000000..4663775 --- /dev/null +++ b/test2/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "test2" +version = "0.1.0" +edition = "2024" + +[dependencies] +framework = { path = "../framework" } +glam = "0.30.3" +rayon = "1.10.0" diff --git a/test2/src/decode.rs b/test2/src/decode.rs new file mode 100644 index 0000000..974c6d9 --- /dev/null +++ b/test2/src/decode.rs @@ -0,0 +1,20 @@ +use framework::BitstreamFilter; +use glam::{I16Vec2, i16vec2}; + +pub struct Dec { + res: I16Vec2, +} +impl BitstreamFilter for Dec { + const INPUT_CODEC_ID: &str = "V_VCETEST2"; + const OUTPUT_CODEC_ID: &str = "V_UNCOMPRESSED"; + + fn new(width: u32, height: u32) -> Self { + Self { + res: i16vec2(width as i16, height as i16), + } + } + + fn process_block(&mut self, a: Vec) -> Vec { + a + } +} diff --git a/test2/src/encode.rs b/test2/src/encode.rs new file mode 100644 index 0000000..799d8d4 --- /dev/null +++ b/test2/src/encode.rs @@ -0,0 +1,155 @@ +use crate::BLOCK_SIZE; +use framework::BitstreamFilter; +use glam::{IVec2, ivec2}; + +pub struct Enc { + res: IVec2, + last: Frame, +} +impl BitstreamFilter for Enc { + const INPUT_CODEC_ID: &str = "V_UNCOMPRESSED"; + const OUTPUT_CODEC_ID: &str = "V_VCETEST2"; + + fn new(width: u32, height: u32) -> Self { + let res = ivec2(width as i32, height as i32); + Self { + res, + last: Frame::new(res), + } + } + + fn process_block(&mut self, a: Vec) -> Vec { + let mut frame = Frame { + data: a, + res: self.res, + }; + + for by in 0..frame.res.y / BLOCK_SIZE { + for bx in 0..frame.res.x / BLOCK_SIZE { + let boff = ivec2(bx * BLOCK_SIZE, by * BLOCK_SIZE); + + let mut best_d = Frame::compare_block(&frame, &self.last, boff, boff); + let mut best_off = ivec2(0, 0); + + for granularity in [8, 4, 2, 1] { + for dir in [ + ivec2(1, 0), + ivec2(1, 1), + ivec2(0, 1), + ivec2(-1, 1), + ivec2(-1, 0), + ivec2(-1, -1), + ivec2(0, -1), + ivec2(1, -1), + ] { + let roff = boff + dir * granularity; + if roff.x >= 0 + && roff.y >= 0 + && roff.x + BLOCK_SIZE < frame.res.x + && roff.y + BLOCK_SIZE < frame.res.y + { + let d = Frame::compare_block(&frame, &self.last, boff, roff); + if d < best_d { + best_d = d; + best_off = roff; + } + } + } + } + + if best_d < 8 * 8 * 10 { + Frame::copy_block(&self.last, &mut frame, best_off, boff); + } + } + } + + self.last = frame.clone(); + frame.data + } +} + +#[derive(Clone)] +struct Frame { + res: IVec2, + data: Vec, +} + +impl Frame { + fn new(res: IVec2) -> Self { + Frame { + res, + data: vec![127; (res.x * res.y + res.x * res.y / 2) as usize], + } + } + fn copy_block(aframe: &Frame, bframe: &mut Frame, aoff: IVec2, boff: IVec2) { + assert_eq!(aframe.res, bframe.res); + let res = aframe.res; + + // Luma + for y in 0..BLOCK_SIZE { + let ay_off = aoff.x + (y + aoff.y) * res.x; + let by_off = boff.x + (y + boff.y) * res.x; + + bframe.data[by_off as usize..(by_off + BLOCK_SIZE) as usize] + .copy_from_slice(&aframe.data[ay_off as usize..(ay_off + BLOCK_SIZE) as usize]); + } + + // Chroma + let uplane_off = res.x * res.y; + let vplane_off = uplane_off + (res.x * res.y) / 4; + + for y in 0..BLOCK_SIZE / 2 { + let ay_off = aoff.x / 2 + (y + aoff.y / 2) * res.x / 2; + let by_off = boff.x / 2 + (y + boff.y / 2) * res.x / 2; + + for x in 0..BLOCK_SIZE / 2 { + let ay_index = ay_off + x; + let by_index = by_off + x; + + bframe.data[(by_index + uplane_off) as usize] = + aframe.data[(ay_index + uplane_off) as usize]; + bframe.data[(by_index + vplane_off) as usize] = + aframe.data[(ay_index + vplane_off) as usize]; + } + } + } + fn compare_block(aframe: &Frame, bframe: &Frame, aoff: IVec2, boff: IVec2) -> u32 { + assert_eq!(aframe.res, bframe.res); + let res = aframe.res; + let mut diff = 0; + + // Luma + for y in 0..BLOCK_SIZE { + let ay_off = aoff.x + (y + aoff.y) * res.x; + let by_off = boff.x + (y + boff.y) * res.x; + + for x in 0..BLOCK_SIZE { + diff += aframe.data[(ay_off + x) as usize] + .abs_diff(bframe.data[(by_off + x) as usize]) as u32 + } + } + + // Chroma + let uplane_off = res.x * res.y; + let vplane_off = uplane_off + (res.x * res.y) / 4; + + for y in 0..BLOCK_SIZE / 2 { + let ay_off = aoff.x / 2 + (y + aoff.y / 2) * res.x / 2; + let by_off = boff.x / 2 + (y + boff.y / 2) * res.x / 2; + + for x in 0..BLOCK_SIZE / 2 { + let ay_index = ay_off + x; + let by_index = by_off + x; + + diff += aframe.data[(ay_index + uplane_off) as usize] + .abs_diff(bframe.data[(by_index + uplane_off) as usize]) + as u32; + diff += aframe.data[(ay_index + vplane_off) as usize] + .abs_diff(bframe.data[(by_index + vplane_off) as usize]) + as u32; + } + } + + diff + } +} diff --git a/test2/src/main.rs b/test2/src/main.rs new file mode 100644 index 0000000..1f10f76 --- /dev/null +++ b/test2/src/main.rs @@ -0,0 +1,17 @@ +pub mod decode; +pub mod encode; + +use decode::Dec; +use encode::Enc; +use framework::bitstream_filter_main; +use std::env::args; + +pub const BLOCK_SIZE: i32 = 8; + +fn main() -> Result<(), std::io::Error> { + match args().nth(1).unwrap().as_str() { + "enc" => bitstream_filter_main::(), + "dec" => bitstream_filter_main::(), + _ => panic!("unknown mode"), + } +} -- cgit v1.2.3-70-g09d2