aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--evc/.gitignore1
-rw-r--r--evc/Cargo.lock323
-rw-r--r--evc/Cargo.toml7
-rw-r--r--evc/spec.md12
-rw-r--r--evc/src/bin/encode.rs20
-rw-r--r--evc/src/block.rs69
-rw-r--r--evc/src/header.rs4
-rw-r--r--evc/src/lib.rs5
-rw-r--r--evc/src/ser.rs154
9 files changed, 590 insertions, 5 deletions
diff --git a/evc/.gitignore b/evc/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/evc/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/evc/Cargo.lock b/evc/Cargo.lock
new file mode 100644
index 0000000..06f5cb2
--- /dev/null
+++ b/evc/Cargo.lock
@@ -0,0 +1,323 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cc"
+version = "1.0.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+
+[[package]]
+name = "clap"
+version = "4.0.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
+dependencies = [
+ "bitflags",
+ "clap_derive",
+ "clap_lex",
+ "is-terminal",
+ "once_cell",
+ "strsim",
+ "termcolor",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "errno"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "evc"
+version = "0.1.0"
+dependencies = [
+ "clap",
+]
+
+[[package]]
+name = "heck"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+
+[[package]]
+name = "hermit-abi"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "io-lifetimes"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
+dependencies = [
+ "hermit-abi",
+ "io-lifetimes",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.138"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
+
+[[package]]
+name = "once_cell"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+
+[[package]]
+name = "os_str_bytes"
+version = "6.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustix"
+version = "0.36.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
diff --git a/evc/Cargo.toml b/evc/Cargo.toml
new file mode 100644
index 0000000..d86ebef
--- /dev/null
+++ b/evc/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "evc"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+clap = { version = "*", features = ["derive"] }
diff --git a/evc/spec.md b/evc/spec.md
index 14fe748..b22fbb6 100644
--- a/evc/spec.md
+++ b/evc/spec.md
@@ -1,19 +1,21 @@
-# File format
+# The Experimental Video Codec
+
+## File format
- magic bytes: `5e b1 c3 08`
- resolution: _`u16, u16`_
- frame count: _`u64`_
-- frames (repeated {frame count}-times)
+- frames (repeated [frame count]-times)
- block type
- block
- **I-Block** (literal contents)
- pixels: _`[[u8; 3]]`_
- - **Split-Block** (delegated to 4 sub-blocks)
- - sub-blocks: _`[block; 4]` (see above)_
+ - **Split-Block** (delegated to 2 sub-blocks split on the longest axis)
+ - sub-blocks: _`[block; 2]` (see above)_
- **Reference-Block**
- translation: _`i8, i8`_
-## Todo
+### Todo
- JPEG compress I-Blocks
- Sub-pixel translation
diff --git a/evc/src/bin/encode.rs b/evc/src/bin/encode.rs
new file mode 100644
index 0000000..88023b3
--- /dev/null
+++ b/evc/src/bin/encode.rs
@@ -0,0 +1,20 @@
+use std::io::BufReader;
+
+use clap::Parser;
+use evc::ser::Source;
+
+#[derive(Parser)]
+#[clap(about, version)]
+pub struct EncodeArgs {
+ #[arg(short, long)]
+ width: usize,
+ #[arg(short, long)]
+ height: usize,
+}
+
+fn main() {
+ let mut input = BufReader::new(std::io::stdin());
+
+
+
+}
diff --git a/evc/src/block.rs b/evc/src/block.rs
new file mode 100644
index 0000000..29dd4ba
--- /dev/null
+++ b/evc/src/block.rs
@@ -0,0 +1,69 @@
+use crate::ser::{Ser, Sink, Source};
+
+#[derive(Copy, Clone, Debug)]
+pub struct Pixel {
+ pub r: u8,
+ pub g: u8,
+ pub b: u8,
+}
+
+#[derive(Clone, Debug)]
+pub struct Block {
+ size: (usize, usize),
+ inner: BlockInner,
+}
+
+#[derive(Clone, Debug)]
+pub enum BlockInner {
+ Literal(Vec<Pixel>),
+ Split(Box<[Block; 2]>),
+ Reference { translation: (usize, usize) },
+}
+
+impl Block {
+ pub fn write(&self, sink: &mut impl std::io::Write) -> std::io::Result<()> {
+ match &self.inner {
+ BlockInner::Literal(pixels) => {
+ sink.put(0u8)?;
+ pixels.write(sink)?;
+ }
+ BlockInner::Split(box [a, b]) => {
+ sink.put(1u8)?;
+ a.write(sink)?;
+ b.write(sink)?;
+ }
+ BlockInner::Reference { translation } => {
+ sink.put(2u8)?;
+ }
+ }
+ Ok(())
+ }
+
+ pub fn read(source: &mut impl std::io::Read, size: (usize, usize)) -> std::io::Result<Self> {
+ let inner = match source.get::<u8>()? {
+ 0 => BlockInner::Literal(source.get()?),
+ 1 => BlockInner::Split(Box::new({
+ let subsize = if size.0 > size.1 {
+ (size.0 / 2, size.1)
+ } else {
+ (size.0, size.1 / 2)
+ };
+ [Block::read(source, subsize)?, Block::read(source, subsize)?]
+ })),
+ 2 => todo!(),
+ _ => panic!("file corrupt"),
+ };
+
+ Ok(Self { size, inner })
+ }
+}
+impl Ser for Pixel {
+ fn write(&self, sink: &mut impl std::io::Write) -> std::io::Result<()> {
+ sink.put((self.r, self.g, self.b))
+ }
+
+ fn read(source: &mut impl std::io::Read) -> std::io::Result<Self> {
+ let (r, g, b) = source.get()?;
+ Ok(Self { r, g, b })
+ }
+}
diff --git a/evc/src/header.rs b/evc/src/header.rs
new file mode 100644
index 0000000..2b2725c
--- /dev/null
+++ b/evc/src/header.rs
@@ -0,0 +1,4 @@
+
+pub struct Header {
+
+}
diff --git a/evc/src/lib.rs b/evc/src/lib.rs
new file mode 100644
index 0000000..3270ebb
--- /dev/null
+++ b/evc/src/lib.rs
@@ -0,0 +1,5 @@
+#![feature(box_patterns)]
+
+pub mod ser;
+pub mod block;
+pub mod header;
diff --git a/evc/src/ser.rs b/evc/src/ser.rs
new file mode 100644
index 0000000..05072b2
--- /dev/null
+++ b/evc/src/ser.rs
@@ -0,0 +1,154 @@
+use std::io::{self, Read, Write};
+
+pub trait Sink {
+ fn put<V: Ser>(&mut self, value: V) -> io::Result<()>;
+}
+pub trait Source {
+ fn get<V: Ser>(&mut self) -> io::Result<V>;
+}
+
+impl<T: Write> Sink for T {
+ fn put<V: Ser>(&mut self, value: V) -> io::Result<()> {
+ value.write(self)
+ }
+}
+impl<T: Read> Source for T {
+ fn get<V: Ser>(&mut self) -> io::Result<V> {
+ V::read(self)
+ }
+}
+
+pub trait Ser: Sized {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()>;
+ fn read(source: &mut impl Read) -> io::Result<Self>;
+}
+
+impl<A: Ser, B: Ser> Ser for (A, B) {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ self.0.write(sink)?;
+ self.1.write(sink)?;
+ Ok(())
+ }
+
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ Ok((A::read(source)?, B::read(source)?))
+ }
+}
+impl<A: Ser, B: Ser, C: Ser> Ser for (A, B, C) {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ self.0.write(sink)?;
+ self.1.write(sink)?;
+ self.2.write(sink)?;
+ Ok(())
+ }
+
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ Ok((A::read(source)?, B::read(source)?, C::read(source)?))
+ }
+}
+
+impl<A: Ser, const N: usize> Ser for [A; N] {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ for e in self {
+ e.write(sink)?;
+ }
+ Ok(())
+ }
+
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut k: [A; N] = unsafe { std::mem::zeroed() };
+ for i in 0..N {
+ k[i] = A::read(source)?;
+ }
+ Ok(k)
+ }
+}
+
+impl<T: Ser> Ser for Vec<T> {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ self.len().write(sink)?;
+ for e in self {
+ e.write(sink)?;
+ }
+ Ok(())
+ }
+
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut v = vec![];
+ for _ in 0..usize::read(source)? {
+ v.push(T::read(source)?)
+ }
+ Ok(v)
+ }
+}
+
+impl Ser for u8 {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ sink.write_all(&[*self])
+ }
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut buf = [0u8; 1];
+ source.read_exact(&mut buf)?;
+ Ok(buf[0])
+ }
+}
+impl Ser for u16 {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ sink.write_all(&unsafe { std::mem::transmute_copy::<_, [u8; 2]>(self) })
+ }
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut buf = [0u8; 2];
+ source.read_exact(&mut buf)?;
+ Ok(unsafe { std::mem::transmute_copy(&buf) })
+ }
+}
+impl Ser for u32 {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ sink.write_all(&unsafe { std::mem::transmute_copy::<_, [u8; 4]>(self) })
+ }
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut buf = [0u8; 4];
+ source.read_exact(&mut buf)?;
+ Ok(unsafe { std::mem::transmute_copy(&buf) })
+ }
+}
+impl Ser for u64 {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ sink.write_all(&unsafe { std::mem::transmute_copy::<_, [u8; 8]>(self) })
+ }
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut buf = [0u8; 8];
+ source.read_exact(&mut buf)?;
+ Ok(unsafe { std::mem::transmute_copy(&buf) })
+ }
+}
+impl Ser for usize {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ sink.write_all(&unsafe { std::mem::transmute_copy::<_, [u8; 8]>(self) })
+ }
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut buf = [0u8; 8];
+ source.read_exact(&mut buf)?;
+ Ok(unsafe { std::mem::transmute_copy(&buf) })
+ }
+}
+impl Ser for f32 {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ sink.write_all(&unsafe { std::mem::transmute_copy::<_, [u8; 4]>(self) })
+ }
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut buf = [0u8; 4];
+ source.read_exact(&mut buf)?;
+ Ok(unsafe { std::mem::transmute_copy(&buf) })
+ }
+}
+impl Ser for f64 {
+ fn write(&self, sink: &mut impl Write) -> io::Result<()> {
+ sink.write_all(&unsafe { std::mem::transmute_copy::<_, [u8; 8]>(self) })
+ }
+ fn read(source: &mut impl Read) -> io::Result<Self> {
+ let mut buf = [0u8; 8];
+ source.read_exact(&mut buf)?;
+ Ok(unsafe { std::mem::transmute_copy(&buf) })
+ }
+}