将两个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_videoclips

    MOVIEPY_AVAILABLE = True
    print("使用 MoviePy 进行视频合并")
except ImportError:
    MOVIEPY_AVAILABLE = False
    print("MoviePy 未安装,将使用 FFmpeg 方法")


def check_ffmpeg():
    """检查系统是否安装了ffmpeg"""
    try:
        result = subprocess.run(['ffmpeg', '-version'], capture_output=True, text=True)
        return result.returncode == 0
    except FileNotFoundError:
        return False


def 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 False

    except Exception as e:
        print(f"错误: {str(e)}")
        return False

    finally:
        # 清理临时文件
        if os.path.exists(list_filename):
            os.remove(list_filename)

    return True


def 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 True

    except Exception as e:
        print(f"错误: 视频合并失败 - {str(e)}")
        try:
            for clip in clips:
                clip.close()
        except:
            pass
        return False


def 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("操作已取消")
            return

    if not existing_files:
        print("错误: 没有找到任何视频文件")
        return

    print(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")
        return

    if 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("操作已取消")
        return

    print("\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")
        return

    if 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的输入列表文件)以保持目录整洁。

  1. 将两个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:合并逻辑

代码会根据工具执行以下操作:

  1. 使用MoviePy合并(merge_videos_moviepy函数):

    • 加载两个视频文件为VideoFileClip对象。
    • 使用concatenate_videoclips将两个片段拼接。
    • 保存结果到merged_video.mp4,使用libx264视频编码和aac音频编码。
    • 清理内存,关闭所有视频片段。
  2. 使用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
    

  1. 关键代码片段解读

以下是与合并两个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的无损合并。

  1. 注意事项
  • 文件格式兼容性
    • 两个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参数可避免路径解析错误。

  1. 如何修改代码以只合并两个特定文件

如果只需要合并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_videoclips
    MOVIEPY_AVAILABLE = True
except ImportError:
    MOVIEPY_AVAILABLE = False

def check_ffmpeg():
    try:
        result = subprocess.run(['ffmpeg', '-version'], capture_output=True, text=True)
        return result.returncode == 0
    except FileNotFoundError:
        return False

def 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 == 0

def 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 True

if __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")

  1. 运行示例

假设目录结构如下:

/project
├── merge_videos.py
├── merged_video_1.mp4
├── merged_video_2.mp4

运行命令:

bash

python merge_videos.py
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MonkeyKing.sun

对你有帮助的话,可以打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值