ahp-development-workstation / skill /scripts /video_decode_check.py
cpuai's picture
Install complete Linux VS Code + AHP MCP development workstation 2026-10-12
c12eb19 verified
Raw History Blame Contribute Delete
2.18 kB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""科普视频成片完整技术审查(比 ffprobe 文件头检查更严格)。
完整解码所有帧并检查音频存在。该脚本不判断科学事实是否正确。
"""
from __future__ import annotations
import argparse,json,subprocess,sys
from pathlib import Path
def run(path:Path,expected_width=1080,expected_height=1920,expected_fps=30):
if not path.is_file():raise FileNotFoundError(path)
obj=json.loads(subprocess.check_output(['ffprobe','-v','error','-show_format','-show_streams','-of','json',str(path)],text=True))
video=next((x for x in obj['streams'] if x.get('codec_type')=='video'),None)
audio=next((x for x in obj['streams'] if x.get('codec_type')=='audio'),None)
assert video and audio,'Missing audio or video'
actual_rate=video.get('avg_frame_rate',video.get('r_frame_rate','0/1'))
numerator,denominator=map(float,actual_rate.split('/'))
assert denominator and abs(numerator/denominator-expected_fps)<.12
assert video.get('width')==expected_width and video.get('height')==expected_height
assert video.get('codec_name')=='h264' and audio.get('codec_name')=='aac'
# Prevent writing garbage to stdout or disk: decode both streams into null sink.
proc=subprocess.run(['ffmpeg','-hide_banner','-nostdin','-v','error','-xerror','-i',str(path),'-f','null','-'],capture_output=True,text=True)
if proc.returncode:raise RuntimeError('Full decode failed: '+proc.stderr[-1500:])
return {'file':str(path),'duration':round(float(obj['format']['duration']),3),'fps':actual_rate,'video_codec':video['codec_name'],'audio_codec':audio['codec_name'],'whole_movie_decode_ok':True}
if __name__=='__main__':
p=argparse.ArgumentParser();p.add_argument('video');p.add_argument('--width',type=int,default=1080);p.add_argument('--height',type=int,default=1920);p.add_argument('--fps',type=int,default=30);a=p.parse_args()
try:
report=run(Path(a.video),a.width,a.height,a.fps)
print(json.dumps(report,ensure_ascii=False,indent=2))
except Exception as e:
print(json.dumps({'qa_pass':False,'error':str(e)},ensure_ascii=False));sys.exit(2)