fix: diagnose split-export stalls and serialize encoder-heavy exports#176
Merged
Conversation
Frame-accurate clip splits could hang until the fixed 120s watchdog with no context on why. Measured on a connected iPad + macOS: the split does a genuine multi-second re-encode for high-res clips (~19s for a 31s 4K clip, ~1.4s for a 6s 4K clip), and concurrent split + render encodes starve each other on the shared hardware encoder (3x concurrent 4K: ~43s each vs ~19s alone; 12x: up to ~22s each). On a throttled device a starved session can sit at 0% until the watchdog — the reported split "freeze". - Diagnostic timeouts (iOS, macOS, Android): the stall (no forward progress for stallTimeout, default 12s) and hard (exportTimeout, default 120s) failures now carry context - which half, last progress, segment/split/total durations, preset/mime, audio - with identical message structure across platforms. - exportTimeout / stallTimeout are configurable on SplitVideoModel; defaults preserve the previous behavior and successful splits are unaffected. - iOS, macOS: a process-wide ExportGate serializes encoder-heavy exports (split halves + renders) so they no longer starve each other; the queue wait happens before the per-export watchdog starts. Passthrough/stream-copy exports (no encoder) stay ungated. - Tests: Dart method-channel param tests, Android SplitExportDiagnostics unit tests, a stacked-re-encode integration regression probe, and an integration test that a healthy split honors custom timeouts. Also raises the example iOS deployment target 12.1 -> 15.0 (it was inconsistent with the 15.0 Podfile and broke the SPM build against file_picker, which now requires 14.0).
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 frame-accurate clip split (
splitVideo) could hang until the fixed 120 s watchdog and fail with a generic message:No context on which half, what progress, or why — so the failure was un-actionable. Reported on iOS (26.5, release); the affected clip was the product of ~5 sequential splits of the same source, with parallel speed-renders running over the same export path.
What I measured (iPad + macOS, on-device)
The split feature itself is correct (all integration tests pass). The timings tell the real story — same
SplitVideo.swifton iOS/macOS:Concurrency contention (macOS, 3× concurrent 4K):
So the root cause is genuine encoder-heavy work starved by contention: concurrent split + render encodes fight over the one hardware encoder, each ~2–3× slower, and on a throttled device a starved session sits at
progress == 0until the watchdog.Changes
Split export stalled after 12s with no progress [half=end progress=0.00 segment=0.52s split=0.53s total=1.05s preset=… audio=false](
preseton Darwin,mimeon Android).stallTimeout(default 12 s) it is force-cancelled early, instead of waiting out the full 120 s. The hardexportTimeout(default 120 s) remains the outer bound.SplitVideoModel(exportTimeout,stallTimeout). Defaults preserve prior behavior; successful splits are unaffected.ExportGate(iOS/macOS). A process-wide gate serializes encoder-heavy exports (split halves + renders) so they no longer starve each other. The queue wait happens before the per-export watchdog starts, so it never counts as a stall. Passthrough/stream-copy exports stay ungated.SplitExportDiagnosticsunit tests, a stacked-re-encode integration regression probe, and a "healthy split honors custom timeouts" integration test.example/iosdeployment target 12.1 → 15.0 (it was inconsistent with the 15.0 Podfile and broke the SPM build againstfile_picker, which now requires 14.0).Verification
flutter test(255 tests) +flutter analyzeclean.:pro_video_editor:testDebugUnitTestgreen (incl. new diagnostics tests); module compiles.split_video_test.dartintegration suite green on a connected iPad and on macOS with the gate, including cancel-mid-split.Honest limitations
half=…, progress=0.00).Follow-ups
ExportGateon Android (Media3Transformer) for parity — to be verified on a physical Android device.