#!/usr/bin/env python3 """Extract decimated frames from a Blu-ray .m2ts into 256x192 PNGs. Source is 1920x1080 (16:9). The arcade original is 4:3, so we CENTER-CROP to 1440x1080 by default -- see docs/STATUS.md open question on framing. """ import subprocess, sys, os, shutil, getpass # Where the Dragon's Lair Blu-ray is mounted. Nothing in this repo ships the # media -- bring your own disc, loop-mount it read-only, and point DLX_BDROM at # the mount if it is not where udisks puts it: # udisksctl loop-setup -r -f DRAGONS_LAIR.iso BDROM = os.environ.get("DLX_BDROM") or f"/media/{getpass.getuser()}/BDROM" STREAM_DIR = f"{BDROM}/BDMV/STREAM" W, H = 256, 192 def duration(path): out = subprocess.check_output(["ffprobe","-v","error","-show_entries", "format=duration","-of","csv=p=0",path], text=True) return float(out.strip()) def extract(stream, outdir, fps=12, mode="crop", start=None, dur=None): src = f"{STREAM_DIR}/{stream}.m2ts" total = duration(src) if start is None: start = 0.0 if dur is None: dur = total - start shutil.rmtree(outdir, ignore_errors=True); os.makedirs(outdir) if mode == "crop": # 4:3 centre crop, arcade framing vf = f"crop=1440:1080:240:0,hqdn3d=4:3:0:0,scale={W}:{H}:flags=lanczos" elif mode == "squash": # full 16:9 squeezed into 4:3 vf = f"hqdn3d=4:3:0:0,scale={W}:{H}:flags=lanczos" elif mode == "wide": # 16:9 preserved, letterboxed later vf = f"hqdn3d=4:3:0:0,scale={W}:144:flags=lanczos" else: raise ValueError(mode) vf = f"fps={fps}," + vf subprocess.check_call(["ffmpeg","-v","error","-ss",str(start),"-t",str(dur), "-i",src,"-vf",vf,"-vsync","0",f"{outdir}/f%04d.png","-y"]) n = len(os.listdir(outdir)) print(f"{stream}: dur={total:.2f}s -> {n} frames @{fps}fps ({mode})") return n if __name__ == "__main__": # extract.py [fps] [mode] [start_s] [dur_s] # start/dur matter for the long streams: 00223 is 9.4 min and the parts # that stress the codec are a few seconds each (tools/analysis/07 finds # them). Without them a survey silently averages action into idle scenes. stream, outdir = sys.argv[1], sys.argv[2] fps = int(sys.argv[3]) if len(sys.argv) > 3 else 12 mode = sys.argv[4] if len(sys.argv) > 4 else "crop" start = float(sys.argv[5]) if len(sys.argv) > 5 else None dur = float(sys.argv[6]) if len(sys.argv) > 6 else None extract(stream, outdir, fps, mode, start, dur)