import cv2 from PyQt5.QtCore import qDebug from .base_thread import BaseThread from .structures import ImageFrame from .utils import gstreamer_pipeline class CaptureThread(BaseThread): def __init__(self, device_id, flip_method=2, drop_if_full=True, api_preference=cv2.CAP_GSTREAMER, resolution=None, use_gst=True, parent=None): """ device_id: device number of the camera. flip_method: 0 for identity, 2 for 180 degree rotation (if the camera is installed up-side-down). drop_if_full: drop the frame if buffer is full. api_preference: cv2.CAP_GSTREAMER for csi cameras, usually cv2.CAP_ANY would suffice. resolution: camera resolution (width, height). """ super(CaptureThread, self).__init__(parent) self.device_id = device_id self.flip_method = flip_method self.use_gst = use_gst self.drop_if_full = drop_if_full self.api_preference = api_preference self.resolution = resolution self.cap = cv2.VideoCapture() # an instance of the MultiBufferManager object, # for synchronizing this thread with other cameras. self.buffer_manager = None def run(self): if self.buffer_manager is None: raise ValueError("This thread has not been binded to any buffer manager yet") while True: self.stop_mutex.lock() if self.stopped: self.stopped = False self.stop_mutex.unlock() break self.stop_mutex.unlock() # save capture time self.processing_time = self.clock.elapsed() # start timer (used to calculate capture rate) self.clock.start() # synchronize with other streams (if enabled for this stream) self.buffer_manager.sync(self.device_id) if not self.cap.grab(): continue # retrieve frame and add it to buffer _, frame = self.cap.retrieve() img_frame = ImageFrame(self.clock.msecsSinceStartOfDay(), frame) self.buffer_manager.get_device(self.device_id).add(img_frame, self.drop_if_full) # update statistics self.update_fps(self.processing_time) self.stat_data.frames_processed_count += 1 # inform GUI of updated statistics self.update_statistics_gui.emit(self.stat_data) qDebug("Stopping capture thread...") # 在surround-view-system-introduction/surround_view/capture_thread.py中修改connect_camera方法 def connect_camera(self): # 如果设备ID是字符串且以rtsp开头,则视为RTSP地址 if isinstance(self.device_id, str) and self.device_id.startswith('rtsp://'): # 使用FFmpeg的H265解码方式打开RTSP流 # 降低延迟参数:-fflags nobuffer -flags low_delay -rtsp_transport tcp ffmpeg_cmd = ( f"rtspsrc location={self.device_id} latency=0 ! " "rtph265depay ! h265parse ! avdec_h265 ! " "videoconvert ! video/x-raw,format=BGR ! appsink" ) self.cap.open(ffmpeg_cmd, cv2.CAP_GSTREAMER) elif self.use_gst: options = gstreamer_pipeline(cam_id=self.device_id, flip_method=self.flip_method) self.cap.open(options, self.api_preference) else: self.cap.open(self.device_id) if not self.cap.isOpened(): qDebug(f"Cannot open camera {self.device_id}") return False # 设置分辨率(RTSP流通常固定分辨率,可根据实际情况调整) if self.resolution is not None: width, height = self.resolution self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width) self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height) return True def disconnect_camera(self): # disconnect camera if it's already opened. if self.cap.isOpened(): self.cap.release() return True # else do nothing and return else: return False def is_camera_connected(self): return self.cap.isOpened()