FreeRDP
Loading...
Searching...
No Matches
rfx_rlgr.c
1
25#include <freerdp/config.h>
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include <winpr/assert.h>
32#include <winpr/cast.h>
33#include <winpr/crt.h>
34#include <winpr/print.h>
35#include <winpr/sysinfo.h>
36#include <winpr/bitstream.h>
37#include <winpr/intrin.h>
38
39#include "rfx_bitstream.h"
40
41#include "rfx_rlgr.h"
42
43/* Constants used in RLGR1/RLGR3 algorithm */
44#define KPMAX (80) /* max value for kp or krp */
45#define LSGR (3) /* shift count to convert kp to k */
46#define UP_GR (4) /* increase in kp after a zero run in RL mode */
47#define DN_GR (6) /* decrease in kp after a nonzero symbol in RL mode */
48#define UQ_GR (3) /* increase in kp after nonzero symbol in GR mode */
49#define DQ_GR (3) /* decrease in kp after zero symbol in GR mode */
50
51/* Returns the least number of bits required to represent a given value */
52#define GetMinBits(_val, _nbits) \
53 do \
54 { \
55 UINT32 _v = (_val); \
56 (_nbits) = 0; \
57 while (_v) \
58 { \
59 _v >>= 1; \
60 (_nbits)++; \
61 } \
62 } while (0)
63
64/*
65 * Update the passed parameter and clamp it to the range [0, KPMAX]
66 * Return the value of parameter right-shifted by LSGR
67 */
68static inline uint32_t UpdateParam(uint32_t* param, int32_t deltaP)
69{
70 WINPR_ASSERT(param);
71 if (deltaP < 0)
72 {
73 const uint32_t udeltaP = WINPR_ASSERTING_INT_CAST(uint32_t, -deltaP);
74 if (udeltaP > *param)
75 *param = 0;
76 else
77 *param -= udeltaP;
78 }
79 else
80 *param += WINPR_ASSERTING_INT_CAST(uint32_t, deltaP);
81
82 if ((*param) > KPMAX)
83 (*param) = KPMAX;
84 return (*param) >> LSGR;
85}
86
87static BOOL g_LZCNT = FALSE;
88
89static INIT_ONCE rfx_rlgr_init_once = INIT_ONCE_STATIC_INIT;
90
91static BOOL CALLBACK rfx_rlgr_init(PINIT_ONCE once, PVOID param, PVOID* context)
92{
93 WINPR_UNUSED(once);
94 WINPR_UNUSED(param);
95 WINPR_UNUSED(context);
96
97 g_LZCNT = IsProcessorFeaturePresentEx(PF_EX_LZCNT);
98 return TRUE;
99}
100
101static INLINE UINT32 lzcnt_s(UINT32 x)
102{
103 if (!x)
104 return 32;
105
106 if (!g_LZCNT)
107 {
108 UINT32 y = 0;
109 UINT32 n = 32;
110 y = x >> 16;
111 if (y != 0)
112 {
113 WINPR_ASSERT(n >= 16);
114 n = n - 16;
115 x = y;
116 }
117 y = x >> 8;
118 if (y != 0)
119 {
120 WINPR_ASSERT(n >= 8);
121 n = n - 8;
122 x = y;
123 }
124 y = x >> 4;
125 if (y != 0)
126 {
127 WINPR_ASSERT(n >= 4);
128 n = n - 4;
129 x = y;
130 }
131 y = x >> 2;
132 if (y != 0)
133 {
134 WINPR_ASSERT(n >= 2);
135 n = n - 2;
136 x = y;
137 }
138 y = x >> 1;
139 if (y != 0)
140 {
141 WINPR_ASSERT(n >= 2);
142 return n - 2;
143 }
144
145 WINPR_ASSERT(n >= x);
146 return n - x;
147 }
148
149 return __lzcnt(x);
150}
151
152int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
153 INT16* WINPR_RESTRICT pDstData, UINT32 rDstSize)
154{
155 uint32_t vk = 0;
156 size_t run = 0;
157 size_t cnt = 0;
158 size_t size = 0;
159 size_t offset = 0;
160 INT16 mag = 0;
161 UINT32 k = 0;
162 UINT32 kp = 0;
163 UINT32 kr = 0;
164 UINT32 krp = 0;
165 UINT16 code = 0;
166 UINT32 sign = 0;
167 UINT32 nIdx = 0;
168 UINT32 val1 = 0;
169 UINT32 val2 = 0;
170 INT16* pOutput = NULL;
171 wBitStream* bs = NULL;
172 wBitStream s_bs = { 0 };
173 const SSIZE_T DstSize = rDstSize;
174
175 InitOnceExecuteOnce(&rfx_rlgr_init_once, rfx_rlgr_init, NULL, NULL);
176
177 k = 1;
178 kp = k << LSGR;
179
180 kr = 1;
181 krp = kr << LSGR;
182
183 if ((mode != RLGR1) && (mode != RLGR3))
184 mode = RLGR1;
185
186 if (!pSrcData || !SrcSize)
187 return -1;
188
189 if (!pDstData || !DstSize)
190 return -1;
191
192 pOutput = pDstData;
193
194 bs = &s_bs;
195
196 BitStream_Attach(bs, pSrcData, SrcSize);
197 BitStream_Fetch(bs);
198
199 while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize))
200 {
201 if (k)
202 {
203 /* Run-Length (RL) Mode */
204
205 run = 0;
206
207 /* count number of leading 0s */
208
209 cnt = lzcnt_s(bs->accumulator);
210
211 size_t nbits = BitStream_GetRemainingLength(bs);
212
213 if (cnt > nbits)
214 cnt = WINPR_ASSERTING_INT_CAST(uint32_t, nbits);
215
216 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
217
218 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
219 {
220 BitStream_Shift32(bs);
221
222 cnt = lzcnt_s(bs->accumulator);
223
224 nbits = BitStream_GetRemainingLength(bs);
225
226 if (cnt > nbits)
227 cnt = nbits;
228
229 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
230 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
231 }
232
233 BitStream_Shift(bs, (vk % 32));
234
235 if (BitStream_GetRemainingLength(bs) < 1)
236 break;
237
238 BitStream_Shift(bs, 1);
239
240 while (vk--)
241 {
242 const UINT32 add = (1 << k); /* add (1 << k) to run length */
243 run += add;
244
245 /* update k, kp params */
246
247 kp += UP_GR;
248
249 if (kp > KPMAX)
250 kp = KPMAX;
251
252 k = kp >> LSGR;
253 }
254
255 /* next k bits contain run length remainder */
256
257 if (BitStream_GetRemainingLength(bs) < k)
258 break;
259
260 bs->mask = ((1 << k) - 1);
261 run += ((bs->accumulator >> (32 - k)) & bs->mask);
262 BitStream_Shift(bs, k);
263
264 /* read sign bit */
265
266 if (BitStream_GetRemainingLength(bs) < 1)
267 break;
268
269 sign = (bs->accumulator & 0x80000000) ? 1 : 0;
270 BitStream_Shift(bs, 1);
271
272 /* count number of leading 1s */
273
274 cnt = lzcnt_s(~(bs->accumulator));
275
276 nbits = BitStream_GetRemainingLength(bs);
277
278 if (cnt > nbits)
279 cnt = nbits;
280
281 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
282
283 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
284 {
285 BitStream_Shift32(bs);
286
287 cnt = lzcnt_s(~(bs->accumulator));
288
289 nbits = BitStream_GetRemainingLength(bs);
290
291 if (cnt > nbits)
292 cnt = nbits;
293
294 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
295 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
296 }
297
298 BitStream_Shift(bs, (vk % 32));
299
300 if (BitStream_GetRemainingLength(bs) < 1)
301 break;
302
303 BitStream_Shift(bs, 1);
304
305 /* next kr bits contain code remainder */
306
307 if (BitStream_GetRemainingLength(bs) < kr)
308 break;
309
310 bs->mask = ((1 << kr) - 1);
311 if (kr > 0)
312 code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
313 else
314 code = 0;
315 BitStream_Shift(bs, kr);
316
317 /* add (vk << kr) to code */
318
319 code |= (vk << kr);
320
321 if (!vk)
322 {
323 /* update kr, krp params */
324
325 if (krp > 2)
326 krp -= 2;
327 else
328 krp = 0;
329
330 kr = krp >> LSGR;
331 }
332 else if (vk != 1)
333 {
334 /* update kr, krp params */
335
336 krp += vk;
337
338 if (krp > KPMAX)
339 krp = KPMAX;
340
341 kr = krp >> LSGR;
342 }
343
344 /* update k, kp params */
345
346 if (kp > DN_GR)
347 kp -= DN_GR;
348 else
349 kp = 0;
350
351 k = kp >> LSGR;
352
353 /* compute magnitude from code */
354
355 if (sign)
356 mag = WINPR_ASSERTING_INT_CAST(int16_t, (code + 1)) * -1;
357 else
358 mag = WINPR_ASSERTING_INT_CAST(int16_t, code + 1);
359
360 /* write to output stream */
361
362 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput)-pDstData);
363 size = run;
364
365 if ((offset + size) > rDstSize)
366 size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
367
368 if (size)
369 {
370 ZeroMemory(pOutput, size * sizeof(INT16));
371 pOutput += size;
372 }
373
374 if ((pOutput - pDstData) < DstSize)
375 {
376 *pOutput = mag;
377 pOutput++;
378 }
379 }
380 else
381 {
382 /* Golomb-Rice (GR) Mode */
383
384 /* count number of leading 1s */
385
386 cnt = lzcnt_s(~(bs->accumulator));
387
388 size_t nbits = BitStream_GetRemainingLength(bs);
389
390 if (cnt > nbits)
391 cnt = nbits;
392
393 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
394
395 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
396 {
397 BitStream_Shift32(bs);
398
399 cnt = lzcnt_s(~(bs->accumulator));
400
401 nbits = BitStream_GetRemainingLength(bs);
402
403 if (cnt > nbits)
404 cnt = nbits;
405
406 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
407 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
408 }
409
410 BitStream_Shift(bs, (vk % 32));
411
412 if (BitStream_GetRemainingLength(bs) < 1)
413 break;
414
415 BitStream_Shift(bs, 1);
416
417 /* next kr bits contain code remainder */
418
419 if (BitStream_GetRemainingLength(bs) < kr)
420 break;
421
422 bs->mask = ((1 << kr) - 1);
423 if (kr > 0)
424 code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
425 else
426 code = 0;
427 BitStream_Shift(bs, kr);
428
429 /* add (vk << kr) to code */
430
431 code |= (vk << kr);
432
433 if (!vk)
434 {
435 /* update kr, krp params */
436
437 if (krp > 2)
438 krp -= 2;
439 else
440 krp = 0;
441
442 kr = (krp >> LSGR) & UINT32_MAX;
443 }
444 else if (vk != 1)
445 {
446 /* update kr, krp params */
447
448 krp += vk;
449
450 if (krp > KPMAX)
451 krp = KPMAX;
452
453 kr = krp >> LSGR;
454 }
455
456 if (mode == RLGR1) /* RLGR1 */
457 {
458 if (!code)
459 {
460 /* update k, kp params */
461
462 kp += UQ_GR;
463
464 if (kp > KPMAX)
465 kp = KPMAX;
466
467 k = kp >> LSGR;
468
469 mag = 0;
470 }
471 else
472 {
473 /* update k, kp params */
474
475 if (kp > DQ_GR)
476 kp -= DQ_GR;
477 else
478 kp = 0;
479
480 k = kp >> LSGR;
481
482 /*
483 * code = 2 * mag - sign
484 * sign + code = 2 * mag
485 */
486
487 if (code & 1)
488 mag = WINPR_ASSERTING_INT_CAST(INT16, (code + 1) >> 1) * -1;
489 else
490 mag = WINPR_ASSERTING_INT_CAST(INT16, code >> 1);
491 }
492
493 if ((pOutput - pDstData) < DstSize)
494 {
495 *pOutput = mag;
496 pOutput++;
497 }
498 }
499 else if (mode == RLGR3) /* RLGR3 */
500 {
501 nIdx = 0;
502
503 if (code)
504 {
505 mag = WINPR_ASSERTING_INT_CAST(int16_t, code);
506 nIdx = 32 - lzcnt_s(WINPR_ASSERTING_INT_CAST(uint32_t, mag));
507 }
508
509 if (BitStream_GetRemainingLength(bs) < nIdx)
510 break;
511
512 bs->mask = ((1 << nIdx) - 1);
513 if (nIdx > 0)
514 val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask);
515 else
516 val1 = 0;
517 BitStream_Shift(bs, nIdx);
518
519 val2 = code - val1;
520
521 if (val1 && val2)
522 {
523 /* update k, kp params */
524
525 if (kp > 2 * DQ_GR)
526 kp -= (2 * DQ_GR);
527 else
528 kp = 0;
529
530 k = kp >> LSGR;
531 }
532 else if (!val1 && !val2)
533 {
534 /* update k, kp params */
535
536 kp += (2 * UQ_GR);
537
538 if (kp > KPMAX)
539 kp = KPMAX;
540
541 k = kp >> LSGR;
542 }
543
544 if (val1 & 1)
545 mag = WINPR_ASSERTING_INT_CAST(int16_t, (val1 + 1) >> 1) * -1;
546 else
547 mag = WINPR_ASSERTING_INT_CAST(int16_t, val1 >> 1);
548
549 if ((pOutput - pDstData) < DstSize)
550 {
551 *pOutput = mag;
552 pOutput++;
553 }
554
555 if (val2 & 1)
556 mag = WINPR_ASSERTING_INT_CAST(int16_t, (val2 + 1) >> 1) * -1;
557 else
558 mag = WINPR_ASSERTING_INT_CAST(int16_t, val2 >> 1);
559
560 if ((pOutput - pDstData) < DstSize)
561 {
562 *pOutput = WINPR_ASSERTING_INT_CAST(int16_t, mag);
563 pOutput++;
564 }
565 }
566 }
567 }
568
569 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
570
571 if (offset < rDstSize)
572 {
573 size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
574 ZeroMemory(pOutput, size * 2);
575 pOutput += size;
576 }
577
578 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
579
580 if ((DstSize < 0) || (offset != (size_t)DstSize))
581 return -1;
582
583 return 1;
584}
585
586/* Returns the next coefficient (a signed int) to encode, from the input stream */
587#define GetNextInput(_n) \
588 do \
589 { \
590 if (data_size > 0) \
591 { \
592 (_n) = *data++; \
593 data_size--; \
594 } \
595 else \
596 { \
597 (_n) = 0; \
598 } \
599 } while (0)
600
601/* Emit bitPattern to the output bitstream */
602#define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
603
604/* Emit a bit (0 or 1), count number of times, to the output bitstream */
605static inline void OutputBit(RFX_BITSTREAM* bs, uint32_t count, UINT8 bit)
606{
607 UINT16 _b = ((bit) ? 0xFFFF : 0);
608 const uint32_t rem = count % 16;
609 for (uint32_t x = 0; x < count - rem; x += 16)
610 rfx_bitstream_put_bits(bs, _b, 16);
611
612 if (rem > 0)
613 rfx_bitstream_put_bits(bs, _b, rem);
614}
615
616/* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 :
617 * 0) and returns it */
618static inline UINT32 Get2MagSign(INT32 input)
619{
620 if (input >= 0)
621 return WINPR_ASSERTING_INT_CAST(UINT32, 2 * input);
622 return WINPR_ASSERTING_INT_CAST(UINT32, -2 * input - 1);
623}
624
625/* Outputs the Golomb/Rice encoding of a non-negative integer */
626#define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
627
628static void rfx_rlgr_code_gr(RFX_BITSTREAM* bs, uint32_t* krp, UINT32 val)
629{
630 uint32_t kr = *krp >> LSGR;
631
632 /* unary part of GR code */
633
634 const uint32_t vk = val >> kr;
635 OutputBit(bs, vk, 1);
636 OutputBit(bs, 1, 0);
637
638 /* remainder part of GR code, if needed */
639 if (kr)
640 {
641 OutputBits(kr, val & ((1 << kr) - 1));
642 }
643
644 /* update krp, only if it is not equal to 1 */
645 if (vk == 0)
646 {
647 (void)UpdateParam(krp, -2);
648 }
649 else if (vk > 1)
650 {
651 (void)UpdateParam(krp, WINPR_CXX_COMPAT_CAST(int32_t, vk));
652 }
653}
654
655int rfx_rlgr_encode(RLGR_MODE mode, const INT16* WINPR_RESTRICT data, UINT32 data_size,
656 BYTE* WINPR_RESTRICT buffer, UINT32 buffer_size)
657{
658 uint32_t k = 0;
659 uint32_t kp = 0;
660 uint32_t krp = 0;
661 RFX_BITSTREAM* bs = NULL;
662
663 if (!(bs = (RFX_BITSTREAM*)winpr_aligned_calloc(1, sizeof(RFX_BITSTREAM), 32)))
664 return 0;
665
666 rfx_bitstream_attach(bs, buffer, buffer_size);
667
668 /* initialize the parameters */
669 k = 1;
670 kp = 1 << LSGR;
671 krp = 1 << LSGR;
672
673 /* process all the input coefficients */
674 while (data_size > 0)
675 {
676 int input = 0;
677
678 if (k)
679 {
680 uint32_t numZeros = 0;
681 uint32_t runmax = 0;
682 BYTE sign = 0;
683
684 /* RUN-LENGTH MODE */
685
686 /* collect the run of zeros in the input stream */
687 numZeros = 0;
688 GetNextInput(input);
689 while (input == 0 && data_size > 0)
690 {
691 numZeros++;
692 GetNextInput(input);
693 }
694
695 // emit output zeros
696 runmax = 1 << k;
697 while (numZeros >= runmax)
698 {
699 OutputBit(bs, 1, 0); /* output a zero bit */
700 numZeros -= runmax;
701 k = UpdateParam(&kp, UP_GR); /* update kp, k */
702 runmax = 1 << k;
703 }
704
705 /* output a 1 to terminate runs */
706 OutputBit(bs, 1, 1);
707
708 /* output the remaining run length using k bits */
709 OutputBits(k, numZeros);
710
711 /* note: when we reach here and the last byte being encoded is 0, we still
712 need to output the last two bits, otherwise mstsc will crash */
713
714 /* encode the nonzero value using GR coding */
715 const UINT32 mag =
716 (UINT32)(input < 0 ? -input : input); /* absolute value of input coefficient */
717 sign = (input < 0 ? 1 : 0); /* sign of input coefficient */
718
719 OutputBit(bs, 1, sign); /* output the sign bit */
720 CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */
721
722 k = UpdateParam(&kp, -DN_GR);
723 }
724 else
725 {
726 /* GOLOMB-RICE MODE */
727
728 if (mode == RLGR1)
729 {
730 UINT32 twoMs = 0;
731
732 /* RLGR1 variant */
733
734 /* convert input to (2*magnitude - sign), encode using GR code */
735 GetNextInput(input);
736 twoMs = Get2MagSign(input);
737 CodeGR(&krp, twoMs);
738
739 /* update k, kp */
740 /* NOTE: as of Aug 2011, the algorithm is still wrongly documented
741 and the update direction is reversed */
742 if (twoMs)
743 {
744 k = UpdateParam(&kp, -DQ_GR);
745 }
746 else
747 {
748 k = UpdateParam(&kp, UQ_GR);
749 }
750 }
751 else /* mode == RLGR3 */
752 {
753 UINT32 twoMs1 = 0;
754 UINT32 twoMs2 = 0;
755 UINT32 sum2Ms = 0;
756 UINT32 nIdx = 0;
757
758 /* RLGR3 variant */
759
760 /* convert the next two input values to (2*magnitude - sign) and */
761 /* encode their sum using GR code */
762
763 GetNextInput(input);
764 twoMs1 = Get2MagSign(input);
765 GetNextInput(input);
766 twoMs2 = Get2MagSign(input);
767 sum2Ms = twoMs1 + twoMs2;
768
769 CodeGR(&krp, sum2Ms);
770
771 /* encode binary representation of the first input (twoMs1). */
772 GetMinBits(sum2Ms, nIdx);
773 OutputBits(nIdx, twoMs1);
774
775 /* update k,kp for the two input values */
776
777 if (twoMs1 && twoMs2)
778 {
779 k = UpdateParam(&kp, -2 * DQ_GR);
780 }
781 else if (!twoMs1 && !twoMs2)
782 {
783 k = UpdateParam(&kp, 2 * UQ_GR);
784 }
785 }
786 }
787 }
788
789 rfx_bitstream_flush(bs);
790 uint32_t processed_size = rfx_bitstream_get_processed_bytes(bs);
791 winpr_aligned_free(bs);
792
793 return WINPR_ASSERTING_INT_CAST(int, processed_size);
794}