Skip to content

Commit 85d8fed

Browse files
author
rdeangel
committed
fix(graphics): don't require CONTEXT block on every progressive frame
Per MS-RDPEGFX 2.2.4.2 the SYNC + CONTEXT blocks establish a codec context once (keyed by codec_context_id) and are not repeated on subsequent frames that reference the same context. The decoder's strict requirement that CONTEXT be present on every decode_bitmap call rejected every frame after the first with MissingBlock("CONTEXT"), freezing the image on the coarse first pass. Real-world servers (xrdp, GNOME Remote Desktop) omit the CONTEXT block on every frame after the first one that established the context. Fall back to the value stored when the context was first created; only error when the very first frame for a context arrives without CONTEXT.
1 parent 2046639 commit 85d8fed

1 file changed

Lines changed: 24 additions & 10 deletions

File tree

crates/ironrdp-graphics/src/progressive.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,16 +1076,30 @@ impl ProgressiveDecoder {
10761076

10771077
let blocks = decode_progressive_stream(bitmap_data)?;
10781078

1079-
// Extract context flags from the CONTEXT block. Per MS-RDPEGFX 2.2.4.2
1080-
// a Progressive stream MUST begin with SYNC + CONTEXT; treat absence as
1081-
// a malformed stream rather than silently defaulting band layout.
1082-
let use_reduce_extrapolate = blocks
1083-
.iter()
1084-
.find_map(|block| match block {
1085-
ProgressiveBlock::Context(ctx) => Some(ctx.uses_reduce_extrapolate()),
1086-
_ => None,
1087-
})
1088-
.ok_or(ProgressiveDecodeError::MissingBlock("CONTEXT"))?;
1079+
// Extract the band-layout flag from the CONTEXT block when present.
1080+
// Per MS-RDPEGFX 2.2.4.2 the SYNC + CONTEXT blocks establish a codec
1081+
// context once (keyed by `codec_context_id`) and are not required to be
1082+
// repeated on subsequent frames that reference the same context.
1083+
// Real-world servers (xrdp, GNOME Remote Desktop) omit the CONTEXT
1084+
// block on every frame after the first one that established the
1085+
// context. The strict requirement rejected each of those frames with
1086+
// `MissingBlock("CONTEXT")`, freezing the image on the coarse first
1087+
// pass.
1088+
//
1089+
// Fall back to the value stored when the context was first created.
1090+
// Only error when neither source is available, i.e. the very first
1091+
// frame for a context arrived without a CONTEXT block.
1092+
let use_reduce_extrapolate = match blocks.iter().find_map(|block| match block {
1093+
ProgressiveBlock::Context(ctx) => Some(ctx.uses_reduce_extrapolate()),
1094+
_ => None,
1095+
}) {
1096+
Some(v) => v,
1097+
None => self
1098+
.contexts
1099+
.get(&codec_context_id)
1100+
.map(|c| c.surface.use_reduce_extrapolate)
1101+
.ok_or(ProgressiveDecodeError::MissingBlock("CONTEXT"))?,
1102+
};
10891103

10901104
// Get or create the context for this codec_context_id
10911105
let context = match self.contexts.entry(codec_context_id) {

0 commit comments

Comments
 (0)