fix: validate pause points and frame extraction
- Get video duration BEFORE the render loop (not after) - Clamp pause_point to 100ms before video end if it exceeds duration - Add validation in _extract_frame() to verify frame was created - Add debug logging for frame extraction timestamps This prevents "Frame file not found" errors when pause points calculated by Whisper refinement exceed the source video duration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
40ece78652
commit
37f5e8d1b0
1 changed files with 24 additions and 2 deletions
|
|
@ -307,7 +307,8 @@ class VideoRendererService:
|
|||
|
||||
# Get detailed video AND audio properties for uniform encoding
|
||||
video_props = await self._get_video_properties(source_video_path)
|
||||
logger.info(f"Source Properties: {video_props}")
|
||||
source_duration = await self._get_video_duration(source_video_path)
|
||||
logger.info(f"Source Properties: {video_props}, Duration: {source_duration:.2f}s")
|
||||
|
||||
segment_files = []
|
||||
current_time = 0.0
|
||||
|
|
@ -320,6 +321,18 @@ class VideoRendererService:
|
|||
cue_index = placement["ad_cue_index"]
|
||||
ad_duration = placement["ad_duration"]
|
||||
resume_from = placement.get("resume_from", pause_point) # Fallback for backwards compat
|
||||
|
||||
# Validate pause_point is within video bounds
|
||||
if pause_point >= source_duration:
|
||||
logger.warning(
|
||||
f"Cue {cue_index}: pause_point {pause_point:.2f}s exceeds video duration "
|
||||
f"{source_duration:.2f}s, clamping to {source_duration - 0.1:.2f}s"
|
||||
)
|
||||
pause_point = max(0, source_duration - 0.1) # Clamp to 100ms before end
|
||||
|
||||
if resume_from >= source_duration:
|
||||
resume_from = pause_point
|
||||
|
||||
overlap = max(0, pause_point - resume_from)
|
||||
|
||||
# Get the AD audio for this cue
|
||||
|
|
@ -401,7 +414,6 @@ class VideoRendererService:
|
|||
current_time = pause_point
|
||||
|
||||
# 4. Add final segment from last pause point to end (re-encoded for uniformity)
|
||||
source_duration = await self._get_video_duration(source_video_path)
|
||||
logger.info(
|
||||
f"Final segment check: current_time={current_time:.2f}s, "
|
||||
f"source_duration={source_duration:.2f}s, "
|
||||
|
|
@ -550,6 +562,8 @@ class VideoRendererService:
|
|||
|
||||
async def _extract_frame(self, video_path: str, time_point: float, output_path: str):
|
||||
"""Extract a single frame as PNG using ffmpeg."""
|
||||
logger.debug(f"Extracting frame at {time_point:.2f}s from {video_path}")
|
||||
|
||||
cmd = [
|
||||
self.ffmpeg_path,
|
||||
"-y",
|
||||
|
|
@ -561,6 +575,14 @@ class VideoRendererService:
|
|||
]
|
||||
await self._run_ffmpeg(cmd)
|
||||
|
||||
# Verify frame was actually created (FFmpeg can "succeed" but produce nothing
|
||||
# if time_point is beyond video duration)
|
||||
if not os.path.exists(output_path):
|
||||
raise FileNotFoundError(
|
||||
f"Frame extraction failed: no frame created at {time_point:.2f}s "
|
||||
f"(time may be beyond video duration)"
|
||||
)
|
||||
|
||||
async def _create_freeze_segment(
|
||||
self,
|
||||
frame_path: str,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue