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