2 * FreeRDP: A Remote Desktop Protocol client.
3 * RemoteFX Codec Library - RLGR
5 * Copyright 2011 Vic Lee
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * This implementation of RLGR refers to
22 * [MS-RDPRFX] 3.1.8.1.7.3 RLGR1/RLGR3 Pseudocode
28 #include <freerdp/utils/memory.h>
29 #include "rfx_bitstream.h"
33 /* Constants used within the RLGR1/RLGR3 algorithm */
34 #define KPMAX (80) /* max value for kp or krp */
35 #define LSGR (3) /* shift count to convert kp to k */
36 #define UP_GR (4) /* increase in kp after a zero run in RL mode */
37 #define DN_GR (6) /* decrease in kp after a nonzero symbol in RL mode */
38 #define UQ_GR (3) /* increase in kp after nonzero symbol in GR mode */
39 #define DQ_GR (3) /* decrease in kp after zero symbol in GR mode */
41 /* Gets (returns) the next nBits from the bitstream */
42 #define GetBits(nBits, r) rfx_bitstream_get_bits(bs, nBits, r)
44 /* From current output pointer, write "value", check and update buffer_size */
45 #define WriteValue(value) \
47 if (buffer_size > 0) \
52 /* From current output pointer, write next nZeroes terms with value 0, check and update buffer_size */
53 #define WriteZeroes(nZeroes) \
55 int nZeroesWritten = (nZeroes); \
56 if (nZeroesWritten > buffer_size) \
57 nZeroesWritten = buffer_size; \
58 if (nZeroesWritten > 0) \
60 memset(dst, 0, nZeroesWritten * sizeof(sint16)); \
61 dst += nZeroesWritten; \
63 buffer_size -= (nZeroes); \
66 /* Returns the least number of bits required to represent a given value */
67 #define GetMinBits(_val, _nbits) \
78 /* Converts from (2 * magnitude - sign) to integer */
79 #define GetIntFrom2MagSign(twoMs) (((twoMs) & 1) ? -1 * (sint16)(((twoMs) + 1) >> 1) : (sint16)((twoMs) >> 1))
82 * Update the passed parameter and clamp it to the range [0, KPMAX]
83 * Return the value of parameter right-shifted by LSGR
85 #define UpdateParam(_param, _deltaP, _k) \
92 _k = (_param >> LSGR); \
95 /* Outputs the Golomb/Rice encoding of a non-negative integer */
96 #define GetGRCode(krp, kr, vk, _mag) \
99 /* chew up/count leading 1s and escape 0 */ \
107 /* get next *kr bits, and combine with leading 1s */ \
108 GetBits(*kr, _mag); \
109 _mag |= (vk << *kr); \
110 /* adjust krp and kr based on vk */ \
112 UpdateParam(*krp, -2, *kr); \
114 else if (vk != 1) { \
115 UpdateParam(*krp, vk, *kr); /* at 1, no change! */ \
118 int rfx_rlgr_decode(RLGR_MODE mode, const uint8* data, int data_size, sint16* buffer, int buffer_size)
131 bs = xnew(RFX_BITSTREAM);
132 rfx_bitstream_attach(bs, data, data_size);
135 /* initialize the parameters */
141 while (!rfx_bitstream_eos(bs) && buffer_size > 0)
150 while (!rfx_bitstream_eos(bs))
155 /* we have an RL escape "0", which translates to a run (1<<k) of zeros */
157 UpdateParam(kp, UP_GR, k); /* raise k and kp up because of zero run */
160 /* next k bits will contain remaining run or zeros */
164 /* get nonzero value, starting with sign bit and then GRCode for magnitude -1 */
167 /* magnitude - 1 was coded (because it was nonzero) */
168 GetGRCode(&krp, &kr, vk, mag16)
169 mag = (int) (mag16 + 1);
171 WriteValue(sign ? -mag : mag);
172 UpdateParam(kp, -DN_GR, k); /* lower k and kp because of nonzero term */
181 /* GR (GOLOMB-RICE) MODE */
182 GetGRCode(&krp, &kr, vk, mag16) /* values coded are 2 * magnitude - sign */
183 mag = (uint32) mag16;
190 UpdateParam(kp, UQ_GR, k); /* raise k and kp due to zero */
194 WriteValue(GetIntFrom2MagSign(mag));
195 UpdateParam(kp, -DQ_GR, k); /* lower k and kp due to nonzero */
198 else /* mode == RLGR3 */
201 * In GR mode FOR RLGR3, we have encoded the
202 * sum of two (2 * mag - sign) values
205 /* maximum possible bits for first term */
206 GetMinBits(mag, nIdx);
208 /* decode val1 is first term's (2 * mag - sign) value */
211 /* val2 is second term's (2 * mag - sign) value */
216 /* raise k and kp if both terms nonzero */
217 UpdateParam(kp, -2 * DQ_GR, k);
219 else if (!val1 && !val2)
221 /* lower k and kp if both terms zero */
222 UpdateParam(kp, 2 * UQ_GR, k);
225 WriteValue(GetIntFrom2MagSign(val1));
226 WriteValue(GetIntFrom2MagSign(val2));
233 return (dst - buffer);
236 /* Returns the next coefficient (a signed int) to encode, from the input stream */
237 #define GetNextInput(_n) \
250 /* Emit bitPattern to the output bitstream */
251 #define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
253 /* Emit a bit (0 or 1), count number of times, to the output bitstream */
254 #define OutputBit(count, bit) \
256 uint16 _b = (bit ? 0xFFFF : 0); \
258 for (; _c > 0; _c -= 16) \
259 rfx_bitstream_put_bits(bs, _b, (_c > 16 ? 16 : _c)); \
262 /* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 : 0) and returns it */
263 #define Get2MagSign(input) ((input) >= 0 ? 2 * (input) : -2 * (input) - 1)
265 /* Outputs the Golomb/Rice encoding of a non-negative integer */
266 #define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
268 static void rfx_rlgr_code_gr(RFX_BITSTREAM* bs, int* krp, uint32 val)
270 int kr = *krp >> LSGR;
272 /* unary part of GR code */
274 uint32 vk = (val) >> kr;
278 /* remainder part of GR code, if needed */
281 OutputBits(kr, val & ((1 << kr) - 1));
284 /* update krp, only if it is not equal to 1 */
287 UpdateParam(*krp, -2, kr);
291 UpdateParam(*krp, vk, kr);
295 int rfx_rlgr_encode(RLGR_MODE mode, const sint16* data, int data_size, uint8* buffer, int buffer_size)
303 bs = xnew(RFX_BITSTREAM);
304 rfx_bitstream_attach(bs, buffer, buffer_size);
306 /* initialize the parameters */
311 /* process all the input coefficients */
312 while (data_size > 0)
323 /* RUN-LENGTH MODE */
325 /* collect the run of zeros in the input stream */
328 while (input == 0 && data_size > 0)
336 while (numZeros >= runmax)
338 OutputBit(1, 0); /* output a zero bit */
340 UpdateParam(kp, UP_GR, k); /* update kp, k */
344 /* output a 1 to terminate runs */
347 /* output the remaining run length using k bits */
348 OutputBits(k, numZeros);
350 /* note: when we reach here and the last byte being encoded is 0, we still
351 need to output the last two bits, otherwise mstsc will crash */
353 /* encode the nonzero value using GR coding */
354 mag = (input < 0 ? -input : input); /* absolute value of input coefficient */
355 sign = (input < 0 ? 1 : 0); /* sign of input coefficient */
357 OutputBit(1, sign); /* output the sign bit */
358 CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */
360 UpdateParam(kp, -DN_GR, k);
364 /* GOLOMB-RICE MODE */
372 /* convert input to (2*magnitude - sign), encode using GR code */
374 twoMs = Get2MagSign(input);
378 /* NOTE: as of Aug 2011, the algorithm is still wrongly documented
379 and the update direction is reversed */
382 UpdateParam(kp, -DQ_GR, k);
386 UpdateParam(kp, UQ_GR, k);
389 else /* mode == RLGR3 */
398 /* convert the next two input values to (2*magnitude - sign) and */
399 /* encode their sum using GR code */
402 twoMs1 = Get2MagSign(input);
404 twoMs2 = Get2MagSign(input);
405 sum2Ms = twoMs1 + twoMs2;
407 CodeGR(&krp, sum2Ms);
409 /* encode binary representation of the first input (twoMs1). */
410 GetMinBits(sum2Ms, nIdx);
411 OutputBits(nIdx, twoMs1);
413 /* update k,kp for the two input values */
415 if (twoMs1 && twoMs2)
417 UpdateParam(kp, -2 * DQ_GR, k);
419 else if (!twoMs1 && !twoMs2)
421 UpdateParam(kp, 2 * UQ_GR, k);
427 processed_size = rfx_bitstream_get_processed_bytes(bs);
430 return processed_size;