Sub-project 2: ingest & tagging / review tools #1

Merged
benstull merged 14 commits from sub-project-2-ingest-tagging-review into main 2026-06-04 14:16:28 +00:00
2 changed files with 96 additions and 0 deletions
Showing only changes of commit d2a97823f5 - Show all commits
+38
View File
@@ -0,0 +1,38 @@
from tools.mediatools import (
compute_dominant_color,
dominant_color_from_rgb,
extract_frame,
)
def test_dominant_color_from_rgb_pure_red():
assert dominant_color_from_rgb(b"\xff\x00\x00") == "#ff0000"
def test_dominant_color_from_rgb_arbitrary():
assert dominant_color_from_rgb(b"\x12\xab\x0f") == "#12ab0f"
def test_compute_dominant_color_uses_runner():
captured = {}
def fake_runner(args):
captured["args"] = args
return b"\x00\x80\xff"
color = compute_dominant_color("clip.mp4", midpoint_s=5.0, runner=fake_runner)
assert color == "#0080ff"
assert "ffmpeg" in captured["args"]
assert "5.0" in captured["args"]
def test_extract_frame_invokes_runner_and_returns_dest(tmp_path):
dest = tmp_path / "frame.png"
calls = []
def fake_runner(args):
calls.append(args)
out = extract_frame("clip.mp4", dest, midpoint_s=2.0, runner=fake_runner)
assert out == dest
assert calls and "ffmpeg" in calls[0] and str(dest) in calls[0]
+58
View File
@@ -0,0 +1,58 @@
"""ffmpeg helpers: representative frame; OPTIONAL dominant color. Runner injectable."""
from __future__ import annotations
import subprocess
def _run_bytes(args) -> bytes:
return subprocess.run(args, capture_output=True, check=True).stdout
def dominant_color_from_rgb(rgb: bytes) -> str:
r, g, b = rgb[0], rgb[1], rgb[2]
return f"#{r:02x}{g:02x}{b:02x}"
def compute_dominant_color(path, *, midpoint_s=0.0, runner=_run_bytes) -> str:
"""ffmpeg-only single-color palette of a mid-segment frame -> #rrggbb."""
args = [
"ffmpeg",
"-v",
"quiet",
"-ss",
str(midpoint_s),
"-i",
str(path),
"-vf",
"thumbnail,palettegen=max_colors=1",
"-frames:v",
"1",
"-f",
"rawvideo",
"-pix_fmt",
"rgb24",
"-",
]
return dominant_color_from_rgb(runner(args))
def extract_frame(path, dest, *, midpoint_s=0.0, runner=None):
"""Write one representative frame to dest (PNG) for the review preview."""
runner = runner or (lambda a: subprocess.run(a, check=True))
runner(
[
"ffmpeg",
"-v",
"quiet",
"-y",
"-ss",
str(midpoint_s),
"-i",
str(path),
"-frames:v",
"1",
str(dest),
]
)
return dest