0001: /*
0002: * $RCSfile: PktEncoder.java,v $
0003: * $Revision: 1.1 $
0004: * $Date: 2005/02/11 05:02:03 $
0005: * $State: Exp $
0006: *
0007: * Class: PktEncoder
0008: *
0009: * Description: Builds bit stream packets and keeps
0010: * interpacket dependencies.
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:
0046: package jj2000.j2k.codestream.writer;
0047:
0048: import java.awt.Point;
0049:
0050: import jj2000.j2k.wavelet.analysis.*;
0051: import jj2000.j2k.entropy.encoder.*;
0052: import jj2000.j2k.codestream.*;
0053: import jj2000.j2k.wavelet.*;
0054: import jj2000.j2k.image.*;
0055: import jj2000.j2k.util.*;
0056: import jj2000.j2k.*;
0057:
0058: import java.util.Vector;
0059: import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
0060:
0061: /**
0062: * This class builds packets and keeps the state information of packet
0063: * interdependencies. It also supports saving the state and reverting
0064: * (restoring) to the last saved state, with the save() and restore() methods.
0065: *
0066: * <P>Each time the encodePacket() method is called a new packet is encoded,
0067: * the packet header is returned by the method, and the packet body can be
0068: * obtained with the getLastBodyBuf() and getLastBodyLen() methods.
0069: * */
0070: public class PktEncoder {
0071:
0072: /** The prefix for packet encoding options: 'P' */
0073: public final static char OPT_PREFIX = 'P';
0074:
0075: /** The list of parameters that is accepted for packet encoding.*/
0076: private final static String[][] pinfo = {
0077: {
0078: "Psop",
0079: "[<tile idx>] true|false"
0080: + "[ [<tile idx>] true|false ...]",
0081: "Specifies whether start of packet (SOP) markers should be used. "
0082: + "'true' enables, 'false' disables it.",
0083: "false" },
0084: {
0085: "Peph",
0086: "[<tile idx>] true|false"
0087: + "[ [<tile idx>] true|false ...]",
0088: "Specifies whether end of packet header (EPH) markers should be "
0089: + " used. 'true' enables, 'false' disables it.",
0090: "false" } };
0091:
0092: /** The initial value for the lblock */
0093: private final static int INIT_LBLOCK = 3;
0094:
0095: /** The source object */
0096: private CodedCBlkDataSrcEnc infoSrc;
0097:
0098: /** The encoder specs */
0099: J2KImageWriteParamJava wp;
0100:
0101: /**
0102: * The tag tree for inclusion information. The indexes are outlined
0103: * below. Note that the layer indexes start at 1, therefore, the layer
0104: * index minus 1 is used. The subband indices are used as they are defined
0105: * in the Subband class. The tile indices start at 0 and follow a
0106: * lexicographical order.
0107: *
0108: * <ul>
0109: * <li>1st index: tile index, in lexicographical order</li>
0110: * <li>2nd index: component index </li>
0111: * <li>3rd index: resolution level </li>
0112: * <li>4th index: subband index </li>
0113: * <li>5th index: precinct index </li>
0114: * </ul>
0115: **/
0116: private TagTreeEncoder ttIncl[][][][][];
0117:
0118: /**
0119: * The tag tree for the maximum significant bit-plane. The indexes are
0120: * outlined below. Note that the layer indexes start at 1, therefore, the
0121: * layer index minus 1 is used. The subband indices are used as they are
0122: * defined in the Subband class. The tile indices start at 0 and follow a
0123: * lexicographical order.
0124: *
0125: * <ul>
0126: * <li>1st index: tile index, in lexicographical order</li>
0127: * <li>2nd index: component index </li>
0128: * <li>3rd index: resolution level </li>
0129: * <li>4th index: subband index - subband index offset </li>
0130: * <li>5th index: precinct index </li>
0131: * </ul>
0132: * */
0133: private TagTreeEncoder ttMaxBP[][][][][];
0134:
0135: /**
0136: * The base number of bits for sending code-block length information
0137: * (referred as Lblock in the JPEG 2000 standard). The indexes are
0138: * outlined below. Note that the layer indexes start at 1, therefore, the
0139: * layer index minus 1 is used. The subband indices are used as they are
0140: * defined in the Subband class. The tile indices start at 0 and follow a
0141: * lexicographical order.
0142: *
0143: * <ul>
0144: * <li>1st index: tile index, in lexicographical order </li>
0145: * <li>2nd index: component index </li>
0146: * <li>3rd index: resolution level </li>
0147: * <li>4th index: subband index - subband index offset </li>
0148: * <li>5th index: code-block index, in lexicographical order</li>
0149: * </ul>
0150: * */
0151: private int lblock[][][][][];
0152:
0153: /**
0154: * The last encoded truncation point for each code-block. A negative value
0155: * means that no information has been included for the block, yet. The
0156: * indexes are outlined below. The subband indices are used as they are
0157: * defined in the Subband class. The tile indices start at 0 and follow a
0158: * lexicographical order. The code-block indices follow a lexicographical
0159: * order within the subband tile.
0160: *
0161: * <P>What is actually stored is the index of the element in
0162: * CBlkRateDistStats.truncIdxs that gives the real truncation point.
0163: *
0164: * <ul>
0165: * <li>1st index: tile index, in lexicographical order </li>
0166: * <li>2nd index: component index </li>
0167: * <li>3rd index: resolution level </li>
0168: * <li>4th index: subband index - subband index offset </li>
0169: * <li>5th index: code-block index, in lexicographical order </li>
0170: * </ul>
0171: * */
0172: private int prevtIdxs[][][][][];
0173:
0174: /**
0175: * The saved base number of bits for sending code-block length
0176: * information. It is used for restoring previous saved state by
0177: * restore(). The indexes are outlined below. Note that the layer indexes
0178: * start at 1, therefore, the layer index minus 1 is used. The subband
0179: * indices are used as they are defined in the Subband class. The tile
0180: * indices start at 0 and follow a lexicographical order.
0181: *
0182: * <ul>
0183: * <li>1st index: tile index, in lexicographical order </li>
0184: * <li>2nd index: component index </li>
0185: * <li>3rd index: resolution level </li>
0186: * <li>4th index: subband index - subband index offset </li>
0187: * <li>5th index: code-block index, in lexicographical order</li>
0188: * </ul>
0189: * */
0190: private int bak_lblock[][][][][];
0191:
0192: /**
0193: * The saved last encoded truncation point for each code-block. It is used
0194: * for restoring previous saved state by restore(). A negative value means
0195: * that no information has been included for the block, yet. The indexes
0196: * are outlined below. The subband indices are used as they are defined in
0197: * the Subband class. The tile indices start at 0 and follow a
0198: * lexicographical order. The code-block indices follow a lexicographical
0199: * order within the subband tile.
0200: *
0201: * <ul>
0202: * <li>1st index: tile index, in lexicographical order </li>
0203: * <li>2nd index: component index </li>
0204: * <li>3rd index: resolution level </li>
0205: * <li>4th index: subband index - subband index offset </li>
0206: * <li>5th index: code-block index, in lexicographical order </li>
0207: * </ul>
0208: * */
0209: private int bak_prevtIdxs[][][][][];
0210:
0211: /** The body buffer of the last encoded packet */
0212: private byte[] lbbuf;
0213:
0214: /** The body length of the last encoded packet */
0215: private int lblen;
0216:
0217: /** The saved state */
0218: private boolean saved;
0219:
0220: /** Whether or not there is ROI information in the last encoded Packet */
0221: private boolean roiInPkt = false;
0222:
0223: /** Length to read in current packet body to get all the ROI information */
0224: private int roiLen = 0;
0225:
0226: /**
0227: * Array containing the coordinates, width, height, indexes, ... of the
0228: * precincts.
0229: *
0230: * <ul>
0231: * <li> 1st dim: tile index.</li>
0232: * <li> 2nd dim: component index.</li>
0233: * <li> 3rd dim: resolution level index.</li>
0234: * <li> 4th dim: precinct index.</li>
0235: * </ul>
0236: * */
0237: private PrecInfo ppinfo[][][][];
0238:
0239: /** Whether or not the current packet is writable */
0240: private boolean packetWritable;
0241:
0242: /**
0243: * Creates a new packet header encoder, using the information from the
0244: * 'infoSrc' object. The information used is the number of components,
0245: * number of tiles, subband decomposition, etc.
0246: *
0247: * <P>Note that this constructor visits all the tiles in the 'infoSrc'
0248: * object. The 'infoSrc' object is left at the original tile (i.e. the
0249: * current tile before calling this constructor), but any side effects of
0250: * visiting the tiles is not reverted.
0251: *
0252: * @param infoSrc The source of information to construct the
0253: * object.
0254: *
0255: * @param encSpec The parameters for the encoding
0256: *
0257: * @param maxNumPrec Maximum number of precinct in each tile, component
0258: * and resolution level.
0259: *
0260: * @param pl ParameterList instance that holds command line options
0261: * */
0262: public PktEncoder(CodedCBlkDataSrcEnc infoSrc,
0263: J2KImageWriteParamJava wp, Point[][][] numPrec) {
0264: this .infoSrc = infoSrc;
0265: this .wp = wp;
0266: // this.numPrec = numPrec;
0267:
0268: // Get number of components and tiles
0269: int nc = infoSrc.getNumComps();
0270: int nt = infoSrc.getNumTiles();
0271:
0272: // Do initial allocation
0273: ttIncl = new TagTreeEncoder[nt][nc][][][];
0274: ttMaxBP = new TagTreeEncoder[nt][nc][][][];
0275: lblock = new int[nt][nc][][][];
0276: prevtIdxs = new int[nt][nc][][][];
0277: ppinfo = new PrecInfo[nt][nc][][];
0278:
0279: // Finish allocation
0280: SubbandAn root, sb;
0281: int maxs, mins;
0282: int mrl;
0283: Point tmpCoord = null;
0284: int numcb; // Number of code-blocks
0285: Vector cblks = null;
0286: infoSrc.setTile(0, 0);
0287: for (int t = 0; t < nt; t++) { // Loop on tiles
0288: for (int c = 0; c < nc; c++) { // Loop on components
0289: // Get number of resolution levels
0290: root = infoSrc.getAnSubbandTree(t, c);
0291: mrl = root.resLvl;
0292:
0293: lblock[t][c] = new int[mrl + 1][][];
0294: ttIncl[t][c] = new TagTreeEncoder[mrl + 1][][];
0295: ttMaxBP[t][c] = new TagTreeEncoder[mrl + 1][][];
0296: prevtIdxs[t][c] = new int[mrl + 1][][];
0297: ppinfo[t][c] = new PrecInfo[mrl + 1][];
0298:
0299: for (int r = 0; r <= mrl; r++) { // Loop on resolution levels
0300: mins = (r == 0) ? 0 : 1;
0301: maxs = (r == 0) ? 1 : 4;
0302:
0303: int maxPrec = numPrec[t][c][r].x
0304: * numPrec[t][c][r].y;
0305:
0306: ttIncl[t][c][r] = new TagTreeEncoder[maxPrec][maxs];
0307: ttMaxBP[t][c][r] = new TagTreeEncoder[maxPrec][maxs];
0308: prevtIdxs[t][c][r] = new int[maxs][];
0309: lblock[t][c][r] = new int[maxs][];
0310:
0311: // Precincts and code-blocks
0312: ppinfo[t][c][r] = new PrecInfo[maxPrec];
0313: fillPrecInfo(t, c, r);
0314:
0315: for (int s = mins; s < maxs; s++) {
0316: // Loop on subbands
0317: sb = (SubbandAn) root.getSubbandByIdx(r, s);
0318: numcb = sb.numCb.x * sb.numCb.y;
0319:
0320: lblock[t][c][r][s] = new int[numcb];
0321: ArrayUtil.intArraySet(lblock[t][c][r][s],
0322: INIT_LBLOCK);
0323:
0324: prevtIdxs[t][c][r][s] = new int[numcb];
0325: ArrayUtil
0326: .intArraySet(prevtIdxs[t][c][r][s], -1);
0327: }
0328: }
0329: }
0330: if (t != nt - 1)
0331: infoSrc.nextTile();
0332: }
0333: }
0334:
0335: /**
0336: * Retrives precincts and code-blocks coordinates in the given resolution,
0337: * component and tile. It terminates TagTreeEncoder initialization as
0338: * well.
0339: *
0340: * @param t Tile index.
0341: *
0342: * @param c Component index.
0343: *
0344: * @param r Resolution level index.
0345: * */
0346: private void fillPrecInfo(int t, int c, int r) {
0347: if (ppinfo[t][c][r].length == 0)
0348: return; // No precinct in this
0349: // resolution level
0350:
0351: Point tileI = infoSrc.getTile(null);
0352: Point nTiles = infoSrc.getNumTiles(null);
0353:
0354: int x0siz = infoSrc.getImgULX();
0355: int y0siz = infoSrc.getImgULY();
0356: int xsiz = x0siz + infoSrc.getImgWidth();
0357: int ysiz = y0siz + infoSrc.getImgHeight();
0358: int xt0siz = infoSrc.getTilePartULX();
0359: int yt0siz = infoSrc.getTilePartULY();
0360: int xtsiz = infoSrc.getNomTileWidth();
0361: int ytsiz = infoSrc.getNomTileHeight();
0362:
0363: int tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
0364: int ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
0365: int tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
0366: * xtsiz : xsiz;
0367: int ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
0368: * ytsiz : ysiz;
0369:
0370: int xrsiz = infoSrc.getCompSubsX(c);
0371: int yrsiz = infoSrc.getCompSubsY(c);
0372:
0373: int tcx0 = (int) Math.ceil(tx0 / (double) (xrsiz));
0374: int tcy0 = (int) Math.ceil(ty0 / (double) (yrsiz));
0375: int tcx1 = (int) Math.ceil(tx1 / (double) (xrsiz));
0376: int tcy1 = (int) Math.ceil(ty1 / (double) (yrsiz));
0377:
0378: int ndl = infoSrc.getAnSubbandTree(t, c).resLvl - r;
0379: int trx0 = (int) Math.ceil(tcx0 / (double) (1 << ndl));
0380: int try0 = (int) Math.ceil(tcy0 / (double) (1 << ndl));
0381: int trx1 = (int) Math.ceil(tcx1 / (double) (1 << ndl));
0382: int try1 = (int) Math.ceil(tcy1 / (double) (1 << ndl));
0383:
0384: int cb0x = infoSrc.getCbULX();
0385: int cb0y = infoSrc.getCbULY();
0386:
0387: double twoppx = (double) wp.getPrecinctPartition().getPPX(t, c,
0388: r);
0389: double twoppy = (double) wp.getPrecinctPartition().getPPY(t, c,
0390: r);
0391: int twoppx2 = (int) (twoppx / 2);
0392: int twoppy2 = (int) (twoppy / 2);
0393:
0394: // Precincts are located at (cb0x+i*twoppx,cb0y+j*twoppy)
0395: // Valid precincts are those which intersect with the current
0396: // resolution level
0397: int maxPrec = ppinfo[t][c][r].length;
0398: int nPrec = 0;
0399:
0400: int istart = (int) Math.floor((try0 - cb0y) / twoppy);
0401: int iend = (int) Math.floor((try1 - 1 - cb0y) / twoppy);
0402: int jstart = (int) Math.floor((trx0 - cb0x) / twoppx);
0403: int jend = (int) Math.floor((trx1 - 1 - cb0x) / twoppx);
0404:
0405: int acb0x, acb0y;
0406:
0407: SubbandAn root = infoSrc.getAnSubbandTree(t, c);
0408: SubbandAn sb = null;
0409:
0410: int p0x, p0y, p1x, p1y; // Precinct projection in subband
0411: int s0x, s0y, s1x, s1y; // Active subband portion
0412: int cw, ch;
0413: int kstart, kend, lstart, lend, k0, l0;
0414: int prg_ulx, prg_uly;
0415: int prg_w = (int) twoppx << ndl;
0416: int prg_h = (int) twoppy << ndl;
0417:
0418: CBlkCoordInfo cb;
0419:
0420: for (int i = istart; i <= iend; i++) { // Vertical precincts
0421: for (int j = jstart; j <= jend; j++, nPrec++) { // Horizontal precincts
0422: if (j == jstart
0423: && (trx0 - cb0x) % (xrsiz * ((int) twoppx)) != 0) {
0424: prg_ulx = tx0;
0425: } else {
0426: prg_ulx = cb0x + j * xrsiz * ((int) twoppx << ndl);
0427: }
0428: if (i == istart
0429: && (try0 - cb0y) % (yrsiz * ((int) twoppy)) != 0) {
0430: prg_uly = ty0;
0431: } else {
0432: prg_uly = cb0y + i * yrsiz * ((int) twoppy << ndl);
0433: }
0434:
0435: ppinfo[t][c][r][nPrec] = new PrecInfo(r,
0436: (int) (cb0x + j * twoppx), (int) (cb0y + i
0437: * twoppy), (int) twoppx, (int) twoppy,
0438: prg_ulx, prg_uly, prg_w, prg_h);
0439:
0440: if (r == 0) { // LL subband
0441: acb0x = cb0x;
0442: acb0y = cb0y;
0443:
0444: p0x = acb0x + j * (int) twoppx;
0445: p1x = p0x + (int) twoppx;
0446: p0y = acb0y + i * (int) twoppy;
0447: p1y = p0y + (int) twoppy;
0448:
0449: sb = (SubbandAn) root.getSubbandByIdx(0, 0);
0450: s0x = (p0x < sb.ulcx) ? sb.ulcx : p0x;
0451: s1x = (p1x > sb.ulcx + sb.w) ? sb.ulcx + sb.w : p1x;
0452: s0y = (p0y < sb.ulcy) ? sb.ulcy : p0y;
0453: s1y = (p1y > sb.ulcy + sb.h) ? sb.ulcy + sb.h : p1y;
0454:
0455: // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
0456: cw = sb.nomCBlkW;
0457: ch = sb.nomCBlkH;
0458: k0 = (int) Math.floor((sb.ulcy - acb0y)
0459: / (double) ch);
0460: kstart = (int) Math.floor((s0y - acb0y)
0461: / (double) ch);
0462: kend = (int) Math.floor((s1y - 1 - acb0y)
0463: / (double) ch);
0464: l0 = (int) Math.floor((sb.ulcx - acb0x)
0465: / (double) cw);
0466: lstart = (int) Math.floor((s0x - acb0x)
0467: / (double) cw);
0468: lend = (int) Math.floor((s1x - 1 - acb0x)
0469: / (double) cw);
0470:
0471: if (s1x - s0x <= 0 || s1y - s0y <= 0) {
0472: ppinfo[t][c][r][nPrec].nblk[0] = 0;
0473: ttIncl[t][c][r][nPrec][0] = new TagTreeEncoder(
0474: 0, 0);
0475: ttMaxBP[t][c][r][nPrec][0] = new TagTreeEncoder(
0476: 0, 0);
0477: } else {
0478: ttIncl[t][c][r][nPrec][0] = new TagTreeEncoder(
0479: kend - kstart + 1, lend - lstart + 1);
0480: ttMaxBP[t][c][r][nPrec][0] = new TagTreeEncoder(
0481: kend - kstart + 1, lend - lstart + 1);
0482: ppinfo[t][c][r][nPrec].cblk[0] = new CBlkCoordInfo[kend
0483: - kstart + 1][lend - lstart + 1];
0484: ppinfo[t][c][r][nPrec].nblk[0] = (kend - kstart + 1)
0485: * (lend - lstart + 1);
0486:
0487: for (int k = kstart; k <= kend; k++) { // Vertical cblks
0488: for (int l = lstart; l <= lend; l++) { // Horiz. cblks
0489:
0490: cb = new CBlkCoordInfo(k - k0, l - l0);
0491: ppinfo[t][c][r][nPrec].cblk[0][k
0492: - kstart][l - lstart] = cb;
0493: } // Horizontal code-blocks
0494: } // Vertical code-blocks
0495: }
0496: } else { // HL, LH and HH subbands
0497: // HL subband
0498: acb0x = 0;
0499: acb0y = cb0y;
0500:
0501: p0x = acb0x + j * twoppx2;
0502: p1x = p0x + twoppx2;
0503: p0y = acb0y + i * twoppy2;
0504: p1y = p0y + twoppy2;
0505:
0506: sb = (SubbandAn) root.getSubbandByIdx(r, 1);
0507: s0x = (p0x < sb.ulcx) ? sb.ulcx : p0x;
0508: s1x = (p1x > sb.ulcx + sb.w) ? sb.ulcx + sb.w : p1x;
0509: s0y = (p0y < sb.ulcy) ? sb.ulcy : p0y;
0510: s1y = (p1y > sb.ulcy + sb.h) ? sb.ulcy + sb.h : p1y;
0511:
0512: // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
0513: cw = sb.nomCBlkW;
0514: ch = sb.nomCBlkH;
0515: k0 = (int) Math.floor((sb.ulcy - acb0y)
0516: / (double) ch);
0517: kstart = (int) Math.floor((s0y - acb0y)
0518: / (double) ch);
0519: kend = (int) Math.floor((s1y - 1 - acb0y)
0520: / (double) ch);
0521: l0 = (int) Math.floor((sb.ulcx - acb0x)
0522: / (double) cw);
0523: lstart = (int) Math.floor((s0x - acb0x)
0524: / (double) cw);
0525: lend = (int) Math.floor((s1x - 1 - acb0x)
0526: / (double) cw);
0527:
0528: if (s1x - s0x <= 0 || s1y - s0y <= 0) {
0529: ppinfo[t][c][r][nPrec].nblk[1] = 0;
0530: ttIncl[t][c][r][nPrec][1] = new TagTreeEncoder(
0531: 0, 0);
0532: ttMaxBP[t][c][r][nPrec][1] = new TagTreeEncoder(
0533: 0, 0);
0534: } else {
0535: ttIncl[t][c][r][nPrec][1] = new TagTreeEncoder(
0536: kend - kstart + 1, lend - lstart + 1);
0537: ttMaxBP[t][c][r][nPrec][1] = new TagTreeEncoder(
0538: kend - kstart + 1, lend - lstart + 1);
0539: ppinfo[t][c][r][nPrec].cblk[1] = new CBlkCoordInfo[kend
0540: - kstart + 1][lend - lstart + 1];
0541: ppinfo[t][c][r][nPrec].nblk[1] = (kend - kstart + 1)
0542: * (lend - lstart + 1);
0543:
0544: for (int k = kstart; k <= kend; k++) { // Vertical cblks
0545: for (int l = lstart; l <= lend; l++) { // Horiz. cblks
0546: cb = new CBlkCoordInfo(k - k0, l - l0);
0547: ppinfo[t][c][r][nPrec].cblk[1][k
0548: - kstart][l - lstart] = cb;
0549: } // Horizontal code-blocks
0550: } // Vertical code-blocks
0551: }
0552:
0553: // LH subband
0554: acb0x = cb0x;
0555: acb0y = 0;
0556:
0557: p0x = acb0x + j * twoppx2;
0558: p1x = p0x + twoppx2;
0559: p0y = acb0y + i * twoppy2;
0560: p1y = p0y + twoppy2;
0561:
0562: sb = (SubbandAn) root.getSubbandByIdx(r, 2);
0563: s0x = (p0x < sb.ulcx) ? sb.ulcx : p0x;
0564: s1x = (p1x > sb.ulcx + sb.w) ? sb.ulcx + sb.w : p1x;
0565: s0y = (p0y < sb.ulcy) ? sb.ulcy : p0y;
0566: s1y = (p1y > sb.ulcy + sb.h) ? sb.ulcy + sb.h : p1y;
0567:
0568: // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
0569: cw = sb.nomCBlkW;
0570: ch = sb.nomCBlkH;
0571: k0 = (int) Math.floor((sb.ulcy - acb0y)
0572: / (double) ch);
0573: kstart = (int) Math.floor((s0y - acb0y)
0574: / (double) ch);
0575: kend = (int) Math.floor((s1y - 1 - acb0y)
0576: / (double) ch);
0577: l0 = (int) Math.floor((sb.ulcx - acb0x)
0578: / (double) cw);
0579: lstart = (int) Math.floor((s0x - acb0x)
0580: / (double) cw);
0581: lend = (int) Math.floor((s1x - 1 - acb0x)
0582: / (double) cw);
0583:
0584: if (s1x - s0x <= 0 || s1y - s0y <= 0) {
0585: ppinfo[t][c][r][nPrec].nblk[2] = 0;
0586: ttIncl[t][c][r][nPrec][2] = new TagTreeEncoder(
0587: 0, 0);
0588: ttMaxBP[t][c][r][nPrec][2] = new TagTreeEncoder(
0589: 0, 0);
0590: } else {
0591: ttIncl[t][c][r][nPrec][2] = new TagTreeEncoder(
0592: kend - kstart + 1, lend - lstart + 1);
0593: ttMaxBP[t][c][r][nPrec][2] = new TagTreeEncoder(
0594: kend - kstart + 1, lend - lstart + 1);
0595: ppinfo[t][c][r][nPrec].cblk[2] = new CBlkCoordInfo[kend
0596: - kstart + 1][lend - lstart + 1];
0597: ppinfo[t][c][r][nPrec].nblk[2] = (kend - kstart + 1)
0598: * (lend - lstart + 1);
0599:
0600: for (int k = kstart; k <= kend; k++) { // Vertical cblks
0601: for (int l = lstart; l <= lend; l++) { // Horiz cblks
0602: cb = new CBlkCoordInfo(k - k0, l - l0);
0603: ppinfo[t][c][r][nPrec].cblk[2][k
0604: - kstart][l - lstart] = cb;
0605: } // Horizontal code-blocks
0606: } // Vertical code-blocks
0607: }
0608:
0609: // HH subband
0610: acb0x = 0;
0611: acb0y = 0;
0612:
0613: p0x = acb0x + j * twoppx2;
0614: p1x = p0x + twoppx2;
0615: p0y = acb0y + i * twoppy2;
0616: p1y = p0y + twoppy2;
0617:
0618: sb = (SubbandAn) root.getSubbandByIdx(r, 3);
0619: s0x = (p0x < sb.ulcx) ? sb.ulcx : p0x;
0620: s1x = (p1x > sb.ulcx + sb.w) ? sb.ulcx + sb.w : p1x;
0621: s0y = (p0y < sb.ulcy) ? sb.ulcy : p0y;
0622: s1y = (p1y > sb.ulcy + sb.h) ? sb.ulcy + sb.h : p1y;
0623:
0624: // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
0625: cw = sb.nomCBlkW;
0626: ch = sb.nomCBlkH;
0627: k0 = (int) Math.floor((sb.ulcy - acb0y)
0628: / (double) ch);
0629: kstart = (int) Math.floor((s0y - acb0y)
0630: / (double) ch);
0631: kend = (int) Math.floor((s1y - 1 - acb0y)
0632: / (double) ch);
0633: l0 = (int) Math.floor((sb.ulcx - acb0x)
0634: / (double) cw);
0635: lstart = (int) Math.floor((s0x - acb0x)
0636: / (double) cw);
0637: lend = (int) Math.floor((s1x - 1 - acb0x)
0638: / (double) cw);
0639:
0640: if (s1x - s0x <= 0 || s1y - s0y <= 0) {
0641: ppinfo[t][c][r][nPrec].nblk[3] = 0;
0642: ttIncl[t][c][r][nPrec][3] = new TagTreeEncoder(
0643: 0, 0);
0644: ttMaxBP[t][c][r][nPrec][3] = new TagTreeEncoder(
0645: 0, 0);
0646: } else {
0647: ttIncl[t][c][r][nPrec][3] = new TagTreeEncoder(
0648: kend - kstart + 1, lend - lstart + 1);
0649: ttMaxBP[t][c][r][nPrec][3] = new TagTreeEncoder(
0650: kend - kstart + 1, lend - lstart + 1);
0651: ppinfo[t][c][r][nPrec].cblk[3] = new CBlkCoordInfo[kend
0652: - kstart + 1][lend - lstart + 1];
0653: ppinfo[t][c][r][nPrec].nblk[3] = (kend - kstart + 1)
0654: * (lend - lstart + 1);
0655:
0656: for (int k = kstart; k <= kend; k++) { // Vertical cblks
0657: for (int l = lstart; l <= lend; l++) { // Horiz cblks
0658: cb = new CBlkCoordInfo(k - k0, l - l0);
0659: ppinfo[t][c][r][nPrec].cblk[3][k
0660: - kstart][l - lstart] = cb;
0661: } // Horizontal code-blocks
0662: } // Vertical code-blocks
0663: }
0664:
0665: }
0666: } // Horizontal precincts
0667: } // Vertical precincts
0668: }
0669:
0670: /**
0671: * Encodes a packet and returns the buffer containing the encoded packet
0672: * header. The code-blocks appear in a 3D array of CBlkRateDistStats,
0673: * 'cbs'. The first index is the tile index in lexicographical order, the
0674: * second index is the subband index (as defined in the Subband class),
0675: * and the third index is the code-block index (whithin the subband tile)
0676: * in lexicographical order as well. The indexes of the new truncation
0677: * points for each code-block are specified by the 3D array of int
0678: * 'tIndx'. The indices of this array are the same as for cbs. The
0679: * truncation point indices in 'tIndx' are the indices of the elements of
0680: * the 'truncIdxs' array, of the CBlkRateDistStats class, that give the
0681: * real truncation points. If a truncation point index is negative it
0682: * means that the code-block has not been included in any layer yet. If
0683: * the truncation point is less than or equal to the highest truncation
0684: * point used in previous layers then the code-block is not included in
0685: * the packet. Otherwise, if larger, the code-block is included in the
0686: * packet. The body of the packet can be obtained with the
0687: * getLastBodyBuf() and getLastBodyLen() methods.
0688: *
0689: * <p>Layers must be coded in increasing order, in consecutive manner, for
0690: * each tile, component and resolution level (e.g., layer 1, then layer 2,
0691: * etc.). For different tile, component and/or resolution level no
0692: * particular order must be followed.</p>
0693: *
0694: * @param ly The layer index (starts at 1).
0695: *
0696: * @param c The component index.
0697: *
0698: * @param r The resolution level
0699: *
0700: * @param t Index of the current tile
0701: *
0702: * @param cbs The 3D array of coded code-blocks.
0703: *
0704: * @param tIndx The truncation point indices for each code-block.
0705: *
0706: * @param hbuf The header buffer. If null a new BitOutputBuffer is created
0707: * and returned. This buffer is reset before anything is written to it.
0708: *
0709: * @param bbuf The body buffer. If null a new one is created. If not large
0710: * enough a new one is created.
0711: *
0712: * @param pIdx The precinct index.
0713: *
0714: * @return The buffer containing the packet header.
0715: * */
0716: public BitOutputBuffer encodePacket(int ly, int c, int r, int t,
0717: CBlkRateDistStats cbs[][], int tIndx[][],
0718: BitOutputBuffer hbuf, byte bbuf[], int pIdx) {
0719: int b, i, maxi;
0720: int ncb;
0721: int thmax;
0722: int newtp;
0723: int cblen;
0724: int prednbits, nbits, deltabits;
0725: TagTreeEncoder cur_ttIncl, cur_ttMaxBP; // inclusion and bit-depth tag
0726: // trees
0727: int cur_prevtIdxs[]; // last encoded truncation points
0728: CBlkRateDistStats cur_cbs[];
0729: int cur_tIndx[]; // truncation points to encode
0730: int minsb = (r == 0) ? 0 : 1;
0731: int maxsb = (r == 0) ? 1 : 4;
0732: Point cbCoord = null;
0733: SubbandAn root = infoSrc.getAnSubbandTree(t, c);
0734: SubbandAn sb;
0735: roiInPkt = false;
0736: roiLen = 0;
0737: int mend, nend;
0738:
0739: // Checks if a precinct with such an index exists in this resolution
0740: // level
0741: if (pIdx >= ppinfo[t][c][r].length) {
0742: packetWritable = false;
0743: return hbuf;
0744: }
0745: PrecInfo prec = ppinfo[t][c][r][pIdx];
0746:
0747: // First, we check if packet is empty (i.e precinct 'pIdx' has no
0748: // code-block in any of the subbands)
0749: boolean isPrecVoid = true;
0750:
0751: for (int s = minsb; s < maxsb; s++) {
0752: if (prec.nblk[s] == 0) {
0753: // The precinct has no code-block in this subband.
0754: continue;
0755: } else {
0756: // The precinct is not empty in at least one subband ->
0757: // stop
0758: isPrecVoid = false;
0759: break;
0760: }
0761: }
0762:
0763: if (isPrecVoid) {
0764: packetWritable = true;
0765:
0766: if (hbuf == null) {
0767: hbuf = new BitOutputBuffer();
0768: } else {
0769: hbuf.reset();
0770: }
0771: if (bbuf == null) {
0772: lbbuf = bbuf = new byte[1];
0773: }
0774: hbuf.writeBit(0);
0775: lblen = 0;
0776:
0777: return hbuf;
0778: }
0779:
0780: if (hbuf == null) {
0781: hbuf = new BitOutputBuffer();
0782: } else {
0783: hbuf.reset();
0784: }
0785:
0786: // Invalidate last body buffer
0787: lbbuf = null;
0788: lblen = 0;
0789:
0790: // Signal that packet is present
0791: hbuf.writeBit(1);
0792:
0793: for (int s = minsb; s < maxsb; s++) { // Loop on subbands
0794: sb = (SubbandAn) root.getSubbandByIdx(r, s);
0795:
0796: // Go directly to next subband if the precinct has no code-block
0797: // in the current one.
0798: if (prec.nblk[s] == 0) {
0799: continue;
0800: }
0801:
0802: cur_ttIncl = ttIncl[t][c][r][pIdx][s];
0803: cur_ttMaxBP = ttMaxBP[t][c][r][pIdx][s];
0804: cur_prevtIdxs = prevtIdxs[t][c][r][s];
0805: cur_cbs = cbs[s];
0806: cur_tIndx = tIndx[s];
0807:
0808: // Set tag tree values for code-blocks in this precinct
0809: mend = (prec.cblk[s] == null) ? 0 : prec.cblk[s].length;
0810: for (int m = 0; m < mend; m++) {
0811: nend = (prec.cblk[s][m] == null) ? 0
0812: : prec.cblk[s][m].length;
0813: for (int n = 0; n < nend; n++) {
0814: cbCoord = prec.cblk[s][m][n].idx;
0815: b = cbCoord.x + cbCoord.y * sb.numCb.x;
0816:
0817: if (cur_tIndx[b] > cur_prevtIdxs[b]
0818: && cur_prevtIdxs[b] < 0) {
0819: // First inclusion
0820: cur_ttIncl.setValue(m, n, ly - 1);
0821: }
0822: if (ly == 1) { // First layer, need to set the skip of MSBP
0823: cur_ttMaxBP.setValue(m, n, cur_cbs[b].skipMSBP);
0824: }
0825: }
0826: }
0827:
0828: // Now encode the information
0829: for (int m = 0; m < prec.cblk[s].length; m++) { // Vertical code-blocks
0830: for (int n = 0; n < prec.cblk[s][m].length; n++) { // Horiz. cblks
0831: cbCoord = prec.cblk[s][m][n].idx;
0832: b = cbCoord.x + cbCoord.y * sb.numCb.x;
0833:
0834: // 1) Inclusion information
0835: if (cur_tIndx[b] > cur_prevtIdxs[b]) {
0836: // Code-block included in this layer
0837: if (cur_prevtIdxs[b] < 0) { // First inclusion
0838: // Encode layer info
0839: cur_ttIncl.encode(m, n, ly, hbuf);
0840:
0841: // 2) Max bitdepth info. Encode value
0842: thmax = cur_cbs[b].skipMSBP + 1;
0843: for (i = 1; i <= thmax; i++) {
0844: cur_ttMaxBP.encode(m, n, i, hbuf);
0845: }
0846:
0847: // Count body size for packet
0848: lblen += cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
0849: } else { // Already in previous layer
0850: // Send "1" bit
0851: hbuf.writeBit(1);
0852: // Count body size for packet
0853: lblen += cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]]
0854: - cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
0855: }
0856:
0857: // 3) Truncation point information
0858: if (cur_prevtIdxs[b] < 0) {
0859: newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]];
0860: } else {
0861: newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]]
0862: - cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]
0863: - 1;
0864: }
0865:
0866: // Mix of switch and if is faster
0867: switch (newtp) {
0868: case 0:
0869: hbuf.writeBit(0); // Send one "0" bit
0870: break;
0871: case 1:
0872: hbuf.writeBits(2, 2); // Send one "1" and one "0"
0873: break;
0874: case 2:
0875: case 3:
0876: case 4:
0877: // Send two "1" bits followed by 2 bits
0878: // representation of newtp-2
0879: hbuf.writeBits((3 << 2) | (newtp - 2), 4);
0880: break;
0881: default:
0882: if (newtp <= 35) {
0883: // Send four "1" bits followed by a five bits
0884: // representation of newtp-5
0885: hbuf.writeBits((15 << 5) | (newtp - 5),
0886: 9);
0887: } else if (newtp <= 163) {
0888: // Send nine "1" bits followed by a seven bits
0889: // representation of newtp-36
0890: hbuf.writeBits((511 << 7)
0891: | (newtp - 36), 16);
0892: } else {
0893: throw new ArithmeticException(
0894: "Maximum number "
0895: + "of truncation "
0896: + "points exceeded");
0897: }
0898: }
0899: } else { // Block not included in this layer
0900: if (cur_prevtIdxs[b] >= 0) {
0901: // Already in previous layer. Send "0" bit
0902: hbuf.writeBit(0);
0903: } else { // Not in any previous layers
0904: cur_ttIncl.encode(m, n, ly, hbuf);
0905: }
0906: // Go to the next one.
0907: continue;
0908: }
0909:
0910: // Code-block length
0911:
0912: // We need to compute the maximum number of bits needed to
0913: // signal the length of each terminated segment and the
0914: // final truncation point.
0915: newtp = 1;
0916: maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
0917: cblen = (cur_prevtIdxs[b] < 0) ? 0
0918: : cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
0919:
0920: // Loop on truncation points
0921: i = (cur_prevtIdxs[b] < 0) ? 0
0922: : cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] + 1;
0923: int minbits = 0;
0924: for (; i < maxi; i++, newtp++) {
0925: // If terminated truncation point calculate length
0926: if (cur_cbs[b].isTermPass != null
0927: && cur_cbs[b].isTermPass[i]) {
0928:
0929: // Calculate length
0930: cblen = cur_cbs[b].truncRates[i] - cblen;
0931:
0932: // Calculate number of needed bits
0933: prednbits = lblock[t][c][r][s][b]
0934: + MathUtil.log2(newtp);
0935: minbits = ((cblen > 0) ? MathUtil
0936: .log2(cblen) : 0) + 1;
0937:
0938: // Update Lblock increment if needed
0939: for (int j = prednbits; j < minbits; j++) {
0940: lblock[t][c][r][s][b]++;
0941: hbuf.writeBit(1);
0942: }
0943: // Initialize for next length
0944: newtp = 0;
0945: cblen = cur_cbs[b].truncRates[i];
0946: }
0947: }
0948: // Last truncation point length always sent
0949:
0950: // Calculate length
0951: cblen = cur_cbs[b].truncRates[i] - cblen;
0952:
0953: // Calculate number of bits
0954: prednbits = lblock[t][c][r][s][b]
0955: + MathUtil.log2(newtp);
0956: minbits = ((cblen > 0) ? MathUtil.log2(cblen) : 0) + 1;
0957: // Update Lblock increment if needed
0958: for (int j = prednbits; j < minbits; j++) {
0959: lblock[t][c][r][s][b]++;
0960: hbuf.writeBit(1);
0961: }
0962:
0963: // End of comma-code increment
0964: hbuf.writeBit(0);
0965:
0966: // There can be terminated several segments, send length
0967: // info for all terminated truncation points in addition
0968: // to final one
0969: newtp = 1;
0970: maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
0971: cblen = (cur_prevtIdxs[b] < 0) ? 0
0972: : cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
0973: // Loop on truncation points and count the groups
0974: i = (cur_prevtIdxs[b] < 0) ? 0
0975: : cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] + 1;
0976: for (; i < maxi; i++, newtp++) {
0977: // If terminated truncation point, send length
0978: if (cur_cbs[b].isTermPass != null
0979: && cur_cbs[b].isTermPass[i]) {
0980:
0981: cblen = cur_cbs[b].truncRates[i] - cblen;
0982: nbits = MathUtil.log2(newtp)
0983: + lblock[t][c][r][s][b];
0984: hbuf.writeBits(cblen, nbits);
0985:
0986: // Initialize for next length
0987: newtp = 0;
0988: cblen = cur_cbs[b].truncRates[i];
0989: }
0990: }
0991: // Last truncation point length is always signalled
0992: // First calculate number of bits needed to signal
0993: // Calculate length
0994: cblen = cur_cbs[b].truncRates[i] - cblen;
0995: nbits = MathUtil.log2(newtp)
0996: + lblock[t][c][r][s][b];
0997: hbuf.writeBits(cblen, nbits);
0998:
0999: } // End loop on horizontal code-blocks
1000: } // End loop on vertical code-blocks
1001: } // End loop on subband
1002:
1003: // -> Copy the data to the body buffer
1004:
1005: // Ensure size for body data
1006: if (bbuf == null || bbuf.length < lblen) {
1007: bbuf = new byte[lblen];
1008: }
1009: lbbuf = bbuf;
1010: lblen = 0;
1011:
1012: for (int s = minsb; s < maxsb; s++) { // Loop on subbands
1013: sb = (SubbandAn) root.getSubbandByIdx(r, s);
1014:
1015: cur_prevtIdxs = prevtIdxs[t][c][r][s];
1016: cur_cbs = cbs[s];
1017: cur_tIndx = tIndx[s];
1018: ncb = cur_prevtIdxs.length;
1019:
1020: mend = (prec.cblk[s] == null) ? 0 : prec.cblk[s].length;
1021: for (int m = 0; m < mend; m++) { // Vertical code-blocks
1022: nend = (prec.cblk[s][m] == null) ? 0
1023: : prec.cblk[s][m].length;
1024: for (int n = 0; n < nend; n++) { // Horiz. cblks
1025: cbCoord = prec.cblk[s][m][n].idx;
1026: b = cbCoord.x + cbCoord.y * sb.numCb.x;
1027:
1028: if (cur_tIndx[b] > cur_prevtIdxs[b]) {
1029:
1030: // Block included in this precinct -> Copy data to
1031: // body buffer and get code-size
1032: if (cur_prevtIdxs[b] < 0) {
1033: cblen = cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
1034: System.arraycopy(cur_cbs[b].data, 0, lbbuf,
1035: lblen, cblen);
1036: } else {
1037: cblen = cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]]
1038: - cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
1039: System
1040: .arraycopy(
1041: cur_cbs[b].data,
1042: cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]],
1043: lbbuf, lblen, cblen);
1044: }
1045: lblen += cblen;
1046:
1047: // Verifies if this code-block contains new ROI
1048: // information
1049: if (cur_cbs[b].nROIcoeff != 0
1050: && (cur_prevtIdxs[b] == -1 || cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] <= cur_cbs[b].nROIcp - 1)) {
1051: roiInPkt = true;
1052: roiLen = lblen;
1053: }
1054:
1055: // Update truncation point
1056: cur_prevtIdxs[b] = cur_tIndx[b];
1057: }
1058: } // End loop on horizontal code-blocks
1059: } // End loop on vertical code-blocks
1060: } // End loop on subbands
1061:
1062: packetWritable = true;
1063:
1064: // Must never happen
1065: if (hbuf.getLength() == 0) {
1066: throw new Error(
1067: "You have found a bug in PktEncoder, method:"
1068: + " encodePacket");
1069: }
1070:
1071: return hbuf;
1072: }
1073:
1074: /**
1075: * Returns the buffer of the body of the last encoded packet. The length
1076: * of the body can be retrieved with the getLastBodyLen() method. The
1077: * length of the array returned by this method may be larger than the
1078: * actual body length.
1079: *
1080: * @return The buffer of body of the last encoded packet.
1081: *
1082: * @exception IllegalArgumentException If no packet has been coded since
1083: * last reset(), last restore(), or object creation.
1084: *
1085: * @see #getLastBodyLen
1086: * */
1087: public byte[] getLastBodyBuf() {
1088: if (lbbuf == null) {
1089: throw new IllegalArgumentException();
1090: }
1091: return lbbuf;
1092: }
1093:
1094: /**
1095: * Returns the length of the body of the last encoded packet, in
1096: * bytes. The body itself can be retrieved with the getLastBodyBuf()
1097: * method.
1098: *
1099: * @return The length of the body of last encoded packet, in bytes.
1100: *
1101: * @see #getLastBodyBuf
1102: * */
1103: public int getLastBodyLen() {
1104: return lblen;
1105: }
1106:
1107: /**
1108: * Saves the current state of this object. The last saved state
1109: * can be restored with the restore() method.
1110: *
1111: * @see #restore
1112: * */
1113: public void save() {
1114: int maxsbi, minsbi;
1115:
1116: // Have we done any save yet?
1117: if (bak_lblock == null) {
1118: // Allocate backup buffers
1119: bak_lblock = new int[ttIncl.length][][][][];
1120: bak_prevtIdxs = new int[ttIncl.length][][][][];
1121: for (int t = ttIncl.length - 1; t >= 0; t--) {
1122: bak_lblock[t] = new int[ttIncl[t].length][][][];
1123: bak_prevtIdxs[t] = new int[ttIncl[t].length][][][];
1124: for (int c = ttIncl[t].length - 1; c >= 0; c--) {
1125: bak_lblock[t][c] = new int[lblock[t][c].length][][];
1126: bak_prevtIdxs[t][c] = new int[ttIncl[t][c].length][][];
1127: for (int r = lblock[t][c].length - 1; r >= 0; r--) {
1128: bak_lblock[t][c][r] = new int[lblock[t][c][r].length][];
1129: bak_prevtIdxs[t][c][r] = new int[prevtIdxs[t][c][r].length][];
1130: minsbi = (r == 0) ? 0 : 1;
1131: maxsbi = (r == 0) ? 1 : 4;
1132: for (int s = minsbi; s < maxsbi; s++) {
1133: bak_lblock[t][c][r][s] = new int[lblock[t][c][r][s].length];
1134: bak_prevtIdxs[t][c][r][s] = new int[prevtIdxs[t][c][r][s].length];
1135: }
1136: }
1137: }
1138: }
1139: }
1140:
1141: //-- Save the data
1142:
1143: // Use reference caches to minimize array access overhead
1144: TagTreeEncoder ttIncl_t_c[][][], ttMaxBP_t_c[][][], ttIncl_t_c_r[][], ttMaxBP_t_c_r[][];
1145: int lblock_t_c[][][], bak_lblock_t_c[][][], prevtIdxs_t_c_r[][], bak_prevtIdxs_t_c_r[][];
1146:
1147: // Loop on tiles
1148: for (int t = ttIncl.length - 1; t >= 0; t--) {
1149: // Loop on components
1150: for (int c = ttIncl[t].length - 1; c >= 0; c--) {
1151: // Initialize reference caches
1152: lblock_t_c = lblock[t][c];
1153: bak_lblock_t_c = bak_lblock[t][c];
1154: ttIncl_t_c = ttIncl[t][c];
1155: ttMaxBP_t_c = ttMaxBP[t][c];
1156: // Loop on resolution levels
1157: for (int r = lblock_t_c.length - 1; r >= 0; r--) {
1158: // Initialize reference caches
1159: ttIncl_t_c_r = ttIncl_t_c[r];
1160: ttMaxBP_t_c_r = ttMaxBP_t_c[r];
1161: prevtIdxs_t_c_r = prevtIdxs[t][c][r];
1162: bak_prevtIdxs_t_c_r = bak_prevtIdxs[t][c][r];
1163:
1164: // Loop on subbands
1165: minsbi = (r == 0) ? 0 : 1;
1166: maxsbi = (r == 0) ? 1 : 4;
1167: for (int s = minsbi; s < maxsbi; s++) {
1168: // Save 'lblock'
1169: System.arraycopy(lblock_t_c[r][s], 0,
1170: bak_lblock_t_c[r][s], 0,
1171: lblock_t_c[r][s].length);
1172: // Save 'prevtIdxs'
1173: System.arraycopy(prevtIdxs_t_c_r[s], 0,
1174: bak_prevtIdxs_t_c_r[s], 0,
1175: prevtIdxs_t_c_r[s].length);
1176: } // End loop on subbands
1177:
1178: // Loop on precincts
1179: for (int p = ppinfo[t][c][r].length - 1; p >= 0; p--) {
1180: if (p < ttIncl_t_c_r.length) {
1181: // Loop on subbands
1182: for (int s = minsbi; s < maxsbi; s++) {
1183: ttIncl_t_c_r[p][s].save();
1184: ttMaxBP_t_c_r[p][s].save();
1185: } // End loop on subbands
1186: }
1187: } // End loop on precincts
1188: } // End loop on resolutions
1189: } // End loop on components
1190: } // End loop on tiles
1191:
1192: // Set the saved state
1193: saved = true;
1194: }
1195:
1196: /**
1197: * Restores the last saved state of this object. An
1198: * IllegalArgumentException is thrown if no state has been saved.
1199: *
1200: * @see #save
1201: * */
1202: public void restore() {
1203: int maxsbi, minsbi;
1204:
1205: if (!saved) {
1206: throw new IllegalArgumentException();
1207: }
1208:
1209: // Invalidate last encoded body buffer
1210: lbbuf = null;
1211:
1212: //-- Restore tha data
1213:
1214: // Use reference caches to minimize array access overhead
1215: TagTreeEncoder ttIncl_t_c[][][], ttMaxBP_t_c[][][], ttIncl_t_c_r[][], ttMaxBP_t_c_r[][];
1216: int lblock_t_c[][][], bak_lblock_t_c[][][], prevtIdxs_t_c_r[][], bak_prevtIdxs_t_c_r[][];
1217:
1218: // Loop on tiles
1219: for (int t = ttIncl.length - 1; t >= 0; t--) {
1220: // Loop on components
1221: for (int c = ttIncl[t].length - 1; c >= 0; c--) {
1222: // Initialize reference caches
1223: lblock_t_c = lblock[t][c];
1224: bak_lblock_t_c = bak_lblock[t][c];
1225: ttIncl_t_c = ttIncl[t][c];
1226: ttMaxBP_t_c = ttMaxBP[t][c];
1227: // Loop on resolution levels
1228: for (int r = lblock_t_c.length - 1; r >= 0; r--) {
1229: // Initialize reference caches
1230: ttIncl_t_c_r = ttIncl_t_c[r];
1231: ttMaxBP_t_c_r = ttMaxBP_t_c[r];
1232: prevtIdxs_t_c_r = prevtIdxs[t][c][r];
1233: bak_prevtIdxs_t_c_r = bak_prevtIdxs[t][c][r];
1234:
1235: // Loop on subbands
1236: minsbi = (r == 0) ? 0 : 1;
1237: maxsbi = (r == 0) ? 1 : 4;
1238: for (int s = minsbi; s < maxsbi; s++) {
1239: // Restore 'lblock'
1240: System.arraycopy(bak_lblock_t_c[r][s], 0,
1241: lblock_t_c[r][s], 0,
1242: lblock_t_c[r][s].length);
1243: // Restore 'prevtIdxs'
1244: System.arraycopy(bak_prevtIdxs_t_c_r[s], 0,
1245: prevtIdxs_t_c_r[s], 0,
1246: prevtIdxs_t_c_r[s].length);
1247: } // End loop on subbands
1248:
1249: // Loop on precincts
1250: for (int p = ppinfo[t][c][r].length - 1; p >= 0; p--) {
1251: if (p < ttIncl_t_c_r.length) {
1252: // Loop on subbands
1253: for (int s = minsbi; s < maxsbi; s++) {
1254: ttIncl_t_c_r[p][s].restore();
1255: ttMaxBP_t_c_r[p][s].restore();
1256: } // End loop on subbands
1257: }
1258: } // End loop on precincts
1259: } // End loop on resolution levels
1260: } // End loop on components
1261: } // End loop on tiles
1262: }
1263:
1264: /**
1265: * Resets the state of the object to the initial state, as if the object
1266: * was just created.
1267: * */
1268: public void reset() {
1269: int maxsbi, minsbi;
1270:
1271: // Invalidate save
1272: saved = false;
1273: // Invalidate last encoded body buffer
1274: lbbuf = null;
1275:
1276: // Reinitialize each element in the arrays
1277:
1278: // Use reference caches to minimize array access overhead
1279: TagTreeEncoder ttIncl_t_c[][][], ttMaxBP_t_c[][][], ttIncl_t_c_r[][], ttMaxBP_t_c_r[][];
1280: int lblock_t_c[][][], prevtIdxs_t_c_r[][];
1281:
1282: // Loop on tiles
1283: for (int t = ttIncl.length - 1; t >= 0; t--) {
1284: // Loop on components
1285: for (int c = ttIncl[t].length - 1; c >= 0; c--) {
1286: // Initialize reference caches
1287: lblock_t_c = lblock[t][c];
1288: ttIncl_t_c = ttIncl[t][c];
1289: ttMaxBP_t_c = ttMaxBP[t][c];
1290: // Loop on resolution levels
1291: for (int r = lblock_t_c.length - 1; r >= 0; r--) {
1292: // Initialize reference caches
1293: ttIncl_t_c_r = ttIncl_t_c[r];
1294: ttMaxBP_t_c_r = ttMaxBP_t_c[r];
1295: prevtIdxs_t_c_r = prevtIdxs[t][c][r];
1296:
1297: // Loop on subbands
1298: minsbi = (r == 0) ? 0 : 1;
1299: maxsbi = (r == 0) ? 1 : 4;
1300: for (int s = minsbi; s < maxsbi; s++) {
1301: // Reset 'prevtIdxs'
1302: ArrayUtil.intArraySet(prevtIdxs_t_c_r[s], -1);
1303: // Reset 'lblock'
1304: ArrayUtil.intArraySet(lblock_t_c[r][s],
1305: INIT_LBLOCK);
1306: } // End loop on subbands
1307:
1308: // Loop on precincts
1309: for (int p = ppinfo[t][c][r].length - 1; p >= 0; p--) {
1310: if (p < ttIncl_t_c_r.length) {
1311: // Loop on subbands
1312: for (int s = minsbi; s < maxsbi; s++) {
1313: ttIncl_t_c_r[p][s].reset();
1314: ttMaxBP_t_c_r[p][s].reset();
1315: } // End loop on subbands
1316: }
1317: } // End loop on precincts
1318: } // End loop on resolution levels
1319: } // End loop on components
1320: } // End loop on tiles
1321: }
1322:
1323: /**
1324: * Returns true if the current packet is writable i.e. should be written.
1325: * Returns false otherwise.
1326: * */
1327: public boolean isPacketWritable() {
1328: return packetWritable;
1329: }
1330:
1331: /**
1332: * Tells if there was ROI information in the last written packet
1333: * */
1334: public boolean isROIinPkt() {
1335: return roiInPkt;
1336: }
1337:
1338: /** Gives the length to read in current packet body to get all ROI
1339: * information */
1340: public int getROILen() {
1341: return roiLen;
1342: }
1343:
1344: /**
1345: * Returns the parameters that are used in this class and implementing
1346: * classes. It returns a 2D String array. Each of the 1D arrays is for a
1347: * different option, and they have 3 elements. The first element is the
1348: * option name, the second one is the synopsis, the third one is a long
1349: * description of what the parameter is and the fourth is its default
1350: * value. The synopsis or description may be 'null', in which case it is
1351: * assumed that there is no synopsis or description of the option,
1352: * respectively. Null may be returned if no options are supported.
1353: *
1354: * @return the options name, their synopsis and their explanation,
1355: * or null if no options are supported.
1356: * */
1357: public static String[][] getParameterInfo() {
1358: return pinfo;
1359: }
1360:
1361: /**
1362: * Returns information about a given precinct
1363: *
1364: * @param t Tile index.
1365: *
1366: * @param c Component index.
1367: *
1368: * @param r Resolution level index.
1369: *
1370: * @param p Precinct index
1371: * */
1372: public PrecInfo getPrecInfo(int t, int c, int r, int p) {
1373: return ppinfo[t][c][r][p];
1374: }
1375: }
|