You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python的OpenCV拼接含原音频的多视频?遇错误求助

问题分析与解决方案

核心问题

  1. OpenCV不支持音频处理:cv2.VideoCapture只能读取视频帧,无法获取音频数据;cv2.VideoWriter也仅能写入视频流,不支持音频写入。你之前试图通过video.read()获取音频帧的逻辑完全错误,反而导致跳帧,最终输出的视频文件结构损坏,触发moov atom not found错误。
  2. 跳帧导致文件损坏:循环中连续调用两次video.read(),每次调用都会读取下一帧,导致实际写入的视频帧丢失一半,文件元数据混乱,进而出现上述错误。

错误修复(先恢复正常视频拼接)

移除代码中错误的音频处理部分,让视频拼接功能回到正常状态:

import os
import cv2
import time
import sys

def merge_videos_no_audio(directory):
    video_files = []
    for file in os.listdir(directory):
        if file.endswith(".mp4"):
            video_files.append(os.path.join(directory, file))

    video_data = []
    for file_path in video_files:
        file_name = os.path.basename(file_path)
        date_time = file_name.split("_")[0]
        video_data.append({"file_path": file_path, "date_time": date_time})

    sorted_video_data = sorted(video_data, key=lambda x: x["date_time"])

    frame_size = None
    fps = None
    video_writer = None

    total_frames = 0
    current_frame = 0
    start_time = time.time()

    for data in sorted_video_data:
        video = cv2.VideoCapture(data["file_path"])

        if frame_size is None:
            frame_size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)),
                          int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))
        if fps is None:
            fps = int(video.get(cv2.CAP_PROP_FPS))

        total_frames += int(video.get(cv2.CAP_PROP_FRAME_COUNT))

        if video_writer is None:
            output_path = os.path.join(directory, "merged_videos_no_audio.mp4")
            video_fourcc = cv2.VideoWriter_fourcc(*"mp4v")
            video_writer = cv2.VideoWriter(output_path, video_fourcc, fps, frame_size, True)

        while video.isOpened():
            ret, frame = video.read()
            if ret:
                video_writer.write(frame)
                current_frame += 1

                progress = current_frame / total_frames
                bar_length = 50
                filled_length = int(round(bar_length * progress))
                remaining_time = (time.time() - start_time) * (total_frames / current_frame - 1)
                eta = time.strftime("%H:%M:%S", time.gmtime(remaining_time))
                bar = "#" * filled_length + "-" * (bar_length - filled_length)
                sys.stdout.write(f"\r|{bar}| {current_frame}/{total_frames} [{progress:.2%}] ETA: {eta}")
                sys.stdout.flush()
            else:
                break

        video.release()

    video_writer.release()

这段代码会生成结构正常的无音频视频,解决moov atom not found错误。

带音频的视频拼接方案(无需手动调用ffmpeg)

因为OpenCV无法处理音频,推荐使用moviepy库——它是基于ffmpeg的Python封装,无需手动执行命令,可直接整合到你的脚本中,完美支持带音频的视频拼接。

步骤1:安装依赖

pip install moviepy

步骤2:完整拼接代码

import os
import time
import sys
from moviepy.editor import VideoFileClip, concatenate_videoclips

def merge_videos_with_audio(directory):
    # 获取目录下所有MP4文件
    video_files = []
    for file in os.listdir(directory):
        if file.endswith(".mp4"):
            video_files.append(os.path.join(directory, file))

    # 提取文件名中的日期时间并排序
    video_data = []
    for file_path in video_files:
        file_name = os.path.basename(file_path)
        date_time = file_name.split("_")[0]
        video_data.append({"file_path": file_path, "date_time": date_time})

    sorted_video_data = sorted(video_data, key=lambda x: x["date_time"])
    sorted_clips = [VideoFileClip(data["file_path"]) for data in sorted_video_data]

    # 计算总时长(用于进度显示)
    total_duration = sum(clip.duration for clip in sorted_clips)
    start_time = time.time()

    # 拼接视频
    merged_clip = concatenate_videoclips(sorted_clips, method="compose")

    # 写入文件,同时显示进度
    output_path = os.path.join(directory, "merged_videos_with_audio.mp4")
    merged_clip.write_videofile(
        output_path,
        codec="libx264",
        audio_codec="aac",
        progress_bar=False,
        verbose=False
    )

    # 手动实现进度显示
    elapsed_time = time.time() - start_time
    bar_length = 50
    bar = "#" * bar_length
    sys.stdout.write(f"\r|{bar}| 100.00% 耗时: {time.strftime('%H:%M:%S', time.gmtime(elapsed_time))}")
    sys.stdout.flush()
    print()

    # 释放资源
    for clip in sorted_clips:
        clip.close()
    merged_clip.close()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("用法: python script.py <视频目录>")
        sys.exit(1)
    merge_videos_with_audio(sys.argv[1])

代码说明

  • concatenate_videoclips会自动处理视频的分辨率、帧率对齐(通过method="compose"),同时保留所有原始音频。
  • 沿用你原来的文件名日期排序逻辑,无需修改。
  • 支持命令行调用,和原脚本使用方式一致。
  • 后续若要添加视频拆分功能,可使用moviepy的subclip方法轻松实现。

关键提示

  • OpenCV定位是计算机视觉处理,而非多媒体文件编辑,因此不适合处理音频相关需求。
  • moviepy是Python多媒体处理的常用库,覆盖视频拼接、拆分、剪辑、音频处理等功能,完全满足你后续扩展需求。

内容的提问来源于stack exchange,提问作者K Dauda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:43:20