static private int cleanuppass(CBlkWTData srcblk, MQCoder mq, bool doterm, int bp, int[] state, int[] fs, int[] zc_lut, int[] symbuf, int[] ctxtbuf, int[] ratebuf, int pidx, int ltpidx, int options)
{
// NOTE: The speedup mode of the MQ coder has been briefly tried to
// speed up the coding of insignificants RLCs, without any success
// (i.e. no speedup whatsoever). The use of the speedup mode should be
// revisisted more in depth and the implementationn of it in MQCoder
// should be reviewed for optimization opportunities.
int j, sj; // The state index for line and stripe
int k, sk; // The data index for line and stripe
int nsym = 0; // Symbol counter for symbol and context buffers
int dscanw; // The data scan-width
int sscanw; // The state scan-width
int jstep; // Stripe to stripe step for 'sj'
int kstep; // Stripe to stripe step for 'sk'
int stopsk; // The loop limit on the variable sk
int csj; // Local copy (i.e. cached) of 'state[j]'
int mask; // The mask for the current bit-plane
int sym; // The symbol to code
int rlclen; // Length of RLC
int ctxt; // The context to use
int[] data; // The data buffer
int dist; // The distortion reduction for this pass
int shift; // Shift amount for distortion
int upshift; // Shift left amount for distortion
int downshift; // Shift right amount for distortion
int normval; // The normalized sample magnitude value
int s; // The stripe index
bool causal; // Flag to indicate if stripe-causal context
// formation is to be used
int nstripes; // The number of stripes in the code-block
int sheight; // Height of the current stripe
int off_ul, off_ur, off_dr, off_dl; // offsets
// Initialize local variables
dscanw = srcblk.scanw;
sscanw = srcblk.w + 2;
jstep = sscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT / 2 - srcblk.w;
kstep = dscanw * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - srcblk.w;
mask = 1 << bp;
data = (int[]) srcblk.Data;
nstripes = (srcblk.h + CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT - 1) / CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
dist = 0;
// We use the MSE_LKP_BITS-1 bits below the bit just coded for
// distortion estimation.
shift = bp - (MSE_LKP_BITS - 1);
upshift = (shift >= 0)?0:- shift;
downshift = (shift <= 0)?0:shift;
causal = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL) != 0;
// Pre-calculate offsets in 'state' for diagonal neighbors
off_ul = - sscanw - 1; // up-left
off_ur = - sscanw + 1; // up-right
off_dr = sscanw + 1; // down-right
off_dl = sscanw - 1; // down-left
// Code stripe by stripe
sk = srcblk.offset;
sj = sscanw + 1;
for (s = nstripes - 1; s >= 0; s--, sk += kstep, sj += jstep)
{
sheight = (s != 0)?CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT:srcblk.h - (nstripes - 1) * CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT;
stopsk = sk + srcblk.w;
// Scan by set of 1 stripe column at a time
for (nsym = 0; sk < stopsk; sk++, sj++)
{
// Start column
j = sj;
csj = state[j];
{
// Check for RLC: if all samples are not significant, not
// visited and do not have a non-zero context, and column
// is full height, we do RLC.
if (csj == 0 && state[j + sscanw] == 0 && sheight == CSJ2K.j2k.entropy.StdEntropyCoderOptions.STRIPE_HEIGHT)
{
k = sk;
if ((data[k] & mask) != 0)
{
rlclen = 0;
}
else if ((data[k += dscanw] & mask) != 0)
{
rlclen = 1;
}
else if ((data[k += dscanw] & mask) != 0)
{
rlclen = 2;
j += sscanw;
csj = state[j];
}
else if ((data[k += dscanw] & mask) != 0)
{
rlclen = 3;
j += sscanw;
csj = state[j];
}
else
{
// Code insignificant RLC
symbuf[nsym] = 0;
ctxtbuf[nsym++] = RLC_CTXT;
// Goto next column
continue;
}
// Code significant RLC
symbuf[nsym] = 1;
ctxtbuf[nsym++] = RLC_CTXT;
// Send MSB bit index
symbuf[nsym] = rlclen >> 1;
ctxtbuf[nsym++] = UNIF_CTXT;
// Send LSB bit index
symbuf[nsym] = rlclen & 0x01;
ctxtbuf[nsym++] = UNIF_CTXT;
// Code sign of sample that became significant
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
// Apply sign coding
sym = SupportClass.URShift(data[k], 31);
if ((rlclen & 0x01) == 0)
{
// Sample that became significant is first row of
// its column half
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
if (rlclen != 0 || !causal)
{
// If in causal mode do not change contexts of
// previous stripe.
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
}
// Update sign state information of neighbors
if (sym != 0)
{
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
if (rlclen != 0 || !causal)
{
// If in causal mode do not change
// contexts of previous stripe.
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
}
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
}
else
{
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
if (rlclen != 0 || !causal)
{
// If in causal mode do not change
// contexts of previous stripe.
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
}
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
}
// Changes to csj are saved later
if ((rlclen >> 1) != 0)
{
// Sample that became significant is in bottom
// half of column => jump to bottom half
//UPGRADE_NOTE: Labeled break statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1012'"
goto top_half_brk;
}
// Otherwise sample that became significant is in
// top half of column => continue on top half
}
else
{
// Sample that became significant is second row of
// its column half
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
// Update state information (significant bit,
// neighbor significant bit of neighbors, non zero
// context of neighbors, sign of neighbors)
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0)
{
csj |= STATE_SIG_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
}
else
{
csj |= STATE_SIG_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
}
// Save changes to csj
state[j] = csj;
if ((rlclen >> 1) != 0)
{
// Sample that became significant is in bottom
// half of column => we're done with this
// column
continue;
}
// Otherwise sample that became significant is in
// top half of column => we're done with top
// column
j += sscanw;
csj = state[j];
//UPGRADE_NOTE: Labeled break statement was changed to a goto statement. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1012'"
goto top_half_brk;
}
}
// Do half top of column
// If any of the two samples is not significant and has
// not been visited in the current bit-plane we can not
// skip them
if ((((csj >> 1) | csj) & VSTD_MASK_R1R2) != VSTD_MASK_R1R2)
{
k = sk;
// Scan first row
if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == 0)
{
// Apply zero coding
ctxtbuf[nsym] = zc_lut[csj & ZC_MASK];
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
{
// Became significant
// Apply sign coding
sym = SupportClass.URShift(data[k], 31);
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors,
// sign of neighbors)
if (!causal)
{
// If in causal mode do not change
// contexts of previous stripe.
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
}
// Update sign state information of neighbors
if (sym != 0)
{
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
if (!causal)
{
// If in causal mode do not change
// contexts of previous stripe.
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
}
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
}
else
{
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
if (!causal)
{
// If in causal mode do not change
// contexts of previous stripe.
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
}
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
}
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
}
}
if (sheight < 2)
{
csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
state[j] = csj;
continue;
}
// Scan second row
if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == 0)
{
k += dscanw;
// Apply zero coding
ctxtbuf[nsym] = zc_lut[(SupportClass.URShift(csj, STATE_SEP)) & ZC_MASK];
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
{
// Became significant
// Apply sign coding
sym = SupportClass.URShift(data[k], 31);
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors,
// sign of neighbors)
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0)
{
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
}
else
{
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
}
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
}
}
}
csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
state[j] = csj;
// Do half bottom of column
if (sheight < 3)
continue;
j += sscanw;
csj = state[j];
}
//UPGRADE_NOTE: Label 'top_half_brk' was added. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1011'"
top_half_brk: ;
// end of 'top_half' block
// If any of the two samples is not significant and has
// not been visited in the current bit-plane we can not
// skip them
if ((((csj >> 1) | csj) & VSTD_MASK_R1R2) != VSTD_MASK_R1R2)
{
k = sk + (dscanw << 1);
// Scan first row
if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == 0)
{
// Apply zero coding
ctxtbuf[nsym] = zc_lut[csj & ZC_MASK];
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
{
// Became significant
// Apply sign coding
sym = SupportClass.URShift(data[k], 31);
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R1)) & SC_MASK];
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors,
// sign of neighbors)
state[j + off_ul] |= STATE_NZ_CTXT_R2 | STATE_D_DR_R2;
state[j + off_ur] |= STATE_NZ_CTXT_R2 | STATE_D_DL_R2;
// Update sign state information of neighbors
if (sym != 0)
{
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2 | STATE_V_U_SIGN_R2;
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2 | STATE_V_D_SIGN_R2;
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_H_L_SIGN_R1 | STATE_D_UL_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_H_R_SIGN_R1 | STATE_D_UR_R2;
}
else
{
csj |= STATE_SIG_R1 | STATE_VISITED_R1 | STATE_NZ_CTXT_R2 | STATE_V_U_R2;
state[j - sscanw] |= STATE_NZ_CTXT_R2 | STATE_V_D_R2;
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_L_R1 | STATE_D_UL_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_H_R_R1 | STATE_D_UR_R2;
}
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
}
}
if (sheight < 4)
{
csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
state[j] = csj;
continue;
}
// Scan second row
if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == 0)
{
k += dscanw;
// Apply zero coding
ctxtbuf[nsym] = zc_lut[(SupportClass.URShift(csj, STATE_SEP)) & ZC_MASK];
if ((symbuf[nsym++] = SupportClass.URShift((data[k] & mask), bp)) != 0)
{
// Became significant
// Apply sign coding
sym = SupportClass.URShift(data[k], 31);
ctxt = SC_LUT[(SupportClass.URShift(csj, SC_SHIFT_R2)) & SC_MASK];
symbuf[nsym] = sym ^ (SupportClass.URShift(ctxt, SC_SPRED_SHIFT));
ctxtbuf[nsym++] = ctxt & SC_LUT_MASK;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors,
// sign of neighbors)
state[j + off_dl] |= STATE_NZ_CTXT_R1 | STATE_D_UR_R1;
state[j + off_dr] |= STATE_NZ_CTXT_R1 | STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0)
{
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1 | STATE_V_D_SIGN_R1;
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1 | STATE_V_U_SIGN_R1;
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2 | STATE_H_L_SIGN_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2 | STATE_H_R_SIGN_R2;
}
else
{
csj |= STATE_SIG_R2 | STATE_VISITED_R2 | STATE_NZ_CTXT_R1 | STATE_V_D_R1;
state[j + sscanw] |= STATE_NZ_CTXT_R1 | STATE_V_U_R1;
state[j + 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DL_R1 | STATE_H_L_R2;
state[j - 1] |= STATE_NZ_CTXT_R1 | STATE_NZ_CTXT_R2 | STATE_D_DR_R1 | STATE_H_R_R2;
}
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fs[normval & ((1 << (MSE_LKP_BITS - 1)) - 1)];
}
}
}
csj &= ~ (STATE_VISITED_R1 | STATE_VISITED_R2);
state[j] = csj;
}
// Code all buffered symbols, if any
if (nsym > 0)
mq.codeSymbols(symbuf, ctxtbuf, nsym);
}
// Insert a segment marker if we need to
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_SEG_SYMBOLS) != 0)
{
mq.codeSymbols(SEG_SYMBOLS, SEG_SYMB_CTXTS, SEG_SYMBOLS.Length);
}
// Reset the MQ context states if we need to
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ) != 0)
{
mq.resetCtxts();
}
// Terminate the MQ bit stream if we need to
if (doterm)
{
ratebuf[pidx] = mq.terminate(); // Termination has special length
}
else
{
// Use normal length calculation
ratebuf[pidx] = mq.NumCodedBytes;
}
// Add length of previous segments, if any
if (ltpidx >= 0)
{
ratebuf[pidx] += ratebuf[ltpidx];
}
// Finish length calculation if needed
if (doterm)
{
mq.finishLengthCalculation(ratebuf, pidx);
}
// Return the reduction in distortion
return dist;
}