Restore a bad_apple frame packing script that actually matches the RLE format in the assembly code

pull/11/head
Luke Wren 2021-03-04 20:56:26 +00:00
rodzic 6585015fa5
commit cb7f9bcb27
4 zmienionych plików z 30 dodań i 79 usunięć

Wyświetl plik

@ -15,7 +15,7 @@
#include "test_frame.h"
#define MOVIE_BASE (XIP_BASE + 0x10000)
#define MOVIE_FRAMES 1799
#define MOVIE_FRAMES 209
// DVDD 1.25V (slower silicon may need the full 1.3, or just not work)
#define FRAME_WIDTH 1280
@ -54,8 +54,8 @@ int main() {
dvi_start(&dvi0);
int frame = 0;
const uint8_t *line = (const uint8_t*)MOVIE_BASE;
while (true) {
const uint8_t *line = frame_bin;
uint32_t *render_target;
for (int y = 0; y < FRAME_HEIGHT; ++y) {
uint8_t line_len = *line++;

Wyświetl plik

@ -5,7 +5,7 @@ rm -rf raw rle pack.bin pack.uf2
mkdir raw
ffmpeg \
-ss 00:00:25 -to 00:01:25 \
-ss 00:00:05.5 -to 00:00:12.5 \
-i src.mkv \
-f lavfi -i color=gray:s=1920x1080 \
-f lavfi -i color=black:s=1920x1080 \
@ -13,6 +13,9 @@ ffmpeg \
-filter_complex "threshold,fps=30,crop=1440:1080:240:0,scale=960x720" \
raw/frame%04d.png
./rle_compress.py raw pack.bin
mkdir rle
make -f packframes.mk -j$(nproc)
uf2conv -f rp2040 -b 0x10010000 pack.bin -o pack.uf2
cat $(find rle -name "*.bin" | sort) > pack.bin
uf2conv -f rp2040 -b 0x10010000 pack.bin -o pack.uf2

Wyświetl plik

@ -5,4 +5,4 @@ RAW=$(sort $(wildcard raw/*))
all: $(patsubst raw/%.png,rle/%.bin,$(RAW))
rle/%.bin: raw/%.png
./rle_compress.py $< $@
./rle_compress.py $< $@

Wyświetl plik

@ -1,11 +1,5 @@
#!/usr/bin/env python3
import sys
from PIL import Image
import functools
import os
import struct
# We avoid TMDS encode on the M0+ by holding the following sequences as
# prebalanced symbol pairs:
#
@ -25,93 +19,47 @@ import struct
# on the M0+ and, because everything stays byte-aligned, it's amenable to
# further compression.
import sys
from PIL import Image
def fmt_byte(a, b, n):
assert(n >= 1 and n <= 64)
return a << 7 | b << 6 | (n - 1 & 0x3f)
@functools.lru_cache
# row is iterable of (bool, bool)
def pack_row(row):
current = (False, False)
current_len = 0
pack = []
for x in range(0, len(row), 2):
pix = row[x:x+2]
while True:
try:
pix = next(row)
except StopIteration:
if current_len > 0:
yield fmt_byte(*current, current_len)
break
if pix == current or current_len == 0:
current = pix
current_len += 1
if pix != current:
pack.append(fmt_byte(*current, current_len))
yield fmt_byte(*current, current_len)
current = pix
current_len = 1
if current_len >= 64:
pack.append(fmt_byte(*current, current_len))
yield fmt_byte(*current, current_len)
current_len = 0
# Flush run at end of scanline
if current_len > 0:
pack.append(fmt_byte(*current, current_len))
return bytes(pack)
class RowHistory:
def __init__(self, log_size):
self.size = 1 << log_size
# Ring buffer of last n rows we saw
self.history = [None] * self.size
self.ptr = 0
self.row_occurrences = {}
def update(self, newrow):
# First update lookups for the row we are about to evict. Note we evict rows
# one slot in *advance* (reducing effective dict size by 1) to avoid
# returning references to the slot that the new row is written to.
oldrow = self.history[(self.ptr + 1) % self.size]
if oldrow is not None:
count, lastseen = self.row_occurrences[oldrow]
if count == 1:
self.row_occurrences.pop(oldrow)
else:
self.row_occurrences[oldrow] = (count - 1, lastseen)
self.history[self.ptr] = newrow
# Then update reference count and last-seen position for the new occupant
if newrow in self.row_occurrences:
self.row_occurrences[newrow] = (self.row_occurrences[newrow][0] + 1, self.ptr)
else:
self.row_occurrences[newrow] = (1, self.ptr)
self.ptr = (self.ptr + 1) % self.size
def last_seen(self, row):
if row in self.row_occurrences:
return self.row_occurrences[row][1]
else:
return None
def pack_image(history, img):
def pack_image(img):
assert(img.width % 2 == 0)
assert(img.mode == "RGB")
bimg = img.tobytes()
w = img.width
for y in range(img.height):
raw_row = tuple(bimg[3 * (x + w * y)] >= 0x80 for x in range(w))
last_seen = history.last_seen(raw_row)
history.update(raw_row)
# Uncomment for row dictionary format:
# if last_seen is None:
# packed = pack_row(raw_row)
# yield struct.pack("<H", len(packed))
# yield packed
# else:
# yield struct.pack("<H", 0x8000 | last_seen)
packed = pack_row(raw_row)
yield bytes((len(packed),))
yield packed
row = bytes(pack_row(
(bimg[3 * (x + w * y)] >= 0x80, bimg[3 * (x + 1 + w * y)] >= 0x80)
for x in range(0, img.width, 2)))
yield bytes((len(row),))
yield row
if __name__ == "__main__":
filelist = sorted(os.listdir(sys.argv[1]))
assert(all(x.lower().endswith(".png") for x in filelist))
ofile = open(sys.argv[2], "wb")
history = RowHistory(log_size=15)
for fname in filelist:
print(fname)
img = Image.open(os.path.join(sys.argv[1], fname))
ofile.write(b"".join(pack_image(history, img)))
img = Image.open(sys.argv[1])
open(sys.argv[2], "wb").write(b"".join(pack_image(img)))