Fix cutter-report clip duration: render full beat / match length
Bug: the report rendered every preview clip at most 3 s, so any beat longer than 3 s (e.g. beat 02 at 8.56 s) only got a fragment in the cutter report and looked wrong. The hard 3 s cap was an early prototype constant that silently truncated normal-length beats. Trailer clip is now the full beat duration so the cutter sees the entire reference beat. Source clip is the full matched duration (may be shorter than the beat when the match drops before the beat ends — that's correct, the cutter needs to see exactly the matched span). A 30 s safety cap stays as a guard against runaway durations but it should never trip on a normal trailer beat. All existing clips were dropped and re-rendered so the report on disk matches the new logic. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -129,7 +129,11 @@ def parse_field(desc: str | None, key: str) -> str:
|
|||||||
STILL_WIDTH = 480
|
STILL_WIDTH = 480
|
||||||
STILL_QUALITY = 4
|
STILL_QUALITY = 4
|
||||||
CLIP_WIDTH = 480
|
CLIP_WIDTH = 480
|
||||||
CLIP_DURATION_S = 3.0
|
# Clips run for the full beat / match duration, with this cap as a safety net
|
||||||
|
# so a runaway match doesn't pull a 60 s preview. Most beats are below 10 s
|
||||||
|
# anyway. The cap should never silently truncate a normal beat — set it well
|
||||||
|
# above any realistic beat length.
|
||||||
|
CLIP_MAX_DURATION_S = 30.0
|
||||||
|
|
||||||
|
|
||||||
def _stale(out: Path, src: Path) -> bool:
|
def _stale(out: Path, src: Path) -> bool:
|
||||||
@@ -265,13 +269,18 @@ def collect_rows(
|
|||||||
if extract_still(source_path, s_still, sjpg):
|
if extract_still(source_path, s_still, sjpg):
|
||||||
source_still = sjpg
|
source_still = sjpg
|
||||||
if with_clips:
|
if with_clips:
|
||||||
tdur = min(CLIP_DURATION_S, max(0.5, beat["end_s"] - beat["start_s"]))
|
# Trailer clip: full beat duration so the cutter sees the entire
|
||||||
|
# reference beat, not an arbitrary-length excerpt.
|
||||||
|
tdur = max(0.5, min(CLIP_MAX_DURATION_S, beat["end_s"] - beat["start_s"]))
|
||||||
tmp4 = clips_dir / f"beat_{bid:02d}_trailer.mp4"
|
tmp4 = clips_dir / f"beat_{bid:02d}_trailer.mp4"
|
||||||
if extract_clip(trailer_path, beat["start_s"], tdur, tmp4):
|
if extract_clip(trailer_path, beat["start_s"], tdur, tmp4):
|
||||||
trailer_clip = tmp4
|
trailer_clip = tmp4
|
||||||
|
# Source clip: full matched duration. May be shorter than the beat
|
||||||
|
# when the match drops out before the beat ends (fade / shot
|
||||||
|
# change in the source); that's intentional — the cutter needs to
|
||||||
|
# see exactly the matched span.
|
||||||
if rec is not None:
|
if rec is not None:
|
||||||
src_dur = max(0.5, rec["out_point_s"] - rec["in_point_s"])
|
sdur = max(0.5, min(CLIP_MAX_DURATION_S, rec["out_point_s"] - rec["in_point_s"]))
|
||||||
sdur = min(CLIP_DURATION_S, src_dur)
|
|
||||||
smp4 = clips_dir / f"beat_{bid:02d}_source.mp4"
|
smp4 = clips_dir / f"beat_{bid:02d}_source.mp4"
|
||||||
if extract_clip(source_path, rec["in_point_s"], sdur, smp4):
|
if extract_clip(source_path, rec["in_point_s"], sdur, smp4):
|
||||||
source_clip = smp4
|
source_clip = smp4
|
||||||
|
|||||||
Reference in New Issue
Block a user