如何用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
相关产品推荐
相关产品推荐

