diff options
Diffstat (limited to 'bv1/codec')
-rw-r--r-- | bv1/codec/Cargo.toml | 12 | ||||
-rw-r--r-- | bv1/codec/src/debug.rs | 42 | ||||
-rw-r--r-- | bv1/codec/src/decode.rs | 75 | ||||
-rw-r--r-- | bv1/codec/src/encode.rs | 210 | ||||
-rw-r--r-- | bv1/codec/src/frameio.rs | 35 | ||||
-rw-r--r-- | bv1/codec/src/huff.rs | 192 | ||||
-rw-r--r-- | bv1/codec/src/impls.rs | 165 | ||||
-rw-r--r-- | bv1/codec/src/lib.rs | 52 | ||||
-rw-r--r-- | bv1/codec/src/serialize.rs | 116 | ||||
-rw-r--r-- | bv1/codec/src/split.rs | 42 |
10 files changed, 0 insertions, 941 deletions
diff --git a/bv1/codec/Cargo.toml b/bv1/codec/Cargo.toml deleted file mode 100644 index d4c9002..0000000 --- a/bv1/codec/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "bv1" -version = "0.1.0" -edition = "2021" - -[dependencies] -rayon = {version="1.10.0",optional = true} - -[features] -default = ["parallel"] -parallel = ["dep:rayon"] - diff --git a/bv1/codec/src/debug.rs b/bv1/codec/src/debug.rs deleted file mode 100644 index d6c37c2..0000000 --- a/bv1/codec/src/debug.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{split::split, Block, Frame, Pixel, View, P2}; - -pub fn draw_debug(frame: &mut Frame, view: View, block: &Block) { - match block { - Block::Lit(_) => rect(frame, view, Pixel::GREEN), - Block::Split(a, b) => { - let [av, bv] = split(view); - draw_debug(frame, av, &a); - draw_debug(frame, bv, &b); - } - Block::Ref(r) => { - let v = View { - a: view.a, - b: view.a + P2 { x: 2, y: 2 }, - }; - if r.pos_off != P2::ZERO { - fill_rect(frame, v + P2 { x: 0, y: 0 }, Pixel::BLUE) - } - if r.color_off != Pixel::BLACK { - fill_rect(frame, v + P2 { x: 2, y: 0 }, Pixel::RED) - } - } - } -} - -fn rect(frame: &mut Frame, view: View, color: Pixel) { - for x in view.a.x..view.b.x { - frame[P2 { x, y: view.a.y }] = color; - frame[P2 { x, y: view.b.y - 1 }] = color; - } - for y in view.a.y..view.b.y { - frame[P2 { y, x: view.a.x }] = color; - frame[P2 { y, x: view.b.x - 1 }] = color; - } -} -fn fill_rect(frame: &mut Frame, view: View, color: Pixel) { - for y in view.a.y..view.b.y { - for x in view.a.x..view.b.x { - frame[P2 { x, y }] = color; - } - } -} diff --git a/bv1/codec/src/decode.rs b/bv1/codec/src/decode.rs deleted file mode 100644 index aaebc6a..0000000 --- a/bv1/codec/src/decode.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::{ - debug::draw_debug, huff::read_huff, impls::join, split::split, Block, Frame, View, P2, -}; -use std::io::{BufReader, BufWriter, Read, Result, Write}; - -pub fn decode(size: P2, debug: bool, input: impl Read, output: impl Write) -> Result<()> { - let mut input = BufReader::new(input); - let mut output = BufWriter::new(output); - let mut d = Decoder::new(size); - let mut f = Frame::new(size); - loop { - d.decode_frame(&mut input, &mut f, debug)?; - Frame::write(&mut output, &f)?; - } -} - -pub struct Decoder { - last_frame: Frame, - size: P2, -} - -impl Decoder { - pub fn new(size: P2) -> Self { - Self { - size, - last_frame: Frame::new(size), - } - } - pub fn decode_frame( - &mut self, - mut input: impl Read, - output: &mut Frame, - debug: bool, - ) -> Result<()> { - let huff = true; - let b = if huff { - let mut buf = vec![]; - read_huff(&mut input, &mut buf)?; - let mut buf = std::io::Cursor::new(&mut buf); - Block::read(&mut buf, View::all(self.size))? - } else { - Block::read(&mut input, View::all(self.size))? - }; - - decode_block(&self.last_frame, output, View::all(self.size), &b); - self.last_frame.pixels.copy_from_slice(&output.pixels); // TODO use mem::swap - if debug { - draw_debug(output, View::all(self.size), &b); - } - Ok(()) - } -} - -pub fn decode_block(last_frame: &Frame, frame: &mut Frame, view: View, block: &Block) { - match block { - Block::Lit(pxs) => frame.import(view, &pxs), - Block::Split(a, b) => { - let [av, bv] = split(view); - let (frame1, frame2) = - unsafe { (&mut *(frame as *mut Frame), &mut *(frame as *mut Frame)) }; - join( - || decode_block(last_frame, frame1, av, &a), - || decode_block(last_frame, frame2, bv, &b), - ); - } - Block::Ref(r) => { - for y in view.a.y..view.b.y { - for x in view.a.x..view.b.x { - let p = P2 { x, y }; - frame[p] = last_frame[p + r.pos_off] + r.color_off - } - } - } - } -} diff --git a/bv1/codec/src/encode.rs b/bv1/codec/src/encode.rs deleted file mode 100644 index 31e1066..0000000 --- a/bv1/codec/src/encode.rs +++ /dev/null @@ -1,210 +0,0 @@ -use crate::huff::write_huff; -use crate::impls::join; -use crate::split::split; -use crate::{decode::decode_block, Block, Frame, Pixel, Ref, View, P2}; -use std::io::{BufReader, BufWriter, Read, Write}; -use std::time::Instant; - -#[derive(Debug, Clone)] -pub struct EncodeConfig { - pub threshold: f32, - pub max_block_size: usize, - pub min_block_size: usize, - pub attention_split: u32, - pub motion_split_f: f32, - pub keyframe_interval: usize, -} - -pub fn encode( - config: EncodeConfig, - size: P2, - input: impl Read, - output: impl Write, -) -> std::io::Result<()> { - let mut input = BufReader::new(input); - let mut output = BufWriter::new(output); - - let mut last_frame = Frame::new(size); - for frame_number in 0.. { - let mut frame = Frame::read(&mut input, size)?; - - let mut config = config.clone(); - if frame_number % config.keyframe_interval != 0 { - config.threshold = std::f32::INFINITY; - } - - let t = Instant::now(); - let b: Block = encode_block(&last_frame, &frame, View::all(size), &config); - let time_encode = t.elapsed(); - - let t = Instant::now(); - decode_block(&last_frame, &mut frame, View::all(size), &b); - last_frame = frame; - let time_decode = t.elapsed(); - - if true { - let mut buf = vec![]; - let mut bufw = std::io::Cursor::new(&mut buf); - b.write(&mut bufw)?; - drop(bufw); - let t = Instant::now(); - let bits_raw = buf.len() * 8; - let bits_huff = write_huff(&buf, &mut output)?; - let time_huff = t.elapsed(); - drop(buf); - - eprintln!( - "frame {frame_number}: {:?}", - time_decode + time_huff + time_encode - ); - eprintln!( - "\tencode {time_encode:?} ({:.2}%)", - (bits_raw as f32 / (size.area() * 24) as f32) * 100.0 - ); - eprintln!( - "\thuff {time_huff:?} ({:.2}%)", - (bits_huff as f32 / bits_raw as f32) * 100.0 - ); - eprintln!("\tdecode {time_decode:?}"); - } else { - b.write(&mut output)?; - } - } - Ok(()) -} - -pub fn encode_block(last_frame: &Frame, frame: &Frame, view: View, config: &EncodeConfig) -> Block { - let view_area = view.size().area(); - let thres = config.threshold * view_area as f32; - - if view_area > config.max_block_size - || (view_area > config.min_block_size - && (total_contrast(frame, view) > config.attention_split - || diff([last_frame, frame], view, Ref::default()) - > (thres * config.motion_split_f) as u32)) - { - let [av, bv] = split(view); - let (ab, bb) = join( - || encode_block(last_frame, frame, av, config), - || encode_block(last_frame, frame, bv, config), - ); - return Block::Split(Box::new(ab), Box::new(bb)); - } - - let mut r = Ref::default(); - let mut d = diff([last_frame, frame], view, r); - - let target_average = average_color(frame, view); - - for granularity in [1, 2, 3, 5, 7, 5, 3, 2, 1] { - let (nd, nrp) = optimize_ref(last_frame, frame, view, r, granularity, target_average); - if nd < d { - r = nrp; - d = nd; - } else { - break; - } - } - - if d < thres as u32 { - return Block::Ref(r); - } else { - Block::Lit(frame.export(view)) - } -} - -pub fn optimize_ref( - last_frame: &Frame, - frame: &Frame, - view: View, - r: Ref, - g: i32, - target_average: Pixel, -) -> (u32, Ref) { - let g2 = g * 2; - [ - Some(r.apply(|r| r.pos_off += P2 { x: g, y: 0 })), - Some(r.apply(|r| r.pos_off += P2 { x: g, y: g })), - Some(r.apply(|r| r.pos_off += P2 { x: 0, y: g })), - Some(r.apply(|r| r.pos_off += P2 { x: -g, y: g })), - Some(r.apply(|r| r.pos_off += P2 { x: -g, y: 0 })), - Some(r.apply(|r| r.pos_off += P2 { x: -g, y: -g })), - Some(r.apply(|r| r.pos_off += P2 { x: 0, y: -g })), - Some(r.apply(|r| r.pos_off += P2 { x: g, y: -g })), - Some(r.apply(|r| r.pos_off += P2 { x: g2, y: 0 })), - Some(r.apply(|r| r.pos_off += P2 { x: g2, y: g2 })), - Some(r.apply(|r| r.pos_off += P2 { x: 0, y: g2 })), - Some(r.apply(|r| r.pos_off += P2 { x: -g2, y: g2 })), - Some(r.apply(|r| r.pos_off += P2 { x: -g2, y: 0 })), - Some(r.apply(|r| r.pos_off += P2 { x: -g2, y: -g2 })), - Some(r.apply(|r| r.pos_off += P2 { x: 0, y: -g2 })), - Some(r.apply(|r| r.pos_off += P2 { x: g2, y: -g2 })), - { - let mut r = r; - let last_avr = average_color(last_frame, view); - let diff = target_average - last_avr; - r.color_off = diff; - if diff != Pixel::BLACK { - Some(r) - } else { - None - } - }, - ] - .into_iter() - .flatten() - .map(|r| (diff([last_frame, frame], view, r), r)) - .min_by_key(|e| e.0) - .unwrap() -} - -pub fn total_contrast(frame: &Frame, view: View) -> u32 { - let mut k = 0; - for y in view.a.y..view.b.y - 1 { - for x in view.a.x..view.b.x - 1 { - let p = P2 { x, y }; - k += pixel_diff(frame[p], frame[p + P2::X]).pow(2); - k += pixel_diff(frame[p], frame[p + P2::Y]).pow(2); - } - } - k -} - -pub fn average_color(frame: &Frame, view: View) -> Pixel { - let mut r = 0u32; - let mut g = 0u32; - let mut b = 0u32; - - for y in view.a.y..view.b.y { - for x in view.a.x..view.b.x { - let p = frame[P2 { x, y }]; - r += p.r as u32; - g += p.g as u32; - b += p.b as u32; - } - } - let area = view.size().area() as u32; - Pixel { - r: (r / area) as i16, - g: (g / area) as i16, - b: (b / area) as i16, - } -} - -pub fn diff([frame1, frame2]: [&Frame; 2], view: View, rp: Ref) -> u32 { - let mut k = 0; - for y in view.a.y..view.b.y { - for x in view.a.x..view.b.x { - let pos = P2 { x, y }; - let p1 = frame1[pos + rp.pos_off] + rp.color_off; - let p2 = frame2[pos]; - k += pixel_diff(p1, p2) - } - } - k -} - -#[inline(always)] -pub fn pixel_diff(p1: Pixel, p2: Pixel) -> u32 { - p1.r.abs_diff(p2.r) as u32 + p1.g.abs_diff(p2.g) as u32 + p1.b.abs_diff(p2.b) as u32 -} diff --git a/bv1/codec/src/frameio.rs b/bv1/codec/src/frameio.rs deleted file mode 100644 index f6cbcbf..0000000 --- a/bv1/codec/src/frameio.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::{Frame, Pixel, PixelValue, P2}; -use std::io::{Read, Result, Write}; - -impl Frame { - pub fn read(inp: &mut impl Read, size: P2) -> Result<Frame> { - let mut f = Frame::new(size); - - for y in 0..size.y { - for x in 0..size.x { - let mut cc = [0u8; 3]; - inp.read_exact(&mut cc)?; - f[P2 { x, y }] = Pixel { - r: cc[0] as PixelValue, - g: cc[1] as PixelValue, - b: cc[2] as PixelValue, - }; - } - } - Ok(f) - } - - pub fn write(out: &mut impl Write, frame: &Frame) -> Result<()> { - for y in 0..frame.size.y { - for x in 0..frame.size.x { - let p = frame[P2 { x, y }]; - let mut cc = [0u8; 3]; - cc[0] = p.r.clamp(0, 255) as u8; - cc[1] = p.g.clamp(0, 255) as u8; - cc[2] = p.b.clamp(0, 255) as u8; - out.write_all(&mut cc)?; - } - } - Ok(()) - } -} diff --git a/bv1/codec/src/huff.rs b/bv1/codec/src/huff.rs deleted file mode 100644 index 0dbb6ce..0000000 --- a/bv1/codec/src/huff.rs +++ /dev/null @@ -1,192 +0,0 @@ -use std::io::{Read, Result, Write}; - -#[derive(Debug, Clone)] -enum HT { - Branch(Box<HT>, Box<HT>), - Terminal(u8), -} - -pub fn write_huff(buf: &[u8], w: &mut impl Write) -> Result<usize> { - let mut w = BitIO::new(w); - assert!(buf.len() <= 0xffffff, "huff frame too big"); - w.wbyte((buf.len() & 0xff) as u8)?; - w.wbyte(((buf.len() >> 8) & 0xff) as u8)?; - w.wbyte(((buf.len() >> 16) & 0xff) as u8)?; - - let mut probs = [0usize; 256]; - for b in buf { - probs[*b as usize] += 1; - } - let tree = HT::from_probabilities(probs); - let mut table = [0u32; 256]; - tree.create_lut(&mut table, 1); - tree.write(&mut w)?; - - for b in buf { - let mut k = table[*b as usize]; - while k != 1 { - w.wbit((k & 1) == 1)?; - k >>= 1; - } - } - - w.flush()?; - Ok(w.position) -} - -pub fn read_huff(r: &mut impl Read, buf: &mut Vec<u8>) -> Result<usize> { - let mut r = BitIO::new(r); - - let mut len = 0usize; - len |= r.rbyte()? as usize; - len |= (r.rbyte()? as usize) << 8; - len |= (r.rbyte()? as usize) << 16; - - let root = HT::read(&mut r)?; - let root = match &root { - HT::Branch(a, b) => [a, b], - _ => panic!("no!"), - }; - - let mut cursor = root; - while buf.len() != len { - let v = r.rbit()?; - match cursor[v as usize].as_ref() { - HT::Branch(a, b) => { - cursor = [a, b]; - } - HT::Terminal(n) => { - buf.push(*n); - cursor = root; - } - } - } - Ok(r.position) -} - -impl HT { - pub fn from_probabilities(ps: [usize; 256]) -> Self { - let mut parts = ps - .into_iter() - .enumerate() - .map(|(n, p)| (p, HT::Terminal(n as u8))) - .collect::<Vec<_>>(); - - while parts.len() != 1 { - parts.sort_by_key(|e| -(e.0 as isize)); - let ((ap, at), (bp, bt)) = (parts.pop().unwrap(), parts.pop().unwrap()); - parts.push((ap + bp + 1, HT::Branch(Box::new(at), Box::new(bt)))) - } - parts[0].1.clone() - } - pub fn create_lut(&self, table: &mut [u32; 256], mut prefix: u32) { - assert!(self.depth() < 30, "too deep! doesnt fit {}", self.depth()); - match self { - HT::Branch(a, b) => { - let pz = 32 - prefix.leading_zeros(); - prefix ^= 1 << pz; - prefix ^= 1 << (pz - 1); - a.create_lut(table, prefix); - prefix ^= 1 << (pz - 1); - b.create_lut(table, prefix); - } - HT::Terminal(n) => { - assert_eq!(table[*n as usize], 0); - table[*n as usize] = prefix - } - } - } - pub fn depth(&self) -> usize { - match self { - HT::Branch(a, b) => a.depth().max(b.depth()) + 1, - HT::Terminal(_) => 0, - } - } - pub fn write(&self, w: &mut BitIO<impl Write>) -> Result<()> { - match self { - HT::Branch(a, b) => { - w.wbit(false)?; - a.write(w)?; - b.write(w)?; - } - HT::Terminal(n) => { - w.wbit(true)?; - w.wbyte(*n)?; - } - } - Ok(()) - } - pub fn read(r: &mut BitIO<impl Read>) -> Result<Self> { - match r.rbit()? { - false => Ok(Self::Branch( - Box::new(Self::read(r)?), - Box::new(Self::read(r)?), - )), - true => Ok(Self::Terminal(r.rbyte()?)), - } - } -} - -pub struct BitIO<T> { - inner: T, - byte: u8, - position: usize, -} -impl<T> BitIO<T> { - pub fn new(inner: T) -> Self { - Self { - inner, - byte: 0, - position: 0, - } - } -} -impl<T: Write> BitIO<T> { - #[inline] - pub fn wbit(&mut self, b: bool) -> Result<()> { - self.byte <<= 1; - self.byte |= b as u8; - self.position += 1; - if self.position & 0b111 == 0 { - self.inner.write_all(&[self.byte])?; - } - Ok(()) - } - #[inline] - pub fn wbyte(&mut self, v: u8) -> Result<()> { - for i in 0..8 { - self.wbit((v & (1 << i)) != 0)?; - } - Ok(()) - } - pub fn flush(&mut self) -> Result<()> { - while self.position & 0b111 != 0 { - self.wbit(false)?; - } - Ok(()) - } -} - -impl<T: Read> BitIO<T> { - #[inline] - pub fn rbit(&mut self) -> Result<bool> { - if self.position & 0b111 == 0 { - let mut buf = [0]; - self.inner.read_exact(&mut buf)?; - self.byte = buf[0]; - } - - let v = (self.byte & 0b10000000) != 0; - self.byte <<= 1; - self.position += 1; - Ok(v) - } - #[inline] - pub fn rbyte(&mut self) -> Result<u8> { - let mut v = 0u8; - for i in 0..8 { - v |= (self.rbit()? as u8) << i; - } - Ok(v) - } -} diff --git a/bv1/codec/src/impls.rs b/bv1/codec/src/impls.rs deleted file mode 100644 index b4cc119..0000000 --- a/bv1/codec/src/impls.rs +++ /dev/null @@ -1,165 +0,0 @@ -use crate::{Frame, Pixel, Ref, View, P2}; -use std::ops::{Add, AddAssign, Index, IndexMut, Sub}; - -#[cfg(feature = "parallel")] -pub use rayon::join; -#[cfg(not(feature = "parallel"))] -pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) -where - A: FnOnce() -> RA + Send, - B: FnOnce() -> RB + Send, - RA: Send, - RB: Send, -{ - (oper_a(), oper_b()) -} - -impl Frame { - pub fn export(&self, view: View) -> Vec<Pixel> { - let mut o = vec![]; - for y in view.a.y..view.b.y { - for x in view.a.x..view.b.x { - o.push(self[P2 { x, y }]) - } - } - o - } - pub fn import(&mut self, view: View, mut source: &[Pixel]) { - for y in view.a.y..view.b.y { - for x in view.a.x..view.b.x { - self[P2 { x, y }] = source[0]; - source = &source[1..]; - } - } - assert_eq!(source.len(), 0) - } - pub fn new(size: P2) -> Self { - Self { - pixels: vec![Pixel::default(); size.area()], - size, - } - } -} -impl Ref { - #[inline] - pub fn apply<F: Fn(&mut Self)>(mut self, f: F) -> Self { - f(&mut self); - self - } -} -impl Pixel { - pub const BLACK: Pixel = Pixel { r: 0, g: 0, b: 0 }; - pub const RED: Pixel = Pixel { r: 255, g: 0, b: 0 }; - pub const GREEN: Pixel = Pixel { r: 0, g: 255, b: 0 }; - pub const BLUE: Pixel = Pixel { r: 0, g: 0, b: 255 }; -} -impl AddAssign for P2 { - fn add_assign(&mut self, rhs: Self) { - self.x += rhs.x; - self.y += rhs.y; - } -} -impl Add for Pixel { - type Output = Pixel; - #[inline] - fn add(self, rhs: Self) -> Self::Output { - Self { - r: self.r + rhs.r, - g: self.g + rhs.g, - b: self.b + rhs.b, - } - } -} -impl Sub for Pixel { - type Output = Pixel; - #[inline] - fn sub(self, rhs: Self) -> Self::Output { - Self { - r: self.r - rhs.r, - g: self.g - rhs.g, - b: self.b - rhs.b, - } - } -} -impl P2 { - pub const ZERO: P2 = P2 { x: 0, y: 0 }; - pub const X: P2 = P2 { x: 1, y: 0 }; - pub const Y: P2 = P2 { x: 0, y: 1 }; - - #[inline] - pub fn area(&self) -> usize { - (self.x * self.y) as usize - } -} -impl View { - #[inline] - pub fn all(b: P2) -> Self { - Self { - a: P2::default(), - b, - } - } - #[inline] - pub fn size(&self) -> P2 { - self.b - self.a - } -} -impl Add<P2> for View { - type Output = View; - #[inline] - fn add(self, rhs: P2) -> Self::Output { - View { - a: self.a + rhs, - b: self.b + rhs, - } - } -} -impl Add for P2 { - type Output = P2; - #[inline] - fn add(self, rhs: Self) -> Self::Output { - Self { - x: self.x + rhs.x, - y: self.y + rhs.y, - } - } -} -impl Sub for P2 { - type Output = P2; - #[inline] - fn sub(self, rhs: Self) -> Self::Output { - Self { - x: self.x - rhs.x, - y: self.y - rhs.y, - } - } -} - -impl Index<P2> for Frame { - type Output = Pixel; - #[inline] - fn index(&self, P2 { x, y }: P2) -> &Self::Output { - &self - .pixels - .get(x as usize + (y as usize * self.size.x as usize)) - .unwrap_or(&Pixel { r: 0, g: 0, b: 0 }) - } -} -impl IndexMut<P2> for Frame { - #[inline] - fn index_mut(&mut self, P2 { x, y }: P2) -> &mut Self::Output { - &mut self.pixels[x as usize + (y as usize * self.size.x as usize)] - } -} - -pub trait ToArray { - type Output; - fn to_array(self) -> [Self::Output; 2]; -} -impl<A> ToArray for (A, A) { - type Output = A; - #[inline] - fn to_array(self) -> [A; 2] { - [self.0, self.1] - } -} diff --git a/bv1/codec/src/lib.rs b/bv1/codec/src/lib.rs deleted file mode 100644 index 7041950..0000000 --- a/bv1/codec/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![feature(portable_simd)] - -pub mod debug; -pub mod decode; -pub mod encode; -pub mod frameio; -pub mod huff; -pub mod impls; -pub mod serialize; -pub mod split; - -pub type PixelValue = i16; - -pub use decode::{decode, Decoder}; -pub use encode::encode; - -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] -pub struct Pixel { - pub r: PixelValue, - pub g: PixelValue, - pub b: PixelValue, -} - -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] -pub struct P2 { - pub x: i32, - pub y: i32, -} - -pub struct Frame { - pub size: P2, - pub pixels: Vec<Pixel>, -} - -#[derive(Debug, Clone, Copy)] -pub struct View { - pub a: P2, - pub b: P2, -} - -#[derive(Debug, Clone)] -pub enum Block { - Split(Box<Block>, Box<Block>), - Lit(Vec<Pixel>), - Ref(Ref), -} - -#[derive(Debug, Clone, Copy, Default)] -pub struct Ref { - pub pos_off: P2, - pub color_off: Pixel, -} diff --git a/bv1/codec/src/serialize.rs b/bv1/codec/src/serialize.rs deleted file mode 100644 index 86b2919..0000000 --- a/bv1/codec/src/serialize.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::{split::split, Block, Pixel, Ref, View, P2}; -use std::io::{Read, Result, Write}; - -impl Pixel { - #[inline] - pub fn write(&self, w: &mut impl Write) -> Result<()> { - w.write_all(&[ - self.r.clamp(0, 255) as u8, - self.g.clamp(0, 255) as u8, - self.b.clamp(0, 255) as u8, - ]) - } - #[inline] - pub fn read(r: &mut impl Read) -> Result<Pixel> { - Ok(Self { - r: read_byte(r)? as i16, - g: read_byte(r)? as i16, - b: read_byte(r)? as i16, - }) - } -} -impl Pixel { - #[inline] - pub fn write_full(&self, w: &mut impl Write) -> Result<()> { - write_word(w, self.r)?; - write_word(w, self.g)?; - write_word(w, self.b)?; - Ok(()) - } - #[inline] - pub fn read_full(r: &mut impl Read) -> Result<Pixel> { - Ok(Self { - r: read_word(r)?, - g: read_word(r)?, - b: read_word(r)?, - }) - } -} -impl P2 { - #[inline] - pub fn write(&self, w: &mut impl Write) -> Result<()> { - write_word(w, self.x as i16)?; - write_word(w, self.y as i16)?; - Ok(()) - } - - #[inline] - pub fn read(r: &mut impl Read) -> Result<P2> { - Ok(Self { - x: read_word(r)? as i32, - y: read_word(r)? as i32, - }) - } -} - -impl Block { - pub fn write(&self, w: &mut impl Write) -> Result<()> { - match self { - Block::Split(a, b) => { - w.write_all(&[0])?; - a.write(w)?; - b.write(w)?; - } - Block::Lit(pixels) => { - w.write_all(&[1])?; - for p in pixels { - p.write(w)?; - } - } - Block::Ref(k) => { - w.write_all(&[2])?; - k.pos_off.write(w)?; - k.color_off.write_full(w)?; - } - } - Ok(()) - } - pub fn read(r: &mut impl Read, view: View) -> Result<Block> { - match read_byte(r)? { - 0 => { - let [av, bv] = split(view); - Ok(Block::Split( - Box::new(Block::read(r, av)?), - Box::new(Block::read(r, bv)?), - )) - } - 1 => { - let mut px = vec![]; - for _ in 0..view.size().area() { - px.push(Pixel::read(r)?) - } - Ok(Block::Lit(px)) - } - 2 => Ok(Block::Ref(Ref { - pos_off: P2::read(r)?, - color_off: Pixel::read_full(r)?, - })), - _ => Err(std::io::Error::other("unknown block variant")), - } - } -} - -#[inline] -fn read_byte(r: &mut impl Read) -> Result<u8> { - let mut buf = [0u8]; - r.read_exact(&mut buf)?; - Ok(buf[0]) -} -#[inline] -fn write_word(w: &mut impl Write, v: i16) -> Result<()> { - w.write_all(&[(v & 0xff) as u8, (v >> 8) as u8]) -} -#[inline] -fn read_word(r: &mut impl Read) -> Result<i16> { - Ok((read_byte(r)? as u16 | ((read_byte(r)? as u16) << 8)) as i16) -} diff --git a/bv1/codec/src/split.rs b/bv1/codec/src/split.rs deleted file mode 100644 index c17179e..0000000 --- a/bv1/codec/src/split.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{View, P2}; - -pub fn split(view: View) -> [View; 2] { - let s = view.size(); - if s.x > s.y { - let mid_x = (view.a.x + view.b.x) / 2; - [ - View { - a: view.a, - b: P2 { - x: mid_x, - y: view.b.y, - }, - }, - View { - a: P2 { - x: mid_x, - y: view.a.y, - }, - b: view.b, - }, - ] - } else { - let mid_y = (view.a.y + view.b.y) / 2; - [ - View { - a: view.a, - b: P2 { - x: view.b.x, - y: mid_y, - }, - }, - View { - a: P2 { - x: view.a.x, - y: mid_y, - }, - b: view.b, - }, - ] - } -} |