Repository navigation
feat(dgw): drop unchanged frames from finished recordings - #2060
Conversation
Let maintainers know that an action is required on their side
|
|
Implementation notes:
Draft because it needs a cadeau release: cadeau#87 (quantizer range) is merged but not published, so this patches cadeau to git Note Human-tuned, LLM-assisted content. |
4feecc8 to
7718d98
Compare
There was a problem hiding this comment.
🟡 Changes recommended
An output path that aliases the input can truncate the source recording before it is read, creating a critical data-loss risk.
5 open issues
What changed in this PR
This PR adds post-recording WebM compaction to Gateway, using video-streamer to reduce storage for fixed-rate recordings with unchanged pictures.
Changes:
- Re-encodes retained frames as VP8 at a fixed quantizer of 30.
- Runs compaction after remuxing and replaces the recording only when the final output is smaller.
- Adds compaction tests, an example tool, XMF CI coverage, and updated native dependencies.
| File | Description |
|---|---|
testsuite/tests/video_streamer/mod.rs |
Registers compaction integration tests. |
testsuite/tests/video_streamer/compact.rs |
Tests frame retention, timestamps, size savings, and empty inputs. |
testsuite/tests/main.rs |
Registers video-streamer tests. |
testsuite/Cargo.toml |
Adds dependencies for compaction tests. |
devolutions-gateway/src/recording.rs |
Integrates compaction, size-checked replacement, and temporary-file cleanup. |
devolutions-gateway/src/recording.intent.md |
Documents remuxing and replacement guarantees. |
crates/video-streamer/src/lib.rs |
Exports the compaction API. |
crates/video-streamer/src/compact.rs |
Implements frame comparison, VP8 re-encoding, and output generation. |
crates/video-streamer/src/compact.intent.md |
Defines frame-retention and encoding decisions. |
crates/video-streamer/examples/compact.rs |
Adds a command-line compaction example. |
ci/download-cadeau.ps1 |
Updates the native Cadeau release. |
Cargo.toml |
Pins Cadeau patches supporting quantizer controls. |
Cargo.lock |
Records patched dependencies and test additions. |
.github/workflows/ci.yml |
Runs XMF-backed tests on Windows and Linux. |
Review effort: Balanced
|
Before/after numbers from the lab experiment, per scenario. Compaction only replaces a recording when the result is strictly smaller; otherwise the (remuxed) original stays untouched, as in
Note LLM-assisted content (no human feedback). |
Fixed-rate recordings (web sessions at 1 fps) keep growing at the bitrate target even when nothing on screen changes. After a WebM recording is remuxed, Gateway now re-encodes it keeping only the frames whose picture changed, with a quantizer cap so text stays readable, and swaps the file in only when the result is smaller. On lab web recordings that's about -92% idle and -50% active. RDP recordings are already change-driven, so the job gives up early and keeps them as is.
The oracle-markers check requires every new test to name the source of its expected value. No intent or spec states the dedup rules yet, so each test is marked with the fault it catches; each fault was applied by hand and the test failed against it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compaction encoded at the source's average bitrate in the source's codec. On busy recordings that spends bytes above the quality the quantizer cap already guarantees, so the output often came out larger than the original and was thrown away. Kept frames are now encoded as VP8 with the quantizer pinned at 30 and a bitrate high enough that rate control never moves it. On 8 lab recordings (RDP and web, busy and idle, VP8 and VP9 sources) Gateway stores 68.0 MB instead of 84.8 MB out of 116.0 MB, for about the same CPU time and with no visible change lost. VP9 at a fixed quantizer of 25 saves 6.6 MB more for about three times the CPU time. The intent files record the term, the changed-frame rule, the encoding and the remux-then-replace rule, and the compaction tests now cite them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md puts new integration tests in the testsuite crate, so the three compaction tests move there with the few helpers they need. The two markers that cited intent go back to the fault each test catches: the early not-smaller skip inside compact_webm and the "output is less than half" check are not decided by an intent line. Also follows rust-style: comparisons read with < and <=, the block pixel count states its invariant, and a compacted recording logs at debug like the remux next to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The picture size in the WebM header comes from the client and decides two buffers before any frame is decoded, so a recording above 8192 pixels on a side is now skipped as unsupported instead of allocating whatever it declares. The compaction tests skipped themselves when XMF was missing, and CI never provides it to the tests job, so they passed without running. They are now ignored by default, fail loudly without XMF, and a new CI step downloads XMF and runs them on Windows and Linux. Also documents the public compaction types and fixes the example's SAFETY comment and float cast. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
compact_webm now refuses an output path that names the input recording, because creating the output would truncate the recording it reads. When the last frame decodes to no picture (a hidden VP9 frame), there is no picture to keep it with, so the recording is left as it is instead of losing its tail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d694913 to
2ff60e3
Compare
9036cf1
into
master
Moves Gateway to the published cadeau 0.5.4 / xmf-sys 0.4.3 ([cadeau#88](Devolutions/cadeau#88)) and pins the XMF native library to `v2026.10.26.0`. The new crates carry the VPX encoder quantizer range (`XmfVpxEncoder_CreateEx`), which recording compaction in #2060 needs. XMF resolves every symbol at load, so the native library and the crates have to move together. #2060 stacks on top of this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>


Fixed-rate recordings (web sessions at 1 fps) keep growing at the bitrate target even when nothing on screen changes. After a WebM recording is remuxed, Gateway now re-encodes it as VP8 at a fixed quantizer of 30, keeping only the frames whose picture changed, and swaps the file in only when the result is strictly smaller.
On 8 lab recordings (RDP and web, busy and idle, VP8 and VP9 sources) Gateway stores 68.0 MB of 116.0 MB, with no visible change lost. Idle recordings drop to 3–8 % of their size and busy web ones to about 70 %. A busy RDP recording either shrinks a little or comes out larger, and then the original stays.
The encoding costs about 3 CPU seconds per recorded minute on one thread. VP9 at a matching fixed quantizer saved about 6.6 MB more for three times the CPU, which a 2-vCPU Gateway can't spare beside its live sessions.
The rules live in
crates/video-streamer/src/compact.intent.mdand the new Compaction section ofdevolutions-gateway/src/recording.intent.md.