# 本文公开核验脚本：仅验证随附原创文件及声明的有限条件。
import json, csv, hashlib, re, struct, subprocess, sys, zlib
from fractions import Fraction
from pathlib import Path
P = Path(__file__).resolve().parent
def read(name): return json.loads((P/name).read_text(encoding='utf-8-sig'))
def digest(name): return hashlib.sha256((P/name).read_bytes()).hexdigest()
def probe(name, *args):
    command = ['ffprobe','-v','error',*args,'-of','json',str(P/name)]
    run = subprocess.run(command,capture_output=True,text=True,encoding='utf-8',timeout=25)
    assert run.returncode == 0, run.stderr
    return json.loads(run.stdout)
def decode(name):
    command=['ffmpeg','-v','error','-xerror','-i',str(P/name),'-map','0:v?','-map','0:a?','-f','null','-']
    run=subprocess.run(command,capture_output=True,text=True,encoding='utf-8',timeout=25)
    assert run.returncode == 0, run.stderr
    assert not run.stderr.strip(), run.stderr
    return {'file':name,'exit_code':run.returncode,'stderr':run.stderr}
def packets(name, select='v:0'):
    return probe(name,'-select_streams',select,'-show_packets')['packets']
def streams(name): return probe(name,'-show_streams','-show_format')
def stamp(v,base): return Fraction(int(v))*Fraction(base)
def framehash(name):
    run=subprocess.run(['ffmpeg','-v','error','-i',str(P/name),'-map','0:V:0','-f','framemd5','-'],capture_output=True,text=True,encoding='utf-8',timeout=25)
    assert run.returncode==0,run.stderr
    return [x.split(',')[-1].strip() for x in run.stdout.splitlines() if x and not x.startswith('#')]
def emit(value): print(json.dumps(value,ensure_ascii=False,indent=2))

def boxes(name):
    data=(P/name).read_bytes(); offset=0;out=[]
    while offset<len(data):
        assert offset+8<=len(data)
        size,tag=struct.unpack_from('>I4s',data,offset);header=8
        if size==1:size=struct.unpack_from('>Q',data,offset+8)[0];header=16
        if size==0:size=len(data)-offset
        assert size>=header and offset+size<=len(data)
        out.append({'type':tag.decode('ascii'),'offset':offset,'size':size});offset+=size
    assert offset==len(data)
    return out

result={}
for f in ['normal.mp4','faststart.mp4']:
 b=boxes(f);result[f]={'boxes':b,'decode':decode(f)}
def pos(f,t):return next(b['offset'] for b in result[f]['boxes'] if b['type']==t)
assert pos('normal.mp4','moov')>pos('normal.mp4','mdat');assert pos('faststart.mp4','moov')<pos('faststart.mp4','mdat');assert framehash('normal.mp4')==framehash('faststart.mp4')
emit(result)

