refactor: enhance FFmpegRTSPReader to improve frame reading reliability with retry logic
All checks were successful
Build Worker Base and Application Images / check-base-changes (push) Successful in 8s
Build Worker Base and Application Images / build-base (push) Has been skipped
Build Worker Base and Application Images / build-docker (push) Successful in 2m51s
Build Worker Base and Application Images / deploy-stack (push) Successful in 8s

This commit is contained in:
Siwat Sirichai 2025-09-26 02:26:44 +07:00
parent 84144a2955
commit 2742b86961
2 changed files with 35 additions and 17 deletions

View file

@ -170,27 +170,44 @@ class FFmpegRTSPReader:
if self.frame_ready_event.wait(timeout=restart_check_interval): if self.frame_ready_event.wait(timeout=restart_check_interval):
self.frame_ready_event.clear() self.frame_ready_event.clear()
# Read current frame (file is always exactly one frame) # Read current frame with concurrency safety
try: try:
with open(self.temp_file, 'rb') as f: # Try to read frame multiple times to handle race conditions
frame_data = f.read(bytes_per_frame) frame_data = None
for attempt in range(3):
try:
with open(self.temp_file, 'rb') as f:
frame_data = f.read(bytes_per_frame)
if len(frame_data) == bytes_per_frame: # Validate we got a complete frame
# Convert to numpy array if len(frame_data) == bytes_per_frame:
frame = np.frombuffer(frame_data, dtype=np.uint8) break
frame = frame.reshape((self.height, self.width, 3)) else:
logger.debug(f"Camera {self.camera_id}: Partial read {len(frame_data)}/{bytes_per_frame}, attempt {attempt+1}")
time.sleep(0.01) # Brief wait before retry
# Call frame callback except (IOError, OSError) as e:
if self.frame_callback: logger.debug(f"Camera {self.camera_id}: Read error on attempt {attempt+1}: {e}")
self.frame_callback(self.camera_id, frame) time.sleep(0.01)
frame_count += 1 if frame_data and len(frame_data) == bytes_per_frame:
# Convert to numpy array
frame = np.frombuffer(frame_data, dtype=np.uint8)
frame = frame.reshape((self.height, self.width, 3))
# Log progress # Call frame callback directly - trust the retry logic caught corruption
current_time = time.time() if self.frame_callback:
if current_time - last_log_time >= 30: self.frame_callback(self.camera_id, frame)
logger.info(f"Camera {self.camera_id}: {frame_count} frames processed reactively")
last_log_time = current_time 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} frames processed reactively")
last_log_time = current_time
else:
logger.debug(f"Camera {self.camera_id}: Failed to read complete frame after retries")
except (IOError, OSError) as e: except (IOError, OSError) as e:
logger.debug(f"Camera {self.camera_id}: File read error: {e}") logger.debug(f"Camera {self.camera_id}: File read error: {e}")

View file

@ -6,3 +6,4 @@ redis
urllib3<2.0.0 urllib3<2.0.0
numpy numpy
requests requests
watchdog