aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-03-09 19:04:33 +0100
committermetamuffin <metamuffin@disroot.org>2023-03-09 19:04:33 +0100
commit11b78570656bd0ca67594472765fc629aa25fd25 (patch)
tree184356867a6cc372c23cac1ad179919a92224d8b
parentac27a58c87bea9480f6603a731448f69c9c3b0fb (diff)
downloadvideo-codec-experiments-11b78570656bd0ca67594472765fc629aa25fd25.tar
video-codec-experiments-11b78570656bd0ca67594472765fc629aa25fd25.tar.bz2
video-codec-experiments-11b78570656bd0ca67594472765fc629aa25fd25.tar.zst
move all logic to codec crate
-rw-r--r--lvc/app/src/bin/main.rs125
-rw-r--r--lvc/codec/src/decode.rs43
-rw-r--r--lvc/codec/src/encode.rs70
-rw-r--r--lvc/codec/src/frameio.rs35
-rw-r--r--lvc/codec/src/lib.rs1
-rw-r--r--lvc/codec/src/serialize.rs11
6 files changed, 148 insertions, 137 deletions
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<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/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]