From 11b78570656bd0ca67594472765fc629aa25fd25 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Thu, 9 Mar 2023 19:04:33 +0100 Subject: move all logic to codec crate --- lvc/app/src/bin/main.rs | 125 ++------------------------------------------- lvc/codec/src/decode.rs | 43 ++++++++++++++-- lvc/codec/src/encode.rs | 70 +++++++++++++++++++++++-- lvc/codec/src/frameio.rs | 35 +++++++++++++ lvc/codec/src/lib.rs | 1 + lvc/codec/src/serialize.rs | 11 +--- 6 files changed, 148 insertions(+), 137 deletions(-) create mode 100644 lvc/codec/src/frameio.rs diff --git a/lvc/app/src/bin/main.rs b/lvc/app/src/bin/main.rs index 79869c3..8cac292 100644 --- a/lvc/app/src/bin/main.rs +++ b/lvc/app/src/bin/main.rs @@ -1,15 +1,10 @@ use bv1::{ - debug::draw_debug, decode::decode, encode::{encode, EncodeConfig}, - huff::{read_huff, write_huff}, - Block, Frame, Pixel, PixelValue, View, P2, + P2, }; use clap::{Parser, Subcommand}; -use std::{ - io::{stdin, stdout, BufReader, BufWriter, Read, Write}, - time::Instant, -}; +use std::io::{stdin, stdout}; #[derive(Parser)] #[clap(about, version)] @@ -62,123 +57,13 @@ fn main() { threshold, max_block_size, attention_split, + keyframe_interval, }; - let mut last_frame = Frame::new(size); - - let mut stdin = BufReader::new(stdin()); - let mut stdout = BufWriter::new(stdout()); - - let huff = true; - - for frame_number in 0.. { - let mut frame = read_frame(&mut stdin, size); - - let mut config = config.clone(); - if frame_number % keyframe_interval != 0 { - config.threshold = std::f32::INFINITY; - } - - let t = Instant::now(); - let b: Block = encode(&last_frame, &frame, View::all(size), &config); - let time_encode = t.elapsed(); - let t = Instant::now(); - decode(&last_frame, &mut frame, View::all(size), &b); - last_frame = frame; - let time_decode = t.elapsed(); - - if huff { - let mut buf = vec![]; - let mut bufw = std::io::Cursor::new(&mut buf); - b.write(&mut bufw).unwrap(); - drop(bufw); - let t = Instant::now(); - let bits_raw = buf.len() * 8; - let bits_huff = write_huff(&buf, &mut stdout).unwrap(); - 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 stdout).unwrap(); - } - } + encode(config, size, stdin(), stdout()).unwrap(); } Action::Decode { debug } => { - let mut frame = Frame::new(size); - let mut last_frame = Frame::new(size); - let mut debug_frame = if debug { Some(Frame::new(size)) } else { None }; - - let mut stdin = BufReader::new(stdin()); - let mut stdout = BufWriter::new(stdout()); - - let huff = true; - - loop { - let b = if huff { - let mut buf = vec![]; - read_huff(&mut stdin, &mut buf).unwrap(); - let mut buf = std::io::Cursor::new(&mut buf); - Block::read(&mut buf, View::all(size)).unwrap() - } else { - Block::read(&mut stdin, View::all(size)).unwrap() - }; - - decode(&last_frame, &mut frame, View::all(size), &b); - - if let Some(debug_frame) = &mut debug_frame { - debug_frame.pixels.copy_from_slice(&frame.pixels); - draw_debug(debug_frame, View::all(size), &b); - write_frame(&mut stdout, &debug_frame); - } else { - write_frame(&mut stdout, &frame); - } - - last_frame.pixels.copy_from_slice(&frame.pixels); // TODO use mem::swap - frame.pixels.iter_mut().for_each(|e| *e = Pixel::BLACK); - } - } - } -} - -fn read_frame(inp: &mut impl Read, size: P2) -> 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).unwrap(); - f[P2 { x, y }] = Pixel { - r: cc[0] as PixelValue, - g: cc[1] as PixelValue, - b: cc[2] as PixelValue, - }; - } - } - f -} - -fn write_frame(out: &mut impl Write, frame: &Frame) { - 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).unwrap(); + decode(size, debug, stdin(), stdout()).unwrap(); } } } diff --git a/lvc/codec/src/decode.rs b/lvc/codec/src/decode.rs index 771cba9..4830156 100644 --- a/lvc/codec/src/decode.rs +++ b/lvc/codec/src/decode.rs @@ -1,7 +1,42 @@ -use crate::{split::split, Block, Frame, View, P2}; +use crate::{debug::draw_debug, huff::read_huff, split::split, Block, Frame, Pixel, View, P2}; use rayon::join; +use std::io::{BufReader, BufWriter, Read, Result, Write}; -pub fn decode(last_frame: &Frame, frame: &mut Frame, view: View, block: &Block) { +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 frame = Frame::new(size); + let mut last_frame = Frame::new(size); + let mut debug_frame = if debug { Some(Frame::new(size)) } else { None }; + + let huff = true; + loop { + 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(size))? + } else { + Block::read(&mut input, View::all(size))? + }; + + decode_block(&last_frame, &mut frame, View::all(size), &b); + + if let Some(debug_frame) = &mut debug_frame { + debug_frame.pixels.copy_from_slice(&frame.pixels); + draw_debug(debug_frame, View::all(size), &b); + Frame::write(&mut output, &debug_frame)?; + } else { + Frame::write(&mut output, &frame)?; + } + + last_frame.pixels.copy_from_slice(&frame.pixels); // TODO use mem::swap + frame.pixels.iter_mut().for_each(|e| *e = Pixel::BLACK); + } +} + +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) => { @@ -9,8 +44,8 @@ pub fn decode(last_frame: &Frame, frame: &mut Frame, view: View, block: &Block) let (frame1, frame2) = unsafe { (&mut *(frame as *mut Frame), &mut *(frame as *mut Frame)) }; join( - || decode(last_frame, frame1, av, &a), - || decode(last_frame, frame2, bv, &b), + || decode_block(last_frame, frame1, av, &a), + || decode_block(last_frame, frame2, bv, &b), ); } Block::Ref(r) => { diff --git a/lvc/codec/src/encode.rs b/lvc/codec/src/encode.rs index 030e882..d612daf 100644 --- a/lvc/codec/src/encode.rs +++ b/lvc/codec/src/encode.rs @@ -1,23 +1,85 @@ use crate::diff::{diff, pixel_diff}; +use crate::huff::write_huff; use crate::split::split; -use crate::{Block, Frame, Pixel, Ref, View, P2}; +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 attention_split: u32, + pub keyframe_interval: usize, } -pub fn encode(last_frame: &Frame, frame: &Frame, view: View, config: &EncodeConfig) -> Block { +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(); if view_area > config.max_block_size || (view_area > 64 && attention(frame, view) > config.attention_split) { let [av, bv] = split(view); let (ab, bb) = rayon::join( - || Box::new(encode(last_frame, frame, av, config)), - || Box::new(encode(last_frame, frame, bv, config)), + || Box::new(encode_block(last_frame, frame, av, config)), + || Box::new(encode_block(last_frame, frame, bv, config)), ); return Block::Split(ab, bb); } diff --git a/lvc/codec/src/frameio.rs b/lvc/codec/src/frameio.rs new file mode 100644 index 0000000..f6cbcbf --- /dev/null +++ b/lvc/codec/src/frameio.rs @@ -0,0 +1,35 @@ +use crate::{Frame, Pixel, PixelValue, P2}; +use std::io::{Read, Result, Write}; + +impl Frame { + pub fn read(inp: &mut impl Read, size: P2) -> Result { + 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/lvc/codec/src/lib.rs b/lvc/codec/src/lib.rs index 5ebd91c..5cd83b9 100644 --- a/lvc/codec/src/lib.rs +++ b/lvc/codec/src/lib.rs @@ -10,6 +10,7 @@ pub mod huff; pub mod impls; pub mod serialize; pub mod split; +pub mod frameio; pub type PixelValue = i16; diff --git a/lvc/codec/src/serialize.rs b/lvc/codec/src/serialize.rs index ac6230e..960aa1b 100644 --- a/lvc/codec/src/serialize.rs +++ b/lvc/codec/src/serialize.rs @@ -1,12 +1,5 @@ -use crate::split::split; -use crate::Block; -use crate::Pixel; -use crate::Ref; -use crate::View; -use crate::P2; -use std::io::Read; -use std::io::Result; -use std::io::Write; +use crate::{split::split, Block, Pixel, Ref, View, P2}; +use std::io::{Read, Result, Write}; impl Pixel { #[inline] -- cgit v1.2.3-70-g09d2