From 074925c360bba0d0d0655af1b922de925b65cf38 Mon Sep 17 00:00:00 2001 From: buenosairesam Date: Fri, 3 Apr 2026 11:54:22 -0300 Subject: [PATCH] one behind duplicated, and the correct --- cht/stream/ffmpeg.py | 10 +++++++++- cht/stream/manager.py | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cht/stream/ffmpeg.py b/cht/stream/ffmpeg.py index a7c7f90..7ce4183 100644 --- a/cht/stream/ffmpeg.py +++ b/cht/stream/ffmpeg.py @@ -98,7 +98,15 @@ def receive_record_relay_and_detect(stream_url, output_path, relay_url, # Scene detection: CUDA decode (GPU) → select filter (CPU, lightweight) # → showinfo → MJPEG piped to stdout - select_expr = f"gt(scene,{scene_threshold})" + # + # Flush trick: select the scene-change frame AND the next 2 frames. + # The pipeline has 2 levels of buffering (encoder + muxer), so we + # need 2 flush frames to push the real scene-change frame out. + # mod(selected_n,3) prevents chaining: after 2 flushes, selected_n + # hits a multiple of 3 and the chain stops. + scene_expr = f"gt(scene,{scene_threshold})" + flush_expr = "eq(n,prev_selected_n+1)*mod(selected_n,3)" + select_expr = f"{scene_expr}+{flush_expr}" scene_stream = stream.filter("select", select_expr).filter("showinfo") scene_out = ffmpeg.output( scene_stream, "pipe:1", diff --git a/cht/stream/manager.py b/cht/stream/manager.py index 1952e8b..a7d9eea 100644 --- a/cht/stream/manager.py +++ b/cht/stream/manager.py @@ -263,6 +263,7 @@ class StreamManager: def _read_stdout(): frame_num = start_number offset = self.current_global_offset + last_pts = -1.0 buf = b"" raw_fd = proc.stdout.fileno() while True: @@ -288,6 +289,12 @@ class StreamManager: log.warning("No timestamp for scene frame %d", frame_num) pts_time = 0.0 + # Skip flush frames (within 100ms of previous = duplicate) + if pts_time - last_pts < 0.1: + log.debug("Skipping flush frame at pts=%.3f", pts_time) + continue + last_pts = pts_time + frame_id = f"F{frame_num:04d}" frame_path = self.frames_dir / f"{frame_id}.jpg" frame_path.write_bytes(jpeg_data)