/// <summary> Performs the magnitude refinement pass on the specified data and
/// bit-plane. It codes the samples which are significant and which do not
/// have the "visited" state bit turned on, using the MR primitive. The
/// "visited" state bit is not mofified for any samples.
///
/// </summary>
/// <param name="srcblk">The code-block data to code
///
/// </param>
/// <param name="mq">The MQ-coder to use
///
/// </param>
/// <param name="doterm">If true it performs an MQ-coder termination after the end
/// of the pass
///
/// </param>
/// <param name="bp">The bit-plane to code
///
/// </param>
/// <param name="state">The state information for the code-block
///
/// </param>
/// <param name="fm">The distortion estimation lookup table for MR
///
/// </param>
/// <param name="symbuf">The buffer to hold symbols to send to the MQ coder
///
/// </param>
/// <param name="ctxtbuf">A buffer to hold the contexts to use in sending the
/// buffered symbols to the MQ coder.
///
/// </param>
/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at
/// the end of this coding pass.
///
/// </param>
/// <param name="pidx">The coding pass index. Is the index in the 'ratebuf' array
/// where to store the coded length after this coding pass.
///
/// </param>
/// <param name="ltpidx">The index of the last pass that was terminated, or
/// negative if none.
///
/// </param>
/// <param name="options">The bitmask of entropy coding options to apply to the
/// code-block
///
/// </param>
/// <returns> The decrease in distortion for this pass, in the fixed-point
/// normalized representation of the 'FS_LOSSY' and 'FS_LOSSLESS' tables.
///
/// </returns>
static private int magRefPass(CBlkWTData srcblk, MQCoder mq, bool doterm, int bp, int[] state, int[] fm, int[] symbuf, int[] ctxtbuf, int[] ratebuf, int pidx, int ltpidx, int options)
{
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[] 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
int nstripes; // The number of stripes in the code-block
int sheight; // Height of the current stripe
// 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 bit just coded plus 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;
// 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++)
{
// Do half top of column
j = sj;
csj = state[j];
// If any of the two samples is significant and not yet
// visited in the current bit-plane we can not skip them
if ((((SupportClass.URShift(csj, 1)) & (~ csj)) & VSTD_MASK_R1R2) != 0)
{
k = sk;
// Scan first row
if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == STATE_SIG_R1)
{
// Apply MR primitive
symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
ctxtbuf[nsym++] = MR_LUT[csj & MR_MASK];
// Update the STATE_PREV_MR bit
csj |= STATE_PREV_MR_R1;
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
}
if (sheight < 2)
{
state[j] = csj;
continue;
}
// Scan second row
if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
{
k += dscanw;
// Apply MR primitive
symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
ctxtbuf[nsym++] = MR_LUT[(SupportClass.URShift(csj, STATE_SEP)) & MR_MASK];
// Update the STATE_PREV_MR bit
csj |= STATE_PREV_MR_R2;
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
}
state[j] = csj;
}
// Do half bottom of column
if (sheight < 3)
continue;
j += sscanw;
csj = state[j];
// If any of the two samples is significant and not yet
// visited in the current bit-plane we can not skip them
if ((((SupportClass.URShift(csj, 1)) & (~ csj)) & VSTD_MASK_R1R2) != 0)
{
k = sk + (dscanw << 1);
// Scan first row
if ((csj & (STATE_SIG_R1 | STATE_VISITED_R1)) == STATE_SIG_R1)
{
// Apply MR primitive
symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
ctxtbuf[nsym++] = MR_LUT[csj & MR_MASK];
// Update the STATE_PREV_MR bit
csj |= STATE_PREV_MR_R1;
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
}
if (sheight < 4)
{
state[j] = csj;
continue;
}
// Scan second row
if ((state[j] & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2)
{
k += dscanw;
// Apply MR primitive
symbuf[nsym] = SupportClass.URShift((data[k] & mask), bp);
ctxtbuf[nsym++] = MR_LUT[(SupportClass.URShift(csj, STATE_SEP)) & MR_MASK];
// Update the STATE_PREV_MR bit
csj |= STATE_PREV_MR_R2;
// Update distortion
normval = (data[k] >> downshift) << upshift;
dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)];
}
state[j] = csj;
}
}
// Code all buffered symbols, if any
if (nsym > 0)
mq.codeSymbols(symbuf, ctxtbuf, nsym);
}
// 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;
}