mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-11-01 12:14:56 +02:00
docs(badapple): how the clip data is prepared, with the measured costs
The setup section said 'a clip cache' without saying where a clip comes from, what it costs, or how to tell the result is sane. Adds a Data preparation section: the public sources (and why an upscale is not better), the frame extraction (3,292 frames, 489 MB, ~12 s, LSB-first), the cache build (~2 min 47 s, four files, 6.1 MB), and the make_tiles summary to compare against -- including that a saturated 256-entry dictionary and 24 dB PSNR are expected, not a failure.
This commit is contained in:
1 parent
8f831eaf33
commit
d6aa6f46c1
1 file changed
+77
-12
+77
-12
@@ -8,7 +8,7 @@ against MAME's debugger API and is not how anything reaches a machine.
|
||||
|
||||
```
|
||||
harness/badapple/
|
||||
├── README.md this file
|
||||
├── README.md this file (setup, data preparation, run)
|
||||
├── demo.sh one command: wait for the OS, load, send
|
||||
├── rdebug_load.py payload image → terminal RAM over rdebug (TCP 771)
|
||||
├── clip_from_video.py video → raw 1-bpp frames for make_tiles.py
|
||||
@@ -42,28 +42,93 @@ Two facts about it are load-bearing and were measured:
|
||||
|
||||
## Setup
|
||||
|
||||
Two builds and one piece of data preparation. Steps 1 and 2 are C builds; step 3
|
||||
is the part that needs a source video.
|
||||
|
||||
```sh
|
||||
cd /path/to/vt1200
|
||||
|
||||
# 1. MAME + the driver (skip if you already have vt1200 built)
|
||||
# 1. MAME + the driver (skip if vt1200 is already built)
|
||||
harness/mame/build.sh
|
||||
|
||||
# 2. the payload (TI SDK under DOSBox)
|
||||
harness/udpstream/build-stream.sh # -> harness/udpstream/build/vidstream.bin
|
||||
# 2. the payload (TI SDK under DOSBox) -> harness/udpstream/build/vidstream.bin
|
||||
harness/udpstream/build-stream.sh
|
||||
```
|
||||
|
||||
# 3. a clip cache (skip to use the committed 30-frame synthetic clip)
|
||||
Step 3 is described below, because the numbers (time, disk, what "good" looks
|
||||
like) are what make it repeatable.
|
||||
|
||||
## Data preparation: a video to a tile cache
|
||||
|
||||
Nothing ships a full clip: `harness/udpstream/tiles/` in the repo is the
|
||||
**30-frame synthetic clip**, which is enough to smoke-test the transport but shows
|
||||
a moving ellipse, not the animation. A real clip is three commands and about
|
||||
five minutes.
|
||||
|
||||
### 3a. Get a source video
|
||||
|
||||
Any file ffmpeg can read. For Bad Apple the usable public sources are:
|
||||
|
||||
| source | why |
|
||||
|---|---|
|
||||
| `archive.org/details/hd-60-fps-bad-apple-shadow-art-pv-720-x-960-60fps` | 960x720, 60 fps, 219 s, ~35 MB — the one this demo was measured on (the item name is scrambled; the file inside is 960x720) |
|
||||
| `yt-dlp <url>` from YouTube | fine, but the 4K/8K uploads are upscales of the same 2009 render and add no detail |
|
||||
| the original PV's Flash file (`archive.org/details/dagobah_Bad_Apple_HQ`) | the true master, vector — needs a Flash renderer to rasterise, which nothing here does |
|
||||
|
||||
Resolution matters less than it looks: the terminal shows **1 bpp**, and the
|
||||
pipeline scales to 1280 px wide before thresholding, so anything at 960 px or
|
||||
more lands on the same picture.
|
||||
|
||||
### 3b. Frames
|
||||
|
||||
```sh
|
||||
python3 harness/badapple/clip_from_video.py bad-apple.mp4 /tmp/badapple --fps 15
|
||||
```
|
||||
|
||||
* one `*.bin` per frame, 1280x960, 1 bpp, 160-byte rows, **LSB first** — bit 0 of
|
||||
a byte is the row's leftmost pixel, the order both the terminal's scanout and
|
||||
the payload's encoder use. Do not substitute `ffmpeg`'s `format=monob`: it
|
||||
packs MSB first and mirrors every eight pixels on the display.
|
||||
* `--fps 15` on the 219 s source gives **3,292 frames**; `--height 960` fills 30
|
||||
of the 32 tile bands (a 4:3 source at 1280x960, the bottom two rows black), and
|
||||
`--height 1024` fills the screen by stretching 4:3.
|
||||
* measured cost: **~12 s**, **489 MB** on disk (153,600 B per frame).
|
||||
* the source is white paper with black silhouettes, which is already the right
|
||||
polarity. If yours is inverted, add `--invert`; `--threshold` (default 127)
|
||||
decides what counts as ink.
|
||||
|
||||
### 3c. The cache
|
||||
|
||||
```sh
|
||||
python3 harness/udpstream/make_tiles.py --clip /tmp/badapple --out /tmp/badapple-tiles
|
||||
```
|
||||
|
||||
`clip_from_video.py` writes **LSB-first** 1-bpp rows (bit 0 of a byte is the
|
||||
leftmost pixel), which is the order both the terminal's scanout and the
|
||||
payload's encoder use. Do not substitute `ffmpeg`'s `format=monob`: it packs
|
||||
MSB first and mirrors every eight pixels on the display.
|
||||
Takes **~2 min 47 s** (pure-Python Lloyd's algorithm over 3,292 frames) and
|
||||
writes four files, **6.1 MB** total:
|
||||
|
||||
`make_tiles.py` prints what it built — on the real clip (3,292 frames at 15 fps,
|
||||
1280x960) that is 256/256 dictionary entries, 55 keyframes, mean delta 496 B,
|
||||
1.63 MB of stream, PSNR 24.4 dB.
|
||||
| file | size | what it is |
|
||||
|---|---|---|
|
||||
| `dictionary.bin` | 32,768 B | 256 32x32 tiles, the vocabulary every frame is expressed in |
|
||||
| `indices.bin` | 4,213,760 B | one 1,280-byte index frame per clip frame |
|
||||
| `stream.bin` | 1,645,081 B | the plan: 55 keyframes + 3,141 deltas + 96 "nothing changed" |
|
||||
| `manifest.json` | 199 KB | the numbers below, per frame |
|
||||
|
||||
It prints the same summary. What it said for this clip, and what to check:
|
||||
|
||||
```
|
||||
3292 frames, 256 dictionary entries (256 used) <- the dictionary is saturated
|
||||
55 keyframe(s), 3141 delta(s), 96 unchanged
|
||||
payload 1280 B full, 496 B mean delta (5..3602), 1628615 B total
|
||||
reconstruction 15823231 bit(s) over 3292 frame(s), BER 0.003667, PSNR 24.36 dB
|
||||
```
|
||||
|
||||
Saturated entries and a 24 dB PSNR are expected, not errors: one byte per tile is
|
||||
the format's ceiling, and shadow-art edges are expensive. A clip that reports
|
||||
`inf` PSNR has every tile in the dictionary — that happens only for very flat
|
||||
footage.
|
||||
|
||||
Keep the cache outside the repo: it is 6.1 MB of derived data. Pass it to the
|
||||
demo with `--tiles /tmp/badapple-tiles`.
|
||||
|
||||
## Run it in MAME
|
||||
|
||||
|
||||
Reference in new issue
Block a user