足部录像版本优化
This commit is contained in:
parent
70cf89501a
commit
97ccc120d7
@ -12,7 +12,7 @@ import base64
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import Optional, Dict, Any, Tuple
|
from typing import Optional, Dict, Any, Tuple
|
||||||
import logging
|
import logging
|
||||||
from collections import deque
|
import queue
|
||||||
import gc
|
import gc
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -60,7 +60,7 @@ class CameraManager(BaseDevice):
|
|||||||
# 流控制
|
# 流控制
|
||||||
self.streaming_thread = None
|
self.streaming_thread = None
|
||||||
# 减小缓存长度,保留最近2帧即可,避免累计占用
|
# 减小缓存长度,保留最近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.last_frame = None
|
||||||
self.frame_count = 0
|
self.frame_count = 0
|
||||||
self.dropped_frames = 0
|
self.dropped_frames = 0
|
||||||
@ -82,11 +82,8 @@ class CameraManager(BaseDevice):
|
|||||||
'dropped_frames': 0
|
'dropped_frames': 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# 全局帧缓存(用于录制)
|
# 全局帧队列(用于录制)
|
||||||
self.global_frame_cache = {}
|
self.frame_queue = queue.Queue(maxsize=10) # 最大长度10,自动丢弃旧帧
|
||||||
self.frame_cache_lock = threading.Lock()
|
|
||||||
self.max_cache_size = 10
|
|
||||||
self.cache_timeout = 5.0 # 5秒超时
|
|
||||||
|
|
||||||
# OpenCV优化开关
|
# OpenCV优化开关
|
||||||
try:
|
try:
|
||||||
@ -334,15 +331,29 @@ class CameraManager(BaseDevice):
|
|||||||
# 重置丢帧计数
|
# 重置丢帧计数
|
||||||
self.dropped_frames = 0
|
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)
|
processed_frame = self._process_frame(frame)
|
||||||
|
|
||||||
# 缓存帧(不复制,减少内存占用)
|
# # 缓存帧(不复制,减少内存占用)
|
||||||
self.last_frame = processed_frame
|
# self.last_frame = processed_frame
|
||||||
self.frame_cache.append(processed_frame)
|
# self.frame_cache.append(processed_frame)
|
||||||
|
|
||||||
# 发送帧数据
|
# 发送帧数据
|
||||||
self._send_frame_data(processed_frame)
|
self._send_frame_data(processed_frame)
|
||||||
@ -530,15 +541,7 @@ class CameraManager(BaseDevice):
|
|||||||
self.logger.error(f"捕获图像异常: {e}")
|
self.logger.error(f"捕获图像异常: {e}")
|
||||||
return None
|
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):
|
def disconnect(self):
|
||||||
"""
|
"""
|
||||||
@ -574,12 +577,20 @@ class CameraManager(BaseDevice):
|
|||||||
pass
|
pass
|
||||||
self.cap = None
|
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
|
self.last_frame = None
|
||||||
|
|
||||||
# 清理全局帧缓存
|
# 清理帧队列
|
||||||
with self.frame_cache_lock:
|
while not self.frame_queue.empty():
|
||||||
self.global_frame_cache.clear()
|
try:
|
||||||
|
self.frame_queue.get_nowait()
|
||||||
|
except queue.Empty:
|
||||||
|
break
|
||||||
|
|
||||||
super().cleanup()
|
super().cleanup()
|
||||||
self.logger.info("相机资源清理完成")
|
self.logger.info("相机资源清理完成")
|
||||||
@ -618,48 +629,34 @@ class CameraManager(BaseDevice):
|
|||||||
self.logger.error(f'保存帧到缓存失败: {e}')
|
self.logger.error(f'保存帧到缓存失败: {e}')
|
||||||
|
|
||||||
def _get_latest_frame_from_cache(self, frame_type='camera'):
|
def _get_latest_frame_from_cache(self, frame_type='camera'):
|
||||||
"""从缓存获取最新帧"""
|
"""从队列获取最新帧"""
|
||||||
try:
|
try:
|
||||||
with self.frame_cache_lock:
|
if self.frame_queue.empty():
|
||||||
if frame_type not in self.global_frame_cache:
|
self.logger.debug('帧队列为空')
|
||||||
self.logger.debug(f'缓存中不存在帧类型: {frame_type}, 可用类型: {list(self.global_frame_cache.keys())}')
|
return None, None
|
||||||
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()
|
|
||||||
|
|
||||||
for frame_type in list(self.global_frame_cache.keys()):
|
# 获取队列中的所有帧,保留最新的一个
|
||||||
expired_keys = []
|
frames = []
|
||||||
for timestamp in self.global_frame_cache[frame_type].keys():
|
while not self.frame_queue.empty():
|
||||||
if current_time - timestamp > self.cache_timeout:
|
try:
|
||||||
expired_keys.append(timestamp)
|
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:
|
except Exception as e:
|
||||||
self.logger.error(f'清理过期帧失败: {e}')
|
self.logger.error(f'从队列获取帧失败: {e}')
|
||||||
|
return None, None
|
||||||
|
@ -173,14 +173,17 @@ class RecordingManager:
|
|||||||
# 初始化屏幕录制写入器
|
# 初始化屏幕录制写入器
|
||||||
# record_size = self.screen_region[2:4] if self.screen_region else self.screen_size
|
# record_size = self.screen_region[2:4] if self.screen_region else self.screen_size
|
||||||
# print('屏幕写入器的宽高..............',record_size)
|
# print('屏幕写入器的宽高..............',record_size)
|
||||||
self.screen_video_writer = cv2.VideoWriter(
|
# self.screen_video_writer = cv2.VideoWriter(
|
||||||
screen_video_path, fourcc, fps, (self.screen_size[0],self.screen_size[1])
|
# 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}')
|
self.logger.info(f'屏幕视频写入器初始化成功: {screen_video_path}')
|
||||||
else:
|
elif self.screen_video_writer:
|
||||||
self.logger.error(f'屏幕视频写入器初始化失败: {screen_video_path}')
|
self.logger.error(f'屏幕视频写入器初始化失败: {screen_video_path}')
|
||||||
|
else:
|
||||||
|
self.logger.info('屏幕录制功能暂时禁用')
|
||||||
|
|
||||||
# 重置停止事件
|
# 重置停止事件
|
||||||
self.recording_stop_event.clear()
|
self.recording_stop_event.clear()
|
||||||
@ -195,13 +198,13 @@ class RecordingManager:
|
|||||||
)
|
)
|
||||||
self.feet_recording_thread.start()
|
self.feet_recording_thread.start()
|
||||||
|
|
||||||
if self.screen_video_writer:
|
# if self.screen_video_writer:
|
||||||
self.screen_recording_thread = threading.Thread(
|
# self.screen_recording_thread = threading.Thread(
|
||||||
target=self._screen_recording_thread,
|
# target=self._screen_recording_thread,
|
||||||
daemon=True,
|
# daemon=True,
|
||||||
name='ScreenRecordingThread'
|
# name='ScreenRecordingThread'
|
||||||
)
|
# )
|
||||||
self.screen_recording_thread.start()
|
# self.screen_recording_thread.start()
|
||||||
|
|
||||||
result['success'] = True
|
result['success'] = True
|
||||||
result['recording_start_time'] = self.recording_start_time.isoformat()
|
result['recording_start_time'] = self.recording_start_time.isoformat()
|
||||||
|
Loading…
Reference in New Issue
Block a user