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