/// <summary> Initializes the EBCOT rate allocator of entropy coded data. The layout /// of layers, and their bitrate constraints, is specified by the 'lyrs' /// parameter. /// /// </summary> /// <param name="src">The source of entropy coded data. /// /// </param> /// <param name="lyrs">The layers layout specification. /// /// </param> /// <param name="writer">The bit stream writer. /// /// </param> /// <seealso cref="ProgressionType"> /// /// </seealso> public EBCOTRateAllocator(CodedCBlkDataSrcEnc src, LayersInfo lyrs, CodestreamWriter writer, EncoderSpecs encSpec, ParameterList pl) : base(src, lyrs.TotNumLayers, writer, encSpec) { int minsbi, maxsbi; int i; SubbandAn sb, sb2; Coord ncblks = null; // If we do timing create necessary structures #if DO_TIMING // If we are timing make sure that 'finalize' gets called. //UPGRADE_ISSUE: Method 'java.lang.System.runFinalizersOnExit' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangSystem'" // CONVERSION PROBLEM? //System_Renamed.runFinalizersOnExit(true); // The System.runFinalizersOnExit() method is deprecated in Java // 1.2 since it can cause a deadlock in some cases. However, here // we use it only for profiling purposes and is disabled in // production code. initTime = 0L; buildTime = 0L; writeTime = 0L; #endif // Save the layer specs lyrSpec = lyrs; //Initialize the size of the RD slope rates array RDSlopesRates = new int[RD_SUMMARY_SIZE]; //Get number of tiles, components int nt = src.getNumTiles(); int nc = NumComps; //Allocate the coded code-blocks and truncation points indexes arrays cblks = new CBlkRateDistStats[nt][][][][]; for (int i2 = 0; i2 < nt; i2++) { cblks[i2] = new CBlkRateDistStats[nc][][][]; } truncIdxs = new int[nt][][][][][]; for (int i3 = 0; i3 < nt; i3++) { truncIdxs[i3] = new int[num_Layers][][][][]; for (int i4 = 0; i4 < num_Layers; i4++) { truncIdxs[i3][i4] = new int[nc][][][]; } } int cblkPerSubband; // Number of code-blocks per subband int mrl; // Number of resolution levels int l; // layer index int s; //subband index // Used to compute the maximum number of precincts for each resolution // level int tx0, ty0, tx1, ty1; // Current tile position in the reference grid int tcx0, tcy0, tcx1, tcy1; // Current tile position in the domain of // the image component int trx0, try0, trx1, try1; // Current tile position in the reduced // resolution image domain int xrsiz, yrsiz; // Component sub-sampling factors Coord tileI = null; Coord nTiles = null; int xsiz, ysiz, x0siz, y0siz; int xt0siz, yt0siz; int xtsiz, ytsiz; int cb0x = src.CbULX; int cb0y = src.CbULY; src.setTile(0, 0); for (int t = 0; t < nt; t++) { // Loop on tiles nTiles = src.getNumTiles(nTiles); tileI = src.getTile(tileI); x0siz = ImgULX; y0siz = ImgULY; xsiz = x0siz + ImgWidth; ysiz = y0siz + ImgHeight; xt0siz = src.TilePartULX; yt0siz = src.TilePartULY; xtsiz = src.NomTileWidth; ytsiz = src.NomTileHeight; // Tile's coordinates on the reference grid tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz; ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz; tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz; ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz; for (int c = 0; c < nc; c++) { // loop on components //Get the number of resolution levels sb = src.getAnSubbandTree(t, c); mrl = sb.resLvl + 1; // Initialize maximum number of precincts per resolution array if (numPrec == null) { Coord[][][] tmpArray = new Coord[nt][][]; for (int i5 = 0; i5 < nt; i5++) { tmpArray[i5] = new Coord[nc][]; } numPrec = tmpArray; } if (numPrec[t][c] == null) { numPrec[t][c] = new Coord[mrl]; } // Subsampling factors xrsiz = src.getCompSubsX(c); yrsiz = src.getCompSubsY(c); // Tile's coordinates in the image component domain //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" tcx0 = (int) System.Math.Ceiling(tx0 / (double) (xrsiz)); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" tcy0 = (int) System.Math.Ceiling(ty0 / (double) (yrsiz)); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" tcx1 = (int) System.Math.Ceiling(tx1 / (double) (xrsiz)); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" tcy1 = (int) System.Math.Ceiling(ty1 / (double) (yrsiz)); cblks[t][c] = new CBlkRateDistStats[mrl][][]; for (l = 0; l < num_Layers; l++) { truncIdxs[t][l][c] = new int[mrl][][]; } for (int r = 0; r < mrl; r++) { // loop on resolution levels // Tile's coordinates in the reduced resolution image // domain //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" trx0 = (int) System.Math.Ceiling(tcx0 / (double) (1 << (mrl - 1 - r))); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" try0 = (int) System.Math.Ceiling(tcy0 / (double) (1 << (mrl - 1 - r))); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" trx1 = (int) System.Math.Ceiling(tcx1 / (double) (1 << (mrl - 1 - r))); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" try1 = (int) System.Math.Ceiling(tcy1 / (double) (1 << (mrl - 1 - r))); // Calculate the maximum number of precincts for each // resolution level taking into account tile specific // options. double twoppx = (double) encSpec.pss.getPPX(t, c, r); double twoppy = (double) encSpec.pss.getPPY(t, c, r); numPrec[t][c][r] = new Coord(); if (trx1 > trx0) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" numPrec[t][c][r].x = (int) System.Math.Ceiling((trx1 - cb0x) / twoppx) - (int) System.Math.Floor((trx0 - cb0x) / twoppx); } else { numPrec[t][c][r].x = 0; } if (try1 > try0) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" numPrec[t][c][r].y = (int) System.Math.Ceiling((try1 - cb0y) / twoppy) - (int) System.Math.Floor((try0 - cb0y) / (double) twoppy); } else { numPrec[t][c][r].y = 0; } minsbi = (r == 0)?0:1; maxsbi = (r == 0)?1:4; cblks[t][c][r] = new CBlkRateDistStats[maxsbi][]; for (l = 0; l < num_Layers; l++) { truncIdxs[t][l][c][r] = new int[maxsbi][]; } for (s = minsbi; s < maxsbi; s++) { // loop on subbands //Get the number of blocks in the current subband sb2 = (SubbandAn) sb.getSubbandByIdx(r, s); ncblks = sb2.numCb; cblkPerSubband = ncblks.x * ncblks.y; cblks[t][c][r][s] = new CBlkRateDistStats[cblkPerSubband]; for (l = 0; l < num_Layers; l++) { truncIdxs[t][l][c][r][s] = new int[cblkPerSubband]; for (i = 0; i < cblkPerSubband; i++) { truncIdxs[t][l][c][r][s][i] = - 1; } } } // End loop on subbands } // End lopp on resolution levels } // End loop on components if (t != nt - 1) { src.nextTile(); } } // End loop on tiles //Initialize the packet encoder pktEnc = new PktEncoder(src, encSpec, numPrec, pl); // The layers array has to be initialized after the constructor since // it is needed that the bit stream header has been entirely written }
/// <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> Encodes a packet and returns the buffer containing the encoded packet /// header. The code-blocks appear in a 3D array of CBlkRateDistStats, /// 'cbs'. The first index is the tile index in lexicographical order, the /// second index is the subband index (as defined in the Subband class), /// and the third index is the code-block index (whithin the subband tile) /// in lexicographical order as well. The indexes of the new truncation /// points for each code-block are specified by the 3D array of int /// 'tIndx'. The indices of this array are the same as for cbs. The /// truncation point indices in 'tIndx' are the indices of the elements of /// the 'truncIdxs' array, of the CBlkRateDistStats class, that give the /// real truncation points. If a truncation point index is negative it /// means that the code-block has not been included in any layer yet. If /// the truncation point is less than or equal to the highest truncation /// point used in previous layers then the code-block is not included in /// the packet. Otherwise, if larger, the code-block is included in the /// packet. The body of the packet can be obtained with the /// getLastBodyBuf() and getLastBodyLen() methods. /// /// <p>Layers must be coded in increasing order, in consecutive manner, for /// each tile, component and resolution level (e.g., layer 1, then layer 2, /// etc.). For different tile, component and/or resolution level no /// particular order must be followed.</p> /// /// </summary> /// <param name="ly">The layer index (starts at 1). /// /// </param> /// <param name="c">The component index. /// /// </param> /// <param name="r">The resolution level /// /// </param> /// <param name="t">Index of the current tile /// /// </param> /// <param name="cbs">The 3D array of coded code-blocks. /// /// </param> /// <param name="tIndx">The truncation point indices for each code-block. /// /// </param> /// <param name="hbuf">The header buffer. If null a new BitOutputBuffer is created /// and returned. This buffer is reset before anything is written to it. /// /// </param> /// <param name="bbuf">The body buffer. If null a new one is created. If not large /// enough a new one is created. /// /// </param> /// <param name="pIdx">The precinct index. /// /// </param> /// <returns> The buffer containing the packet header. /// /// </returns> public virtual BitOutputBuffer encodePacket(int ly, int c, int r, int t, CBlkRateDistStats[][] cbs, int[][] tIndx, BitOutputBuffer hbuf, byte[] bbuf, int pIdx) { int b, i, maxi; int ncb; int thmax; int newtp; int cblen; int prednbits, nbits; // deltabits removed TagTreeEncoder cur_ttIncl, cur_ttMaxBP; // inclusion and bit-depth tag // trees int[] cur_prevtIdxs; // last encoded truncation points CBlkRateDistStats[] cur_cbs; int[] cur_tIndx; // truncation points to encode int minsb = (r == 0)?0:1; int maxsb = (r == 0)?1:4; Coord cbCoord = null; SubbandAn root = infoSrc.getAnSubbandTree(t, c); SubbandAn sb; roiInPkt = false; roiLen = 0; int mend, nend; // Checks if a precinct with such an index exists in this resolution // level if (pIdx >= ppinfo[t][c][r].Length) { packetWritable = false; return hbuf; } PrecInfo prec = ppinfo[t][c][r][pIdx]; // First, we check if packet is empty (i.e precinct 'pIdx' has no // code-block in any of the subbands) bool isPrecVoid = true; for (int s = minsb; s < maxsb; s++) { if (prec.nblk[s] == 0) { // The precinct has no code-block in this subband. continue; } else { // The precinct is not empty in at least one subband -> // stop isPrecVoid = false; break; } } if (isPrecVoid) { packetWritable = true; if (hbuf == null) { hbuf = new BitOutputBuffer(); } else { hbuf.reset(); } if (bbuf == null) { lbbuf = bbuf = new byte[1]; } hbuf.writeBit(0); lblen = 0; return hbuf; } if (hbuf == null) { hbuf = new BitOutputBuffer(); } else { hbuf.reset(); } // Invalidate last body buffer lbbuf = null; lblen = 0; // Signal that packet is present hbuf.writeBit(1); for (int s = minsb; s < maxsb; s++) { // Loop on subbands sb = (SubbandAn) root.getSubbandByIdx(r, s); // Go directly to next subband if the precinct has no code-block // in the current one. if (prec.nblk[s] == 0) { continue; } cur_ttIncl = ttIncl[t][c][r][pIdx][s]; cur_ttMaxBP = ttMaxBP[t][c][r][pIdx][s]; cur_prevtIdxs = prevtIdxs[t][c][r][s]; cur_cbs = cbs[s]; cur_tIndx = tIndx[s]; // Set tag tree values for code-blocks in this precinct mend = (prec.cblk[s] == null)?0:prec.cblk[s].Length; for (int m = 0; m < mend; m++) { nend = (prec.cblk[s][m] == null)?0:prec.cblk[s][m].Length; for (int n = 0; n < nend; n++) { cbCoord = prec.cblk[s][m][n].idx; b = cbCoord.x + cbCoord.y * sb.numCb.x; if (cur_tIndx[b] > cur_prevtIdxs[b] && cur_prevtIdxs[b] < 0) { // First inclusion cur_ttIncl.setValue(m, n, ly - 1); } if (ly == 1) { // First layer, need to set the skip of MSBP cur_ttMaxBP.setValue(m, n, cur_cbs[b].skipMSBP); } } } // Now encode the information for (int m = 0; m < prec.cblk[s].Length; m++) { // Vertical code-blocks for (int n = 0; n < prec.cblk[s][m].Length; n++) { // Horiz. cblks cbCoord = prec.cblk[s][m][n].idx; b = cbCoord.x + cbCoord.y * sb.numCb.x; // 1) Inclusion information if (cur_tIndx[b] > cur_prevtIdxs[b]) { // Code-block included in this layer if (cur_prevtIdxs[b] < 0) { // First inclusion // Encode layer info cur_ttIncl.encode(m, n, ly, hbuf); // 2) Max bitdepth info. Encode value thmax = cur_cbs[b].skipMSBP + 1; for (i = 1; i <= thmax; i++) { cur_ttMaxBP.encode(m, n, i, hbuf); } // Count body size for packet lblen += cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]]; } else { // Already in previous layer // Send "1" bit hbuf.writeBit(1); // Count body size for packet lblen += cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]] - cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]]; } // 3) Truncation point information if (cur_prevtIdxs[b] < 0) { newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]]; } else { newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]] - cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] - 1; } // Mix of switch and if is faster switch (newtp) { case 0: hbuf.writeBit(0); // Send one "0" bit break; case 1: hbuf.writeBits(2, 2); // Send one "1" and one "0" break; case 2: case 3: case 4: // Send two "1" bits followed by 2 bits // representation of newtp-2 hbuf.writeBits((3 << 2) | (newtp - 2), 4); break; default: if (newtp <= 35) { // Send four "1" bits followed by a five bits // representation of newtp-5 hbuf.writeBits((15 << 5) | (newtp - 5), 9); } else if (newtp <= 163) { // Send nine "1" bits followed by a seven bits // representation of newtp-36 hbuf.writeBits((511 << 7) | (newtp - 36), 16); } else { throw new System.ArithmeticException("Maximum number " + "of truncation " + "points exceeded"); } break; } } else { // Block not included in this layer if (cur_prevtIdxs[b] >= 0) { // Already in previous layer. Send "0" bit hbuf.writeBit(0); } else { // Not in any previous layers cur_ttIncl.encode(m, n, ly, hbuf); } // Go to the next one. continue; } // Code-block length // We need to compute the maximum number of bits needed to // signal the length of each terminated segment and the // final truncation point. newtp = 1; maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]]; cblen = (cur_prevtIdxs[b] < 0)?0:cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]]; // Loop on truncation points i = (cur_prevtIdxs[b] < 0)?0:cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] + 1; int minbits = 0; for (; i < maxi; i++, newtp++) { // If terminated truncation point calculate length if (cur_cbs[b].isTermPass != null && cur_cbs[b].isTermPass[i]) { // Calculate length cblen = cur_cbs[b].truncRates[i] - cblen; // Calculate number of needed bits prednbits = lblock[t][c][r][s][b] + MathUtil.log2(newtp); minbits = ((cblen > 0)?MathUtil.log2(cblen):0) + 1; // Update Lblock increment if needed for (int j = prednbits; j < minbits; j++) { lblock[t][c][r][s][b]++; hbuf.writeBit(1); } // Initialize for next length newtp = 0; cblen = cur_cbs[b].truncRates[i]; } } // Last truncation point length always sent // Calculate length cblen = cur_cbs[b].truncRates[i] - cblen; // Calculate number of bits prednbits = lblock[t][c][r][s][b] + MathUtil.log2(newtp); minbits = ((cblen > 0)?MathUtil.log2(cblen):0) + 1; // Update Lblock increment if needed for (int j = prednbits; j < minbits; j++) { lblock[t][c][r][s][b]++; hbuf.writeBit(1); } // End of comma-code increment hbuf.writeBit(0); // There can be terminated several segments, send length // info for all terminated truncation points in addition // to final one newtp = 1; maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]]; cblen = (cur_prevtIdxs[b] < 0)?0:cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]]; // Loop on truncation points and count the groups i = (cur_prevtIdxs[b] < 0)?0:cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] + 1; for (; i < maxi; i++, newtp++) { // If terminated truncation point, send length if (cur_cbs[b].isTermPass != null && cur_cbs[b].isTermPass[i]) { cblen = cur_cbs[b].truncRates[i] - cblen; nbits = MathUtil.log2(newtp) + lblock[t][c][r][s][b]; hbuf.writeBits(cblen, nbits); // Initialize for next length newtp = 0; cblen = cur_cbs[b].truncRates[i]; } } // Last truncation point length is always signalled // First calculate number of bits needed to signal // Calculate length cblen = cur_cbs[b].truncRates[i] - cblen; nbits = MathUtil.log2(newtp) + lblock[t][c][r][s][b]; hbuf.writeBits(cblen, nbits); } // End loop on horizontal code-blocks } // End loop on vertical code-blocks } // End loop on subband // -> Copy the data to the body buffer // Ensure size for body data if (bbuf == null || bbuf.Length < lblen) { bbuf = new byte[lblen]; } lbbuf = bbuf; lblen = 0; for (int s = minsb; s < maxsb; s++) { // Loop on subbands sb = (SubbandAn) root.getSubbandByIdx(r, s); cur_prevtIdxs = prevtIdxs[t][c][r][s]; cur_cbs = cbs[s]; cur_tIndx = tIndx[s]; ncb = cur_prevtIdxs.Length; mend = (prec.cblk[s] == null)?0:prec.cblk[s].Length; for (int m = 0; m < mend; m++) { // Vertical code-blocks nend = (prec.cblk[s][m] == null)?0:prec.cblk[s][m].Length; for (int n = 0; n < nend; n++) { // Horiz. cblks cbCoord = prec.cblk[s][m][n].idx; b = cbCoord.x + cbCoord.y * sb.numCb.x; if (cur_tIndx[b] > cur_prevtIdxs[b]) { // Block included in this precinct -> Copy data to // body buffer and get code-size if (cur_prevtIdxs[b] < 0) { cblen = cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]]; Array.Copy(cur_cbs[b].data, 0, lbbuf, lblen, cblen); } else { cblen = cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]] - cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]]; Array.Copy(cur_cbs[b].data, cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]], lbbuf, lblen, cblen); } lblen += cblen; // Verifies if this code-block contains new ROI // information if (cur_cbs[b].nROIcoeff != 0 && (cur_prevtIdxs[b] == - 1 || cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] <= cur_cbs[b].nROIcp - 1)) { roiInPkt = true; roiLen = lblen; } // Update truncation point cur_prevtIdxs[b] = cur_tIndx[b]; } } // End loop on horizontal code-blocks } // End loop on vertical code-blocks } // End loop on subbands packetWritable = true; // Must never happen if (hbuf.Length == 0) { throw new System.InvalidOperationException("You have found a bug in PktEncoder, method:" + " encodePacket"); } return hbuf; }
/// <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> 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; } } }