3.1.8.1.7.3.1 RLGR1/RLGR3 Decode
The following pseudocode sample shows how to decode a stream of bits encoded using the RLGR1/RLGR3 algorithm.
// Constants used within the RLGR1/RLGR3 algorithm
#define KPMAX (80) // max value for kp or krp
#define LSGR (3) // shift count to convert kp to k
#define UP_GR (4) // increase in kp after a zero run in RL mode
#define DN_GR (6) // decrease in kp after a nonzero symbol in RL mode
#define UQ_GR (3) // increase in kp after nonzero symbol in GR mode
#define DQ_GR (3) // decrease in kp after zero symbol in GR mode
//
// Gets (returns) the next nBits from the bitstream
// The layout of N bits in the bitstream with regard to a byte array is:
// [0..N] -> [0..7](MSB..LSB),[8..15](MSB..LSB) ...,
// where (MSB..LSB) denotes a byte.
//
UINT GetBits(
UINT nBits
);
//
// From current output pointer, write "value", check and update *termsToDecode
//
VOID
WriteValue(
INT value,
INT *termsToDecode
);
//
// From current output pointer, write next nZeroes terms with value 0;
// check and update *termsToDecode
//
VOID
WriteZeroes(
UINT nZeroes,
INT *termsToDecode
);
//
// Returns the least number of bits required to represent a given value
//
UINT
GetMinBits(
UINT val// returns ceil(log2(val))
);
//
// Converts from (2 * magnitude - sign) to integer
//
INT
GetIntFrom2MagSign(
UINT twoMs
);
//
// Update the passed parameter and clamp it to the range [0,KPMAX]
// Return the value of parameter right-shifted by LSGR
//
INT
UpdateParam(
INT* param, // parameter to update
INT deltaP // update delta
)
{
*param += deltaP;// adjust parameter
if (*param > KPMAX) *param = KPMAX;// max clamp
if (*param < 0) *param = 0;// min clamp
return (*param >> LSGR);
}
//
// Outputs the Golomb/Rice encoding of a non-negative integer
//
UINT
GetGRCode(
INT* krp,
INT* kr
)
{
INT vk;
UINT mag;
// chew up/count leading 1s and escape 0
for (vk=0;GetBits(1)==1;) {
vk++;
}
// get next *kr bits, and combine with leading 1s
mag = (vk<<*kr) | GetBits(*kr);
// adjust kpr and kr based on vk
if (!vk)
{
*kr = UpdateParam(kpr, -2);
}
else if (vk!=1)// at 1, no change!
{
*kr = UpdateParam(kpr, vk);
}
return (mag);
}
//
// Routine that reads and decodes stream of RLGR data
//
VOID
RLGR_Decode(
RLGR_MODE rlgrMode, // RLGR1 || RLGR3
INT termsToDecode
)
{
// initialize the parameters
INT k = 1;
INT kp = k << LSGR;
INT kr = 1;
INT krp = kr << LSGR;
while (termsToDecode > 0)
{
INT run;
if (k)
{
// RL MODE
while (GetBits(1) == 0)
{
// we have an RL escape "0", which translates to a run (1<<k) of zeros
WriteZeroes(1<<k, &termsToDecode);
k = UpdateParam(&kp,UpGR); // raise k and kp up because of zero run
}
if (termsToDecode > 0)
{
// next k bits will contain remaining run of zeros
run = GetBits(k);
WriteZeroes(run, &termsToDecode);
}
if (termsToDecode > 0)
{
// get nonzero value, starting with sign bit and
// then GRCode for magnitude - 1
UINT sign = GetBits(1);
// magnitude - 1 was coded (because it was nonzero)
INT mag = (INT)GetGRCode(&krp,&kr) + 1;
WriteValue(sign ? -mag : mag, &termsToDecode);
k = UpdateParam(&kp, -DnGR); // lower k and kp because of nonzero term
}
}
else
{
// GR (GOLOMB-RICE) MODE
UINT mag = GetGRCode(&krp, &kr); // values coded are 2*magnitude - sign
if (rlgrMode == RLGR1)
{
if (!mag)
{
WriteValue(0, &termsToDecode);
k = UpdateParam(&kp, UqGR); // raise k and kp due to zero
}
else
{
WriteValue(GetIntFrom2MagSign(mag), &termsToDecode);
k = UpdateParam(&kp, -DqGR); // lower k and kp due to nonzero
}
}
else // rlgrMode == RLGR3
{
// In GR mode FOR RLGR3, we have encoded the
// sum of two (2*mag - sign) values
// maximum possible bits for first term
UINT nIdx = GetMinBits(mag);
// decode val1 is first term's (2*mag - sign) value
UINT val1 = GetBits(nIdx);
// val2 is second term's (2*mag - sign) value
UINT val2 = mag - val1;
if (val1 && val2) {
// raise k and kp if both terms nonzero
k = UpdateParam(&kp, -2*DqGR);
}
else if (!val1 && !val2) {
// lower k and kp if both terms zero
k = UpdateParam(&kp, 2*UqGR);
}
WriteValue(GetIntFrom2MagSign(val1), &termsToDecode);
WriteValue(GetIntFrom2MagSign(val2), &termsToDecode);
}
}
}
}
