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 = 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 = (1 << k); /* add (1 << 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 = ((1 << 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 = ((1 << 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 if (sign)
357 mag = WINPR_ASSERTING_INT_CAST(int16_t, (code + 1)) * -1;
358 else
359 mag = WINPR_ASSERTING_INT_CAST(int16_t, code + 1);
360
361 /* write to output stream */
362
363 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput)-pDstData);
364 size = run;
365
366 if ((offset + size) > rDstSize)
367 size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
368
369 if (size)
370 {
371 ZeroMemory(pOutput, size * sizeof(INT16));
372 pOutput += size;
373 }
374
375 if ((pOutput - pDstData) < DstSize)
376 {
377 *pOutput = mag;
378 pOutput++;
379 }
380 }
381 else
382 {
383 /* Golomb-Rice (GR) Mode */
384
385 /* count number of leading 1s */
386
387 cnt = lzcnt_s(~(bs->accumulator));
388
389 size_t nbits = BitStream_GetRemainingLength(bs);
390
391 if (cnt > nbits)
392 cnt = nbits;
393
394 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
395
396 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
397 {
398 BitStream_Shift32(bs);
399
400 cnt = lzcnt_s(~(bs->accumulator));
401
402 nbits = BitStream_GetRemainingLength(bs);
403
404 if (cnt > nbits)
405 cnt = nbits;
406
407 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
408 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
409 }
410
411 BitStream_Shift(bs, (vk % 32));
412
413 if (BitStream_GetRemainingLength(bs) < 1)
414 break;
415
416 BitStream_Shift(bs, 1);
417
418 /* next kr bits contain code remainder */
419
420 if (BitStream_GetRemainingLength(bs) < kr)
421 break;
422
423 bs->mask = ((1 << kr) - 1);
424 if (kr > 0)
425 code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
426 else
427 code = 0;
428 BitStream_Shift(bs, kr);
429
430 /* add (vk << kr) to code */
431
432 code |= (vk << kr);
433
434 if (!vk)
435 {
436 /* update kr, krp params */
437
438 if (krp > 2)
439 krp -= 2;
440 else
441 krp = 0;
442
443 kr = (krp >> LSGR) & UINT32_MAX;
444 }
445 else if (vk != 1)
446 {
447 /* update kr, krp params */
448
449 krp += vk;
450
451 if (krp > KPMAX)
452 krp = KPMAX;
453
454 kr = krp >> LSGR;
455 }
456
457 if (mode == RLGR1) /* RLGR1 */
458 {
459 if (!code)
460 {
461 /* update k, kp params */
462
463 kp += UQ_GR;
464
465 if (kp > KPMAX)
466 kp = KPMAX;
467
468 k = kp >> LSGR;
469
470 mag = 0;
471 }
472 else
473 {
474 /* update k, kp params */
475
476 if (kp > DQ_GR)
477 kp -= DQ_GR;
478 else
479 kp = 0;
480
481 k = kp >> LSGR;
482
483 /*
484 * code = 2 * mag - sign
485 * sign + code = 2 * mag
486 */
487
488 if (code & 1)
489 mag = WINPR_ASSERTING_INT_CAST(INT16, (code + 1) >> 1) * -1;
490 else
491 mag = WINPR_ASSERTING_INT_CAST(INT16, code >> 1);
492 }
493
494 if ((pOutput - pDstData) < DstSize)
495 {
496 *pOutput = mag;
497 pOutput++;
498 }
499 }
500 else if (mode == RLGR3) /* RLGR3 */
501 {
502 nIdx = 0;
503
504 if (code)
505 {
506 mag = WINPR_ASSERTING_INT_CAST(int16_t, code);
507 nIdx = 32 - lzcnt_s(WINPR_ASSERTING_INT_CAST(uint32_t, mag));
508 }
509
510 if (BitStream_GetRemainingLength(bs) < nIdx)
511 break;
512
513 bs->mask = ((1 << nIdx) - 1);
514 if (nIdx > 0)
515 val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask);
516 else
517 val1 = 0;
518 BitStream_Shift(bs, nIdx);
519
520 val2 = code - val1;
521
522 if (val1 && val2)
523 {
524 /* update k, kp params */
525
526 if (kp > 2 * DQ_GR)
527 kp -= (2 * DQ_GR);
528 else
529 kp = 0;
530
531 k = kp >> LSGR;
532 }
533 else if (!val1 && !val2)
534 {
535 /* update k, kp params */
536
537 kp += (2 * UQ_GR);
538
539 if (kp > KPMAX)
540 kp = KPMAX;
541
542 k = kp >> LSGR;
543 }
544
545 if (val1 & 1)
546 mag = WINPR_ASSERTING_INT_CAST(int16_t, (val1 + 1) >> 1) * -1;
547 else
548 mag = WINPR_ASSERTING_INT_CAST(int16_t, val1 >> 1);
549
550 if ((pOutput - pDstData) < DstSize)
551 {
552 *pOutput = mag;
553 pOutput++;
554 }
555
556 if (val2 & 1)
557 mag = WINPR_ASSERTING_INT_CAST(int16_t, (val2 + 1) >> 1) * -1;
558 else
559 mag = WINPR_ASSERTING_INT_CAST(int16_t, val2 >> 1);
560
561 if ((pOutput - pDstData) < DstSize)
562 {
563 *pOutput = WINPR_ASSERTING_INT_CAST(int16_t, mag);
564 pOutput++;
565 }
566 }
567 }
568 }
569
570 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
571
572 if (offset < rDstSize)
573 {
574 size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
575 ZeroMemory(pOutput, size * 2);
576 pOutput += size;
577 }
578
579 offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
580
581 if ((DstSize < 0) || (offset != (size_t)DstSize))
582 return -1;
583
584 return 1;
585}
586
587/* Returns the next coefficient (a signed int) to encode, from the input stream */
588#define GetNextInput(_n) \
589 do \
590 { \
591 if (data_size > 0) \
592 { \
593 (_n) = *data++; \
594 data_size--; \
595 } \
596 else \
597 { \
598 (_n) = 0; \
599 } \
600 } while (0)
601
602/* Emit bitPattern to the output bitstream */
603#define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
604
605/* Emit a bit (0 or 1), count number of times, to the output bitstream */
606static inline void OutputBit(RFX_BITSTREAM* bs, uint32_t count, UINT8 bit)
607{
608 UINT16 _b = ((bit) ? 0xFFFF : 0);
609 const uint32_t rem = count % 16;
610 for (uint32_t x = 0; x < count - rem; x += 16)
611 rfx_bitstream_put_bits(bs, _b, 16);
612
613 if (rem > 0)
614 rfx_bitstream_put_bits(bs, _b, rem);
615}
616
617/* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 :
618 * 0) and returns it */
619static inline UINT32 Get2MagSign(INT32 input)
620{
621 if (input >= 0)
622 return WINPR_ASSERTING_INT_CAST(UINT32, 2 * input);
623 return WINPR_ASSERTING_INT_CAST(UINT32, -2 * input - 1);
624}
625
626/* Outputs the Golomb/Rice encoding of a non-negative integer */
627#define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
628
629static void rfx_rlgr_code_gr(RFX_BITSTREAM* bs, uint32_t* krp, UINT32 val)
630{
631 uint32_t kr = *krp >> LSGR;
632
633 /* unary part of GR code */
634
635 const uint32_t vk = val >> kr;
636 OutputBit(bs, vk, 1);
637 OutputBit(bs, 1, 0);
638
639 /* remainder part of GR code, if needed */
640 if (kr)
641 {
642 OutputBits(kr, val & ((1 << kr) - 1));
643 }
644
645 /* update krp, only if it is not equal to 1 */
646 if (vk == 0)
647 {
648 (void)UpdateParam(krp, -2);
649 }
650 else if (vk > 1)
651 {
652 (void)UpdateParam(krp, WINPR_CXX_COMPAT_CAST(int32_t, vk));
653 }
654}
655
656int rfx_rlgr_encode(RLGR_MODE mode, const INT16* WINPR_RESTRICT data, UINT32 data_size,
657 BYTE* WINPR_RESTRICT buffer, UINT32 buffer_size)
658{
659 uint32_t k = 0;
660 uint32_t kp = 0;
661 uint32_t krp = 0;
662 RFX_BITSTREAM* bs = nullptr;
663
664 if (!(bs = (RFX_BITSTREAM*)winpr_aligned_calloc(1, sizeof(RFX_BITSTREAM), 32)))
665 return 0;
666
667 rfx_bitstream_attach(bs, buffer, buffer_size);
668
669 /* initialize the parameters */
670 k = 1;
671 kp = 1 << LSGR;
672 krp = 1 << LSGR;
673
674 /* process all the input coefficients */
675 while (data_size > 0)
676 {
677 int input = 0;
678
679 if (k)
680 {
681 uint32_t numZeros = 0;
682 uint32_t runmax = 0;
683 BYTE sign = 0;
684
685 /* RUN-LENGTH MODE */
686
687 /* collect the run of zeros in the input stream */
688 numZeros = 0;
689 GetNextInput(input);
690 while (input == 0 && data_size > 0)
691 {
692 numZeros++;
693 GetNextInput(input);
694 }
695
696 // emit output zeros
697 runmax = 1 << k;
698 while (numZeros >= runmax)
699 {
700 OutputBit(bs, 1, 0); /* output a zero bit */
701 numZeros -= runmax;
702 k = UpdateParam(&kp, UP_GR); /* update kp, k */
703 runmax = 1 << k;
704 }
705
706 /* output a 1 to terminate runs */
707 OutputBit(bs, 1, 1);
708
709 /* output the remaining run length using k bits */
710 OutputBits(k, numZeros);
711
712 /* note: when we reach here and the last byte being encoded is 0, we still
713 need to output the last two bits, otherwise mstsc will crash */
714
715 /* encode the nonzero value using GR coding */
716 const UINT32 mag =
717 (UINT32)(input < 0 ? -input : input); /* absolute value of input coefficient */
718 sign = (input < 0 ? 1 : 0); /* sign of input coefficient */
719
720 OutputBit(bs, 1, sign); /* output the sign bit */
721 CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */
722
723 k = UpdateParam(&kp, -DN_GR);
724 }
725 else
726 {
727 /* GOLOMB-RICE MODE */
728
729 if (mode == RLGR1)
730 {
731 UINT32 twoMs = 0;
732
733 /* RLGR1 variant */
734
735 /* convert input to (2*magnitude - sign), encode using GR code */
736 GetNextInput(input);
737 twoMs = Get2MagSign(input);
738 CodeGR(&krp, twoMs);
739
740 /* update k, kp */
741 /* NOTE: as of Aug 2011, the algorithm is still wrongly documented
742 and the update direction is reversed */
743 if (twoMs)
744 {
745 k = UpdateParam(&kp, -DQ_GR);
746 }
747 else
748 {
749 k = UpdateParam(&kp, UQ_GR);
750 }
751 }
752 else /* mode == RLGR3 */
753 {
754 UINT32 twoMs1 = 0;
755 UINT32 twoMs2 = 0;
756 UINT32 sum2Ms = 0;
757 UINT32 nIdx = 0;
758
759 /* RLGR3 variant */
760
761 /* convert the next two input values to (2*magnitude - sign) and */
762 /* encode their sum using GR code */
763
764 GetNextInput(input);
765 twoMs1 = Get2MagSign(input);
766 GetNextInput(input);
767 twoMs2 = Get2MagSign(input);
768 sum2Ms = twoMs1 + twoMs2;
769
770 CodeGR(&krp, sum2Ms);
771
772 /* encode binary representation of the first input (twoMs1). */
773 GetMinBits(sum2Ms, nIdx);
774 OutputBits(nIdx, twoMs1);
775
776 /* update k,kp for the two input values */
777
778 if (twoMs1 && twoMs2)
779 {
780 k = UpdateParam(&kp, -2 * DQ_GR);
781 }
782 else if (!twoMs1 && !twoMs2)
783 {
784 k = UpdateParam(&kp, 2 * UQ_GR);
785 }
786 }
787 }
788 }
789
790 rfx_bitstream_flush(bs);
791 uint32_t processed_size = rfx_bitstream_get_processed_bytes(bs);
792 winpr_aligned_free(bs);
793
794 return WINPR_ASSERTING_INT_CAST(int, processed_size);
795}