Add ScottoScripts

This commit is contained in:
Joe Scotto
2026-01-15 15:52:37 -05:00
parent 9f086dc3a1
commit ed1f708583
6 changed files with 182 additions and 0 deletions
+1
View File
@@ -3,3 +3,4 @@ IndentCaseLabels: true
AllowShortEnumsOnASingleLine: false AllowShortEnumsOnASingleLine: false
ColumnLimit: 120 ColumnLimit: 120
BinPackArguments: false BinPackArguments: false
SortIncludes: false
@@ -0,0 +1,45 @@
import re
# Read your exported hex file
with open("frames.txt", "r") as f:
data = f.read()
frames = []
current_frame = []
for line in data.splitlines():
# Skip empty lines
if not line.strip():
continue
# If line is a frame comment, start a new frame
if line.strip().startswith("// 'out_"):
if current_frame:
frames.append(current_frame)
current_frame = []
continue
# Extract all hex numbers in the line
hex_values = re.findall(r"0x[0-9a-fA-F]+", line)
current_frame.extend(hex_values)
# Append last frame
if current_frame:
frames.append(current_frame)
# Write formatted array to frames.c and overwrite on subsequent runs
with open("frames.c", "w") as f:
f.write(
"const uint8_t PROGMEM frames[{}][{}] = {{\n".format(
len(frames), len(frames[0])
)
)
for f_idx, frame in enumerate(frames):
f.write(" {")
f.write(", ".join(frame))
f.write("}}, // frame {}\n".format(f_idx + 1))
f.write("};\n")
print("Export complete: frames.c with {} frames.".format(len(frames)))
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
import argparse
import os
import subprocess
# Arguments
parser = argparse.ArgumentParser(description="Extract frames from video for QMK OLED")
parser.add_argument("input", help="Path to input video file")
parser.add_argument(
"--fps", type=float, default=15, help="Frames per second (default: 15)"
)
parser.add_argument(
"--width", type=int, default=128, help="Output frame width (default: 128)"
)
parser.add_argument(
"--height", type=int, default=64, help="Output frame height (default: 64)"
)
parser.add_argument(
"--frames",
type=int,
default=120,
help="Number of frames to extract (default: 120)",
)
parser.add_argument(
"--format",
default="gray",
choices=["gray", "rgb24", "monow"],
help="Output pixel format (default: gray)",
)
parser.add_argument(
"--speed",
type=float,
default=1.0,
help="Playback speed, maps to setpts (default: 1.0)",
)
args = parser.parse_args()
# Create output directory
os.makedirs("frames", exist_ok=True)
# Create ffmpeg command
output_pattern = os.path.join(args.output, "out_%03d.png")
# setpts expression: PTS = 1/speed * PTS
setpts_expr = f"setpts={1/args.speed}*PTS"
ffmpeg_cmd = [
"ffmpeg",
"-i",
args.input,
"-filter:v",
f"{setpts_expr},fps={args.fps},scale={args.width}:{args.height},format={args.format}",
"-frames:v",
str(args.frames),
output_pattern,
]
# Print command for debugging
print("Running command:\n", " ".join(ffmpeg_cmd))
# Run command
subprocess.run(ffmpeg_cmd, check=True)
print(f"Frames exported to {args.output}")
@@ -0,0 +1 @@
Paste your output from Image2CPP here...
+37
View File
@@ -0,0 +1,37 @@
#include "frames.c"
#include "quantum.h"
#ifdef OLED_ENABLE
oled_rotation_t oled_init_user(oled_rotation_t rotation) {
return OLED_ROTATION_180; // flips the display 180 degrees if offhand
}
#define NUM_FRAMES 120
#define FRAME_WIDTH 128
#define FRAME_HEIGHT 64
#define FRAME_SIZE \
(FRAME_WIDTH * FRAME_HEIGHT / 8) // 128*64 / 8 = 1024 bytes per frame
#define FRAME_DELAY 100 // ms per frame, ~10 fps
bool oled_task_user(void) {
static uint16_t frame_index = 0;
static uint32_t last_update = 0;
// Only update frame every FRAME_DELAY ms
if (timer_elapsed32(last_update) > FRAME_DELAY) {
last_update = timer_read32();
// Write current frame to OLED (cast to const char* to fix signedness)
oled_write_raw_P((const char *)frames[frame_index], FRAME_SIZE);
// Advance to next frame, loop back to 0
frame_index++;
if (frame_index >= NUM_FRAMES)
frame_index = 0;
}
return false; // keep other OLED content disabled
}
#endif
+32
View File
@@ -0,0 +1,32 @@
# OLED Video
Used to convert a video for display on a QMK OLED.
This should work on pretty much any QMK keyboard but I highly recommend using a controller with a decent amount of flash memory such as an RP2040.
# Instructions
1. Generate your frames using [`extract_frames.py`](#extract_frames.py)
- They will output to the `frames` directory.
2. Upload those to [Image2CPP](https://javl.github.io/image2cpp/)
1. Choose your dithering mode if you want to play with the look.
2. Output should be set to `Draw mode: Vertical - 1 bit per pixel`
3. Click `Generate code` and copy the output to `frames.txt`.
3. Generate your `frames.c` using [create_frames_array.py](create_frames_array.py).
1. Copy `frames.c` and `oled.c` to your QMK keymap.
2. Import `oled.c` into your `keymap.c`.
3. Compile and flash.
4. You should now see a video playing on your OLED!
# extract_frames.py
This is the script used to generate the video frames you will use to convert.
| Argument | Type | Default | Description |
| ---------- | ------- | ---------- | ------------------------------------------------- |
| `input` | `str` | _required_ | Path to the input video file. |
| `--fps` | `float` | `15` | Playback frames per second. |
| `--width` | `int` | `128` | Width of the output frames in pixels. |
| `--height` | `int` | `64` | Height of the output frames in pixels. |
| `--frames` | `int` | `120` | Number of frames to extract from the video. |
| `--format` | `str` | `gray` | Output pixel format: `gray`, `rgb24`, or `monow`. |
| `--speed` | `float` | `1.0` | Playback speed of the video. |