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