001/*
002 * $RCSfile: EBCOTRateAllocator.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:08 $
005 * $State: Exp $
006 *
007 * Class:                   EBCOTRateAllocator
008 *
009 * Description:             Generic interface for post-compression
010 *                          rate allocator.
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 * */
045package jj2000.j2k.entropy.encoder;
046import java.awt.Point;
047
048import jj2000.j2k.codestream.writer.*;
049import jj2000.j2k.wavelet.analysis.*;
050import jj2000.j2k.entropy.encoder.*;
051import jj2000.j2k.codestream.*;
052import jj2000.j2k.entropy.*;
053import jj2000.j2k.image.*;
054import jj2000.j2k.util.*;
055
056import java.util.Vector;
057import java.io.*;
058
059import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
060/**
061 * This implements the EBCOT post compression rate allocation algorithm. This
062 * algorithm finds the most suitable truncation points for the set of
063 * code-blocks, for each layer target bitrate. It works by first collecting
064 * the rate distortion info from all code-blocks, in all tiles and all
065 * components, and then running the rate-allocation on the whole image at
066 * once, for each layer.
067 *
068 * <P>This implementation also provides some timing features. They can be
069 * enabled by setting the 'DO_TIMING' constant of this class to true and
070 * recompiling. The timing uses the 'System.currentTimeMillis()' Java API
071 * call, which returns wall clock time, not the actual CPU time used. The
072 * timing results will be printed on the message output. Since the times
073 * reported are wall clock times and not CPU usage times they can not be added
074 * to find the total used time (i.e. some time might be counted in several
075 * places). When timing is disabled ('DO_TIMING' is false) there is no penalty
076 * if the compiler performs some basic optimizations. Even if not the penalty
077 * should be negligeable.
078 *
079 * @see PostCompRateAllocator
080 *
081 * @see CodedCBlkDataSrcEnc
082 *
083 * @see jj2000.j2k.codestream.writer.CodestreamWriter
084 * */
085public class EBCOTRateAllocator extends PostCompRateAllocator {
086
087    /** Whether to collect timing information or not: false. Used as a compile
088     * time directive. */
089    private final static boolean DO_TIMING = false;
090
091    /** The wall time for the initialization. */
092    private long initTime;
093
094    /** The wall time for the building of layers. */
095    private long buildTime;
096
097    /** The wall time for the writing of layers. */
098    private long writeTime;
099
100    /**
101     * 5D Array containing all the coded code-blocks:
102     *
103     * <ul>
104     * <li>1st index: tile index</li>
105     * <li>2nd index: component index</li>
106     * <li>3rd index: resolution level index</li>
107     * <li>4th index: subband index</li>
108     * <li>5th index: code-block index</li>
109     * </ul>
110     **/
111    private CBlkRateDistStats cblks[][][][][];
112
113    /**
114     * 6D Array containing the indices of the truncation points. It actually
115     * contains the index of the element in CBlkRateDistStats.truncIdxs that
116     * gives the real truncation point index.
117     *
118     * <ul>
119     * <li>1st index: tile index</li>
120     * <li>2nd index: layer index</li>
121     * <li>3rd index: component index</li>
122     * <li>4th index: resolution level index</li>
123     * <li>5th index: subband index</li>
124     * <li>6th index: code-block index</li>
125     * </ul>
126     **/
127    private int truncIdxs[][][][][][];
128
129    /**
130     * Maximum number of precincts :
131     *
132     * <ul>
133     * <li>1st dim: tile index.</li>
134     * <li>2nd dim: component index.</li>
135     * <li>3nd dim: resolution level index.</li>
136     * </ul>
137     */
138    private Point numPrec[][][];
139
140    /** Array containing the layers information. */
141    private EBCOTLayer layers[];
142
143    /** The log of 2, natural base */
144    private static final double LOG2 = Math.log(2);
145
146    /** The normalization offset for the R-D summary table */
147    private static final int RD_SUMMARY_OFF = 24;
148
149    /** The size of the summary table */
150    private static final int RD_SUMMARY_SIZE = 64;
151
152    /** The relative precision for float data. This is the relative tolerance
153     * up to which the layer slope thresholds are calculated. */
154    private static final float FLOAT_REL_PRECISION = 1e-4f;
155
156    /** The precision for float data type, in an absolute sense. Two float
157     * numbers are considered "equal" if they are within this precision. */
158    private static final float FLOAT_ABS_PRECISION = 1e-10f;
159
160    /**
161     * Minimum average size of a packet. If layer has less bytes than the this
162     * constant multiplied by number of packets in the layer, then the layer
163     * is skipped.
164     * */
165    private static final int MIN_AVG_PACKET_SZ = 32;
166
167    /**
168     * The R-D summary information collected from the coding of all
169     * code-blocks. For each entry it contains the accumulated length of all
170     * truncation points that have a slope not less than
171     * '2*(k-RD_SUMMARY_OFF)', where 'k' is the entry index.
172     *
173     * <P>Therefore, the length at entry 'k' is the total number of bytes of
174     * code-block data that would be obtained if the truncation slope was
175     * chosen as '2*(k-RD_SUMMARY_OFF)', without counting the overhead
176     * associated with the packet heads.
177     *
178     * <P>This summary is used to estimate the relation of the R-D slope to
179     * coded length, and to obtain absolute minimums on the slope given a
180     * length.
181     **/
182    private int RDSlopesRates[];
183
184    /** Packet encoder. */
185    private PktEncoder pktEnc;
186
187    /** The layer specifications */
188    private LayersInfo lyrSpec;
189
190    /** The maximum slope accross all code-blocks and truncation points. */
191    private float maxSlope;
192
193    /** The minimum slope accross all code-blocks and truncation points. */
194    private float minSlope;
195
196    /**
197     * Initializes the EBCOT rate allocator of entropy coded data. The layout
198     * of layers, and their bitrate constraints, is specified by the 'lyrs'
199     * parameter.
200     *
201     * @param src The source of entropy coded data.
202     *
203     * @param lyrs The layers layout specification.
204     *
205     * @param writer The bit stream writer.
206     *
207     * @see ProgressionType
208     * */
209    public EBCOTRateAllocator(CodedCBlkDataSrcEnc src, LayersInfo lyrs,
210                              CodestreamWriter writer,
211                              J2KImageWriteParamJava wp) {
212
213        super(src,lyrs.getTotNumLayers(),writer,wp);
214
215        int minsbi, maxsbi;
216        int i;
217        SubbandAn sb, sb2;
218        Point ncblks = null;
219
220        // If we do timing create necessary structures
221        if (DO_TIMING) {
222            // If we are timing make sure that 'finalize' gets called.
223            System.runFinalizersOnExit(true);
224            // The System.runFinalizersOnExit() method is deprecated in Java
225            // 1.2 since it can cause a deadlock in some cases. However, here
226            // we use it only for profiling purposes and is disabled in
227            // production code.
228            initTime = 0L;
229            buildTime = 0L;
230            writeTime = 0L;
231        }
232
233        // Save the layer specs
234        lyrSpec = lyrs;
235
236        //Initialize the size of the RD slope rates array
237        RDSlopesRates = new int[RD_SUMMARY_SIZE];
238
239        //Get number of tiles, components
240        int nt = src.getNumTiles();
241        int nc = getNumComps();
242
243        //Allocate the coded code-blocks and truncation points indexes arrays
244        cblks = new CBlkRateDistStats[nt][nc][][][];
245        truncIdxs = new int[nt][numLayers][nc][][][];
246
247        int cblkPerSubband; // Number of code-blocks per subband
248        int mrl; // Number of resolution levels
249        int l; // layer index
250        int s; //subband index
251
252        // Used to compute the maximum number of precincts for each resolution
253        // level
254        int tx0, ty0, tx1, ty1; // Current tile position in the reference grid
255        int tcx0, tcy0, tcx1, tcy1; // Current tile position in the domain of
256        // the image component
257        int trx0, try0, trx1, try1; // Current tile position in the reduced
258        // resolution image domain
259        int xrsiz, yrsiz; // Component sub-sampling factors
260        Point tileI = null;
261        Point nTiles = null;
262        int xsiz,ysiz,x0siz,y0siz;
263        int xt0siz,yt0siz;
264        int xtsiz,ytsiz;
265    
266        int cb0x = src.getCbULX();
267        int cb0y = src.getCbULY();
268    
269        src.setTile(0,0);
270        for (int t=0; t<nt; t++) { // Loop on tiles
271            nTiles = src.getNumTiles(nTiles);
272            tileI = src.getTile(tileI);
273            x0siz = getImgULX();
274            y0siz = getImgULY();
275            xsiz = x0siz + getImgWidth();
276            ysiz = y0siz + getImgHeight();
277            xt0siz = src.getTilePartULX();
278            yt0siz = src.getTilePartULY();
279            xtsiz = src.getNomTileWidth();
280            ytsiz = src.getNomTileHeight();
281
282            // Tile's coordinates on the reference grid
283            tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
284            ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
285            tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
286            ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
287
288            for(int c=0; c<nc; c++) { // loop on components
289
290                //Get the number of resolution levels
291                sb = src.getAnSubbandTree(t,c);
292                mrl = sb.resLvl+1;
293
294                // Initialize maximum number of precincts per resolution array
295                if (numPrec==null) { numPrec = new Point[nt][nc][]; }
296                if (numPrec[t][c]==null) {
297                    numPrec[t][c] = new Point[mrl];
298                }
299
300                // Subsampling factors
301                xrsiz = src.getCompSubsX(c);
302                yrsiz = src.getCompSubsY(c);
303
304                // Tile's coordinates in the image component domain
305                tcx0 = (int)Math.ceil(tx0/(double)(xrsiz));
306                tcy0 = (int)Math.ceil(ty0/(double)(yrsiz));
307                tcx1 = (int)Math.ceil(tx1/(double)(xrsiz));
308                tcy1 = (int)Math.ceil(ty1/(double)(yrsiz));
309
310                cblks[t][c] = new CBlkRateDistStats[mrl][][];
311
312                for(l=0; l<numLayers; l++) {
313                    truncIdxs[t][l][c] = new int[mrl][][];
314                }
315
316                for(int r=0; r<mrl; r++) { // loop on resolution levels
317
318                    // Tile's coordinates in the reduced resolution image
319                    // domain
320                    trx0 = (int)Math.ceil(tcx0/(double)(1<<(mrl-1-r)));
321                    try0 = (int)Math.ceil(tcy0/(double)(1<<(mrl-1-r)));
322                    trx1 = (int)Math.ceil(tcx1/(double)(1<<(mrl-1-r)));
323                    try1 = (int)Math.ceil(tcy1/(double)(1<<(mrl-1-r)));
324
325                    // Calculate the maximum number of precincts for each
326                    // resolution level taking into account tile specific
327                    // options.
328                    double twoppx = (double)wp.getPrecinctPartition().getPPX(t,c,r);
329                    double twoppy = (double)wp.getPrecinctPartition().getPPY(t,c,r);
330                    numPrec[t][c][r] = new Point();
331                    if (trx1>trx0) {
332                        numPrec[t][c][r].x = (int)Math.ceil((trx1-cb0x)/twoppx)
333                            - (int)Math.floor((trx0-cb0x)/twoppx);
334                    } else {
335                        numPrec[t][c][r].x = 0;
336                    }
337                    if (try1>try0) {
338                        numPrec[t][c][r].y = (int)Math.ceil((try1-cb0y)/twoppy)
339                            - (int)Math.floor((try0-cb0y)/(double)twoppy);
340                    } else {
341                        numPrec[t][c][r].y = 0;
342                    }
343
344                    minsbi = (r==0) ? 0 : 1;
345                    maxsbi = (r==0) ? 1 : 4;
346
347                    cblks[t][c][r] = new CBlkRateDistStats[maxsbi][];
348                    for(l=0; l<numLayers; l++) {
349                        truncIdxs[t][l][c][r] = new int[maxsbi][];
350                    }
351
352                    for(s=minsbi; s<maxsbi; s++) { // loop on subbands
353                        //Get the number of blocks in the current subband
354                        sb2 = (SubbandAn)sb.getSubbandByIdx(r,s);
355                        ncblks = sb2.numCb;
356                        cblkPerSubband = ncblks.x*ncblks.y;
357                        cblks[t][c][r][s] =
358                            new CBlkRateDistStats[cblkPerSubband];
359
360                        for(l=0; l<numLayers; l++) {
361                            truncIdxs[t][l][c][r][s] = new int[cblkPerSubband];
362                            for(i=0; i<cblkPerSubband; i++) {
363                                truncIdxs[t][l][c][r][s][i] = -1;
364                            }
365                        }
366                    } // End loop on subbands
367                } // End lopp on resolution levels
368            } // End loop on components
369            if (t!=nt-1) {
370                src.nextTile();
371            }
372        } // End loop on tiles
373
374        //Initialize the packet encoder
375        pktEnc = new PktEncoder(src,wp,numPrec);
376
377        // The layers array has to be initialized after the constructor since
378        // it is needed that the bit stream header has been entirely written
379    }
380
381    /**
382     * Prints the timing information, if collected, and calls 'finalize' on
383     * the super class.
384     * */
385    public void finalize() throws Throwable {
386        if (DO_TIMING) {
387            StringBuffer sb;
388
389            sb = new StringBuffer("EBCOTRateAllocator wall clock times:\n");
390            sb.append("  initialization: ");
391            sb.append(initTime);
392            sb.append(" ms\n");
393            sb.append("  layer building: ");
394            sb.append(buildTime);
395            sb.append(" ms\n");
396            sb.append("  final writing:  ");
397            sb.append(writeTime);
398            sb.append(" ms");
399            FacilityManager.getMsgLogger().
400                printmsg(MsgLogger.INFO,sb.toString());
401        }
402        super.finalize();
403    }
404
405    /**
406     * Runs the rate allocation algorithm and writes the data to the bit
407     * stream writer object provided to the constructor.
408     * */
409    public void runAndWrite() throws IOException {
410        //Now, run the rate allocation
411        buildAndWriteLayers();
412    }
413
414    /**
415     * Initializes the layers array. This must be called after the main header
416     * has been entirely written or simulated, so as to take its overhead into
417     * account. This method will get all the code-blocks and then initialize
418     * the target bitrates for each layer, according to the specifications.
419     * */
420    public void initialize() throws IOException{
421        int n,i,l;
422        int ho; // The header overhead (in bytes)
423        float np;// The number of pixels divided by the number of bits per byte
424        double ls; // Step for log-scale
425        double basebytes;
426        int lastbytes,newbytes,nextbytes;
427        int loopnlyrs;
428        int minlsz; // The minimum allowable number of bytes in a layer
429        int totenclength;
430        int maxpkt;
431        int numTiles  = src.getNumTiles();
432        int numComps  = src.getNumComps();
433        int numLvls;
434        int avgPktLen;
435
436        long stime = 0L;
437
438        // Start by getting all the code-blocks, we need this in order to have
439        // an idea of the total encoded bitrate.
440        getAllCodeBlocks();
441
442        if (DO_TIMING) stime = System.currentTimeMillis();
443
444        // Now get the total encoded length
445        totenclength = RDSlopesRates[0]; // all the encoded data
446        // Make a rough estimation of the packet head overhead, as 2 bytes per
447        // packet in average (plus EPH / SOP) , and add that to the total
448        // encoded length
449        for( int t=0 ; t<numTiles ; t++ ){
450            avgPktLen = 2;
451            // Add SOP length if set
452            if (((String)wp.getSOP().getTileDef(t)).equalsIgnoreCase("true")) {
453                avgPktLen += Markers.SOP_LENGTH;
454            }
455            // Add EPH length if set
456            if (((String)wp.getEPH().getTileDef(t)).equalsIgnoreCase("true")) {
457                avgPktLen += Markers.EPH_LENGTH;
458            }
459
460            for( int c=0 ; c<numComps ; c++ ){
461                numLvls   = src.getAnSubbandTree(t,c).resLvl+1;
462                if( !src.precinctPartitionUsed(c,t) ) {
463                    // Precinct partition is not used so there is only
464                    // one packet per resolution level/layer
465                    totenclength += numLayers*avgPktLen*numLvls;
466                }
467                else {
468                    // Precinct partition is used so for each
469                    // component/tile/resolution level, we get the maximum
470                    // number of packets
471                    for ( int rl=0 ; rl<numLvls ; rl++ ) {
472                        maxpkt = numPrec[t][c][rl].x * numPrec[t][c][rl].y;
473                        totenclength += numLayers*avgPktLen*maxpkt;
474                    }
475                }
476            } // End loop on components
477        } // End loop on tiles
478
479        // If any layer specifies more than 'totenclength' as its target
480        // length then 'totenclength' is used. This is to prevent that
481        // estimated layers get excessively large target lengths due to an
482        // excessively large target bitrate. At the end the last layer is set
483        // to the target length corresponding to the overall target
484        // bitrate. Thus, 'totenclength' can not limit the total amount of
485        // encoded data, as intended.
486
487        ho = headEnc.getLength();
488        np = src.getImgWidth()*src.getImgHeight()/8f;
489
490        // SOT marker must be taken into account
491        for(int t=0; t<numTiles; t++){
492            headEnc.reset();
493            headEnc.encodeTilePartHeader(0,t);
494            ho += headEnc.getLength();
495        }
496
497        layers = new EBCOTLayer[numLayers];
498        for (n = numLayers-1; n>=0; n--) {
499            layers[n] = new EBCOTLayer();
500        }
501
502        minlsz = 0; // To keep compiler happy
503        for( int t=0 ; t<numTiles ; t++ ){
504            for( int c=0 ; c<numComps ; c++ ){
505                numLvls   = src.getAnSubbandTree(t,c).resLvl+1;
506
507                if ( !src.precinctPartitionUsed(c,t) ) {
508                    // Precinct partition is not used
509                    minlsz += MIN_AVG_PACKET_SZ*numLvls;
510                }
511                else {
512                    // Precinct partition is used
513                    for ( int rl=0 ; rl<numLvls ; rl++ ) {
514                        maxpkt = numPrec[t][c][rl].x * numPrec[t][c][rl].y;
515                        minlsz += MIN_AVG_PACKET_SZ*maxpkt;
516                    }
517                }
518            } // End loop on components
519        } // End loop on tiles
520
521        // Initialize layers
522        n = 0;
523        i = 0;
524        lastbytes = 0;
525
526        while (n < numLayers-1) {
527            // At an optimized layer
528            basebytes = Math.floor(lyrSpec.getTargetBitrate(i)*np);
529            if (i < lyrSpec.getNOptPoints()-1) {
530                nextbytes = (int) (lyrSpec.getTargetBitrate(i+1)*np);
531                // Limit target length to 'totenclength'
532                if (nextbytes > totenclength)
533                    nextbytes = totenclength;
534            }
535            else {
536                nextbytes = 1;
537            }
538            loopnlyrs = lyrSpec.getExtraLayers(i)+1;
539            ls = Math.exp(Math.log((double)nextbytes/basebytes)/loopnlyrs);
540            layers[n].optimize = true;
541            for (l = 0; l < loopnlyrs; l++) {
542                newbytes = (int)basebytes - lastbytes - ho;
543                if (newbytes < minlsz) {  // Skip layer (too small)
544                    basebytes *= ls;
545                    numLayers--;
546                    continue;
547                }
548                lastbytes = (int)basebytes - ho;
549                layers[n].maxBytes = lastbytes;
550                basebytes *= ls;
551                n++;
552            }
553            i++; // Goto next optimization point
554        }
555
556        // Ensure minimum size of last layer (this one determines overall
557        // bitrate)
558        n = numLayers-2;
559        nextbytes = (int) (lyrSpec.getTotBitrate()*np) - ho;
560        newbytes = nextbytes - ((n>=0) ? layers[n].maxBytes : 0);
561        while (newbytes < minlsz) {
562            if (numLayers == 1) {
563                if (newbytes <= 0) {
564                    throw new
565                        IllegalArgumentException("Overall target bitrate too "+
566                                                 "low, given the current "+
567                                                 "bit stream header overhead");
568                }
569                break;
570            }
571            // Delete last layer
572            numLayers--;
573            n--;
574            newbytes = nextbytes - ((n>=0) ? layers[n].maxBytes : 0);
575        }
576        // Set last layer to the overall target bitrate
577        n++;
578        layers[n].maxBytes = nextbytes;
579        layers[n].optimize = true;
580
581        // Re-initialize progression order changes if needed Default values
582        Progression[] prog1,prog2;
583        prog1 = (Progression[])wp.getProgressionType().getDefault();
584        int nValidProg = prog1.length;
585        for(int prg=0; prg<prog1.length;prg++){
586            if(prog1[prg].lye>numLayers){
587                prog1[prg].lye = numLayers;
588            }
589        }
590        if(nValidProg==0)
591            throw new Error("Unable to initialize rate allocator: No "+
592                            "default progression type has been defined.");
593
594        // Tile specific values
595        for(int t=0; t<numTiles; t++){
596            if(wp.getProgressionType().isTileSpecified(t)){
597                prog1 = (Progression[])wp.getProgressionType().getTileDef(t);
598                nValidProg = prog1.length;
599                for(int prg=0; prg<prog1.length;prg++){
600                    if(prog1[prg].lye>numLayers){
601                        prog1[prg].lye = numLayers;
602                    }
603                }
604                if(nValidProg==0)
605                    throw new Error("Unable to initialize rate allocator: No "+
606                            "default progression type has been defined.");
607            }
608        } // End loop on tiles
609
610        if (DO_TIMING) initTime += System.currentTimeMillis()-stime;
611    }
612
613    /**
614     * This method gets all the coded code-blocks from the EBCOT entropy coder
615     * for every component and every tile. Each coded code-block is stored in
616     * a 5D array according to the component, the resolution level, the tile,
617     * the subband it belongs and its position in the subband.
618     *
619     * <P> For each code-block, the valid slopes are computed and converted
620     * into the mantissa-exponent representation.
621     * */
622    private void getAllCodeBlocks() {
623
624        int numComps, numTiles, numBytes;
625        int c, r, t, s, sidx, k;
626        int slope;
627        SubbandAn subb;
628        CBlkRateDistStats ccb = null;
629        Point ncblks = null;
630        int last_sidx;
631        float fslope;
632
633        long stime = 0L;
634
635        maxSlope = 0f;
636        minSlope = Float.MAX_VALUE;
637
638        //Get the number of components and tiles
639        numComps = src.getNumComps();
640        numTiles = src.getNumTiles();
641
642        SubbandAn root,sb;
643        int cblkToEncode = 0;
644        int nEncCblk = 0;
645        ProgressWatch pw = FacilityManager.getProgressWatch();
646
647        //Get all coded code-blocks Goto first tile
648        src.setTile(0,0);
649        for (t=0; t<numTiles; t++) { //loop on tiles
650            nEncCblk = 0;
651            cblkToEncode = 0;
652            for(c=0; c<numComps; c++) {
653                root = src.getAnSubbandTree(t,c);
654                for(r=0; r<=root.resLvl; r++) {
655                    if(r==0) {
656                        sb = (SubbandAn)root.getSubbandByIdx(0,0);
657                        if(sb!=null) cblkToEncode += sb.numCb.x*sb.numCb.y;
658                    } else {
659                        sb = (SubbandAn)root.getSubbandByIdx(r,1);
660                        if(sb!=null) cblkToEncode += sb.numCb.x*sb.numCb.y;
661                        sb = (SubbandAn)root.getSubbandByIdx(r,2);
662                        if(sb!=null) cblkToEncode += sb.numCb.x*sb.numCb.y;
663                        sb = (SubbandAn)root.getSubbandByIdx(r,3);
664                        if(sb!=null) cblkToEncode += sb.numCb.x*sb.numCb.y;
665                    }
666                }
667            }
668            if(pw!=null) {
669                pw.initProgressWatch(0,cblkToEncode,"Encoding tile "+t+"...");
670            }
671
672            for (c=0; c<numComps; c++) { //loop on components
673
674                //Get next coded code-block coordinates
675                while ( (ccb = src.getNextCodeBlock(c,ccb)) != null) {
676                    if (DO_TIMING) stime = System.currentTimeMillis();
677
678                    if(pw!=null) {
679                        nEncCblk++;
680                        pw.updateProgressWatch(nEncCblk,null);
681                    }
682
683                    subb = ccb.sb;
684
685                    //Get the coded code-block resolution level index
686                    r = subb.resLvl;
687
688                    //Get the coded code-block subband index
689                    s = subb.sbandIdx;
690
691                    //Get the number of blocks in the current subband
692                    ncblks = subb.numCb;
693
694                    // Add code-block contribution to summary R-D table
695                    // RDSlopesRates
696                    last_sidx = -1;
697                    for (k=ccb.nVldTrunc-1; k>=0; k--) {
698                        fslope = ccb.truncSlopes[k];
699                        if (fslope > maxSlope) maxSlope = fslope;
700                        if (fslope < minSlope) minSlope = fslope;
701                        sidx = getLimitedSIndexFromSlope(fslope);
702                        for (; sidx > last_sidx; sidx--) {
703                            RDSlopesRates[sidx] +=
704                                ccb.truncRates[ccb.truncIdxs[k]];
705                        }
706                        last_sidx = getLimitedSIndexFromSlope(fslope);
707                    }
708
709                    //Fills code-blocks array
710                    cblks[t][c][r][s][(ccb.m*ncblks.x)+ccb.n] = ccb;
711                    ccb = null;
712
713                    if(DO_TIMING) initTime += System.currentTimeMillis()-stime;
714                }
715            }
716
717            if(pw!=null) {
718                pw.terminateProgressWatch();
719            }
720
721            //Goto next tile
722            if(t<numTiles-1) //not at last tile
723                src.nextTile();
724        }
725    }
726
727    /**
728     * This method builds all the bit stream layers and then writes them to
729     * the output bit stream. Firstly it builds all the layers by computing
730     * the threshold according to the layer target bit-rate, and then it
731     * writes the layer bit streams according to the Progression type.
732     * */
733    private void buildAndWriteLayers() throws IOException {
734        int nPrec = 0;
735        int maxBytes, actualBytes;
736        float rdThreshold;
737        SubbandAn sb;
738        float threshold;
739        BitOutputBuffer hBuff = null;
740        byte[] bBuff = null;
741        int[] tileLengths; // Length of each tile
742        int tmp;
743        boolean sopUsed; // Should SOP markers be used ?
744        boolean ephUsed; // Should EPH markers be used ?
745        int nc = src.getNumComps();
746        int nt = src.getNumTiles();
747        int mrl;
748
749        long stime = 0L;
750
751        if (DO_TIMING) stime = System.currentTimeMillis();
752
753        // Start with the maximum slope
754        rdThreshold = maxSlope;
755
756        tileLengths = new int[nt];
757        actualBytes = 0;
758
759        // +------------------------------+
760        // |  First we build the layers   |
761        // +------------------------------+
762        // Bitstream is simulated to know tile length
763        for(int l=0; l<numLayers; l++){ //loop on layers
764
765            maxBytes = layers[l].maxBytes;
766            if(layers[l].optimize) {
767                rdThreshold =
768                    optimizeBitstreamLayer(l,rdThreshold,maxBytes,actualBytes);
769            } else {
770                if( l<=0 || l>=numLayers-1 ) {
771                    throw new IllegalArgumentException("The first and the"+
772                                                       " last layer "+
773                                                       "thresholds"+
774                                                       " must be optimized");
775                }
776                rdThreshold = estimateLayerThreshold(maxBytes,layers[l-1]);
777            }
778
779            for(int t=0; t<nt; t++) { //loop on tiles
780                if(l==0) {
781                    // Tile header
782                    headEnc.reset();
783                    headEnc.encodeTilePartHeader(0,t);
784                    tileLengths[t] += headEnc.getLength();
785                }
786
787                for(int c=0; c<nc; c++) { //loop on components
788
789                    // set boolean sopUsed here (SOP markers)
790                    sopUsed = ((String)wp.getSOP().getTileDef(t)).
791                        equalsIgnoreCase("true");
792                    // set boolean ephUsed here (EPH markers)
793                    ephUsed = ((String)wp.getEPH().getTileDef(t)).
794                        equalsIgnoreCase("true");
795
796                    // Go to LL band
797                    sb = src.getAnSubbandTree(t,c);
798                    mrl = sb.resLvl+1;
799
800                    while (sb.subb_LL!=null) {
801                        sb = sb.subb_LL;
802                    }
803
804                    for(int r=0; r<mrl ; r++) { // loop on resolution levels
805
806                        nPrec = numPrec[t][c][r].x*numPrec[t][c][r].y;
807                        for(int p=0; p<nPrec; p++) { // loop on precincts
808
809                            findTruncIndices(l,c,r,t,sb,rdThreshold,p);
810
811                            hBuff =
812                                pktEnc.encodePacket(l+1,c,r,t,
813                                                    cblks[t][c][r],
814                                                    truncIdxs[t][l][c][r],
815                                                    hBuff, bBuff,p);
816                            if(pktEnc.isPacketWritable()) {
817                                tmp = bsWriter.
818                                    writePacketHead(hBuff.getBuffer(),
819                                                    hBuff.getLength(),
820                                                    true, sopUsed,ephUsed);
821                                tmp += bsWriter.
822                                    writePacketBody(pktEnc.getLastBodyBuf(),
823                                                    pktEnc.getLastBodyLen(),
824                                                    true,pktEnc.isROIinPkt(),
825                                                    pktEnc.getROILen());
826                                actualBytes += tmp;
827                                tileLengths[t] += tmp;
828                            }
829                        } // End loop on precincts
830                        sb = sb.parent;
831                    } // End loop on resolution levels
832                } // End loop on components
833            } // end loop on tiles
834            layers[l].rdThreshold = rdThreshold;
835            layers[l].actualBytes = actualBytes;
836        } // end loop on layers
837
838        if (DO_TIMING) buildTime += System.currentTimeMillis()-stime;
839
840        // The bit-stream was not yet generated (only simulated).
841
842        if (DO_TIMING) stime = System.currentTimeMillis();
843
844        // +--------------------------------------------------+
845        // | Write tiles according to their Progression order |
846        // +--------------------------------------------------+
847        // Reset the packet encoder before writing all packets
848        pktEnc.reset();
849        Progression[] prog; // Progression(s) in each tile
850        int cs,ce,rs,re,lye;
851
852        int[] mrlc = new int[nc];
853        for(int t=0; t<nt; t++) { //loop on tiles
854            int[][] lysA; // layer index start for each component and
855            // resolution level
856            int[][] lys = new int[nc][];
857            for(int c=0; c<nc; c++){
858                mrlc[c] = src.getAnSubbandTree(t,c).resLvl;
859                lys[c] = new int[mrlc[c]+1];
860            }
861
862            // Tile header
863            headEnc.reset();
864            headEnc.encodeTilePartHeader(tileLengths[t],t);
865            bsWriter.commitBitstreamHeader(headEnc);
866            prog = (Progression[])wp.getProgressionType().getTileDef(t);
867
868            for(int prg=0; prg<prog.length;prg++){ // Loop on progression
869                lye = prog[prg].lye;
870                cs = prog[prg].cs;
871                ce = prog[prg].ce;
872                rs = prog[prg].rs;
873                re = prog[prg].re;
874
875                switch(prog[prg].type){
876                case ProgressionType.RES_LY_COMP_POS_PROG:
877                    writeResLyCompPos(t,rs,re,cs,ce,lys,lye);
878                    break;
879                case ProgressionType.LY_RES_COMP_POS_PROG:
880                    writeLyResCompPos(t,rs,re,cs,ce,lys,lye);
881                    break;
882                case ProgressionType.POS_COMP_RES_LY_PROG:
883                    writePosCompResLy(t,rs,re,cs,ce,lys,lye);
884                    break;
885                case ProgressionType.COMP_POS_RES_LY_PROG:
886                    writeCompPosResLy(t,rs,re,cs,ce,lys,lye);
887                    break;
888                case ProgressionType.RES_POS_COMP_LY_PROG:
889                    writeResPosCompLy(t,rs,re,cs,ce,lys,lye);
890                    break;
891                default:
892                    throw new Error("Unsupported bit stream progression type");
893                } // switch on progression
894
895                // Update next first layer index 
896                for(int c=cs; c<ce; c++)
897                    for(int r=rs; r<re; r++){
898                        if(r>mrlc[c]) continue;
899                        lys[c][r] = lye;
900                    }
901            } // End loop on progression
902        } // End loop on tiles
903
904        if (DO_TIMING) writeTime += System.currentTimeMillis()-stime;
905    }
906
907    /** 
908     * Write a piece of bit stream according to the
909     * RES_LY_COMP_POS_PROG progression mode and between given bounds
910     *
911     * @param t Tile index.
912     *
913     * @param rs First resolution level index.
914     *
915     * @param re Last resolution level index.
916     *
917     * @param cs First component index.
918     *
919     * @param ce Last component index.
920     *
921     * @param lys First layer index for each component and resolution.
922     *
923     * @param lye Index of the last layer.
924     * */
925    public void writeResLyCompPos(int t,int rs,int re,int cs,int ce,
926                                  int lys[][],int lye) throws IOException {
927
928        boolean sopUsed; // Should SOP markers be used ?
929        boolean ephUsed; // Should EPH markers be used ?
930        int nc = src.getNumComps();
931        int[] mrl = new int[nc];
932        SubbandAn sb;
933        float threshold;
934        BitOutputBuffer hBuff = null;
935        byte[] bBuff = null;
936        int nPrec = 0;
937
938        // Max number of resolution levels in the tile
939        int maxResLvl = 0;
940        for(int c=0; c<nc; c++) {
941            mrl[c] = src.getAnSubbandTree(t,c).resLvl;
942            if(mrl[c]>maxResLvl) maxResLvl = mrl[c];
943        }
944
945        int minlys; // minimum layer start index of each component
946
947        for(int r=rs; r<re; r++) { //loop on resolution levels
948            if(r>maxResLvl) continue;
949
950            minlys = 100000;
951            for(int c=cs; c<ce; c++) {
952                if( r<lys[c].length && lys[c][r]<minlys ) {
953                    minlys = lys[c][r];
954                }
955            }
956
957            for(int l=minlys; l<lye; l++) { //loop on layers
958                for(int c=cs; c<ce; c++) {//loop on components
959                    if(r>=lys[c].length) continue;
960                    if(l<lys[c][r]) continue;
961
962                    // If no more decomposition levels for this component
963                    if(r>mrl[c]) continue;
964
965                    nPrec = numPrec[t][c][r].x*numPrec[t][c][r].y;
966                    for(int p=0; p<nPrec; p++) { // loop on precincts
967
968                        // set boolean sopUsed here (SOP markers)
969                        sopUsed = ((String)wp.getSOP().getTileDef(t)).equals("true");
970                        // set boolean ephUsed here (EPH markers)
971                        ephUsed = ((String)wp.getEPH().getTileDef(t)).equals("true");
972
973                        sb = src.getAnSubbandTree(t,c);
974                        for(int i=mrl[c]; i>r; i--) {
975                            sb = sb.subb_LL;
976                        }
977
978                        threshold = layers[l].rdThreshold;
979                        findTruncIndices(l,c,r,t,sb,threshold,p);
980
981                        hBuff = pktEnc.encodePacket(l+1,c,r,t,cblks[t][c][r],
982                                                    truncIdxs[t][l][c][r],
983                                                    hBuff,bBuff,p);
984
985                        if(pktEnc.isPacketWritable()) {
986                            bsWriter.writePacketHead(hBuff.getBuffer(),
987                                                     hBuff.getLength(),
988                                                     false,sopUsed,ephUsed);
989                            bsWriter.writePacketBody(pktEnc.getLastBodyBuf(),
990                                                     pktEnc.getLastBodyLen(),
991                                                     false,pktEnc.isROIinPkt(),
992                                                     pktEnc.getROILen());
993                        }
994
995                    } // End loop on precincts
996                } // End loop on components
997            } // End loop on layers
998        } // End loop on resolution levels
999    }
1000
1001    /** 
1002     * Write a piece of bit stream according to the
1003     * LY_RES_COMP_POS_PROG progression mode and between given bounds
1004     *
1005     * @param t Tile index.
1006     *
1007     * @param rs First resolution level index.
1008     *
1009     * @param re Last resolution level index.
1010     *
1011     * @param cs First component index.
1012     *
1013     * @param ce Last component index.
1014     *
1015     * @param lys First layer index for each component and resolution.
1016     *
1017     * @param lye Index of the last layer.
1018     * */
1019    public void writeLyResCompPos(int t,int rs,int re,int cs,int ce,
1020                                  int[][] lys,int lye) throws IOException {
1021
1022        boolean sopUsed; // Should SOP markers be used ?
1023        boolean ephUsed; // Should EPH markers be used ?
1024        int nc = src.getNumComps();
1025        int mrl;
1026        SubbandAn sb;
1027        float threshold;
1028        BitOutputBuffer hBuff = null;
1029        byte[] bBuff = null;
1030        int nPrec = 0;
1031
1032        int minlys = 100000; // minimum layer start index of each component
1033        for(int c=cs; c<ce; c++) {
1034            for(int r=0; r<lys.length; r++) {
1035                if(lys[c]!=null && r<lys[c].length && lys[c][r]<minlys ) {
1036                    minlys = lys[c][r];
1037                }
1038            }
1039        }
1040
1041        for(int l=minlys; l<lye; l++) { // loop on layers
1042            for(int r=rs; r<re; r++) { // loop on resolution level
1043                for(int c=cs; c<ce; c++) { // loop on components
1044                    mrl = src.getAnSubbandTree(t,c).resLvl;
1045                    if(r>mrl) continue;
1046                    if(r>=lys[c].length) continue;
1047                    if(l<lys[c][r]) continue;
1048                    nPrec = numPrec[t][c][r].x*numPrec[t][c][r].y;
1049                    for(int p=0; p<nPrec; p++) { // loop on precincts
1050
1051                        // set boolean sopUsed here (SOP markers)
1052                        sopUsed = ((String)wp.getSOP().getTileDef(t)).equals("true");
1053                        // set boolean ephUsed here (EPH markers)
1054                        ephUsed = ((String)wp.getEPH().getTileDef(t)).equals("true");
1055
1056                        sb = src.getAnSubbandTree(t,c);
1057                        for(int i=mrl; i>r; i--) {
1058                            sb = sb.subb_LL;
1059                        }
1060
1061                        threshold = layers[l].rdThreshold;
1062                        findTruncIndices(l,c,r,t,sb,threshold,p);
1063
1064                        hBuff = pktEnc.encodePacket(l+1,c,r,t,cblks[t][c][r],
1065                                                    truncIdxs[t][l][c][r],
1066                                                    hBuff,bBuff,p);
1067
1068                        if(pktEnc.isPacketWritable()) {
1069                            bsWriter.writePacketHead(hBuff.getBuffer(),
1070                                                     hBuff.getLength(),
1071                                                     false,sopUsed,ephUsed);
1072                            bsWriter.writePacketBody(pktEnc.getLastBodyBuf(),
1073                                                     pktEnc.getLastBodyLen(),
1074                                                     false,pktEnc.isROIinPkt(),
1075                                                     pktEnc.getROILen());
1076                        }
1077                    } // end loop on precincts
1078                } // end loop on components
1079            } // end loop on resolution levels
1080        } // end loop on layers
1081    }
1082
1083    /** 
1084     * Write a piece of bit stream according to the
1085     * COMP_POS_RES_LY_PROG progression mode and between given bounds
1086     *
1087     * @param t Tile index.
1088     *
1089     * @param rs First resolution level index.
1090     *
1091     * @param re Last resolution level index.
1092     *
1093     * @param cs First component index.
1094     *
1095     * @param ce Last component index.
1096     *
1097     * @param lys First layer index for each component and resolution.
1098     *
1099     * @param lye Index of the last layer.
1100     * */
1101    public void writePosCompResLy(int t,int rs,int re,int cs,int ce,
1102                                  int[][] lys,int lye) throws IOException {
1103
1104        boolean sopUsed; // Should SOP markers be used ?
1105        boolean ephUsed; // Should EPH markers be used ?
1106        int nc = src.getNumComps();
1107        int mrl;
1108        SubbandAn sb;
1109        float threshold;
1110        BitOutputBuffer hBuff = null;
1111        byte[] bBuff = null;
1112
1113        // Computes current tile offset in the reference grid
1114        Point nTiles = src.getNumTiles(null);
1115        Point tileI = src.getTile(null);
1116        int x0siz = src.getImgULX();
1117        int y0siz = src.getImgULY();
1118        int xsiz = x0siz + src.getImgWidth();
1119        int ysiz = y0siz + src.getImgHeight();
1120        int xt0siz = src.getTilePartULX();
1121        int yt0siz = src.getTilePartULY();
1122        int xtsiz = src.getNomTileWidth();
1123        int ytsiz = src.getNomTileHeight();
1124        int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
1125        int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
1126        int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
1127        int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
1128
1129        // Get precinct information (number,distance between two consecutive
1130        // precincts in the reference grid) in each component and resolution
1131        // level
1132        PrecInfo prec; // temporary variable
1133        int p; // Current precinct index
1134        int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1135        int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1136        int nPrec = 0; // Total number of found precincts
1137        int[][] nextPrec = new int [ce][]; // Next precinct index in each
1138        // component and resolution level
1139        int minlys = 100000; // minimum layer start index of each component
1140        int minx = tx1; // Horiz. offset of the second precinct in the
1141        // reference grid
1142        int miny = ty1; // Vert. offset of the second precinct in the
1143        // reference grid. 
1144        int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1145        int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1146        for(int c=cs; c<ce; c++) {
1147            mrl = src.getAnSubbandTree(t,c).resLvl;
1148            nextPrec[c] = new int[mrl+1];
1149            for(int r=rs; r<re; r++) {
1150                if(r>mrl) continue;
1151                if (r<lys[c].length && lys[c][r]<minlys) {
1152                    minlys = lys[c][r];
1153                }
1154                p = numPrec[t][c][r].y*numPrec[t][c][r].x-1;
1155                for(; p>=0; p--) {
1156                    prec = pktEnc.getPrecInfo(t,c,r,p);
1157                    if(prec.rgulx!=tx0) {
1158                        if(prec.rgulx<minx) minx = prec.rgulx;
1159                        if(prec.rgulx>maxx) maxx = prec.rgulx;
1160                    }
1161                    if(prec.rguly!=ty0){
1162                        if(prec.rguly<miny) miny = prec.rguly;
1163                        if(prec.rguly>maxy) maxy = prec.rguly;
1164                    }
1165
1166                    if(nPrec==0) {
1167                        gcd_x = prec.rgw;
1168                        gcd_y = prec.rgh;
1169                    } else {
1170                        gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
1171                        gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
1172                    }
1173                    nPrec++;
1174                } // precincts
1175            } // resolution levels
1176        } // components
1177        if(nPrec==0) {
1178            throw new Error("Image cannot have no precinct");
1179        }
1180
1181        int pyend = (maxy-miny)/gcd_y+1;
1182        int pxend = (maxx-minx)/gcd_x+1;
1183        int y = ty0;
1184        int x = tx0;
1185        for(int py=0; py<=pyend; py++) { // Vertical precincts
1186            for(int px=0; px<=pxend; px++) { // Horiz. precincts
1187                for(int c=cs; c<ce; c++) { // Components
1188                    mrl = src.getAnSubbandTree(t,c).resLvl;
1189                    for(int r=rs; r<re; r++) { // Resolution levels
1190                        if(r>mrl) continue;
1191                        if(nextPrec[c][r] >=
1192                           numPrec[t][c][r].x*numPrec[t][c][r].y) {
1193                            continue;
1194                        }
1195                        prec = pktEnc.getPrecInfo(t,c,r,nextPrec[c][r]);
1196                        if((prec.rgulx!=x) || (prec.rguly!=y)) {
1197                            continue;
1198                        }
1199                        for(int l=minlys; l<lye; l++) { // Layers
1200                            if(r>=lys[c].length) continue;
1201                            if(l<lys[c][r]) continue;
1202
1203                            // set boolean sopUsed here (SOP markers)
1204                            sopUsed = ((String)wp.getSOP().getTileDef(t)).equals("true");
1205                            // set boolean ephUsed here (EPH markers)
1206                            ephUsed = ((String)wp.getEPH().getTileDef(t)).equals("true");
1207
1208                            sb = src.getAnSubbandTree(t,c);
1209                            for(int i=mrl; i>r; i--) {
1210                                sb = sb.subb_LL;
1211                            }
1212
1213                            threshold = layers[l].rdThreshold;
1214                            findTruncIndices(l,c,r,t,sb,threshold,
1215                                             nextPrec[c][r]);
1216
1217
1218                            hBuff = pktEnc.encodePacket(l+1,c,r,t,
1219                                                        cblks[t][c][r],
1220                                                        truncIdxs[t][l][c][r],
1221                                                        hBuff,bBuff,
1222                                                        nextPrec[c][r]);
1223
1224                            if(pktEnc.isPacketWritable()) {
1225                                bsWriter.writePacketHead(hBuff.getBuffer(),
1226                                                         hBuff.getLength(),
1227                                                         false,sopUsed,
1228                                                         ephUsed);
1229                                bsWriter.writePacketBody(pktEnc.
1230                                                         getLastBodyBuf(),
1231                                                         pktEnc.
1232                                                         getLastBodyLen(),
1233                                                         false,
1234                                                         pktEnc.isROIinPkt(),
1235                                                         pktEnc.getROILen());
1236                            }
1237                        } // layers
1238                        nextPrec[c][r]++;
1239                    } // Resolution levels
1240                } // Components
1241                if(px!=pxend) {
1242                    x = minx+px*gcd_x;
1243                } else {
1244                    x = tx0;
1245                }
1246            } // Horizontal precincts
1247            if(py!=pyend) {
1248                y = miny+py*gcd_y;
1249            } else {
1250                y = ty0;
1251            }
1252        } // Vertical precincts
1253
1254        // Check that all precincts have been written
1255        for(int c=cs; c<ce; c++) {
1256            mrl = src.getAnSubbandTree(t,c).resLvl;
1257            for(int r=rs; r<re; r++) {
1258                if(r>mrl) continue;
1259                if(nextPrec[c][r]<numPrec[t][c][r].x*numPrec[t][c][r].y-1) {
1260                    throw new Error("JJ2000 bug: One precinct at least has "+
1261                                    "not been written for resolution level "+r
1262                                    +" of component "+c+" in tile "+t+".");
1263                }
1264            }
1265        }
1266    }
1267
1268    /** 
1269     * Write a piece of bit stream according to the
1270     * COMP_POS_RES_LY_PROG progression mode and between given bounds
1271     *
1272     * @param t Tile index.
1273     *
1274     * @param rs First resolution level index.
1275     *
1276     * @param re Last resolution level index.
1277     *
1278     * @param cs First component index.
1279     *
1280     * @param ce Last component index.
1281     *
1282     * @param lys First layer index for each component and resolution.
1283     *
1284     * @param lye Index of the last layer.
1285     * */
1286    public void writeCompPosResLy(int t,int rs,int re,int cs,int ce,
1287                                  int[][] lys,int lye) throws IOException {
1288
1289        boolean sopUsed; // Should SOP markers be used ?
1290        boolean ephUsed; // Should EPH markers be used ?
1291        int nc = src.getNumComps();
1292        int mrl;
1293        SubbandAn sb;
1294        float threshold;
1295        BitOutputBuffer hBuff = null;
1296        byte[] bBuff = null;
1297
1298        // Computes current tile offset in the reference grid
1299        Point nTiles = src.getNumTiles(null);
1300        Point tileI = src.getTile(null);
1301        int x0siz = src.getImgULX();
1302        int y0siz = src.getImgULY();
1303        int xsiz = x0siz + src.getImgWidth();
1304        int ysiz = y0siz + src.getImgHeight();
1305        int xt0siz = src.getTilePartULX();
1306        int yt0siz = src.getTilePartULY();
1307        int xtsiz = src.getNomTileWidth();
1308        int ytsiz = src.getNomTileHeight();
1309        int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
1310        int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
1311        int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
1312        int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
1313
1314        // Get precinct information (number,distance between two consecutive
1315        // precincts in the reference grid) in each component and resolution
1316        // level
1317        PrecInfo prec; // temporary variable
1318        int p; // Current precinct index
1319        int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1320        int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1321        int nPrec = 0; // Total number of found precincts
1322        int[][] nextPrec = new int [ce][]; // Next precinct index in each
1323        // component and resolution level
1324        int minlys = 100000; // minimum layer start index of each component
1325        int minx = tx1; // Horiz. offset of the second precinct in the
1326        // reference grid
1327        int miny = ty1; // Vert. offset of the second precinct in the
1328        // reference grid. 
1329        int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1330        int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1331        for(int c=cs; c<ce; c++) {
1332            mrl = src.getAnSubbandTree(t,c).resLvl;
1333            for(int r=rs; r<re; r++) {
1334                if(r>mrl) continue;
1335                nextPrec[c] = new int[mrl+1];
1336                if (r<lys[c].length && lys[c][r]<minlys) {
1337                    minlys = lys[c][r];
1338                }
1339                p = numPrec[t][c][r].y*numPrec[t][c][r].x-1;
1340                for(; p>=0; p--) {
1341                    prec = pktEnc.getPrecInfo(t,c,r,p);
1342                    if(prec.rgulx!=tx0) {
1343                        if(prec.rgulx<minx) minx = prec.rgulx;
1344                        if(prec.rgulx>maxx) maxx = prec.rgulx;
1345                    }
1346                    if(prec.rguly!=ty0){
1347                        if(prec.rguly<miny) miny = prec.rguly;
1348                        if(prec.rguly>maxy) maxy = prec.rguly;
1349                    }
1350
1351                    if(nPrec==0) {
1352                        gcd_x = prec.rgw;
1353                        gcd_y = prec.rgh;
1354                    } else {
1355                        gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
1356                        gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
1357                    }
1358                    nPrec++;
1359                } // precincts
1360            } // resolution levels
1361        } // components
1362        if(nPrec==0) {
1363            throw new Error("Image cannot have no precinct");
1364        }
1365
1366        int pyend = (maxy-miny)/gcd_y+1;
1367        int pxend = (maxx-minx)/gcd_x+1;
1368        int y;
1369        int x;
1370        for(int c=cs; c<ce; c++) { // Loop on components
1371            y = ty0;
1372            x = tx0;
1373            mrl = src.getAnSubbandTree(t,c).resLvl;
1374            for(int py=0; py<=pyend; py++) { // Vertical precincts
1375                for(int px=0; px<=pxend; px++) { // Horiz. precincts
1376                    for(int r=rs; r<re; r++) { // Resolution levels
1377                        if(r>mrl) continue;
1378                        if(nextPrec[c][r] >=
1379                           numPrec[t][c][r].x*numPrec[t][c][r].y) {
1380                            continue;
1381                        }
1382                        prec = pktEnc.getPrecInfo(t,c,r,nextPrec[c][r]);
1383                        if((prec.rgulx!=x) || (prec.rguly!=y)) {
1384                            continue;
1385                        }
1386
1387                        for(int l=minlys; l<lye; l++) { // Layers
1388                            if(r>=lys[c].length) continue;
1389                            if(l<lys[c][r]) continue;
1390
1391                            // set boolean sopUsed here (SOP markers)
1392                            sopUsed = ((String)wp.getSOP().getTileDef(t)).equals("true");
1393                            // set boolean ephUsed here (EPH markers)
1394                            ephUsed = ((String)wp.getEPH().getTileDef(t)).equals("true");
1395
1396                            sb = src.getAnSubbandTree(t,c);
1397                            for(int i=mrl; i>r; i--) {
1398                                sb = sb.subb_LL;
1399                            }
1400
1401                            threshold = layers[l].rdThreshold;
1402                            findTruncIndices(l,c,r,t,sb,threshold,
1403                                             nextPrec[c][r]);
1404
1405                            hBuff = pktEnc.encodePacket(l+1,c,r,t,
1406                                                        cblks[t][c][r],
1407                                                        truncIdxs[t][l][c][r],
1408                                                        hBuff,bBuff,
1409                                                        nextPrec[c][r]);
1410
1411                            if(pktEnc.isPacketWritable()) {
1412                                bsWriter.writePacketHead(hBuff.getBuffer(),
1413                                                         hBuff.getLength(),
1414                                                         false,sopUsed,
1415                                                         ephUsed);
1416                                bsWriter.writePacketBody(pktEnc.
1417                                                         getLastBodyBuf(),
1418                                                         pktEnc.
1419                                                         getLastBodyLen(),
1420                                                         false,
1421                                                         pktEnc.isROIinPkt(),
1422                                                         pktEnc.getROILen());
1423                            }
1424
1425                        } // Layers
1426                        nextPrec[c][r]++;
1427                    } // Resolution levels                    
1428                    if(px!=pxend) {
1429                        x = minx+px*gcd_x;
1430                    } else {
1431                        x = tx0;
1432                    }
1433                } // Horizontal precincts
1434                if(py!=pyend) {
1435                    y = miny+py*gcd_y;
1436                } else {
1437                    y = ty0;
1438                }
1439            } // Vertical precincts
1440        } // components
1441
1442        // Check that all precincts have been written
1443        for(int c=cs; c<ce; c++) {
1444            mrl = src.getAnSubbandTree(t,c).resLvl;
1445            for(int r=rs; r<re; r++) {
1446                if(r>mrl) continue;
1447                if(nextPrec[c][r]<numPrec[t][c][r].x*numPrec[t][c][r].y-1) {
1448                    throw new Error("JJ2000 bug: One precinct at least has "+
1449                                    "not been written for resolution level "+r
1450                                    +" of component "+c+" in tile "+t+".");
1451                }
1452            }
1453        }
1454    }
1455
1456    /** 
1457     * Write a piece of bit stream according to the
1458     * RES_POS_COMP_LY_PROG progression mode and between given bounds
1459     *
1460     * @param t Tile index.
1461     *
1462     * @param rs First resolution level index.
1463     *
1464     * @param re Last resolution level index.
1465     *
1466     * @param cs First component index.
1467     *
1468     * @param ce Last component index.
1469     *
1470     * @param lys First layer index for each component and resolution.
1471     *
1472     * @param lye Last layer index.
1473     * */
1474    public void writeResPosCompLy(int t,int rs,int re,int cs,int ce,
1475                                  int[][] lys,int lye) throws IOException {
1476
1477        boolean sopUsed; // Should SOP markers be used ?
1478        boolean ephUsed; // Should EPH markers be used ?
1479        int nc = src.getNumComps();
1480        int mrl;
1481        SubbandAn sb;
1482        float threshold;
1483        BitOutputBuffer hBuff = null;
1484        byte[] bBuff = null;
1485
1486        // Computes current tile offset in the reference grid
1487        Point nTiles = src.getNumTiles(null);
1488        Point tileI = src.getTile(null);
1489        int x0siz = src.getImgULX();
1490        int y0siz = src.getImgULY();
1491        int xsiz = x0siz + src.getImgWidth();
1492        int ysiz = y0siz + src.getImgHeight();
1493        int xt0siz = src.getTilePartULX();
1494        int yt0siz = src.getTilePartULY();
1495        int xtsiz = src.getNomTileWidth();
1496        int ytsiz = src.getNomTileHeight();
1497        int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
1498        int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
1499        int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
1500        int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
1501
1502        // Get precinct information (number,distance between two consecutive
1503        // precincts in the reference grid) in each component and resolution
1504        // level
1505        PrecInfo prec; // temporary variable
1506        int p; // Current precinct index
1507        int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1508        int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1509        int nPrec = 0; // Total number of found precincts
1510        int[][] nextPrec = new int [ce][]; // Next precinct index in each
1511        // component and resolution level
1512        int minlys = 100000; // minimum layer start index of each component
1513        int minx = tx1; // Horiz. offset of the second precinct in the
1514        // reference grid
1515        int miny = ty1; // Vert. offset of the second precinct in the
1516        // reference grid. 
1517        int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1518        int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1519        for(int c=cs; c<ce; c++) {
1520            mrl = src.getAnSubbandTree(t,c).resLvl;
1521            nextPrec[c] = new int[mrl+1];
1522            for(int r=rs; r<re; r++) {
1523                if(r>mrl) continue;
1524                if (r<lys[c].length && lys[c][r]<minlys) {
1525                    minlys = lys[c][r];
1526                }
1527                p = numPrec[t][c][r].y*numPrec[t][c][r].x-1;
1528                for(; p>=0; p--) {
1529                    prec = pktEnc.getPrecInfo(t,c,r,p);
1530                    if(prec.rgulx!=tx0) {
1531                        if(prec.rgulx<minx) minx = prec.rgulx;
1532                        if(prec.rgulx>maxx) maxx = prec.rgulx;
1533                    }
1534                    if(prec.rguly!=ty0){
1535                        if(prec.rguly<miny) miny = prec.rguly;
1536                        if(prec.rguly>maxy) maxy = prec.rguly;
1537                    }
1538
1539                    if(nPrec==0) {
1540                        gcd_x = prec.rgw;
1541                        gcd_y = prec.rgh;
1542                    } else {
1543                        gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
1544                        gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
1545                    }
1546                    nPrec++;
1547                } // precincts
1548            } // resolution levels
1549        } // components
1550
1551        if(nPrec==0) {
1552            throw new Error("Image cannot have no precinct");
1553        }
1554
1555        int pyend = (maxy-miny)/gcd_y+1;
1556        int pxend = (maxx-minx)/gcd_x+1;
1557        int x,y;
1558        for(int r=rs; r<re; r++) { // Resolution levels
1559            y = ty0;
1560            x = tx0;
1561            for(int py=0; py<=pyend; py++) { // Vertical precincts
1562                for(int px=0; px<=pxend; px++) { // Horiz. precincts
1563                    for(int c=cs; c<ce; c++) { // Components
1564                        mrl = src.getAnSubbandTree(t,c).resLvl;
1565                        if(r>mrl) continue;
1566                        if(nextPrec[c][r] >=
1567                           numPrec[t][c][r].x*numPrec[t][c][r].y) {
1568                            continue;
1569                        }
1570                        prec = pktEnc.getPrecInfo(t,c,r,nextPrec[c][r]);
1571                        if((prec.rgulx!=x) || (prec.rguly!=y)) {
1572                            continue;
1573                        }
1574                        for(int l=minlys; l<lye; l++) {
1575                            if(r>=lys[c].length) continue;
1576                            if(l<lys[c][r]) continue;
1577
1578                            // set boolean sopUsed here (SOP markers)
1579                            sopUsed = ((String)wp.getSOP().getTileDef(t)).equals("true");
1580                            // set boolean ephUsed here (EPH markers)
1581                            ephUsed = ((String)wp.getEPH().getTileDef(t)).equals("true");
1582
1583                            sb = src.getAnSubbandTree(t,c);
1584                            for(int i=mrl; i>r; i--) {
1585                                sb = sb.subb_LL;
1586                            }
1587
1588                            threshold = layers[l].rdThreshold;
1589                            findTruncIndices(l,c,r,t,sb,threshold,
1590                                             nextPrec[c][r]);
1591
1592                            hBuff = pktEnc.encodePacket(l+1,c,r,t,
1593                                                        cblks[t][c][r],
1594                                                        truncIdxs[t][l][c][r],
1595                                                        hBuff,bBuff,
1596                                                        nextPrec[c][r]);
1597
1598                            if(pktEnc.isPacketWritable()) {
1599                                bsWriter.writePacketHead(hBuff.getBuffer(),
1600                                                         hBuff.getLength(),
1601                                                         false,sopUsed,
1602                                                         ephUsed);
1603                                bsWriter.writePacketBody(pktEnc.
1604                                                         getLastBodyBuf(),
1605                                                         pktEnc.
1606                                                         getLastBodyLen(),
1607                                                         false,
1608                                                         pktEnc.isROIinPkt(),
1609                                                         pktEnc.getROILen());
1610                            }
1611
1612                        } // layers
1613                        nextPrec[c][r]++;
1614                    } // Components
1615                    if(px!=pxend) {
1616                        x = minx+px*gcd_x;
1617                    } else {
1618                        x = tx0;
1619                    }
1620                } // Horizontal precincts
1621                if(py!=pyend) {
1622                    y = miny+py*gcd_y;
1623                } else {
1624                    y = ty0;
1625                }
1626            } // Vertical precincts
1627        } // Resolution levels
1628
1629        // Check that all precincts have been written
1630        for(int c=cs; c<ce; c++) {
1631            mrl = src.getAnSubbandTree(t,c).resLvl;
1632            for(int r=rs; r<re; r++) {
1633                if(r>mrl) continue;
1634                if(nextPrec[c][r]<numPrec[t][c][r].x*numPrec[t][c][r].y-1) {
1635                    throw new Error("JJ2000 bug: One precinct at least has "+
1636                                    "not been written for resolution level "+r
1637                                    +" of component "+c+" in tile "+t+".");
1638                }
1639            }
1640        }
1641    }
1642
1643    /**
1644     * This function implements the rate-distortion optimization algorithm.
1645     * It saves the state of any previously generated bit-stream layers and
1646     * then simulate the formation of a new layer in the bit stream as often
1647     * as necessary to find the smallest rate-distortion threshold such that
1648     * the total number of bytes required to represent the layer does not
1649     * exceed `maxBytes' minus `prevBytes'.  It then restores the state of any
1650     * previously generated bit-stream layers and returns the threshold.
1651     *
1652     * @param layerIdx The index of the current layer
1653     *
1654     * @param fmaxt The maximum admissible slope value. Normally the threshold
1655     * slope of the previous layer.
1656     *
1657     * @param maxBytes The maximum number of bytes that can be written. It
1658     * includes the length of the current layer bistream length and all the
1659     * previous layers bit streams.
1660     *
1661     * @param prevBytes The number of bytes of all the previous layers.
1662     *
1663     * @return The value of the slope threshold.
1664     * */
1665    private float optimizeBitstreamLayer (int layerIdx, float fmaxt,
1666                                          int maxBytes, int prevBytes)
1667        throws IOException {
1668
1669        int nt;         // The total number of tiles
1670        int nc;          // The total number of components
1671        int numLvls;          // The total number of resolution levels
1672        int actualBytes;      // Actual number of bytes for a layer
1673        float fmint;          // Minimum of the current threshold interval
1674        float ft;             // Current threshold
1675        SubbandAn sb;         // Current subband
1676        BitOutputBuffer hBuff;// The packet head buffer
1677        byte[] bBuff;         // The packet body buffer
1678        int sidx;             // The index in the summary table
1679        boolean sopUsed;      // Should SOP markers be used ?
1680        boolean ephUsed;      // Should EPH markers be used ?
1681        int precinctIdx;      // Precinct index for current packet
1682        int nPrec; // Number of precincts in the current resolution level
1683
1684        // Save the packet encoder state
1685        pktEnc.save();
1686
1687        nt = src.getNumTiles();
1688        nc = src.getNumComps();
1689        hBuff = null;
1690        bBuff = null;
1691
1692        // Estimate the minimum slope to start with from the summary
1693        // information in 'RDSlopesRates'. This is a real minimum since it
1694        // does not include the packet head overhead, which is always
1695        // non-zero.
1696
1697        // Look for the summary entry that gives 'maxBytes' or more data
1698        for (sidx=RD_SUMMARY_SIZE-1; sidx > 0; sidx--) {
1699            if (RDSlopesRates[sidx] >= maxBytes) {
1700                break;
1701            }
1702        }
1703        // Get the corresponding minimum slope
1704        fmint = getSlopeFromSIndex(sidx);
1705        // Ensure that it is smaller the maximum slope
1706        if (fmint>=fmaxt) {
1707            sidx--;
1708            fmint = getSlopeFromSIndex(sidx);
1709        }
1710        // If we are using the last entry of the summary, then that
1711        // corresponds to all the data, Thus, set the minimum slope to 0.
1712        if (sidx<=0) fmint = 0;
1713
1714        // We look for the best threshold 'ft', which is the lowest threshold
1715        // that generates no more than 'maxBytes' code bytes.
1716
1717        // The search is done iteratively using a binary split algorithm. We
1718        // start with 'fmaxt' as the maximum possible threshold, and 'fmint'
1719        // as the minimum threshold. The threshold 'ft' is calculated as the
1720        // middle point of 'fmaxt'-'fmint' interval. The 'fmaxt' or 'fmint'
1721        // bounds are moved according to the number of bytes obtained from a
1722        // simulation, where 'ft' is used as the threshold.
1723
1724        // We stop whenever the interval is sufficiently small, and thus
1725        // enough precision is achieved.
1726
1727        // Initialize threshold as the middle point of the interval.
1728        ft = (fmaxt+fmint)/2f;
1729        // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are so
1730        // close that the average is 'fmint', due to rounding. Force it to
1731        // 'fmaxt' instead, since 'fmint' is normally an exclusive lower
1732        // bound.
1733        if (ft <= fmint) ft = fmaxt;
1734
1735        do {
1736            // Get the number of bytes used by this layer, if 'ft' is the
1737            // threshold, by simulation.
1738            actualBytes = prevBytes;
1739            src.setTile(0,0);
1740
1741            for (int t=0; t<nt; t++){
1742                for (int c=0; c<nc; c++) {
1743                    // set boolean sopUsed here (SOP markers)
1744                    sopUsed = ((String)wp.getSOP().getTileDef(t)).equalsIgnoreCase("true");
1745                    // set boolean ephUsed here (EPH markers)
1746                    ephUsed = ((String)wp.getEPH().getTileDef(t)).equalsIgnoreCase("true");
1747
1748                    // Get LL subband
1749                    sb = (SubbandAn) src.getAnSubbandTree(t,c);
1750                    numLvls = sb.resLvl + 1;
1751                    sb = (SubbandAn) sb.getSubbandByIdx(0,0);
1752                    //loop on resolution levels
1753                    for(int r=0; r<numLvls; r++) {
1754
1755                        nPrec = numPrec[t][c][r].x*numPrec[t][c][r].y;
1756                        for(int p=0; p<nPrec; p++) {
1757
1758                            findTruncIndices(layerIdx,c,r,t,sb,ft,p);
1759                            hBuff = pktEnc.encodePacket(layerIdx+1,c,r,t,
1760                                                        cblks[t][c][r],
1761                                                        truncIdxs[t][layerIdx]
1762                                                        [c][r],hBuff,bBuff,p);
1763
1764                            if(pktEnc.isPacketWritable()) {
1765                                bBuff = pktEnc.getLastBodyBuf();
1766                                actualBytes += bsWriter.
1767                                    writePacketHead(hBuff.getBuffer(),
1768                                                    hBuff.getLength(),
1769                                                    true, sopUsed,ephUsed);
1770                                actualBytes += bsWriter.
1771                                    writePacketBody(bBuff,
1772                                                    pktEnc.getLastBodyLen(),
1773                                                    true,pktEnc.isROIinPkt(),
1774                                                    pktEnc.getROILen());
1775                            }
1776                        } // end loop on precincts
1777                        sb = sb.parent;
1778                    } // End loop on resolution levels
1779                } // End loop on components
1780            } // End loop on tiles
1781
1782            // Move the interval bounds according to simulation result
1783            if (actualBytes>maxBytes) {
1784                // 'ft' is too low and generates too many bytes, make it the
1785                // new minimum.
1786                fmint = ft;
1787            } else {
1788                // 'ft' is too high and does not generate as many bytes as we
1789                // are allowed too, make it the new maximum.
1790                fmaxt = ft;
1791            }
1792
1793            // Update 'ft' for the new iteration as the middle point of the
1794            // new interval.
1795            ft = (fmaxt+fmint)/2f;
1796            // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are
1797            // so close that the average is 'fmint', due to rounding. Force it
1798            // to 'fmaxt' instead, since 'fmint' is normally an exclusive
1799            // lower bound.
1800            if (ft <= fmint) ft = fmaxt;
1801
1802            // Restore previous packet encoder state
1803            pktEnc.restore();
1804
1805            // We continue to iterate, until the threshold reaches the upper
1806            // limit of the interval, within a FLOAT_REL_PRECISION relative
1807            // tolerance, or a FLOAT_ABS_PRECISION absolute tolerance. This is
1808            // the sign that the interval is sufficiently small.
1809        } while (ft < fmaxt*(1f-FLOAT_REL_PRECISION) &&
1810                 ft < (fmaxt-FLOAT_ABS_PRECISION));
1811
1812        // If we have a threshold which is close to 0, set it to 0 so that
1813        // everything is taken into the layer. This is to avoid not sending
1814        // some least significant bit-planes in the lossless case. We use the
1815        // FLOAT_ABS_PRECISION value as a measure of "close" to 0.
1816        if (ft <= FLOAT_ABS_PRECISION) {
1817            ft = 0f;
1818        } else {
1819            // Otherwise make the threshold 'fmaxt', just to be sure that we
1820            // will not send more bytes than allowed.
1821            ft = fmaxt;
1822        }
1823       return ft;
1824    }
1825
1826    /**
1827     * This function attempts to estimate a rate-distortion slope threshold
1828     * which will achieve a target number of code bytes close the
1829     * `targetBytes' value.
1830     *
1831     * @param targetBytes The target number of bytes for the current layer
1832     *
1833     * @param lastLayer The previous layer information.
1834     *
1835     * @return The value of the slope threshold for the estimated layer
1836     * */
1837    private float estimateLayerThreshold(int targetBytes,
1838                                         EBCOTLayer lastLayer) {
1839        float log_sl1;  // The log of the first slope used for interpolation
1840        float log_sl2;  // The log of the second slope used for interpolation
1841        float log_len1; // The log of the first length used for interpolation
1842        float log_len2; // The log of the second length used for interpolation
1843        float log_isl;  // The log of the interpolated slope
1844        float log_ilen; // Log of the interpolated length
1845        float log_ab;   // Log of actual bytes in last layer
1846        int sidx;       // Index into the summary R-D info array
1847        float log_off;  // The log of the offset proportion
1848        int tlen;       // The corrected target layer length
1849        float lthresh;  // The threshold of the last layer
1850        float eth;      // The estimated threshold
1851
1852        // In order to estimate the threshold we base ourselves in the summary
1853        // R-D info in RDSlopesRates. In order to use it we must compensate
1854        // for the overhead of the packet heads. The proportion of overhead is
1855        // estimated using the last layer simulation results.
1856
1857        // NOTE: the model used in this method is that the slope varies
1858        // linearly with the log of the rate (i.e. length).
1859
1860        // NOTE: the model used in this method is that the distortion is
1861        // proprotional to a power of the rate. Thus, the slope is also
1862        // proportional to another power of the rate. This translates as the
1863        // log of the slope varies linearly with the log of the rate, which is
1864        // what we use.
1865
1866        // 1) Find the offset of the length predicted from the summary R-D
1867        // information, to the actual length by using the last layer.
1868
1869        // We ensure that the threshold we use for estimation actually
1870        // includes some data.
1871        lthresh = lastLayer.rdThreshold;
1872        if (lthresh > maxSlope) lthresh = maxSlope;
1873        // If the slope of the last layer is too small then we just include
1874        // all the rest (not possible to do better).
1875        if (lthresh < FLOAT_ABS_PRECISION) return 0f;
1876        sidx = getLimitedSIndexFromSlope(lthresh);
1877        // If the index is outside of the summary info array use the last two,
1878        // or first two, indexes, as appropriate
1879        if (sidx >= RD_SUMMARY_SIZE-1) sidx = RD_SUMMARY_SIZE-2;
1880
1881        // Get the logs of the lengths and the slopes
1882
1883        if (RDSlopesRates[sidx+1] == 0) {
1884            // Pathological case, we can not use log of 0. Add
1885            // RDSlopesRates[sidx]+1 bytes to the rates (just a crude simple
1886            // solution to this rare case)
1887            log_len1 = (float)Math.log((RDSlopesRates[sidx]<<1)+1);
1888            log_len2 = (float)Math.log(RDSlopesRates[sidx]+1);
1889            log_ab = (float)Math.log(lastLayer.actualBytes+
1890                                     RDSlopesRates[sidx]+1);
1891        }
1892        else {
1893            log_len1 = (float)Math.log(RDSlopesRates[sidx]);
1894            log_len2 = (float)Math.log(RDSlopesRates[sidx+1]);
1895            log_ab = (float)Math.log(lastLayer.actualBytes);
1896        }
1897
1898        log_sl1 = (float)Math.log(getSlopeFromSIndex(sidx));
1899        log_sl2 = (float)Math.log(getSlopeFromSIndex(sidx+1));
1900
1901        log_isl = (float)Math.log(lthresh);
1902
1903        log_ilen = log_len1 +
1904            (log_isl-log_sl1)*(log_len1-log_len2)/(log_sl1-log_sl2);
1905
1906        log_off = log_ab - log_ilen;
1907
1908        // Do not use negative offsets (i.e. offset proportion larger than 1)
1909        // since that is probably a sign that our model is off. To be
1910        // conservative use an offset of 0 (i.e. offset proportiojn 1).
1911        if (log_off < 0) log_off = 0f;
1912
1913        // 2) Correct the target layer length by the offset.
1914
1915        tlen = (int)(targetBytes/(float)Math.exp(log_off));
1916
1917        // 3) Find, from the summary R-D info, the thresholds that generate
1918        // lengths just above and below our corrected target layer length.
1919
1920        // Look for the index in the summary info array that gives the largest
1921        // length smaller than the target length
1922        for (sidx = RD_SUMMARY_SIZE-1; sidx>=0 ; sidx--) {
1923            if (RDSlopesRates[sidx] >= tlen) break;
1924        }
1925        sidx++;
1926        // Correct if out of the array
1927        if (sidx >= RD_SUMMARY_SIZE) sidx = RD_SUMMARY_SIZE-1;
1928        if (sidx <= 0) sidx = 1;
1929
1930        // Get the log of the lengths and the slopes that are just above and
1931        // below the target length.
1932
1933        if (RDSlopesRates[sidx] == 0) {
1934            // Pathological case, we can not use log of 0. Add
1935            // RDSlopesRates[sidx-1]+1 bytes to the rates (just a crude simple
1936            // solution to this rare case)
1937            log_len1 = (float)Math.log(RDSlopesRates[sidx-1]+1);
1938            log_len2 = (float)Math.log((RDSlopesRates[sidx-1]<<1)+1);
1939            log_ilen = (float)Math.log(tlen+RDSlopesRates[sidx-1]+1);
1940        }
1941        else {
1942            // Normal case, we can safely take the logs.
1943            log_len1 = (float)Math.log(RDSlopesRates[sidx]);
1944            log_len2 = (float)Math.log(RDSlopesRates[sidx-1]);
1945            log_ilen = (float)Math.log(tlen);
1946        }
1947
1948        log_sl1 = (float)Math.log(getSlopeFromSIndex(sidx));
1949        log_sl2 = (float)Math.log(getSlopeFromSIndex(sidx-1));
1950
1951        // 4) Interpolate the two thresholds to find the target threshold.
1952
1953        log_isl = log_sl1 +
1954            (log_ilen-log_len1)*(log_sl1-log_sl2)/(log_len1-log_len2);
1955
1956        eth = (float)Math.exp(log_isl);
1957
1958        // Correct out of bounds results
1959        if (eth > lthresh) eth = lthresh;
1960        if (eth < FLOAT_ABS_PRECISION) eth = 0f;
1961
1962        // Return the estimated threshold
1963        return eth;
1964    }
1965
1966    /**
1967     * This function finds the new truncation points indices for a packet. It
1968     * does so by including the data from the code-blocks in the component,
1969     * resolution level and tile, associated with a R-D slope which is larger
1970     * than or equal to 'fthresh'.
1971     *
1972     * @param layerIdx The index of the current layer
1973     *
1974     * @param compIdx The index of the current component
1975     *
1976     * @param lvlIdx The index of the current resolution level
1977     *
1978     * @param tileIdx The index of the current tile
1979     *
1980     * @param subb The LL subband in the resolution level lvlIdx, which is
1981     * parent of all the subbands in the packet. Except for resolution level 0
1982     * this subband is always a node.
1983     *
1984     * @param fthresh The value of the rate-distortion threshold
1985     * */
1986    private void findTruncIndices(int layerIdx, int compIdx, int lvlIdx,
1987                                  int tileIdx, SubbandAn subb,
1988                                  float fthresh, int precinctIdx) {
1989        int minsbi, maxsbi, b, bIdx, n;
1990        Point ncblks = null;
1991        SubbandAn sb;
1992        CBlkRateDistStats cur_cblk;
1993        PrecInfo prec = pktEnc.getPrecInfo(tileIdx,compIdx,lvlIdx,precinctIdx);
1994        Point cbCoord;
1995
1996        sb = subb;
1997        while(sb.subb_HH != null) {
1998            sb = sb.subb_HH;
1999        }
2000        minsbi = (lvlIdx==0) ? 0 : 1;
2001        maxsbi = (lvlIdx==0) ? 1 : 4;
2002
2003        int yend,xend;
2004
2005        sb = (SubbandAn)subb.getSubbandByIdx(lvlIdx, minsbi);
2006        for(int s=minsbi; s<maxsbi; s++) { //loop on subbands
2007            yend = (prec.cblk[s]!=null) ? prec.cblk[s].length : 0;
2008            for(int y=0; y<yend; y++) {
2009                xend = (prec.cblk[s][y]!=null) ? prec.cblk[s][y].length : 0;
2010                for (int x=0; x<xend; x++) {
2011                    cbCoord = prec.cblk[s][y][x].idx;
2012                    b = cbCoord.x+cbCoord.y*sb.numCb.x;
2013                    //Get the current code-block
2014                    cur_cblk = cblks[tileIdx][compIdx][lvlIdx][s][b];
2015                    for(n=0; n<cur_cblk.nVldTrunc; n++) {
2016                        if(cur_cblk.truncSlopes[n] < fthresh) {
2017                            break;
2018                        } else {
2019                            continue;
2020                        }
2021                    }
2022                    // Store the index in the code-block truncIdxs that gives
2023                    // the real truncation index.
2024                    truncIdxs[tileIdx][layerIdx][compIdx][lvlIdx][s][b] = n-1;
2025
2026                } // End loop on horizontal code-blocks
2027            } // End loop on vertical code-blocks
2028            sb = (SubbandAn)sb.nextSubband();
2029        } // End loop on subbands
2030    }
2031
2032
2033    /**
2034     * Returns the index of a slope for the summary table, limiting to the
2035     * admissible values. The index is calculated as RD_SUMMARY_OFF plus the
2036     * maximum exponent, base 2, that yields a value not larger than the slope
2037     * itself.
2038     *
2039     * <P>If the value to return is lower than 0, 0 is returned. If it is
2040     * larger than the maximum table index, then the maximum is returned.
2041     *
2042     * @param slope The slope value
2043     *
2044     * @return The index for the summary table of the slope.
2045     * */
2046    private static int getLimitedSIndexFromSlope(float slope) {
2047        int idx;
2048
2049        idx = (int)Math.floor(Math.log(slope)/LOG2) + RD_SUMMARY_OFF;
2050
2051        if (idx < 0) {
2052            return 0;
2053        }
2054        else if (idx >= RD_SUMMARY_SIZE) {
2055            return RD_SUMMARY_SIZE-1;
2056        }
2057        else {
2058            return idx;
2059        }
2060    }
2061
2062    /**
2063     * Returns the minimum slope value associated with a summary table
2064     * index. This minimum slope is just 2^(index-RD_SUMMARY_OFF).
2065     *
2066     * @param index The summary index value.
2067     *
2068     * @return The minimum slope value associated with a summary table index.
2069     * */
2070    private static float getSlopeFromSIndex(int index) {
2071        return (float)Math.pow(2,(index-RD_SUMMARY_OFF));
2072    }
2073}