add diff rle and run decoding on final byte array

This commit is contained in:
Crispy 2024-04-11 20:52:12 +02:00
parent eca5344c66
commit 3af9be328c
6 changed files with 308 additions and 48 deletions

View file

@ -1,33 +1,67 @@
use enum_map::{Enum, EnumMap};
use num_enum::TryFromPrimitive;
mod dec;
mod enc;
mod util;
pub use util::*;
const INTERACTIVE: bool = false;
const INSPECT_ENC: bool = false;
const INSPECT_DEC: bool = true;
fn main() {
let frames = get_all_frames("../video/frames/");
let encoded = encode(&frames);
println!("{} frames, total {} bytes", frames.len(), encoded.len());
//
// 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;
let mut frame_index = 0;
while reader < encoded.len() {
let frame_type: Encoding = encoded[reader].try_into().unwrap();
stats[frame_type] += 1;
reader += 1;
let decoder = get_matching_decoder(frame_type);
last_frame = decoder(&last_frame, &encoded[reader..], &mut reader);
if INSPECT_DEC {
println!("\n{frame_type:?}");
render_images(&frames[frame_index], &last_frame);
wait_for_input();
frame_index += 1;
}
}
for (encoding, frames) in stats.iter() {
println!("{encoding:?} - {frames} frames");
}
println!();
println!(
"{} frames, total {} bytes (~{} bpf)",
frames.len(),
encoded.len(),
encoded.len() / frames.len()
);
}
fn encode(frames: &[Frame]) -> Vec<u8> {
let mut out = Vec::new();
let encodings: Vec<(FrameEncoder, FrameDecoder)> = vec![
(enc::fill_white, dec::fill_white),
(enc::fill_black, dec::fill_black),
(enc::rle_horizontal, dec::rle_horizontal),
(enc::rle_vertical, dec::rle_vertical),
let encodings: Vec<FrameEncoder> = vec![
enc::fill_white,
enc::fill_black,
enc::rle_horizontal,
enc::rle_vertical,
enc::rle_diff_horizontal,
enc::rle_diff_vertical,
];
let max_error = 0;
let mut last_frame = FRAME_0;
for frame in frames {
let mut options = Vec::new();
for (encode, decode) in &encodings {
for encode in &encodings {
let encoded = encode(&last_frame, frame);
let decoded = decode(&last_frame, &encoded.data);
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 {
options.push(encoded);
@ -35,7 +69,7 @@ fn encode(frames: &[Frame]) -> Vec<u8> {
}
options.sort_by_key(|b| b.data.len());
let best_encoding = options.into_iter().next().unwrap();
if INTERACTIVE {
if INSPECT_ENC {
println!();
println!(
"{:?}, {} bytes",
@ -43,8 +77,7 @@ fn encode(frames: &[Frame]) -> Vec<u8> {
best_encoding.data.len() + 1
);
render_image(frame);
let mut a = String::new();
std::io::stdin().read_line(&mut a).unwrap();
wait_for_input();
}
let best_encoding = best_encoding.into_bytes();
out.extend_from_slice(&best_encoding);
@ -53,38 +86,59 @@ fn encode(frames: &[Frame]) -> Vec<u8> {
out
}
#[derive(Debug)]
#[derive(Debug, TryFromPrimitive, Enum, Copy, Clone)]
#[repr(u8)]
enum Encoding {
FillWhite,
FillBlack,
RLEHorizontal,
RLEVertical,
BGStrips,
CellDiff8Horizontal,
CellDiff8Vertical,
RLEDiffHorizontal,
RLEDiffVertical,
BGStripsH,
BGStripsV,
QuadTree,
DrawCommands,
CellDiff8H,
CellDiff8V,
CellDiff4HH,
CellDiff4HV,
CellDiff4VH,
CellDiff4VV,
}
fn get_matching_decoder(encoding: Encoding) -> FrameDecoder {
match encoding {
Encoding::FillWhite => dec::fill_white,
Encoding::FillBlack => dec::fill_black,
Encoding::RLEHorizontal => dec::rle_horizontal,
Encoding::RLEVertical => dec::rle_vertical,
Encoding::RLEDiffHorizontal => dec::rle_diff_horizontal,
Encoding::RLEDiffVertical => dec::rle_diff_vertical,
Encoding::BGStripsH => todo!(),
Encoding::BGStripsV => todo!(),
Encoding::QuadTree => todo!(),
Encoding::DrawCommands => todo!(),
Encoding::CellDiff8H => todo!(),
Encoding::CellDiff8V => todo!(),
Encoding::CellDiff4HH => todo!(),
Encoding::CellDiff4HV => todo!(),
Encoding::CellDiff4VH => todo!(),
Encoding::CellDiff4VV => todo!(),
}
}
type FrameEncoder = fn(previous_frame: &Frame, new_frame: &Frame) -> EncodedFrame;
type FrameDecoder = fn(previous_frame: &Frame, encoded_bytes: &[u8]) -> Frame;
type FrameDecoder = fn(previous_frame: &Frame, encoded_bytes: &[u8], reader: &mut usize) -> Frame;
struct EncodedFrame {
encoding: Encoding,
head_u4: u8,
data: Vec<u8>,
}
impl EncodedFrame {
fn into_bytes(self) -> Vec<u8> {
let head = (self.encoding as u8) << 4;
let head = head | (self.head_u4 & 15);
let mut out = Vec::with_capacity(self.data.len() + 1);
out.push(head);
out.extend(self.data.into_iter());
out
fn into_bytes(mut self) -> Vec<u8> {
self.data.insert(0, self.encoding as u8);
self.data
}
}