aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-03-09 18:09:07 +0100
committermetamuffin <metamuffin@disroot.org>2023-03-09 18:09:07 +0100
commit4fbf4bb4310da4bede43c9428809ac9a8804982a (patch)
treedaa7b2b34bb0aad4c188550b413ccd725eb1c5c4
parentecb81ba6448d6e33a9e7ecd3cd5d41513713f814 (diff)
downloadvideo-codec-experiments-4fbf4bb4310da4bede43c9428809ac9a8804982a.tar
video-codec-experiments-4fbf4bb4310da4bede43c9428809ac9a8804982a.tar.bz2
video-codec-experiments-4fbf4bb4310da4bede43c9428809ac9a8804982a.tar.zst
works very well
-rw-r--r--lvc/src/bin/main.rs29
-rw-r--r--lvc/src/decode.rs9
-rw-r--r--lvc/src/encode.rs37
-rw-r--r--lvc/src/huff.rs6
4 files changed, 46 insertions, 35 deletions
diff --git a/lvc/src/bin/main.rs b/lvc/src/bin/main.rs
index 7c0d965..6037855 100644
--- a/lvc/src/bin/main.rs
+++ b/lvc/src/bin/main.rs
@@ -28,12 +28,14 @@ struct Args {
enum Action {
// Compress video
Encode {
- #[arg(short, long, default_value_t = 400)]
+ #[arg(short, long, default_value_t = 800)]
max_block_size: usize,
+ #[arg(short, long, default_value_t = 10_000)]
+ attention_split: u32,
+ #[arg(short, long, default_value_t = 10.)]
+ threshold: f32,
#[arg(short, long, default_value_t = 10)]
- iters: usize,
- #[arg(short, long, default_value_t = 5_000)]
- threshold: u32,
+ keyframe_interval: usize,
},
// Decompress video
Decode {
@@ -53,12 +55,13 @@ fn main() {
Action::Encode {
max_block_size,
threshold,
- iters,
+ attention_split,
+ keyframe_interval,
} => {
let config = EncodeConfig {
threshold,
max_block_size,
- iters,
+ attention_split,
};
let mut last_frame = Frame::new(size);
@@ -70,6 +73,11 @@ fn main() {
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();
@@ -95,12 +103,12 @@ fn main() {
time_decode + time_huff + time_encode
);
eprintln!(
- "\tencode {time_encode:?} ({}%)",
- ((bits_raw as f32 / (size.area() * 24) as f32) * 100.0).round()
+ "\tencode {time_encode:?} ({:.2}%)",
+ (bits_raw as f32 / (size.area() * 24) as f32) * 100.0
);
eprintln!(
- "\thuff {time_huff:?} ({}%)",
- ((bits_huff as f32 / bits_raw as f32) * 100.0).round()
+ "\thuff {time_huff:?} ({:.2}%)",
+ (bits_huff as f32 / bits_raw as f32) * 100.0
);
eprintln!("\tdecode {time_decode:?}");
} else {
@@ -119,7 +127,6 @@ fn main() {
let huff = true;
loop {
-
let b = if huff {
let mut buf = vec![];
read_huff(&mut stdin, &mut buf).unwrap();
diff --git a/lvc/src/decode.rs b/lvc/src/decode.rs
index da69080..771cba9 100644
--- a/lvc/src/decode.rs
+++ b/lvc/src/decode.rs
@@ -1,12 +1,17 @@
use crate::{split::split, Block, Frame, View, P2};
+use rayon::join;
pub fn decode(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);
- decode(last_frame, frame, av, &a);
- decode(last_frame, frame, bv, &b);
+ 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),
+ );
}
Block::Ref(r) => {
for y in view.a.y..view.b.y {
diff --git a/lvc/src/encode.rs b/lvc/src/encode.rs
index 4ec72cf..030e882 100644
--- a/lvc/src/encode.rs
+++ b/lvc/src/encode.rs
@@ -2,15 +2,18 @@ use crate::diff::{diff, pixel_diff};
use crate::split::split;
use crate::{Block, Frame, Pixel, Ref, View, P2};
+#[derive(Debug, Clone)]
pub struct EncodeConfig {
- pub threshold: u32,
+ pub threshold: f32,
pub max_block_size: usize,
- pub iters: usize,
+ pub attention_split: u32,
}
pub fn encode(last_frame: &Frame, frame: &Frame, view: View, config: &EncodeConfig) -> Block {
let view_area = view.size().area();
- if view_area > config.max_block_size {
+ 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)),
@@ -22,12 +25,13 @@ pub fn encode(last_frame: &Frame, frame: &Frame, view: View, config: &EncodeConf
let mut r = Ref::default();
let mut d = diff([last_frame, frame], view, r);
- let att = 1. - attention(frame, view) as f32 * 0.000001;
- let thres = (config.threshold as f32 * att.clamp(0.2, 1.0)) as u32;
+ // let att = 1. - attention(frame, view) as f32 * 0.000001;
+ // let thres = (config.threshold as f32 * att.clamp(0.2, 1.0)) as u32;
+ let thres = (config.threshold * view_area as f32) as u32;
let target_average = average_color(frame, view);
- for granularity in [8, 8, 4, 2, 1, 1, 1] {
+ for granularity in [2, 1, 2, 1, 2, 1, 2, 1] {
let (nd, nrp) = optimize_ref(last_frame, frame, view, r, granularity, target_average);
if nd < d {
r = nrp;
@@ -52,6 +56,7 @@ pub fn optimize_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 })),
@@ -61,6 +66,14 @@ pub fn optimize_ref(
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);
@@ -72,20 +85,10 @@ pub fn optimize_ref(
None
}
},
- // Some(r.apply(|r| r.color_off.r += (g as i16) << 2)),
- // Some(r.apply(|r| r.color_off.r -= (g as i16) << 2)),
- // Some(r.apply(|r| r.color_off.g += (g as i16) << 2)),
- // Some(r.apply(|r| r.color_off.g -= (g as i16) << 2)),
- // Some(r.apply(|r| r.color_off.b += (g as i16) << 2)),
- // Some(r.apply(|r| r.color_off.b -= (g as i16) << 2)),
]
.into_iter()
.flatten()
- .map(|r| {
- let d = diff([last_frame, frame], view, r);
-
- (d, r)
- })
+ .map(|r| (diff([last_frame, frame], view, r), r))
.min_by_key(|e| e.0)
.unwrap()
}
diff --git a/lvc/src/huff.rs b/lvc/src/huff.rs
index b00aaa0..6d74c42 100644
--- a/lvc/src/huff.rs
+++ b/lvc/src/huff.rs
@@ -22,6 +22,7 @@ pub fn write_huff(buf: &[u8], w: &mut impl Write) -> Result<usize> {
tree.create_lut(&mut table, 1);
tree.write(&mut w)?;
+
for b in buf {
let mut k = table[*b as usize];
while k != 1 {
@@ -31,7 +32,6 @@ pub fn write_huff(buf: &[u8], w: &mut impl Write) -> Result<usize> {
}
w.flush()?;
- eprintln!("{}", w.position);
Ok(w.position)
}
@@ -43,9 +43,7 @@ pub fn read_huff(r: &mut impl Read, buf: &mut Vec<u8>) -> Result<usize> {
len |= (r.rbyte()? as usize) << 8;
len |= (r.rbyte()? as usize) << 16;
- eprintln!("len={len:?}");
let root = HT::read(&mut r)?;
- // eprintln!("{root:?}");
let root = match &root {
HT::Branch(a, b) => [a, b],
_ => panic!("no!"),
@@ -64,8 +62,6 @@ pub fn read_huff(r: &mut impl Read, buf: &mut Vec<u8>) -> Result<usize> {
}
}
}
- eprintln!("len(buf)={}", buf.len());
- eprintln!("{}", r.position);
Ok(r.position)
}