将两个mp4的文件合并在一起形成新的文件
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
视频合并程序
将多个mp4视频文件按照名称顺序合并成一个视频文件
支持两种方法:moviepy 和 ffmpeg
"""import os
import glob
import subprocess
import sys# 尝试导入moviepy,如果失败则使用ffmpeg方法
try:from moviepy.editor import VideoFileClip, concatenate_videoclipsMOVIEPY_AVAILABLE = Trueprint("使用 MoviePy 进行视频合并")
except ImportError:MOVIEPY_AVAILABLE = Falseprint("MoviePy 未安装,将使用 FFmpeg 方法")def check_ffmpeg():"""检查系统是否安装了ffmpeg"""try:result = subprocess.run(['ffmpeg', '-version'], capture_output=True, text=True)return result.returncode == 0except FileNotFoundError:return Falsedef merge_videos_ffmpeg(video_files, output_filename="merged_video.mp4"):"""使用FFmpeg合并视频"""# 创建文件列表list_filename = "video_list.txt"try:with open(list_filename, 'w') as f:for video_file in video_files:f.write(f"file '{video_file}'\n")# 使用ffmpeg合并cmd = ['ffmpeg', '-f', 'concat', '-safe', '0','-i', list_filename, '-c', 'copy', output_filename, '-y']print("正在使用FFmpeg合并视频...")result = subprocess.run(cmd, capture_output=True, text=True)if result.returncode == 0:print(f"✓ 视频合并完成!")print(f"输出文件: {output_filename}")else:print(f"FFmpeg错误: {result.stderr}")return Falseexcept Exception as e:print(f"错误: {str(e)}")return Falsefinally:# 清理临时文件if os.path.exists(list_filename):os.remove(list_filename)return Truedef merge_videos_moviepy(video_files, output_filename="merged_video.mp4"):"""使用MoviePy合并视频"""try:clips = []for i, video_file in enumerate(video_files):print(f"正在加载视频 {i + 1}/{len(video_files)}: {video_file}")clip = VideoFileClip(video_file)clips.append(clip)print("正在合并视频...")final_clip = concatenate_videoclips(clips, method="compose")print(f"正在保存合并后的视频: {output_filename}")final_clip.write_videofile(output_filename,codec='libx264',audio_codec='aac',temp_audiofile='temp-audio.m4a',remove_temp=True)# 清理内存for clip in clips:clip.close()final_clip.close()print(f"✓ 视频合并完成!")print(f"输出文件: {output_filename}")return Trueexcept Exception as e:print(f"错误: 视频合并失败 - {str(e)}")try:for clip in clips:clip.close()except:passreturn Falsedef merge_videos():"""合并视频文件的主函数"""# 定义视频文件列表(按照你提供的文件名顺序)# video_files = [# "0014_new-a-open2_segment_000_composite.mp4",# "0014_new-a-open2_segment_001_composite.mp4",# "0014_new-a-open2_segment_002_composite.mp4",# "0014_new-a-open2_segment_003_composite.mp4",# "0014_new-a-open2_segment_004_composite.mp4",# "0014_new-a-open2_segment_005_composite.mp4",# "0014_new-a-open2_segment_006_composite.mp4",# "0014_new-a-open2_segment_007_composite.mp4",# "0014_new-a-open2_segment_008_composite.mp4",# "0014_new-a-open2_segment_009_composite.mp4"# ]video_files = ["merged_video_1.mp4","merged_video_2.mp4"]# 检查文件是否存在existing_files = []missing_files = []for video_file in video_files:if os.path.exists(video_file):existing_files.append(video_file)print(f"✓ 找到文件: {video_file}")else:missing_files.append(video_file)print(f"✗ 文件未找到: {video_file}")if missing_files:print(f"\n警告: 有 {len(missing_files)} 个文件未找到")choice = input("是否继续合并已存在的文件? (y/n): ")if choice.lower() != 'y':print("操作已取消")returnif not existing_files:print("错误: 没有找到任何视频文件")returnprint(f"\n开始合并 {len(existing_files)} 个视频文件...")# 选择合并方法if MOVIEPY_AVAILABLE:success = merge_videos_moviepy(existing_files)elif check_ffmpeg():success = merge_videos_ffmpeg(existing_files)else:print("错误: 既没有安装MoviePy也没有安装FFmpeg")print("请安装其中一个:")print("1. 安装MoviePy: pip install moviepy")print("2. 安装FFmpeg: https://ffmpeg.org/download.html")returnif success:print(f"合并了 {len(existing_files)} 个视频文件")def merge_videos_auto_detect():"""自动检测当前目录下的视频文件并按名称排序合并"""# 查找所有mp4文件video_files = glob.glob("0014_new-a-open_segment_*_composite.mp4")if not video_files:print("错误: 在当前目录下没有找到匹配的视频文件")print("请确保视频文件在当前目录下,且文件名格式为: 0014_new-a-open_segment_XXX_composite.mp4")return# 按名称排序video_files.sort()print(f"找到 {len(video_files)} 个视频文件:")for i, file in enumerate(video_files):print(f"{i + 1}. {file}")choice = input("\n是否继续合并这些文件? (y/n): ")if choice.lower() != 'y':print("操作已取消")returnprint("\n开始合并视频...")# 选择合并方法if MOVIEPY_AVAILABLE:success = merge_videos_moviepy(video_files)elif check_ffmpeg():success = merge_videos_ffmpeg(video_files)else:print("错误: 既没有安装MoviePy也没有安装FFmpeg")print("请安装其中一个:")print("1. 安装MoviePy: pip install moviepy")print("2. 安装FFmpeg: https://ffmpeg.org/download.html")returnif success:print(f"合并了 {len(video_files)} 个视频文件")if __name__ == "__main__":print("视频合并程序")print("=" * 50)# 检查可用的工具if MOVIEPY_AVAILABLE:print("✓ MoviePy 可用")else:print("✗ MoviePy 不可用")if check_ffmpeg():print("✓ FFmpeg 可用")else:print("✗ FFmpeg 不可用")if not MOVIEPY_AVAILABLE and not check_ffmpeg():print("\n错误: 没有可用的视频处理工具!")print("请安装以下工具之一:")print("1. MoviePy: pip install moviepy")print("2. FFmpeg: https://ffmpeg.org/download.html")sys.exit(1)print("\n选择合并模式:")print("1. 使用预定义的文件列表合并")print("2. 自动检测当前目录下的视频文件")choice = input("\n请选择模式 (1/2): ")if choice == "1":merge_videos()elif choice == "2":merge_videos_auto_detect()else:print("无效选择,使用默认模式...")merge_videos()
- 目的:将多个MP4视频文件按顺序合并成一个输出视频文件(默认名为merged_video.mp4)。
- 支持的方法:
- MoviePy:一个Python库,适合处理视频编辑任务,代码中通过加载视频片段并拼接实现合并。
- FFmpeg:一个强大的多媒体处理工具,通过命令行调用实现快速合并。
- 主要特点:
- 自动检测系统中是否安装了MoviePy或FFmpeg,优先使用MoviePy,如果不可用则fallback到FFmpeg。
- 提供两种合并模式:
- 预定义文件列表:用户在代码中手动指定要合并的视频文件。
- 自动检测:扫描当前目录下符合特定命名规则的MP4文件并按名称排序后合并。
- 检查输入文件是否存在,允许用户选择是否继续合并部分存在的文件。
- 清理临时文件(如FFmpeg的输入列表文件)以保持目录整洁。
- 将两个MP4文件合并的实现方式
代码中已经预定义了一个文件列表,用于合并两个MP4文件:
python
video_files = ["merged_video_1.mp4","merged_video_2.mp4"
]
要合并这两个文件,可以通过以下步骤实现:
步骤 1:准备环境
- 确保系统中安装了以下任一工具:
- MoviePy:运行pip install moviepy安装。
- FFmpeg:从FFmpeg官网下载并配置环境变量,确保命令行能运行ffmpeg -version。
- 将两个MP4文件(merged_video_1.mp4和merged_video_2.mp4)放在代码运行的同一目录下。
步骤 2:运行代码
- 运行方式:
- 保存代码为Python文件(例如merge_videos.py)。
- 在命令行中运行:python merge_videos.py。
- 选择模式:
- 在程序启动时,选择模式1(使用预定义文件列表合并)。
- 程序会检查merged_video_1.mp4和merged_video_2.mp4是否存在。
- 如果文件存在,程序将根据可用工具(MoviePy或FFmpeg)执行合并。
步骤 3:合并逻辑
代码会根据工具执行以下操作:
-
使用MoviePy合并(merge_videos_moviepy函数):
- 加载两个视频文件为VideoFileClip对象。
- 使用concatenate_videoclips将两个片段拼接。
- 保存结果到merged_video.mp4,使用libx264视频编码和aac音频编码。
- 清理内存,关闭所有视频片段。
-
使用FFmpeg合并(merge_videos_ffmpeg函数):
-
创建一个临时文本文件video_list.txt,列出两个视频文件的路径(格式为file ‘filename’)。
-
运行FFmpeg命令:
bash
ffmpeg -f concat -safe 0 -i video_list.txt -c copy merged_video.mp4 -y
- -f concat:使用FFmpeg的concat demuxer合并文件。
- -safe 0:允许非标准文件路径。
- -c copy:直接复制视频和音频流,无需重新编码,速度快且无损。
- -y:自动覆盖输出文件。
-
删除临时文件video_list.txt。
-
步骤 4:输出
-
合并成功后,输出文件为merged_video.mp4,位于当前目录。
-
程序会打印日志,如:
✓ 视频合并完成! 输出文件: merged_video.mp4
- 关键代码片段解读
以下是与合并两个MP4文件直接相关的核心部分:
预定义文件列表
python
video_files = ["merged_video_1.mp4","merged_video_2.mp4"
]
- 定义了两个要合并的文件,程序会按列表顺序拼接(先播放merged_video_1.mp4,再播放merged_video_2.mp4)。
文件存在性检查
python
existing_files = []
missing_files = []
for video_file in video_files:if os.path.exists(video_file):existing_files.append(video_file)print(f"✓ 找到文件: {video_file}")else:missing_files.append(video_file)print(f"✗ 文件未找到: {video_file}")
- 确保merged_video_1.mp4和merged_video_2.mp4存在。
- 如果有文件缺失,询问用户是否继续合并已有文件。
MoviePy合并逻辑
python
clips = []
for video_file in video_files:clip = VideoFileClip(video_file)clips.append(clip)
final_clip = concatenate_videoclips(clips, method="compose")
final_clip.write_videofile(output_filename, codec='libx264', audio_codec='aac')
- 逐个加载视频,拼接后保存。
FFmpeg合并逻辑
python
with open(list_filename, 'w') as f:for video_file in video_files:f.write(f"file '{video_file}'\n")
cmd = ['ffmpeg', '-f', 'concat', '-safe', '0', '-i', list_filename, '-c', 'copy', output_filename, '-y']
subprocess.run(cmd, capture_output=True, text=True)
- 创建文件列表,调用FFmpeg的无损合并。
- 注意事项
- 文件格式兼容性:
- 两个MP4文件的视频和音频编码格式需一致(如都使用H.264视频和AAC音频),否则FFmpeg的-c copy可能失败。
- MoviePy会重新编码输出文件,兼容性较高,但速度较慢且可能有质量损失。
- 性能对比:
- FFmpeg的-c copy方式速度快、无损,适合格式一致的视频。
- MoviePy适合需要额外编辑(如裁剪、添加效果)的场景,但耗时较长。
- 错误处理:
- 如果文件缺失,程序会提示用户选择是否继续。
- 如果工具未安装,程序会引导用户安装MoviePy或FFmpeg。
- 路径问题:
- 确保merged_video_1.mp4和merged_video_2.mp4在当前工作目录下。
- 如果路径包含非ASCII字符,FFmpeg的-safe 0参数可避免路径解析错误。
- 如何修改代码以只合并两个特定文件
如果只需要合并merged_video_1.mp4和merged_video_2.mp4,可以简化代码,直接调用merge_videos函数:
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import subprocess
try:from moviepy.editor import VideoFileClip, concatenate_videoclipsMOVIEPY_AVAILABLE = True
except ImportError:MOVIEPY_AVAILABLE = Falsedef check_ffmpeg():try:result = subprocess.run(['ffmpeg', '-version'], capture_output=True, text=True)return result.returncode == 0except FileNotFoundError:return Falsedef merge_videos_ffmpeg(video_files, output_filename="merged_video.mp4"):list_filename = "video_list.txt"with open(list_filename, 'w') as f:for video_file in video_files:f.write(f"file '{video_file}'\n")cmd = ['ffmpeg', '-f', 'concat', '-safe', '0', '-i', list_filename, '-c', 'copy', output_filename, '-y']result = subprocess.run(cmd, capture_output=True, text=True)os.remove(list_filename)return result.returncode == 0def merge_videos_moviepy(video_files, output_filename="merged_video.mp4"):clips = [VideoFileClip(video_file) for video_file in video_files]final_clip = concatenate_videoclips(clips, method="compose")final_clip.write_videofile(output_filename, codec='libx264', audio_codec='aac')for clip in clips:clip.close()final_clip.close()return Trueif __name__ == "__main__":video_files = ["merged_video_1.mp4", "merged_video_2.mp4"]existing_files = [f for f in video_files if os.path.exists(f)]if len(existing_files) != 2:print("错误: 请确保两个视频文件都存在")exit(1)if MOVIEPY_AVAILABLE:merge_videos_moviepy(existing_files)elif check_ffmpeg():merge_videos_ffmpeg(existing_files)else:print("错误: 请安装MoviePy或FFmpeg")exit(1)print("合并完成,输出文件:merged_video.mp4")
- 运行示例
假设目录结构如下:
/project
├── merge_videos.py
├── merged_video_1.mp4
├── merged_video_2.mp4
运行命令:
bash
python merge_videos.py