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

如何用OpenCV保存摄像头流的最后N秒视频

使用OpenCV保存视频流最后N秒的高效方案

当然可以实现,而且有比内存缓冲更靠谱的方案,既能避免内存占用过高,又能减少结束时的延迟。下面介绍两种实用的实现思路:

方案一:先录制完整视频,再裁剪最后N秒

这个方案实现最简单,适合磁盘空间充足的场景。核心思路是先将整个视频流实时写入临时文件,录制结束后再提取最后N秒的内容生成最终文件。

代码示例(Python)

import cv2
import os

def save_last_n_seconds(video_source, output_path, n_seconds):
    # 1. 录制完整视频到临时文件
    temp_file = "temp_full_video.mp4"
    cap = cv2.VideoCapture(video_source)
    
    if not cap.isOpened():
        print("无法打开视频源")
        return
    
    # 获取视频参数
    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    
    # 初始化临时文件写入器
    temp_writer = cv2.VideoWriter(temp_file, fourcc, fps, (width, height))
    
    print("录制中,按q键停止...")
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        temp_writer.write(frame)
        # 监听停止指令
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    
    # 释放资源
    cap.release()
    temp_writer.release()
    cv2.destroyAllWindows()
    
    # 2. 裁剪最后N秒的视频
    temp_cap = cv2.VideoCapture(temp_file)
    total_frames = int(temp_cap.get(cv2.CAP_PROP_FRAME_COUNT))
    # 计算起始帧:总帧数减去N秒对应的帧数
    start_frame = max(0, total_frames - int(fps * n_seconds))
    
    # 初始化最终文件写入器
    final_writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
    
    # 跳转到起始帧
    temp_cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
    while temp_cap.isOpened():
        ret, frame = temp_cap.read()
        if not ret:
            break
        final_writer.write(frame)
    
    # 释放资源并删除临时文件
    temp_cap.release()
    final_writer.release()
    os.remove(temp_file)
    print(f"已完成!最后{n_seconds}秒视频已保存到 {output_path}")

# 使用示例:摄像头编号0,保存最后10秒到output.mp4
save_last_n_seconds(0, "output.mp4", 10)

方案二:分段录制+自动清理旧片段

如果磁盘空间有限,或者需要长时间录制只保留最后N秒(比如监控场景),可以用分段录制的方式:将视频分成固定时长的小片段,只保留最近N秒内的片段,录制结束后合并这些片段。

代码示例(Python)

import cv2
import os
from collections import deque

def save_last_n_seconds_segmented(video_source, output_path, n_seconds, segment_duration=1):
    cap = cv2.VideoCapture(video_source)
    if not cap.isOpened():
        print("无法打开视频源")
        return
    
    # 获取视频参数
    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    
    # 用队列保存最近的片段路径,超过N秒自动丢弃最早的
    max_segments = int(n_seconds / segment_duration)
    segment_queue = deque(maxlen=max_segments)
    segment_frame_count = int(fps * segment_duration)  # 每个片段的帧数
    frame_counter = 0
    segment_idx = 0
    current_segment_writer = None
    
    print("录制中,按q键停止...")
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        
        # 每到新片段的起始帧,初始化新的写入器
        if frame_counter % segment_frame_count == 0:
            segment_path = f"temp_segment_{segment_idx}.mp4"
            current_segment_writer = cv2.VideoWriter(segment_path, fourcc, fps, (width, height))
            segment_queue.append(segment_path)
            segment_idx += 1
        
        current_segment_writer.write(frame)
        frame_counter += 1
        
        # 监听停止指令
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    
    # 关闭最后一个片段的写入器
    if current_segment_writer:
        current_segment_writer.release()
    cap.release()
    cv2.destroyAllWindows()
    
    # 合并所有保留的片段
    final_writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
    for seg_path in segment_queue:
        seg_cap = cv2.VideoCapture(seg_path)
        while seg_cap.isOpened():
            ret, frame = seg_cap.read()
            if not ret:
                break
            final_writer.write(frame)
        seg_cap.release()
        os.remove(seg_path)  # 删除临时片段
    
    final_writer.release()
    print(f"已完成!最后{n_seconds}秒视频已保存到 {output_path}")

# 使用示例:摄像头编号0,保存最后10秒(每1秒一个片段)
save_last_n_seconds_segmented(0, "output_segmented.mp4", 10, segment_duration=1)

方案对比

  • 方案一:实现简单,代码量小,适合短时间录制场景;缺点是需要临时存储完整视频,磁盘占用稍高。
  • 方案二:磁盘和内存占用低,适合长时间录制或磁盘空间有限的场景;缺点是代码稍复杂,需要处理分段合并逻辑。

两种方案都解决了内存缓冲的痛点:实时写入磁盘避免内存溢出,结束时的处理时间远低于内存缓冲一次性写入的延迟。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:01:16