diff --git a/cht/stream/ffmpeg.py b/cht/stream/ffmpeg.py index 4110cc5..a7c7f90 100644 --- a/cht/stream/ffmpeg.py +++ b/cht/stream/ffmpeg.py @@ -97,13 +97,13 @@ 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 (avoids image2 muxer one-frame buffer) + # → showinfo → MJPEG piped to stdout select_expr = f"gt(scene,{scene_threshold})" scene_stream = stream.filter("select", select_expr).filter("showinfo") scene_out = ffmpeg.output( scene_stream, "pipe:1", f="image2pipe", vcodec="mjpeg", - vsync="vfr", flush_packets=1, **{"q:v": "2"}, + flush_packets=1, **{"q:v": "2", "fps_mode": "passthrough"}, ) return ffmpeg.merge_outputs(file_out, relay_out, scene_out).global_args(*GLOBAL_ARGS) diff --git a/cht/stream/manager.py b/cht/stream/manager.py index 620f303..1952e8b 100644 --- a/cht/stream/manager.py +++ b/cht/stream/manager.py @@ -10,10 +10,8 @@ Architecture: import json import logging -import os import re import time -from queue import Queue, Empty from threading import Thread from cht.config import ( @@ -244,10 +242,9 @@ class StreamManager: - stderr: parses showinfo lines, queues pts_time values - stdout: reads JPEG frames from pipe, pairs with queued timestamps, writes files to disk, fires callbacks immediately - - showinfo fires before the JPEG encoder, so timestamps are always - queued before the corresponding JPEG data arrives on stdout. """ + from queue import Queue, Empty + import os ts_queue = Queue() def _read_stderr(): @@ -269,13 +266,10 @@ class StreamManager: buf = b"" raw_fd = proc.stdout.fileno() while True: - # os.read on the raw fd returns as soon as ANY data is available - # (no Python buffered-IO blocking waiting to fill a buffer) chunk = os.read(raw_fd, 65536) if not chunk: break buf += chunk - # Split JPEG frames by SOI (0xFFD8) and EOI (0xFFD9) markers while True: soi = buf.find(b"\xff\xd8") if soi < 0: @@ -283,12 +277,11 @@ class StreamManager: break eoi = buf.find(b"\xff\xd9", soi + 2) if eoi < 0: - buf = buf[soi:] # keep from SOI, need more data + buf = buf[soi:] break jpeg_data = buf[soi:eoi + 2] buf = buf[eoi + 2:] - # Get timestamp (showinfo fires before encode, so it's queued) try: pts_time = ts_queue.get(timeout=2.0) except Empty: