lossy compression

This commit is contained in:
Crispy 2024-04-12 18:47:40 +02:00
parent 242724d7fd
commit 8bfeb6d2f3
4 changed files with 194 additions and 37 deletions

View file

@ -8,13 +8,13 @@ pub use util::*;
const INSPECT_ENC: bool = false;
const INSPECT_DEC: bool = false;
const MAX_ERROR: usize = 0;
const MAX_ERROR: usize = 4; // max wrong pixels
const MAX_LOSS: usize = 16; // highest "loss" value tried for all lossy encodings
fn main() {
let frames = get_all_frames("../video/frames/");
let encoded = encode(&frames);
// todo print average bytes per frame for each encoding type
let mut stats: EnumMap<Encoding, u32> = EnumMap::default();
let mut reader = 0;
let mut last_frame = FRAME_0;
@ -49,34 +49,59 @@ fn main() {
fn encode(frames: &[Frame]) -> Vec<u8> {
let mut out = Vec::new();
let encodings: Vec<FrameEncoder> = vec![
enc::fill_white,
enc::fill_black,
let lossless_encodings: Vec<FrameEncoder> = vec![
enc::rle_horizontal,
enc::rle_vertical,
enc::rle_diff_horizontal,
enc::rle_diff_vertical,
enc::bg_strips_horizontal,
];
let lossy_encodings: Vec<FrameEncoderLossy> = vec![
enc::fill_white,
enc::fill_black,
enc::cell_diff_8_vertical,
enc::cell_diff_4_vertical,
];
let mut last_frame = FRAME_0;
for (i, frame) in frames.iter().enumerate() {
for (_i, frame) in frames.iter().enumerate() {
let mut options = Vec::new();
for encode in &encodings {
for encode in &lossless_encodings {
let encoded = encode(&last_frame, frame);
let decode = get_matching_decoder(encoded.encoding);
let decoded = decode(&last_frame, &encoded.data, &mut 0);
let error = frame_error(frame, &decoded);
if error <= MAX_ERROR {
if error == 0 {
options.push(encoded);
} else {
// dbg!(&encoded);
// println!("{:?}, error: {error}, frame: {i}", encoded.encoding);
// render_images(&frame, &decoded);
// panic!("loss in compression");
dbg!(&encoded);
println!("{:?}, error: {error}, frame: {_i}", encoded.encoding);
render_images(&frame, &decoded);
panic!("error in lossless compression");
}
}
for encode in &lossy_encodings {
for loss in 0..MAX_LOSS {
let encoded = encode(&last_frame, frame, loss);
let decode = get_matching_decoder(encoded.encoding);
let decoded = decode(&last_frame, &encoded.data, &mut 0);
let error = frame_error(frame, &decoded);
// if error > 0 && loss == 0 {
// dbg!(&encoded);
// println!("{:?}, error: {error}, frame: {_i}", encoded.encoding);
// render_images(&frame, &decoded);
// panic!("error in 'loss 0' compression");
// }
if error < MAX_ERROR {
options.push(encoded);
} else {
// higher loss value will mean more error so can be skipped
break;
}
}
}
options.sort_by_key(|b| b.data.len());
let best_encoding = options.into_iter().next().unwrap();
if INSPECT_ENC {
@ -99,10 +124,10 @@ fn encode(frames: &[Frame]) -> Vec<u8> {
#[derive(Debug, TryFromPrimitive, Enum, Copy, Clone)]
#[repr(u8)]
enum Encoding {
FillWhite,
FillBlack,
RLEHorizontal,
RLEVertical,
FillBlack = 0,
FillWhite = 1,
RLEHorizontal = 2,
RLEVertical = 3,
RLEDiffHorizontal,
RLEDiffVertical,
BGStripsH,
@ -114,7 +139,7 @@ enum Encoding {
// CellDiff4HH,
// CellDiff4HV,
// CellDiff4VH,
// CellDiff4VV,
CellDiff4VV,
}
fn get_matching_decoder(encoding: Encoding) -> FrameDecoder {
@ -134,11 +159,12 @@ fn get_matching_decoder(encoding: Encoding) -> FrameDecoder {
// Encoding::CellDiff4HH => todo!(),
// Encoding::CellDiff4HV => todo!(),
// Encoding::CellDiff4VH => todo!(),
// Encoding::CellDiff4VV => todo!(),
Encoding::CellDiff4VV => dec::cell_diff_4_vertical,
}
}
type FrameEncoder = fn(previous_frame: &Frame, new_frame: &Frame) -> EncodedFrame;
type FrameEncoderLossy = fn(previous_frame: &Frame, new_frame: &Frame, loss: usize) -> EncodedFrame;
type FrameDecoder = fn(previous_frame: &Frame, encoded_bytes: &[u8], reader: &mut usize) -> Frame;
#[derive(Debug)]