int rfx_rlgr_encode(RLGR_MODE mode, const INT16* data, int data_size, BYTE* buffer, int buffer_size) { int k; int kp; int krp; RFX_BITSTREAM* bs; int processed_size; bs = (RFX_BITSTREAM*) malloc(sizeof(RFX_BITSTREAM)); ZeroMemory(bs, sizeof(RFX_BITSTREAM)); rfx_bitstream_attach(bs, buffer, buffer_size); /* initialize the parameters */ k = 1; kp = 1 << LSGR; krp = 1 << LSGR; /* process all the input coefficients */ while (data_size > 0) { int input; if (k) { int numZeros; int runmax; int mag; int sign; /* RUN-LENGTH MODE */ /* collect the run of zeros in the input stream */ numZeros = 0; GetNextInput(input); while (input == 0 && data_size > 0) { numZeros++; GetNextInput(input); } // emit output zeros runmax = 1 << k; while (numZeros >= runmax) { OutputBit(1, 0); /* output a zero bit */ numZeros -= runmax; UpdateParam(kp, UP_GR, k); /* update kp, k */ runmax = 1 << k; } /* output a 1 to terminate runs */ OutputBit(1, 1); /* output the remaining run length using k bits */ OutputBits(k, numZeros); /* note: when we reach here and the last byte being encoded is 0, we still need to output the last two bits, otherwise mstsc will crash */ /* encode the nonzero value using GR coding */ mag = (input < 0 ? -input : input); /* absolute value of input coefficient */ sign = (input < 0 ? 1 : 0); /* sign of input coefficient */ OutputBit(1, sign); /* output the sign bit */ CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */ UpdateParam(kp, -DN_GR, k); } else { /* GOLOMB-RICE MODE */ if (mode == RLGR1) { UINT32 twoMs; /* RLGR1 variant */ /* convert input to (2*magnitude - sign), encode using GR code */ GetNextInput(input); twoMs = Get2MagSign(input); CodeGR(&krp, twoMs); /* update k, kp */ /* NOTE: as of Aug 2011, the algorithm is still wrongly documented and the update direction is reversed */ if (twoMs) { UpdateParam(kp, -DQ_GR, k); } else { UpdateParam(kp, UQ_GR, k); } } else /* mode == RLGR3 */ { UINT32 twoMs1; UINT32 twoMs2; UINT32 sum2Ms; UINT32 nIdx; /* RLGR3 variant */ /* convert the next two input values to (2*magnitude - sign) and */ /* encode their sum using GR code */ GetNextInput(input); twoMs1 = Get2MagSign(input); GetNextInput(input); twoMs2 = Get2MagSign(input); sum2Ms = twoMs1 + twoMs2; CodeGR(&krp, sum2Ms); /* encode binary representation of the first input (twoMs1). */ GetMinBits(sum2Ms, nIdx); OutputBits(nIdx, twoMs1); /* update k,kp for the two input values */ if (twoMs1 && twoMs2) { UpdateParam(kp, -2 * DQ_GR, k); } else if (!twoMs1 && !twoMs2) { UpdateParam(kp, 2 * UQ_GR, k); } } } } processed_size = rfx_bitstream_get_processed_bytes(bs); free(bs); return processed_size; }
int rfx_rlgr1_encode(const sint16* data, int data_size, uint8* buffer, int buffer_size) { int k; int kp; int krp; int input; int numZeros; int runmax; int mag; int sign; int processed_size; int lmag; RFX_BITSTREAM bs; uint32 twoMs; rfx_bitstream_attach(bs, buffer, buffer_size); /* initialize the parameters */ k = 1; kp = 1 << LSGR; krp = 1 << LSGR; /* process all the input coefficients */ while (data_size > 0) { if (k) { /* RUN-LENGTH MODE */ /* collect the run of zeros in the input stream */ numZeros = 0; GetNextInput(input); while (input == 0 && data_size > 0) { numZeros++; GetNextInput(input); } /* emit output zeros */ runmax = 1 << k; while (numZeros >= runmax) { OutputBit(1, 0); /* output a zero bit */ numZeros -= runmax; UpdateParam(kp, UP_GR, k); /* update kp, k */ runmax = 1 << k; } /* output a 1 to terminate runs */ OutputBit(1, 1); /* output the remaining run length using k bits */ OutputBits(k, numZeros); /* note: when we reach here and the last byte being encoded is 0, we still need to output the last two bits, otherwise mstsc will crash */ /* encode the nonzero value using GR coding */ mag = (input < 0 ? -input : input); /* absolute value of input coefficient */ sign = (input < 0 ? 1 : 0); /* sign of input coefficient */ OutputBit(1, sign); /* output the sign bit */ lmag = mag ? mag - 1 : 0; CodeGR(krp, lmag); /* output GR code for (mag - 1) */ UpdateParam(kp, -DN_GR, k); } else { /* GOLOMB-RICE MODE */ /* RLGR1 variant */ /* convert input to (2*magnitude - sign), encode using GR code */ GetNextInput(input); twoMs = Get2MagSign(input); CodeGR(krp, twoMs); /* update k, kp */ /* NOTE: as of Aug 2011, the algorithm is still wrongly documented and the update direction is reversed */ if (twoMs) { UpdateParam(kp, -DQ_GR, k); } else { UpdateParam(kp, UQ_GR, k); } } } processed_size = rfx_bitstream_get_processed_bytes(bs); return processed_size; }