#!/usr/bin/env python3 """wai.pack.scenecut/1, differentially: wai-pack's streaming segmenter against pack_verify.py's on-demand form. Seeded random clips (flat and noisy shots, cuts, flashes, small perturbations, empty and one-frame clips) under random parameters; every piece (start, length, flags and the statistics classification reads) and every score from `wai-pack segment-json`, pushed a frame at a time or in a batch, must equal pack_verify.py's, and every piece but the last must lie between `min` and `max` frames (the last at most `max`). python3 segment_diff.py [seed] [count] Exit status 0 only if every clip agrees. """ import json import os import random import subprocess import sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) import pack_verify as PV # noqa: E402 def clip(rng): w, h = rng.randint(1, 5), rng.randint(1, 4) scenes = [] for _ in range(rng.randint(1, 5)): if rng.random() < 0.5: scenes.append([rng.randrange(256)] * (w * h * 3)) else: scenes.append([rng.randrange(256) for _ in range(w * h * 3)]) n = rng.randint(0, 40) if rng.random() < 0.9 else rng.randint(0, 3) frames, cur = [], 0 for _ in range(n): if rng.random() < 0.15: cur = rng.randrange(len(scenes)) f = scenes[cur] if rng.random() < 0.1: f = scenes[rng.randrange(len(scenes))] if rng.random() < 0.2: f = [min(255, max(0, x + rng.randint(-6, 6))) for x in f] frames.append(list(f)) mn = rng.randint(1, 6) tg = mn + rng.randint(0, 6) mx = tg + rng.randint(0, 8) p = {"min": mn, "target": tg, "max": mx, "cut_abs": rng.choice([1, 50, 100, 300, 500, 1000]), "cut_rel": rng.choice([0, 1000, 3000, 1000000]), "window": rng.randint(1, 8), "lookahead": rng.randint(0, 7)} return {"w": w, "h": h, "p": p, "frames": frames, "stream": rng.random() < 0.5} def main(argv): if len(argv) < 2: print(__doc__) return 2 binary = argv[1] seed = int(argv[2]) if len(argv) > 2 else 1 count = int(argv[3]) if len(argv) > 3 else 2000 rng = random.Random(seed) cases = [clip(rng) for _ in range(count)] r = subprocess.run([binary, "segment-json"], input=("\n".join(json.dumps(c) for c in cases) + "\n").encode(), capture_output=True) outs = r.stdout.decode().splitlines() if r.returncode != 0 or len(outs) != count: print(r.stderr.decode(errors="replace")[-2000:]) return 1 bad = 0 for c, o in zip(cases, outs): ro = json.loads(o) if not c["frames"]: ok = ro["pieces"] == [] else: pp, ps = PV.segment(c["frames"], c["w"], c["h"], c["p"]) py = [[x["start"], x["len"], x["flags"], x["abs_diff"], x["changed"], x["compared"], x["occupancy"]] for x in pp] ok = py == ro["pieces"] and ps == ro["scores"] pcs = ro["pieces"] for i, x in enumerate(pcs): if x[1] > c["p"]["max"] or (i + 1 < len(pcs) and x[1] < c["p"]["min"]): ok = False if not ok: bad += 1 if bad <= 5: print("DIFF", json.dumps(c["p"]), "frames", len(c["frames"]), "stream", c["stream"]) print(f"segment_diff: seed {seed}, {count} clips, {bad} differences") return 0 if bad == 0 else 1 if __name__ == "__main__": sys.exit(main(sys.argv))