ffmpeg fix

This commit is contained in:
2026-04-03 09:28:03 -03:00
parent 36e8358fc9
commit 3f76670169
5 changed files with 138 additions and 19 deletions

View File

@@ -72,27 +72,23 @@ def extract_scene_frames(input_path, output_dir, scene_threshold=0.10,
meaningfully vs the previous frame. No periodic fallback so static content
produces no spurious frames.
start_time/duration: applied via the select filter expression (NOT as -ss/-t
input options, which break h264 scene detection on MKV).
Uses -ss input seeking for O(1) startup regardless of file size.
pts_time in showinfo output is relative to the seek point.
Returns (stdout, stderr) as decoded strings for timestamp parsing.
"""
scene_expr = f"gt(scene,{scene_threshold})"
# Add time range filter if specified (incremental processing)
time_conditions = []
if start_time > 0:
time_conditions.append(f"gte(t,{start_time})")
# With -ss input seeking, t starts at 0 from the seek point.
# Only need end boundary (duration), start is handled by -ss.
if duration is not None:
time_conditions.append(f"lte(t,{start_time + duration})")
scene_expr = f"({scene_expr})*lte(t,{duration})"
if time_conditions:
time_filter = "*".join(time_conditions)
select_expr = f"({scene_expr})*{time_filter}"
else:
select_expr = scene_expr
input_kwargs = {}
if start_time > 0:
input_kwargs["ss"] = start_time
stream = ffmpeg.input(str(input_path))
stream = stream.filter("select", select_expr).filter("showinfo")
stream = ffmpeg.input(str(input_path), **input_kwargs)
stream = stream.filter("select", scene_expr).filter("showinfo")
output = (
ffmpeg.output(

View File

@@ -68,6 +68,7 @@ class StreamManager:
self._segment_offsets = {0: 0.0} # segment_index → global_offset
self.scene_threshold = SCENE_THRESHOLD
self.readonly = False # True when loaded from existing session
self.telemetry = None # set by window after start
log.info("Session: %s", session_id)
@classmethod
@@ -306,6 +307,8 @@ class StreamManager:
def _detect_scenes(self, start_time, end_time):
"""Run ffmpeg scene detection on a time range. Returns list of new frame entries."""
import time as _time
t0 = _time.monotonic()
duration = end_time - start_time
start_number = self._next_frame_number()
@@ -335,7 +338,8 @@ class StreamManager:
continue
pts_match = re.search(r"pts_time:\s*([\d.]+)", line)
if pts_match:
pts_time = float(pts_match.group(1))
# pts_time is relative to -ss seek point, add start_time for local offset
pts_time = float(pts_match.group(1)) + start_time
frame_id = f"F{frame_num:04d}"
frame_path = self.frames_dir / f"{frame_id}.jpg"
if frame_path.exists():
@@ -350,6 +354,20 @@ class StreamManager:
frame_num += 1
index_path.write_text(json.dumps(index, indent=2))
elapsed_ms = (_time.monotonic() - t0) * 1000
tel = getattr(self, "telemetry", None)
if tel:
tel.metric("scene_detection", {
"start": start_time, "end": end_time,
"duration": duration,
"frames_found": len(new_frames),
"total_frames": len(index),
"threshold": self.scene_threshold,
"elapsed_ms": round(elapsed_ms),
"file_duration": self._estimate_safe_duration() or 0,
})
return new_frames
def capture_now(self, on_new_frames=None):