Skip to content

Instantly share code, notes, and snippets.

@shimamura-sakura
Created January 1, 2023 06:19
Show Gist options
  • Save shimamura-sakura/74adc2ad6cbf38905d8a308cbe83e06f to your computer and use it in GitHub Desktop.
Save shimamura-sakura/74adc2ad6cbf38905d8a308cbe83e06f to your computer and use it in GitHub Desktop.
  1. zig build-exe main.zig
  2. The video must be in resolution 1920 x 1080.
  3. ./run.sh video-file
  4. get file "file-out" at current directory
const std = @import("std");
pub fn Canvas(comptime T: type) type {
return struct {
const Self = @This();
pix: []T,
line: usize,
width: usize,
height: usize,
pub fn getAreaUnsafe(self: Self, l: usize, u: usize, r: usize, d: usize) Self {
const beg = u * self.line + l;
return .{
.pix = self.pix[beg..self.pix.len],
.line = self.line,
.width = r - l,
.height = d - u,
};
}
pub fn getAreaStrict(self: Self, l: usize, u: usize, r: usize, d: usize) !Self {
if (l > r or u > d or r > self.width or d > self.height) return error.OutOfRange;
return self.getAreaUnsafe(l, u, r, d);
}
pub fn getAreaClamped(self: Self, l: usize, u: usize, r: usize, d: usize) !Self {
if (l > r or u > d or l >= self.width or u >= self.height) return error.OutOfRange;
return self.getAreaUnsafe(l, u, @min(r, self.width), @min(d, self.height));
}
pub fn getLineUnsafe(self: Self, y: usize, l: usize, r: usize) []T {
const off = y * self.line;
return self.pix[off + l .. off + r];
}
pub fn getLineStrict(self: Self, y: usize, l: usize, r: usize) ![]T {
if (l > r or r > self.width or y >= self.height) return error.OutOfRange;
return self.getLineUnsafe(y, l, r);
}
pub fn getLineClamped(self: Self, y: usize, l: usize, r: usize) ![]T {
if (l > r or l >= self.width or y >= self.height) return error.OutOfRange;
return self.getLineUnsafe(y, l, @min(r, self.width));
}
pub fn copyFromUnsafe(cpTo: Self, cpFr: Self) void {
var y: usize = 0;
const w = @min(cpTo.width, cpFr.width);
const h = @min(cpTo.height, cpFr.height);
while (y < h) : (y += 1)
std.mem.copy(T, cpTo.getLineUnsafe(y, 0, w), cpFr.getLineUnsafe(y, 0, w));
}
pub fn fill(self: Self, pixel: T) void {
var y: usize = 0;
while (y < self.height) : (y += 1)
std.mem.set(T, self.getLineUnsafe(y, 0, self.width), pixel);
}
};
}
pub fn MyRange(comptime T: type) type {
return struct {
const Self = @This();
count: usize,
value: T,
delta: T,
addDt: bool,
pub fn next(self: *Self) ?T {
if (self.count == 0) return null;
self.count -= 1;
const v = self.value;
if (self.count == 0) return v;
if (self.addDt) self.value += self.delta else self.value -= self.delta;
return v;
}
};
}
pub fn range(comptime T: type, beg: T, end: T) MyRange(T) {
return .{
.count = if (end > beg) end - beg + 1 else beg - end + 1,
.value = beg,
.delta = 1,
.addDt = end > beg,
};
}
const std = @import("std");
const lib = @import("./lib.zig");
const mem = std.mem;
const hep: mem.Allocator = std.heap.page_allocator;
const RGBPixel = [3]u8;
const RGBCanvas = lib.Canvas(RGBPixel);
fn cvsToByte(cvs: RGBCanvas) u8 {
var r: usize = 0;
var g: usize = 0;
var b: usize = 0;
var n: usize = 0;
var y: usize = 0;
while (y < cvs.height) : (y += 1)
for (cvs.getLineUnsafe(y, 0, cvs.width)) |px| {
r += px[0];
g += px[1];
b += px[2];
n += 1;
};
r /= n;
g /= n;
b /= n;
// std.debug.print("{b:0<8} {b:0<8} {b:0<8}\n", .{ r, g, b });
return @intCast(u8, 0 |
(((r + 0b000_011_11) >> 0) & 0b111_000_00) |
(((g + 0b000_011_11) >> 3) & 0b000_111_00) |
(((b + 0b000_111_11) >> 6) & 0b000_000_11));
}
pub fn main() !void {
const inW = 1920;
const inH = 1080;
const inDat = try hep.alloc(RGBPixel, inW * inH);
const inByt = std.mem.sliceAsBytes(inDat);
defer hep.free(inDat);
const cvIn = RGBCanvas{
.pix = inDat,
.line = inW,
.width = inW,
.height = inH,
};
const stdin = std.io.getStdIn().reader();
const file_len = while ((try stdin.readAll(inByt)) == inByt.len) {
var magic: [5]u8 = undefined;
for (magic) |*b, i|
b.* = cvsToByte(cvIn.getAreaUnsafe(i * 16 + 8, 0 + 8, i * 16 + 16, 16));
if (std.mem.eql(u8, &magic, "HELLO") == false) continue;
var buffer: [8]u8 = undefined;
for (buffer) |*b, i|
b.* = cvsToByte(cvIn.getAreaUnsafe(i * 16, 16, i * 16 + 16, 32));
break std.mem.readIntLittle(u64, &buffer);
} else return error.MagicNotFound;
std.debug.print("[HELLO: file length = {}]\n", .{file_len});
const file_dat = try hep.alloc(u8, @intCast(usize, file_len));
defer hep.free(file_dat);
while ((try stdin.readAll(inByt)) == inByt.len) {
var magic: [5]u8 = undefined;
for (magic) |*b, i|
b.* = cvsToByte(cvIn.getAreaUnsafe(i * 16 + 8, 0 + 8, i * 16 + 16, 16));
if (std.mem.eql(u8, &magic, "ABCDE")) break;
if (std.mem.eql(u8, &magic, "WORLD") == false) continue;
var buffer: [16]u8 = undefined;
for (buffer) |*b, i|
b.* = cvsToByte(cvIn.getAreaUnsafe(i * 16, 16, i * 16 + 16, 32));
const offset = @intCast(usize, std.mem.readIntLittle(u64, buffer[0..8]));
const length = @intCast(usize, std.mem.readIntLittle(u64, buffer[8..16]));
std.debug.print("[WORLD: offset = {}, length = {}]\n", .{ offset, length });
for (file_dat[offset .. offset + length]) |*b, i| {
const y = (i >> 6) << 4;
const x = (i & 0b011_1111) << 4;
b.* = cvsToByte(cvIn.getAreaUnsafe(x, y + 32, x + 16, y + 48));
}
} else return error.NoData;
while ((try stdin.readAll(inByt)) == inByt.len) {}
try std.fs.cwd().writeFile("file_out", file_dat);
}
#!/bin/sh
set -ue
ffmpeg -i "$1" -f rawvideo -pix_fmt rgb24 -y - | ./main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment