ffmpeg 将视频智能分割成多个小视频
这是一个基于Python的视频智能分割工具,整合了场景变化和静音检测两种分割模式。程序通过FFmpeg实现自动检测分割点并批量切割视频,支持自定义检测阈值(场景敏感度/静音分贝)。主要功能包括:1)场景突变自动分割;2)静音片段自动分割;3)保持原编码快速切割;4)自动过滤短片段。使用前需安装Python3和FFmpeg,支持命令行参数调整检测敏感度。该工具可高效处理视频分割需求,避免手动操作中间
·
下面提供一个基于 Python 的综合程序,整合了 场景变化分割 和 静音片段分割 两种智能分割逻辑,可自动检测分割点并批量切割视频。程序封装了 FFmpeg 调用、时间戳解析和视频切割流程,无需手动处理中间文件。
程序功能
- 支持两种分割模式:
scene(场景突变分割)、silence(静音片段分割) - 自动检测分割时间点,无需手动提取
- 批量切割视频为多个片段,保持原编码(快速切割)
- 可自定义检测阈值(场景敏感度 / 静音分贝)
程序代码(Python)
python
运行
import os
import re
import subprocess
import argparse
from typing import List, Tuple
def check_dependencies() -> None:
"""检查是否安装 ffmpeg 和 ffprobe"""
try:
subprocess.run(["ffmpeg", "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
subprocess.run(["ffprobe", "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
except (subprocess.CalledProcessError, FileNotFoundError):
raise RuntimeError("请先安装 ffmpeg 并确保其在环境变量中(https://ffmpeg.org/download.html)")
def get_video_duration(input_path: str) -> float:
"""用 ffprobe 获取视频总时长(秒)"""
cmd = [
"ffprobe", "-v", "error",
"-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1",
input_path
]
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
return float(result.stdout.strip())
def detect_scene_changes(input_path: str, threshold: float = 0.3, min_duration: float = 0.1) -> List[float]:
"""检测场景变化时间点(返回分割时间戳列表)"""
cmd = [
"ffmpeg", "-i", input_path,
"-filter:v", f"scenedetect=threshold={threshold}:duration={min_duration}, metadata=print:file=-",
"-f", "null", "-"
]
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
output = result.stdout
# 从输出中提取 pts_time(场景切换时间)
time_pattern = re.compile(r"pts_time:(\d+\.\d+)")
times = [float(m.group(1)) for m in time_pattern.finditer(output)]
# 去重并排序(确保时间递增)
times = sorted(list(set(times)))
return times
def detect_silence(input_path: str, noise_threshold: str = "-50dB", min_silence: float = 1.0) -> List[float]:
"""检测静音片段,返回静音结束时间作为分割点"""
cmd = [
"ffmpeg", "-i", input_path,
"-filter:a", f"silencedetect=noise={noise_threshold}:d={min_silence}",
"-f", "null", "-"
]
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
output = result.stderr # silencedetect 输出在 stderr
# 提取静音结束时间(silence_end)
end_pattern = re.compile(r"silence_end: (\d+\.\d+)")
times = [float(m.group(1)) for m in end_pattern.finditer(output)]
# 去重并排序
times = sorted(list(set(times)))
return times
def split_video(input_path: str, output_prefix: str, split_times: List[float], duration: float) -> None:
"""根据分割时间戳切割视频"""
# 确保分割时间包含起点(0)和终点(总时长)
split_times = [0.0] + split_times + [duration]
# 去重并再次排序(避免重复时间)
split_times = sorted(list(set(split_times)))
# 循环切割每个片段
for i in range(len(split_times) - 1):
start = split_times[i]
end = split_times[i + 1]
if end - start < 0.5: # 跳过短于0.5秒的片段
continue
output_path = f"{output_prefix}_{i:03d}.mp4"
cmd = [
"ffmpeg", "-ss", str(start), # 开始时间
"-i", input_path,
"-to", str(end), # 结束时间
"-c", "copy", # 直接复制编码(快速)
"-y", # 覆盖已有文件
output_path
]
print(f"切割片段 {i+1}/{len(split_times)-1}:{start:.2f}s -> {end:.2f}s -> {output_path}")
subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
def main():
parser = argparse.ArgumentParser(description="FFmpeg 智能分割视频(场景变化/静音检测)")
parser.add_argument("input", help="输入视频文件路径(如 input.mp4)")
parser.add_argument("-m", "--mode", choices=["scene", "silence"], required=True,
help="分割模式:scene(场景变化)/ silence(静音片段)")
parser.add_argument("-o", "--output", default="output", help="输出片段前缀(默认:output)")
# 场景检测参数
parser.add_argument("--scene-threshold", type=float, default=0.3,
help="场景变化阈值(0-1,越小越敏感,默认0.3)")
parser.add_argument("--scene-min-duration", type=float, default=0.1,
help="忽略短于该时长的场景变化(秒,默认0.1)")
# 静音检测参数
parser.add_argument("--silence-noise", default="-50dB",
help="静音分贝阈值(默认-50dB,值越小越严格)")
parser.add_argument("--silence-min", type=float, default=1.0,
help="最小静音时长(秒,默认1.0)")
args = parser.parse_args()
# 检查依赖和输入文件
check_dependencies()
if not os.path.exists(args.input):
raise FileNotFoundError(f"输入文件不存在:{args.input}")
# 获取视频总时长
duration = get_video_duration(args.input)
print(f"视频总时长:{duration:.2f}秒")
# 检测分割时间点
print(f"开始{args.mode}检测...")
if args.mode == "scene":
split_times = detect_scene_changes(
args.input,
threshold=args.scene_threshold,
min_duration=args.scene_min_duration
)
else: # silence
split_times = detect_silence(
args.input,
noise_threshold=args.silence_noise,
min_silence=args.silence_min
)
if not split_times:
print("未检测到分割点,不进行切割")
return
print(f"检测到 {len(split_times)} 个分割点:{[f'{t:.2f}s' for t in split_times]}")
# 切割视频
split_video(args.input, args.output, split_times, duration)
print("分割完成!")
if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"错误:{str(e)}")
exit(1)
使用方法
前提条件
- 安装 Python 3.x(https://www.python.org/downloads/)
- 安装 FFmpeg 并添加到环境变量(https://ffmpeg.org/download.html,确保
ffmpeg和ffprobe可在命令行直接调用)
基本命令
1. 基于场景变化分割(默认参数)
bash
运行
python split_video.py input.mp4 -m scene -o scene_output
- 功能:检测视频中场景突变的时间点,切割为多个片段
- 输出文件:
scene_output_000.mp4、scene_output_001.mp4...
2. 基于静音片段分割(默认参数)
bash
运行
python split_video.py input.mp4 -m silence -o silence_output
- 功能:检测视频中持续 1 秒以上的静音片段,在静音结束处分割
- 输出文件:
silence_output_000.mp4、silence_output_001.mp4...
自定义参数
调整场景检测敏感度
bash
运行
python split_video.py input.mp4 -m scene --scene-threshold 0.2 --scene-min-duration 0.5 -o scene_output
--scene-threshold 0.2:降低阈值(更敏感,检测更多场景变化)--scene-min-duration 0.5:忽略短于 0.5 秒的场景变化(减少误检)
调整静音检测严格度
bash
运行
python split_video.py input.mp4 -m silence --silence-noise -60dB --silence-min 2.0 -o silence_output
--silence-noise -60dB:更严格的静音标准(只有更安静的片段才视为静音)--silence-min 2.0:只检测持续 2 秒以上的静音片段
注意事项
- 切割速度:使用
-c copy直接复制编码,速度极快,但可能在非关键帧处切割导致片段开头 / 结尾有轻微卡顿(如需精确可去掉-c copy,但会重新编码,速度较慢)。 - 阈值调整:不同视频(如明暗对比、音量大小)需要调整阈值,建议先小范围测试。
- 短片段过滤:程序会自动跳过短于 0.5 秒的片段,避免生成无效文件。
通过这个程序,可以快速实现基于内容的智能视频分割,无需手动处理中间步骤。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)