/// <summary> Compresses the code-block in 'srcblk' and puts the results in 'ccb',
/// using the specified options and temporary storage.
///
/// </summary>
/// <param name="c">The component for which to return the next code-block.
///
/// </param>
/// <param name="ccb">The object where the compressed data will be stored. If the
/// 'data' array of 'cbb' is not null it may be reused to return the
/// compressed data.
///
/// </param>
/// <param name="srcblk">The code-block data to code
///
/// </param>
/// <param name="mq">The MQ-coder to use
///
/// </param>
/// <param name="bout">The bit level output to use. Used only if 'OPT_BYPASS' is
/// turned on in the 'options' argument.
///
/// </param>
/// <param name="out">The byte buffer trough which the compressed data is stored.
///
/// </param>
/// <param name="state">The state information for the code-block
///
/// </param>
/// <param name="distbuf">The buffer where to store the distortion at
/// the end of each coding pass.
///
/// </param>
/// <param name="ratebuf">The buffer where to store the rate (i.e. coded lenth) at
/// the end of each coding pass.
///
/// </param>
/// <param name="istermbuf">The buffer where to store the terminated flag for each
/// coding pass.
///
/// </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="options">The options to use when coding this code-block
///
/// </param>
/// <param name="rev">The reversible flag. Should be true if the source of this
/// code-block's data is reversible.
///
/// </param>
/// <param name="lcType">The type of length calculation to use with the MQ coder.
///
/// </param>
/// <param name="tType">The type of termination to use with the MQ coder.
///
/// </param>
/// <seealso cref="getNextCodeBlock">
///
/// </seealso>
static private void compressCodeBlock(int c, CBlkRateDistStats ccb, CBlkWTData srcblk, MQCoder mq, BitToByteOutput bout, ByteOutputBuffer out_Renamed, int[] state, double[] distbuf, int[] ratebuf, bool[] istermbuf, int[] symbuf, int[] ctxtbuf, int options, bool rev, int lcType, int tType)
{
// NOTE: This method should not access any non-final instance or
// static variables, either directly or indirectly through other
// methods in order to be sure that the method is thread safe.
int[] zc_lut; // The ZC lookup table to use
int skipbp; // The number of non-significant bit-planes to skip
int curbp; // The current magnitude bit-plane (starts at 30)
int[] fm; // The distortion estimation lookup table for MR
int[] fs; // The distortion estimation lookup table for SC
int lmb; // The least significant magnitude bit
int npass; // The number of coding passes, for R-D statistics
double msew; // The distortion (MSE weight) for the current bit-plane
double totdist; // The total cumulative distortion decrease
int ltpidx; // The index of the last pass which is terminated
// Check error-resilient termination
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0 && tType != MQCoder.TERM_PRED_ER)
{
throw new System.ArgumentException("Embedded error-resilient info " + "in MQ termination option " + "specified but incorrect MQ " + "termination " + "policy specified");
}
// Set MQ flags
mq.LenCalcType = lcType;
mq.TermType = tType;
lmb = 30 - srcblk.magbits + 1;
// If there are more bit-planes to code than the implementation
// bit-depth set lmb to 0
lmb = (lmb < 0)?0:lmb;
// Reset state
ArrayUtil.intArraySet(state, 0);
// Find the most significant bit-plane
skipbp = calcSkipMSBP(srcblk, lmb);
// Initialize output code-block
ccb.m = srcblk.m;
ccb.n = srcblk.n;
ccb.sb = srcblk.sb;
ccb.nROIcoeff = srcblk.nROIcoeff;
ccb.skipMSBP = skipbp;
if (ccb.nROIcoeff != 0)
{
ccb.nROIcp = 3 * (srcblk.nROIbp - skipbp - 1) + 1;
}
else
{
ccb.nROIcp = 0;
}
// Choose correct ZC lookup table for global orientation
switch (srcblk.sb.orientation)
{
case Subband.WT_ORIENT_HL:
zc_lut = ZC_LUT_HL;
break;
case Subband.WT_ORIENT_LL:
case Subband.WT_ORIENT_LH:
zc_lut = ZC_LUT_LH;
break;
case Subband.WT_ORIENT_HH:
zc_lut = ZC_LUT_HH;
break;
default:
throw new System.InvalidOperationException("JJ2000 internal error");
}
// Loop on significant magnitude bit-planes doing the 3 passes
curbp = 30 - skipbp;
fs = FS_LOSSY;
fm = FM_LOSSY;
msew = System.Math.Pow(2, ((curbp - lmb) << 1) - MSE_LKP_FRAC_BITS) * srcblk.sb.stepWMSE * srcblk.wmseScaling;
totdist = 0f;
npass = 0;
ltpidx = - 1;
// First significant bit-plane has only the pass pass
if (curbp >= lmb)
{
// Do we need the "lossless" 'fs' table ?
if (rev && curbp == lmb)
{
fs = FM_LOSSLESS;
}
// We terminate if regular termination, last bit-plane, or next
// bit-plane is "raw".
istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || curbp == lmb || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp) >= curbp);
totdist += cleanuppass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
distbuf[npass] = totdist;
if (istermbuf[npass])
ltpidx = npass;
npass++;
msew *= 0.25;
curbp--;
}
// Other bit-planes have all passes
while (curbp >= lmb)
{
// Do we need the "lossless" 'fs' and 'fm' tables ?
if (rev && curbp == lmb)
{
fs = FS_LOSSLESS;
fm = FM_LOSSLESS;
}
// Do the significance propagation pass
// We terminate if regular termination only
istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0;
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) == 0 || (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp <= curbp))
{
// No bypass coding
totdist += sigProgPass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
}
else
{
// Bypass ("raw") coding
bout.PredTerm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0;
totdist += rawSigProgPass(srcblk, bout, istermbuf[npass], curbp, state, fs, ratebuf, npass, ltpidx, options) * msew;
}
distbuf[npass] = totdist;
if (istermbuf[npass])
ltpidx = npass;
npass++;
// Do the magnitude refinement pass
// We terminate if regular termination or bypass ("raw") coding
istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp > curbp));
if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) == 0 || (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp <= curbp))
{
// No bypass coding
totdist += magRefPass(srcblk, mq, istermbuf[npass], curbp, state, fm, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
}
else
{
// Bypass ("raw") coding
bout.PredTerm = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM) != 0;
totdist += rawMagRefPass(srcblk, bout, istermbuf[npass], curbp, state, fm, ratebuf, npass, ltpidx, options) * msew;
}
distbuf[npass] = totdist;
if (istermbuf[npass])
ltpidx = npass;
npass++;
// Do the clenup pass
// We terminate if regular termination, last bit-plane, or next
// bit-plane is "raw".
istermbuf[npass] = (options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0 || curbp == lmb || ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && (31 - CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_NON_BYPASS_MS_BP - skipbp) >= curbp);
totdist += cleanuppass(srcblk, mq, istermbuf[npass], curbp, state, fs, zc_lut, symbuf, ctxtbuf, ratebuf, npass, ltpidx, options) * msew;
distbuf[npass] = totdist;
if (istermbuf[npass])
ltpidx = npass;
npass++;
// Goto next bit-plane
msew *= 0.25;
curbp--;
}
// Copy compressed data and rate-distortion statistics to output
ccb.data = new byte[out_Renamed.size()];
out_Renamed.toByteArray(0, out_Renamed.size(), ccb.data, 0);
checkEndOfPassFF(ccb.data, ratebuf, istermbuf, npass);
ccb.selectConvexHull(ratebuf, distbuf, (options & (CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS | CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS)) != 0?istermbuf:null, npass, rev);
// Reset MQ coder and bit output for next code-block
mq.reset();
if (bout != null)
bout.reset();
}