kopia lustrzana https://github.com/Wren6991/PicoDVI
Restore a bad_apple frame packing script that actually matches the RLE format in the assembly code
rodzic
6585015fa5
commit
cb7f9bcb27
|
@ -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++;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 $< $@
|
||||
|
|
|
@ -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)))
|
||||
|
|
Ładowanie…
Reference in New Issue