Python音视频剪辑处理:基于Python和FFmpeg的音视频剪辑命令行工具 通过简单的命令就能实现剪切、合并、提取音频/视频和调整速度等常用操作。pythonimport osimport subprocessimport sysfrom pathlib import Pathdef check_ffmpeg():检查系统是否安装FFmpegtry:subprocess.run([ffmpeg, -version], stdoutsubprocess.DEVNULL, stderrsubprocess.DEVNULL)return Trueexcept FileNotFoundError:print(错误: 未找到FFmpeg请先安装FFmpeg并添加到系统PATH。)print(下载地址: https://ffmpeg.org/download.html)return Falsedef get_duration(file_path):获取媒体文件时长秒cmd [ffprobe, -v, error, -show_entries, formatduration,-of, defaultnoprint_wrappers1:nokey1, file_path]try:result subprocess.run(cmd, capture_outputTrue, textTrue, checkTrue)return float(result.stdout.strip())except Exception as e:print(f获取文件时长失败: {e})return Nonedef clip_media(input_file, output_file, start_time, end_timeNone, durationNone):剪辑音视频片段参数:input_file: 输入文件路径output_file: 输出文件路径start_time: 开始时间 (格式: HH:MM:SS 或秒数)end_time: 结束时间 (格式: HH:MM:SS 或秒数)duration: 持续时长 (秒)if not Path(input_file).exists():print(f错误: 输入文件 {input_file} 不存在)return False# 构建ffmpeg命令cmd [ffmpeg, -i, input_file, -ss, start_time]if end_time and duration:print(警告: 同时指定了end_time和duration将使用duration)if duration:cmd.extend([-t, str(duration)])elif end_time:# 计算持续时间try:# 尝试将时间转换为秒def time_to_seconds(t):parts t.split(:)if len(parts) 3:return int(parts[0]) * 3600 int(parts[1]) * 60 float(parts[2])elif len(parts) 2:return int(parts[0]) * 60 float(parts[1])else:return float(t)start_sec time_to_seconds(start_time)end_sec time_to_seconds(end_time)if end_sec start_sec:print(错误: 结束时间必须大于开始时间)return Falsecmd.extend([-t, str(end_sec - start_sec)])except Exception as e:print(f时间解析错误: {e})return False# 根据文件扩展名推断编码格式output_ext Path(output_file).suffix.lower()if output_ext in [.mp4]:cmd.extend([-c:v, libx264, -c:a, aac])elif output_ext in [.mkv]:cmd.extend([-c:v, libx264, -c:a, aac])elif output_ext in [.avi]:cmd.extend([-c:v, libxvid, -c:a, mp3])elif output_ext in [.mov]:cmd.extend([-c:v, libx264, -c:a, aac])elif output_ext in [.mp3]:cmd.extend([-vn, -c:a, libmp3lame, -q:a, 2])elif output_ext in [.aac]:cmd.extend([-vn, -c:a, aac])elif output_ext in [.wav]:cmd.extend([-vn, -c:a, pcm_s16le])else:# 默认复制编码适用于相同格式的剪辑cmd.extend([-c, copy])# 覆盖输出文件如果有cmd.extend([-y])print(f执行命令: { .join(cmd)})try:subprocess.run(cmd, checkTrue, capture_outputTrue, textTrue)print(f剪辑成功! 输出文件: {output_file})return Trueexcept subprocess.CalledProcessError as e:print(f剪辑失败: {e.stderr})return Falsedef merge_media(input_files, output_file):合并多个音视频文件if len(input_files) 2:print(错误: 至少需要两个文件才能合并)return Falsefor f in input_files:if not Path(f).exists():print(f错误: 文件 {f} 不存在)return False# 创建临时文件列表list_file filelist.txtwith open(list_file, w, encodingutf-8) as f:for file in input_files:f.write(ffile {Path(file).absolute()}\n)# 构建命令cmd [ffmpeg, -f, concat, -safe, 0, -i, list_file]# 根据输出格式设置编码output_ext Path(output_file).suffix.lower()if output_ext in [.mp4, .mkv]:cmd.extend([-c:v, libx264, -c:a, aac])elif output_ext in [.mp3]:cmd.extend([-vn, -c:a, libmp3lame, -q:a, 2])else:cmd.extend([-c, copy])cmd.extend([-y, output_file])print(f执行命令: { .join(cmd)})try:subprocess.run(cmd, checkTrue, capture_outputTrue, textTrue)print(f合并成功! 输出文件: {output_file})os.remove(list_file)return Trueexcept subprocess.CalledProcessError as e:print(f合并失败: {e.stderr})os.remove(list_file)return Falsedef extract_audio(input_file, output_file, bitrate192k):提取音频if not Path(input_file).exists():print(f错误: 输入文件 {input_file} 不存在)return Falsecmd [ffmpeg, -i, input_file, -vn, -c:a, libmp3lame, -b:a, bitrate, -y, output_file]print(f执行命令: { .join(cmd)})try:subprocess.run(cmd, checkTrue, capture_outputTrue, textTrue)print(f音频提取成功! 输出文件: {output_file})return Trueexcept subprocess.CalledProcessError as e:print(f提取失败: {e.stderr})return Falsedef extract_video(input_file, output_file):提取视频无声if not Path(input_file).exists():print(f错误: 输入文件 {input_file} 不存在)return Falsecmd [ffmpeg, -i, input_file, -an, -c:v, libx264, -y, output_file]print(f执行命令: { .join(cmd)})try:subprocess.run(cmd, checkTrue, capture_outputTrue, textTrue)print(f视频提取成功! 输出文件: {output_file})return Trueexcept subprocess.CalledProcessError as e:print(f提取失败: {e.stderr})return Falsedef change_speed(input_file, output_file, speed1.0):调整播放速度if not Path(input_file).exists():print(f错误: 输入文件 {input_file} 不存在)return Falseif speed 0:print(错误: 速度必须大于0)return False# 判断是音频还是视频output_ext Path(output_file).suffix.lower()if output_ext in [.mp3, .aac, .wav]:# 纯音频处理cmd [ffmpeg, -i, input_file, -filter:a, fatempo{speed}, -y, output_file]else:# 视频处理音视频一起变速cmd [ffmpeg, -i, input_file,-filter_complex, f[0:v]setpts{1/speed}*PTS[v];[0:a]atempo{speed}[a],-map, [v], -map, [a], -y, output_file]print(f执行命令: { .join(cmd)})try:subprocess.run(cmd, checkTrue, capture_outputTrue, textTrue)print(f变速成功! 速度: {speed}x, 输出文件: {output_file})return Trueexcept subprocess.CalledProcessError as e:print(f变速失败: {e.stderr})return Falsedef main():命令行交互主函数print( * 50)print( 音视频剪辑工具 (基于FFmpeg))print( * 50)if not check_ffmpeg():returnwhile True:print(\n请选择操作:)print(1. 剪辑片段 (剪切))print(2. 合并多个文件)print(3. 提取音频)print(4. 提取视频 (无声))print(5. 调整播放速度)print(6. 查看文件信息)print(0. 退出)choice input(\n请输入数字选择: ).strip()if choice 0:print(感谢使用再见!)breakelif choice 1:input_file input(输入文件路径: ).strip()if not Path(input_file).exists():print(文件不存在!)continue# 获取时长duration get_duration(input_file)if duration:print(f文件总时长: {duration:.2f} 秒)start input(开始时间 (格式: HH:MM:SS 或秒数): ).strip()if not start:print(开始时间不能为空!)continueend input(结束时间 (格式: HH:MM:SS 或秒数, 留空则使用时长): ).strip()dur input(持续时长 (秒, 优先级高于结束时间, 留空则自动计算): ).strip()output_file input(输出文件路径: ).strip()if not output_file:print(输出路径不能为空!)continueif dur:try:clip_media(input_file, output_file, start, durationfloat(dur))except ValueError:print(持续时间必须是数字!)else:clip_media(input_file, output_file, start, end_timeend if end else None)elif choice 2:files []print(输入要合并的文件路径 (每行一个输入空行结束):)while True:f input().strip()if not f:breakif Path(f).exists():files.append(f)else:print(f文件 {f} 不存在已跳过)if len(files) 2:print(至少需要2个有效文件!)continueoutput_file input(输出文件路径: ).strip()if not output_file:print(输出路径不能为空!)continuemerge_media(files, output_file)elif choice 3:input_file input(输入文件路径: ).strip()output_file input(输出音频路径 (如 output.mp3): ).strip()if not input_file or not output_file:print(路径不能为空!)continuebitrate input(比特率 (默认192k, 如 128k, 320k): ).strip() or 192kextract_audio(input_file, output_file, bitrate)elif choice 4:input_file input(输入文件路径: ).strip()output_file input(输出视频路径 (如 output.mp4): ).strip()if not input_file or not output_file:print(路径不能为空!)continueextract_video(input_file, output_file)elif choice 5:input_file input(输入文件路径: ).strip()if not Path(input_file).exists():print(文件不存在!)continuetry:speed float(input(速度倍数 (如 0.5 慢放, 2.0 快放): ).strip())except ValueError:print(请输入有效数字!)continueoutput_file input(输出文件路径: ).strip()if not output_file:print(输出路径不能为空!)continuechange_speed(input_file, output_file, speed)elif choice 6:input_file input(输入文件路径: ).strip()if not Path(input_file).exists():print(文件不存在!)continueduration get_duration(input_file)if duration:print(f文件时长: {duration:.2f} 秒 ({duration/60:.2f} 分钟))else:print(无法获取文件信息)else:print(无效选择请重新输入)if __name__ __main__:main()剪辑功能与操作说明您可以通过命令行交互完成多种剪辑任务所有操作都基于FFmpeg实现。· 核心剪辑功能支持按时间点剪切片段可指定开始/结束时间或持续时长、合并多个文件、提取音频或视频轨道以及调整播放速度0.5倍慢放至2倍快放。· 交互式操作流程运行程序后您会看到清晰的功能菜单。选择对应数字后程序会逐步引导您输入文件路径、时间参数等必要信息并实时显示执行的FFmpeg命令方便您了解底层操作。· 智能格式处理程序会根据输出文件的扩展名如.mp4、.mp3自动选择合理的编码参数。对于常见的剪辑操作如相同格式的剪切会优先使用-c copy模式实现无损且快速的剪辑。