Repository navigation
fix(recording): flush every packet to the out-of-process muxer - #2643
Merged
Merged
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Member
Author
|
hey @greptileai, please re-review the PR |
This comment has been minimized.
This comment has been minimized.
…en recovery joins the groups
Member
Author
|
@greptileai review |
This branch was successfully deployed
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.
With the experimental out-of-process muxer on (Settings > Experimental), encoded screen video sits in the recorder's memory instead of reaching
cap-muxer, so the muxer that is meant to make recordings survive crashes loses everything a crash catches in flight, and a muxer crash goes unnoticed until stop.flowchart LR E[encoder thread] -->|write_packet| W["BufWriter 1 MiB<br/>(recorder memory)"] W -->|"flushed only at Start / Finish"| P[stdin pipe] --> M[cap-muxer] --> D[(segments)] style W fill:#fddMuxerSubprocesswraps the child's stdin in a 1 MiBBufWriter(crates/recording/src/output_pipeline/oop_muxer.rs:225) andwrite_packetnever flushes it. At screen bitrates that is seconds of video, and on a mostly static screen far more.RespawningMuxerSubprocessnever respawned in practice and every packet after the crash went into the dead pipe.write_packetnow flushes after every packet (one write per packet, 30 to 60 per second). The buffer still assembles each frame's header and payload into a single write.Effect
Engine-verify
crashsuite on Blacksmith macOS (libx264), out-of-process muxer, synthetic 30 fps screen:stop()fails the display track ("subprocess was reaped with unusable output")Respawned muxer kept at its capture time
Once packets reach the child, a killed
cap-muxerreally is replaced, and that path had never run. Recovery finalizes the first muxer's fragments and eachrespawn-Ndirectory into separate files, then joined them with the concat demuxer, which plays each file straight after the previous one. The fragment the killed muxer had open is lost, so everything after it moved earlier by that gap: on thecrash/muxer-kill/oopcase, 144 frames landed 1.2 s early, which would put the rest of the screen track 1.2 s ahead of its audio.concatenate_video_fragments_on_timeline(crates/enc-ffmpeg/src/remux.rs) gives each file a concatdurationequal to the gap to the next file's start, so the next file starts at its capture time and the last frame before the gap is held. It never uses less than the file's own duration, so overlapping files still play end to end, and it falls back to the probed duration when a start time is unknown.RecoveryManager::finalize_to_progressive_mp4_with_validationuses it. Single-group and in-process recordings take the same path as before.crash/muxer-kill/oop, local M4 Max, 3 runstimeline_concat_keeps_a_later_file_at_its_start_timechecks a file starting at 1.0 s stays there (the old join puts it before 0.5 s), andtimeline_concat_plays_overlapping_files_end_to_endcovers overlap. With #2644 merged, everycrash/recorder-kill/oop/*andcrash/muxer-kill/oopcase passes locally, so their xfail entries are removed fromcrates/verify/expectations.toml.every_packet_reaches_the_child_before_the_next_one_is_writtenanda_dead_child_is_reported_on_the_next_packet(oop_muxer.rstests) fail without the flush.finish_preserves_packets_when_a_slow_muxer_takes_more_than_five_secondsnow measures from the packet write, since a muxer that reads nothing for 6 s now blocks the write instead offinish.

Confidence Score: 5/5
The PR appears safe to merge; no new blocking issue was established.Summary
The PR flushes every encoded packet to
cap-muxerand preserves capture-time gaps when joining files from replacement muxers.No new actionable issues were established. Review used the full PR diff because the current and previously reviewed commits have different merge bases with the target commit. Tests were inspected but not run.
Reviews (3) · Last reviewed commit: "fix(recording): keep a respawned muxer's..." · Reviewed by Greptile