From a17021e610e0bdb89f32b71b80d6ed9a5bfff961 Mon Sep 17 00:00:00 2001 From: enne2 Date: Mon, 2 Nov 2026 17:54:15 +0100 Subject: [PATCH] Cattura: rimuovi videorate e limita la coda all'ultimo frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La pipeline GStreamer non forza più la frequenza con videorate e usa un appsink con max-buffers=1, drop e enable-last-sample=false: si elabora solo il frame più recente invece di duplicare frame o accumulare ritardo. Il demone rinnova inoltre l'ultimo frame inviato ogni 10 s quando la sorgente a frequenza variabile non produce nuovi campioni (schermata statica), evitando il timeout del firmware Adalight, e usa time.monotonic per il pacing di invio al posto di time.time. --- backend/ambicapture.py | 7 +++---- backend/ambilightd.py | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/backend/ambicapture.py b/backend/ambicapture.py index f2b92ec..e5807cc 100644 --- a/backend/ambicapture.py +++ b/backend/ambicapture.py @@ -79,10 +79,9 @@ class Capture: self.gw = leds * sub self.gh = rows desc = (f"pipewiresrc path={node} do-timestamp=true ! " - f"videoconvert ! videoscale ! videorate ! " - f"video/x-raw,format=RGB,width={self.gw},height={self.gh}," - f"framerate={int(fps)}/1 ! " - f"appsink name=sink emit-signals=false max-buffers=2 drop=true sync=false") + f"videoconvert ! videoscale ! " + f"video/x-raw,format=RGB,width={self.gw},height={self.gh} ! " + f"appsink name=sink emit-signals=false max-buffers=1 drop=true sync=false enable-last-sample=false") self.pipe = Gst.parse_launch(desc) self.sink = self.pipe.get_by_name("sink") diff --git a/backend/ambilightd.py b/backend/ambilightd.py index 715ee4d..7794c3f 100755 --- a/backend/ambilightd.py +++ b/backend/ambilightd.py @@ -208,6 +208,7 @@ def capture_loop(state, strip): last_write = 0.0 t_log = time.time() n_none = 0 + last_frame = None while True: cfg = state.snapshot() if not cfg["running"]: @@ -215,6 +216,7 @@ def capture_loop(state, strip): cap.stop() cap = None prev = None + last_frame = None time.sleep(0.15) continue @@ -239,10 +241,15 @@ def capture_loop(state, strip): frame = cap.frame(200) if frame is None: + # Una sorgente a frequenza variabile può fermarsi su una schermata + # statica; rinnova il frame per il timeout del firmware Adalight. + if last_frame is not None and time.monotonic() - last_write >= 10: + if strip.write(last_frame): + last_write = time.monotonic() n_none += 1 time.sleep(0.005) if time.time() - t_log >= 10: - log(f"diagnostica: 10 s senza frame (timeout={n_none}), " + log(f"diagnostica: attese cattura negli ultimi 10 s (timeout={n_none}), " f"fps={state.fps} sent={sent}") t_log, n_none = time.time(), 0 continue @@ -270,12 +277,13 @@ def capture_loop(state, strip): frame_bits = (6 + 3 * cfg["leds"]) * 10 min_interval = max(1.0 / max(1, cfg["target_fps"]), 1.7 * frame_bits / max(9600, cfg["baud"])) - wait = min_interval - (time.time() - last_write) + wait = min_interval - (time.monotonic() - last_write) if wait > 0: time.sleep(wait) - ok = strip.write(adalight_frame(px)) + last_frame = adalight_frame(px) + ok = strip.write(last_frame) if ok: - last_write = time.time() + last_write = time.monotonic() sent += 1 now = time.time() if now - t_win >= 1.0: