master
John Lauer Preserve BQ independent routing, narration and native copper-retention evidence a4b7711 1mo ago
"""Find actual PCB-canvas action intervals in native WGC recordings."""
import json,subprocess,sys
from pathlib import Path
import numpy as np
ROOT=Path(__file__).resolve().parent
for name in sys.argv[1:]:
 p=ROOT/name;video=next(p.glob('window-8916576-*.mp4'));info=json.loads(subprocess.check_output(['ffprobe','-v','error','-show_streams','-of','json',str(video)]))['streams'][0]
 width,height=info['width'],info['height'];fps=10;w,h=985,575
 proc=subprocess.Popen(['ffmpeg','-v','error','-i',str(video),'-vf',f'crop=1970:1150:0:280,scale={w}:{h},fps={fps}','-f','rawvideo','-pix_fmt','rgb24','pipe:1'],stdout=subprocess.PIPE)
 size=w*h*3;previous=None;metrics=[];i=0
 while True:
  data=proc.stdout.read(size)
  if len(data)!=size:break
  frame=np.frombuffer(data,dtype=np.uint8).reshape(h,w,3).astype(np.int16)
  count=0 if previous is None else int(np.count_nonzero(np.max(np.abs(frame-previous),axis=2)>16))
  metrics.append([round(i/fps,3),count]);previous=frame;i+=1
 assert proc.wait()==0
 motion=[t for t,c in metrics if c>=12];intervals=[];duration=float(info['duration'])
 for t in motion:
  a=max(0,t-.18);b=min(duration,t+.45)
  if intervals and a<=intervals[-1][1]+.25:intervals[-1][1]=max(intervals[-1][1],b)
  else:intervals.append([a,b])
 out={'source':str(video),'fpsAnalyzed':fps,'canvasCrop':[0,280,1970,1150],'threshold':{'channelDifference':16,'pixels':12},'duration':duration,'intervals':intervals,'retainedSeconds':sum(b-a for a,b in intervals),'metrics':metrics}
 (p/'motion.json').write_text(json.dumps(out,indent=2));print(name,'source',duration,'retained',out['retainedSeconds'],'intervals',len(intervals),flush=True)