fix(session): decode RGBA QOI bitmaps instead of dropping the frame#1341
Merged
Benoît Cortier (CBenoit) merged 2 commits intoJun 1, 2026
Merged
Conversation
5 tasks
Contributor
|
thanks! lgtm |
3425c87 to
ffa8855
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes the client-side QOI decode path in ironrdp-session so RGBA-channel QOI frames are decoded and applied to the framebuffer instead of being dropped, improving interoperability with third-party RDP servers and older ironrdp-server builds that emit RGBA QOI.
Changes:
- Add
DecodedImage::apply_rgba32/apply_rgba32_iterto blit RGBA32 pixel data (including alpha) into the session framebuffer. - Update
qoi_applyto apply decoded QOI frames for bothqoi::Channels::Rgbandqoi::Channels::Rgba(removing the “Unsupported RGBA QOI data” drop path).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
crates/ironrdp-session/src/image.rs |
Adds an RGBA32 apply path mirroring the existing RGB24 path, preserving the alpha byte. |
crates/ironrdp-session/src/fast_path.rs |
Routes QOI RGBA frames to the new RGBA32 apply function instead of warning + dropping. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
added 2 commits
June 2, 2026 01:39
`qoi_apply` previously dropped `Channels::Rgba` frames with
`warn!("Unsupported RGBA QOI data")`, leaving any server that emits
`*A32`-sourced QOI (the natural mapping from a BGRA / ARGB capture)
rendering blank.
Mirror the existing `apply_rgb24` pair with a 4-bytes-per-pixel
`apply_rgba32` / `apply_rgba32_iter` that copies the alpha byte
through to the framebuffer instead of forcing it to `0xFF`, and call
it from the QOI Rgba arm. The Rgb arm is unchanged.
The screen framebuffer doesn't blend, so on opaque captures the only
observable difference is that the warning is gone and the frame is
applied. Servers carrying real translucent content (layered
compositing, third-party RDP impls) now also work.
qoi_apply fed the decoded buffer straight into apply_rgb24/apply_rgba32, which derive the row count from the decoded length. The only downstream bounds check (rect_fits) validates the rectangle against the image, not the buffer against the rectangle, so an oversized/malformed QOI payload could drive the per-row write index past self.data and panic (client-side DoS). Reject any decode whose length != width*height*channels before applying. Guards both the new RGBA path and the existing RGB path.
ffa8855 to
7c892a0
Compare
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.
Companion to #1335 on the client side. Addresses Marc-Andre Lureau (@elmarco)'s review comment on that PR: "if the server is correctly encoding RGBA bitmap, why not fix the client instead?" — short answer: doing both, because they fix different things and reinforce each other (server-side is also a bandwidth optimization, client-side is correctness against third-party RDP servers).
What's broken
In
crates/ironrdp-session/src/fast_path.rs::qoi_apply, theChannels::Rgbaarm is literally:So any server that emits an
*a-channel QOI header — which is the natural mapping from aBgrA32/ARgb32/ etc. screen capture inironrdp-server::encoder::qoi_encodetoday — gets one warning per frame and a blank window on the viewer. #1335 fixes the server side of that for the in-treeironrdp-server. But:Channels::Rgba. A third-party RDP server that genuinely cares about alpha (layered composition, premultiplied content from a different capture path, etc.) is well within its rights to emit it.ironrdp-serverrelease, every otherironrdp-serverconsumer in the wild keeps emitting RGBA QOI. Clients carrying this patch render those sessions correctly; clients without it don't.So the client-side fix is the durable one. The server-side fix in #1335 stands on its own merits (it's a bandwidth optimization — opaque-capture alpha is always
0xFFand costs one byte per QOI literal chunk for zero information).Fix
Mirror the existing
apply_rgb24/apply_rgb24_iterpair with a 4-bytes-per-pixelapply_rgba32/apply_rgba32_iterthat passes the alpha byte through to the framebuffer (instead of forcing0xFFthe way the rgb24 path does), and call it from the QOI Rgba arm. The Rgb arm is unchanged.The screen framebuffer is a flat RGBA blit target with no blending, so for an opaque-capture server (everything carrying #1335, plus all current in-tree servers) the only observable effect is that the warning is gone and the frame renders. For a server that legitimately encodes translucent content, the alpha byte is now preserved end-to-end.
Reproduction (before the fix)
Built
ironrdp-viewerwith--features qoiand pointed it atmacrdp0.5.50 with its vendored QOI Rgb-only workaround disabled (so it emits the natural RGBA mapping):After the fix
Same loopback session against the same
macrdpbuild, no other changes:Unsupported RGBA QOI datawarningsTest plan
cargo build -p ironrdp-session --features qoi— cleancargo clippy -p ironrdp-session --features qoi --all-targets -- -D warnings— clean (only pre-existing repo-wide MSRV-mismatch notice)cargo test -p ironrdp-session --features qoi— cleancargo fmt --check— cleanironrdp-viewer --features qoiagainst amacrdpbuild emitting RGBA QOI: desktop renders, zero RGBA warningsNotes
apply_rgba32takes the sameflipparameter shape asapply_rgb24for symmetry; QOI calls it withflip = false.