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

Linux环境下使用OpenCV合成的视频播放速度过快如何解决

问题根因

  • 文件格式不匹配:你在save_frames函数中存储的是.jpg格式的帧文件,但make_video函数中筛选文件的条件是if ".png" in f,这会导致你实际读取合成的根本不是本次捕获的帧,大概率是路径下之前遗留的旧png文件,所以你修改fps参数自然不会生效。
  • 帧读取逻辑错误:捕获帧的循环中没有判断cap.read()返回的ret值,视频读取到末尾后ret会变为False,此时frame是空值,你依然执行了存图和计数自增逻辑,会多存大量无效的空帧:原视频10秒30fps实际只有300帧有效帧,你统计到的600帧是包含无效帧的错误数据,最终合成时长自然不对。
  • 文件排序错误:os.listdir()返回的文件名是按照系统字典序排列,不是按帧号的自然顺序,比如frame00010.jpg会排在frame00002.jpg前面,帧顺序混乱也会导致播放异常。
  • fps参数未正确传递:你save_frames已经返回了原视频的fps值,调用make_video时需要把这个值传入,不要用默认的25。

修复代码

修复后的视频捕获函数

def save_frames(video_file, path_in):
    cap = cv2.VideoCapture(video_file)
    if not cap.isOpened():
        raise IOError(f"无法打开视频文件{video_file}")
    fps = cap.get(cv2.CAP_PROP_FPS)
    count = 1
    while cap.isOpened():
        ret, frame = cap.read()
        # 读取失败直接退出循环,不存无效帧
        if not ret:
            break
        cv2.imwrite(path_in + f"frame{str(count).zfill(5)}.jpg", frame)
        # 本地读视频不需要waitKey判断,可直接删除
        count += 1
    cap.release()
    cv2.destroyAllWindows()
    print(f"共捕获有效帧{count-1}张,原视频帧率{fps}")
    return fps

修复后的视频合成函数

def make_video(path_out, outvid, fps=25, size=None, is_color=True, format='mp4v'):
    # 筛选后缀改为jpg,按帧号自然排序
    images = sorted([f for f in os.listdir(path_out) if f.endswith(".jpg")], key=lambda x:int(x.split("frame")[1].split(".jpg")[0]))
    if not images:
        raise ValueError(f"路径{path_out}下没有找到jpg格式的帧文件")
    from cv2 import VideoWriter, VideoWriter_fourcc, imread, resize
    fourcc = VideoWriter_fourcc(*'mp4v')
    vid = None
    for idx, image in enumerate(images):
        img_path = os.path.join(path_out, image)
        if not os.path.exists(img_path):
            raise FileNotFoundError(img_path)
        img = imread(img_path)
        if vid is None:
            if size is None:
                size = img.shape[1], img.shape[0]
            vid = VideoWriter(outvid, fourcc, float(fps), size, is_color)
        # 宽或高不匹配就resize,原逻辑的and判断错误
        if size[0] != img.shape[1] or size[1] != img.shape[0]:
            img = resize(img, size)
        vid.write(img)
        if idx % 100 == 0:
            print("Progress: %0.2f%%" % (idx / len(images) * 100,), flush=True)
    vid.release()
    print(f"合成完成,共写入{len(images)}帧,输出帧率{fps}")
    return

调用示例

# 先捕获帧,拿到原视频的真实帧率
source_fps = save_frames("你的原视频路径.mp4", "./帧存储目录/")
# 合成时传入原视频帧率
make_video("./帧存储目录/", "./输出视频路径.mp4", fps=source_fps)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 21:15:02