Skip to content

Commit 94965e9

Browse files
committed
WIP: Add QOI codec
Signed-off-by: Marc-André Lureau <[email protected]>
1 parent a3798db commit 94965e9

File tree

19 files changed

+219
-50
lines changed

19 files changed

+219
-50
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
[workspace]
2-
members = [
3-
"crates/*",
4-
"xtask",
5-
"ffi",
6-
]
2+
members = ["crates/*", "xtask", "ffi"]
73
resolver = "2"
84

95
# FIXME: fix compilation
106
exclude = [
11-
"crates/ironrdp-client-glutin",
12-
"crates/ironrdp-glutin-renderer",
13-
"crates/ironrdp-replay-client",
7+
"crates/ironrdp-client-glutin",
8+
"crates/ironrdp-glutin-renderer",
9+
"crates/ironrdp-replay-client",
1410
]
1511

1612
[workspace.package]
1713
edition = "2021"
1814
license = "MIT OR Apache-2.0"
1915
homepage = "https://github.com/Devolutions/IronRDP"
2016
repository = "https://github.com/Devolutions/IronRDP"
21-
authors = ["Devolutions Inc. <[email protected]>", "Teleport <goteleport.com>"]
17+
authors = [
18+
"Devolutions Inc. <[email protected]>",
19+
"Teleport <goteleport.com>",
20+
]
2221
keywords = ["rdp", "remote-desktop", "network", "client", "protocol"]
2322
categories = ["network-programming"]
2423

@@ -61,6 +60,7 @@ bitflags = "2.4"
6160
expect-test = "1"
6261
png = "0.17"
6362
proptest = "1.4"
63+
qoi = "0.4"
6464
rstest = "0.18"
6565
sspi = "0.15"
6666
tracing = { version = "0.1", features = ["log"] }
@@ -82,7 +82,7 @@ unsafe_op_in_unsafe_fn = "warn"
8282
invalid_reference_casting = "warn"
8383

8484
# == Style, readability == #
85-
elided_lifetimes_in_paths = "warn" # https://quinedot.github.io/rust-learning/dont-hide.html
85+
elided_lifetimes_in_paths = "warn" # https://quinedot.github.io/rust-learning/dont-hide.html
8686
absolute_paths_not_starting_with_crate = "warn"
8787
single_use_lifetimes = "warn"
8888
unreachable_pub = "warn"
@@ -118,14 +118,14 @@ as_underscore = "warn"
118118
large_stack_frames = "warn"
119119

120120
# == Style, readability == #
121-
semicolon_outside_block = "warn" # With semicolon-outside-block-ignore-multiline = true
121+
semicolon_outside_block = "warn" # With semicolon-outside-block-ignore-multiline = true
122122
clone_on_ref_ptr = "warn"
123123
cloned_instead_of_copied = "warn"
124124
trait_duplication_in_bounds = "warn"
125125
type_repetition_in_bounds = "warn"
126126
checked_conversions = "warn"
127127
get_unwrap = "warn"
128-
similar_names = "warn" # Reduce risk of confusing similar names together, and protects against typos when variable shadowing was intended.
128+
similar_names = "warn" # Reduce risk of confusing similar names together, and protects against typos when variable shadowing was intended.
129129
str_to_string = "warn"
130130
string_to_string = "warn"
131131
std_instead_of_core = "warn"

crates/ironrdp-client/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ test = false
2727
default = ["rustls"]
2828
rustls = ["ironrdp-tls/rustls"]
2929
native-tls = ["ironrdp-tls/native-tls"]
30+
qoi = ["ironrdp/qoi"]
3031

3132
[dependencies]
3233

@@ -41,7 +42,7 @@ ironrdp = { workspace = true, features = [
4142
"rdpsnd",
4243
"cliprdr",
4344
"displaycontrol",
44-
"connector"
45+
"connector",
4546
] }
4647
ironrdp-cliprdr-native.workspace = true
4748
ironrdp-rdpsnd-native.workspace = true
@@ -78,7 +79,7 @@ reqwest = "0.12"
7879
url = "2.5"
7980
raw-window-handle = "0.6.2"
8081
ironrdp-core = { workspace = true, features = ["alloc"] }
81-
uuid = { version = "1.12.1"}
82+
uuid = { version = "1.12.1" }
8283

8384
[target.'cfg(windows)'.dependencies]
8485
windows = { workspace = true, features = ["Win32_Foundation"] }

crates/ironrdp-client/src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ impl Config {
263263
Some(connector::BitmapConfig {
264264
color_depth,
265265
lossy_compression: true,
266+
#[cfg(feature = "qoi")]
267+
with_qoi: true,
266268
})
267269
} else {
268270
None

crates/ironrdp-connector/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ test = false
1717

1818
[features]
1919
arbitrary = ["dep:arbitrary"]
20+
qoi = ["ironrdp-pdu/qoi"]
2021

2122
[dependencies]
2223
arbitrary = { version = "1", features = ["derive"], optional = true }

crates/ironrdp-connector/src/connection_activation.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,24 @@ fn create_client_confirm_active(
279279
BitmapDrawingFlags::ALLOW_SKIP_ALPHA
280280
};
281281

282+
#[allow(unused_mut)]
283+
let mut bitmap_codecs = vec![Codec {
284+
id: 0x03, // RemoteFX
285+
property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer(RfxClientCapsContainer {
286+
capture_flags: CaptureFlags::empty(),
287+
caps_data: RfxCaps(RfxCapset(vec![RfxICap {
288+
flags: RfxICapFlags::empty(),
289+
entropy_bits: EntropyBits::Rlgr3,
290+
}])),
291+
})),
292+
}];
293+
294+
#[cfg(feature = "qoi")]
295+
bitmap_codecs.push(Codec {
296+
id: 0x0A, // QOI
297+
property: CodecProperty::QOI,
298+
});
299+
282300
server_capability_sets.extend_from_slice(&[
283301
CapabilitySet::General(General {
284302
major_platform_type: config.platform,
@@ -355,16 +373,7 @@ fn create_client_confirm_active(
355373
CapabilitySet::SurfaceCommands(SurfaceCommands {
356374
flags: CmdFlags::SET_SURFACE_BITS | CmdFlags::STREAM_SURFACE_BITS | CmdFlags::FRAME_MARKER,
357375
}),
358-
CapabilitySet::BitmapCodecs(BitmapCodecs(vec![Codec {
359-
id: 0x03, // RemoteFX
360-
property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer(RfxClientCapsContainer {
361-
capture_flags: CaptureFlags::empty(),
362-
caps_data: RfxCaps(RfxCapset(vec![RfxICap {
363-
flags: RfxICapFlags::empty(),
364-
entropy_bits: EntropyBits::Rlgr3,
365-
}])),
366-
})),
367-
}])),
376+
CapabilitySet::BitmapCodecs(BitmapCodecs(bitmap_codecs)),
368377
CapabilitySet::FrameAcknowledge(FrameAcknowledge {
369378
// FIXME(#447): Revert this to 2 per FreeRDP.
370379
// This is a temporary hack to fix a resize bug, see:

crates/ironrdp-connector/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ pub struct DesktopSize {
4646
pub struct BitmapConfig {
4747
pub lossy_compression: bool,
4848
pub color_depth: u32,
49+
#[cfg(feature = "qoi")]
50+
pub with_qoi: bool,
4951
}
5052

5153
#[derive(Debug, Clone)]

crates/ironrdp-pdu/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ doctest = false
1919
default = []
2020
std = ["alloc", "ironrdp-error/std", "ironrdp-core/std"]
2121
alloc = ["ironrdp-core/alloc", "ironrdp-error/alloc"]
22+
qoi = []
2223

2324
[dependencies]
2425
bitflags.workspace = true

crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ const GUID_REMOTEFX: Guid = Guid(0x7677_2f12, 0xbd72, 0x4463, 0xaf, 0xb3, 0xb7,
3737
const GUID_IMAGE_REMOTEFX: Guid = Guid(0x2744_ccd4, 0x9d8a, 0x4e74, 0x80, 0x3c, 0x0e, 0xcb, 0xee, 0xa1, 0x9c, 0x54);
3838
#[rustfmt::skip]
3939
const GUID_IGNORE: Guid = Guid(0x9c43_51a6, 0x3535, 0x42ae, 0x91, 0x0c, 0xcd, 0xfc, 0xe5, 0x76, 0x0b, 0x58);
40+
#[rustfmt::skip]
41+
#[cfg(feature="qoi")]
42+
const GUID_QOI: Guid = Guid(0x4dae9af8, 0xb399, 0x4df6, 0xb4, 0x3a, 0x66, 0x2f, 0xd9, 0xc0, 0xf5, 0xd6);
4043

4144
#[derive(Debug, PartialEq, Eq)]
4245
pub struct Guid(u32, u16, u16, u8, u8, u8, u8, u8, u8, u8, u8);
@@ -164,6 +167,8 @@ impl Encode for Codec {
164167
CodecProperty::RemoteFx(_) => GUID_REMOTEFX,
165168
CodecProperty::ImageRemoteFx(_) => GUID_IMAGE_REMOTEFX,
166169
CodecProperty::Ignore => GUID_IGNORE,
170+
#[cfg(feature = "qoi")]
171+
CodecProperty::QOI => GUID_QOI,
167172
_ => return Err(other_err!("invalid codec")),
168173
};
169174
guid.encode(dst)?;
@@ -201,6 +206,8 @@ impl Encode for Codec {
201206
}
202207
};
203208
}
209+
#[cfg(feature = "qoi")]
210+
CodecProperty::QOI => dst.write_u16(0),
204211
CodecProperty::Ignore => dst.write_u16(0),
205212
CodecProperty::None => dst.write_u16(0),
206213
};
@@ -224,6 +231,8 @@ impl Encode for Codec {
224231
RemoteFxContainer::ClientContainer(container) => container.size(),
225232
RemoteFxContainer::ServerContainer(size) => *size,
226233
},
234+
#[cfg(feature = "qoi")]
235+
CodecProperty::QOI => 0,
227236
CodecProperty::Ignore => 0,
228237
CodecProperty::None => 0,
229238
}
@@ -258,6 +267,8 @@ impl<'de> Decode<'de> for Codec {
258267
_ => unreachable!(),
259268
}
260269
}
270+
#[cfg(feature = "qoi")]
271+
GUID_QOI => CodecProperty::QOI,
261272
GUID_IGNORE => CodecProperty::Ignore,
262273
_ => CodecProperty::None,
263274
}
@@ -269,6 +280,8 @@ impl<'de> Decode<'de> for Codec {
269280
"invalid codec property length"
270281
));
271282
}
283+
#[cfg(feature = "qoi")]
284+
GUID_QOI => CodecProperty::QOI,
272285
GUID_IGNORE => CodecProperty::Ignore,
273286
_ => CodecProperty::None,
274287
}
@@ -290,6 +303,8 @@ pub enum CodecProperty {
290303
RemoteFx(RemoteFxContainer),
291304
ImageRemoteFx(RemoteFxContainer),
292305
Ignore,
306+
#[cfg(feature = "qoi")]
307+
QOI,
293308
None,
294309
}
295310

crates/ironrdp-server/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ test = false
1919
default = ["rayon"]
2020
helper = ["dep:x509-cert", "dep:rustls-pemfile"]
2121
rayon = ["dep:rayon"]
22+
qoi = ["dep:qoi", "ironrdp-pdu/qoi"]
2223

2324
# Internal (PRIVATE!) features used to aid testing.
2425
# Don't rely on these whatsoever. They may disappear at any time.
@@ -45,6 +46,7 @@ tracing.workspace = true
4546
x509-cert = { version = "0.2.5", optional = true }
4647
rustls-pemfile = { version = "2.2.0", optional = true }
4748
rayon = { version = "1.10.0", optional = true }
49+
qoi = { workspace = true, optional = true }
4850

4951
[dev-dependencies]
5052
tokio = { version = "1", features = ["sync"] }

crates/ironrdp-server/src/builder.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub struct BuilderDone {
3030
display: Box<dyn RdpServerDisplay>,
3131
cliprdr_factory: Option<Box<dyn CliprdrServerFactory>>,
3232
sound_factory: Option<Box<dyn SoundServerFactory>>,
33+
#[cfg(feature = "qoi")]
34+
with_qoi: bool,
3335
}
3436

3537
pub struct RdpServerBuilder<State> {
@@ -125,6 +127,8 @@ impl RdpServerBuilder<WantsDisplay> {
125127
sound_factory: None,
126128
cliprdr_factory: None,
127129
with_remote_fx: true,
130+
#[cfg(feature = "qoi")]
131+
with_qoi: true,
128132
},
129133
}
130134
}
@@ -139,6 +143,8 @@ impl RdpServerBuilder<WantsDisplay> {
139143
sound_factory: None,
140144
cliprdr_factory: None,
141145
with_remote_fx: true,
146+
#[cfg(feature = "qoi")]
147+
with_qoi: true,
142148
},
143149
}
144150
}
@@ -160,12 +166,20 @@ impl RdpServerBuilder<BuilderDone> {
160166
self
161167
}
162168

169+
#[cfg(feature = "qoi")]
170+
pub fn with_qoi(mut self, enabled: bool) -> Self {
171+
self.state.with_qoi = enabled;
172+
self
173+
}
174+
163175
pub fn build(self) -> RdpServer {
164176
RdpServer::new(
165177
RdpServerOptions {
166178
addr: self.state.addr,
167179
security: self.state.security,
168180
with_remote_fx: self.state.with_remote_fx,
181+
#[cfg(feature = "qoi")]
182+
with_qoi: self.state.with_qoi,
169183
},
170184
self.state.handler,
171185
self.state.display,

0 commit comments

Comments
 (0)