mirror of
https://github.com/joe-scotto/scottokeebs.git
synced 2026-08-24 10:14:29 -05:00
Add ScottoScripts
This commit is contained in:
@@ -3,3 +3,4 @@ IndentCaseLabels: true
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
ColumnLimit: 120
|
||||
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...
|
||||
@@ -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
|
||||
@@ -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. |
|
||||
Reference in New Issue
Block a user