/// <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(); }
/// <summary> Returns the next coded code-block in the current tile for the specified /// component, as a copy (see below). The order in which code-blocks are /// returned is not specified. However each code-block is returned only /// once and all code-blocks will be returned if the method is called 'N' /// times, where 'N' is the number of code-blocks in the tile. After all /// the code-blocks have been returned for the current tile calls to this /// method will return 'null'. /// /// <p>When changing the current tile (through 'setTile()' or 'nextTile()') /// this method will always return the first code-block, as if this method /// was never called before for the new current tile.</p> /// /// <p>The data returned by this method is always a copy of the internal /// data of this object, if any, and it can be modified "in place" without /// any problems after being returned.</p> /// /// </summary> /// <param name="c">The component for which to return the next code-block. /// /// </param> /// <param name="ccb">If non-null this object might be used in returning the coded /// code-block in this or any subsequent call to this method. If null a new /// one is created and returned. If the 'data' array of 'cbb' is not null /// it may be reused to return the compressed data. /// /// </param> /// <returns> The next coded code-block in the current tile for component /// 'n', or null if all code-blocks for the current tile have been /// returned. /// /// </returns> /// <seealso cref="CBlkRateDistStats"> /// /// </seealso> public override CBlkRateDistStats getNextCodeBlock(int c, CBlkRateDistStats ccb) { #if DO_TIMING long stime = 0L; // Start time for timed sections #endif // Use single threaded implementation // Get code-block data from source srcblkT[0] = src.getNextInternCodeBlock(c, srcblkT[0]); #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif if (srcblkT[0] == null) { // We got all code-blocks return null; } // Initialize thread local variables if ((opts[tIdx][c] & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && boutT[0] == null) { boutT[0] = new BitToByteOutput(outT[0]); } // Initialize output code-block if (ccb == null) { ccb = new CBlkRateDistStats(); } // Compress code-block compressCodeBlock(c, ccb, srcblkT[0], mqT[0], boutT[0], outT[0], stateT[0], distbufT[0], ratebufT[0], istermbufT[0], symbufT[0], ctxtbufT[0], opts[tIdx][c], isReversible(tIdx, c), lenCalc[tIdx][c], tType[tIdx][c]); #if DO_TIMING time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif // Return result return ccb; }
/// <summary> Performs the significance propagation pass on the specified data and /// bit-plane, without using the arithmetic coder. It codes all /// insignificant samples which have, at least, one of its immediate eight /// neighbors already significant, using the ZC and SC primitives as /// needed. It toggles the "visited" state bit to 1 for all those samples. /// /// <p>In this method, the arithmetic coder is bypassed, and raw bits are /// directly written in the bit stream (useful when distribution are close /// to uniform, for intance, at high bit-rates and at lossless /// compression).</p> /// /// </summary> /// <param name="srcblk">The code-block data to code /// /// </param> /// <param name="bout">The bit based output /// /// </param> /// <param name="doterm">If true the bit based output is byte aligned 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="fs">The distortion estimation lookup table for SC /// /// </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 rawSigProgPass(CBlkWTData srcblk, BitToByteOutput bout, bool doterm, int bp, int[] state, int[] fs, 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 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 nsym = 0; // Number of symbol int sym; // The symbol to code 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 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 (; sk < stopsk; sk++, sj++) { // Do half top of column j = sj; csj = state[j]; // If any of the two samples is not significant and has a // non-zero context (i.e. some neighbor is significant) we can // not skip them if ((((~ csj) & (csj << 2)) & SIG_MASK_R1R2) != 0) { k = sk; // Scan first row if ((csj & (STATE_SIG_R1 | STATE_NZ_CTXT_R1)) == STATE_NZ_CTXT_R1) { // Apply zero coding sym = SupportClass.URShift((data[k] & mask), bp); bout.writeBit(sym); nsym++; if (sym != 0) { // Became significant // Apply sign coding sym = SupportClass.URShift(data[k], 31); bout.writeBit(sym); nsym++; // 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)]; } else { csj |= STATE_VISITED_R1; } } if (sheight < 2) { state[j] = csj; continue; } // Scan second row if ((csj & (STATE_SIG_R2 | STATE_NZ_CTXT_R2)) == STATE_NZ_CTXT_R2) { k += dscanw; // Apply zero coding sym = SupportClass.URShift((data[k] & mask), bp); bout.writeBit(sym); nsym++; if (sym != 0) { // Became significant // Apply sign coding sym = SupportClass.URShift(data[k], 31); bout.writeBit(sym); nsym++; // 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)]; } else { csj |= STATE_VISITED_R2; } } state[j] = csj; } // Do half bottom of column if (sheight < 3) continue; j += sscanw; csj = state[j]; // If any of the two samples is not significant and has a // non-zero context (i.e. some neighbor is significant) we can // not skip them if ((((~ csj) & (csj << 2)) & SIG_MASK_R1R2) != 0) { k = sk + (dscanw << 1); // Scan first row if ((csj & (STATE_SIG_R1 | STATE_NZ_CTXT_R1)) == STATE_NZ_CTXT_R1) { sym = SupportClass.URShift((data[k] & mask), bp); bout.writeBit(sym); nsym++; if (sym != 0) { // Became significant // Apply sign coding sym = SupportClass.URShift(data[k], 31); bout.writeBit(sym); nsym++; // 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)]; } else { csj |= STATE_VISITED_R1; } } if (sheight < 4) { state[j] = csj; continue; } if ((csj & (STATE_SIG_R2 | STATE_NZ_CTXT_R2)) == STATE_NZ_CTXT_R2) { k += dscanw; // Apply zero coding sym = SupportClass.URShift((data[k] & mask), bp); bout.writeBit(sym); nsym++; if (sym != 0) { // Became significant // Apply sign coding sym = SupportClass.URShift(data[k], 31); bout.writeBit(sym); nsym++; // 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)]; } else { csj |= STATE_VISITED_R2; } } state[j] = csj; } } } // Get length and terminate if needed if (doterm) { ratebuf[pidx] = bout.terminate(); } else { ratebuf[pidx] = bout.length(); } // Add length of previous segments, if any if (ltpidx >= 0) { ratebuf[pidx] += ratebuf[ltpidx]; } // Return the reduction in distortion return dist; }
/// <summary> Performs the magnitude refinement pass on the specified data and /// bit-plane, without using the arithmetic coder. 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. /// /// <p>In this method, the arithmetic coder is bypassed, and raw bits are /// directly written in the bit stream (useful when distribution are close /// to uniform, for intance, at high bit-rates and at lossless /// compression). The 'STATE_PREV_MR_R1' and 'STATE_PREV_MR_R2' bits are /// not set because they are used only when the arithmetic coder is not /// bypassed.</p> /// /// </summary> /// <param name="srcblk">The code-block data to code /// /// </param> /// <param name="bout">The bit based output /// /// </param> /// <param name="doterm">If true the bit based output is byte aligned 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="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 rawMagRefPass(CBlkWTData srcblk, BitToByteOutput bout, bool doterm, int bp, int[] state, int[] fm, 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 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 int nsym = 0; // 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 (; 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) { // Code bit "raw" bout.writeBit(SupportClass.URShift((data[k] & mask), bp)); nsym++; // No need to set STATE_PREV_MR_R1 since all magnitude // refinement passes to follow are "raw" // Update distortion normval = (data[k] >> downshift) << upshift; dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)]; } if (sheight < 2) continue; // Scan second row if ((csj & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2) { k += dscanw; // Code bit "raw" bout.writeBit(SupportClass.URShift((data[k] & mask), bp)); nsym++; // No need to set STATE_PREV_MR_R2 since all magnitude // refinement passes to follow are "raw" // Update distortion normval = (data[k] >> downshift) << upshift; dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)]; } } // 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) { // Code bit "raw" bout.writeBit(SupportClass.URShift((data[k] & mask), bp)); nsym++; // No need to set STATE_PREV_MR_R1 since all magnitude // refinement passes to follow are "raw" // Update distortion normval = (data[k] >> downshift) << upshift; dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)]; } if (sheight < 4) continue; // Scan second row if ((state[j] & (STATE_SIG_R2 | STATE_VISITED_R2)) == STATE_SIG_R2) { k += dscanw; // Code bit "raw" bout.writeBit(SupportClass.URShift((data[k] & mask), bp)); nsym++; // No need to set STATE_PREV_MR_R2 since all magnitude // refinement passes to follow are "raw" // Update distortion normval = (data[k] >> downshift) << upshift; dist += fm[normval & ((1 << MSE_LKP_BITS) - 1)]; } } } } // Get length and terminate if needed if (doterm) { ratebuf[pidx] = bout.terminate(); } else { ratebuf[pidx] = bout.length(); } // Add length of previous segments, if any if (ltpidx >= 0) { ratebuf[pidx] += ratebuf[ltpidx]; } // Return the reduction in distortion return dist; }
/// <summary> Returns the next coded code-block in the current tile for the specified /// component, as a copy (see below). The order in which code-blocks are /// returned is not specified. However each code-block is returned only /// once and all code-blocks will be returned if the method is called 'N' /// times, where 'N' is the number of code-blocks in the tile. After all /// the code-blocks have been returned for the current tile calls to this /// method will return 'null'. /// /// <p>When changing the current tile (through 'setTile()' or 'nextTile()') /// this method will always return the first code-block, as if this method /// was never called before for the new current tile.</p> /// /// <p>The data returned by this method is always a copy of the internal /// data of this object, if any, and it can be modified "in place" without /// any problems after being returned.</p> /// /// </summary> /// <param name="c">The component for which to return the next code-block. /// /// </param> /// <param name="ccb">If non-null this object might be used in returning the coded /// code-block in this or any subsequent call to this method. If null a new /// one is created and returned. If the 'data' array of 'cbb' is not null /// it may be reused to return the compressed data. /// /// </param> /// <returns> The next coded code-block in the current tile for component /// 'n', or null if all code-blocks for the current tile have been /// returned. /// /// </returns> /// <seealso cref="CBlkRateDistStats"> /// /// </seealso> public override CBlkRateDistStats getNextCodeBlock(int c, CBlkRateDistStats ccb) { #if DO_TIMING long stime = 0L; // Start time for timed sections #endif if (tPool == null) { // Use single threaded implementation // Get code-block data from source srcblkT[0] = src.getNextInternCodeBlock(c, srcblkT[0]); #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif if (srcblkT[0] == null) { // We got all code-blocks return null; } // Initialize thread local variables if ((opts[tIdx][c] & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && boutT[0] == null) { boutT[0] = new BitToByteOutput(outT[0]); } // Initialize output code-block if (ccb == null) { ccb = new CBlkRateDistStats(); } // Compress code-block compressCodeBlock(c, ccb, srcblkT[0], mqT[0], boutT[0], outT[0], stateT[0], distbufT[0], ratebufT[0], istermbufT[0], symbufT[0], ctxtbufT[0], opts[tIdx][c], isReversible(tIdx, c), lenCalc[tIdx][c], tType[tIdx][c]); #if DO_TIMING time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif // Return result return ccb; } else { // Use multiple threaded implementation int cIdx; // Compressor idx Compressor compr; // Compressor #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif // Give data to all free compressors, using the current component while (!finishedTileComponent[c] && !(idleComps.Count == 0)) { // Get an idle compressor compr = (Compressor) SupportClass.StackSupport.Pop(idleComps); cIdx = compr.Idx; // Get data for the compressor and wake it up #if DO_TIMING time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif srcblkT[cIdx] = src.getNextInternCodeBlock(c, srcblkT[cIdx]); #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif if (srcblkT[cIdx] != null) { // Initialize thread local variables if ((opts[tIdx][c] & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0 && boutT[cIdx] == null) { boutT[cIdx] = new BitToByteOutput(outT[cIdx]); } // Initialize output code-block and compressor thread if (ccb == null) ccb = new CBlkRateDistStats(); compr.ccb = ccb; compr.c = c; compr.options = opts[tIdx][c]; compr.rev = isReversible(tIdx, c); compr.lcType = lenCalc[tIdx][c]; compr.tType = tType[tIdx][c]; nBusyComps[c]++; ccb = null; // Send compressor to execution in thread pool tPool.runTarget(compr, completedComps[c]); } else { // We finished with all the code-blocks in the current // tile component idleComps.Add(compr); finishedTileComponent[c] = true; } } // If there are threads for this component which result has not // been returned yet, get it if (nBusyComps[c] > 0) { lock (completedComps[c]) { // If no compressor is done, wait until one is if ((completedComps[c].Count == 0)) { try { #if DO_TIMING time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif System.Threading.Monitor.Wait(completedComps[c]); #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif } catch (System.Threading.ThreadInterruptedException) { } } // Remove the thread from the completed queue and put it // on the idle queue compr = (Compressor) SupportClass.StackSupport.Pop(completedComps[c]); cIdx = compr.Idx; nBusyComps[c]--; idleComps.Add(compr); // Check targets error condition tPool.checkTargetErrors(); // Get the result of compression and return that. #if DO_TIMING time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif return compr.ccb; } } else { // Check targets error condition tPool.checkTargetErrors(); // Printing timing info if necessary #if DO_TIMING time[c] += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif // Nothing is running => no more code-blocks return null; } } }