"""Make a silent portrait base from one shot, preserving the full source frame.
Explicit retiming only: no looping, generated frames or content-aware crop.
"""
import argparse, json, subprocess
from pathlib import Path
def duration(p):
    return float(json.loads(subprocess.check_output(['ffprobe','-v','error','-show_format','-of','json',p],text=True))['format']['duration'])
def main():
    p=argparse.ArgumentParser(description=__doc__)
    p.add_argument('--video',required=True);p.add_argument('--audio',required=True);p.add_argument('--out',required=True)
    a=p.parse_args()
    if Path(a.out).exists():p.error('Output exists; choose a new revision filename')
    vd,ad=duration(a.video),duration(a.audio);speed=vd/ad
    if not .5<=speed<=4:p.error('Required speed is outside 0.5–4x. Select/trim different footage or assemble several shots first.')
    vf=f'setpts={ad/vd:.8f}*(PTS-STARTPTS),scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=white,setsar=1'
    subprocess.run(['ffmpeg','-v','error','-i',a.video,'-an','-vf',vf,'-r','30','-t',str(ad),'-c:v','libx264','-crf','18','-pix_fmt','yuv420p','-movflags','+faststart',a.out],check=True)
    print(f'Silent base prepared at {speed:.3f}x source speed. Full frame preserved on white padding. Review movement before using it.')
if __name__=='__main__':main()
