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#include "rfx_types.h"
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 = nullptr;
171 wBitStream* bs = nullptr;
172 wBitStream s_bs = WINPR_C_ARRAY_INIT;
173 const SSIZE_T DstSize = rDstSize;
174
175 if (!InitOnceExecuteOnce(&rfx_rlgr_init_once, rfx_rlgr_init, nullptr, nullptr))
176 return -1;
177
178 k = 1;
179 kp = k << LSGR;
180
181 kr = 1;
182 krp = kr << LSGR;
183
184 if ((mode != RLGR1) && (mode != RLGR3))
185 mode = RLGR1;
186
187 if (!pSrcData || !SrcSize)
188 return -1;
189
190 if (!pDstData || !DstSize)
191 return -1;
192
193 pOutput = pDstData;
194
195 bs = &s_bs;
196
197 BitStream_Attach(bs, pSrcData, SrcSize);
198 BitStream_Fetch(bs);
199
200 while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize))
201 {
202 if (k)
203 {
204 /* Run-Length (RL) Mode */
205
206 run = 0;
207
208 /* count number of leading 0s */
209
210 cnt = lzcnt_s(bs->accumulator);
211
212 size_t nbits = BitStream_GetRemainingLength(bs);
213
214 if (cnt > nbits)
215 cnt = WINPR_ASSERTING_INT_CAST(uint32_t, nbits);
216
217 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
218
219 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
220 {
221 BitStream_Shift32(bs);
222
223 cnt = lzcnt_s(bs->accumulator);
224
225 nbits = BitStream_GetRemainingLength(bs);
226
227 if (cnt > nbits)
228 cnt = nbits;
229
230 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
231 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
232 }
233
234 BitStream_Shift(bs, (vk % 32));
235
236 if (BitStream_GetRemainingLength(bs) < 1)
237 break;
238
239 BitStream_Shift(bs, 1);
240
241 while (vk--)
242 {
243 const UINT32 add = (1u << k); /* add (1u << k) to run length */
244 run += add;
245
246 /* update k, kp params */
247
248 kp += UP_GR;
249
250 if (kp > KPMAX)
251 kp = KPMAX;
252
253 k = kp >> LSGR;
254 }
255
256 /* next k bits contain run length remainder */
257
258 if (BitStream_GetRemainingLength(bs) < k)
259 break;
260
261 bs->mask = ((1u << k) - 1);
262 run += ((bs->accumulator >> (32 - k)) & bs->mask);
263 BitStream_Shift(bs, k);
264
265 /* read sign bit */
266
267 if (BitStream_GetRemainingLength(bs) < 1)
268 break;
269
270 sign = (bs->accumulator & 0x80000000) ? 1 : 0;
271 BitStream_Shift(bs, 1);
272
273 /* count number of leading 1s */
274
275 cnt = lzcnt_s(~(bs->accumulator));
276
277 nbits = BitStream_GetRemainingLength(bs);
278
279 if (cnt > nbits)
280 cnt = nbits;
281
282 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
283
284 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
285 {
286 BitStream_Shift32(bs);
287
288 cnt = lzcnt_s(~(bs->accumulator));
289
290 nbits = BitStream_GetRemainingLength(bs);
291
292 if (cnt > nbits)
293 cnt = nbits;
294
295 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
296 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
297 }
298
299 BitStream_Shift(bs, (vk % 32));
300
301 if (BitStream_GetRemainingLength(bs) < 1)
302 break;
303
304 BitStream_Shift(bs, 1);
305
306 /* next kr bits contain code remainder */
307
308 if (BitStream_GetRemainingLength(bs) < kr)
309 break;
310
311 bs->mask = ((1u << kr) - 1);
312 if (kr > 0)
313 code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
314 else
315 code = 0;
316 BitStream_Shift(bs, kr);
317
318 /* add (vk << kr) to code */
319
320 code |= (vk << kr);
321
322 if (!vk)
323 {
324 /* update kr, krp params */
325
326 if (krp > 2)
327 krp -= 2;
328 else
329 krp = 0;
330
331 kr = krp >> LSGR;
332 }
333 else if (vk != 1)
334 {
335 /* update kr, krp params */
336
337 krp += vk;
338
339 if (krp > KPMAX)
340 krp = KPMAX;
341
342 kr = krp >> LSGR;
343 }
344
345 /* update k, kp params */
346
347 if (kp > DN_GR)
348 kp -= DN_GR;
349 else
350 kp = 0;
351
352 k = kp >> LSGR;
353
354 /* compute magnitude from code */
355
356 const INT32 code1 = code + 1;
357 if ((code1 > INT16_MAX) || (code1 < INT16_MIN))
358 {
359 WLog_ERR(RFX_TAG, "code1=%d", code1);
360 return -1;
361 }
362
363 if (sign)
364 mag = WINPR_ASSERTING_INT_CAST(int16_t, code1) * -1;
365 else
366 mag = WINPR_ASSERTING_INT_CAST(int16_t, code1);
367
368 /* write to output stream */
369
370 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput)-pDstData);
371 size = run;
372
373 if ((offset + size) > rDstSize)
374 size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
375
376 if (size)
377 {
378 ZeroMemory(pOutput, size * sizeof(INT16));
379 pOutput += size;
380 }
381
382 if ((pOutput - pDstData) < DstSize)
383 {
384 *pOutput = mag;
385 pOutput++;
386 }
387 }
388 else
389 {
390 /* Golomb-Rice (GR) Mode */
391
392 /* count number of leading 1s */
393
394 cnt = lzcnt_s(~(bs->accumulator));
395
396 size_t nbits = BitStream_GetRemainingLength(bs);
397
398 if (cnt > nbits)
399 cnt = nbits;
400
401 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
402
403 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
404 {
405 BitStream_Shift32(bs);
406
407 cnt = lzcnt_s(~(bs->accumulator));
408
409 nbits = BitStream_GetRemainingLength(bs);
410
411 if (cnt > nbits)
412 cnt = nbits;
413
414 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
415 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
416 }
417
418 BitStream_Shift(bs, (vk % 32));
419
420 if (BitStream_GetRemainingLength(bs) < 1)
421 break;
422
423 BitStream_Shift(bs, 1);
424
425 /* next kr bits contain code remainder */
426
427 if (BitStream_GetRemainingLength(bs) < kr)
428 break;
429
430 bs->mask = ((1u << kr) - 1);
431 if (kr > 0)
432 code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
433 else
434 code = 0;
435 BitStream_Shift(bs, kr);
436
437 /* add (vk << kr) to code */
438
439 code |= (vk << kr);
440
441 if (!vk)
442 {
443 /* update kr, krp params */
444
445 if (krp > 2)
446 krp -= 2;
447 else
448 krp = 0;
449
450 kr = (krp >> LSGR) & UINT32_MAX;
451 }
452 else if (vk != 1)
453 {
454 /* update kr, krp params */
455
456 krp += vk;
457
458 if (krp > KPMAX)
459 krp = KPMAX;
460
461 kr = krp >> LSGR;
462 }
463
464 if (mode == RLGR1) /* RLGR1 */
465 {
466 if (!code)
467 {
468 /* update k, kp params */
469
470 kp += UQ_GR;
471
472 if (kp > KPMAX)
473 kp = KPMAX;
474
475 k = kp >> LSGR;
476
477 mag = 0;
478 }
479 else
480 {
481 /* update k, kp params */
482
483 if (kp > DQ_GR)
484 kp -= DQ_GR;
485 else
486 kp = 0;
487
488 k = kp >> LSGR;
489
490 /*
491 * code = 2 * mag - sign
492 * sign + code = 2 * mag
493 */
494 const INT32 codeShift = code >> 1;
495 const INT32 code1shift = (code + 1) >> 1;
496 if ((codeShift > INT16_MAX) || (codeShift < INT16_MIN))
497 {
498 WLog_ERR(RFX_TAG, "codeShift=%d", codeShift);
499 return -1;
500 }
501 if ((code1shift > INT16_MAX) || (code1shift < INT16_MIN))
502 {
503 WLog_ERR(RFX_TAG, "code1shift=%d", code1shift);
504 return -1;
505 }
506 if (code & 1)
507 mag = WINPR_ASSERTING_INT_CAST(INT16, code1shift) * -1;
508 else
509 mag = WINPR_ASSERTING_INT_CAST(INT16, codeShift);
510 }
511
512 if ((pOutput - pDstData) < DstSize)
513 {
514 *pOutput = mag;
515 pOutput++;
516 }
517 }
518 else if (mode == RLGR3) /* RLGR3 */
519 {
520 nIdx = 0;
521
522 if (code)
523 {
524 mag = WINPR_ASSERTING_INT_CAST(int16_t, code);
525 nIdx = 32 - lzcnt_s(WINPR_ASSERTING_INT_CAST(uint32_t, mag));
526 }
527
528 if (BitStream_GetRemainingLength(bs) < nIdx)
529 break;
530
531 bs->mask = ((1u << nIdx) - 1);
532 if (nIdx > 0)
533 val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask);
534 else
535 val1 = 0;
536 BitStream_Shift(bs, nIdx);
537
538 val2 = code - val1;
539
540 if (val1 && val2)
541 {
542 /* update k, kp params */
543
544 if (kp > 2 * DQ_GR)
545 kp -= (2 * DQ_GR);
546 else
547 kp = 0;
548
549 k = kp >> LSGR;
550 }
551 else if (!val1 && !val2)
552 {
553 /* update k, kp params */
554
555 kp += (2 * UQ_GR);
556
557 if (kp > KPMAX)
558 kp = KPMAX;
559
560 k = kp >> LSGR;
561 }
562
563 const UINT32 val1Shift = val1 >> 1;
564 const UINT32 val11Shift = (val1 + 1) >> 1;
565 if (val1Shift > INT16_MAX)
566 {
567 WLog_ERR(RFX_TAG, "val1Shift=%" PRIu32, val1Shift);
568 return -1;
569 }
570 if (val11Shift > INT16_MAX)
571 {
572 WLog_ERR(RFX_TAG, "val11Shift=%" PRIu32, val11Shift);
573 return -1;
574 }
575 if (val1 & 1)
576 mag = WINPR_ASSERTING_INT_CAST(int16_t, val11Shift) * -1;
577 else
578 mag = WINPR_ASSERTING_INT_CAST(int16_t, val1Shift);
579
580 if ((pOutput - pDstData) < DstSize)
581 {
582 *pOutput = mag;
583 pOutput++;
584 }
585
586 const UINT32 val2Shift = val2 / 2;
587 const UINT32 val21Shift = (val2 + 1) / 2;
588 if (val2Shift > INT16_MAX)
589 {
590 WLog_ERR(RFX_TAG, "val2Shift=%" PRIu32, val2Shift);
591 return -1;
592 }
593
594 if (val21Shift > INT16_MAX)
595 {
596 WLog_ERR(RFX_TAG, "val21Shift=%" PRIu32, val21Shift);
597 return -1;
598 }
599 if (val2 & 1)
600 mag = WINPR_ASSERTING_INT_CAST(int16_t, val21Shift) * -1;
601 else
602 mag = WINPR_ASSERTING_INT_CAST(int16_t, val2Shift);
603
604 if ((pOutput - pDstData) < DstSize)
605 {
606 *pOutput = WINPR_ASSERTING_INT_CAST(int16_t, mag);
607 pOutput++;
608 }
609 }
610 }
611 }
612
613 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
614
615 if (offset < rDstSize)
616 {
617 size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
618 ZeroMemory(pOutput, size * 2);
619 pOutput += size;
620 }
621
622 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
623
624 if ((DstSize < 0) || (offset != (size_t)DstSize))
625 return -1;
626
627 return 1;
628}
629
630/* Returns the next coefficient (a signed int) to encode, from the input stream */
631#define GetNextInput(_n) \
632 do \
633 { \
634 if (data_size > 0) \
635 { \
636 (_n) = *data++; \
637 data_size--; \
638 } \
639 else \
640 { \
641 (_n) = 0; \
642 } \
643 } while (0)
644
645/* Emit bitPattern to the output bitstream */
646#define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
647
648/* Emit a bit (0 or 1), count number of times, to the output bitstream */
649static inline void OutputBit(RFX_BITSTREAM* bs, uint32_t count, UINT8 bit)
650{
651 UINT16 _b = ((bit) ? 0xFFFF : 0);
652 const uint32_t rem = count % 16;
653 for (uint32_t x = 0; x < count - rem; x += 16)
654 rfx_bitstream_put_bits(bs, _b, 16);
655
656 if (rem > 0)
657 rfx_bitstream_put_bits(bs, _b, rem);
658}
659
660/* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 :
661 * 0) and returns it */
662static inline UINT32 Get2MagSign(INT32 input)
663{
664 if (input >= 0)
665 return WINPR_ASSERTING_INT_CAST(UINT32, 2 * input);
666 return WINPR_ASSERTING_INT_CAST(UINT32, -2 * input - 1);
667}
668
669/* Outputs the Golomb/Rice encoding of a non-negative integer */
670#define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
671
672static void rfx_rlgr_code_gr(RFX_BITSTREAM* bs, uint32_t* krp, UINT32 val)
673{
674 uint32_t kr = *krp >> LSGR;
675
676 /* unary part of GR code */
677
678 const uint32_t vk = val >> kr;
679 OutputBit(bs, vk, 1);
680 OutputBit(bs, 1, 0);
681
682 /* remainder part of GR code, if needed */
683 if (kr)
684 {
685 OutputBits(kr, val & ((1u << kr) - 1));
686 }
687
688 /* update krp, only if it is not equal to 1 */
689 if (vk == 0)
690 {
691 (void)UpdateParam(krp, -2);
692 }
693 else if (vk > 1)
694 {
695 (void)UpdateParam(krp, WINPR_CXX_COMPAT_CAST(int32_t, vk));
696 }
697}
698
699int rfx_rlgr_encode(RLGR_MODE mode, const INT16* WINPR_RESTRICT data, UINT32 data_size,
700 BYTE* WINPR_RESTRICT buffer, UINT32 buffer_size)
701{
702 RFX_BITSTREAM* bs = (RFX_BITSTREAM*)winpr_aligned_calloc(1, sizeof(RFX_BITSTREAM), 32);
703
704 if (!bs)
705 return 0;
706
707 rfx_bitstream_attach(bs, buffer, buffer_size);
708
709 /* initialize the parameters */
710 uint32_t k = 1;
711 uint32_t kp = 1u << LSGR;
712 uint32_t krp = 1u << LSGR;
713
714 /* process all the input coefficients */
715 while (data_size > 0)
716 {
717 int input = 0;
718
719 if (k)
720 {
721 uint32_t numZeros = 0;
722 uint32_t runmax = 0;
723 BYTE sign = 0;
724
725 /* RUN-LENGTH MODE */
726
727 /* collect the run of zeros in the input stream */
728 numZeros = 0;
729 GetNextInput(input);
730 while (input == 0 && data_size > 0)
731 {
732 numZeros++;
733 GetNextInput(input);
734 }
735
736 // emit output zeros
737 runmax = 1u << k;
738 while (numZeros >= runmax)
739 {
740 OutputBit(bs, 1, 0); /* output a zero bit */
741 numZeros -= runmax;
742 k = UpdateParam(&kp, UP_GR); /* update kp, k */
743 runmax = 1u << k;
744 }
745
746 /* output a 1 to terminate runs */
747 OutputBit(bs, 1, 1);
748
749 /* output the remaining run length using k bits */
750 OutputBits(k, numZeros);
751
752 /* note: when we reach here and the last byte being encoded is 0, we still
753 need to output the last two bits, otherwise mstsc will crash */
754
755 /* encode the nonzero value using GR coding */
756 const UINT32 mag =
757 (UINT32)(input < 0 ? -input : input); /* absolute value of input coefficient */
758 sign = (input < 0 ? 1 : 0); /* sign of input coefficient */
759
760 OutputBit(bs, 1, sign); /* output the sign bit */
761 CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */
762
763 k = UpdateParam(&kp, -DN_GR);
764 }
765 else
766 {
767 /* GOLOMB-RICE MODE */
768
769 if (mode == RLGR1)
770 {
771 UINT32 twoMs = 0;
772
773 /* RLGR1 variant */
774
775 /* convert input to (2*magnitude - sign), encode using GR code */
776 GetNextInput(input);
777 twoMs = Get2MagSign(input);
778 CodeGR(&krp, twoMs);
779
780 /* update k, kp */
781 /* NOTE: as of Aug 2011, the algorithm is still wrongly documented
782 and the update direction is reversed */
783 if (twoMs)
784 {
785 k = UpdateParam(&kp, -DQ_GR);
786 }
787 else
788 {
789 k = UpdateParam(&kp, UQ_GR);
790 }
791 }
792 else /* mode == RLGR3 */
793 {
794 UINT32 twoMs1 = 0;
795 UINT32 twoMs2 = 0;
796 UINT32 sum2Ms = 0;
797 UINT32 nIdx = 0;
798
799 /* RLGR3 variant */
800
801 /* convert the next two input values to (2*magnitude - sign) and */
802 /* encode their sum using GR code */
803
804 GetNextInput(input);
805 twoMs1 = Get2MagSign(input);
806 GetNextInput(input);
807 twoMs2 = Get2MagSign(input);
808 sum2Ms = twoMs1 + twoMs2;
809
810 CodeGR(&krp, sum2Ms);
811
812 /* encode binary representation of the first input (twoMs1). */
813 GetMinBits(sum2Ms, nIdx);
814 OutputBits(nIdx, twoMs1);
815
816 /* update k,kp for the two input values */
817
818 if (twoMs1 && twoMs2)
819 {
820 k = UpdateParam(&kp, -2 * DQ_GR);
821 }
822 else if (!twoMs1 && !twoMs2)
823 {
824 k = UpdateParam(&kp, 2 * UQ_GR);
825 }
826 }
827 }
828 }
829
830 rfx_bitstream_flush(bs);
831 uint32_t processed_size = rfx_bitstream_get_processed_bytes(bs);
832 winpr_aligned_free(bs);
833
834 return WINPR_ASSERTING_INT_CAST(int, processed_size);
835}