155 lines
5.0 KiB
Python
155 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Video Validation Tool
|
|
视频验证工具
|
|
|
|
验证切分后的视频文件是否有效
|
|
"""
|
|
|
|
import sys
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
def validate_video_file(video_path: Path) -> dict:
|
|
"""验证单个视频文件"""
|
|
try:
|
|
# 使用ffprobe获取视频信息
|
|
cmd = [
|
|
'ffprobe',
|
|
'-v', 'quiet',
|
|
'-print_format', 'json',
|
|
'-show_format',
|
|
'-show_streams',
|
|
str(video_path)
|
|
]
|
|
|
|
result = subprocess.run(
|
|
cmd,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
import json
|
|
data = json.loads(result.stdout)
|
|
|
|
# 提取基本信息
|
|
format_info = data.get('format', {})
|
|
streams = data.get('streams', [])
|
|
|
|
video_stream = None
|
|
audio_stream = None
|
|
|
|
for stream in streams:
|
|
if stream.get('codec_type') == 'video':
|
|
video_stream = stream
|
|
elif stream.get('codec_type') == 'audio':
|
|
audio_stream = stream
|
|
|
|
return {
|
|
'valid': True,
|
|
'file_size': int(format_info.get('size', 0)),
|
|
'duration': float(format_info.get('duration', 0)),
|
|
'bitrate': int(format_info.get('bit_rate', 0)),
|
|
'video_codec': video_stream.get('codec_name') if video_stream else None,
|
|
'video_resolution': f"{video_stream.get('width')}x{video_stream.get('height')}" if video_stream else None,
|
|
'video_fps': eval(video_stream.get('r_frame_rate', '0/1')) if video_stream else 0,
|
|
'audio_codec': audio_stream.get('codec_name') if audio_stream else None,
|
|
'audio_sample_rate': int(audio_stream.get('sample_rate', 0)) if audio_stream else 0,
|
|
'error': None
|
|
}
|
|
else:
|
|
return {
|
|
'valid': False,
|
|
'error': f"ffprobe failed: {result.stderr}"
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'valid': False,
|
|
'error': str(e)
|
|
}
|
|
|
|
|
|
def validate_split_videos(scenes_dir: Path):
|
|
"""验证切分目录中的所有视频"""
|
|
print(f"🔍 验证目录: {scenes_dir}")
|
|
|
|
if not scenes_dir.exists():
|
|
print(f"❌ 目录不存在: {scenes_dir}")
|
|
return False
|
|
|
|
# 查找所有mp4文件
|
|
video_files = list(scenes_dir.glob("*.mp4"))
|
|
|
|
if not video_files:
|
|
print(f"❌ 目录中没有找到mp4文件")
|
|
return False
|
|
|
|
print(f"📹 找到 {len(video_files)} 个视频文件")
|
|
|
|
valid_count = 0
|
|
total_size = 0
|
|
total_duration = 0
|
|
|
|
for video_file in sorted(video_files):
|
|
print(f"\n🎬 验证: {video_file.name}")
|
|
|
|
validation = validate_video_file(video_file)
|
|
|
|
if validation['valid']:
|
|
valid_count += 1
|
|
file_size = validation['file_size']
|
|
duration = validation['duration']
|
|
total_size += file_size
|
|
total_duration += duration
|
|
|
|
print(f" ✅ 有效")
|
|
print(f" 📏 大小: {file_size:,} bytes ({file_size/1024/1024:.1f} MB)")
|
|
print(f" ⏱️ 时长: {duration:.2f}秒")
|
|
print(f" 🎥 视频: {validation['video_codec']} {validation['video_resolution']} {validation['video_fps']:.1f}fps")
|
|
if validation['audio_codec']:
|
|
print(f" 🔊 音频: {validation['audio_codec']} {validation['audio_sample_rate']}Hz")
|
|
print(f" 📊 码率: {validation['bitrate']:,} bps")
|
|
else:
|
|
print(f" ❌ 无效: {validation['error']}")
|
|
|
|
print(f"\n📊 验证摘要:")
|
|
print(f" 有效文件: {valid_count}/{len(video_files)}")
|
|
print(f" 成功率: {valid_count/len(video_files)*100:.1f}%")
|
|
print(f" 总大小: {total_size:,} bytes ({total_size/1024/1024:.1f} MB)")
|
|
print(f" 总时长: {total_duration:.2f}秒")
|
|
|
|
return valid_count == len(video_files)
|
|
|
|
|
|
def main():
|
|
"""主函数"""
|
|
print("🚀 视频验证工具")
|
|
print("=" * 50)
|
|
|
|
# 验证最新的切分结果
|
|
test_scenes_dir = Path("/tmp/test_batch_output/1752032011698/scenes")
|
|
|
|
if test_scenes_dir.exists():
|
|
print("🎯 验证最新的批量切分结果")
|
|
success = validate_split_videos(test_scenes_dir)
|
|
|
|
if success:
|
|
print("\n🎉 所有视频文件都有效!切分成功!")
|
|
return 0
|
|
else:
|
|
print("\n⚠️ 部分视频文件无效")
|
|
return 1
|
|
else:
|
|
print("❌ 没有找到测试切分结果")
|
|
print("💡 请先运行批量切分命令:")
|
|
print(" python3 -m python_core.cli scene batch /tmp/test_batch_input /tmp/test_batch_output --verbose --no-ai")
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|