001/*
002 * $RCSfile: PktEncoder.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:03 $
005 * $State: Exp $
006 *
007 * Class:                   PktEncoder
008 *
009 * Description:             Builds bit stream packets and keeps
010 *                          interpacket dependencies.
011 *
012 *
013 *
014 * COPYRIGHT:
015 *
016 * This software module was originally developed by Raphaël Grosbois and
017 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
018 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
019 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
020 * Centre France S.A) in the course of development of the JPEG2000
021 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
022 * software module is an implementation of a part of the JPEG 2000
023 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
024 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
025 * Partners) agree not to assert against ISO/IEC and users of the JPEG
026 * 2000 Standard (Users) any of their rights under the copyright, not
027 * including other intellectual property rights, for this software module
028 * with respect to the usage by ISO/IEC and Users of this software module
029 * or modifications thereof for use in hardware or software products
030 * claiming conformance to the JPEG 2000 Standard. Those intending to use
031 * this software module in hardware or software products are advised that
032 * their use may infringe existing patents. The original developers of
033 * this software module, JJ2000 Partners and ISO/IEC assume no liability
034 * for use of this software module or modifications thereof. No license
035 * or right to this software module is granted for non JPEG 2000 Standard
036 * conforming products. JJ2000 Partners have full right to use this
037 * software module for his/her own purpose, assign or donate this
038 * software module to any third party and to inhibit third parties from
039 * using this software module for non JPEG 2000 Standard conforming
040 * products. This copyright notice must be included in all copies or
041 * derivative works of this software module.
042 *
043 * Copyright (c) 1999/2000 JJ2000 Partners.
044 * */
045
046package jj2000.j2k.codestream.writer;
047import java.awt.Point;
048
049import jj2000.j2k.wavelet.analysis.*;
050import jj2000.j2k.entropy.encoder.*;
051import jj2000.j2k.codestream.*;
052import jj2000.j2k.wavelet.*;
053import jj2000.j2k.image.*;
054import jj2000.j2k.util.*;
055import jj2000.j2k.*;
056
057import java.util.Vector;
058import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
059/**
060 * This class builds packets and keeps the state information of packet
061 * interdependencies. It also supports saving the state and reverting
062 * (restoring) to the last saved state, with the save() and restore() methods.
063 *
064 * <P>Each time the encodePacket() method is called a new packet is encoded,
065 * the packet header is returned by the method, and the packet body can be
066 * obtained with the getLastBodyBuf() and getLastBodyLen() methods.
067 * */
068public class PktEncoder {
069
070    /** The prefix for packet encoding options: 'P' */
071    public final static char OPT_PREFIX = 'P';
072
073    /** The list of parameters that is accepted for packet encoding.*/
074    private final static String [][] pinfo = {
075        { "Psop", "[<tile idx>] true|false"+
076         "[ [<tile idx>] true|false ...]",
077          "Specifies whether start of packet (SOP) markers should be used. "+
078          "'true' enables, 'false' disables it.","false"},
079        { "Peph", "[<tile idx>] true|false"+
080         "[ [<tile  idx>] true|false ...]",
081          "Specifies whether end of packet header (EPH) markers should be "+
082          " used. 'true' enables, 'false' disables it.","false"}
083    };
084
085    /** The initial value for the lblock */
086    private final static int INIT_LBLOCK = 3;
087
088    /** The source object */
089    private CodedCBlkDataSrcEnc infoSrc;
090
091    /** The encoder specs */
092    J2KImageWriteParamJava wp;
093
094    /**
095     * The tag tree for inclusion information. The indexes are outlined
096     * below. Note that the layer indexes start at 1, therefore, the layer
097     * index minus 1 is used. The subband indices are used as they are defined
098     * in the Subband class. The tile indices start at 0 and follow a
099     * lexicographical order.
100     *
101     * <ul>
102     * <li>1st index: tile index, in lexicographical order</li>
103     * <li>2nd index: component index </li>
104     * <li>3rd index: resolution level </li>
105     * <li>4th index: subband index </li>
106     * <li>5th index: precinct index </li>
107     * </ul>
108     **/
109    private TagTreeEncoder ttIncl[][][][][];
110
111    /**
112     * The tag tree for the maximum significant bit-plane. The indexes are
113     * outlined below. Note that the layer indexes start at 1, therefore, the
114     * layer index minus 1 is used. The subband indices are used as they are
115     * defined in the Subband class. The tile indices start at 0 and follow a
116     * lexicographical order.
117     *
118     * <ul>
119     * <li>1st index: tile index, in lexicographical order</li>
120     * <li>2nd index: component index </li>
121     * <li>3rd index: resolution level </li>
122     * <li>4th index: subband index - subband index offset </li>
123     * <li>5th index: precinct index </li>
124     * </ul>
125     * */
126    private TagTreeEncoder ttMaxBP[][][][][];
127
128    /**
129     * The base number of bits for sending code-block length information
130     * (referred as Lblock in the JPEG 2000 standard). The indexes are
131     * outlined below. Note that the layer indexes start at 1, therefore, the
132     * layer index minus 1 is used. The subband indices are used as they are
133     * defined in the Subband class. The tile indices start at 0 and follow a
134     * lexicographical order.
135     *
136     * <ul>
137     * <li>1st index: tile index, in lexicographical order </li>
138     * <li>2nd index: component index </li>
139     * <li>3rd index: resolution level </li>
140     * <li>4th index: subband index - subband index offset </li>
141     * <li>5th index: code-block index, in lexicographical order</li>
142     * </ul>
143     * */
144    private int lblock[][][][][];
145
146    /**
147     * The last encoded truncation point for each code-block. A negative value
148     * means that no information has been included for the block, yet. The
149     * indexes are outlined below. The subband indices are used as they are
150     * defined in the Subband class. The tile indices start at 0 and follow a
151     * lexicographical order. The code-block indices follow a lexicographical
152     * order within the subband tile.
153     *
154     * <P>What is actually stored is the index of the element in
155     * CBlkRateDistStats.truncIdxs that gives the real truncation point.
156     *
157     * <ul>
158     * <li>1st index: tile index, in lexicographical order </li>
159     * <li>2nd index: component index </li>
160     * <li>3rd index: resolution level </li>
161     * <li>4th index: subband index - subband index offset </li>
162     * <li>5th index: code-block index, in lexicographical order </li>
163     * </ul>
164     *  */
165    private int prevtIdxs[][][][][];
166
167    /**
168     * The saved base number of bits for sending code-block length
169     * information. It is used for restoring previous saved state by
170     * restore(). The indexes are outlined below. Note that the layer indexes
171     * start at 1, therefore, the layer index minus 1 is used. The subband
172     * indices are used as they are defined in the Subband class. The tile
173     * indices start at 0 and follow a lexicographical order.
174     *
175     * <ul>
176     * <li>1st index: tile index, in lexicographical order </li>
177     * <li>2nd index: component index </li>
178     * <li>3rd index: resolution level </li>
179     * <li>4th index: subband index - subband index offset </li>
180     * <li>5th index: code-block index, in lexicographical order</li>
181     * </ul>
182     * */
183    private int bak_lblock[][][][][];
184
185    /**
186     * The saved last encoded truncation point for each code-block. It is used
187     * for restoring previous saved state by restore(). A negative value means
188     * that no information has been included for the block, yet. The indexes
189     * are outlined below. The subband indices are used as they are defined in
190     * the Subband class. The tile indices start at 0 and follow a
191     * lexicographical order. The code-block indices follow a lexicographical
192     * order within the subband tile.
193     *
194     * <ul>
195     * <li>1st index: tile index, in lexicographical order </li>
196     * <li>2nd index: component index </li>
197     * <li>3rd index: resolution level </li>
198     * <li>4th index: subband index - subband index offset </li>
199     * <li>5th index: code-block index, in lexicographical order </li>
200     * </ul>
201     *  */
202    private int bak_prevtIdxs[][][][][];
203
204    /** The body buffer of the last encoded packet */
205    private byte[] lbbuf;
206
207    /** The body length of the last encoded packet */
208    private int lblen;
209
210    /** The saved state */
211    private boolean saved;
212
213    /** Whether or not there is ROI information in the last encoded Packet */
214    private boolean roiInPkt = false;
215
216    /** Length to read in current packet body to get all the ROI information */
217    private int roiLen = 0;
218
219    /**
220     * Array containing the coordinates, width, height, indexes, ... of the
221     * precincts.
222     *
223     * <ul>
224     * <li> 1st dim: tile index.</li>
225     * <li> 2nd dim: component index.</li>
226     * <li> 3rd dim: resolution level index.</li>
227     * <li> 4th dim: precinct index.</li>
228     * </ul> 
229     * */
230    private PrecInfo ppinfo[][][][];
231
232    /** Whether or not the current packet is writable */
233    private boolean packetWritable;
234
235    /**
236     * Creates a new packet header encoder, using the information from the
237     * 'infoSrc' object. The information used is the number of components,
238     * number of tiles, subband decomposition, etc.
239     *
240     * <P>Note that this constructor visits all the tiles in the 'infoSrc'
241     * object. The 'infoSrc' object is left at the original tile (i.e. the
242     * current tile before calling this constructor), but any side effects of
243     * visiting the tiles is not reverted.
244     *
245     * @param infoSrc The source of information to construct the
246     * object.
247     *
248     * @param encSpec The parameters for the encoding
249     *
250     * @param maxNumPrec Maximum number of precinct in each tile, component
251     * and resolution level.
252     *
253     * @param pl ParameterList instance that holds command line options
254     * */
255    public PktEncoder(CodedCBlkDataSrcEnc infoSrc, J2KImageWriteParamJava wp,
256                      Point[][][] numPrec) {
257        this.infoSrc = infoSrc;
258        this.wp = wp;
259//        this.numPrec = numPrec;
260
261        // Get number of components and tiles
262        int nc = infoSrc.getNumComps();
263        int nt = infoSrc.getNumTiles();
264
265        // Do initial allocation
266        ttIncl = new TagTreeEncoder[nt][nc][][][];
267        ttMaxBP = new TagTreeEncoder[nt][nc][][][];
268        lblock = new int[nt][nc][][][];
269        prevtIdxs = new int[nt][nc][][][];
270        ppinfo = new PrecInfo[nt][nc][][];
271
272        // Finish allocation
273        SubbandAn root,sb;
274        int maxs,mins;
275        int mrl;
276        Point tmpCoord = null;
277        int numcb;       // Number of code-blocks
278        Vector cblks = null;
279        infoSrc.setTile(0,0);
280        for (int t=0; t<nt; t++) { // Loop on tiles
281            for (int c=0; c<nc; c++) { // Loop on components
282                // Get number of resolution levels
283                root = infoSrc.getAnSubbandTree(t,c);
284                mrl = root.resLvl;
285
286                lblock[t][c] = new int[mrl+1][][];
287                ttIncl[t][c] = new TagTreeEncoder[mrl+1][][];
288                ttMaxBP[t][c] = new TagTreeEncoder[mrl+1][][];
289                prevtIdxs[t][c] = new int[mrl+1][][];
290                ppinfo[t][c] = new PrecInfo[mrl+1][];
291
292                for(int r=0; r<=mrl; r++) { // Loop on resolution levels
293                    mins = (r==0) ? 0 : 1;
294                    maxs = (r==0) ? 1 : 4;
295
296                    int maxPrec = numPrec[t][c][r].x*numPrec[t][c][r].y;
297
298                    ttIncl[t][c][r] = new TagTreeEncoder[maxPrec][maxs];
299                    ttMaxBP[t][c][r] = new TagTreeEncoder[maxPrec][maxs];
300                    prevtIdxs[t][c][r] = new int[maxs][];
301                    lblock[t][c][r] = new int[maxs][];
302
303                    // Precincts and code-blocks
304                    ppinfo[t][c][r] = new PrecInfo[maxPrec];
305                    fillPrecInfo(t,c,r);
306
307                    for(int s=mins; s<maxs; s++) {
308                        // Loop on subbands
309                        sb = (SubbandAn)root.getSubbandByIdx(r,s);
310                        numcb = sb.numCb.x*sb.numCb.y;
311
312                        lblock[t][c][r][s] = new int[numcb];
313                        ArrayUtil.intArraySet(lblock[t][c][r][s],INIT_LBLOCK);
314
315                        prevtIdxs[t][c][r][s] = new int[numcb];
316                        ArrayUtil.intArraySet(prevtIdxs[t][c][r][s],-1);
317                    }
318                }
319            }
320            if(t!=nt-1) infoSrc.nextTile();
321        }
322    }
323
324
325    /** 
326     * Retrives precincts and code-blocks coordinates in the given resolution,
327     * component and tile. It terminates TagTreeEncoder initialization as
328     * well.
329     *
330     * @param t Tile index.
331     *
332     * @param c Component index.
333     *
334     * @param r Resolution level index.
335     * */
336    private void fillPrecInfo(int t,int c,int r) {
337        if(ppinfo[t][c][r].length==0) return; // No precinct in this
338        // resolution level
339
340        Point tileI = infoSrc.getTile(null);
341        Point nTiles = infoSrc.getNumTiles(null);
342
343        int x0siz = infoSrc.getImgULX();
344        int y0siz = infoSrc.getImgULY();
345        int xsiz = x0siz + infoSrc.getImgWidth();
346        int ysiz = y0siz + infoSrc.getImgHeight();
347        int xt0siz = infoSrc.getTilePartULX();
348        int yt0siz = infoSrc.getTilePartULY();
349        int xtsiz = infoSrc.getNomTileWidth();
350        int ytsiz = infoSrc.getNomTileHeight();
351
352        int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
353        int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
354        int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
355        int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
356
357        int xrsiz = infoSrc.getCompSubsX(c);
358        int yrsiz = infoSrc.getCompSubsY(c);
359
360        int tcx0 = (int)Math.ceil(tx0/(double)(xrsiz));
361        int tcy0 = (int)Math.ceil(ty0/(double)(yrsiz));
362        int tcx1 = (int)Math.ceil(tx1/(double)(xrsiz));
363        int tcy1 = (int)Math.ceil(ty1/(double)(yrsiz));
364
365        int ndl = infoSrc.getAnSubbandTree(t,c).resLvl-r;
366        int trx0 = (int)Math.ceil(tcx0/(double)(1<<ndl));
367        int try0 = (int)Math.ceil(tcy0/(double)(1<<ndl));
368        int trx1 = (int)Math.ceil(tcx1/(double)(1<<ndl));
369        int try1 = (int)Math.ceil(tcy1/(double)(1<<ndl));
370
371        int cb0x = infoSrc.getCbULX();
372        int cb0y = infoSrc.getCbULY();
373
374        double twoppx = (double)wp.getPrecinctPartition().getPPX(t,c,r);
375        double twoppy = (double)wp.getPrecinctPartition().getPPY(t,c,r);
376        int twoppx2 = (int)(twoppx/2);
377        int twoppy2 = (int)(twoppy/2);
378
379        // Precincts are located at (cb0x+i*twoppx,cb0y+j*twoppy)
380        // Valid precincts are those which intersect with the current
381        // resolution level
382        int maxPrec = ppinfo[t][c][r].length;
383        int nPrec = 0;
384
385        int istart = (int)Math.floor((try0-cb0y)/twoppy);
386        int iend = (int)Math.floor((try1-1-cb0y)/twoppy);
387        int jstart = (int)Math.floor((trx0-cb0x)/twoppx);
388        int jend = (int)Math.floor((trx1-1-cb0x)/twoppx);
389
390        int acb0x,acb0y;
391
392        SubbandAn root = infoSrc.getAnSubbandTree(t,c);
393        SubbandAn sb = null;
394
395        int p0x,p0y,p1x,p1y; // Precinct projection in subband
396        int s0x,s0y,s1x,s1y; // Active subband portion
397        int cw,ch;
398        int kstart,kend,lstart,lend,k0,l0;
399        int prg_ulx,prg_uly;
400        int prg_w = (int)twoppx<<ndl;
401        int prg_h = (int)twoppy<<ndl;
402
403        CBlkCoordInfo cb;
404
405        for(int i=istart; i<=iend; i++) { // Vertical precincts
406            for(int j=jstart; j<=jend; j++,nPrec++) { // Horizontal precincts
407                if(j==jstart && (trx0-cb0x)%(xrsiz*((int)twoppx))!=0) {
408                    prg_ulx = tx0;
409                } else {
410                    prg_ulx = cb0x+j*xrsiz*((int)twoppx<<ndl);
411                }
412                if(i==istart && (try0-cb0y)%(yrsiz*((int)twoppy))!=0) {
413                    prg_uly = ty0;
414                } else {
415                    prg_uly = cb0y+i*yrsiz*((int)twoppy<<ndl);
416                }
417
418                ppinfo[t][c][r][nPrec] =
419                    new PrecInfo(r,(int)(cb0x+j*twoppx),(int)(cb0y+i*twoppy),
420                                 (int)twoppx,(int)twoppy,
421                                 prg_ulx,prg_uly,prg_w,prg_h);
422
423                if(r==0) { // LL subband
424                    acb0x = cb0x;
425                    acb0y = cb0y;
426
427                    p0x = acb0x+j*(int)twoppx;
428                    p1x = p0x + (int)twoppx;
429                    p0y = acb0y+i*(int)twoppy;
430                    p1y = p0y + (int)twoppy;
431
432                    sb = (SubbandAn)root.getSubbandByIdx(0,0);
433                    s0x = (p0x<sb.ulcx) ? sb.ulcx : p0x;
434                    s1x = (p1x>sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x;
435                    s0y = (p0y<sb.ulcy) ? sb.ulcy : p0y;
436                    s1y = (p1y>sb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y;
437
438                    // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
439                    cw = sb.nomCBlkW;
440                    ch = sb.nomCBlkH;
441                    k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch);
442                    kstart = (int)Math.floor((s0y-acb0y)/(double)ch);
443                    kend = (int)Math.floor((s1y-1-acb0y)/(double)ch);
444                    l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw);
445                    lstart = (int)Math.floor((s0x-acb0x)/(double)cw);
446                    lend = (int)Math.floor((s1x-1-acb0x)/(double)cw);
447
448                    if(s1x-s0x<=0 || s1y-s0y<=0) {
449                        ppinfo[t][c][r][nPrec].nblk[0] = 0;
450                        ttIncl[t][c][r][nPrec][0] = new TagTreeEncoder(0,0);
451                        ttMaxBP[t][c][r][nPrec][0] = new TagTreeEncoder(0,0);
452                    } else {
453                        ttIncl[t][c][r][nPrec][0] =
454                            new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
455                        ttMaxBP[t][c][r][nPrec][0] =
456                            new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
457                        ppinfo[t][c][r][nPrec].cblk[0] =
458                            new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
459                        ppinfo[t][c][r][nPrec].
460                            nblk[0] = (kend-kstart+1)*(lend-lstart+1);
461
462                        for(int k=kstart; k<=kend; k++) { // Vertical cblks
463                            for(int l=lstart; l<=lend; l++) { // Horiz. cblks
464
465                               cb = new CBlkCoordInfo(k-k0,l-l0);
466                                ppinfo[t][c][r][nPrec].
467                                    cblk[0][k-kstart][l-lstart] = cb;
468                            } // Horizontal code-blocks
469                        } // Vertical code-blocks
470                    }
471                } else { // HL, LH and HH subbands
472                    // HL subband
473                    acb0x = 0;
474                    acb0y = cb0y;
475
476                    p0x = acb0x+j*twoppx2;
477                    p1x = p0x + twoppx2;
478                    p0y = acb0y+i*twoppy2;
479                    p1y = p0y + twoppy2;
480
481                    sb = (SubbandAn)root.getSubbandByIdx(r,1);
482                    s0x = (p0x<sb.ulcx) ? sb.ulcx : p0x;
483                    s1x = (p1x>sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x;
484                    s0y = (p0y<sb.ulcy) ? sb.ulcy : p0y;
485                    s1y = (p1y>sb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y;
486
487                    // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
488                    cw = sb.nomCBlkW;
489                    ch = sb.nomCBlkH;
490                    k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch);
491                    kstart = (int)Math.floor((s0y-acb0y)/(double)ch);
492                    kend = (int)Math.floor((s1y-1-acb0y)/(double)ch);
493                    l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw);
494                    lstart = (int)Math.floor((s0x-acb0x)/(double)cw);
495                    lend = (int)Math.floor((s1x-1-acb0x)/(double)cw);
496
497                    if(s1x-s0x<=0 || s1y-s0y<=0) {
498                        ppinfo[t][c][r][nPrec].nblk[1] = 0;
499                        ttIncl[t][c][r][nPrec][1] = new TagTreeEncoder(0,0);
500                        ttMaxBP[t][c][r][nPrec][1] = new TagTreeEncoder(0,0);
501                    } else {
502                        ttIncl[t][c][r][nPrec][1] =
503                            new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
504                        ttMaxBP[t][c][r][nPrec][1] =
505                            new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
506                        ppinfo[t][c][r][nPrec].cblk[1] =
507                            new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
508                        ppinfo[t][c][r][nPrec].
509                            nblk[1] = (kend-kstart+1)*(lend-lstart+1);
510
511                        for(int k=kstart; k<=kend; k++) { // Vertical cblks
512                            for(int l=lstart; l<=lend; l++) { // Horiz. cblks
513                                cb = new CBlkCoordInfo(k-k0,l-l0);
514                                ppinfo[t][c][r][nPrec].
515                                    cblk[1][k-kstart][l-lstart] = cb;
516                            } // Horizontal code-blocks
517                        } // Vertical code-blocks
518                    }
519
520                    // LH subband
521                    acb0x = cb0x;
522                    acb0y = 0;
523
524                    p0x = acb0x+j*twoppx2;
525                    p1x = p0x + twoppx2;
526                    p0y = acb0y+i*twoppy2;
527                    p1y = p0y + twoppy2;
528
529                    sb = (SubbandAn)root.getSubbandByIdx(r,2);
530                    s0x = (p0x<sb.ulcx) ? sb.ulcx : p0x;
531                    s1x = (p1x>sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x;
532                    s0y = (p0y<sb.ulcy) ? sb.ulcy : p0y;
533                    s1y = (p1y>sb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y;
534
535                    // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
536                    cw = sb.nomCBlkW;
537                    ch = sb.nomCBlkH;
538                    k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch);
539                    kstart = (int)Math.floor((s0y-acb0y)/(double)ch);
540                    kend = (int)Math.floor((s1y-1-acb0y)/(double)ch);
541                    l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw);
542                    lstart = (int)Math.floor((s0x-acb0x)/(double)cw);
543                    lend = (int)Math.floor((s1x-1-acb0x)/(double)cw);
544
545                    if(s1x-s0x<=0 || s1y-s0y<=0) {
546                        ppinfo[t][c][r][nPrec].nblk[2] = 0;
547                        ttIncl[t][c][r][nPrec][2] = new TagTreeEncoder(0,0);
548                        ttMaxBP[t][c][r][nPrec][2] = new TagTreeEncoder(0,0);
549                    } else {
550                        ttIncl[t][c][r][nPrec][2] =
551                            new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
552                        ttMaxBP[t][c][r][nPrec][2] =
553                            new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
554                        ppinfo[t][c][r][nPrec].cblk[2] =
555                            new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
556                        ppinfo[t][c][r][nPrec].
557                            nblk[2] = (kend-kstart+1)*(lend-lstart+1);
558
559                        for(int k=kstart; k<=kend; k++) { // Vertical cblks
560                            for(int l=lstart; l<=lend; l++) { // Horiz cblks
561                                cb = new CBlkCoordInfo(k-k0,l-l0);
562                                ppinfo[t][c][r][nPrec].
563                                    cblk[2][k-kstart][l-lstart] = cb;
564                            } // Horizontal code-blocks
565                        } // Vertical code-blocks
566                    }
567
568                    // HH subband
569                    acb0x = 0;
570                    acb0y = 0;
571
572                    p0x = acb0x+j*twoppx2;
573                    p1x = p0x + twoppx2;
574                    p0y = acb0y+i*twoppy2;
575                    p1y = p0y + twoppy2;
576
577                    sb = (SubbandAn)root.getSubbandByIdx(r,3);
578                    s0x = (p0x<sb.ulcx) ? sb.ulcx : p0x;
579                    s1x = (p1x>sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x;
580                    s0y = (p0y<sb.ulcy) ? sb.ulcy : p0y;
581                    s1y = (p1y>sb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y;
582
583                    // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
584                    cw = sb.nomCBlkW;
585                    ch = sb.nomCBlkH;
586                    k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch);
587                    kstart = (int)Math.floor((s0y-acb0y)/(double)ch);
588                    kend = (int)Math.floor((s1y-1-acb0y)/(double)ch);
589                    l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw);
590                    lstart = (int)Math.floor((s0x-acb0x)/(double)cw);
591                    lend = (int)Math.floor((s1x-1-acb0x)/(double)cw);
592
593                    if(s1x-s0x<=0 || s1y-s0y<=0) {
594                        ppinfo[t][c][r][nPrec].nblk[3] = 0;
595                        ttIncl[t][c][r][nPrec][3] = new TagTreeEncoder(0,0);
596                        ttMaxBP[t][c][r][nPrec][3] = new TagTreeEncoder(0,0);
597                    } else {
598                        ttIncl[t][c][r][nPrec][3] =
599                            new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
600                        ttMaxBP[t][c][r][nPrec][3] =
601                            new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
602                        ppinfo[t][c][r][nPrec].cblk[3] =
603                            new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
604                        ppinfo[t][c][r][nPrec].
605                            nblk[3] = (kend-kstart+1)*(lend-lstart+1);
606
607                        for(int k=kstart; k<=kend; k++) { // Vertical cblks
608                            for(int l=lstart; l<=lend; l++) { // Horiz cblks
609                                cb = new CBlkCoordInfo(k-k0,l-l0);
610                                ppinfo[t][c][r][nPrec].
611                                    cblk[3][k-kstart][l-lstart] = cb;
612                            } // Horizontal code-blocks
613                        } // Vertical code-blocks
614                    }
615
616                }
617            } // Horizontal precincts
618        } // Vertical precincts
619   }
620
621
622    /**
623     * Encodes a packet and returns the buffer containing the encoded packet
624     * header. The code-blocks appear in a 3D array of CBlkRateDistStats,
625     * 'cbs'. The first index is the tile index in lexicographical order, the
626     * second index is the subband index (as defined in the Subband class),
627     * and the third index is the code-block index (whithin the subband tile)
628     * in lexicographical order as well. The indexes of the new truncation
629     * points for each code-block are specified by the 3D array of int
630     * 'tIndx'. The indices of this array are the same as for cbs. The
631     * truncation point indices in 'tIndx' are the indices of the elements of
632     * the 'truncIdxs' array, of the CBlkRateDistStats class, that give the
633     * real truncation points. If a truncation point index is negative it
634     * means that the code-block has not been included in any layer yet. If
635     * the truncation point is less than or equal to the highest truncation
636     * point used in previous layers then the code-block is not included in
637     * the packet. Otherwise, if larger, the code-block is included in the
638     * packet. The body of the packet can be obtained with the
639     * getLastBodyBuf() and getLastBodyLen() methods.
640     *
641     * <p>Layers must be coded in increasing order, in consecutive manner, for
642     * each tile, component and resolution level (e.g., layer 1, then layer 2,
643     * etc.). For different tile, component and/or resolution level no
644     * particular order must be followed.</p>
645     *
646     * @param ly The layer index (starts at 1).
647     *
648     * @param c The component index.
649     *
650     * @param r The resolution level
651     *
652     * @param t Index of the current tile
653     *
654     * @param cbs The 3D array of coded code-blocks.
655     *
656     * @param tIndx The truncation point indices for each code-block.
657     *
658     * @param hbuf The header buffer. If null a new BitOutputBuffer is created
659     * and returned. This buffer is reset before anything is written to it.
660     *
661     * @param bbuf The body buffer. If null a new one is created. If not large
662     * enough a new one is created.
663     *
664     * @param pIdx The precinct index.
665     *
666     * @return The buffer containing the packet header.
667     * */
668    public BitOutputBuffer encodePacket(int ly,int c,int r,int t,
669                                        CBlkRateDistStats cbs[][],
670                                        int tIndx[][],BitOutputBuffer hbuf,
671                                        byte bbuf[],int pIdx) {
672        int b,i,maxi;
673        int ncb;
674        int thmax;
675        int newtp;
676        int cblen;
677        int prednbits,nbits,deltabits;
678        TagTreeEncoder cur_ttIncl,cur_ttMaxBP; // inclusion and bit-depth tag
679        // trees 
680        int cur_prevtIdxs[]; // last encoded truncation points
681        CBlkRateDistStats cur_cbs[];
682        int cur_tIndx[]; // truncation points to encode
683        int minsb = (r==0) ? 0 : 1;
684        int maxsb = (r==0) ? 1 : 4;
685        Point cbCoord = null;
686        SubbandAn root = infoSrc.getAnSubbandTree(t,c);
687        SubbandAn sb;
688        roiInPkt = false;
689        roiLen = 0;
690        int mend,nend;
691
692        // Checks if a precinct with such an index exists in this resolution
693        // level
694        if(pIdx>=ppinfo[t][c][r].length) {
695            packetWritable = false;
696            return hbuf;
697        }
698        PrecInfo prec = ppinfo[t][c][r][pIdx];
699
700        // First, we check if packet is empty (i.e precinct 'pIdx' has no
701        // code-block in any of the subbands)
702        boolean isPrecVoid = true;
703
704        for(int s=minsb; s<maxsb; s++) {
705            if(prec.nblk[s]==0) {
706                // The precinct has no code-block in this subband.
707                continue;
708            } else {
709                // The precinct is not empty in at least one subband ->
710                // stop
711                isPrecVoid = false;
712                break;
713            }
714        }
715
716        if(isPrecVoid) {
717            packetWritable = true;
718
719            if(hbuf == null) {
720                hbuf = new BitOutputBuffer();
721            } else {
722                hbuf.reset();
723            }
724            if (bbuf == null) {
725                lbbuf = bbuf = new byte[1];
726            }
727            hbuf.writeBit(0);
728            lblen = 0;
729
730            return hbuf;
731        }
732
733        if(hbuf == null) {
734            hbuf = new BitOutputBuffer();
735        } else {
736            hbuf.reset();
737        }
738
739        // Invalidate last body buffer
740        lbbuf = null;
741        lblen = 0;
742
743        // Signal that packet is present
744        hbuf.writeBit(1);
745
746        for(int s=minsb; s<maxsb; s++) { // Loop on subbands
747            sb = (SubbandAn)root.getSubbandByIdx(r,s);
748
749            // Go directly to next subband if the precinct has no code-block
750            // in the current one.
751            if(prec.nblk[s]==0) {
752                continue;
753            }
754
755            cur_ttIncl = ttIncl[t][c][r][pIdx][s];
756            cur_ttMaxBP = ttMaxBP[t][c][r][pIdx][s];
757            cur_prevtIdxs = prevtIdxs[t][c][r][s];
758            cur_cbs = cbs[s];
759            cur_tIndx = tIndx[s];
760
761            // Set tag tree values for code-blocks in this precinct
762            mend = (prec.cblk[s]==null) ? 0 : prec.cblk[s].length;
763            for(int m=0; m<mend; m++) {
764                nend = (prec.cblk[s][m]==null) ? 0 : prec.cblk[s][m].length;
765                for (int n=0; n<nend; n++) {
766                    cbCoord = prec.cblk[s][m][n].idx;
767                    b = cbCoord.x+cbCoord.y*sb.numCb.x;
768
769                    if (cur_tIndx[b]>cur_prevtIdxs[b] && cur_prevtIdxs[b]<0) {
770                        // First inclusion
771                        cur_ttIncl.setValue(m,n,ly-1);
772                    }
773                    if (ly==1) { // First layer, need to set the skip of MSBP
774                        cur_ttMaxBP.setValue(m,n,cur_cbs[b].skipMSBP);
775                    }
776                }
777            }
778
779            // Now encode the information
780            for(int m=0; m<prec.cblk[s].length; m++) { // Vertical code-blocks
781                for (int n=0; n<prec.cblk[s][m].length; n++) { // Horiz. cblks
782                    cbCoord = prec.cblk[s][m][n].idx;
783                    b = cbCoord.x+cbCoord.y*sb.numCb.x;
784
785                    // 1) Inclusion information
786                    if (cur_tIndx[b]>cur_prevtIdxs[b]) {
787                        // Code-block included in this layer
788                        if (cur_prevtIdxs[b]<0) { // First inclusion
789                            // Encode layer info
790                            cur_ttIncl.encode(m,n,ly,hbuf);
791
792                            // 2) Max bitdepth info. Encode value
793                            thmax = cur_cbs[b].skipMSBP+1;
794                            for (i=1; i<=thmax; i++) {
795                                cur_ttMaxBP.encode(m,n,i,hbuf);
796                            }
797
798                            // Count body size for packet
799                            lblen += cur_cbs[b].
800                                truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
801                        } else { // Already in previous layer
802                            // Send "1" bit
803                            hbuf.writeBit(1);
804                            // Count body size for packet
805                            lblen +=
806                                cur_cbs[b].
807                                truncRates[cur_cbs[b].
808                                          truncIdxs[cur_tIndx[b]]] -
809                                cur_cbs[b].
810                                truncRates[cur_cbs[b].
811                                          truncIdxs[cur_prevtIdxs[b]]];
812                        }
813
814                        // 3) Truncation point information
815                        if (cur_prevtIdxs[b]<0) {
816                            newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]];
817                        } else {
818                            newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]]-
819                                cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]-1;
820                        }
821
822                        // Mix of switch and if is faster
823                        switch (newtp) {
824                        case 0:
825                            hbuf.writeBit(0); // Send one "0" bit
826                            break;
827                        case 1:
828                            hbuf.writeBits(2,2); // Send one "1" and one "0"
829                            break;
830                        case 2:
831                        case 3:
832                        case 4:
833                            // Send two "1" bits followed by 2 bits
834                            // representation of newtp-2
835                            hbuf.writeBits((3<<2)|(newtp-2),4);
836                            break;
837                        default:
838                            if (newtp <= 35) {
839                                // Send four "1" bits followed by a five bits
840                                // representation of newtp-5
841                                hbuf.writeBits((15<<5)|(newtp-5),9);
842                            } else if (newtp <= 163) {
843                                // Send nine "1" bits followed by a seven bits
844                                // representation of newtp-36
845                                hbuf.writeBits((511<<7)|(newtp-36),16);
846                            } else {
847                                throw new
848                                    ArithmeticException("Maximum number "+
849                                                        "of truncation "+
850                                                        "points exceeded");
851                            }
852                        }
853                    } else { // Block not included in this layer
854                        if (cur_prevtIdxs[b]>=0) {
855                            // Already in previous layer. Send "0" bit
856                            hbuf.writeBit(0);
857                        } else { // Not in any previous layers
858                            cur_ttIncl.encode(m,n,ly,hbuf);
859                        }
860                        // Go to the next one.
861                        continue;
862                    }
863
864                    // Code-block length
865
866                    // We need to compute the maximum number of bits needed to
867                    // signal the length of each terminated segment and the
868                    // final truncation point.
869                    newtp = 1;
870                    maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
871                    cblen = (cur_prevtIdxs[b]<0) ? 0 :
872                        cur_cbs[b].truncRates[cur_cbs[b].
873                                             truncIdxs[cur_prevtIdxs[b]]];
874
875                    // Loop on truncation points
876                    i = (cur_prevtIdxs[b]<0) ? 0 :
877                        cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]+1;
878                    int minbits = 0;
879                    for (; i<maxi; i++, newtp++) {
880                        // If terminated truncation point calculate length
881                        if (cur_cbs[b].isTermPass != null &&
882                            cur_cbs[b].isTermPass[i]) {
883
884                            // Calculate length
885                            cblen = cur_cbs[b].truncRates[i] - cblen;
886
887                            // Calculate number of needed bits
888                            prednbits = lblock[t][c][r][s][b] +
889                                MathUtil.log2(newtp);
890                            minbits = ((cblen>0) ? MathUtil.log2(cblen) : 0)+1;
891
892                            // Update Lblock increment if needed
893                            for(int j=prednbits; j<minbits; j++) {
894                                lblock[t][c][r][s][b]++;
895                                hbuf.writeBit(1);
896                            }
897                            // Initialize for next length
898                            newtp = 0;
899                            cblen = cur_cbs[b].truncRates[i];
900                        }
901                    }
902                    // Last truncation point length always sent
903
904                    // Calculate length
905                    cblen = cur_cbs[b].truncRates[i] - cblen;
906
907                    // Calculate number of bits
908                    prednbits = lblock[t][c][r][s][b] + MathUtil.log2(newtp);
909                    minbits = ((cblen>0) ? MathUtil.log2(cblen) : 0)+1;
910                    // Update Lblock increment if needed
911                    for(int j=prednbits; j<minbits; j++) {
912                        lblock[t][c][r][s][b]++;
913                        hbuf.writeBit(1);
914                    }
915
916                    // End of comma-code increment
917                    hbuf.writeBit(0);
918
919                    // There can be terminated several segments, send length
920                    // info for all terminated truncation points in addition
921                    // to final one
922                    newtp = 1;
923                    maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
924                    cblen = (cur_prevtIdxs[b]<0) ? 0 :
925                        cur_cbs[b].truncRates[cur_cbs[b].
926                                             truncIdxs[cur_prevtIdxs[b]]];
927                    // Loop on truncation points and count the groups
928                    i = (cur_prevtIdxs[b]<0) ? 0 :
929                        cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]+1;
930                    for (; i<maxi; i++, newtp++) {
931                        // If terminated truncation point, send length
932                        if (cur_cbs[b].isTermPass != null &&
933                            cur_cbs[b].isTermPass[i]) {
934
935                            cblen = cur_cbs[b].truncRates[i] - cblen;
936                            nbits = MathUtil.log2(newtp)+lblock[t][c][r][s][b];
937                            hbuf.writeBits(cblen,nbits);
938
939                            // Initialize for next length
940                            newtp = 0;
941                            cblen = cur_cbs[b].truncRates[i];
942                        }
943                    }
944                    // Last truncation point length is always signalled
945                    // First calculate number of bits needed to signal
946                    // Calculate length
947                    cblen = cur_cbs[b].truncRates[i] - cblen;
948                    nbits = MathUtil.log2(newtp) + lblock[t][c][r][s][b];
949                    hbuf.writeBits(cblen,nbits);
950
951                } // End loop on horizontal code-blocks
952            } // End loop on vertical code-blocks
953        } // End loop on subband
954
955        // -> Copy the data to the body buffer
956
957        // Ensure size for body data
958        if (bbuf==null || bbuf.length<lblen){
959            bbuf = new byte[lblen];
960        }
961        lbbuf = bbuf;
962        lblen = 0;
963
964        for (int s=minsb; s<maxsb; s++) { // Loop on subbands
965            sb = (SubbandAn)root.getSubbandByIdx(r,s);
966
967            cur_prevtIdxs = prevtIdxs[t][c][r][s];
968            cur_cbs = cbs[s];
969            cur_tIndx = tIndx[s];
970            ncb = cur_prevtIdxs.length;
971
972            mend = (prec.cblk[s]==null) ? 0 : prec.cblk[s].length;
973            for(int m=0; m<mend; m++) { // Vertical code-blocks
974                nend = (prec.cblk[s][m]==null) ? 0 : prec.cblk[s][m].length;
975                for (int n=0; n<nend; n++) { // Horiz. cblks
976                    cbCoord = prec.cblk[s][m][n].idx;
977                    b = cbCoord.x+cbCoord.y*sb.numCb.x;
978
979                    if (cur_tIndx[b]>cur_prevtIdxs[b]) {
980
981                        // Block included in this precinct -> Copy data to
982                        // body buffer and get code-size
983                        if (cur_prevtIdxs[b]<0) {
984                            cblen = cur_cbs[b].
985                                truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
986                            System.arraycopy(cur_cbs[b].data,0,
987                                             lbbuf,lblen,cblen);
988                        } else {
989                            cblen = cur_cbs[b].
990                                truncRates[cur_cbs[b].
991                                          truncIdxs[cur_tIndx[b]]] -
992                                cur_cbs[b].
993                                truncRates[cur_cbs[b].
994                                          truncIdxs[cur_prevtIdxs[b]]];
995                            System.
996                                arraycopy(cur_cbs[b].data,
997                                          cur_cbs[b].
998                                          truncRates[cur_cbs[b].
999                                                    truncIdxs[cur_prevtIdxs
1000                                                             [b]]],
1001                                          lbbuf,lblen,cblen);
1002                        }
1003                        lblen += cblen;
1004
1005                        // Verifies if this code-block contains new ROI
1006                        // information
1007                        if(cur_cbs[b].nROIcoeff!=0 &&
1008                           (cur_prevtIdxs[b]==-1 ||
1009                            cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] <=
1010                            cur_cbs[b].nROIcp-1) ) {
1011                            roiInPkt = true;
1012                            roiLen = lblen;
1013                        }
1014
1015                        // Update truncation point
1016                        cur_prevtIdxs[b] = cur_tIndx[b];
1017                    }
1018                } // End loop on horizontal code-blocks
1019            } // End loop on vertical code-blocks
1020        } // End loop on subbands
1021
1022        packetWritable = true;
1023
1024        // Must never happen
1025        if(hbuf.getLength()==0) {
1026            throw new Error("You have found a bug in PktEncoder, method:"+
1027                            " encodePacket");
1028        }
1029
1030        return hbuf;
1031    }
1032
1033    /**
1034     * Returns the buffer of the body of the last encoded packet. The length
1035     * of the body can be retrieved with the getLastBodyLen() method. The
1036     * length of the array returned by this method may be larger than the
1037     * actual body length.
1038     *
1039     * @return The buffer of body of the last encoded packet.
1040     *
1041     * @exception IllegalArgumentException If no packet has been coded since
1042     * last reset(), last restore(), or object creation.
1043     *
1044     * @see #getLastBodyLen
1045     * */
1046    public byte[] getLastBodyBuf() {
1047        if (lbbuf == null) {
1048            throw new IllegalArgumentException();
1049        }
1050        return lbbuf;
1051    }
1052
1053    /**
1054     * Returns the length of the body of the last encoded packet, in
1055     * bytes. The body itself can be retrieved with the getLastBodyBuf()
1056     * method.
1057     *
1058     * @return The length of the body of last encoded packet, in bytes.
1059     *
1060     * @see #getLastBodyBuf
1061     * */
1062    public int getLastBodyLen() {
1063        return lblen;
1064    }
1065
1066    /**
1067     * Saves the current state of this object. The last saved state
1068     * can be restored with the restore() method.
1069     *
1070     * @see #restore
1071     * */
1072    public void save() {
1073        int maxsbi,minsbi;
1074
1075        // Have we done any save yet?
1076        if (bak_lblock==null) {
1077            // Allocate backup buffers
1078            bak_lblock = new int[ttIncl.length][][][][];
1079            bak_prevtIdxs = new int[ttIncl.length][][][][];
1080            for (int t=ttIncl.length-1; t>=0; t--) {
1081                bak_lblock[t] = new int[ttIncl[t].length][][][];
1082                bak_prevtIdxs[t] = new int[ttIncl[t].length][][][];
1083                for (int c=ttIncl[t].length-1; c>=0; c--) {
1084                    bak_lblock[t][c] = new int[lblock[t][c].length][][];
1085                    bak_prevtIdxs[t][c] = new int[ttIncl[t][c].length][][];
1086                    for (int r=lblock[t][c].length-1; r>=0; r--) {
1087                        bak_lblock[t][c][r] =
1088                            new int[lblock[t][c][r].length][];
1089                        bak_prevtIdxs[t][c][r] =
1090                            new int[prevtIdxs[t][c][r].length][];
1091                        minsbi = (r==0) ? 0 : 1;
1092                        maxsbi = (r==0) ? 1 : 4;
1093                        for (int s=minsbi; s<maxsbi; s++) {
1094                            bak_lblock[t][c][r][s] =
1095                                new int[lblock[t][c][r][s].length];
1096                            bak_prevtIdxs[t][c][r][s] =
1097                                new int[prevtIdxs[t][c][r][s].length];
1098                        }
1099                    }
1100                }
1101            }
1102        }
1103
1104        //-- Save the data
1105
1106        // Use reference caches to minimize array access overhead
1107        TagTreeEncoder
1108            ttIncl_t_c[][][],
1109            ttMaxBP_t_c[][][],
1110            ttIncl_t_c_r[][],
1111            ttMaxBP_t_c_r[][];
1112        int
1113            lblock_t_c[][][],
1114            bak_lblock_t_c[][][],
1115            prevtIdxs_t_c_r[][],
1116            bak_prevtIdxs_t_c_r[][];
1117
1118        // Loop on tiles
1119        for (int t=ttIncl.length-1; t>=0; t--) {
1120            // Loop on components
1121            for (int c=ttIncl[t].length-1; c>=0; c--) {
1122                // Initialize reference caches
1123                lblock_t_c = lblock[t][c];
1124                bak_lblock_t_c = bak_lblock[t][c];
1125                ttIncl_t_c = ttIncl[t][c];
1126                ttMaxBP_t_c = ttMaxBP[t][c];
1127                // Loop on resolution levels
1128                for (int r=lblock_t_c.length-1; r>=0; r--) {
1129                    // Initialize reference caches
1130                    ttIncl_t_c_r = ttIncl_t_c[r];
1131                    ttMaxBP_t_c_r = ttMaxBP_t_c[r];
1132                    prevtIdxs_t_c_r = prevtIdxs[t][c][r];
1133                    bak_prevtIdxs_t_c_r = bak_prevtIdxs[t][c][r];
1134
1135                    // Loop on subbands
1136                    minsbi = (r==0) ? 0 : 1;
1137                    maxsbi = (r==0) ? 1 : 4;
1138                    for (int s=minsbi; s<maxsbi; s++) {
1139                        // Save 'lblock'
1140                        System.arraycopy(lblock_t_c[r][s],0,
1141                                         bak_lblock_t_c[r][s],0,
1142                                         lblock_t_c[r][s].length);
1143                        // Save 'prevtIdxs'
1144                        System.arraycopy(prevtIdxs_t_c_r[s],0,
1145                                         bak_prevtIdxs_t_c_r[s],0,
1146                                         prevtIdxs_t_c_r[s].length);
1147                    } // End loop on subbands
1148
1149                    // Loop on precincts
1150                    for(int p=ppinfo[t][c][r].length-1; p>=0; p--) {
1151                        if(p<ttIncl_t_c_r.length) {
1152                            // Loop on subbands
1153                            for(int s=minsbi; s<maxsbi; s++) {
1154                                ttIncl_t_c_r[p][s].save();
1155                                ttMaxBP_t_c_r[p][s].save();
1156                            } // End loop on subbands
1157                        }
1158                    } // End loop on precincts
1159                } // End loop on resolutions
1160            } // End loop on components
1161        } // End loop on tiles
1162
1163        // Set the saved state
1164        saved = true;
1165    }
1166
1167
1168    /**
1169     * Restores the last saved state of this object. An
1170     * IllegalArgumentException is thrown if no state has been saved.
1171     *
1172     * @see #save
1173     * */
1174    public void restore() {
1175        int maxsbi,minsbi;
1176
1177        if (!saved) {
1178            throw new IllegalArgumentException();
1179        }
1180
1181        // Invalidate last encoded body buffer
1182        lbbuf = null;
1183
1184        //-- Restore tha data
1185
1186        // Use reference caches to minimize array access overhead
1187        TagTreeEncoder ttIncl_t_c[][][],ttMaxBP_t_c[][][],ttIncl_t_c_r[][],
1188            ttMaxBP_t_c_r[][];
1189        int lblock_t_c[][][],bak_lblock_t_c[][][],prevtIdxs_t_c_r[][],
1190            bak_prevtIdxs_t_c_r[][];
1191
1192        // Loop on tiles
1193        for (int t=ttIncl.length-1; t>=0; t--) {
1194            // Loop on components
1195            for (int c=ttIncl[t].length-1; c>=0; c--) {
1196                // Initialize reference caches
1197                lblock_t_c = lblock[t][c];
1198                bak_lblock_t_c = bak_lblock[t][c];
1199                ttIncl_t_c = ttIncl[t][c];
1200                ttMaxBP_t_c = ttMaxBP[t][c];
1201                // Loop on resolution levels
1202                for (int r=lblock_t_c.length-1; r>=0; r--) {
1203                    // Initialize reference caches
1204                    ttIncl_t_c_r = ttIncl_t_c[r];
1205                    ttMaxBP_t_c_r = ttMaxBP_t_c[r];
1206                    prevtIdxs_t_c_r = prevtIdxs[t][c][r];
1207                    bak_prevtIdxs_t_c_r = bak_prevtIdxs[t][c][r];
1208
1209                    // Loop on subbands
1210                    minsbi = (r==0) ? 0 : 1;
1211                    maxsbi = (r==0) ? 1 : 4;
1212                    for (int s=minsbi; s<maxsbi; s++) {
1213                        // Restore 'lblock'
1214                        System.arraycopy(bak_lblock_t_c[r][s],0,
1215                                         lblock_t_c[r][s],0,
1216                                         lblock_t_c[r][s].length);
1217                        // Restore 'prevtIdxs'
1218                        System.arraycopy(bak_prevtIdxs_t_c_r[s],0,
1219                                         prevtIdxs_t_c_r[s],0,
1220                                         prevtIdxs_t_c_r[s].length);
1221                    } // End loop on subbands
1222
1223                    // Loop on precincts
1224                    for(int p=ppinfo[t][c][r].length-1; p>=0; p--) {
1225                        if(p<ttIncl_t_c_r.length) {
1226                            // Loop on subbands
1227                            for(int s=minsbi; s<maxsbi; s++) {
1228                                ttIncl_t_c_r[p][s].restore();
1229                                ttMaxBP_t_c_r[p][s].restore();
1230                            } // End loop on subbands
1231                        }
1232                    } // End loop on precincts
1233                } // End loop on resolution levels
1234            } // End loop on components
1235        } // End loop on tiles
1236    }
1237
1238    /**
1239     * Resets the state of the object to the initial state, as if the object
1240     * was just created.
1241     * */
1242    public void reset() {
1243        int maxsbi,minsbi;
1244
1245        // Invalidate save
1246        saved = false;
1247        // Invalidate last encoded body buffer
1248        lbbuf = null;
1249
1250        // Reinitialize each element in the arrays
1251
1252        // Use reference caches to minimize array access overhead
1253        TagTreeEncoder ttIncl_t_c[][][],ttMaxBP_t_c[][][],ttIncl_t_c_r[][],
1254            ttMaxBP_t_c_r[][];
1255        int lblock_t_c[][][],prevtIdxs_t_c_r[][];
1256
1257        // Loop on tiles
1258        for (int t=ttIncl.length-1; t>=0; t--) {
1259            // Loop on components
1260            for (int c=ttIncl[t].length-1; c>=0; c--) {
1261                // Initialize reference caches
1262                lblock_t_c = lblock[t][c];
1263                ttIncl_t_c = ttIncl[t][c];
1264                ttMaxBP_t_c = ttMaxBP[t][c];
1265                // Loop on resolution levels
1266                for (int r=lblock_t_c.length-1; r>=0; r--) {
1267                    // Initialize reference caches
1268                    ttIncl_t_c_r = ttIncl_t_c[r];
1269                    ttMaxBP_t_c_r = ttMaxBP_t_c[r];
1270                    prevtIdxs_t_c_r = prevtIdxs[t][c][r];
1271
1272                    // Loop on subbands
1273                    minsbi = (r==0) ? 0 : 1;
1274                    maxsbi = (r==0) ? 1 : 4;
1275                    for (int s=minsbi; s<maxsbi; s++) {
1276                        // Reset 'prevtIdxs'
1277                        ArrayUtil.intArraySet(prevtIdxs_t_c_r[s],-1);
1278                        // Reset 'lblock'
1279                        ArrayUtil.intArraySet(lblock_t_c[r][s],INIT_LBLOCK);
1280                    } // End loop on subbands
1281
1282                    // Loop on precincts
1283                    for(int p=ppinfo[t][c][r].length-1; p>=0; p--) {
1284                        if(p<ttIncl_t_c_r.length) {
1285                            // Loop on subbands
1286                            for(int s=minsbi; s<maxsbi; s++) {
1287                                ttIncl_t_c_r[p][s].reset();
1288                                ttMaxBP_t_c_r[p][s].reset();
1289                            } // End loop on subbands
1290                        }
1291                    } // End loop on precincts
1292                } // End loop on resolution levels
1293            } // End loop on components
1294        } // End loop on tiles
1295    }
1296
1297    /**
1298     * Returns true if the current packet is writable i.e. should be written.
1299     * Returns false otherwise.
1300     * */
1301    public boolean isPacketWritable() {
1302        return packetWritable;
1303    }
1304
1305    /**
1306     * Tells if there was ROI information in the last written packet
1307     * */
1308    public boolean isROIinPkt(){
1309        return roiInPkt;
1310    }
1311
1312    /** Gives the length to read in current packet body to get all ROI
1313     * information */
1314    public int getROILen(){
1315        return roiLen;
1316    }
1317
1318    /**
1319     * Returns the parameters that are used in this class and implementing
1320     * classes. It returns a 2D String array. Each of the 1D arrays is for a
1321     * different option, and they have 3 elements. The first element is the
1322     * option name, the second one is the synopsis, the third one is a long
1323     * description of what the parameter is and the fourth is its default
1324     * value. The synopsis or description may be 'null', in which case it is
1325     * assumed that there is no synopsis or description of the option,
1326     * respectively. Null may be returned if no options are supported.
1327     *
1328     * @return the options name, their synopsis and their explanation,
1329     * or null if no options are supported.
1330     * */
1331    public static String[][] getParameterInfo() {
1332        return pinfo;
1333    }
1334
1335    /** 
1336     * Returns information about a given precinct
1337     * 
1338     * @param t Tile index.
1339     *
1340     * @param c Component index.
1341     *
1342     * @param r Resolution level index.
1343     *
1344     * @param p Precinct index
1345     * */
1346    public PrecInfo getPrecInfo(int t,int c,int r,int p) {
1347        return ppinfo[t][c][r][p];
1348    }
1349}