diff --git a/core/streaming/readers.py b/core/streaming/readers.py index b623c49..e6eed55 100644 --- a/core/streaming/readers.py +++ b/core/streaming/readers.py @@ -94,8 +94,8 @@ class FFmpegRTSPReader: self.temp_file = f"/tmp/claude/camera_{self.camera_id.replace(' ', '_')}.raw" os.makedirs("/tmp/claude", exist_ok=True) - # Change to JPG format which properly supports -update 1 - self.temp_file = f"/tmp/claude/camera_{self.camera_id.replace(' ', '_')}.jpg" + # Use PPM format - uncompressed with header, supports -update 1 + self.temp_file = f"/tmp/claude/camera_{self.camera_id.replace(' ', '_')}.ppm" cmd = [ 'ffmpeg', @@ -104,8 +104,8 @@ class FFmpegRTSPReader: '-rtsp_transport', 'tcp', '-i', self.rtsp_url, '-f', 'image2', - '-update', '1', # This actually works with image2 format - '-q:v', '2', # High quality JPEG + '-update', '1', # Works with image2 format + '-pix_fmt', 'rgb24', # PPM uses RGB not BGR '-an', # No audio '-y', # Overwrite output file self.temp_file @@ -176,39 +176,28 @@ class FFmpegRTSPReader: if self.frame_ready_event.wait(timeout=restart_check_interval): self.frame_ready_event.clear() - # Read JPEG frame with concurrency safety + # Read PPM frame (uncompressed with header) try: - # Try to read JPEG multiple times to handle race conditions - frame = None - for attempt in range(3): - try: - # Read and decode JPEG directly - frame = cv2.imread(self.temp_file) + if os.path.exists(self.temp_file): + # Read PPM with OpenCV (handles RGB->BGR conversion automatically) + frame = cv2.imread(self.temp_file) - if frame is not None and frame.shape == (self.height, self.width, 3): - break - else: - logger.debug(f"Camera {self.camera_id}: Invalid frame shape or None, attempt {attempt+1}") - time.sleep(0.01) # Brief wait before retry + if frame is not None and frame.shape == (self.height, self.width, 3): + # Call frame callback directly + if self.frame_callback: + self.frame_callback(self.camera_id, frame) - except (IOError, OSError) as e: - logger.debug(f"Camera {self.camera_id}: Read error on attempt {attempt+1}: {e}") - time.sleep(0.01) + frame_count += 1 - if frame is not None: - # Call frame callback directly - if self.frame_callback: - self.frame_callback(self.camera_id, frame) - - frame_count += 1 - - # Log progress - current_time = time.time() - if current_time - last_log_time >= 30: - logger.info(f"Camera {self.camera_id}: {frame_count} JPEG frames processed reactively") - last_log_time = current_time + # Log progress + current_time = time.time() + if current_time - last_log_time >= 30: + logger.info(f"Camera {self.camera_id}: {frame_count} PPM frames processed reactively") + last_log_time = current_time + else: + logger.debug(f"Camera {self.camera_id}: Invalid PPM frame") else: - logger.debug(f"Camera {self.camera_id}: Failed to read valid JPEG after retries") + logger.debug(f"Camera {self.camera_id}: PPM file not found yet") except (IOError, OSError) as e: logger.debug(f"Camera {self.camera_id}: File read error: {e}")