3.1.8.1.7.3.2 RLGR1/RLGR3 Encode
The following pseudocode sample shows how to encode a stream of input symbols 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
//
// Returns the next coefficient (a signed int) to encode, from the input stream
//
INT
GetNextInput();
//
// Emit bitPattern to the output bitstream.
// The bitPattern value represents a bit sequence that is generated by shifting
// new bits in from the right. If we take the binary representation of bitPattern,
// with N(numBits-1) being the leftmost bit position and 0 being the rightmost bit position,
// the mapping of bitPattern to the output bytes is as follows:
//
// bitPattern[N..0] -> byte[MSB..LSB] .. byte[MSB..LSB]
//
VOID
OutputBits(
INT numBits, // number of bits in bitPattern
INT bitPattern // bit pattern
);
//
// Emit a bit (0 or 1), count number of times, to the output bitstream
//
VOID
OutputBit(
INT count, // number of times to emit the bit
INT bit // 0 or 1
);
//
// Returns the least number of bits required to represent a given value
//
UINT
GetMinBits(
INT val // returns ceil(log2(val))
);
//
// Converts the input value to (2 * abs(input) - sign(input)),
// where sign(input) = (input < 0 ? 1 : 0) and returns it
//
UINT
Get2MagSign(
INT input // input value
);
//
// 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;
if (*param > KPMAX) *param = KPMAX;
if (*param < 0) *param = 0;
return (*param >> LSGR);
}
//
// Outputs the Golomb/Rice encoding of a non-negative integer
//
VOID
CodeGR(
INT* krp, // GR parameter, used and updated based on the input value
UINT val // input non-negative value to be encoded
)
{
INT kr = *krp >> LSGR;
// unary part of GR code
UINT vk = val >> kr;
OuputBit(vk, 1);
OutputBit(1, 0);
// remainder part of GR code, if needed
if (kr) {
OutputBits(kr, val & ((1 << kr) - 1));
}
// update krp, only if it is not equal to 1
if (vk == 0) {
UpdateParam(krp, -2);
}
else if (vk > 1) {
UpdateParam(krp, vk);
}
}
//
// Routine that outputs a stream of RLGR1/RLGR3-encoded bits
//
VOID
RLGR_Encode(
RLGR_MODE rlgrMode // RLGR1 || RLGR3
)
{
// initialize the parameters
INT k = 1;
INT kp = 1 << LSGR;
INT kr = 1;
INT krp = 1 << LSGR;
// process all the input coefficients
while (1)
{
INT input;
if (k)
{
// RUN-LENGTH MODE
// collect the run of zeros in the input stream
INT numZeros = 0;
while ((input = GetNextInput()) == 0) {
++ numZeros;
}
// emit output zeros
INT runmax = 1 << k;
while (numZeros >= runmax)
{
OutputBit(1, 0); // output a zero bit
numZeros -= runmax;
k = UpdateParam(&kp, UpGR); // update kp, k
runmax = 1 << k;
}
// output a 1 to terminate runs
OuputBit(1, 1);
// output the remaining run length using k bits
OutputBits(k, numZeros);
// encode the nonzero value using GR coding
INT mag = abs(input); // absolute value of input coefficient
INT sign = (input < 0 ? 1 : 0); // sign of input coefficient
OutputBit(1, sign); // output the sign bit
CodeGR(&krp, mag - 1); // output GR code for (mag - 1)
k = UpdateParam(&kp, -DnGR);
}
else
{
// GOLOMB-RICE MODE
if (rlgrMode == RLGR1)
{
// RLGR1 variant
// convert input to (2*magnitude - sign), encode using GR code
UINT twoMs = Get2MagSign(GetNextInput());
CodeGR(&krp, twoMs);
// update k, kp
if (twoMs) {
k = UpdateParam(&kp, UqGR);
}
else {
k = UpdateParam(&kp, -DqGR);
}
}
else // rlgrMode == RLGR3
{
// RLGR3 variant
// convert the next two input values to (2*magnitude - sign) and
// encode their sum using GR code
UINT twoMs1 = Get2MagSign(GetNextInput());
UINT twoMs2 = Get2MagSign(GetNextInput());
UINT sum2Ms = twoMs1 + twoMs2;
CodeGR(&krp, sum2Ms);
// encode binary representation of the first input (twoMs1).
OutputBits(GetMinBits(sum2Ms), twoMs1);
// update k,kp for the two input values
if (twoMs1 && twoMs2) {
k = UpdateParam(&kp, -2*DqGR);
}
else if (!twoMs1 && !twoMs2) {
k = UpdateParam(&kp, 2*UqGR);
}
}
}
}
}