Video export: keep encoded segments on failure, fall back to cuts, report ffmpeg exit status - #194
Merged
Merged
Conversation
With -loglevel error a process killed from outside (e.g. OOM) writes nothing, so the UI showed a bare 'ffmpeg failed:'. Include the exit status in the error and log the full command and stderr. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkwxQ29m5Zfq3XfaEjDyeZ
… if the crossfade stitch fails A render that died at the stitch threw away every encoded segment, and a retry (a new job) re-encoded all of them. Segments are now filed in a content-keyed cache (hard links, pruned after 48h, discarded on success), so a retry - even with a different transition - only encodes what changed. The crossfade (xfade) stitch holds every segment open at once and is what gets OOM-killed on a small host. If it fails, join with straight cuts and warn rather than failing a render whose encoding is finished. Also fixes the run() failure test added earlier, which had a class-scope bug. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkwxQ29m5Zfq3XfaEjDyeZ
davior
marked this pull request as ready for review
September 30, 2026 11:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A video export failed with a bare
ffmpeg failed:. Host logs showed the kernel OOM-killedffmpegduring the crossfade (xfade) stitch (Circle transition) — the one step that holds every segment open at once — after all segments had already been encoded. Because the scratch dir is always removed and a retry is a new job, every segment was thrown away and had to be re-encoded.Changes
ffmpeg.run(): the error now includes the exit status (killed by signal 9 (most likely out of memory)), and the full argv + stderr are logged. Previously-loglevel error+ a signal kill produced an empty message.video/shot_cache.py(new): encoded segments are filed under a fingerprint of the exact ffmpeg command plus input content (not the job id or whole options), as hard links. A retry — even with a different transition — reuses unchanged segments. Entries are discarded on success and pruned after 48h.renderer.py: uses the cache per shot (replaying the "rendered without motion" warning on reuse); if the xfade stitch fails, it falls back to a plain cut join with a warning and rebuilds chapters/subtitles for the un-overlapped timeline.Tests
tests/test_video_shot_cache.py– fingerprinting, hit/miss, plain-fallback marker, cleanup, prune.tests/test_video_render_resume.py– drives realrender()with a faked ffmpeg: crossfade fallback, failed render keeps segments and retry reuses them, segment-affecting changes miss the cache.tests/test_video_ffmpeg.py– exit-status message.Not verified against a real ffmpeg (none in the dev sandbox). Cache/fallback behaviour is covered with a fake; worth one real export on the server.
🤖 Generated with Claude Code
https://claude.ai/code/session_01QkwxQ29m5Zfq3XfaEjDyeZ
Generated by Claude Code