Files
AIEC_Skills/视频分割/split_video.py
2025-12-11 14:19:36 +08:00

146 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
视频按大小分割脚本
将视频分割为指定大小默认180MB的片段
"""
import os
import subprocess
import json
from pathlib import Path
import imageio_ffmpeg
# 配置
INPUT_DIR = Path(__file__).parent / "原视频"
OUTPUT_DIR = Path(__file__).parent / "分割后"
TARGET_DURATION_MIN = 30 # 目标片段时长(分钟)
MERGE_THRESHOLD_MIN = 10 # 最后一段小于此时长则合并到前一段
FFMPEG_PATH = imageio_ffmpeg.get_ffmpeg_exe()
def get_video_info(video_path):
"""获取视频信息:时长和文件大小(快速,只读取头部)"""
import re
# 只读取文件头部信息,不处理整个视频
cmd = [
FFMPEG_PATH,
'-i', str(video_path),
]
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
# 从stderr中解析时长 (ffmpeg输出信息在stderr)
duration_match = re.search(r'Duration: (\d+):(\d+):(\d+\.?\d*)', result.stderr)
if duration_match:
h, m, s = duration_match.groups()
duration = int(h) * 3600 + int(m) * 60 + float(s)
else:
raise ValueError("无法获取视频时长")
file_size = os.path.getsize(video_path)
return duration, file_size
def split_video(video_path):
"""将视频按时长分割"""
video_path = Path(video_path)
video_name = video_path.stem
video_ext = video_path.suffix
# 获取视频信息
duration, file_size = get_video_info(video_path)
file_size_mb = file_size / (1024 * 1024)
duration_min = duration / 60
print(f"处理: {video_path.name}", flush=True)
print(f" 时长: {duration_min:.1f}分钟, 大小: {file_size_mb:.1f}MB", flush=True)
target_duration = TARGET_DURATION_MIN * 60 # 转为秒
merge_threshold = MERGE_THRESHOLD_MIN * 60 # 转为秒
# 如果视频短于目标时长,直接复制
if duration <= target_duration:
print(f" 视频短于{TARGET_DURATION_MIN}分钟,无需分割")
output_path = OUTPUT_DIR / f"{video_name}-1{video_ext}"
import shutil
shutil.copy2(video_path, output_path)
print(f" 已复制到: {output_path.name}")
return [output_path]
# 计算片段时间点
segments = []
start_time = 0
while start_time < duration:
remaining = duration - start_time
if remaining <= target_duration + merge_threshold:
# 剩余时间不多,作为最后一段
segments.append((start_time, remaining))
break
else:
segments.append((start_time, target_duration))
start_time += target_duration
print(f" 分割为 {len(segments)} 个片段,每段约 {TARGET_DURATION_MIN} 分钟", flush=True)
output_files = []
for segment_index, (start_time, actual_duration) in enumerate(segments, 1):
output_path = OUTPUT_DIR / f"{video_name}-{segment_index}{video_ext}"
cmd = [
FFMPEG_PATH,
'-y', # 覆盖输出文件
'-i', str(video_path),
'-ss', str(start_time),
'-t', str(actual_duration),
'-c', 'copy', # 不重新编码,速度快
'-avoid_negative_ts', 'make_zero',
str(output_path)
]
print(f" 分割片段 {segment_index}: {start_time/60:.1f}min - {(start_time + actual_duration)/60:.1f}min", flush=True)
subprocess.run(cmd, capture_output=True, encoding='utf-8')
# 检查输出文件大小
if output_path.exists():
out_size = os.path.getsize(output_path) / (1024 * 1024)
print(f" -> {output_path.name} ({out_size:.1f}MB, {actual_duration/60:.1f}min)")
output_files.append(output_path)
return output_files
def main():
print("=" * 50)
print("视频分割工具")
print(f"输入目录: {INPUT_DIR}")
print(f"输出目录: {OUTPUT_DIR}")
print(f"目标时长: {TARGET_DURATION_MIN}分钟/段")
print("=" * 50)
# 创建输出目录
OUTPUT_DIR.mkdir(exist_ok=True)
# 支持的视频格式
video_extensions = {'.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm'}
# 获取所有视频文件
video_files = [f for f in INPUT_DIR.iterdir()
if f.is_file() and f.suffix.lower() in video_extensions]
if not video_files:
print("未找到视频文件!")
return
print(f"找到 {len(video_files)} 个视频文件\n")
# 处理每个视频
for video_file in video_files:
try:
split_video(video_file)
print()
except Exception as e:
print(f" 错误: {e}\n")
print("=" * 50)
print("处理完成!")
print("=" * 50)
if __name__ == "__main__":
main()