aboutsummaryrefslogtreecommitdiff
path: root/tweak
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-11-15 13:31:47 +0100
committermetamuffin <metamuffin@disroot.org>2023-11-15 13:31:47 +0100
commit7904f28f4ce37f2bc6758a86bf790369c730670c (patch)
treef35666ca280640da948413522e0dff6a570c4b0b /tweak
parenta1bb99554ff5ebe6e0b7e1216f8f8e2d9addd7cf (diff)
downloadvideo-codec-experiments-7904f28f4ce37f2bc6758a86bf790369c730670c.tar
video-codec-experiments-7904f28f4ce37f2bc6758a86bf790369c730670c.tar.bz2
video-codec-experiments-7904f28f4ce37f2bc6758a86bf790369c730670c.tar.zst
a
Diffstat (limited to 'tweak')
-rw-r--r--tweak/.gitignore1
-rw-r--r--tweak/Cargo.lock7
-rw-r--r--tweak/Cargo.toml8
-rw-r--r--tweak/src/main.rs138
-rwxr-xr-xtweak/test4
5 files changed, 158 insertions, 0 deletions
diff --git a/tweak/.gitignore b/tweak/.gitignore
new file mode 100644
index 0000000..c41cc9e
--- /dev/null
+++ b/tweak/.gitignore
@@ -0,0 +1 @@
+/target \ No newline at end of file
diff --git a/tweak/Cargo.lock b/tweak/Cargo.lock
new file mode 100644
index 0000000..7f45493
--- /dev/null
+++ b/tweak/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "tweak"
+version = "0.1.0"
diff --git a/tweak/Cargo.toml b/tweak/Cargo.toml
new file mode 100644
index 0000000..813497e
--- /dev/null
+++ b/tweak/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "tweak"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/tweak/src/main.rs b/tweak/src/main.rs
new file mode 100644
index 0000000..a46d561
--- /dev/null
+++ b/tweak/src/main.rs
@@ -0,0 +1,138 @@
+use std::{
+ io::{stdin, stdout, Read, Write},
+ ops::Index,
+};
+
+const WIDTH: usize = 1920;
+const HEIGHT: usize = 1080;
+
+fn main() {
+ let mut oframe = Frame::new();
+ loop {
+ let iframe = Frame::read(stdin());
+
+ // let diff = oframe.average_area_diff(&iframe, Area::root());
+ // eprintln!("{diff:?}");
+
+ oframe.apply_area_diff(Area::root(), diff);
+
+ oframe.write(stdout());
+ // oframe = iframe;
+ }
+}
+
+pub fn decode(f: &mut Frame, area: Area, tree: DiffTree) {
+ oframe.apply_area_diff(Area::root(), diff);
+
+}
+
+pub enum DiffTree {
+ Split([Box<DiffTree>; 2]),
+ Diff(PixelDiff),
+}
+
+pub fn stuff(a: &Frame, b: &Frame, area: Area) -> DiffTree {
+ if area.area() == 1 {
+ DiffTree::Diff(Frame::diff_pixel(a, b, area.x1, area.y1))
+ } else {
+ let (aa, ba) = area.split();
+ let (at, bt) = (stuff(a, b, aa), stuff(a, b, ba));
+ DiffTree::Split([Box::new(at), Box::new(bt)])
+ }
+}
+
+#[derive(Debug)]
+pub struct Frame(Vec<u8>);
+#[derive(Debug)]
+pub struct PixelDiff([i8; 3]);
+#[derive(Debug, Clone, Copy)]
+pub struct Area {
+ x1: usize,
+ y1: usize,
+ x2: usize,
+ y2: usize,
+}
+
+impl Frame {
+ pub fn new() -> Self {
+ Self(vec![0u8; WIDTH * HEIGHT * 3])
+ }
+ pub fn read(mut r: impl Read) -> Self {
+ let mut f = Frame::new();
+ r.read_exact(&mut f.0).unwrap();
+ f
+ }
+ pub fn write(&self, mut w: impl Write) {
+ w.write_all(&self.0).unwrap()
+ }
+
+ pub fn diff_pixel(a: &Frame, b: &Frame, x: usize, y: usize) -> PixelDiff {
+ let o = (x + y * WIDTH) * 3;
+ PixelDiff([
+ (a.0[o + 0] as i16 - b.0[o + 0] as i16).clamp(i8::MIN as i16, i8::MAX as i16) as i8,
+ (a.0[o + 1] as i16 - b.0[o + 1] as i16).clamp(i8::MIN as i16, i8::MAX as i16) as i8,
+ (a.0[o + 2] as i16 - b.0[o + 2] as i16).clamp(i8::MIN as i16, i8::MAX as i16) as i8,
+ ])
+ }
+
+ pub fn apply_area_diff(&mut self, Area { x1, y1, x2, y2 }: Area, p: PixelDiff) {
+ for x in x1..x2 {
+ for y in y1..y2 {
+ let o = (x + y * WIDTH) * 3;
+ self.0[o + 0] = self.0[o + 0].saturating_add_signed(p.0[0]);
+ self.0[o + 1] = self.0[o + 1].saturating_add_signed(p.0[1]);
+ self.0[o + 2] = self.0[o + 2].saturating_add_signed(p.0[2]);
+ }
+ }
+ }
+ pub fn average_area_diff(
+ &self,
+ other: &Frame,
+ area @ Area { x1, y1, x2, y2 }: Area,
+ ) -> PixelDiff {
+ let (mut r, mut g, mut b) = (0i32, 0i32, 0i32);
+ for x in x1..x2 {
+ for y in y1..y2 {
+ let o = (x + y * WIDTH) * 3;
+ r += other.0[o + 0] as i32 - self.0[o + 0] as i32;
+ g += other.0[o + 1] as i32 - self.0[o + 1] as i32;
+ b += other.0[o + 2] as i32 - self.0[o + 2] as i32;
+ }
+ }
+ let a = area.area() as i32;
+ PixelDiff([
+ (r / a).clamp(i8::MIN as i32, i8::MAX as i32) as i8,
+ (g / a).clamp(i8::MIN as i32, i8::MAX as i32) as i8,
+ (b / a).clamp(i8::MIN as i32, i8::MAX as i32) as i8,
+ ])
+ }
+}
+impl Area {
+ pub fn area(&self) -> usize {
+ self.width() as usize * self.height() as usize
+ }
+ pub fn width(&self) -> usize {
+ self.x2 - self.x1
+ }
+ pub fn height(&self) -> usize {
+ self.y2 - self.y1
+ }
+ pub fn root() -> Self {
+ Area {
+ x1: 0,
+ y1: 0,
+ x2: WIDTH,
+ y2: HEIGHT,
+ }
+ }
+ pub fn split(&self) -> (Self, Self) {
+ let Area { x1, y1, x2, y2 } = *self;
+ if self.width() > self.height() {
+ let xm = (self.x1 + self.x2) / 2;
+ (Self { x1, x2: xm, y1, y2 }, Self { x1: xm, x2, y1, y2 })
+ } else {
+ let ym = (self.y1 + self.y2) / 2;
+ (Self { x1, x2, y1, y2: ym }, Self { x1, x2, y1: ym, y2 })
+ }
+ }
+}
diff --git a/tweak/test b/tweak/test
new file mode 100755
index 0000000..4bfc7d8
--- /dev/null
+++ b/tweak/test
@@ -0,0 +1,4 @@
+#!/bin/fish
+ffmpeg -loglevel quiet -i $argv[1] -vf 'scale=1920x1080,format=rgb24' -f rawvideo pipe:1 \
+ | cargo run --release \
+ | ffplay -loglevel quiet -video_size 1920x1080 -pixel_format rgb24 -f rawvideo pipe:0