fix(engine): reconcile metadata duration after extraction delivers fewer frames (#4371)

When the probed video stream duration is inflated (container duration
fallback includes a longer audio track), FFmpeg delivers far fewer
frames than expected — typically exactly 50% for stock clips whose
audio is 2x the video length. The coverage gate then aborts the
render because it sees 50% coverage against the inflated expectation.

After extraction, if FFmpeg delivered <=60% of the predicted frames,
correct `metadata.videoStreamDurationSeconds` to the actual video
extent. This reconciliation feeds through to the coverage check via
the same `metadata` reference, so `expectedFramesForVideo` sees the
true duration without any interface changes.

This is a corrective complement to the preventive nb_frames
cross-check in extractMediaMetadata — it catches cases where
nb_frames is unavailable (MKV, live streams, fragmented MP4).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
xiayewang-heygen
2026-09-23 23:06:37 +00:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 5c3f02c855
commit b021cb77be
@@ -923,6 +923,20 @@ export async function extractVideoFramesRange(
);
}
// Post-extraction reconciliation: when FFmpeg delivers <=60% of the
// frames predicted by the probed duration, the duration is likely
// inflated (container duration includes a longer audio track). Correct
// it so downstream coverage accounting uses the actual video extent.
if (framePaths.size > 0 && duration > 0 && !options.finalFrameOnly) {
const expectedAtFps = extractionFrameCountForDuration(duration, normalizedFps, metadata.isVFR);
if (expectedAtFps > 0 && framePaths.size <= expectedAtFps * 0.6) {
const correctedDuration = startTime + framePaths.size / fps;
if (correctedDuration < metadata.videoStreamDurationSeconds) {
metadata.videoStreamDurationSeconds = correctedDuration;
}
}
}
return {
videoId,
srcPath: videoPath,