"""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