add diff rle and run decoding on final byte array
This commit is contained in:
parent
eca5344c66
commit
3af9be328c
6 changed files with 308 additions and 48 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue