ironrdp_pdu/codecs/rfx/
data_messages.rs

1use bit_field::BitField as _;
2use bitflags::bitflags;
3use ironrdp_core::{
4    cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult,
5    ReadCursor, WriteCursor,
6};
7use num_derive::{FromPrimitive, ToPrimitive};
8use num_traits::{FromPrimitive as _, ToPrimitive as _};
9
10use crate::codecs::rfx::Block;
11
12const CONTEXT_ID: u8 = 0;
13const TILE_SIZE: u16 = 0x0040;
14const COLOR_CONVERSION_ICT: u16 = 1;
15const CLW_XFORM_DWT_53_A: u16 = 1;
16const SCALAR_QUANTIZATION: u16 = 1;
17const LRF: bool = true;
18const CBT_REGION: u16 = 0xcac1;
19const NUMBER_OF_TILESETS: u16 = 1;
20const CBT_TILESET: u16 = 0xcac2;
21const IDX: u16 = 0;
22const IS_LAST_TILESET_FLAG: bool = true;
23const RECTANGLE_SIZE: usize = 8;
24
25/// [2.2.2.2.4] TS_RFX_CONTEXT
26///
27/// [2.2.2.2.4]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/bde1ce78-5d9e-44c1-8a15-5843fa12270a
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct ContextPdu {
30    pub flags: OperatingMode,
31    pub entropy_algorithm: EntropyAlgorithm,
32}
33
34impl ContextPdu {
35    const NAME: &'static str = "RfxContext";
36
37    const FIXED_PART_SIZE: usize = 1 /* ctxId */ + 2 /* tileSize */ + 2 /* properties */;
38}
39
40impl Encode for ContextPdu {
41    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
42        ensure_fixed_part_size!(in: dst);
43
44        dst.write_u8(CONTEXT_ID);
45        dst.write_u16(TILE_SIZE);
46
47        let mut properties: u16 = 0;
48        properties.set_bits(0..3, self.flags.bits());
49        properties.set_bits(3..5, COLOR_CONVERSION_ICT);
50        properties.set_bits(5..9, CLW_XFORM_DWT_53_A);
51        properties.set_bits(9..13, self.entropy_algorithm.to_u16().unwrap());
52        properties.set_bits(13..15, SCALAR_QUANTIZATION);
53        properties.set_bit(15, false); // reserved
54        dst.write_u16(properties);
55
56        Ok(())
57    }
58
59    fn name(&self) -> &'static str {
60        Self::NAME
61    }
62
63    fn size(&self) -> usize {
64        Self::FIXED_PART_SIZE
65    }
66}
67
68impl<'de> Decode<'de> for ContextPdu {
69    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
70        ensure_fixed_part_size!(in: src);
71
72        let id = src.read_u8();
73        if id != CONTEXT_ID {
74            return Err(invalid_field_err!("ctxId", "Invalid context ID"));
75        }
76
77        let tile_size = src.read_u16();
78        if tile_size != TILE_SIZE {
79            return Err(invalid_field_err!("tileSize", "Invalid tile size"));
80        }
81
82        let properties = src.read_u16();
83        let flags = OperatingMode::from_bits_truncate(properties.get_bits(0..3));
84        let color_conversion_transform = properties.get_bits(3..5);
85        if color_conversion_transform != COLOR_CONVERSION_ICT {
86            return Err(invalid_field_err!("cct", "Invalid color conversion transform"));
87        }
88
89        let dwt = properties.get_bits(5..9);
90        if dwt != CLW_XFORM_DWT_53_A {
91            return Err(invalid_field_err!("dwt", "Invalid DWT"));
92        }
93
94        let entropy_algorithm_bits = properties.get_bits(9..13);
95        let entropy_algorithm = EntropyAlgorithm::from_u16(entropy_algorithm_bits)
96            .ok_or_else(|| invalid_field_err!("entropy_algorithm", "Invalid entropy algorithm"))?;
97
98        let quantization_type = properties.get_bits(13..15);
99        if quantization_type != SCALAR_QUANTIZATION {
100            return Err(invalid_field_err!("qt", "Invalid quantization type"));
101        }
102
103        let _reserved = properties.get_bit(15);
104
105        Ok(Self {
106            flags,
107            entropy_algorithm,
108        })
109    }
110}
111
112/// [2.2.2.3.1] TS_RFX_FRAME_BEGIN
113///
114/// [2.2.2.3.1]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/7a938a26-3fc2-436b-bc84-09dfff59b5e7
115#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct FrameBeginPdu {
117    pub index: u32,
118    pub number_of_regions: i16,
119}
120
121impl FrameBeginPdu {
122    const NAME: &'static str = "RfxFrameBegin";
123
124    const FIXED_PART_SIZE: usize = 4 /* frameIdx */ + 2 /* numRegions */;
125}
126
127impl Encode for FrameBeginPdu {
128    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
129        ensure_fixed_part_size!(in: dst);
130
131        dst.write_u32(self.index);
132        dst.write_i16(self.number_of_regions);
133
134        Ok(())
135    }
136
137    fn name(&self) -> &'static str {
138        Self::NAME
139    }
140
141    fn size(&self) -> usize {
142        Self::FIXED_PART_SIZE
143    }
144}
145
146impl<'de> Decode<'de> for FrameBeginPdu {
147    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
148        ensure_fixed_part_size!(in: src);
149
150        let index = src.read_u32();
151        let number_of_regions = src.read_i16();
152
153        Ok(Self {
154            index,
155            number_of_regions,
156        })
157    }
158}
159
160/// [2.2.2.3.2] TS_RFX_FRAME_END
161///
162/// [2.2.2.3.1]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/b4cb2676-0268-450b-ad32-72f66d0598e8
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub struct FrameEndPdu;
165
166impl FrameEndPdu {
167    const NAME: &'static str = "RfxFrameEnd";
168
169    const FIXED_PART_SIZE: usize = 0;
170}
171
172impl Encode for FrameEndPdu {
173    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
174        ensure_fixed_part_size!(in: dst);
175
176        Ok(())
177    }
178
179    fn name(&self) -> &'static str {
180        Self::NAME
181    }
182
183    fn size(&self) -> usize {
184        Self::FIXED_PART_SIZE
185    }
186}
187
188impl<'de> Decode<'de> for FrameEndPdu {
189    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
190        ensure_fixed_part_size!(in: src);
191
192        Ok(Self)
193    }
194}
195
196/// [2.2.2.3.3] TS_RFX_REGION
197///
198/// [2.2.2.3.3]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/23d2a1d6-1be0-4357-83eb-998b66ddd4d9
199#[derive(Debug, Clone, PartialEq, Eq)]
200pub struct RegionPdu {
201    pub rectangles: Vec<RfxRectangle>,
202}
203
204impl RegionPdu {
205    const NAME: &'static str = "RfxRegion";
206
207    const FIXED_PART_SIZE: usize = 1 /* regionFlags */ + 2 /* numRects */ + 2 /* regionType */ + 2 /* numTilesets */;
208}
209
210impl Encode for RegionPdu {
211    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
212        ensure_fixed_part_size!(in: dst);
213
214        let mut region_flags = 0;
215        region_flags.set_bit(0, LRF);
216        dst.write_u8(region_flags);
217
218        dst.write_u16(cast_length!("numRectangles", self.rectangles.len())?);
219        for rectangle in self.rectangles.iter() {
220            rectangle.encode(dst)?;
221        }
222
223        dst.write_u16(CBT_REGION);
224        dst.write_u16(NUMBER_OF_TILESETS);
225
226        Ok(())
227    }
228
229    fn name(&self) -> &'static str {
230        Self::NAME
231    }
232
233    fn size(&self) -> usize {
234        Self::FIXED_PART_SIZE + self.rectangles.len() * RECTANGLE_SIZE
235    }
236}
237
238impl<'de> Decode<'de> for RegionPdu {
239    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
240        ensure_fixed_part_size!(in: src);
241
242        let region_flags = src.read_u8();
243        let lrf = region_flags.get_bit(0);
244        if lrf != LRF {
245            return Err(invalid_field_err!("lrf", "Invalid lrf"));
246        }
247
248        let number_of_rectangles = usize::from(src.read_u16());
249
250        ensure_size!(in: src, size: number_of_rectangles * RECTANGLE_SIZE);
251
252        let rectangles = (0..number_of_rectangles)
253            .map(|_| RfxRectangle::decode(src))
254            .collect::<Result<Vec<_>, _>>()?;
255
256        ensure_size!(in: src, size: 4);
257
258        let region_type = src.read_u16();
259        if region_type != CBT_REGION {
260            return Err(invalid_field_err!("regionType", "Invalid region type"));
261        }
262
263        let number_of_tilesets = src.read_u16();
264        if number_of_tilesets != NUMBER_OF_TILESETS {
265            return Err(invalid_field_err!("numTilesets", "Invalid number of tilesets"));
266        }
267
268        Ok(Self { rectangles })
269    }
270}
271
272/// [2.2.2.3.4] TS_RFX_TILESET
273///
274/// [2.2.2.3.4] https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/7c926114-4bea-4c69-a9a1-caa6e88847a6
275#[derive(Debug, Clone, PartialEq, Eq)]
276pub struct TileSetPdu<'a> {
277    pub entropy_algorithm: EntropyAlgorithm,
278    pub quants: Vec<Quant>,
279    pub tiles: Vec<Tile<'a>>,
280}
281
282impl TileSetPdu<'_> {
283    const NAME: &'static str = "RfxTileSet";
284
285    const FIXED_PART_SIZE: usize = 2 /* subtype */ + 2 /* idx */ + 2 /* properties */ + 1 /* numQuant */ + 1 /* tileSize */+ 2 /* numTiles */ + 4 /* tilesDataSize */;
286}
287
288impl Encode for TileSetPdu<'_> {
289    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
290        ensure_fixed_part_size!(in: dst);
291
292        dst.write_u16(CBT_TILESET);
293        dst.write_u16(IDX);
294
295        let mut properties: u16 = 0;
296        properties.set_bit(0, IS_LAST_TILESET_FLAG);
297        properties.set_bits(1..4, OperatingMode::empty().bits()); // The decoder MUST ignore this flag
298        properties.set_bits(4..6, COLOR_CONVERSION_ICT);
299        properties.set_bits(6..10, CLW_XFORM_DWT_53_A);
300        properties.set_bits(10..14, self.entropy_algorithm.to_u16().unwrap());
301        properties.set_bits(14..16, SCALAR_QUANTIZATION);
302        dst.write_u16(properties);
303
304        dst.write_u8(cast_length!("numQuant", self.quants.len())?);
305        dst.write_u8(TILE_SIZE as u8);
306        dst.write_u16(cast_length!("numTiles", self.tiles.len())?);
307
308        let tiles_data_size = self.tiles.iter().map(|t| Block::Tile(t.clone()).size()).sum::<usize>();
309        dst.write_u32(cast_length!("tilesDataSize", tiles_data_size)?);
310
311        for quant in &self.quants {
312            quant.encode(dst)?;
313        }
314
315        for tile in &self.tiles {
316            Block::Tile(tile.clone()).encode(dst)?;
317        }
318
319        Ok(())
320    }
321
322    fn name(&self) -> &'static str {
323        Self::NAME
324    }
325
326    fn size(&self) -> usize {
327        Self::FIXED_PART_SIZE
328            + self.quants.iter().map(Encode::size).sum::<usize>()
329            + self.tiles.iter().map(|t| Block::Tile(t.clone()).size()).sum::<usize>()
330    }
331}
332
333impl<'de> Decode<'de> for TileSetPdu<'de> {
334    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
335        ensure_fixed_part_size!(in: src);
336
337        let subtype = src.read_u16();
338        if subtype != CBT_TILESET {
339            return Err(invalid_field_err!("subtype", "Invalid message type"));
340        }
341
342        let id_of_context = src.read_u16();
343        if id_of_context != IDX {
344            return Err(invalid_field_err!("id_of_context", "Invalid RFX context"));
345        }
346
347        let properties = src.read_u16();
348        let is_last = properties.get_bit(0);
349        if is_last != IS_LAST_TILESET_FLAG {
350            return Err(invalid_field_err!("last", "Invalid last flag"));
351        }
352
353        // The encoder MUST set `flags` value to the value of flags
354        // that is set in the properties field of TS_RFX_CONTEXT.
355        // The decoder MUST ignore this flag and MUST use the flags specified
356        // in the flags field of the TS_RFX_CONTEXT.
357
358        let color_conversion_transform = properties.get_bits(4..6);
359        if color_conversion_transform != COLOR_CONVERSION_ICT {
360            return Err(invalid_field_err!("cct", "Invalid color conversion"));
361        }
362
363        let dwt = properties.get_bits(6..10);
364        if dwt != CLW_XFORM_DWT_53_A {
365            return Err(invalid_field_err!("xft", "Invalid DWT"));
366        }
367
368        let entropy_algorithm_bits = properties.get_bits(10..14);
369        let entropy_algorithm = EntropyAlgorithm::from_u16(entropy_algorithm_bits)
370            .ok_or_else(|| invalid_field_err!("entropy", "Invalid entropy algorithm"))?;
371
372        let quantization_type = properties.get_bits(14..16);
373        if quantization_type != SCALAR_QUANTIZATION {
374            return Err(invalid_field_err!("scalar", "Invalid quantization type"));
375        }
376
377        let number_of_quants = usize::from(src.read_u8());
378
379        let tile_size = u16::from(src.read_u8());
380        if tile_size != TILE_SIZE {
381            return Err(invalid_field_err!("tile_size", "Invalid tile size"));
382        }
383
384        let number_of_tiles = src.read_u16();
385        let _tiles_data_size = src.read_u32() as usize;
386
387        let quants = (0..number_of_quants)
388            .map(|_| Quant::decode(src))
389            .collect::<Result<Vec<_>, _>>()?;
390
391        let tiles = (0..number_of_tiles)
392            .map(|_| Block::decode(src))
393            .collect::<Result<Vec<_>, _>>()?;
394
395        let tiles = tiles
396            .into_iter()
397            .map(|b| match b {
398                Block::Tile(tile) => Ok(tile),
399                _ => Err(invalid_field_err!("tile", "Invalid block type, expected Tile")),
400            })
401            .collect::<Result<Vec<_>, _>>()?;
402
403        Ok(Self {
404            entropy_algorithm,
405            quants,
406            tiles,
407        })
408    }
409}
410/// [2.2.2.1.6] TS_RFX_RECT
411///
412/// [2.2.2.1.6]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/26eb819a-955b-4b08-b3a0-997231170059
413#[derive(Debug, Clone, PartialEq, Eq)]
414pub struct RfxRectangle {
415    pub x: u16,
416    pub y: u16,
417    pub width: u16,
418    pub height: u16,
419}
420
421impl RfxRectangle {
422    const NAME: &'static str = "RfxRectangle";
423
424    const FIXED_PART_SIZE: usize = 4 * 2 /* x, y, width, height */;
425}
426
427impl Encode for RfxRectangle {
428    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
429        ensure_fixed_part_size!(in: dst);
430
431        dst.write_u16(self.x);
432        dst.write_u16(self.y);
433        dst.write_u16(self.width);
434        dst.write_u16(self.height);
435
436        Ok(())
437    }
438
439    fn name(&self) -> &'static str {
440        Self::NAME
441    }
442
443    fn size(&self) -> usize {
444        Self::FIXED_PART_SIZE
445    }
446}
447
448impl<'de> Decode<'de> for RfxRectangle {
449    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
450        ensure_fixed_part_size!(in: src);
451
452        let x = src.read_u16();
453        let y = src.read_u16();
454        let width = src.read_u16();
455        let height = src.read_u16();
456
457        Ok(Self { x, y, width, height })
458    }
459}
460
461/// 2.2.2.1.5 TS_RFX_CODEC_QUANT
462///
463/// [2.2.2.1.5]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/3e9c8af4-7539-4c9d-95de-14b1558b902c
464#[derive(Debug, Clone, PartialEq, Eq)]
465pub struct Quant {
466    pub ll3: u8,
467    pub lh3: u8,
468    pub hl3: u8,
469    pub hh3: u8,
470    pub lh2: u8,
471    pub hl2: u8,
472    pub hh2: u8,
473    pub lh1: u8,
474    pub hl1: u8,
475    pub hh1: u8,
476}
477
478// The quantization values control the compression rate and quality. The value
479// range is between 6 and 15. The higher value, the higher compression rate and
480// lower quality.
481//
482// This is the default values being use by the MS RDP server, and we will also
483// use it as our default values for the encoder.
484impl Default for Quant {
485    fn default() -> Self {
486        Self {
487            ll3: 6,
488            lh3: 6,
489            hl3: 6,
490            hh3: 6,
491            lh2: 7,
492            hl2: 7,
493            hh2: 8,
494            lh1: 8,
495            hl1: 8,
496            hh1: 9,
497        }
498    }
499}
500
501impl Quant {
502    const NAME: &'static str = "RfxFrameEnd";
503
504    const FIXED_PART_SIZE: usize = 5 /* 10 * 4 bits */;
505}
506
507impl Encode for Quant {
508    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
509        ensure_fixed_part_size!(in: dst);
510
511        let mut level3 = 0;
512        level3.set_bits(0..4, u16::from(self.ll3));
513        level3.set_bits(4..8, u16::from(self.lh3));
514        level3.set_bits(8..12, u16::from(self.hl3));
515        level3.set_bits(12..16, u16::from(self.hh3));
516
517        let mut level2_with_lh1 = 0;
518        level2_with_lh1.set_bits(0..4, u16::from(self.lh2));
519        level2_with_lh1.set_bits(4..8, u16::from(self.hl2));
520        level2_with_lh1.set_bits(8..12, u16::from(self.hh2));
521        level2_with_lh1.set_bits(12..16, u16::from(self.lh1));
522
523        let mut level1 = 0;
524        level1.set_bits(0..4, self.hl1);
525        level1.set_bits(4..8, self.hh1);
526
527        dst.write_u16(level3);
528        dst.write_u16(level2_with_lh1);
529        dst.write_u8(level1);
530
531        Ok(())
532    }
533
534    fn name(&self) -> &'static str {
535        Self::NAME
536    }
537
538    fn size(&self) -> usize {
539        Self::FIXED_PART_SIZE
540    }
541}
542
543impl<'de> Decode<'de> for Quant {
544    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
545        #![allow(clippy::similar_names)] // It’s hard to do better than ll3, lh3, etc without going overly verbose.
546        ensure_fixed_part_size!(in: src);
547
548        let level3 = src.read_u16();
549        let ll3 = level3.get_bits(0..4) as u8;
550        let lh3 = level3.get_bits(4..8) as u8;
551        let hl3 = level3.get_bits(8..12) as u8;
552        let hh3 = level3.get_bits(12..16) as u8;
553
554        let level2_with_lh1 = src.read_u16();
555        let lh2 = level2_with_lh1.get_bits(0..4) as u8;
556        let hl2 = level2_with_lh1.get_bits(4..8) as u8;
557        let hh2 = level2_with_lh1.get_bits(8..12) as u8;
558        let lh1 = level2_with_lh1.get_bits(12..16) as u8;
559
560        let level1 = src.read_u8();
561        let hl1 = level1.get_bits(0..4);
562        let hh1 = level1.get_bits(4..8);
563
564        Ok(Self {
565            ll3,
566            lh3,
567            hl3,
568            hh3,
569            lh2,
570            hl2,
571            hh2,
572            lh1,
573            hl1,
574            hh1,
575        })
576    }
577}
578/// [2.2.2.3.4.1] TS_RFX_TILE
579///
580/// [2.2.2.3.4.1]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/89e669ed-b6dd-4591-a267-73a72bc6d84e
581#[derive(Debug, Clone, PartialEq, Eq)]
582pub struct Tile<'a> {
583    pub y_quant_index: u8,
584    pub cb_quant_index: u8,
585    pub cr_quant_index: u8,
586
587    pub x: u16,
588    pub y: u16,
589
590    pub y_data: &'a [u8],
591    pub cb_data: &'a [u8],
592    pub cr_data: &'a [u8],
593}
594
595impl Tile<'_> {
596    const NAME: &'static str = "RfxTile";
597
598    const FIXED_PART_SIZE: usize = 1 /* quantIdxY */ + 1 /* quantIdxCb */ + 1 /* quantIdxCr */ + 2 /* xIdx */ + 2 /* yIdx */ + 2 /* YLen */ + 2 /* CbLen */ + 2 /* CrLen */;
599}
600
601impl Encode for Tile<'_> {
602    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
603        ensure_size!(in: dst, size: self.size());
604
605        dst.write_u8(self.y_quant_index);
606        dst.write_u8(self.cb_quant_index);
607        dst.write_u8(self.cr_quant_index);
608
609        dst.write_u16(self.x);
610        dst.write_u16(self.y);
611
612        dst.write_u16(cast_length!("YLen", self.y_data.len())?);
613        dst.write_u16(cast_length!("CbLen", self.cb_data.len())?);
614        dst.write_u16(cast_length!("CrLen", self.cr_data.len())?);
615
616        dst.write_slice(self.y_data);
617        dst.write_slice(self.cb_data);
618        dst.write_slice(self.cr_data);
619
620        Ok(())
621    }
622
623    fn name(&self) -> &'static str {
624        Self::NAME
625    }
626
627    fn size(&self) -> usize {
628        Self::FIXED_PART_SIZE + self.y_data.len() + self.cb_data.len() + self.cr_data.len()
629    }
630}
631
632impl<'de> Decode<'de> for Tile<'de> {
633    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
634        #![allow(clippy::similar_names)] // It’s hard to find better names for cr, cb, etc.
635        ensure_fixed_part_size!(in: src);
636
637        let y_quant_index = src.read_u8();
638        let cb_quant_index = src.read_u8();
639        let cr_quant_index = src.read_u8();
640
641        let x = src.read_u16();
642        let y = src.read_u16();
643
644        let y_component_length = usize::from(src.read_u16());
645        let cb_component_length = usize::from(src.read_u16());
646        let cr_component_length = usize::from(src.read_u16());
647
648        ensure_size!(in: src, size: y_component_length + cb_component_length + cr_component_length);
649
650        let y_data = src.read_slice(y_component_length);
651        let cb_data = src.read_slice(cb_component_length);
652        let cr_data = src.read_slice(cr_component_length);
653
654        Ok(Self {
655            y_quant_index,
656            cb_quant_index,
657            cr_quant_index,
658
659            x,
660            y,
661
662            y_data,
663            cb_data,
664            cr_data,
665        })
666    }
667}
668
669#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
670#[repr(u16)]
671pub enum EntropyAlgorithm {
672    Rlgr1 = 0x01,
673    Rlgr3 = 0x04,
674}
675
676bitflags! {
677    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
678    pub struct OperatingMode: u16 {
679        const IMAGE_MODE = 0x02; // if not set, the codec is operating in video mode
680    }
681}