berarr
This commit is contained in:
@@ -56,7 +56,7 @@ class StreamManager:
|
||||
|
||||
@property
|
||||
def recording_path(self):
|
||||
return self.stream_dir / "recording.mkv"
|
||||
return self.stream_dir / "recording.mp4"
|
||||
|
||||
# -- Recording --
|
||||
|
||||
@@ -81,9 +81,13 @@ class StreamManager:
|
||||
def _detect():
|
||||
processed_time = 0.0
|
||||
frame_count = 0
|
||||
idle_cycles = 0 # consecutive cycles with no new frames
|
||||
|
||||
while "stop" not in self._stop_flags:
|
||||
time.sleep(5)
|
||||
# Adaptive sleep: 1s after finding frames, then 2→4→8→10s backoff
|
||||
sleep_secs = 1 if idle_cycles == 0 else min(2, 2 ** idle_cycles)
|
||||
time.sleep(sleep_secs)
|
||||
|
||||
if not self.recording_path.exists():
|
||||
continue
|
||||
|
||||
@@ -91,16 +95,14 @@ class StreamManager:
|
||||
if size < 100_000:
|
||||
continue
|
||||
|
||||
# Get current duration. Use a 6s safety margin — MKV tail can
|
||||
# be corrupt for several seconds after the last flush, causing
|
||||
# ffmpeg to crash even with a 3s margin.
|
||||
# 2s safety margin — fragmented MP4 is valid up to last complete
|
||||
# keyframe fragment (~1 keyframe interval); 2s covers worst case.
|
||||
safe_duration = self._estimate_safe_duration()
|
||||
if safe_duration is None or safe_duration <= processed_time + 8:
|
||||
if safe_duration is None:
|
||||
continue
|
||||
|
||||
# Process from last checkpoint to safe point
|
||||
process_to = safe_duration - 6 # 6s safety margin for MKV tail
|
||||
if process_to <= processed_time:
|
||||
process_to = safe_duration - 2
|
||||
if process_to <= processed_time + 0.5:
|
||||
continue
|
||||
|
||||
log.info("Scene detection: %.1fs → %.1fs", processed_time, process_to)
|
||||
@@ -112,9 +114,12 @@ class StreamManager:
|
||||
|
||||
if new_frames:
|
||||
frame_count += len(new_frames)
|
||||
idle_cycles = 0 # reset — check again quickly
|
||||
log.info("Found %d new scene frames (total: %d)", len(new_frames), frame_count)
|
||||
if self._on_new_frames:
|
||||
self._on_new_frames(new_frames)
|
||||
else:
|
||||
idle_cycles += 1 # back off: 2s, 4s, 8s, 10s
|
||||
|
||||
processed_time = process_to
|
||||
|
||||
@@ -125,13 +130,23 @@ class StreamManager:
|
||||
self._threads["scene_detector"] = t
|
||||
|
||||
def _estimate_safe_duration(self):
|
||||
"""Estimate recording duration. Uses ffprobe, falls back to file size."""
|
||||
"""Estimate recording duration. Uses ffprobe, falls back to file size.
|
||||
|
||||
For fragmented MP4 (empty_moov), format-level duration is 0 so we
|
||||
check stream duration from the last video stream instead.
|
||||
"""
|
||||
try:
|
||||
import ffmpeg as ffmpeg_lib
|
||||
info = ffmpeg_lib.probe(str(self.recording_path))
|
||||
# Format duration works for non-fragmented; 0 for empty_moov fMP4
|
||||
dur = float(info.get("format", {}).get("duration", 0))
|
||||
if dur > 0:
|
||||
return dur
|
||||
# Fragmented MP4: check video stream duration
|
||||
for stream in info.get("streams", []):
|
||||
sdur = float(stream.get("duration", 0))
|
||||
if sdur > 0:
|
||||
return sdur
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user