/* * CVS identifier: * * $Id: EBCOTRateAllocator.java,v 1.97 2002/05/22 14:59:44 grosbois Exp $ * * Class: EBCOTRateAllocator * * Description: Generic interface for post-compression * rate allocator. * * * * COPYRIGHT: * * This software module was originally developed by Raphaël Grosbois and * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research * Centre France S.A) in the course of development of the JPEG2000 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This * software module is an implementation of a part of the JPEG 2000 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio * Systems AB and Canon Research Centre France S.A (collectively JJ2000 * Partners) agree not to assert against ISO/IEC and users of the JPEG * 2000 Standard (Users) any of their rights under the copyright, not * including other intellectual property rights, for this software module * with respect to the usage by ISO/IEC and Users of this software module * or modifications thereof for use in hardware or software products * claiming conformance to the JPEG 2000 Standard. Those intending to use * this software module in hardware or software products are advised that * their use may infringe existing patents. The original developers of * this software module, JJ2000 Partners and ISO/IEC assume no liability * for use of this software module or modifications thereof. No license * or right to this software module is granted for non JPEG 2000 Standard * conforming products. JJ2000 Partners have full right to use this * software module for his/her own purpose, assign or donate this * software module to any third party and to inhibit third parties from * using this software module for non JPEG 2000 Standard conforming * products. This copyright notice must be included in all copies or * derivative works of this software module. * * Copyright (c) 1999/2000 JJ2000 Partners. * */ using System; using CSJ2K.j2k.codestream.writer; using CSJ2K.j2k.wavelet.analysis; using CSJ2K.j2k.entropy.encoder; using CSJ2K.j2k.codestream; using CSJ2K.j2k.entropy; using CSJ2K.j2k.encoder; using CSJ2K.j2k.image; using CSJ2K.j2k.util; namespace CSJ2K.j2k.entropy.encoder { /// This implements the EBCOT post compression rate allocation algorithm. This /// algorithm finds the most suitable truncation points for the set of /// code-blocks, for each layer target bitrate. It works by first collecting /// the rate distortion info from all code-blocks, in all tiles and all /// components, and then running the rate-allocation on the whole image at /// once, for each layer. /// ///

This implementation also provides some timing features. They can be /// enabled by setting the 'DO_TIMING' constant of this class to true and /// recompiling. The timing uses the 'System.currentTimeMillis()' Java API /// call, which returns wall clock time, not the actual CPU time used. The /// timing results will be printed on the message output. Since the times /// reported are wall clock times and not CPU usage times they can not be added /// to find the total used time (i.e. some time might be counted in several /// places). When timing is disabled ('DO_TIMING' is false) there is no penalty /// if the compiler performs some basic optimizations. Even if not the penalty /// should be negligeable.

/// ///
/// /// /// /// /// /// /// public class EBCOTRateAllocator:PostCompRateAllocator { /// Whether to collect timing information or not: false. Used as a compile /// time directive. /// #if DO_TIMING /// The wall time for the initialization. //private long initTime; /// The wall time for the building of layers. //private long buildTime; /// The wall time for the writing of layers. //private long writeTime; #endif /// 5D Array containing all the coded code-blocks: /// /// /// /// private CBlkRateDistStats[][][][][] cblks; /// 6D Array containing the indices of the truncation points. It actually /// contains the index of the element in CBlkRateDistStats.truncIdxs that /// gives the real truncation point index. /// /// /// /// private int[][][][][][] truncIdxs; /// Number of precincts in each resolution level: /// /// /// /// private Coord[][][] numPrec; /// Array containing the layers information. private EBCOTLayer[] layers; /// The log of 2, natural base //UPGRADE_NOTE: Final was removed from the declaration of 'LOG2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" private static readonly double LOG2 = System.Math.Log(2); /// The normalization offset for the R-D summary table private const int RD_SUMMARY_OFF = 24; /// The size of the summary table private const int RD_SUMMARY_SIZE = 64; /// The relative precision for float data. This is the relative tolerance /// up to which the layer slope thresholds are calculated. /// private const float FLOAT_REL_PRECISION = 1e-4f; /// The precision for float data type, in an absolute sense. Two float /// numbers are considered "equal" if they are within this precision. /// private const float FLOAT_ABS_PRECISION = 1e-10f; /// Minimum average size of a packet. If layer has less bytes than the /// this constant multiplied by number of packets in the layer, then the /// layer is skipped. /// private const int MIN_AVG_PACKET_SZ = 32; /// The R-D summary information collected from the coding of all /// code-blocks. For each entry it contains the accumulated length of all /// truncation points that have a slope not less than /// '2*(k-RD_SUMMARY_OFF)', where 'k' is the entry index. /// ///

Therefore, the length at entry 'k' is the total number of bytes of /// code-block data that would be obtained if the truncation slope was /// chosen as '2*(k-RD_SUMMARY_OFF)', without counting the overhead /// associated with the packet heads.

/// ///

This summary is used to estimate the relation of the R-D slope to /// coded length, and to obtain absolute minimums on the slope given a /// length.

///
private int[] RDSlopesRates; /// Packet encoder. private PktEncoder pktEnc; /// The layer specifications private LayersInfo lyrSpec; /// The maximum slope accross all code-blocks and truncation points. private float maxSlope; /// The minimum slope accross all code-blocks and truncation points. private float minSlope; /// Initializes the EBCOT rate allocator of entropy coded data. The layout /// of layers, and their bitrate constraints, is specified by the 'lyrs' /// parameter. /// /// /// The source of entropy coded data. /// /// /// The layers layout specification. /// /// /// The bit stream writer. /// /// /// /// /// 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 } #if DO_TIMING /// Prints the timing information, if collected, and calls 'finalize' on /// the super class. /// /// ~EBCOTRateAllocator() { System.Text.StringBuilder sb; sb = new System.Text.StringBuilder("EBCOTRateAllocator wall clock times:\n"); sb.Append(" initialization: "); sb.Append(initTime); sb.Append(" ms\n"); sb.Append(" layer building: "); sb.Append(buildTime); sb.Append(" ms\n"); sb.Append(" final writing: "); sb.Append(writeTime); sb.Append(" ms"); FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.INFO, sb.ToString()); //UPGRADE_NOTE: Call to 'super.finalize()' was removed. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1124'" } #endif /// Runs the rate allocation algorithm and writes the data to the bit /// stream writer object provided to the constructor. /// /// public override void runAndWrite() { //Now, run the rate allocation buildAndWriteLayers(); } /// Initializes the layers array. This must be called after the main header /// has been entirely written or simulated, so as to take its overhead into /// account. This method will get all the code-blocks and then initialize /// the target bitrates for each layer, according to the specifications. /// /// public override void initialize() { int n, i, l; int ho; // The header overhead (in bytes) float np; // The number of pixels divided by the number of bits per byte double ls; // Step for log-scale double basebytes; int lastbytes, newbytes, nextbytes; int loopnlyrs; int minlsz; // The minimum allowable number of bytes in a layer int totenclength; int maxpkt; int numTiles = src.getNumTiles(); int numComps = src.NumComps; int numLvls; int avgPktLen; #if DO_TIMING long stime = 0L; #endif // Start by getting all the code-blocks, we need this in order to have // an idea of the total encoded bitrate. getAllCodeBlocks(); #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif // Now get the total encoded length totenclength = RDSlopesRates[0]; // all the encoded data // Make a rough estimation of the packet head overhead, as 2 bytes per // packet in average (plus EPH / SOP) , and add that to the total // encoded length for (int t = 0; t < numTiles; t++) { avgPktLen = 2; // Add SOP length if set if (((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper())) { avgPktLen += CSJ2K.j2k.codestream.Markers.SOP_LENGTH; } // Add EPH length if set if (((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper())) { avgPktLen += CSJ2K.j2k.codestream.Markers.EPH_LENGTH; } for (int c = 0; c < numComps; c++) { numLvls = src.getAnSubbandTree(t, c).resLvl + 1; if (!src.precinctPartitionUsed(c, t)) { // Precinct partition is not used so there is only // one packet per resolution level/layer totenclength += num_Layers * avgPktLen * numLvls; } else { // Precinct partition is used so for each // component/tile/resolution level, we get the maximum // number of packets for (int rl = 0; rl < numLvls; rl++) { maxpkt = numPrec[t][c][rl].x * numPrec[t][c][rl].y; totenclength += num_Layers * avgPktLen * maxpkt; } } } // End loop on components } // End loop on tiles // If any layer specifies more than 'totenclength' as its target // length then 'totenclength' is used. This is to prevent that // estimated layers get excessively large target lengths due to an // excessively large target bitrate. At the end the last layer is set // to the target length corresponding to the overall target // bitrate. Thus, 'totenclength' can not limit the total amount of // encoded data, as intended. ho = headEnc.Length; np = src.ImgWidth * src.ImgHeight / 8f; // SOT marker must be taken into account for (int t = 0; t < numTiles; t++) { headEnc.reset(); headEnc.encodeTilePartHeader(0, t); ho += headEnc.Length; } layers = new EBCOTLayer[num_Layers]; for (n = num_Layers - 1; n >= 0; n--) { layers[n] = new EBCOTLayer(); } minlsz = 0; // To keep compiler happy for (int t = 0; t < numTiles; t++) { for (int c = 0; c < numComps; c++) { numLvls = src.getAnSubbandTree(t, c).resLvl + 1; if (!src.precinctPartitionUsed(c, t)) { // Precinct partition is not used minlsz += MIN_AVG_PACKET_SZ * numLvls; } else { // Precinct partition is used for (int rl = 0; rl < numLvls; rl++) { maxpkt = numPrec[t][c][rl].x * numPrec[t][c][rl].y; minlsz += MIN_AVG_PACKET_SZ * maxpkt; } } } // End loop on components } // End loop on tiles // Initialize layers n = 0; i = 0; lastbytes = 0; while (n < num_Layers - 1) { // At an optimized layer basebytes = System.Math.Floor(lyrSpec.getTargetBitrate(i) * np); if (i < lyrSpec.NOptPoints - 1) { //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'" nextbytes = (int) (lyrSpec.getTargetBitrate(i + 1) * np); // Limit target length to 'totenclength' if (nextbytes > totenclength) nextbytes = totenclength; } else { nextbytes = 1; } loopnlyrs = lyrSpec.getExtraLayers(i) + 1; ls = System.Math.Exp(System.Math.Log((double) nextbytes / basebytes) / loopnlyrs); layers[n].optimize = true; for (l = 0; l < loopnlyrs; l++) { //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'" newbytes = (int) basebytes - lastbytes - ho; if (newbytes < minlsz) { // Skip layer (too small) basebytes *= ls; num_Layers--; continue; } //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'" lastbytes = (int) basebytes - ho; layers[n].maxBytes = lastbytes; basebytes *= ls; n++; } i++; // Goto next optimization point } // Ensure minimum size of last layer (this one determines overall // bitrate) n = num_Layers - 2; //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'" nextbytes = (int) (lyrSpec.TotBitrate * np) - ho; newbytes = nextbytes - ((n >= 0)?layers[n].maxBytes:0); while (newbytes < minlsz) { if (num_Layers == 1) { if (newbytes <= 0) { throw new System.ArgumentException("Overall target bitrate too " + "low, given the current " + "bit stream header overhead"); } break; } // Delete last layer num_Layers--; n--; newbytes = nextbytes - ((n >= 0)?layers[n].maxBytes:0); } // Set last layer to the overall target bitrate n++; layers[n].maxBytes = nextbytes; layers[n].optimize = true; // Re-initialize progression order changes if needed Default values Progression[] prog1; // prog2 removed prog1 = (Progression[]) encSpec.pocs.getDefault(); int nValidProg = prog1.Length; for (int prg = 0; prg < prog1.Length; prg++) { if (prog1[prg].lye > num_Layers) { prog1[prg].lye = num_Layers; } } if (nValidProg == 0) { throw new System.ApplicationException("Unable to initialize rate allocator: No " + "default progression type has been defined."); } // Tile specific values for (int t = 0; t < numTiles; t++) { if (encSpec.pocs.isTileSpecified(t)) { prog1 = (Progression[]) encSpec.pocs.getTileDef(t); nValidProg = prog1.Length; for (int prg = 0; prg < prog1.Length; prg++) { if (prog1[prg].lye > num_Layers) { prog1[prg].lye = num_Layers; } } if (nValidProg == 0) { throw new System.ApplicationException("Unable to initialize rate allocator:" + " No default progression type has been " + "defined for tile " + t); } } } // End loop on tiles #if DO_TIMING initTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif } /// This method gets all the coded code-blocks from the EBCOT entropy coder /// for every component and every tile. Each coded code-block is stored in /// a 5D array according to the component, the resolution level, the tile, /// the subband it belongs and its position in the subband. /// ///

For each code-block, the valid slopes are computed and converted /// into the mantissa-exponent representation. /// ///

private void getAllCodeBlocks() { int numComps, numTiles; // numBytes removed int c, r, t, s, sidx, k; //int slope; SubbandAn subb; CBlkRateDistStats ccb = null; Coord ncblks = null; int last_sidx; float fslope; #if DO_TIMING long stime = 0L; #endif maxSlope = 0f; minSlope = System.Single.MaxValue; //Get the number of components and tiles numComps = src.NumComps; numTiles = src.getNumTiles(); SubbandAn root, sb; int cblkToEncode = 0; int nEncCblk = 0; ProgressWatch pw = FacilityManager.ProgressWatch; //Get all coded code-blocks Goto first tile src.setTile(0, 0); for (t = 0; t < numTiles; t++) { //loop on tiles nEncCblk = 0; cblkToEncode = 0; for (c = 0; c < numComps; c++) { root = src.getAnSubbandTree(t, c); for (r = 0; r <= root.resLvl; r++) { if (r == 0) { sb = (SubbandAn) root.getSubbandByIdx(0, 0); if (sb != null) cblkToEncode += sb.numCb.x * sb.numCb.y; } else { sb = (SubbandAn) root.getSubbandByIdx(r, 1); if (sb != null) cblkToEncode += sb.numCb.x * sb.numCb.y; sb = (SubbandAn) root.getSubbandByIdx(r, 2); if (sb != null) cblkToEncode += sb.numCb.x * sb.numCb.y; sb = (SubbandAn) root.getSubbandByIdx(r, 3); if (sb != null) cblkToEncode += sb.numCb.x * sb.numCb.y; } } } if (pw != null) { pw.initProgressWatch(0, cblkToEncode, "Encoding tile " + t + "..."); } for (c = 0; c < numComps; c++) { //loop on components //Get next coded code-block coordinates while ((ccb = src.getNextCodeBlock(c, ccb)) != null) { #if DO_TIMING stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif if (pw != null) { nEncCblk++; pw.updateProgressWatch(nEncCblk, null); } subb = ccb.sb; //Get the coded code-block resolution level index r = subb.resLvl; //Get the coded code-block subband index s = subb.sbandIdx; //Get the number of blocks in the current subband ncblks = subb.numCb; // Add code-block contribution to summary R-D table // RDSlopesRates last_sidx = - 1; for (k = ccb.nVldTrunc - 1; k >= 0; k--) { fslope = ccb.truncSlopes[k]; if (fslope > maxSlope) maxSlope = fslope; if (fslope < minSlope) minSlope = fslope; sidx = getLimitedSIndexFromSlope(fslope); for (; sidx > last_sidx; sidx--) { RDSlopesRates[sidx] += ccb.truncRates[ccb.truncIdxs[k]]; } last_sidx = getLimitedSIndexFromSlope(fslope); } //Fills code-blocks array cblks[t][c][r][s][(ccb.m * ncblks.x) + ccb.n] = ccb; ccb = null; #if DO_TIMING initTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif } } if (pw != null) { pw.terminateProgressWatch(); } //Goto next tile if (t < numTiles - 1) //not at last tile src.nextTile(); } } /// This method builds all the bit stream layers and then writes them to /// the output bit stream. Firstly it builds all the layers by computing /// the threshold according to the layer target bit-rate, and then it /// writes the layer bit streams according to the progressive type. /// /// private void buildAndWriteLayers() { int nPrec = 0; int maxBytes, actualBytes; float rdThreshold; SubbandAn sb; //float threshold; BitOutputBuffer hBuff = null; byte[] bBuff = null; int[] tileLengths; // Length of each tile int tmp; bool sopUsed; // Should SOP markers be used ? bool ephUsed; // Should EPH markers be used ? int nc = src.NumComps; int nt = src.getNumTiles(); int mrl; #if DO_TIMING long stime = 0L; stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif // Start with the maximum slope rdThreshold = maxSlope; tileLengths = new int[nt]; actualBytes = 0; // +------------------------------+ // | First we build the layers | // +------------------------------+ // Bitstream is simulated to know tile length for (int l = 0; l < num_Layers; l++) { //loop on layers maxBytes = layers[l].maxBytes; if (layers[l].optimize) { rdThreshold = optimizeBitstreamLayer(l, rdThreshold, maxBytes, actualBytes); } else { if (l <= 0 || l >= num_Layers - 1) { throw new System.ArgumentException("The first and the" + " last layer " + "thresholds" + " must be optimized"); } rdThreshold = estimateLayerThreshold(maxBytes, layers[l - 1]); } for (int t = 0; t < nt; t++) { //loop on tiles if (l == 0) { // Tile header headEnc.reset(); headEnc.encodeTilePartHeader(0, t); tileLengths[t] += headEnc.Length; } for (int c = 0; c < nc; c++) { //loop on components // set boolean sopUsed here (SOP markers) sopUsed = ((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper()); // set boolean ephUsed here (EPH markers) ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper()); // Go to LL band sb = src.getAnSubbandTree(t, c); mrl = sb.resLvl + 1; while (sb.subb_LL != null) { sb = sb.subb_LL; } for (int r = 0; r < mrl; r++) { // loop on resolution levels nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y; for (int p = 0; p < nPrec; p++) { // loop on precincts findTruncIndices(l, c, r, t, sb, rdThreshold, p); hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p); if (pktEnc.PacketWritable) { tmp = bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, true, sopUsed, ephUsed); tmp += bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, true, pktEnc.ROIinPkt, pktEnc.ROILen); actualBytes += tmp; tileLengths[t] += tmp; } } // End loop on precincts sb = sb.parentband; } // End loop on resolution levels } // End loop on components } // end loop on tiles layers[l].rdThreshold = rdThreshold; layers[l].actualBytes = actualBytes; } // end loop on layers #if DO_TIMING buildTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; #endif // +--------------------------------------------------+ // | Write tiles according to their Progression order | // +--------------------------------------------------+ // Reset the packet encoder before writing all packets pktEnc.reset(); Progression[] prog; // Progression(s) in each tile int cs, ce, rs, re, lye; int[] mrlc = new int[nc]; for (int t = 0; t < nt; t++) { //loop on tiles //int[][] lysA; // layer index start for each component and // resolution level int[][] lys = new int[nc][]; for (int c = 0; c < nc; c++) { mrlc[c] = src.getAnSubbandTree(t, c).resLvl; lys[c] = new int[mrlc[c] + 1]; } // Tile header headEnc.reset(); headEnc.encodeTilePartHeader(tileLengths[t], t); bsWriter.commitBitstreamHeader(headEnc); prog = (Progression[]) encSpec.pocs.getTileDef(t); for (int prg = 0; prg < prog.Length; prg++) { // Loop on progression lye = prog[prg].lye; cs = prog[prg].cs; ce = prog[prg].ce; rs = prog[prg].rs; re = prog[prg].re; switch (prog[prg].type) { case CSJ2K.j2k.codestream.ProgressionType.RES_LY_COMP_POS_PROG: writeResLyCompPos(t, rs, re, cs, ce, lys, lye); break; case CSJ2K.j2k.codestream.ProgressionType.LY_RES_COMP_POS_PROG: writeLyResCompPos(t, rs, re, cs, ce, lys, lye); break; case CSJ2K.j2k.codestream.ProgressionType.POS_COMP_RES_LY_PROG: writePosCompResLy(t, rs, re, cs, ce, lys, lye); break; case CSJ2K.j2k.codestream.ProgressionType.COMP_POS_RES_LY_PROG: writeCompPosResLy(t, rs, re, cs, ce, lys, lye); break; case CSJ2K.j2k.codestream.ProgressionType.RES_POS_COMP_LY_PROG: writeResPosCompLy(t, rs, re, cs, ce, lys, lye); break; default: throw new System.ApplicationException("Unsupported bit stream progression type"); } // switch on progression // Update next first layer index for (int c = cs; c < ce; c++) for (int r = rs; r < re; r++) { if (r > mrlc[c]) continue; lys[c][r] = lye; } } // End loop on progression } // End loop on tiles #if DO_TIMING writeTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; #endif } /// Write a piece of bit stream according to the /// RES_LY_COMP_POS_PROG progression mode and between given bounds /// /// /// Tile index. /// /// /// First resolution level index. /// /// /// Last resolution level index. /// /// /// First component index. /// /// /// Last component index. /// /// /// First layer index for each component and resolution. /// /// /// Index of the last layer. /// /// public virtual void writeResLyCompPos(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) { bool sopUsed; // Should SOP markers be used ? bool ephUsed; // Should EPH markers be used ? int nc = src.NumComps; int[] mrl = new int[nc]; SubbandAn sb; float threshold; BitOutputBuffer hBuff = null; byte[] bBuff = null; int nPrec = 0; // Max number of resolution levels in the tile int maxResLvl = 0; for (int c = 0; c < nc; c++) { mrl[c] = src.getAnSubbandTree(t, c).resLvl; if (mrl[c] > maxResLvl) maxResLvl = mrl[c]; } int minlys; // minimum layer start index of each component for (int r = rs; r < re; r++) { //loop on resolution levels if (r > maxResLvl) continue; minlys = 100000; for (int c = cs; c < ce; c++) { if (r < lys[c].Length && lys[c][r] < minlys) { minlys = lys[c][r]; } } for (int l = minlys; l < lye; l++) { //loop on layers for (int c = cs; c < ce; c++) { //loop on components if (r >= lys[c].Length) continue; if (l < lys[c][r]) continue; // If no more decomposition levels for this component if (r > mrl[c]) continue; nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y; for (int p = 0; p < nPrec; p++) { // loop on precincts // set boolean sopUsed here (SOP markers) sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); // set boolean ephUsed here (EPH markers) ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); sb = src.getAnSubbandTree(t, c); for (int i = mrl[c]; i > r; i--) { sb = sb.subb_LL; } threshold = layers[l].rdThreshold; findTruncIndices(l, c, r, t, sb, threshold, p); hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p); if (pktEnc.PacketWritable) { bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); } } // End loop on precincts } // End loop on components } // End loop on layers } // End loop on resolution levels } /// Write a piece of bit stream according to the /// LY_RES_COMP_POS_PROG progression mode and between given bounds /// /// /// Tile index. /// /// /// First resolution level index. /// /// /// Last resolution level index. /// /// /// First component index. /// /// /// Last component index. /// /// /// First layer index for each component and resolution. /// /// /// Index of the last layer. /// /// public virtual void writeLyResCompPos(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) { bool sopUsed; // Should SOP markers be used ? bool ephUsed; // Should EPH markers be used ? int nc = src.NumComps; int mrl; SubbandAn sb; float threshold; BitOutputBuffer hBuff = null; byte[] bBuff = null; int nPrec = 0; int minlys = 100000; // minimum layer start index of each component for (int c = cs; c < ce; c++) { for (int r = 0; r < lys.Length; r++) { if (lys[c] != null && r < lys[c].Length && lys[c][r] < minlys) { minlys = lys[c][r]; } } } for (int l = minlys; l < lye; l++) { // loop on layers for (int r = rs; r < re; r++) { // loop on resolution level for (int c = cs; c < ce; c++) { // loop on components mrl = src.getAnSubbandTree(t, c).resLvl; if (r > mrl) continue; if (r >= lys[c].Length) continue; if (l < lys[c][r]) continue; nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y; for (int p = 0; p < nPrec; p++) { // loop on precincts // set boolean sopUsed here (SOP markers) sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); // set boolean ephUsed here (EPH markers) ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); sb = src.getAnSubbandTree(t, c); for (int i = mrl; i > r; i--) { sb = sb.subb_LL; } threshold = layers[l].rdThreshold; findTruncIndices(l, c, r, t, sb, threshold, p); hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p); if (pktEnc.PacketWritable) { bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); } } // end loop on precincts } // end loop on components } // end loop on resolution levels } // end loop on layers } /// Write a piece of bit stream according to the /// COMP_POS_RES_LY_PROG progression mode and between given bounds /// /// /// Tile index. /// /// /// First resolution level index. /// /// /// Last resolution level index. /// /// /// First component index. /// /// /// Last component index. /// /// /// First layer index for each component and resolution. /// /// /// Index of the last layer. /// /// public virtual void writePosCompResLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) { bool sopUsed; // Should SOP markers be used ? bool ephUsed; // Should EPH markers be used ? int nc = src.NumComps; int mrl; SubbandAn sb; float threshold; BitOutputBuffer hBuff = null; byte[] bBuff = null; // Computes current tile offset in the reference grid Coord nTiles = src.getNumTiles(null); Coord tileI = src.getTile(null); int x0siz = src.ImgULX; int y0siz = src.ImgULY; int xsiz = x0siz + src.ImgWidth; int ysiz = y0siz + src.ImgHeight; int xt0siz = src.TilePartULX; int yt0siz = src.TilePartULY; int xtsiz = src.NomTileWidth; int ytsiz = src.NomTileHeight; int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz; int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz; int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz; int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz; // Get precinct information (number,distance between two consecutive // precincts in the reference grid) in each component and resolution // level PrecInfo prec; // temporary variable int p; // Current precinct index int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid int nPrec = 0; // Total number of found precincts int[][] nextPrec = new int[ce][]; // Next precinct index in each // component and resolution level int minlys = 100000; // minimum layer start index of each component int minx = tx1; // Horiz. offset of the second precinct in the // reference grid int miny = ty1; // Vert. offset of the second precinct in the // reference grid. int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid int maxy = ty0; // Max. vert. offset of precincts in the ref. grid for (int c = cs; c < ce; c++) { mrl = src.getAnSubbandTree(t, c).resLvl; nextPrec[c] = new int[mrl + 1]; for (int r = rs; r < re; r++) { if (r > mrl) continue; if (r < lys[c].Length && lys[c][r] < minlys) { minlys = lys[c][r]; } p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1; for (; p >= 0; p--) { prec = pktEnc.getPrecInfo(t, c, r, p); if (prec.rgulx != tx0) { if (prec.rgulx < minx) minx = prec.rgulx; if (prec.rgulx > maxx) maxx = prec.rgulx; } if (prec.rguly != ty0) { if (prec.rguly < miny) miny = prec.rguly; if (prec.rguly > maxy) maxy = prec.rguly; } if (nPrec == 0) { gcd_x = prec.rgw; gcd_y = prec.rgh; } else { gcd_x = MathUtil.gcd(gcd_x, prec.rgw); gcd_y = MathUtil.gcd(gcd_y, prec.rgh); } nPrec++; } // precincts } // resolution levels } // components if (nPrec == 0) { throw new System.ApplicationException("Image cannot have no precinct"); } int pyend = (maxy - miny) / gcd_y + 1; int pxend = (maxx - minx) / gcd_x + 1; int y = ty0; int x = tx0; for (int py = 0; py <= pyend; py++) { // Vertical precincts for (int px = 0; px <= pxend; px++) { // Horiz. precincts for (int c = cs; c < ce; c++) { // Components mrl = src.getAnSubbandTree(t, c).resLvl; for (int r = rs; r < re; r++) { // Resolution levels if (r > mrl) continue; if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y) { continue; } prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]); if ((prec.rgulx != x) || (prec.rguly != y)) { continue; } for (int l = minlys; l < lye; l++) { // Layers if (r >= lys[c].Length) continue; if (l < lys[c][r]) continue; // set boolean sopUsed here (SOP markers) sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); // set boolean ephUsed here (EPH markers) ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); sb = src.getAnSubbandTree(t, c); for (int i = mrl; i > r; i--) { sb = sb.subb_LL; } threshold = layers[l].rdThreshold; findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]); hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]); if (pktEnc.PacketWritable) { bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); } } // layers nextPrec[c][r]++; } // Resolution levels } // Components if (px != pxend) { x = minx + px * gcd_x; } else { x = tx0; } } // Horizontal precincts if (py != pyend) { y = miny + py * gcd_y; } else { y = ty0; } } // Vertical precincts // Check that all precincts have been written for (int c = cs; c < ce; c++) { mrl = src.getAnSubbandTree(t, c).resLvl; for (int r = rs; r < re; r++) { if (r > mrl) continue; if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1) { throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + "."); } } } } /// Write a piece of bit stream according to the /// COMP_POS_RES_LY_PROG progression mode and between given bounds /// /// /// Tile index. /// /// /// First resolution level index. /// /// /// Last resolution level index. /// /// /// First component index. /// /// /// Last component index. /// /// /// First layer index for each component and resolution. /// /// /// Index of the last layer. /// /// public virtual void writeCompPosResLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) { bool sopUsed; // Should SOP markers be used ? bool ephUsed; // Should EPH markers be used ? int nc = src.NumComps; int mrl; SubbandAn sb; float threshold; BitOutputBuffer hBuff = null; byte[] bBuff = null; // Computes current tile offset in the reference grid Coord nTiles = src.getNumTiles(null); Coord tileI = src.getTile(null); int x0siz = src.ImgULX; int y0siz = src.ImgULY; int xsiz = x0siz + src.ImgWidth; int ysiz = y0siz + src.ImgHeight; int xt0siz = src.TilePartULX; int yt0siz = src.TilePartULY; int xtsiz = src.NomTileWidth; int ytsiz = src.NomTileHeight; int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz; int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz; int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz; int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz; // Get precinct information (number,distance between two consecutive // precincts in the reference grid) in each component and resolution // level PrecInfo prec; // temporary variable int p; // Current precinct index int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid int nPrec = 0; // Total number of found precincts int[][] nextPrec = new int[ce][]; // Next precinct index in each // component and resolution level int minlys = 100000; // minimum layer start index of each component int minx = tx1; // Horiz. offset of the second precinct in the // reference grid int miny = ty1; // Vert. offset of the second precinct in the // reference grid. int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid int maxy = ty0; // Max. vert. offset of precincts in the ref. grid for (int c = cs; c < ce; c++) { mrl = src.getAnSubbandTree(t, c).resLvl; for (int r = rs; r < re; r++) { if (r > mrl) continue; nextPrec[c] = new int[mrl + 1]; if (r < lys[c].Length && lys[c][r] < minlys) { minlys = lys[c][r]; } p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1; for (; p >= 0; p--) { prec = pktEnc.getPrecInfo(t, c, r, p); if (prec.rgulx != tx0) { if (prec.rgulx < minx) minx = prec.rgulx; if (prec.rgulx > maxx) maxx = prec.rgulx; } if (prec.rguly != ty0) { if (prec.rguly < miny) miny = prec.rguly; if (prec.rguly > maxy) maxy = prec.rguly; } if (nPrec == 0) { gcd_x = prec.rgw; gcd_y = prec.rgh; } else { gcd_x = MathUtil.gcd(gcd_x, prec.rgw); gcd_y = MathUtil.gcd(gcd_y, prec.rgh); } nPrec++; } // precincts } // resolution levels } // components if (nPrec == 0) { throw new System.ApplicationException("Image cannot have no precinct"); } int pyend = (maxy - miny) / gcd_y + 1; int pxend = (maxx - minx) / gcd_x + 1; int y; int x; for (int c = cs; c < ce; c++) { // Loop on components y = ty0; x = tx0; mrl = src.getAnSubbandTree(t, c).resLvl; for (int py = 0; py <= pyend; py++) { // Vertical precincts for (int px = 0; px <= pxend; px++) { // Horiz. precincts for (int r = rs; r < re; r++) { // Resolution levels if (r > mrl) continue; if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y) { continue; } prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]); if ((prec.rgulx != x) || (prec.rguly != y)) { continue; } for (int l = minlys; l < lye; l++) { // Layers if (r >= lys[c].Length) continue; if (l < lys[c][r]) continue; // set boolean sopUsed here (SOP markers) sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); // set boolean ephUsed here (EPH markers) ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); sb = src.getAnSubbandTree(t, c); for (int i = mrl; i > r; i--) { sb = sb.subb_LL; } threshold = layers[l].rdThreshold; findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]); hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]); if (pktEnc.PacketWritable) { bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); } } // Layers nextPrec[c][r]++; } // Resolution levels if (px != pxend) { x = minx + px * gcd_x; } else { x = tx0; } } // Horizontal precincts if (py != pyend) { y = miny + py * gcd_y; } else { y = ty0; } } // Vertical precincts } // components // Check that all precincts have been written for (int c = cs; c < ce; c++) { mrl = src.getAnSubbandTree(t, c).resLvl; for (int r = rs; r < re; r++) { if (r > mrl) continue; if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1) { throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + "."); } } } } /// Write a piece of bit stream according to the /// RES_POS_COMP_LY_PROG progression mode and between given bounds /// /// /// Tile index. /// /// /// First resolution level index. /// /// /// Last resolution level index. /// /// /// First component index. /// /// /// Last component index. /// /// /// First layer index for each component and resolution. /// /// /// Last layer index. /// /// public virtual void writeResPosCompLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) { bool sopUsed; // Should SOP markers be used ? bool ephUsed; // Should EPH markers be used ? int nc = src.NumComps; int mrl; SubbandAn sb; float threshold; BitOutputBuffer hBuff = null; byte[] bBuff = null; // Computes current tile offset in the reference grid Coord nTiles = src.getNumTiles(null); Coord tileI = src.getTile(null); int x0siz = src.ImgULX; int y0siz = src.ImgULY; int xsiz = x0siz + src.ImgWidth; int ysiz = y0siz + src.ImgHeight; int xt0siz = src.TilePartULX; int yt0siz = src.TilePartULY; int xtsiz = src.NomTileWidth; int ytsiz = src.NomTileHeight; int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz; int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz; int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz; int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz; // Get precinct information (number,distance between two consecutive // precincts in the reference grid) in each component and resolution // level PrecInfo prec; // temporary variable int p; // Current precinct index int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid int nPrec = 0; // Total number of found precincts int[][] nextPrec = new int[ce][]; // Next precinct index in each // component and resolution level int minlys = 100000; // minimum layer start index of each component int minx = tx1; // Horiz. offset of the second precinct in the // reference grid int miny = ty1; // Vert. offset of the second precinct in the // reference grid. int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid int maxy = ty0; // Max. vert. offset of precincts in the ref. grid for (int c = cs; c < ce; c++) { mrl = src.getAnSubbandTree(t, c).resLvl; nextPrec[c] = new int[mrl + 1]; for (int r = rs; r < re; r++) { if (r > mrl) continue; if (r < lys[c].Length && lys[c][r] < minlys) { minlys = lys[c][r]; } p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1; for (; p >= 0; p--) { prec = pktEnc.getPrecInfo(t, c, r, p); if (prec.rgulx != tx0) { if (prec.rgulx < minx) minx = prec.rgulx; if (prec.rgulx > maxx) maxx = prec.rgulx; } if (prec.rguly != ty0) { if (prec.rguly < miny) miny = prec.rguly; if (prec.rguly > maxy) maxy = prec.rguly; } if (nPrec == 0) { gcd_x = prec.rgw; gcd_y = prec.rgh; } else { gcd_x = MathUtil.gcd(gcd_x, prec.rgw); gcd_y = MathUtil.gcd(gcd_y, prec.rgh); } nPrec++; } // precincts } // resolution levels } // components if (nPrec == 0) { throw new System.ApplicationException("Image cannot have no precinct"); } int pyend = (maxy - miny) / gcd_y + 1; int pxend = (maxx - minx) / gcd_x + 1; int x, y; for (int r = rs; r < re; r++) { // Resolution levels y = ty0; x = tx0; for (int py = 0; py <= pyend; py++) { // Vertical precincts for (int px = 0; px <= pxend; px++) { // Horiz. precincts for (int c = cs; c < ce; c++) { // Components mrl = src.getAnSubbandTree(t, c).resLvl; if (r > mrl) continue; if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y) { continue; } prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]); if ((prec.rgulx != x) || (prec.rguly != y)) { continue; } for (int l = minlys; l < lye; l++) { if (r >= lys[c].Length) continue; if (l < lys[c][r]) continue; // set boolean sopUsed here (SOP markers) sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); // set boolean ephUsed here (EPH markers) ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); sb = src.getAnSubbandTree(t, c); for (int i = mrl; i > r; i--) { sb = sb.subb_LL; } threshold = layers[l].rdThreshold; findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]); hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]); if (pktEnc.PacketWritable) { bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); } } // layers nextPrec[c][r]++; } // Components if (px != pxend) { x = minx + px * gcd_x; } else { x = tx0; } } // Horizontal precincts if (py != pyend) { y = miny + py * gcd_y; } else { y = ty0; } } // Vertical precincts } // Resolution levels // Check that all precincts have been written for (int c = cs; c < ce; c++) { mrl = src.getAnSubbandTree(t, c).resLvl; for (int r = rs; r < re; r++) { if (r > mrl) continue; if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1) { throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + "."); } } } } /// This function implements the rate-distortion optimization algorithm. /// It saves the state of any previously generated bit-stream layers and /// then simulate the formation of a new layer in the bit stream as often /// as necessary to find the smallest rate-distortion threshold such that /// the total number of bytes required to represent the layer does not /// exceed `maxBytes' minus `prevBytes'. It then restores the state of any /// previously generated bit-stream layers and returns the threshold. /// /// /// The index of the current layer /// /// /// The maximum admissible slope value. Normally the threshold /// slope of the previous layer. /// /// /// The maximum number of bytes that can be written. It /// includes the length of the current layer bistream length and all the /// previous layers bit streams. /// /// /// The number of bytes of all the previous layers. /// /// /// The value of the slope threshold. /// /// private float optimizeBitstreamLayer(int layerIdx, float fmaxt, int maxBytes, int prevBytes) { int nt; // The total number of tiles int nc; // The total number of components int numLvls; // The total number of resolution levels int actualBytes; // Actual number of bytes for a layer float fmint; // Minimum of the current threshold interval float ft; // Current threshold SubbandAn sb; // Current subband BitOutputBuffer hBuff; // The packet head buffer byte[] bBuff; // The packet body buffer int sidx; // The index in the summary table bool sopUsed; // Should SOP markers be used ? bool ephUsed; // Should EPH markers be used ? //int precinctIdx; // Precinct index for current packet int nPrec; // Number of precincts in the current resolution level // Save the packet encoder state pktEnc.save(); nt = src.getNumTiles(); nc = src.NumComps; hBuff = null; bBuff = null; // Estimate the minimum slope to start with from the summary // information in 'RDSlopesRates'. This is a real minimum since it // does not include the packet head overhead, which is always // non-zero. // Look for the summary entry that gives 'maxBytes' or more data for (sidx = RD_SUMMARY_SIZE - 1; sidx > 0; sidx--) { if (RDSlopesRates[sidx] >= maxBytes) { break; } } // Get the corresponding minimum slope fmint = getSlopeFromSIndex(sidx); // Ensure that it is smaller the maximum slope if (fmint >= fmaxt) { sidx--; fmint = getSlopeFromSIndex(sidx); } // If we are using the last entry of the summary, then that // corresponds to all the data, Thus, set the minimum slope to 0. if (sidx <= 0) fmint = 0; // We look for the best threshold 'ft', which is the lowest threshold // that generates no more than 'maxBytes' code bytes. // The search is done iteratively using a binary split algorithm. We // start with 'fmaxt' as the maximum possible threshold, and 'fmint' // as the minimum threshold. The threshold 'ft' is calculated as the // middle point of 'fmaxt'-'fmint' interval. The 'fmaxt' or 'fmint' // bounds are moved according to the number of bytes obtained from a // simulation, where 'ft' is used as the threshold. // We stop whenever the interval is sufficiently small, and thus // enough precision is achieved. // Initialize threshold as the middle point of the interval. ft = (fmaxt + fmint) / 2f; // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are so // close that the average is 'fmint', due to rounding. Force it to // 'fmaxt' instead, since 'fmint' is normally an exclusive lower // bound. if (ft <= fmint) ft = fmaxt; do { // Get the number of bytes used by this layer, if 'ft' is the // threshold, by simulation. actualBytes = prevBytes; src.setTile(0, 0); for (int t = 0; t < nt; t++) { for (int c = 0; c < nc; c++) { // set boolean sopUsed here (SOP markers) sopUsed = ((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper()); // set boolean ephUsed here (EPH markers) ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper()); // Get LL subband sb = (SubbandAn) src.getAnSubbandTree(t, c); numLvls = sb.resLvl + 1; sb = (SubbandAn) sb.getSubbandByIdx(0, 0); //loop on resolution levels for (int r = 0; r < numLvls; r++) { nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y; for (int p = 0; p < nPrec; p++) { findTruncIndices(layerIdx, c, r, t, sb, ft, p); hBuff = pktEnc.encodePacket(layerIdx + 1, c, r, t, cblks[t][c][r], truncIdxs[t][layerIdx][c][r], hBuff, bBuff, p); if (pktEnc.PacketWritable) { bBuff = pktEnc.LastBodyBuf; actualBytes += bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, true, sopUsed, ephUsed); actualBytes += bsWriter.writePacketBody(bBuff, pktEnc.LastBodyLen, true, pktEnc.ROIinPkt, pktEnc.ROILen); } } // end loop on precincts sb = sb.parentband; } // End loop on resolution levels } // End loop on components } // End loop on tiles // Move the interval bounds according to simulation result if (actualBytes > maxBytes) { // 'ft' is too low and generates too many bytes, make it the // new minimum. fmint = ft; } else { // 'ft' is too high and does not generate as many bytes as we // are allowed too, make it the new maximum. fmaxt = ft; } // Update 'ft' for the new iteration as the middle point of the // new interval. ft = (fmaxt + fmint) / 2f; // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are // so close that the average is 'fmint', due to rounding. Force it // to 'fmaxt' instead, since 'fmint' is normally an exclusive // lower bound. if (ft <= fmint) ft = fmaxt; // Restore previous packet encoder state pktEnc.restore(); // We continue to iterate, until the threshold reaches the upper // limit of the interval, within a FLOAT_REL_PRECISION relative // tolerance, or a FLOAT_ABS_PRECISION absolute tolerance. This is // the sign that the interval is sufficiently small. } while (ft < fmaxt * (1f - FLOAT_REL_PRECISION) && ft < (fmaxt - FLOAT_ABS_PRECISION)); // If we have a threshold which is close to 0, set it to 0 so that // everything is taken into the layer. This is to avoid not sending // some least significant bit-planes in the lossless case. We use the // FLOAT_ABS_PRECISION value as a measure of "close" to 0. if (ft <= FLOAT_ABS_PRECISION) { ft = 0f; } else { // Otherwise make the threshold 'fmaxt', just to be sure that we // will not send more bytes than allowed. ft = fmaxt; } return ft; } /// This function attempts to estimate a rate-distortion slope threshold /// which will achieve a target number of code bytes close the /// `targetBytes' value. /// /// /// The target number of bytes for the current layer /// /// /// The previous layer information. /// /// /// The value of the slope threshold for the estimated layer /// /// private float estimateLayerThreshold(int targetBytes, EBCOTLayer lastLayer) { float log_sl1; // The log of the first slope used for interpolation float log_sl2; // The log of the second slope used for interpolation float log_len1; // The log of the first length used for interpolation float log_len2; // The log of the second length used for interpolation float log_isl; // The log of the interpolated slope float log_ilen; // Log of the interpolated length float log_ab; // Log of actual bytes in last layer int sidx; // Index into the summary R-D info array float log_off; // The log of the offset proportion int tlen; // The corrected target layer length float lthresh; // The threshold of the last layer float eth; // The estimated threshold // In order to estimate the threshold we base ourselves in the summary // R-D info in RDSlopesRates. In order to use it we must compensate // for the overhead of the packet heads. The proportion of overhead is // estimated using the last layer simulation results. // NOTE: the model used in this method is that the slope varies // linearly with the log of the rate (i.e. length). // NOTE: the model used in this method is that the distortion is // proprotional to a power of the rate. Thus, the slope is also // proportional to another power of the rate. This translates as the // log of the slope varies linearly with the log of the rate, which is // what we use. // 1) Find the offset of the length predicted from the summary R-D // information, to the actual length by using the last layer. // We ensure that the threshold we use for estimation actually // includes some data. lthresh = lastLayer.rdThreshold; if (lthresh > maxSlope) lthresh = maxSlope; // If the slope of the last layer is too small then we just include // all the rest (not possible to do better). if (lthresh < FLOAT_ABS_PRECISION) return 0f; sidx = getLimitedSIndexFromSlope(lthresh); // If the index is outside of the summary info array use the last two, // or first two, indexes, as appropriate if (sidx >= RD_SUMMARY_SIZE - 1) sidx = RD_SUMMARY_SIZE - 2; // Get the logs of the lengths and the slopes if (RDSlopesRates[sidx + 1] == 0) { // Pathological case, we can not use log of 0. Add // RDSlopesRates[sidx]+1 bytes to the rates (just a crude simple // solution to this rare case) //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'" log_len1 = (float) System.Math.Log((RDSlopesRates[sidx] << 1) + 1); //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'" log_len2 = (float) System.Math.Log(RDSlopesRates[sidx] + 1); //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'" log_ab = (float) System.Math.Log(lastLayer.actualBytes + RDSlopesRates[sidx] + 1); } else { //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'" log_len1 = (float) System.Math.Log(RDSlopesRates[sidx]); //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'" log_len2 = (float) System.Math.Log(RDSlopesRates[sidx + 1]); //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'" log_ab = (float) System.Math.Log(lastLayer.actualBytes); } //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'" log_sl1 = (float) System.Math.Log(getSlopeFromSIndex(sidx)); //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'" log_sl2 = (float) System.Math.Log(getSlopeFromSIndex(sidx + 1)); //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'" log_isl = (float) System.Math.Log(lthresh); log_ilen = log_len1 + (log_isl - log_sl1) * (log_len1 - log_len2) / (log_sl1 - log_sl2); log_off = log_ab - log_ilen; // Do not use negative offsets (i.e. offset proportion larger than 1) // since that is probably a sign that our model is off. To be // conservative use an offset of 0 (i.e. offset proportiojn 1). if (log_off < 0) log_off = 0f; // 2) Correct the target layer length by the offset. //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'" tlen = (int) (targetBytes / (float) System.Math.Exp(log_off)); // 3) Find, from the summary R-D info, the thresholds that generate // lengths just above and below our corrected target layer length. // Look for the index in the summary info array that gives the largest // length smaller than the target length for (sidx = RD_SUMMARY_SIZE - 1; sidx >= 0; sidx--) { if (RDSlopesRates[sidx] >= tlen) break; } sidx++; // Correct if out of the array if (sidx >= RD_SUMMARY_SIZE) sidx = RD_SUMMARY_SIZE - 1; if (sidx <= 0) sidx = 1; // Get the log of the lengths and the slopes that are just above and // below the target length. if (RDSlopesRates[sidx] == 0) { // Pathological case, we can not use log of 0. Add // RDSlopesRates[sidx-1]+1 bytes to the rates (just a crude simple // solution to this rare case) //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'" log_len1 = (float) System.Math.Log(RDSlopesRates[sidx - 1] + 1); //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'" log_len2 = (float) System.Math.Log((RDSlopesRates[sidx - 1] << 1) + 1); //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'" log_ilen = (float) System.Math.Log(tlen + RDSlopesRates[sidx - 1] + 1); } else { // Normal case, we can safely take the logs. //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'" log_len1 = (float) System.Math.Log(RDSlopesRates[sidx]); //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'" log_len2 = (float) System.Math.Log(RDSlopesRates[sidx - 1]); //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'" log_ilen = (float) System.Math.Log(tlen); } //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'" log_sl1 = (float) System.Math.Log(getSlopeFromSIndex(sidx)); //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'" log_sl2 = (float) System.Math.Log(getSlopeFromSIndex(sidx - 1)); // 4) Interpolate the two thresholds to find the target threshold. log_isl = log_sl1 + (log_ilen - log_len1) * (log_sl1 - log_sl2) / (log_len1 - log_len2); //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'" eth = (float) System.Math.Exp(log_isl); // Correct out of bounds results if (eth > lthresh) eth = lthresh; if (eth < FLOAT_ABS_PRECISION) eth = 0f; // Return the estimated threshold return eth; } /// This function finds the new truncation points indices for a packet. It /// does so by including the data from the code-blocks in the component, /// resolution level and tile, associated with a R-D slope which is larger /// than or equal to 'fthresh'. /// /// /// The index of the current layer /// /// /// The index of the current component /// /// /// The index of the current resolution level /// /// /// The index of the current tile /// /// /// The LL subband in the resolution level lvlIdx, which is /// parent of all the subbands in the packet. Except for resolution level 0 /// this subband is always a node. /// /// /// The value of the rate-distortion threshold /// /// private void findTruncIndices(int layerIdx, int compIdx, int lvlIdx, int tileIdx, SubbandAn subb, float fthresh, int precinctIdx) { int minsbi, maxsbi, b, n; // bIdx removed //Coord ncblks = null; SubbandAn sb; CBlkRateDistStats cur_cblk; PrecInfo prec = pktEnc.getPrecInfo(tileIdx, compIdx, lvlIdx, precinctIdx); Coord cbCoord; sb = subb; while (sb.subb_HH != null) { sb = sb.subb_HH; } minsbi = (lvlIdx == 0)?0:1; maxsbi = (lvlIdx == 0)?1:4; int yend, xend; sb = (SubbandAn) subb.getSubbandByIdx(lvlIdx, minsbi); for (int s = minsbi; s < maxsbi; s++) { //loop on subbands yend = (prec.cblk[s] != null)?prec.cblk[s].Length:0; for (int y = 0; y < yend; y++) { xend = (prec.cblk[s][y] != null)?prec.cblk[s][y].Length:0; for (int x = 0; x < xend; x++) { cbCoord = prec.cblk[s][y][x].idx; b = cbCoord.x + cbCoord.y * sb.numCb.x; //Get the current code-block cur_cblk = cblks[tileIdx][compIdx][lvlIdx][s][b]; for (n = 0; n < cur_cblk.nVldTrunc; n++) { if (cur_cblk.truncSlopes[n] < fthresh) { break; } else { continue; } } // Store the index in the code-block truncIdxs that gives // the real truncation index. truncIdxs[tileIdx][layerIdx][compIdx][lvlIdx][s][b] = n - 1; } // End loop on horizontal code-blocks } // End loop on vertical code-blocks sb = (SubbandAn) sb.nextSubband(); } // End loop on subbands } /// Returns the index of a slope for the summary table, limiting to the /// admissible values. The index is calculated as RD_SUMMARY_OFF plus the /// maximum exponent, base 2, that yields a value not larger than the slope /// itself. /// ///

If the value to return is lower than 0, 0 is returned. If it is /// larger than the maximum table index, then the maximum is returned.

/// ///
/// The slope value /// /// /// The index for the summary table of the slope. /// /// private static int getLimitedSIndexFromSlope(float slope) { int idx; //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'" idx = (int) System.Math.Floor(System.Math.Log(slope) / LOG2) + RD_SUMMARY_OFF; if (idx < 0) { return 0; } else if (idx >= RD_SUMMARY_SIZE) { return RD_SUMMARY_SIZE - 1; } else { return idx; } } /// Returns the minimum slope value associated with a summary table /// index. This minimum slope is just 2^(index-RD_SUMMARY_OFF). /// /// /// The summary index value. /// /// /// The minimum slope value associated with a summary table index. /// /// private static float getSlopeFromSIndex(int index) { //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'" return (float) System.Math.Pow(2, (index - RD_SUMMARY_OFF)); } } }