cap written stream error

This commit is contained in:
Alberto-Audrix committed 2026-08-27 10:29:31 +07:00
1 parent b52e876eed
commit 706f9261fb
3 files changed
+57 -3

No files matched your search

+4
View File
@@ -207,6 +207,10 @@ WARMUP_FRAMES=30
RECONNECT_DELAY_SEC=3
# Maximum reconnection attempts (0 = infinite)
MAX_RECONNECT_ATTEMPTS=0
# Max stream-error log lines per outage (Cannot open / Stream dropped).
# After this, further errors are silent until the stream recovers; then the
# budget resets for the next outage. 0 = unlimited.
STREAM_ERROR_LOG_MAX=3
# Seconds after which a tracked but unseen object is pruned from the active set
TRACKED_PRUNE_SEC=300
+51 -3
View File
@@ -96,6 +96,10 @@ RATE_WINDOW_SEC = int(os.getenv("RATE_WINDOW_SEC", "60"))
WARMUP_FRAMES = int(os.getenv("WARMUP_FRAMES", "30"))
RECONNECT_DELAY_SEC = int(os.getenv("RECONNECT_DELAY_SEC", "3"))
MAX_RECONNECT_ATTEMPTS = int(os.getenv("MAX_RECONNECT_ATTEMPTS", "0"))
# Max stream-error prints per outage (Cannot open / Stream dropped). After this,
# further errors are silent until the stream recovers, then the budget resets.
# 0 = unlimited (old behavior).
STREAM_ERROR_LOG_MAX = int(os.getenv("STREAM_ERROR_LOG_MAX", "3"))
TRACKED_PRUNE_SEC = int(os.getenv("TRACKED_PRUNE_SEC", "300"))
RECORD_VIDEO = os.getenv("RECORD_VIDEO", "false").lower() == "true"
VIDEO_SEGMENT_SEC = int(os.getenv("VIDEO_SEGMENT_SEC", "3600")) # legacy segment mode only
@@ -1168,6 +1172,46 @@ def draw_popups(img, popups, frame_idx):
return alive
class StreamErrorLog:
"""Rate-limit stream error prints to STREAM_ERROR_LOG_MAX per outage.
After the cap, messages are suppressed until note_up() when the stream
is healthy again; the next drop starts a fresh budget.
"""
def __init__(self, max_logs=STREAM_ERROR_LOG_MAX):
self.max_logs = int(max_logs)
self._emitted = 0
self._suppressed = 0
def emit(self, msg: str) -> None:
if self.max_logs <= 0:
print(msg)
return
if self._emitted < self.max_logs:
self._emitted += 1
print(msg)
if self._emitted >= self.max_logs:
print(
f"[{now_str()}] Stream errors capped at {self.max_logs} "
f"this outage — further messages suppressed until stream recovers"
)
else:
self._suppressed += 1
def note_up(self) -> None:
if self._suppressed > 0:
print(
f"[{now_str()}] Stream recovered "
f"(suppressed {self._suppressed} error log(s) during outage)"
)
self._emitted = 0
self._suppressed = 0
stream_error_log = StreamErrorLog()
def connect_stream(source, warmup=WARMUP_FRAMES):
attempts = 0
while not shutdown_requested:
@@ -1178,7 +1222,9 @@ def connect_stream(source, warmup=WARMUP_FRAMES):
raise RuntimeError(
f"Cannot open source after {attempts} attempts: {source}"
)
print(f"Cannot open source, retry in {RECONNECT_DELAY_SEC}s...")
stream_error_log.emit(
f"Cannot open source, retry in {RECONNECT_DELAY_SEC}s..."
)
time.sleep(RECONNECT_DELAY_SEC)
continue
if warmup > 0 and source.lower().startswith(("rtsp://", "http://")):
@@ -1188,6 +1234,7 @@ def connect_stream(source, warmup=WARMUP_FRAMES):
fps = cap.get(cv2.CAP_PROP_FPS)
if not fps or fps <= 1:
fps = OUTPUT_FPS
stream_error_log.note_up()
return cap, w, h, fps
return None, 0, 0, OUTPUT_FPS
@@ -1349,8 +1396,9 @@ def run():
if not IS_LIVE:
break
reconnect_count += 1
print(
f"Stream dropped (attempt {reconnect_count}), reconnecting in {RECONNECT_DELAY_SEC}s..."
stream_error_log.emit(
f"Stream dropped (attempt {reconnect_count}), "
f"reconnecting in {RECONNECT_DELAY_SEC}s..."
)
cap.release()
time.sleep(RECONNECT_DELAY_SEC)
+2
View File
@@ -131,6 +131,8 @@ RATE_WINDOW_SEC=60
WARMUP_FRAMES=30
RECONNECT_DELAY_SEC=3
MAX_RECONNECT_ATTEMPTS=0
# Max stream-error logs per outage; resets when stream recovers. 0 = unlimited.
STREAM_ERROR_LOG_MAX=3
TRACKED_PRUNE_SEC=300
# --- Live stream snapshot ---