0001: /*
0002: * $RCSfile: EBCOTRateAllocator.java,v $
0003: * $Revision: 1.1 $
0004: * $Date: 2005/02/11 05:02:08 $
0005: * $State: Exp $
0006: *
0007: * Class: EBCOTRateAllocator
0008: *
0009: * Description: Generic interface for post-compression
0010: * rate allocator.
0011: *
0012: *
0013: *
0014: * COPYRIGHT:
0015: *
0016: * This software module was originally developed by Raphaël Grosbois and
0017: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
0018: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
0019: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
0020: * Centre France S.A) in the course of development of the JPEG2000
0021: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
0022: * software module is an implementation of a part of the JPEG 2000
0023: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
0024: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
0025: * Partners) agree not to assert against ISO/IEC and users of the JPEG
0026: * 2000 Standard (Users) any of their rights under the copyright, not
0027: * including other intellectual property rights, for this software module
0028: * with respect to the usage by ISO/IEC and Users of this software module
0029: * or modifications thereof for use in hardware or software products
0030: * claiming conformance to the JPEG 2000 Standard. Those intending to use
0031: * this software module in hardware or software products are advised that
0032: * their use may infringe existing patents. The original developers of
0033: * this software module, JJ2000 Partners and ISO/IEC assume no liability
0034: * for use of this software module or modifications thereof. No license
0035: * or right to this software module is granted for non JPEG 2000 Standard
0036: * conforming products. JJ2000 Partners have full right to use this
0037: * software module for his/her own purpose, assign or donate this
0038: * software module to any third party and to inhibit third parties from
0039: * using this software module for non JPEG 2000 Standard conforming
0040: * products. This copyright notice must be included in all copies or
0041: * derivative works of this software module.
0042: *
0043: * Copyright (c) 1999/2000 JJ2000 Partners.
0044: * */
0045: package jj2000.j2k.entropy.encoder;
0046:
0047: import java.awt.Point;
0048:
0049: import jj2000.j2k.codestream.writer.*;
0050: import jj2000.j2k.wavelet.analysis.*;
0051: import jj2000.j2k.entropy.encoder.*;
0052: import jj2000.j2k.codestream.*;
0053: import jj2000.j2k.entropy.*;
0054: import jj2000.j2k.image.*;
0055: import jj2000.j2k.util.*;
0056:
0057: import java.util.Vector;
0058: import java.io.*;
0059:
0060: import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
0061:
0062: /**
0063: * This implements the EBCOT post compression rate allocation algorithm. This
0064: * algorithm finds the most suitable truncation points for the set of
0065: * code-blocks, for each layer target bitrate. It works by first collecting
0066: * the rate distortion info from all code-blocks, in all tiles and all
0067: * components, and then running the rate-allocation on the whole image at
0068: * once, for each layer.
0069: *
0070: * <P>This implementation also provides some timing features. They can be
0071: * enabled by setting the 'DO_TIMING' constant of this class to true and
0072: * recompiling. The timing uses the 'System.currentTimeMillis()' Java API
0073: * call, which returns wall clock time, not the actual CPU time used. The
0074: * timing results will be printed on the message output. Since the times
0075: * reported are wall clock times and not CPU usage times they can not be added
0076: * to find the total used time (i.e. some time might be counted in several
0077: * places). When timing is disabled ('DO_TIMING' is false) there is no penalty
0078: * if the compiler performs some basic optimizations. Even if not the penalty
0079: * should be negligeable.
0080: *
0081: * @see PostCompRateAllocator
0082: *
0083: * @see CodedCBlkDataSrcEnc
0084: *
0085: * @see jj2000.j2k.codestream.writer.CodestreamWriter
0086: * */
0087: public class EBCOTRateAllocator extends PostCompRateAllocator {
0088:
0089: /** Whether to collect timing information or not: false. Used as a compile
0090: * time directive. */
0091: private final static boolean DO_TIMING = false;
0092:
0093: /** The wall time for the initialization. */
0094: private long initTime;
0095:
0096: /** The wall time for the building of layers. */
0097: private long buildTime;
0098:
0099: /** The wall time for the writing of layers. */
0100: private long writeTime;
0101:
0102: /**
0103: * 5D Array containing all the coded code-blocks:
0104: *
0105: * <ul>
0106: * <li>1st index: tile index</li>
0107: * <li>2nd index: component index</li>
0108: * <li>3rd index: resolution level index</li>
0109: * <li>4th index: subband index</li>
0110: * <li>5th index: code-block index</li>
0111: * </ul>
0112: **/
0113: private CBlkRateDistStats cblks[][][][][];
0114:
0115: /**
0116: * 6D Array containing the indices of the truncation points. It actually
0117: * contains the index of the element in CBlkRateDistStats.truncIdxs that
0118: * gives the real truncation point index.
0119: *
0120: * <ul>
0121: * <li>1st index: tile index</li>
0122: * <li>2nd index: layer index</li>
0123: * <li>3rd index: component index</li>
0124: * <li>4th index: resolution level index</li>
0125: * <li>5th index: subband index</li>
0126: * <li>6th index: code-block index</li>
0127: * </ul>
0128: **/
0129: private int truncIdxs[][][][][][];
0130:
0131: /**
0132: * Maximum number of precincts :
0133: *
0134: * <ul>
0135: * <li>1st dim: tile index.</li>
0136: * <li>2nd dim: component index.</li>
0137: * <li>3nd dim: resolution level index.</li>
0138: * </ul>
0139: */
0140: private Point numPrec[][][];
0141:
0142: /** Array containing the layers information. */
0143: private EBCOTLayer layers[];
0144:
0145: /** The log of 2, natural base */
0146: private static final double LOG2 = Math.log(2);
0147:
0148: /** The normalization offset for the R-D summary table */
0149: private static final int RD_SUMMARY_OFF = 24;
0150:
0151: /** The size of the summary table */
0152: private static final int RD_SUMMARY_SIZE = 64;
0153:
0154: /** The relative precision for float data. This is the relative tolerance
0155: * up to which the layer slope thresholds are calculated. */
0156: private static final float FLOAT_REL_PRECISION = 1e-4f;
0157:
0158: /** The precision for float data type, in an absolute sense. Two float
0159: * numbers are considered "equal" if they are within this precision. */
0160: private static final float FLOAT_ABS_PRECISION = 1e-10f;
0161:
0162: /**
0163: * Minimum average size of a packet. If layer has less bytes than the this
0164: * constant multiplied by number of packets in the layer, then the layer
0165: * is skipped.
0166: * */
0167: private static final int MIN_AVG_PACKET_SZ = 32;
0168:
0169: /**
0170: * The R-D summary information collected from the coding of all
0171: * code-blocks. For each entry it contains the accumulated length of all
0172: * truncation points that have a slope not less than
0173: * '2*(k-RD_SUMMARY_OFF)', where 'k' is the entry index.
0174: *
0175: * <P>Therefore, the length at entry 'k' is the total number of bytes of
0176: * code-block data that would be obtained if the truncation slope was
0177: * chosen as '2*(k-RD_SUMMARY_OFF)', without counting the overhead
0178: * associated with the packet heads.
0179: *
0180: * <P>This summary is used to estimate the relation of the R-D slope to
0181: * coded length, and to obtain absolute minimums on the slope given a
0182: * length.
0183: **/
0184: private int RDSlopesRates[];
0185:
0186: /** Packet encoder. */
0187: private PktEncoder pktEnc;
0188:
0189: /** The layer specifications */
0190: private LayersInfo lyrSpec;
0191:
0192: /** The maximum slope accross all code-blocks and truncation points. */
0193: private float maxSlope;
0194:
0195: /** The minimum slope accross all code-blocks and truncation points. */
0196: private float minSlope;
0197:
0198: /**
0199: * Initializes the EBCOT rate allocator of entropy coded data. The layout
0200: * of layers, and their bitrate constraints, is specified by the 'lyrs'
0201: * parameter.
0202: *
0203: * @param src The source of entropy coded data.
0204: *
0205: * @param lyrs The layers layout specification.
0206: *
0207: * @param writer The bit stream writer.
0208: *
0209: * @see ProgressionType
0210: * */
0211: public EBCOTRateAllocator(CodedCBlkDataSrcEnc src, LayersInfo lyrs,
0212: CodestreamWriter writer, J2KImageWriteParamJava wp) {
0213:
0214: super (src, lyrs.getTotNumLayers(), writer, wp);
0215:
0216: int minsbi, maxsbi;
0217: int i;
0218: SubbandAn sb, sb2;
0219: Point ncblks = null;
0220:
0221: // If we do timing create necessary structures
0222: if (DO_TIMING) {
0223: // If we are timing make sure that 'finalize' gets called.
0224: System.runFinalizersOnExit(true);
0225: // The System.runFinalizersOnExit() method is deprecated in Java
0226: // 1.2 since it can cause a deadlock in some cases. However, here
0227: // we use it only for profiling purposes and is disabled in
0228: // production code.
0229: initTime = 0L;
0230: buildTime = 0L;
0231: writeTime = 0L;
0232: }
0233:
0234: // Save the layer specs
0235: lyrSpec = lyrs;
0236:
0237: //Initialize the size of the RD slope rates array
0238: RDSlopesRates = new int[RD_SUMMARY_SIZE];
0239:
0240: //Get number of tiles, components
0241: int nt = src.getNumTiles();
0242: int nc = getNumComps();
0243:
0244: //Allocate the coded code-blocks and truncation points indexes arrays
0245: cblks = new CBlkRateDistStats[nt][nc][][][];
0246: truncIdxs = new int[nt][numLayers][nc][][][];
0247:
0248: int cblkPerSubband; // Number of code-blocks per subband
0249: int mrl; // Number of resolution levels
0250: int l; // layer index
0251: int s; //subband index
0252:
0253: // Used to compute the maximum number of precincts for each resolution
0254: // level
0255: int tx0, ty0, tx1, ty1; // Current tile position in the reference grid
0256: int tcx0, tcy0, tcx1, tcy1; // Current tile position in the domain of
0257: // the image component
0258: int trx0, try0, trx1, try1; // Current tile position in the reduced
0259: // resolution image domain
0260: int xrsiz, yrsiz; // Component sub-sampling factors
0261: Point tileI = null;
0262: Point nTiles = null;
0263: int xsiz, ysiz, x0siz, y0siz;
0264: int xt0siz, yt0siz;
0265: int xtsiz, ytsiz;
0266:
0267: int cb0x = src.getCbULX();
0268: int cb0y = src.getCbULY();
0269:
0270: src.setTile(0, 0);
0271: for (int t = 0; t < nt; t++) { // Loop on tiles
0272: nTiles = src.getNumTiles(nTiles);
0273: tileI = src.getTile(tileI);
0274: x0siz = getImgULX();
0275: y0siz = getImgULY();
0276: xsiz = x0siz + getImgWidth();
0277: ysiz = y0siz + getImgHeight();
0278: xt0siz = src.getTilePartULX();
0279: yt0siz = src.getTilePartULY();
0280: xtsiz = src.getNomTileWidth();
0281: ytsiz = src.getNomTileHeight();
0282:
0283: // Tile's coordinates on the reference grid
0284: tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
0285: ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
0286: tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
0287: * xtsiz : xsiz;
0288: ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
0289: * ytsiz : ysiz;
0290:
0291: for (int c = 0; c < nc; c++) { // loop on components
0292:
0293: //Get the number of resolution levels
0294: sb = src.getAnSubbandTree(t, c);
0295: mrl = sb.resLvl + 1;
0296:
0297: // Initialize maximum number of precincts per resolution array
0298: if (numPrec == null) {
0299: numPrec = new Point[nt][nc][];
0300: }
0301: if (numPrec[t][c] == null) {
0302: numPrec[t][c] = new Point[mrl];
0303: }
0304:
0305: // Subsampling factors
0306: xrsiz = src.getCompSubsX(c);
0307: yrsiz = src.getCompSubsY(c);
0308:
0309: // Tile's coordinates in the image component domain
0310: tcx0 = (int) Math.ceil(tx0 / (double) (xrsiz));
0311: tcy0 = (int) Math.ceil(ty0 / (double) (yrsiz));
0312: tcx1 = (int) Math.ceil(tx1 / (double) (xrsiz));
0313: tcy1 = (int) Math.ceil(ty1 / (double) (yrsiz));
0314:
0315: cblks[t][c] = new CBlkRateDistStats[mrl][][];
0316:
0317: for (l = 0; l < numLayers; l++) {
0318: truncIdxs[t][l][c] = new int[mrl][][];
0319: }
0320:
0321: for (int r = 0; r < mrl; r++) { // loop on resolution levels
0322:
0323: // Tile's coordinates in the reduced resolution image
0324: // domain
0325: trx0 = (int) Math.ceil(tcx0
0326: / (double) (1 << (mrl - 1 - r)));
0327: try0 = (int) Math.ceil(tcy0
0328: / (double) (1 << (mrl - 1 - r)));
0329: trx1 = (int) Math.ceil(tcx1
0330: / (double) (1 << (mrl - 1 - r)));
0331: try1 = (int) Math.ceil(tcy1
0332: / (double) (1 << (mrl - 1 - r)));
0333:
0334: // Calculate the maximum number of precincts for each
0335: // resolution level taking into account tile specific
0336: // options.
0337: double twoppx = (double) wp.getPrecinctPartition()
0338: .getPPX(t, c, r);
0339: double twoppy = (double) wp.getPrecinctPartition()
0340: .getPPY(t, c, r);
0341: numPrec[t][c][r] = new Point();
0342: if (trx1 > trx0) {
0343: numPrec[t][c][r].x = (int) Math
0344: .ceil((trx1 - cb0x) / twoppx)
0345: - (int) Math.floor((trx0 - cb0x)
0346: / twoppx);
0347: } else {
0348: numPrec[t][c][r].x = 0;
0349: }
0350: if (try1 > try0) {
0351: numPrec[t][c][r].y = (int) Math
0352: .ceil((try1 - cb0y) / twoppy)
0353: - (int) Math.floor((try0 - cb0y)
0354: / (double) twoppy);
0355: } else {
0356: numPrec[t][c][r].y = 0;
0357: }
0358:
0359: minsbi = (r == 0) ? 0 : 1;
0360: maxsbi = (r == 0) ? 1 : 4;
0361:
0362: cblks[t][c][r] = new CBlkRateDistStats[maxsbi][];
0363: for (l = 0; l < numLayers; l++) {
0364: truncIdxs[t][l][c][r] = new int[maxsbi][];
0365: }
0366:
0367: for (s = minsbi; s < maxsbi; s++) { // loop on subbands
0368: //Get the number of blocks in the current subband
0369: sb2 = (SubbandAn) sb.getSubbandByIdx(r, s);
0370: ncblks = sb2.numCb;
0371: cblkPerSubband = ncblks.x * ncblks.y;
0372: cblks[t][c][r][s] = new CBlkRateDistStats[cblkPerSubband];
0373:
0374: for (l = 0; l < numLayers; l++) {
0375: truncIdxs[t][l][c][r][s] = new int[cblkPerSubband];
0376: for (i = 0; i < cblkPerSubband; i++) {
0377: truncIdxs[t][l][c][r][s][i] = -1;
0378: }
0379: }
0380: } // End loop on subbands
0381: } // End lopp on resolution levels
0382: } // End loop on components
0383: if (t != nt - 1) {
0384: src.nextTile();
0385: }
0386: } // End loop on tiles
0387:
0388: //Initialize the packet encoder
0389: pktEnc = new PktEncoder(src, wp, numPrec);
0390:
0391: // The layers array has to be initialized after the constructor since
0392: // it is needed that the bit stream header has been entirely written
0393: }
0394:
0395: /**
0396: * Prints the timing information, if collected, and calls 'finalize' on
0397: * the super class.
0398: * */
0399: public void finalize() throws Throwable {
0400: if (DO_TIMING) {
0401: StringBuffer sb;
0402:
0403: sb = new StringBuffer(
0404: "EBCOTRateAllocator wall clock times:\n");
0405: sb.append(" initialization: ");
0406: sb.append(initTime);
0407: sb.append(" ms\n");
0408: sb.append(" layer building: ");
0409: sb.append(buildTime);
0410: sb.append(" ms\n");
0411: sb.append(" final writing: ");
0412: sb.append(writeTime);
0413: sb.append(" ms");
0414: FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,
0415: sb.toString());
0416: }
0417: super .finalize();
0418: }
0419:
0420: /**
0421: * Runs the rate allocation algorithm and writes the data to the bit
0422: * stream writer object provided to the constructor.
0423: * */
0424: public void runAndWrite() throws IOException {
0425: //Now, run the rate allocation
0426: buildAndWriteLayers();
0427: }
0428:
0429: /**
0430: * Initializes the layers array. This must be called after the main header
0431: * has been entirely written or simulated, so as to take its overhead into
0432: * account. This method will get all the code-blocks and then initialize
0433: * the target bitrates for each layer, according to the specifications.
0434: * */
0435: public void initialize() throws IOException {
0436: int n, i, l;
0437: int ho; // The header overhead (in bytes)
0438: float np;// The number of pixels divided by the number of bits per byte
0439: double ls; // Step for log-scale
0440: double basebytes;
0441: int lastbytes, newbytes, nextbytes;
0442: int loopnlyrs;
0443: int minlsz; // The minimum allowable number of bytes in a layer
0444: int totenclength;
0445: int maxpkt;
0446: int numTiles = src.getNumTiles();
0447: int numComps = src.getNumComps();
0448: int numLvls;
0449: int avgPktLen;
0450:
0451: long stime = 0L;
0452:
0453: // Start by getting all the code-blocks, we need this in order to have
0454: // an idea of the total encoded bitrate.
0455: getAllCodeBlocks();
0456:
0457: if (DO_TIMING)
0458: stime = System.currentTimeMillis();
0459:
0460: // Now get the total encoded length
0461: totenclength = RDSlopesRates[0]; // all the encoded data
0462: // Make a rough estimation of the packet head overhead, as 2 bytes per
0463: // packet in average (plus EPH / SOP) , and add that to the total
0464: // encoded length
0465: for (int t = 0; t < numTiles; t++) {
0466: avgPktLen = 2;
0467: // Add SOP length if set
0468: if (((String) wp.getSOP().getTileDef(t))
0469: .equalsIgnoreCase("true")) {
0470: avgPktLen += Markers.SOP_LENGTH;
0471: }
0472: // Add EPH length if set
0473: if (((String) wp.getEPH().getTileDef(t))
0474: .equalsIgnoreCase("true")) {
0475: avgPktLen += Markers.EPH_LENGTH;
0476: }
0477:
0478: for (int c = 0; c < numComps; c++) {
0479: numLvls = src.getAnSubbandTree(t, c).resLvl + 1;
0480: if (!src.precinctPartitionUsed(c, t)) {
0481: // Precinct partition is not used so there is only
0482: // one packet per resolution level/layer
0483: totenclength += numLayers * avgPktLen * numLvls;
0484: } else {
0485: // Precinct partition is used so for each
0486: // component/tile/resolution level, we get the maximum
0487: // number of packets
0488: for (int rl = 0; rl < numLvls; rl++) {
0489: maxpkt = numPrec[t][c][rl].x
0490: * numPrec[t][c][rl].y;
0491: totenclength += numLayers * avgPktLen * maxpkt;
0492: }
0493: }
0494: } // End loop on components
0495: } // End loop on tiles
0496:
0497: // If any layer specifies more than 'totenclength' as its target
0498: // length then 'totenclength' is used. This is to prevent that
0499: // estimated layers get excessively large target lengths due to an
0500: // excessively large target bitrate. At the end the last layer is set
0501: // to the target length corresponding to the overall target
0502: // bitrate. Thus, 'totenclength' can not limit the total amount of
0503: // encoded data, as intended.
0504:
0505: ho = headEnc.getLength();
0506: np = src.getImgWidth() * src.getImgHeight() / 8f;
0507:
0508: // SOT marker must be taken into account
0509: for (int t = 0; t < numTiles; t++) {
0510: headEnc.reset();
0511: headEnc.encodeTilePartHeader(0, t);
0512: ho += headEnc.getLength();
0513: }
0514:
0515: layers = new EBCOTLayer[numLayers];
0516: for (n = numLayers - 1; n >= 0; n--) {
0517: layers[n] = new EBCOTLayer();
0518: }
0519:
0520: minlsz = 0; // To keep compiler happy
0521: for (int t = 0; t < numTiles; t++) {
0522: for (int c = 0; c < numComps; c++) {
0523: numLvls = src.getAnSubbandTree(t, c).resLvl + 1;
0524:
0525: if (!src.precinctPartitionUsed(c, t)) {
0526: // Precinct partition is not used
0527: minlsz += MIN_AVG_PACKET_SZ * numLvls;
0528: } else {
0529: // Precinct partition is used
0530: for (int rl = 0; rl < numLvls; rl++) {
0531: maxpkt = numPrec[t][c][rl].x
0532: * numPrec[t][c][rl].y;
0533: minlsz += MIN_AVG_PACKET_SZ * maxpkt;
0534: }
0535: }
0536: } // End loop on components
0537: } // End loop on tiles
0538:
0539: // Initialize layers
0540: n = 0;
0541: i = 0;
0542: lastbytes = 0;
0543:
0544: while (n < numLayers - 1) {
0545: // At an optimized layer
0546: basebytes = Math.floor(lyrSpec.getTargetBitrate(i) * np);
0547: if (i < lyrSpec.getNOptPoints() - 1) {
0548: nextbytes = (int) (lyrSpec.getTargetBitrate(i + 1) * np);
0549: // Limit target length to 'totenclength'
0550: if (nextbytes > totenclength)
0551: nextbytes = totenclength;
0552: } else {
0553: nextbytes = 1;
0554: }
0555: loopnlyrs = lyrSpec.getExtraLayers(i) + 1;
0556: ls = Math.exp(Math.log((double) nextbytes / basebytes)
0557: / loopnlyrs);
0558: layers[n].optimize = true;
0559: for (l = 0; l < loopnlyrs; l++) {
0560: newbytes = (int) basebytes - lastbytes - ho;
0561: if (newbytes < minlsz) { // Skip layer (too small)
0562: basebytes *= ls;
0563: numLayers--;
0564: continue;
0565: }
0566: lastbytes = (int) basebytes - ho;
0567: layers[n].maxBytes = lastbytes;
0568: basebytes *= ls;
0569: n++;
0570: }
0571: i++; // Goto next optimization point
0572: }
0573:
0574: // Ensure minimum size of last layer (this one determines overall
0575: // bitrate)
0576: n = numLayers - 2;
0577: nextbytes = (int) (lyrSpec.getTotBitrate() * np) - ho;
0578: newbytes = nextbytes - ((n >= 0) ? layers[n].maxBytes : 0);
0579: while (newbytes < minlsz) {
0580: if (numLayers == 1) {
0581: if (newbytes <= 0) {
0582: throw new IllegalArgumentException(
0583: "Overall target bitrate too "
0584: + "low, given the current "
0585: + "bit stream header overhead");
0586: }
0587: break;
0588: }
0589: // Delete last layer
0590: numLayers--;
0591: n--;
0592: newbytes = nextbytes - ((n >= 0) ? layers[n].maxBytes : 0);
0593: }
0594: // Set last layer to the overall target bitrate
0595: n++;
0596: layers[n].maxBytes = nextbytes;
0597: layers[n].optimize = true;
0598:
0599: // Re-initialize progression order changes if needed Default values
0600: Progression[] prog1, prog2;
0601: prog1 = (Progression[]) wp.getProgressionType().getDefault();
0602: int nValidProg = prog1.length;
0603: for (int prg = 0; prg < prog1.length; prg++) {
0604: if (prog1[prg].lye > numLayers) {
0605: prog1[prg].lye = numLayers;
0606: }
0607: }
0608: if (nValidProg == 0)
0609: throw new Error("Unable to initialize rate allocator: No "
0610: + "default progression type has been defined.");
0611:
0612: // Tile specific values
0613: for (int t = 0; t < numTiles; t++) {
0614: if (wp.getProgressionType().isTileSpecified(t)) {
0615: prog1 = (Progression[]) wp.getProgressionType()
0616: .getTileDef(t);
0617: nValidProg = prog1.length;
0618: for (int prg = 0; prg < prog1.length; prg++) {
0619: if (prog1[prg].lye > numLayers) {
0620: prog1[prg].lye = numLayers;
0621: }
0622: }
0623: if (nValidProg == 0)
0624: throw new Error(
0625: "Unable to initialize rate allocator: No "
0626: + "default progression type has been defined.");
0627: }
0628: } // End loop on tiles
0629:
0630: if (DO_TIMING)
0631: initTime += System.currentTimeMillis() - stime;
0632: }
0633:
0634: /**
0635: * This method gets all the coded code-blocks from the EBCOT entropy coder
0636: * for every component and every tile. Each coded code-block is stored in
0637: * a 5D array according to the component, the resolution level, the tile,
0638: * the subband it belongs and its position in the subband.
0639: *
0640: * <P> For each code-block, the valid slopes are computed and converted
0641: * into the mantissa-exponent representation.
0642: * */
0643: private void getAllCodeBlocks() {
0644:
0645: int numComps, numTiles, numBytes;
0646: int c, r, t, s, sidx, k;
0647: int slope;
0648: SubbandAn subb;
0649: CBlkRateDistStats ccb = null;
0650: Point ncblks = null;
0651: int last_sidx;
0652: float fslope;
0653:
0654: long stime = 0L;
0655:
0656: maxSlope = 0f;
0657: minSlope = Float.MAX_VALUE;
0658:
0659: //Get the number of components and tiles
0660: numComps = src.getNumComps();
0661: numTiles = src.getNumTiles();
0662:
0663: SubbandAn root, sb;
0664: int cblkToEncode = 0;
0665: int nEncCblk = 0;
0666: ProgressWatch pw = FacilityManager.getProgressWatch();
0667:
0668: //Get all coded code-blocks Goto first tile
0669: src.setTile(0, 0);
0670: for (t = 0; t < numTiles; t++) { //loop on tiles
0671: nEncCblk = 0;
0672: cblkToEncode = 0;
0673: for (c = 0; c < numComps; c++) {
0674: root = src.getAnSubbandTree(t, c);
0675: for (r = 0; r <= root.resLvl; r++) {
0676: if (r == 0) {
0677: sb = (SubbandAn) root.getSubbandByIdx(0, 0);
0678: if (sb != null)
0679: cblkToEncode += sb.numCb.x * sb.numCb.y;
0680: } else {
0681: sb = (SubbandAn) root.getSubbandByIdx(r, 1);
0682: if (sb != null)
0683: cblkToEncode += sb.numCb.x * sb.numCb.y;
0684: sb = (SubbandAn) root.getSubbandByIdx(r, 2);
0685: if (sb != null)
0686: cblkToEncode += sb.numCb.x * sb.numCb.y;
0687: sb = (SubbandAn) root.getSubbandByIdx(r, 3);
0688: if (sb != null)
0689: cblkToEncode += sb.numCb.x * sb.numCb.y;
0690: }
0691: }
0692: }
0693: if (pw != null) {
0694: pw.initProgressWatch(0, cblkToEncode, "Encoding tile "
0695: + t + "...");
0696: }
0697:
0698: for (c = 0; c < numComps; c++) { //loop on components
0699:
0700: //Get next coded code-block coordinates
0701: while ((ccb = src.getNextCodeBlock(c, ccb)) != null) {
0702: if (DO_TIMING)
0703: stime = System.currentTimeMillis();
0704:
0705: if (pw != null) {
0706: nEncCblk++;
0707: pw.updateProgressWatch(nEncCblk, null);
0708: }
0709:
0710: subb = ccb.sb;
0711:
0712: //Get the coded code-block resolution level index
0713: r = subb.resLvl;
0714:
0715: //Get the coded code-block subband index
0716: s = subb.sbandIdx;
0717:
0718: //Get the number of blocks in the current subband
0719: ncblks = subb.numCb;
0720:
0721: // Add code-block contribution to summary R-D table
0722: // RDSlopesRates
0723: last_sidx = -1;
0724: for (k = ccb.nVldTrunc - 1; k >= 0; k--) {
0725: fslope = ccb.truncSlopes[k];
0726: if (fslope > maxSlope)
0727: maxSlope = fslope;
0728: if (fslope < minSlope)
0729: minSlope = fslope;
0730: sidx = getLimitedSIndexFromSlope(fslope);
0731: for (; sidx > last_sidx; sidx--) {
0732: RDSlopesRates[sidx] += ccb.truncRates[ccb.truncIdxs[k]];
0733: }
0734: last_sidx = getLimitedSIndexFromSlope(fslope);
0735: }
0736:
0737: //Fills code-blocks array
0738: cblks[t][c][r][s][(ccb.m * ncblks.x) + ccb.n] = ccb;
0739: ccb = null;
0740:
0741: if (DO_TIMING)
0742: initTime += System.currentTimeMillis() - stime;
0743: }
0744: }
0745:
0746: if (pw != null) {
0747: pw.terminateProgressWatch();
0748: }
0749:
0750: //Goto next tile
0751: if (t < numTiles - 1) //not at last tile
0752: src.nextTile();
0753: }
0754: }
0755:
0756: /**
0757: * This method builds all the bit stream layers and then writes them to
0758: * the output bit stream. Firstly it builds all the layers by computing
0759: * the threshold according to the layer target bit-rate, and then it
0760: * writes the layer bit streams according to the Progression type.
0761: * */
0762: private void buildAndWriteLayers() throws IOException {
0763: int nPrec = 0;
0764: int maxBytes, actualBytes;
0765: float rdThreshold;
0766: SubbandAn sb;
0767: float threshold;
0768: BitOutputBuffer hBuff = null;
0769: byte[] bBuff = null;
0770: int[] tileLengths; // Length of each tile
0771: int tmp;
0772: boolean sopUsed; // Should SOP markers be used ?
0773: boolean ephUsed; // Should EPH markers be used ?
0774: int nc = src.getNumComps();
0775: int nt = src.getNumTiles();
0776: int mrl;
0777:
0778: long stime = 0L;
0779:
0780: if (DO_TIMING)
0781: stime = System.currentTimeMillis();
0782:
0783: // Start with the maximum slope
0784: rdThreshold = maxSlope;
0785:
0786: tileLengths = new int[nt];
0787: actualBytes = 0;
0788:
0789: // +------------------------------+
0790: // | First we build the layers |
0791: // +------------------------------+
0792: // Bitstream is simulated to know tile length
0793: for (int l = 0; l < numLayers; l++) { //loop on layers
0794:
0795: maxBytes = layers[l].maxBytes;
0796: if (layers[l].optimize) {
0797: rdThreshold = optimizeBitstreamLayer(l, rdThreshold,
0798: maxBytes, actualBytes);
0799: } else {
0800: if (l <= 0 || l >= numLayers - 1) {
0801: throw new IllegalArgumentException(
0802: "The first and the" + " last layer "
0803: + "thresholds"
0804: + " must be optimized");
0805: }
0806: rdThreshold = estimateLayerThreshold(maxBytes,
0807: layers[l - 1]);
0808: }
0809:
0810: for (int t = 0; t < nt; t++) { //loop on tiles
0811: if (l == 0) {
0812: // Tile header
0813: headEnc.reset();
0814: headEnc.encodeTilePartHeader(0, t);
0815: tileLengths[t] += headEnc.getLength();
0816: }
0817:
0818: for (int c = 0; c < nc; c++) { //loop on components
0819:
0820: // set boolean sopUsed here (SOP markers)
0821: sopUsed = ((String) wp.getSOP().getTileDef(t))
0822: .equalsIgnoreCase("true");
0823: // set boolean ephUsed here (EPH markers)
0824: ephUsed = ((String) wp.getEPH().getTileDef(t))
0825: .equalsIgnoreCase("true");
0826:
0827: // Go to LL band
0828: sb = src.getAnSubbandTree(t, c);
0829: mrl = sb.resLvl + 1;
0830:
0831: while (sb.subb_LL != null) {
0832: sb = sb.subb_LL;
0833: }
0834:
0835: for (int r = 0; r < mrl; r++) { // loop on resolution levels
0836:
0837: nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
0838: for (int p = 0; p < nPrec; p++) { // loop on precincts
0839:
0840: findTruncIndices(l, c, r, t, sb,
0841: rdThreshold, p);
0842:
0843: hBuff = pktEnc.encodePacket(l + 1, c, r, t,
0844: cblks[t][c][r],
0845: truncIdxs[t][l][c][r], hBuff,
0846: bBuff, p);
0847: if (pktEnc.isPacketWritable()) {
0848: tmp = bsWriter.writePacketHead(hBuff
0849: .getBuffer(),
0850: hBuff.getLength(), true,
0851: sopUsed, ephUsed);
0852: tmp += bsWriter.writePacketBody(pktEnc
0853: .getLastBodyBuf(), pktEnc
0854: .getLastBodyLen(), true, pktEnc
0855: .isROIinPkt(), pktEnc
0856: .getROILen());
0857: actualBytes += tmp;
0858: tileLengths[t] += tmp;
0859: }
0860: } // End loop on precincts
0861: sb = sb.parent;
0862: } // End loop on resolution levels
0863: } // End loop on components
0864: } // end loop on tiles
0865: layers[l].rdThreshold = rdThreshold;
0866: layers[l].actualBytes = actualBytes;
0867: } // end loop on layers
0868:
0869: if (DO_TIMING)
0870: buildTime += System.currentTimeMillis() - stime;
0871:
0872: // The bit-stream was not yet generated (only simulated).
0873:
0874: if (DO_TIMING)
0875: stime = System.currentTimeMillis();
0876:
0877: // +--------------------------------------------------+
0878: // | Write tiles according to their Progression order |
0879: // +--------------------------------------------------+
0880: // Reset the packet encoder before writing all packets
0881: pktEnc.reset();
0882: Progression[] prog; // Progression(s) in each tile
0883: int cs, ce, rs, re, lye;
0884:
0885: int[] mrlc = new int[nc];
0886: for (int t = 0; t < nt; t++) { //loop on tiles
0887: int[][] lysA; // layer index start for each component and
0888: // resolution level
0889: int[][] lys = new int[nc][];
0890: for (int c = 0; c < nc; c++) {
0891: mrlc[c] = src.getAnSubbandTree(t, c).resLvl;
0892: lys[c] = new int[mrlc[c] + 1];
0893: }
0894:
0895: // Tile header
0896: headEnc.reset();
0897: headEnc.encodeTilePartHeader(tileLengths[t], t);
0898: bsWriter.commitBitstreamHeader(headEnc);
0899: prog = (Progression[]) wp.getProgressionType()
0900: .getTileDef(t);
0901:
0902: for (int prg = 0; prg < prog.length; prg++) { // Loop on progression
0903: lye = prog[prg].lye;
0904: cs = prog[prg].cs;
0905: ce = prog[prg].ce;
0906: rs = prog[prg].rs;
0907: re = prog[prg].re;
0908:
0909: switch (prog[prg].type) {
0910: case ProgressionType.RES_LY_COMP_POS_PROG:
0911: writeResLyCompPos(t, rs, re, cs, ce, lys, lye);
0912: break;
0913: case ProgressionType.LY_RES_COMP_POS_PROG:
0914: writeLyResCompPos(t, rs, re, cs, ce, lys, lye);
0915: break;
0916: case ProgressionType.POS_COMP_RES_LY_PROG:
0917: writePosCompResLy(t, rs, re, cs, ce, lys, lye);
0918: break;
0919: case ProgressionType.COMP_POS_RES_LY_PROG:
0920: writeCompPosResLy(t, rs, re, cs, ce, lys, lye);
0921: break;
0922: case ProgressionType.RES_POS_COMP_LY_PROG:
0923: writeResPosCompLy(t, rs, re, cs, ce, lys, lye);
0924: break;
0925: default:
0926: throw new Error(
0927: "Unsupported bit stream progression type");
0928: } // switch on progression
0929:
0930: // Update next first layer index
0931: for (int c = cs; c < ce; c++)
0932: for (int r = rs; r < re; r++) {
0933: if (r > mrlc[c])
0934: continue;
0935: lys[c][r] = lye;
0936: }
0937: } // End loop on progression
0938: } // End loop on tiles
0939:
0940: if (DO_TIMING)
0941: writeTime += System.currentTimeMillis() - stime;
0942: }
0943:
0944: /**
0945: * Write a piece of bit stream according to the
0946: * RES_LY_COMP_POS_PROG progression mode and between given bounds
0947: *
0948: * @param t Tile index.
0949: *
0950: * @param rs First resolution level index.
0951: *
0952: * @param re Last resolution level index.
0953: *
0954: * @param cs First component index.
0955: *
0956: * @param ce Last component index.
0957: *
0958: * @param lys First layer index for each component and resolution.
0959: *
0960: * @param lye Index of the last layer.
0961: * */
0962: public void writeResLyCompPos(int t, int rs, int re, int cs,
0963: int ce, int lys[][], int lye) throws IOException {
0964:
0965: boolean sopUsed; // Should SOP markers be used ?
0966: boolean ephUsed; // Should EPH markers be used ?
0967: int nc = src.getNumComps();
0968: int[] mrl = new int[nc];
0969: SubbandAn sb;
0970: float threshold;
0971: BitOutputBuffer hBuff = null;
0972: byte[] bBuff = null;
0973: int nPrec = 0;
0974:
0975: // Max number of resolution levels in the tile
0976: int maxResLvl = 0;
0977: for (int c = 0; c < nc; c++) {
0978: mrl[c] = src.getAnSubbandTree(t, c).resLvl;
0979: if (mrl[c] > maxResLvl)
0980: maxResLvl = mrl[c];
0981: }
0982:
0983: int minlys; // minimum layer start index of each component
0984:
0985: for (int r = rs; r < re; r++) { //loop on resolution levels
0986: if (r > maxResLvl)
0987: continue;
0988:
0989: minlys = 100000;
0990: for (int c = cs; c < ce; c++) {
0991: if (r < lys[c].length && lys[c][r] < minlys) {
0992: minlys = lys[c][r];
0993: }
0994: }
0995:
0996: for (int l = minlys; l < lye; l++) { //loop on layers
0997: for (int c = cs; c < ce; c++) {//loop on components
0998: if (r >= lys[c].length)
0999: continue;
1000: if (l < lys[c][r])
1001: continue;
1002:
1003: // If no more decomposition levels for this component
1004: if (r > mrl[c])
1005: continue;
1006:
1007: nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
1008: for (int p = 0; p < nPrec; p++) { // loop on precincts
1009:
1010: // set boolean sopUsed here (SOP markers)
1011: sopUsed = ((String) wp.getSOP().getTileDef(t))
1012: .equals("true");
1013: // set boolean ephUsed here (EPH markers)
1014: ephUsed = ((String) wp.getEPH().getTileDef(t))
1015: .equals("true");
1016:
1017: sb = src.getAnSubbandTree(t, c);
1018: for (int i = mrl[c]; i > r; i--) {
1019: sb = sb.subb_LL;
1020: }
1021:
1022: threshold = layers[l].rdThreshold;
1023: findTruncIndices(l, c, r, t, sb, threshold, p);
1024:
1025: hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1026: cblks[t][c][r], truncIdxs[t][l][c][r],
1027: hBuff, bBuff, p);
1028:
1029: if (pktEnc.isPacketWritable()) {
1030: bsWriter.writePacketHead(hBuff.getBuffer(),
1031: hBuff.getLength(), false, sopUsed,
1032: ephUsed);
1033: bsWriter.writePacketBody(pktEnc
1034: .getLastBodyBuf(), pktEnc
1035: .getLastBodyLen(), false, pktEnc
1036: .isROIinPkt(), pktEnc.getROILen());
1037: }
1038:
1039: } // End loop on precincts
1040: } // End loop on components
1041: } // End loop on layers
1042: } // End loop on resolution levels
1043: }
1044:
1045: /**
1046: * Write a piece of bit stream according to the
1047: * LY_RES_COMP_POS_PROG progression mode and between given bounds
1048: *
1049: * @param t Tile index.
1050: *
1051: * @param rs First resolution level index.
1052: *
1053: * @param re Last resolution level index.
1054: *
1055: * @param cs First component index.
1056: *
1057: * @param ce Last component index.
1058: *
1059: * @param lys First layer index for each component and resolution.
1060: *
1061: * @param lye Index of the last layer.
1062: * */
1063: public void writeLyResCompPos(int t, int rs, int re, int cs,
1064: int ce, int[][] lys, int lye) throws IOException {
1065:
1066: boolean sopUsed; // Should SOP markers be used ?
1067: boolean ephUsed; // Should EPH markers be used ?
1068: int nc = src.getNumComps();
1069: int mrl;
1070: SubbandAn sb;
1071: float threshold;
1072: BitOutputBuffer hBuff = null;
1073: byte[] bBuff = null;
1074: int nPrec = 0;
1075:
1076: int minlys = 100000; // minimum layer start index of each component
1077: for (int c = cs; c < ce; c++) {
1078: for (int r = 0; r < lys.length; r++) {
1079: if (lys[c] != null && r < lys[c].length
1080: && lys[c][r] < minlys) {
1081: minlys = lys[c][r];
1082: }
1083: }
1084: }
1085:
1086: for (int l = minlys; l < lye; l++) { // loop on layers
1087: for (int r = rs; r < re; r++) { // loop on resolution level
1088: for (int c = cs; c < ce; c++) { // loop on components
1089: mrl = src.getAnSubbandTree(t, c).resLvl;
1090: if (r > mrl)
1091: continue;
1092: if (r >= lys[c].length)
1093: continue;
1094: if (l < lys[c][r])
1095: continue;
1096: nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
1097: for (int p = 0; p < nPrec; p++) { // loop on precincts
1098:
1099: // set boolean sopUsed here (SOP markers)
1100: sopUsed = ((String) wp.getSOP().getTileDef(t))
1101: .equals("true");
1102: // set boolean ephUsed here (EPH markers)
1103: ephUsed = ((String) wp.getEPH().getTileDef(t))
1104: .equals("true");
1105:
1106: sb = src.getAnSubbandTree(t, c);
1107: for (int i = mrl; i > r; i--) {
1108: sb = sb.subb_LL;
1109: }
1110:
1111: threshold = layers[l].rdThreshold;
1112: findTruncIndices(l, c, r, t, sb, threshold, p);
1113:
1114: hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1115: cblks[t][c][r], truncIdxs[t][l][c][r],
1116: hBuff, bBuff, p);
1117:
1118: if (pktEnc.isPacketWritable()) {
1119: bsWriter.writePacketHead(hBuff.getBuffer(),
1120: hBuff.getLength(), false, sopUsed,
1121: ephUsed);
1122: bsWriter.writePacketBody(pktEnc
1123: .getLastBodyBuf(), pktEnc
1124: .getLastBodyLen(), false, pktEnc
1125: .isROIinPkt(), pktEnc.getROILen());
1126: }
1127: } // end loop on precincts
1128: } // end loop on components
1129: } // end loop on resolution levels
1130: } // end loop on layers
1131: }
1132:
1133: /**
1134: * Write a piece of bit stream according to the
1135: * COMP_POS_RES_LY_PROG progression mode and between given bounds
1136: *
1137: * @param t Tile index.
1138: *
1139: * @param rs First resolution level index.
1140: *
1141: * @param re Last resolution level index.
1142: *
1143: * @param cs First component index.
1144: *
1145: * @param ce Last component index.
1146: *
1147: * @param lys First layer index for each component and resolution.
1148: *
1149: * @param lye Index of the last layer.
1150: * */
1151: public void writePosCompResLy(int t, int rs, int re, int cs,
1152: int ce, int[][] lys, int lye) throws IOException {
1153:
1154: boolean sopUsed; // Should SOP markers be used ?
1155: boolean ephUsed; // Should EPH markers be used ?
1156: int nc = src.getNumComps();
1157: int mrl;
1158: SubbandAn sb;
1159: float threshold;
1160: BitOutputBuffer hBuff = null;
1161: byte[] bBuff = null;
1162:
1163: // Computes current tile offset in the reference grid
1164: Point nTiles = src.getNumTiles(null);
1165: Point tileI = src.getTile(null);
1166: int x0siz = src.getImgULX();
1167: int y0siz = src.getImgULY();
1168: int xsiz = x0siz + src.getImgWidth();
1169: int ysiz = y0siz + src.getImgHeight();
1170: int xt0siz = src.getTilePartULX();
1171: int yt0siz = src.getTilePartULY();
1172: int xtsiz = src.getNomTileWidth();
1173: int ytsiz = src.getNomTileHeight();
1174: int tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
1175: int ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
1176: int tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
1177: * xtsiz : xsiz;
1178: int ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
1179: * ytsiz : ysiz;
1180:
1181: // Get precinct information (number,distance between two consecutive
1182: // precincts in the reference grid) in each component and resolution
1183: // level
1184: PrecInfo prec; // temporary variable
1185: int p; // Current precinct index
1186: int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1187: int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1188: int nPrec = 0; // Total number of found precincts
1189: int[][] nextPrec = new int[ce][]; // Next precinct index in each
1190: // component and resolution level
1191: int minlys = 100000; // minimum layer start index of each component
1192: int minx = tx1; // Horiz. offset of the second precinct in the
1193: // reference grid
1194: int miny = ty1; // Vert. offset of the second precinct in the
1195: // reference grid.
1196: int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1197: int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1198: for (int c = cs; c < ce; c++) {
1199: mrl = src.getAnSubbandTree(t, c).resLvl;
1200: nextPrec[c] = new int[mrl + 1];
1201: for (int r = rs; r < re; r++) {
1202: if (r > mrl)
1203: continue;
1204: if (r < lys[c].length && lys[c][r] < minlys) {
1205: minlys = lys[c][r];
1206: }
1207: p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
1208: for (; p >= 0; p--) {
1209: prec = pktEnc.getPrecInfo(t, c, r, p);
1210: if (prec.rgulx != tx0) {
1211: if (prec.rgulx < minx)
1212: minx = prec.rgulx;
1213: if (prec.rgulx > maxx)
1214: maxx = prec.rgulx;
1215: }
1216: if (prec.rguly != ty0) {
1217: if (prec.rguly < miny)
1218: miny = prec.rguly;
1219: if (prec.rguly > maxy)
1220: maxy = prec.rguly;
1221: }
1222:
1223: if (nPrec == 0) {
1224: gcd_x = prec.rgw;
1225: gcd_y = prec.rgh;
1226: } else {
1227: gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
1228: gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
1229: }
1230: nPrec++;
1231: } // precincts
1232: } // resolution levels
1233: } // components
1234: if (nPrec == 0) {
1235: throw new Error("Image cannot have no precinct");
1236: }
1237:
1238: int pyend = (maxy - miny) / gcd_y + 1;
1239: int pxend = (maxx - minx) / gcd_x + 1;
1240: int y = ty0;
1241: int x = tx0;
1242: for (int py = 0; py <= pyend; py++) { // Vertical precincts
1243: for (int px = 0; px <= pxend; px++) { // Horiz. precincts
1244: for (int c = cs; c < ce; c++) { // Components
1245: mrl = src.getAnSubbandTree(t, c).resLvl;
1246: for (int r = rs; r < re; r++) { // Resolution levels
1247: if (r > mrl)
1248: continue;
1249: if (nextPrec[c][r] >= numPrec[t][c][r].x
1250: * numPrec[t][c][r].y) {
1251: continue;
1252: }
1253: prec = pktEnc.getPrecInfo(t, c, r,
1254: nextPrec[c][r]);
1255: if ((prec.rgulx != x) || (prec.rguly != y)) {
1256: continue;
1257: }
1258: for (int l = minlys; l < lye; l++) { // Layers
1259: if (r >= lys[c].length)
1260: continue;
1261: if (l < lys[c][r])
1262: continue;
1263:
1264: // set boolean sopUsed here (SOP markers)
1265: sopUsed = ((String) wp.getSOP().getTileDef(
1266: t)).equals("true");
1267: // set boolean ephUsed here (EPH markers)
1268: ephUsed = ((String) wp.getEPH().getTileDef(
1269: t)).equals("true");
1270:
1271: sb = src.getAnSubbandTree(t, c);
1272: for (int i = mrl; i > r; i--) {
1273: sb = sb.subb_LL;
1274: }
1275:
1276: threshold = layers[l].rdThreshold;
1277: findTruncIndices(l, c, r, t, sb, threshold,
1278: nextPrec[c][r]);
1279:
1280: hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1281: cblks[t][c][r],
1282: truncIdxs[t][l][c][r], hBuff,
1283: bBuff, nextPrec[c][r]);
1284:
1285: if (pktEnc.isPacketWritable()) {
1286: bsWriter.writePacketHead(hBuff
1287: .getBuffer(),
1288: hBuff.getLength(), false,
1289: sopUsed, ephUsed);
1290: bsWriter.writePacketBody(pktEnc
1291: .getLastBodyBuf(), pktEnc
1292: .getLastBodyLen(), false,
1293: pktEnc.isROIinPkt(), pktEnc
1294: .getROILen());
1295: }
1296: } // layers
1297: nextPrec[c][r]++;
1298: } // Resolution levels
1299: } // Components
1300: if (px != pxend) {
1301: x = minx + px * gcd_x;
1302: } else {
1303: x = tx0;
1304: }
1305: } // Horizontal precincts
1306: if (py != pyend) {
1307: y = miny + py * gcd_y;
1308: } else {
1309: y = ty0;
1310: }
1311: } // Vertical precincts
1312:
1313: // Check that all precincts have been written
1314: for (int c = cs; c < ce; c++) {
1315: mrl = src.getAnSubbandTree(t, c).resLvl;
1316: for (int r = rs; r < re; r++) {
1317: if (r > mrl)
1318: continue;
1319: if (nextPrec[c][r] < numPrec[t][c][r].x
1320: * numPrec[t][c][r].y - 1) {
1321: throw new Error(
1322: "JJ2000 bug: One precinct at least has "
1323: + "not been written for resolution level "
1324: + r + " of component " + c
1325: + " in tile " + t + ".");
1326: }
1327: }
1328: }
1329: }
1330:
1331: /**
1332: * Write a piece of bit stream according to the
1333: * COMP_POS_RES_LY_PROG progression mode and between given bounds
1334: *
1335: * @param t Tile index.
1336: *
1337: * @param rs First resolution level index.
1338: *
1339: * @param re Last resolution level index.
1340: *
1341: * @param cs First component index.
1342: *
1343: * @param ce Last component index.
1344: *
1345: * @param lys First layer index for each component and resolution.
1346: *
1347: * @param lye Index of the last layer.
1348: * */
1349: public void writeCompPosResLy(int t, int rs, int re, int cs,
1350: int ce, int[][] lys, int lye) throws IOException {
1351:
1352: boolean sopUsed; // Should SOP markers be used ?
1353: boolean ephUsed; // Should EPH markers be used ?
1354: int nc = src.getNumComps();
1355: int mrl;
1356: SubbandAn sb;
1357: float threshold;
1358: BitOutputBuffer hBuff = null;
1359: byte[] bBuff = null;
1360:
1361: // Computes current tile offset in the reference grid
1362: Point nTiles = src.getNumTiles(null);
1363: Point tileI = src.getTile(null);
1364: int x0siz = src.getImgULX();
1365: int y0siz = src.getImgULY();
1366: int xsiz = x0siz + src.getImgWidth();
1367: int ysiz = y0siz + src.getImgHeight();
1368: int xt0siz = src.getTilePartULX();
1369: int yt0siz = src.getTilePartULY();
1370: int xtsiz = src.getNomTileWidth();
1371: int ytsiz = src.getNomTileHeight();
1372: int tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
1373: int ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
1374: int tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
1375: * xtsiz : xsiz;
1376: int ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
1377: * ytsiz : ysiz;
1378:
1379: // Get precinct information (number,distance between two consecutive
1380: // precincts in the reference grid) in each component and resolution
1381: // level
1382: PrecInfo prec; // temporary variable
1383: int p; // Current precinct index
1384: int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1385: int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1386: int nPrec = 0; // Total number of found precincts
1387: int[][] nextPrec = new int[ce][]; // Next precinct index in each
1388: // component and resolution level
1389: int minlys = 100000; // minimum layer start index of each component
1390: int minx = tx1; // Horiz. offset of the second precinct in the
1391: // reference grid
1392: int miny = ty1; // Vert. offset of the second precinct in the
1393: // reference grid.
1394: int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1395: int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1396: for (int c = cs; c < ce; c++) {
1397: mrl = src.getAnSubbandTree(t, c).resLvl;
1398: for (int r = rs; r < re; r++) {
1399: if (r > mrl)
1400: continue;
1401: nextPrec[c] = new int[mrl + 1];
1402: if (r < lys[c].length && lys[c][r] < minlys) {
1403: minlys = lys[c][r];
1404: }
1405: p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
1406: for (; p >= 0; p--) {
1407: prec = pktEnc.getPrecInfo(t, c, r, p);
1408: if (prec.rgulx != tx0) {
1409: if (prec.rgulx < minx)
1410: minx = prec.rgulx;
1411: if (prec.rgulx > maxx)
1412: maxx = prec.rgulx;
1413: }
1414: if (prec.rguly != ty0) {
1415: if (prec.rguly < miny)
1416: miny = prec.rguly;
1417: if (prec.rguly > maxy)
1418: maxy = prec.rguly;
1419: }
1420:
1421: if (nPrec == 0) {
1422: gcd_x = prec.rgw;
1423: gcd_y = prec.rgh;
1424: } else {
1425: gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
1426: gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
1427: }
1428: nPrec++;
1429: } // precincts
1430: } // resolution levels
1431: } // components
1432: if (nPrec == 0) {
1433: throw new Error("Image cannot have no precinct");
1434: }
1435:
1436: int pyend = (maxy - miny) / gcd_y + 1;
1437: int pxend = (maxx - minx) / gcd_x + 1;
1438: int y;
1439: int x;
1440: for (int c = cs; c < ce; c++) { // Loop on components
1441: y = ty0;
1442: x = tx0;
1443: mrl = src.getAnSubbandTree(t, c).resLvl;
1444: for (int py = 0; py <= pyend; py++) { // Vertical precincts
1445: for (int px = 0; px <= pxend; px++) { // Horiz. precincts
1446: for (int r = rs; r < re; r++) { // Resolution levels
1447: if (r > mrl)
1448: continue;
1449: if (nextPrec[c][r] >= numPrec[t][c][r].x
1450: * numPrec[t][c][r].y) {
1451: continue;
1452: }
1453: prec = pktEnc.getPrecInfo(t, c, r,
1454: nextPrec[c][r]);
1455: if ((prec.rgulx != x) || (prec.rguly != y)) {
1456: continue;
1457: }
1458:
1459: for (int l = minlys; l < lye; l++) { // Layers
1460: if (r >= lys[c].length)
1461: continue;
1462: if (l < lys[c][r])
1463: continue;
1464:
1465: // set boolean sopUsed here (SOP markers)
1466: sopUsed = ((String) wp.getSOP().getTileDef(
1467: t)).equals("true");
1468: // set boolean ephUsed here (EPH markers)
1469: ephUsed = ((String) wp.getEPH().getTileDef(
1470: t)).equals("true");
1471:
1472: sb = src.getAnSubbandTree(t, c);
1473: for (int i = mrl; i > r; i--) {
1474: sb = sb.subb_LL;
1475: }
1476:
1477: threshold = layers[l].rdThreshold;
1478: findTruncIndices(l, c, r, t, sb, threshold,
1479: nextPrec[c][r]);
1480:
1481: hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1482: cblks[t][c][r],
1483: truncIdxs[t][l][c][r], hBuff,
1484: bBuff, nextPrec[c][r]);
1485:
1486: if (pktEnc.isPacketWritable()) {
1487: bsWriter.writePacketHead(hBuff
1488: .getBuffer(),
1489: hBuff.getLength(), false,
1490: sopUsed, ephUsed);
1491: bsWriter.writePacketBody(pktEnc
1492: .getLastBodyBuf(), pktEnc
1493: .getLastBodyLen(), false,
1494: pktEnc.isROIinPkt(), pktEnc
1495: .getROILen());
1496: }
1497:
1498: } // Layers
1499: nextPrec[c][r]++;
1500: } // Resolution levels
1501: if (px != pxend) {
1502: x = minx + px * gcd_x;
1503: } else {
1504: x = tx0;
1505: }
1506: } // Horizontal precincts
1507: if (py != pyend) {
1508: y = miny + py * gcd_y;
1509: } else {
1510: y = ty0;
1511: }
1512: } // Vertical precincts
1513: } // components
1514:
1515: // Check that all precincts have been written
1516: for (int c = cs; c < ce; c++) {
1517: mrl = src.getAnSubbandTree(t, c).resLvl;
1518: for (int r = rs; r < re; r++) {
1519: if (r > mrl)
1520: continue;
1521: if (nextPrec[c][r] < numPrec[t][c][r].x
1522: * numPrec[t][c][r].y - 1) {
1523: throw new Error(
1524: "JJ2000 bug: One precinct at least has "
1525: + "not been written for resolution level "
1526: + r + " of component " + c
1527: + " in tile " + t + ".");
1528: }
1529: }
1530: }
1531: }
1532:
1533: /**
1534: * Write a piece of bit stream according to the
1535: * RES_POS_COMP_LY_PROG progression mode and between given bounds
1536: *
1537: * @param t Tile index.
1538: *
1539: * @param rs First resolution level index.
1540: *
1541: * @param re Last resolution level index.
1542: *
1543: * @param cs First component index.
1544: *
1545: * @param ce Last component index.
1546: *
1547: * @param lys First layer index for each component and resolution.
1548: *
1549: * @param lye Last layer index.
1550: * */
1551: public void writeResPosCompLy(int t, int rs, int re, int cs,
1552: int ce, int[][] lys, int lye) throws IOException {
1553:
1554: boolean sopUsed; // Should SOP markers be used ?
1555: boolean ephUsed; // Should EPH markers be used ?
1556: int nc = src.getNumComps();
1557: int mrl;
1558: SubbandAn sb;
1559: float threshold;
1560: BitOutputBuffer hBuff = null;
1561: byte[] bBuff = null;
1562:
1563: // Computes current tile offset in the reference grid
1564: Point nTiles = src.getNumTiles(null);
1565: Point tileI = src.getTile(null);
1566: int x0siz = src.getImgULX();
1567: int y0siz = src.getImgULY();
1568: int xsiz = x0siz + src.getImgWidth();
1569: int ysiz = y0siz + src.getImgHeight();
1570: int xt0siz = src.getTilePartULX();
1571: int yt0siz = src.getTilePartULY();
1572: int xtsiz = src.getNomTileWidth();
1573: int ytsiz = src.getNomTileHeight();
1574: int tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
1575: int ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
1576: int tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
1577: * xtsiz : xsiz;
1578: int ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
1579: * ytsiz : ysiz;
1580:
1581: // Get precinct information (number,distance between two consecutive
1582: // precincts in the reference grid) in each component and resolution
1583: // level
1584: PrecInfo prec; // temporary variable
1585: int p; // Current precinct index
1586: int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1587: int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1588: int nPrec = 0; // Total number of found precincts
1589: int[][] nextPrec = new int[ce][]; // Next precinct index in each
1590: // component and resolution level
1591: int minlys = 100000; // minimum layer start index of each component
1592: int minx = tx1; // Horiz. offset of the second precinct in the
1593: // reference grid
1594: int miny = ty1; // Vert. offset of the second precinct in the
1595: // reference grid.
1596: int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1597: int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1598: for (int c = cs; c < ce; c++) {
1599: mrl = src.getAnSubbandTree(t, c).resLvl;
1600: nextPrec[c] = new int[mrl + 1];
1601: for (int r = rs; r < re; r++) {
1602: if (r > mrl)
1603: continue;
1604: if (r < lys[c].length && lys[c][r] < minlys) {
1605: minlys = lys[c][r];
1606: }
1607: p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
1608: for (; p >= 0; p--) {
1609: prec = pktEnc.getPrecInfo(t, c, r, p);
1610: if (prec.rgulx != tx0) {
1611: if (prec.rgulx < minx)
1612: minx = prec.rgulx;
1613: if (prec.rgulx > maxx)
1614: maxx = prec.rgulx;
1615: }
1616: if (prec.rguly != ty0) {
1617: if (prec.rguly < miny)
1618: miny = prec.rguly;
1619: if (prec.rguly > maxy)
1620: maxy = prec.rguly;
1621: }
1622:
1623: if (nPrec == 0) {
1624: gcd_x = prec.rgw;
1625: gcd_y = prec.rgh;
1626: } else {
1627: gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
1628: gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
1629: }
1630: nPrec++;
1631: } // precincts
1632: } // resolution levels
1633: } // components
1634:
1635: if (nPrec == 0) {
1636: throw new Error("Image cannot have no precinct");
1637: }
1638:
1639: int pyend = (maxy - miny) / gcd_y + 1;
1640: int pxend = (maxx - minx) / gcd_x + 1;
1641: int x, y;
1642: for (int r = rs; r < re; r++) { // Resolution levels
1643: y = ty0;
1644: x = tx0;
1645: for (int py = 0; py <= pyend; py++) { // Vertical precincts
1646: for (int px = 0; px <= pxend; px++) { // Horiz. precincts
1647: for (int c = cs; c < ce; c++) { // Components
1648: mrl = src.getAnSubbandTree(t, c).resLvl;
1649: if (r > mrl)
1650: continue;
1651: if (nextPrec[c][r] >= numPrec[t][c][r].x
1652: * numPrec[t][c][r].y) {
1653: continue;
1654: }
1655: prec = pktEnc.getPrecInfo(t, c, r,
1656: nextPrec[c][r]);
1657: if ((prec.rgulx != x) || (prec.rguly != y)) {
1658: continue;
1659: }
1660: for (int l = minlys; l < lye; l++) {
1661: if (r >= lys[c].length)
1662: continue;
1663: if (l < lys[c][r])
1664: continue;
1665:
1666: // set boolean sopUsed here (SOP markers)
1667: sopUsed = ((String) wp.getSOP().getTileDef(
1668: t)).equals("true");
1669: // set boolean ephUsed here (EPH markers)
1670: ephUsed = ((String) wp.getEPH().getTileDef(
1671: t)).equals("true");
1672:
1673: sb = src.getAnSubbandTree(t, c);
1674: for (int i = mrl; i > r; i--) {
1675: sb = sb.subb_LL;
1676: }
1677:
1678: threshold = layers[l].rdThreshold;
1679: findTruncIndices(l, c, r, t, sb, threshold,
1680: nextPrec[c][r]);
1681:
1682: hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1683: cblks[t][c][r],
1684: truncIdxs[t][l][c][r], hBuff,
1685: bBuff, nextPrec[c][r]);
1686:
1687: if (pktEnc.isPacketWritable()) {
1688: bsWriter.writePacketHead(hBuff
1689: .getBuffer(),
1690: hBuff.getLength(), false,
1691: sopUsed, ephUsed);
1692: bsWriter.writePacketBody(pktEnc
1693: .getLastBodyBuf(), pktEnc
1694: .getLastBodyLen(), false,
1695: pktEnc.isROIinPkt(), pktEnc
1696: .getROILen());
1697: }
1698:
1699: } // layers
1700: nextPrec[c][r]++;
1701: } // Components
1702: if (px != pxend) {
1703: x = minx + px * gcd_x;
1704: } else {
1705: x = tx0;
1706: }
1707: } // Horizontal precincts
1708: if (py != pyend) {
1709: y = miny + py * gcd_y;
1710: } else {
1711: y = ty0;
1712: }
1713: } // Vertical precincts
1714: } // Resolution levels
1715:
1716: // Check that all precincts have been written
1717: for (int c = cs; c < ce; c++) {
1718: mrl = src.getAnSubbandTree(t, c).resLvl;
1719: for (int r = rs; r < re; r++) {
1720: if (r > mrl)
1721: continue;
1722: if (nextPrec[c][r] < numPrec[t][c][r].x
1723: * numPrec[t][c][r].y - 1) {
1724: throw new Error(
1725: "JJ2000 bug: One precinct at least has "
1726: + "not been written for resolution level "
1727: + r + " of component " + c
1728: + " in tile " + t + ".");
1729: }
1730: }
1731: }
1732: }
1733:
1734: /**
1735: * This function implements the rate-distortion optimization algorithm.
1736: * It saves the state of any previously generated bit-stream layers and
1737: * then simulate the formation of a new layer in the bit stream as often
1738: * as necessary to find the smallest rate-distortion threshold such that
1739: * the total number of bytes required to represent the layer does not
1740: * exceed `maxBytes' minus `prevBytes'. It then restores the state of any
1741: * previously generated bit-stream layers and returns the threshold.
1742: *
1743: * @param layerIdx The index of the current layer
1744: *
1745: * @param fmaxt The maximum admissible slope value. Normally the threshold
1746: * slope of the previous layer.
1747: *
1748: * @param maxBytes The maximum number of bytes that can be written. It
1749: * includes the length of the current layer bistream length and all the
1750: * previous layers bit streams.
1751: *
1752: * @param prevBytes The number of bytes of all the previous layers.
1753: *
1754: * @return The value of the slope threshold.
1755: * */
1756: private float optimizeBitstreamLayer(int layerIdx, float fmaxt,
1757: int maxBytes, int prevBytes) throws IOException {
1758:
1759: int nt; // The total number of tiles
1760: int nc; // The total number of components
1761: int numLvls; // The total number of resolution levels
1762: int actualBytes; // Actual number of bytes for a layer
1763: float fmint; // Minimum of the current threshold interval
1764: float ft; // Current threshold
1765: SubbandAn sb; // Current subband
1766: BitOutputBuffer hBuff;// The packet head buffer
1767: byte[] bBuff; // The packet body buffer
1768: int sidx; // The index in the summary table
1769: boolean sopUsed; // Should SOP markers be used ?
1770: boolean ephUsed; // Should EPH markers be used ?
1771: int precinctIdx; // Precinct index for current packet
1772: int nPrec; // Number of precincts in the current resolution level
1773:
1774: // Save the packet encoder state
1775: pktEnc.save();
1776:
1777: nt = src.getNumTiles();
1778: nc = src.getNumComps();
1779: hBuff = null;
1780: bBuff = null;
1781:
1782: // Estimate the minimum slope to start with from the summary
1783: // information in 'RDSlopesRates'. This is a real minimum since it
1784: // does not include the packet head overhead, which is always
1785: // non-zero.
1786:
1787: // Look for the summary entry that gives 'maxBytes' or more data
1788: for (sidx = RD_SUMMARY_SIZE - 1; sidx > 0; sidx--) {
1789: if (RDSlopesRates[sidx] >= maxBytes) {
1790: break;
1791: }
1792: }
1793: // Get the corresponding minimum slope
1794: fmint = getSlopeFromSIndex(sidx);
1795: // Ensure that it is smaller the maximum slope
1796: if (fmint >= fmaxt) {
1797: sidx--;
1798: fmint = getSlopeFromSIndex(sidx);
1799: }
1800: // If we are using the last entry of the summary, then that
1801: // corresponds to all the data, Thus, set the minimum slope to 0.
1802: if (sidx <= 0)
1803: fmint = 0;
1804:
1805: // We look for the best threshold 'ft', which is the lowest threshold
1806: // that generates no more than 'maxBytes' code bytes.
1807:
1808: // The search is done iteratively using a binary split algorithm. We
1809: // start with 'fmaxt' as the maximum possible threshold, and 'fmint'
1810: // as the minimum threshold. The threshold 'ft' is calculated as the
1811: // middle point of 'fmaxt'-'fmint' interval. The 'fmaxt' or 'fmint'
1812: // bounds are moved according to the number of bytes obtained from a
1813: // simulation, where 'ft' is used as the threshold.
1814:
1815: // We stop whenever the interval is sufficiently small, and thus
1816: // enough precision is achieved.
1817:
1818: // Initialize threshold as the middle point of the interval.
1819: ft = (fmaxt + fmint) / 2f;
1820: // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are so
1821: // close that the average is 'fmint', due to rounding. Force it to
1822: // 'fmaxt' instead, since 'fmint' is normally an exclusive lower
1823: // bound.
1824: if (ft <= fmint)
1825: ft = fmaxt;
1826:
1827: do {
1828: // Get the number of bytes used by this layer, if 'ft' is the
1829: // threshold, by simulation.
1830: actualBytes = prevBytes;
1831: src.setTile(0, 0);
1832:
1833: for (int t = 0; t < nt; t++) {
1834: for (int c = 0; c < nc; c++) {
1835: // set boolean sopUsed here (SOP markers)
1836: sopUsed = ((String) wp.getSOP().getTileDef(t))
1837: .equalsIgnoreCase("true");
1838: // set boolean ephUsed here (EPH markers)
1839: ephUsed = ((String) wp.getEPH().getTileDef(t))
1840: .equalsIgnoreCase("true");
1841:
1842: // Get LL subband
1843: sb = (SubbandAn) src.getAnSubbandTree(t, c);
1844: numLvls = sb.resLvl + 1;
1845: sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1846: //loop on resolution levels
1847: for (int r = 0; r < numLvls; r++) {
1848:
1849: nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
1850: for (int p = 0; p < nPrec; p++) {
1851:
1852: findTruncIndices(layerIdx, c, r, t, sb, ft,
1853: p);
1854: hBuff = pktEnc.encodePacket(layerIdx + 1,
1855: c, r, t, cblks[t][c][r],
1856: truncIdxs[t][layerIdx][c][r],
1857: hBuff, bBuff, p);
1858:
1859: if (pktEnc.isPacketWritable()) {
1860: bBuff = pktEnc.getLastBodyBuf();
1861: actualBytes += bsWriter
1862: .writePacketHead(hBuff
1863: .getBuffer(), hBuff
1864: .getLength(), true,
1865: sopUsed, ephUsed);
1866: actualBytes += bsWriter
1867: .writePacketBody(bBuff, pktEnc
1868: .getLastBodyLen(),
1869: true, pktEnc
1870: .isROIinPkt(),
1871: pktEnc.getROILen());
1872: }
1873: } // end loop on precincts
1874: sb = sb.parent;
1875: } // End loop on resolution levels
1876: } // End loop on components
1877: } // End loop on tiles
1878:
1879: // Move the interval bounds according to simulation result
1880: if (actualBytes > maxBytes) {
1881: // 'ft' is too low and generates too many bytes, make it the
1882: // new minimum.
1883: fmint = ft;
1884: } else {
1885: // 'ft' is too high and does not generate as many bytes as we
1886: // are allowed too, make it the new maximum.
1887: fmaxt = ft;
1888: }
1889:
1890: // Update 'ft' for the new iteration as the middle point of the
1891: // new interval.
1892: ft = (fmaxt + fmint) / 2f;
1893: // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are
1894: // so close that the average is 'fmint', due to rounding. Force it
1895: // to 'fmaxt' instead, since 'fmint' is normally an exclusive
1896: // lower bound.
1897: if (ft <= fmint)
1898: ft = fmaxt;
1899:
1900: // Restore previous packet encoder state
1901: pktEnc.restore();
1902:
1903: // We continue to iterate, until the threshold reaches the upper
1904: // limit of the interval, within a FLOAT_REL_PRECISION relative
1905: // tolerance, or a FLOAT_ABS_PRECISION absolute tolerance. This is
1906: // the sign that the interval is sufficiently small.
1907: } while (ft < fmaxt * (1f - FLOAT_REL_PRECISION)
1908: && ft < (fmaxt - FLOAT_ABS_PRECISION));
1909:
1910: // If we have a threshold which is close to 0, set it to 0 so that
1911: // everything is taken into the layer. This is to avoid not sending
1912: // some least significant bit-planes in the lossless case. We use the
1913: // FLOAT_ABS_PRECISION value as a measure of "close" to 0.
1914: if (ft <= FLOAT_ABS_PRECISION) {
1915: ft = 0f;
1916: } else {
1917: // Otherwise make the threshold 'fmaxt', just to be sure that we
1918: // will not send more bytes than allowed.
1919: ft = fmaxt;
1920: }
1921: return ft;
1922: }
1923:
1924: /**
1925: * This function attempts to estimate a rate-distortion slope threshold
1926: * which will achieve a target number of code bytes close the
1927: * `targetBytes' value.
1928: *
1929: * @param targetBytes The target number of bytes for the current layer
1930: *
1931: * @param lastLayer The previous layer information.
1932: *
1933: * @return The value of the slope threshold for the estimated layer
1934: * */
1935: private float estimateLayerThreshold(int targetBytes,
1936: EBCOTLayer lastLayer) {
1937: float log_sl1; // The log of the first slope used for interpolation
1938: float log_sl2; // The log of the second slope used for interpolation
1939: float log_len1; // The log of the first length used for interpolation
1940: float log_len2; // The log of the second length used for interpolation
1941: float log_isl; // The log of the interpolated slope
1942: float log_ilen; // Log of the interpolated length
1943: float log_ab; // Log of actual bytes in last layer
1944: int sidx; // Index into the summary R-D info array
1945: float log_off; // The log of the offset proportion
1946: int tlen; // The corrected target layer length
1947: float lthresh; // The threshold of the last layer
1948: float eth; // The estimated threshold
1949:
1950: // In order to estimate the threshold we base ourselves in the summary
1951: // R-D info in RDSlopesRates. In order to use it we must compensate
1952: // for the overhead of the packet heads. The proportion of overhead is
1953: // estimated using the last layer simulation results.
1954:
1955: // NOTE: the model used in this method is that the slope varies
1956: // linearly with the log of the rate (i.e. length).
1957:
1958: // NOTE: the model used in this method is that the distortion is
1959: // proprotional to a power of the rate. Thus, the slope is also
1960: // proportional to another power of the rate. This translates as the
1961: // log of the slope varies linearly with the log of the rate, which is
1962: // what we use.
1963:
1964: // 1) Find the offset of the length predicted from the summary R-D
1965: // information, to the actual length by using the last layer.
1966:
1967: // We ensure that the threshold we use for estimation actually
1968: // includes some data.
1969: lthresh = lastLayer.rdThreshold;
1970: if (lthresh > maxSlope)
1971: lthresh = maxSlope;
1972: // If the slope of the last layer is too small then we just include
1973: // all the rest (not possible to do better).
1974: if (lthresh < FLOAT_ABS_PRECISION)
1975: return 0f;
1976: sidx = getLimitedSIndexFromSlope(lthresh);
1977: // If the index is outside of the summary info array use the last two,
1978: // or first two, indexes, as appropriate
1979: if (sidx >= RD_SUMMARY_SIZE - 1)
1980: sidx = RD_SUMMARY_SIZE - 2;
1981:
1982: // Get the logs of the lengths and the slopes
1983:
1984: if (RDSlopesRates[sidx + 1] == 0) {
1985: // Pathological case, we can not use log of 0. Add
1986: // RDSlopesRates[sidx]+1 bytes to the rates (just a crude simple
1987: // solution to this rare case)
1988: log_len1 = (float) Math.log((RDSlopesRates[sidx] << 1) + 1);
1989: log_len2 = (float) Math.log(RDSlopesRates[sidx] + 1);
1990: log_ab = (float) Math.log(lastLayer.actualBytes
1991: + RDSlopesRates[sidx] + 1);
1992: } else {
1993: log_len1 = (float) Math.log(RDSlopesRates[sidx]);
1994: log_len2 = (float) Math.log(RDSlopesRates[sidx + 1]);
1995: log_ab = (float) Math.log(lastLayer.actualBytes);
1996: }
1997:
1998: log_sl1 = (float) Math.log(getSlopeFromSIndex(sidx));
1999: log_sl2 = (float) Math.log(getSlopeFromSIndex(sidx + 1));
2000:
2001: log_isl = (float) Math.log(lthresh);
2002:
2003: log_ilen = log_len1 + (log_isl - log_sl1)
2004: * (log_len1 - log_len2) / (log_sl1 - log_sl2);
2005:
2006: log_off = log_ab - log_ilen;
2007:
2008: // Do not use negative offsets (i.e. offset proportion larger than 1)
2009: // since that is probably a sign that our model is off. To be
2010: // conservative use an offset of 0 (i.e. offset proportiojn 1).
2011: if (log_off < 0)
2012: log_off = 0f;
2013:
2014: // 2) Correct the target layer length by the offset.
2015:
2016: tlen = (int) (targetBytes / (float) Math.exp(log_off));
2017:
2018: // 3) Find, from the summary R-D info, the thresholds that generate
2019: // lengths just above and below our corrected target layer length.
2020:
2021: // Look for the index in the summary info array that gives the largest
2022: // length smaller than the target length
2023: for (sidx = RD_SUMMARY_SIZE - 1; sidx >= 0; sidx--) {
2024: if (RDSlopesRates[sidx] >= tlen)
2025: break;
2026: }
2027: sidx++;
2028: // Correct if out of the array
2029: if (sidx >= RD_SUMMARY_SIZE)
2030: sidx = RD_SUMMARY_SIZE - 1;
2031: if (sidx <= 0)
2032: sidx = 1;
2033:
2034: // Get the log of the lengths and the slopes that are just above and
2035: // below the target length.
2036:
2037: if (RDSlopesRates[sidx] == 0) {
2038: // Pathological case, we can not use log of 0. Add
2039: // RDSlopesRates[sidx-1]+1 bytes to the rates (just a crude simple
2040: // solution to this rare case)
2041: log_len1 = (float) Math.log(RDSlopesRates[sidx - 1] + 1);
2042: log_len2 = (float) Math
2043: .log((RDSlopesRates[sidx - 1] << 1) + 1);
2044: log_ilen = (float) Math.log(tlen + RDSlopesRates[sidx - 1]
2045: + 1);
2046: } else {
2047: // Normal case, we can safely take the logs.
2048: log_len1 = (float) Math.log(RDSlopesRates[sidx]);
2049: log_len2 = (float) Math.log(RDSlopesRates[sidx - 1]);
2050: log_ilen = (float) Math.log(tlen);
2051: }
2052:
2053: log_sl1 = (float) Math.log(getSlopeFromSIndex(sidx));
2054: log_sl2 = (float) Math.log(getSlopeFromSIndex(sidx - 1));
2055:
2056: // 4) Interpolate the two thresholds to find the target threshold.
2057:
2058: log_isl = log_sl1 + (log_ilen - log_len1) * (log_sl1 - log_sl2)
2059: / (log_len1 - log_len2);
2060:
2061: eth = (float) Math.exp(log_isl);
2062:
2063: // Correct out of bounds results
2064: if (eth > lthresh)
2065: eth = lthresh;
2066: if (eth < FLOAT_ABS_PRECISION)
2067: eth = 0f;
2068:
2069: // Return the estimated threshold
2070: return eth;
2071: }
2072:
2073: /**
2074: * This function finds the new truncation points indices for a packet. It
2075: * does so by including the data from the code-blocks in the component,
2076: * resolution level and tile, associated with a R-D slope which is larger
2077: * than or equal to 'fthresh'.
2078: *
2079: * @param layerIdx The index of the current layer
2080: *
2081: * @param compIdx The index of the current component
2082: *
2083: * @param lvlIdx The index of the current resolution level
2084: *
2085: * @param tileIdx The index of the current tile
2086: *
2087: * @param subb The LL subband in the resolution level lvlIdx, which is
2088: * parent of all the subbands in the packet. Except for resolution level 0
2089: * this subband is always a node.
2090: *
2091: * @param fthresh The value of the rate-distortion threshold
2092: * */
2093: private void findTruncIndices(int layerIdx, int compIdx,
2094: int lvlIdx, int tileIdx, SubbandAn subb, float fthresh,
2095: int precinctIdx) {
2096: int minsbi, maxsbi, b, bIdx, n;
2097: Point ncblks = null;
2098: SubbandAn sb;
2099: CBlkRateDistStats cur_cblk;
2100: PrecInfo prec = pktEnc.getPrecInfo(tileIdx, compIdx, lvlIdx,
2101: precinctIdx);
2102: Point cbCoord;
2103:
2104: sb = subb;
2105: while (sb.subb_HH != null) {
2106: sb = sb.subb_HH;
2107: }
2108: minsbi = (lvlIdx == 0) ? 0 : 1;
2109: maxsbi = (lvlIdx == 0) ? 1 : 4;
2110:
2111: int yend, xend;
2112:
2113: sb = (SubbandAn) subb.getSubbandByIdx(lvlIdx, minsbi);
2114: for (int s = minsbi; s < maxsbi; s++) { //loop on subbands
2115: yend = (prec.cblk[s] != null) ? prec.cblk[s].length : 0;
2116: for (int y = 0; y < yend; y++) {
2117: xend = (prec.cblk[s][y] != null) ? prec.cblk[s][y].length
2118: : 0;
2119: for (int x = 0; x < xend; x++) {
2120: cbCoord = prec.cblk[s][y][x].idx;
2121: b = cbCoord.x + cbCoord.y * sb.numCb.x;
2122: //Get the current code-block
2123: cur_cblk = cblks[tileIdx][compIdx][lvlIdx][s][b];
2124: for (n = 0; n < cur_cblk.nVldTrunc; n++) {
2125: if (cur_cblk.truncSlopes[n] < fthresh) {
2126: break;
2127: } else {
2128: continue;
2129: }
2130: }
2131: // Store the index in the code-block truncIdxs that gives
2132: // the real truncation index.
2133: truncIdxs[tileIdx][layerIdx][compIdx][lvlIdx][s][b] = n - 1;
2134:
2135: } // End loop on horizontal code-blocks
2136: } // End loop on vertical code-blocks
2137: sb = (SubbandAn) sb.nextSubband();
2138: } // End loop on subbands
2139: }
2140:
2141: /**
2142: * Returns the index of a slope for the summary table, limiting to the
2143: * admissible values. The index is calculated as RD_SUMMARY_OFF plus the
2144: * maximum exponent, base 2, that yields a value not larger than the slope
2145: * itself.
2146: *
2147: * <P>If the value to return is lower than 0, 0 is returned. If it is
2148: * larger than the maximum table index, then the maximum is returned.
2149: *
2150: * @param slope The slope value
2151: *
2152: * @return The index for the summary table of the slope.
2153: * */
2154: private static int getLimitedSIndexFromSlope(float slope) {
2155: int idx;
2156:
2157: idx = (int) Math.floor(Math.log(slope) / LOG2) + RD_SUMMARY_OFF;
2158:
2159: if (idx < 0) {
2160: return 0;
2161: } else if (idx >= RD_SUMMARY_SIZE) {
2162: return RD_SUMMARY_SIZE - 1;
2163: } else {
2164: return idx;
2165: }
2166: }
2167:
2168: /**
2169: * Returns the minimum slope value associated with a summary table
2170: * index. This minimum slope is just 2^(index-RD_SUMMARY_OFF).
2171: *
2172: * @param index The summary index value.
2173: *
2174: * @return The minimum slope value associated with a summary table index.
2175: * */
2176: private static float getSlopeFromSIndex(int index) {
2177: return (float) Math.pow(2, (index - RD_SUMMARY_OFF));
2178: }
2179: }
|