From 97ccc120d7b0ede8fbf8617c869bfd9cb6ac73b5 Mon Sep 17 00:00:00 2001 From: zhaozilong12 <405241463@qq.com> Date: Thu, 21 Aug 2025 12:04:14 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B6=B3=E9=83=A8=E5=BD=95=E5=83=8F=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/devices/camera_manager.py | 129 ++++++++++++++--------------- backend/devices/screen_recorder.py | 27 +++--- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/backend/devices/camera_manager.py b/backend/devices/camera_manager.py index ad6326ed..7b2243db 100644 --- a/backend/devices/camera_manager.py +++ b/backend/devices/camera_manager.py @@ -12,7 +12,7 @@ import base64 import numpy as np from typing import Optional, Dict, Any, Tuple import logging -from collections import deque +import queue import gc try: @@ -60,7 +60,7 @@ class CameraManager(BaseDevice): # 流控制 self.streaming_thread = None # 减小缓存长度,保留最近2帧即可,避免累计占用 - self.frame_cache = deque(maxlen=int(config.get('frame_cache_len', 2))) + self.frame_cache = queue.Queue(maxsize=int(config.get('frame_cache_len', 2))) self.last_frame = None self.frame_count = 0 self.dropped_frames = 0 @@ -82,11 +82,8 @@ class CameraManager(BaseDevice): 'dropped_frames': 0 } - # 全局帧缓存(用于录制) - self.global_frame_cache = {} - self.frame_cache_lock = threading.Lock() - self.max_cache_size = 10 - self.cache_timeout = 5.0 # 5秒超时 + # 全局帧队列(用于录制) + self.frame_queue = queue.Queue(maxsize=10) # 最大长度10,自动丢弃旧帧 # OpenCV优化开关 try: @@ -334,15 +331,29 @@ class CameraManager(BaseDevice): # 重置丢帧计数 self.dropped_frames = 0 - # 保存原始帧到全局缓存(用于录制) - self._save_frame_to_cache(frame, 'camera') + # 保存原始帧到队列(用于录制) + try: + self.frame_queue.put_nowait({ + 'frame': frame.copy(), + 'timestamp': time.time() + }) + except queue.Full: + # 队列满时丢弃最旧的帧,添加新帧 + try: + self.frame_queue.get_nowait() # 移除最旧的帧 + self.frame_queue.put_nowait({ + 'frame': frame.copy(), + 'timestamp': time.time() + }) + except queue.Empty: + pass # 队列为空,忽略 # 处理帧(降采样以优化传输负载) processed_frame = self._process_frame(frame) - # 缓存帧(不复制,减少内存占用) - self.last_frame = processed_frame - self.frame_cache.append(processed_frame) + # # 缓存帧(不复制,减少内存占用) + # self.last_frame = processed_frame + # self.frame_cache.append(processed_frame) # 发送帧数据 self._send_frame_data(processed_frame) @@ -530,15 +541,7 @@ class CameraManager(BaseDevice): self.logger.error(f"捕获图像异常: {e}") return None - def get_latest_frame(self) -> Optional[np.ndarray]: - """ - 获取最新帧 - - Returns: - Optional[np.ndarray]: 最新帧,无帧返回None - """ - # 对外提供拷贝,内部保持原对象,避免重复持有 - return self.last_frame.copy() if self.last_frame is not None else None + def disconnect(self): """ @@ -574,12 +577,20 @@ class CameraManager(BaseDevice): pass self.cap = None - self.frame_cache.clear() + # 清理帧缓存 + while not self.frame_cache.empty(): + try: + self.frame_cache.get_nowait() + except queue.Empty: + break self.last_frame = None - # 清理全局帧缓存 - with self.frame_cache_lock: - self.global_frame_cache.clear() + # 清理帧队列 + while not self.frame_queue.empty(): + try: + self.frame_queue.get_nowait() + except queue.Empty: + break super().cleanup() self.logger.info("相机资源清理完成") @@ -618,48 +629,34 @@ class CameraManager(BaseDevice): self.logger.error(f'保存帧到缓存失败: {e}') def _get_latest_frame_from_cache(self, frame_type='camera'): - """从缓存获取最新帧""" + """从队列获取最新帧""" try: - with self.frame_cache_lock: - if frame_type not in self.global_frame_cache: - self.logger.debug(f'缓存中不存在帧类型: {frame_type}, 可用类型: {list(self.global_frame_cache.keys())}') - return None, None - - if not self.global_frame_cache[frame_type]: - self.logger.debug(f'帧类型 {frame_type} 的缓存为空') - return None, None - - # 清理过期帧 - self._cleanup_expired_frames() - - if not self.global_frame_cache[frame_type]: - self.logger.debug(f'清理过期帧后,帧类型 {frame_type} 的缓存为空') - return None, None - - # 获取最新帧 - latest_timestamp = max(self.global_frame_cache[frame_type].keys()) - frame_data = self.global_frame_cache[frame_type][latest_timestamp] - - return frame_data['frame'].copy(), frame_data['timestamp'] - - except Exception as e: - self.logger.error(f'从缓存获取帧失败: {e}') - return None, None - - def _cleanup_expired_frames(self): - """清理过期的缓存帧""" - try: - current_time = time.time() + if self.frame_queue.empty(): + self.logger.debug('帧队列为空') + return None, None - for frame_type in list(self.global_frame_cache.keys()): - expired_keys = [] - for timestamp in self.global_frame_cache[frame_type].keys(): - if current_time - timestamp > self.cache_timeout: - expired_keys.append(timestamp) + # 获取队列中的所有帧,保留最新的一个 + frames = [] + while not self.frame_queue.empty(): + try: + frames.append(self.frame_queue.get_nowait()) + except queue.Empty: + break + + if not frames: + return None, None + + # 获取最新帧(最后一个) + latest_frame = frames[-1] + + # 将最新帧重新放回队列 + try: + self.frame_queue.put_nowait(latest_frame) + except queue.Full: + pass # 队列满时忽略 + + return latest_frame['frame'].copy(), latest_frame['timestamp'] - # 删除过期帧 - for key in expired_keys: - del self.global_frame_cache[frame_type][key] - except Exception as e: - self.logger.error(f'清理过期帧失败: {e}') + self.logger.error(f'从队列获取帧失败: {e}') + return None, None diff --git a/backend/devices/screen_recorder.py b/backend/devices/screen_recorder.py index 176ba69c..e53a4a4e 100644 --- a/backend/devices/screen_recorder.py +++ b/backend/devices/screen_recorder.py @@ -173,14 +173,17 @@ class RecordingManager: # 初始化屏幕录制写入器 # record_size = self.screen_region[2:4] if self.screen_region else self.screen_size # print('屏幕写入器的宽高..............',record_size) - self.screen_video_writer = cv2.VideoWriter( - screen_video_path, fourcc, fps, (self.screen_size[0],self.screen_size[1]) - ) + # self.screen_video_writer = cv2.VideoWriter( + # screen_video_path, fourcc, fps, (self.screen_size[0],self.screen_size[1]) + # ) - if self.screen_video_writer.isOpened(): + # 检查屏幕视频写入器状态(仅在初始化时) + if self.screen_video_writer and self.screen_video_writer.isOpened(): self.logger.info(f'屏幕视频写入器初始化成功: {screen_video_path}') - else: + elif self.screen_video_writer: self.logger.error(f'屏幕视频写入器初始化失败: {screen_video_path}') + else: + self.logger.info('屏幕录制功能暂时禁用') # 重置停止事件 self.recording_stop_event.clear() @@ -195,13 +198,13 @@ class RecordingManager: ) self.feet_recording_thread.start() - if self.screen_video_writer: - self.screen_recording_thread = threading.Thread( - target=self._screen_recording_thread, - daemon=True, - name='ScreenRecordingThread' - ) - self.screen_recording_thread.start() + # if self.screen_video_writer: + # self.screen_recording_thread = threading.Thread( + # target=self._screen_recording_thread, + # daemon=True, + # name='ScreenRecordingThread' + # ) + # self.screen_recording_thread.start() result['success'] = True result['recording_start_time'] = self.recording_start_time.isoformat()