Source Code Cross Referenced for EBCOTRateAllocator.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » jj2000 » j2k » entropy » encoder » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » Java Advanced Imaging » jj2000.j2k.entropy.encoder 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: EBCOTRateAllocator.java,v $
0003:         * $Revision: 1.1 $
0004:         * $Date: 2005/02/11 05:02:08 $
0005:         * $State: Exp $
0006:         *
0007:         * Class:                   EBCOTRateAllocator
0008:         *
0009:         * Description:             Generic interface for post-compression
0010:         *                          rate allocator.
0011:         *
0012:         *
0013:         *
0014:         * COPYRIGHT:
0015:         *
0016:         * This software module was originally developed by Raphaël Grosbois and
0017:         * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
0018:         * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
0019:         * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
0020:         * Centre France S.A) in the course of development of the JPEG2000
0021:         * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
0022:         * software module is an implementation of a part of the JPEG 2000
0023:         * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
0024:         * Systems AB and Canon Research Centre France S.A (collectively JJ2000
0025:         * Partners) agree not to assert against ISO/IEC and users of the JPEG
0026:         * 2000 Standard (Users) any of their rights under the copyright, not
0027:         * including other intellectual property rights, for this software module
0028:         * with respect to the usage by ISO/IEC and Users of this software module
0029:         * or modifications thereof for use in hardware or software products
0030:         * claiming conformance to the JPEG 2000 Standard. Those intending to use
0031:         * this software module in hardware or software products are advised that
0032:         * their use may infringe existing patents. The original developers of
0033:         * this software module, JJ2000 Partners and ISO/IEC assume no liability
0034:         * for use of this software module or modifications thereof. No license
0035:         * or right to this software module is granted for non JPEG 2000 Standard
0036:         * conforming products. JJ2000 Partners have full right to use this
0037:         * software module for his/her own purpose, assign or donate this
0038:         * software module to any third party and to inhibit third parties from
0039:         * using this software module for non JPEG 2000 Standard conforming
0040:         * products. This copyright notice must be included in all copies or
0041:         * derivative works of this software module.
0042:         *
0043:         * Copyright (c) 1999/2000 JJ2000 Partners.
0044:         * */
0045:        package jj2000.j2k.entropy.encoder;
0046:
0047:        import java.awt.Point;
0048:
0049:        import jj2000.j2k.codestream.writer.*;
0050:        import jj2000.j2k.wavelet.analysis.*;
0051:        import jj2000.j2k.entropy.encoder.*;
0052:        import jj2000.j2k.codestream.*;
0053:        import jj2000.j2k.entropy.*;
0054:        import jj2000.j2k.image.*;
0055:        import jj2000.j2k.util.*;
0056:
0057:        import java.util.Vector;
0058:        import java.io.*;
0059:
0060:        import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
0061:
0062:        /**
0063:         * This implements the EBCOT post compression rate allocation algorithm. This
0064:         * algorithm finds the most suitable truncation points for the set of
0065:         * code-blocks, for each layer target bitrate. It works by first collecting
0066:         * the rate distortion info from all code-blocks, in all tiles and all
0067:         * components, and then running the rate-allocation on the whole image at
0068:         * once, for each layer.
0069:         *
0070:         * <P>This implementation also provides some timing features. They can be
0071:         * enabled by setting the 'DO_TIMING' constant of this class to true and
0072:         * recompiling. The timing uses the 'System.currentTimeMillis()' Java API
0073:         * call, which returns wall clock time, not the actual CPU time used. The
0074:         * timing results will be printed on the message output. Since the times
0075:         * reported are wall clock times and not CPU usage times they can not be added
0076:         * to find the total used time (i.e. some time might be counted in several
0077:         * places). When timing is disabled ('DO_TIMING' is false) there is no penalty
0078:         * if the compiler performs some basic optimizations. Even if not the penalty
0079:         * should be negligeable.
0080:         *
0081:         * @see PostCompRateAllocator
0082:         *
0083:         * @see CodedCBlkDataSrcEnc
0084:         *
0085:         * @see jj2000.j2k.codestream.writer.CodestreamWriter
0086:         * */
0087:        public class EBCOTRateAllocator extends PostCompRateAllocator {
0088:
0089:            /** Whether to collect timing information or not: false. Used as a compile
0090:             * time directive. */
0091:            private final static boolean DO_TIMING = false;
0092:
0093:            /** The wall time for the initialization. */
0094:            private long initTime;
0095:
0096:            /** The wall time for the building of layers. */
0097:            private long buildTime;
0098:
0099:            /** The wall time for the writing of layers. */
0100:            private long writeTime;
0101:
0102:            /**
0103:             * 5D Array containing all the coded code-blocks:
0104:             *
0105:             * <ul>
0106:             * <li>1st index: tile index</li>
0107:             * <li>2nd index: component index</li>
0108:             * <li>3rd index: resolution level index</li>
0109:             * <li>4th index: subband index</li>
0110:             * <li>5th index: code-block index</li>
0111:             * </ul>
0112:             **/
0113:            private CBlkRateDistStats cblks[][][][][];
0114:
0115:            /**
0116:             * 6D Array containing the indices of the truncation points. It actually
0117:             * contains the index of the element in CBlkRateDistStats.truncIdxs that
0118:             * gives the real truncation point index.
0119:             *
0120:             * <ul>
0121:             * <li>1st index: tile index</li>
0122:             * <li>2nd index: layer index</li>
0123:             * <li>3rd index: component index</li>
0124:             * <li>4th index: resolution level index</li>
0125:             * <li>5th index: subband index</li>
0126:             * <li>6th index: code-block index</li>
0127:             * </ul>
0128:             **/
0129:            private int truncIdxs[][][][][][];
0130:
0131:            /**
0132:             * Maximum number of precincts :
0133:             *
0134:             * <ul>
0135:             * <li>1st dim: tile index.</li>
0136:             * <li>2nd dim: component index.</li>
0137:             * <li>3nd dim: resolution level index.</li>
0138:             * </ul>
0139:             */
0140:            private Point numPrec[][][];
0141:
0142:            /** Array containing the layers information. */
0143:            private EBCOTLayer layers[];
0144:
0145:            /** The log of 2, natural base */
0146:            private static final double LOG2 = Math.log(2);
0147:
0148:            /** The normalization offset for the R-D summary table */
0149:            private static final int RD_SUMMARY_OFF = 24;
0150:
0151:            /** The size of the summary table */
0152:            private static final int RD_SUMMARY_SIZE = 64;
0153:
0154:            /** The relative precision for float data. This is the relative tolerance
0155:             * up to which the layer slope thresholds are calculated. */
0156:            private static final float FLOAT_REL_PRECISION = 1e-4f;
0157:
0158:            /** The precision for float data type, in an absolute sense. Two float
0159:             * numbers are considered "equal" if they are within this precision. */
0160:            private static final float FLOAT_ABS_PRECISION = 1e-10f;
0161:
0162:            /**
0163:             * Minimum average size of a packet. If layer has less bytes than the this
0164:             * constant multiplied by number of packets in the layer, then the layer
0165:             * is skipped.
0166:             * */
0167:            private static final int MIN_AVG_PACKET_SZ = 32;
0168:
0169:            /**
0170:             * The R-D summary information collected from the coding of all
0171:             * code-blocks. For each entry it contains the accumulated length of all
0172:             * truncation points that have a slope not less than
0173:             * '2*(k-RD_SUMMARY_OFF)', where 'k' is the entry index.
0174:             *
0175:             * <P>Therefore, the length at entry 'k' is the total number of bytes of
0176:             * code-block data that would be obtained if the truncation slope was
0177:             * chosen as '2*(k-RD_SUMMARY_OFF)', without counting the overhead
0178:             * associated with the packet heads.
0179:             *
0180:             * <P>This summary is used to estimate the relation of the R-D slope to
0181:             * coded length, and to obtain absolute minimums on the slope given a
0182:             * length.
0183:             **/
0184:            private int RDSlopesRates[];
0185:
0186:            /** Packet encoder. */
0187:            private PktEncoder pktEnc;
0188:
0189:            /** The layer specifications */
0190:            private LayersInfo lyrSpec;
0191:
0192:            /** The maximum slope accross all code-blocks and truncation points. */
0193:            private float maxSlope;
0194:
0195:            /** The minimum slope accross all code-blocks and truncation points. */
0196:            private float minSlope;
0197:
0198:            /**
0199:             * Initializes the EBCOT rate allocator of entropy coded data. The layout
0200:             * of layers, and their bitrate constraints, is specified by the 'lyrs'
0201:             * parameter.
0202:             *
0203:             * @param src The source of entropy coded data.
0204:             *
0205:             * @param lyrs The layers layout specification.
0206:             *
0207:             * @param writer The bit stream writer.
0208:             *
0209:             * @see ProgressionType
0210:             * */
0211:            public EBCOTRateAllocator(CodedCBlkDataSrcEnc src, LayersInfo lyrs,
0212:                    CodestreamWriter writer, J2KImageWriteParamJava wp) {
0213:
0214:                super (src, lyrs.getTotNumLayers(), writer, wp);
0215:
0216:                int minsbi, maxsbi;
0217:                int i;
0218:                SubbandAn sb, sb2;
0219:                Point ncblks = null;
0220:
0221:                // If we do timing create necessary structures
0222:                if (DO_TIMING) {
0223:                    // If we are timing make sure that 'finalize' gets called.
0224:                    System.runFinalizersOnExit(true);
0225:                    // The System.runFinalizersOnExit() method is deprecated in Java
0226:                    // 1.2 since it can cause a deadlock in some cases. However, here
0227:                    // we use it only for profiling purposes and is disabled in
0228:                    // production code.
0229:                    initTime = 0L;
0230:                    buildTime = 0L;
0231:                    writeTime = 0L;
0232:                }
0233:
0234:                // Save the layer specs
0235:                lyrSpec = lyrs;
0236:
0237:                //Initialize the size of the RD slope rates array
0238:                RDSlopesRates = new int[RD_SUMMARY_SIZE];
0239:
0240:                //Get number of tiles, components
0241:                int nt = src.getNumTiles();
0242:                int nc = getNumComps();
0243:
0244:                //Allocate the coded code-blocks and truncation points indexes arrays
0245:                cblks = new CBlkRateDistStats[nt][nc][][][];
0246:                truncIdxs = new int[nt][numLayers][nc][][][];
0247:
0248:                int cblkPerSubband; // Number of code-blocks per subband
0249:                int mrl; // Number of resolution levels
0250:                int l; // layer index
0251:                int s; //subband index
0252:
0253:                // Used to compute the maximum number of precincts for each resolution
0254:                // level
0255:                int tx0, ty0, tx1, ty1; // Current tile position in the reference grid
0256:                int tcx0, tcy0, tcx1, tcy1; // Current tile position in the domain of
0257:                // the image component
0258:                int trx0, try0, trx1, try1; // Current tile position in the reduced
0259:                // resolution image domain
0260:                int xrsiz, yrsiz; // Component sub-sampling factors
0261:                Point tileI = null;
0262:                Point nTiles = null;
0263:                int xsiz, ysiz, x0siz, y0siz;
0264:                int xt0siz, yt0siz;
0265:                int xtsiz, ytsiz;
0266:
0267:                int cb0x = src.getCbULX();
0268:                int cb0y = src.getCbULY();
0269:
0270:                src.setTile(0, 0);
0271:                for (int t = 0; t < nt; t++) { // Loop on tiles
0272:                    nTiles = src.getNumTiles(nTiles);
0273:                    tileI = src.getTile(tileI);
0274:                    x0siz = getImgULX();
0275:                    y0siz = getImgULY();
0276:                    xsiz = x0siz + getImgWidth();
0277:                    ysiz = y0siz + getImgHeight();
0278:                    xt0siz = src.getTilePartULX();
0279:                    yt0siz = src.getTilePartULY();
0280:                    xtsiz = src.getNomTileWidth();
0281:                    ytsiz = src.getNomTileHeight();
0282:
0283:                    // Tile's coordinates on the reference grid
0284:                    tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
0285:                    ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
0286:                    tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
0287:                            * xtsiz : xsiz;
0288:                    ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
0289:                            * ytsiz : ysiz;
0290:
0291:                    for (int c = 0; c < nc; c++) { // loop on components
0292:
0293:                        //Get the number of resolution levels
0294:                        sb = src.getAnSubbandTree(t, c);
0295:                        mrl = sb.resLvl + 1;
0296:
0297:                        // Initialize maximum number of precincts per resolution array
0298:                        if (numPrec == null) {
0299:                            numPrec = new Point[nt][nc][];
0300:                        }
0301:                        if (numPrec[t][c] == null) {
0302:                            numPrec[t][c] = new Point[mrl];
0303:                        }
0304:
0305:                        // Subsampling factors
0306:                        xrsiz = src.getCompSubsX(c);
0307:                        yrsiz = src.getCompSubsY(c);
0308:
0309:                        // Tile's coordinates in the image component domain
0310:                        tcx0 = (int) Math.ceil(tx0 / (double) (xrsiz));
0311:                        tcy0 = (int) Math.ceil(ty0 / (double) (yrsiz));
0312:                        tcx1 = (int) Math.ceil(tx1 / (double) (xrsiz));
0313:                        tcy1 = (int) Math.ceil(ty1 / (double) (yrsiz));
0314:
0315:                        cblks[t][c] = new CBlkRateDistStats[mrl][][];
0316:
0317:                        for (l = 0; l < numLayers; l++) {
0318:                            truncIdxs[t][l][c] = new int[mrl][][];
0319:                        }
0320:
0321:                        for (int r = 0; r < mrl; r++) { // loop on resolution levels
0322:
0323:                            // Tile's coordinates in the reduced resolution image
0324:                            // domain
0325:                            trx0 = (int) Math.ceil(tcx0
0326:                                    / (double) (1 << (mrl - 1 - r)));
0327:                            try0 = (int) Math.ceil(tcy0
0328:                                    / (double) (1 << (mrl - 1 - r)));
0329:                            trx1 = (int) Math.ceil(tcx1
0330:                                    / (double) (1 << (mrl - 1 - r)));
0331:                            try1 = (int) Math.ceil(tcy1
0332:                                    / (double) (1 << (mrl - 1 - r)));
0333:
0334:                            // Calculate the maximum number of precincts for each
0335:                            // resolution level taking into account tile specific
0336:                            // options.
0337:                            double twoppx = (double) wp.getPrecinctPartition()
0338:                                    .getPPX(t, c, r);
0339:                            double twoppy = (double) wp.getPrecinctPartition()
0340:                                    .getPPY(t, c, r);
0341:                            numPrec[t][c][r] = new Point();
0342:                            if (trx1 > trx0) {
0343:                                numPrec[t][c][r].x = (int) Math
0344:                                        .ceil((trx1 - cb0x) / twoppx)
0345:                                        - (int) Math.floor((trx0 - cb0x)
0346:                                                / twoppx);
0347:                            } else {
0348:                                numPrec[t][c][r].x = 0;
0349:                            }
0350:                            if (try1 > try0) {
0351:                                numPrec[t][c][r].y = (int) Math
0352:                                        .ceil((try1 - cb0y) / twoppy)
0353:                                        - (int) Math.floor((try0 - cb0y)
0354:                                                / (double) twoppy);
0355:                            } else {
0356:                                numPrec[t][c][r].y = 0;
0357:                            }
0358:
0359:                            minsbi = (r == 0) ? 0 : 1;
0360:                            maxsbi = (r == 0) ? 1 : 4;
0361:
0362:                            cblks[t][c][r] = new CBlkRateDistStats[maxsbi][];
0363:                            for (l = 0; l < numLayers; l++) {
0364:                                truncIdxs[t][l][c][r] = new int[maxsbi][];
0365:                            }
0366:
0367:                            for (s = minsbi; s < maxsbi; s++) { // loop on subbands
0368:                                //Get the number of blocks in the current subband
0369:                                sb2 = (SubbandAn) sb.getSubbandByIdx(r, s);
0370:                                ncblks = sb2.numCb;
0371:                                cblkPerSubband = ncblks.x * ncblks.y;
0372:                                cblks[t][c][r][s] = new CBlkRateDistStats[cblkPerSubband];
0373:
0374:                                for (l = 0; l < numLayers; l++) {
0375:                                    truncIdxs[t][l][c][r][s] = new int[cblkPerSubband];
0376:                                    for (i = 0; i < cblkPerSubband; i++) {
0377:                                        truncIdxs[t][l][c][r][s][i] = -1;
0378:                                    }
0379:                                }
0380:                            } // End loop on subbands
0381:                        } // End lopp on resolution levels
0382:                    } // End loop on components
0383:                    if (t != nt - 1) {
0384:                        src.nextTile();
0385:                    }
0386:                } // End loop on tiles
0387:
0388:                //Initialize the packet encoder
0389:                pktEnc = new PktEncoder(src, wp, numPrec);
0390:
0391:                // The layers array has to be initialized after the constructor since
0392:                // it is needed that the bit stream header has been entirely written
0393:            }
0394:
0395:            /**
0396:             * Prints the timing information, if collected, and calls 'finalize' on
0397:             * the super class.
0398:             * */
0399:            public void finalize() throws Throwable {
0400:                if (DO_TIMING) {
0401:                    StringBuffer sb;
0402:
0403:                    sb = new StringBuffer(
0404:                            "EBCOTRateAllocator wall clock times:\n");
0405:                    sb.append("  initialization: ");
0406:                    sb.append(initTime);
0407:                    sb.append(" ms\n");
0408:                    sb.append("  layer building: ");
0409:                    sb.append(buildTime);
0410:                    sb.append(" ms\n");
0411:                    sb.append("  final writing:  ");
0412:                    sb.append(writeTime);
0413:                    sb.append(" ms");
0414:                    FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,
0415:                            sb.toString());
0416:                }
0417:                super .finalize();
0418:            }
0419:
0420:            /**
0421:             * Runs the rate allocation algorithm and writes the data to the bit
0422:             * stream writer object provided to the constructor.
0423:             * */
0424:            public void runAndWrite() throws IOException {
0425:                //Now, run the rate allocation
0426:                buildAndWriteLayers();
0427:            }
0428:
0429:            /**
0430:             * Initializes the layers array. This must be called after the main header
0431:             * has been entirely written or simulated, so as to take its overhead into
0432:             * account. This method will get all the code-blocks and then initialize
0433:             * the target bitrates for each layer, according to the specifications.
0434:             * */
0435:            public void initialize() throws IOException {
0436:                int n, i, l;
0437:                int ho; // The header overhead (in bytes)
0438:                float np;// The number of pixels divided by the number of bits per byte
0439:                double ls; // Step for log-scale
0440:                double basebytes;
0441:                int lastbytes, newbytes, nextbytes;
0442:                int loopnlyrs;
0443:                int minlsz; // The minimum allowable number of bytes in a layer
0444:                int totenclength;
0445:                int maxpkt;
0446:                int numTiles = src.getNumTiles();
0447:                int numComps = src.getNumComps();
0448:                int numLvls;
0449:                int avgPktLen;
0450:
0451:                long stime = 0L;
0452:
0453:                // Start by getting all the code-blocks, we need this in order to have
0454:                // an idea of the total encoded bitrate.
0455:                getAllCodeBlocks();
0456:
0457:                if (DO_TIMING)
0458:                    stime = System.currentTimeMillis();
0459:
0460:                // Now get the total encoded length
0461:                totenclength = RDSlopesRates[0]; // all the encoded data
0462:                // Make a rough estimation of the packet head overhead, as 2 bytes per
0463:                // packet in average (plus EPH / SOP) , and add that to the total
0464:                // encoded length
0465:                for (int t = 0; t < numTiles; t++) {
0466:                    avgPktLen = 2;
0467:                    // Add SOP length if set
0468:                    if (((String) wp.getSOP().getTileDef(t))
0469:                            .equalsIgnoreCase("true")) {
0470:                        avgPktLen += Markers.SOP_LENGTH;
0471:                    }
0472:                    // Add EPH length if set
0473:                    if (((String) wp.getEPH().getTileDef(t))
0474:                            .equalsIgnoreCase("true")) {
0475:                        avgPktLen += Markers.EPH_LENGTH;
0476:                    }
0477:
0478:                    for (int c = 0; c < numComps; c++) {
0479:                        numLvls = src.getAnSubbandTree(t, c).resLvl + 1;
0480:                        if (!src.precinctPartitionUsed(c, t)) {
0481:                            // Precinct partition is not used so there is only
0482:                            // one packet per resolution level/layer
0483:                            totenclength += numLayers * avgPktLen * numLvls;
0484:                        } else {
0485:                            // Precinct partition is used so for each
0486:                            // component/tile/resolution level, we get the maximum
0487:                            // number of packets
0488:                            for (int rl = 0; rl < numLvls; rl++) {
0489:                                maxpkt = numPrec[t][c][rl].x
0490:                                        * numPrec[t][c][rl].y;
0491:                                totenclength += numLayers * avgPktLen * maxpkt;
0492:                            }
0493:                        }
0494:                    } // End loop on components
0495:                } // End loop on tiles
0496:
0497:                // If any layer specifies more than 'totenclength' as its target
0498:                // length then 'totenclength' is used. This is to prevent that
0499:                // estimated layers get excessively large target lengths due to an
0500:                // excessively large target bitrate. At the end the last layer is set
0501:                // to the target length corresponding to the overall target
0502:                // bitrate. Thus, 'totenclength' can not limit the total amount of
0503:                // encoded data, as intended.
0504:
0505:                ho = headEnc.getLength();
0506:                np = src.getImgWidth() * src.getImgHeight() / 8f;
0507:
0508:                // SOT marker must be taken into account
0509:                for (int t = 0; t < numTiles; t++) {
0510:                    headEnc.reset();
0511:                    headEnc.encodeTilePartHeader(0, t);
0512:                    ho += headEnc.getLength();
0513:                }
0514:
0515:                layers = new EBCOTLayer[numLayers];
0516:                for (n = numLayers - 1; n >= 0; n--) {
0517:                    layers[n] = new EBCOTLayer();
0518:                }
0519:
0520:                minlsz = 0; // To keep compiler happy
0521:                for (int t = 0; t < numTiles; t++) {
0522:                    for (int c = 0; c < numComps; c++) {
0523:                        numLvls = src.getAnSubbandTree(t, c).resLvl + 1;
0524:
0525:                        if (!src.precinctPartitionUsed(c, t)) {
0526:                            // Precinct partition is not used
0527:                            minlsz += MIN_AVG_PACKET_SZ * numLvls;
0528:                        } else {
0529:                            // Precinct partition is used
0530:                            for (int rl = 0; rl < numLvls; rl++) {
0531:                                maxpkt = numPrec[t][c][rl].x
0532:                                        * numPrec[t][c][rl].y;
0533:                                minlsz += MIN_AVG_PACKET_SZ * maxpkt;
0534:                            }
0535:                        }
0536:                    } // End loop on components
0537:                } // End loop on tiles
0538:
0539:                // Initialize layers
0540:                n = 0;
0541:                i = 0;
0542:                lastbytes = 0;
0543:
0544:                while (n < numLayers - 1) {
0545:                    // At an optimized layer
0546:                    basebytes = Math.floor(lyrSpec.getTargetBitrate(i) * np);
0547:                    if (i < lyrSpec.getNOptPoints() - 1) {
0548:                        nextbytes = (int) (lyrSpec.getTargetBitrate(i + 1) * np);
0549:                        // Limit target length to 'totenclength'
0550:                        if (nextbytes > totenclength)
0551:                            nextbytes = totenclength;
0552:                    } else {
0553:                        nextbytes = 1;
0554:                    }
0555:                    loopnlyrs = lyrSpec.getExtraLayers(i) + 1;
0556:                    ls = Math.exp(Math.log((double) nextbytes / basebytes)
0557:                            / loopnlyrs);
0558:                    layers[n].optimize = true;
0559:                    for (l = 0; l < loopnlyrs; l++) {
0560:                        newbytes = (int) basebytes - lastbytes - ho;
0561:                        if (newbytes < minlsz) { // Skip layer (too small)
0562:                            basebytes *= ls;
0563:                            numLayers--;
0564:                            continue;
0565:                        }
0566:                        lastbytes = (int) basebytes - ho;
0567:                        layers[n].maxBytes = lastbytes;
0568:                        basebytes *= ls;
0569:                        n++;
0570:                    }
0571:                    i++; // Goto next optimization point
0572:                }
0573:
0574:                // Ensure minimum size of last layer (this one determines overall
0575:                // bitrate)
0576:                n = numLayers - 2;
0577:                nextbytes = (int) (lyrSpec.getTotBitrate() * np) - ho;
0578:                newbytes = nextbytes - ((n >= 0) ? layers[n].maxBytes : 0);
0579:                while (newbytes < minlsz) {
0580:                    if (numLayers == 1) {
0581:                        if (newbytes <= 0) {
0582:                            throw new IllegalArgumentException(
0583:                                    "Overall target bitrate too "
0584:                                            + "low, given the current "
0585:                                            + "bit stream header overhead");
0586:                        }
0587:                        break;
0588:                    }
0589:                    // Delete last layer
0590:                    numLayers--;
0591:                    n--;
0592:                    newbytes = nextbytes - ((n >= 0) ? layers[n].maxBytes : 0);
0593:                }
0594:                // Set last layer to the overall target bitrate
0595:                n++;
0596:                layers[n].maxBytes = nextbytes;
0597:                layers[n].optimize = true;
0598:
0599:                // Re-initialize progression order changes if needed Default values
0600:                Progression[] prog1, prog2;
0601:                prog1 = (Progression[]) wp.getProgressionType().getDefault();
0602:                int nValidProg = prog1.length;
0603:                for (int prg = 0; prg < prog1.length; prg++) {
0604:                    if (prog1[prg].lye > numLayers) {
0605:                        prog1[prg].lye = numLayers;
0606:                    }
0607:                }
0608:                if (nValidProg == 0)
0609:                    throw new Error("Unable to initialize rate allocator: No "
0610:                            + "default progression type has been defined.");
0611:
0612:                // Tile specific values
0613:                for (int t = 0; t < numTiles; t++) {
0614:                    if (wp.getProgressionType().isTileSpecified(t)) {
0615:                        prog1 = (Progression[]) wp.getProgressionType()
0616:                                .getTileDef(t);
0617:                        nValidProg = prog1.length;
0618:                        for (int prg = 0; prg < prog1.length; prg++) {
0619:                            if (prog1[prg].lye > numLayers) {
0620:                                prog1[prg].lye = numLayers;
0621:                            }
0622:                        }
0623:                        if (nValidProg == 0)
0624:                            throw new Error(
0625:                                    "Unable to initialize rate allocator: No "
0626:                                            + "default progression type has been defined.");
0627:                    }
0628:                } // End loop on tiles
0629:
0630:                if (DO_TIMING)
0631:                    initTime += System.currentTimeMillis() - stime;
0632:            }
0633:
0634:            /**
0635:             * This method gets all the coded code-blocks from the EBCOT entropy coder
0636:             * for every component and every tile. Each coded code-block is stored in
0637:             * a 5D array according to the component, the resolution level, the tile,
0638:             * the subband it belongs and its position in the subband.
0639:             *
0640:             * <P> For each code-block, the valid slopes are computed and converted
0641:             * into the mantissa-exponent representation.
0642:             * */
0643:            private void getAllCodeBlocks() {
0644:
0645:                int numComps, numTiles, numBytes;
0646:                int c, r, t, s, sidx, k;
0647:                int slope;
0648:                SubbandAn subb;
0649:                CBlkRateDistStats ccb = null;
0650:                Point ncblks = null;
0651:                int last_sidx;
0652:                float fslope;
0653:
0654:                long stime = 0L;
0655:
0656:                maxSlope = 0f;
0657:                minSlope = Float.MAX_VALUE;
0658:
0659:                //Get the number of components and tiles
0660:                numComps = src.getNumComps();
0661:                numTiles = src.getNumTiles();
0662:
0663:                SubbandAn root, sb;
0664:                int cblkToEncode = 0;
0665:                int nEncCblk = 0;
0666:                ProgressWatch pw = FacilityManager.getProgressWatch();
0667:
0668:                //Get all coded code-blocks Goto first tile
0669:                src.setTile(0, 0);
0670:                for (t = 0; t < numTiles; t++) { //loop on tiles
0671:                    nEncCblk = 0;
0672:                    cblkToEncode = 0;
0673:                    for (c = 0; c < numComps; c++) {
0674:                        root = src.getAnSubbandTree(t, c);
0675:                        for (r = 0; r <= root.resLvl; r++) {
0676:                            if (r == 0) {
0677:                                sb = (SubbandAn) root.getSubbandByIdx(0, 0);
0678:                                if (sb != null)
0679:                                    cblkToEncode += sb.numCb.x * sb.numCb.y;
0680:                            } else {
0681:                                sb = (SubbandAn) root.getSubbandByIdx(r, 1);
0682:                                if (sb != null)
0683:                                    cblkToEncode += sb.numCb.x * sb.numCb.y;
0684:                                sb = (SubbandAn) root.getSubbandByIdx(r, 2);
0685:                                if (sb != null)
0686:                                    cblkToEncode += sb.numCb.x * sb.numCb.y;
0687:                                sb = (SubbandAn) root.getSubbandByIdx(r, 3);
0688:                                if (sb != null)
0689:                                    cblkToEncode += sb.numCb.x * sb.numCb.y;
0690:                            }
0691:                        }
0692:                    }
0693:                    if (pw != null) {
0694:                        pw.initProgressWatch(0, cblkToEncode, "Encoding tile "
0695:                                + t + "...");
0696:                    }
0697:
0698:                    for (c = 0; c < numComps; c++) { //loop on components
0699:
0700:                        //Get next coded code-block coordinates
0701:                        while ((ccb = src.getNextCodeBlock(c, ccb)) != null) {
0702:                            if (DO_TIMING)
0703:                                stime = System.currentTimeMillis();
0704:
0705:                            if (pw != null) {
0706:                                nEncCblk++;
0707:                                pw.updateProgressWatch(nEncCblk, null);
0708:                            }
0709:
0710:                            subb = ccb.sb;
0711:
0712:                            //Get the coded code-block resolution level index
0713:                            r = subb.resLvl;
0714:
0715:                            //Get the coded code-block subband index
0716:                            s = subb.sbandIdx;
0717:
0718:                            //Get the number of blocks in the current subband
0719:                            ncblks = subb.numCb;
0720:
0721:                            // Add code-block contribution to summary R-D table
0722:                            // RDSlopesRates
0723:                            last_sidx = -1;
0724:                            for (k = ccb.nVldTrunc - 1; k >= 0; k--) {
0725:                                fslope = ccb.truncSlopes[k];
0726:                                if (fslope > maxSlope)
0727:                                    maxSlope = fslope;
0728:                                if (fslope < minSlope)
0729:                                    minSlope = fslope;
0730:                                sidx = getLimitedSIndexFromSlope(fslope);
0731:                                for (; sidx > last_sidx; sidx--) {
0732:                                    RDSlopesRates[sidx] += ccb.truncRates[ccb.truncIdxs[k]];
0733:                                }
0734:                                last_sidx = getLimitedSIndexFromSlope(fslope);
0735:                            }
0736:
0737:                            //Fills code-blocks array
0738:                            cblks[t][c][r][s][(ccb.m * ncblks.x) + ccb.n] = ccb;
0739:                            ccb = null;
0740:
0741:                            if (DO_TIMING)
0742:                                initTime += System.currentTimeMillis() - stime;
0743:                        }
0744:                    }
0745:
0746:                    if (pw != null) {
0747:                        pw.terminateProgressWatch();
0748:                    }
0749:
0750:                    //Goto next tile
0751:                    if (t < numTiles - 1) //not at last tile
0752:                        src.nextTile();
0753:                }
0754:            }
0755:
0756:            /**
0757:             * This method builds all the bit stream layers and then writes them to
0758:             * the output bit stream. Firstly it builds all the layers by computing
0759:             * the threshold according to the layer target bit-rate, and then it
0760:             * writes the layer bit streams according to the Progression type.
0761:             * */
0762:            private void buildAndWriteLayers() throws IOException {
0763:                int nPrec = 0;
0764:                int maxBytes, actualBytes;
0765:                float rdThreshold;
0766:                SubbandAn sb;
0767:                float threshold;
0768:                BitOutputBuffer hBuff = null;
0769:                byte[] bBuff = null;
0770:                int[] tileLengths; // Length of each tile
0771:                int tmp;
0772:                boolean sopUsed; // Should SOP markers be used ?
0773:                boolean ephUsed; // Should EPH markers be used ?
0774:                int nc = src.getNumComps();
0775:                int nt = src.getNumTiles();
0776:                int mrl;
0777:
0778:                long stime = 0L;
0779:
0780:                if (DO_TIMING)
0781:                    stime = System.currentTimeMillis();
0782:
0783:                // Start with the maximum slope
0784:                rdThreshold = maxSlope;
0785:
0786:                tileLengths = new int[nt];
0787:                actualBytes = 0;
0788:
0789:                // +------------------------------+
0790:                // |  First we build the layers   |
0791:                // +------------------------------+
0792:                // Bitstream is simulated to know tile length
0793:                for (int l = 0; l < numLayers; l++) { //loop on layers
0794:
0795:                    maxBytes = layers[l].maxBytes;
0796:                    if (layers[l].optimize) {
0797:                        rdThreshold = optimizeBitstreamLayer(l, rdThreshold,
0798:                                maxBytes, actualBytes);
0799:                    } else {
0800:                        if (l <= 0 || l >= numLayers - 1) {
0801:                            throw new IllegalArgumentException(
0802:                                    "The first and the" + " last layer "
0803:                                            + "thresholds"
0804:                                            + " must be optimized");
0805:                        }
0806:                        rdThreshold = estimateLayerThreshold(maxBytes,
0807:                                layers[l - 1]);
0808:                    }
0809:
0810:                    for (int t = 0; t < nt; t++) { //loop on tiles
0811:                        if (l == 0) {
0812:                            // Tile header
0813:                            headEnc.reset();
0814:                            headEnc.encodeTilePartHeader(0, t);
0815:                            tileLengths[t] += headEnc.getLength();
0816:                        }
0817:
0818:                        for (int c = 0; c < nc; c++) { //loop on components
0819:
0820:                            // set boolean sopUsed here (SOP markers)
0821:                            sopUsed = ((String) wp.getSOP().getTileDef(t))
0822:                                    .equalsIgnoreCase("true");
0823:                            // set boolean ephUsed here (EPH markers)
0824:                            ephUsed = ((String) wp.getEPH().getTileDef(t))
0825:                                    .equalsIgnoreCase("true");
0826:
0827:                            // Go to LL band
0828:                            sb = src.getAnSubbandTree(t, c);
0829:                            mrl = sb.resLvl + 1;
0830:
0831:                            while (sb.subb_LL != null) {
0832:                                sb = sb.subb_LL;
0833:                            }
0834:
0835:                            for (int r = 0; r < mrl; r++) { // loop on resolution levels
0836:
0837:                                nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
0838:                                for (int p = 0; p < nPrec; p++) { // loop on precincts
0839:
0840:                                    findTruncIndices(l, c, r, t, sb,
0841:                                            rdThreshold, p);
0842:
0843:                                    hBuff = pktEnc.encodePacket(l + 1, c, r, t,
0844:                                            cblks[t][c][r],
0845:                                            truncIdxs[t][l][c][r], hBuff,
0846:                                            bBuff, p);
0847:                                    if (pktEnc.isPacketWritable()) {
0848:                                        tmp = bsWriter.writePacketHead(hBuff
0849:                                                .getBuffer(),
0850:                                                hBuff.getLength(), true,
0851:                                                sopUsed, ephUsed);
0852:                                        tmp += bsWriter.writePacketBody(pktEnc
0853:                                                .getLastBodyBuf(), pktEnc
0854:                                                .getLastBodyLen(), true, pktEnc
0855:                                                .isROIinPkt(), pktEnc
0856:                                                .getROILen());
0857:                                        actualBytes += tmp;
0858:                                        tileLengths[t] += tmp;
0859:                                    }
0860:                                } // End loop on precincts
0861:                                sb = sb.parent;
0862:                            } // End loop on resolution levels
0863:                        } // End loop on components
0864:                    } // end loop on tiles
0865:                    layers[l].rdThreshold = rdThreshold;
0866:                    layers[l].actualBytes = actualBytes;
0867:                } // end loop on layers
0868:
0869:                if (DO_TIMING)
0870:                    buildTime += System.currentTimeMillis() - stime;
0871:
0872:                // The bit-stream was not yet generated (only simulated).
0873:
0874:                if (DO_TIMING)
0875:                    stime = System.currentTimeMillis();
0876:
0877:                // +--------------------------------------------------+
0878:                // | Write tiles according to their Progression order |
0879:                // +--------------------------------------------------+
0880:                // Reset the packet encoder before writing all packets
0881:                pktEnc.reset();
0882:                Progression[] prog; // Progression(s) in each tile
0883:                int cs, ce, rs, re, lye;
0884:
0885:                int[] mrlc = new int[nc];
0886:                for (int t = 0; t < nt; t++) { //loop on tiles
0887:                    int[][] lysA; // layer index start for each component and
0888:                    // resolution level
0889:                    int[][] lys = new int[nc][];
0890:                    for (int c = 0; c < nc; c++) {
0891:                        mrlc[c] = src.getAnSubbandTree(t, c).resLvl;
0892:                        lys[c] = new int[mrlc[c] + 1];
0893:                    }
0894:
0895:                    // Tile header
0896:                    headEnc.reset();
0897:                    headEnc.encodeTilePartHeader(tileLengths[t], t);
0898:                    bsWriter.commitBitstreamHeader(headEnc);
0899:                    prog = (Progression[]) wp.getProgressionType()
0900:                            .getTileDef(t);
0901:
0902:                    for (int prg = 0; prg < prog.length; prg++) { // Loop on progression
0903:                        lye = prog[prg].lye;
0904:                        cs = prog[prg].cs;
0905:                        ce = prog[prg].ce;
0906:                        rs = prog[prg].rs;
0907:                        re = prog[prg].re;
0908:
0909:                        switch (prog[prg].type) {
0910:                        case ProgressionType.RES_LY_COMP_POS_PROG:
0911:                            writeResLyCompPos(t, rs, re, cs, ce, lys, lye);
0912:                            break;
0913:                        case ProgressionType.LY_RES_COMP_POS_PROG:
0914:                            writeLyResCompPos(t, rs, re, cs, ce, lys, lye);
0915:                            break;
0916:                        case ProgressionType.POS_COMP_RES_LY_PROG:
0917:                            writePosCompResLy(t, rs, re, cs, ce, lys, lye);
0918:                            break;
0919:                        case ProgressionType.COMP_POS_RES_LY_PROG:
0920:                            writeCompPosResLy(t, rs, re, cs, ce, lys, lye);
0921:                            break;
0922:                        case ProgressionType.RES_POS_COMP_LY_PROG:
0923:                            writeResPosCompLy(t, rs, re, cs, ce, lys, lye);
0924:                            break;
0925:                        default:
0926:                            throw new Error(
0927:                                    "Unsupported bit stream progression type");
0928:                        } // switch on progression
0929:
0930:                        // Update next first layer index 
0931:                        for (int c = cs; c < ce; c++)
0932:                            for (int r = rs; r < re; r++) {
0933:                                if (r > mrlc[c])
0934:                                    continue;
0935:                                lys[c][r] = lye;
0936:                            }
0937:                    } // End loop on progression
0938:                } // End loop on tiles
0939:
0940:                if (DO_TIMING)
0941:                    writeTime += System.currentTimeMillis() - stime;
0942:            }
0943:
0944:            /** 
0945:             * Write a piece of bit stream according to the
0946:             * RES_LY_COMP_POS_PROG progression mode and between given bounds
0947:             *
0948:             * @param t Tile index.
0949:             *
0950:             * @param rs First resolution level index.
0951:             *
0952:             * @param re Last resolution level index.
0953:             *
0954:             * @param cs First component index.
0955:             *
0956:             * @param ce Last component index.
0957:             *
0958:             * @param lys First layer index for each component and resolution.
0959:             *
0960:             * @param lye Index of the last layer.
0961:             * */
0962:            public void writeResLyCompPos(int t, int rs, int re, int cs,
0963:                    int ce, int lys[][], int lye) throws IOException {
0964:
0965:                boolean sopUsed; // Should SOP markers be used ?
0966:                boolean ephUsed; // Should EPH markers be used ?
0967:                int nc = src.getNumComps();
0968:                int[] mrl = new int[nc];
0969:                SubbandAn sb;
0970:                float threshold;
0971:                BitOutputBuffer hBuff = null;
0972:                byte[] bBuff = null;
0973:                int nPrec = 0;
0974:
0975:                // Max number of resolution levels in the tile
0976:                int maxResLvl = 0;
0977:                for (int c = 0; c < nc; c++) {
0978:                    mrl[c] = src.getAnSubbandTree(t, c).resLvl;
0979:                    if (mrl[c] > maxResLvl)
0980:                        maxResLvl = mrl[c];
0981:                }
0982:
0983:                int minlys; // minimum layer start index of each component
0984:
0985:                for (int r = rs; r < re; r++) { //loop on resolution levels
0986:                    if (r > maxResLvl)
0987:                        continue;
0988:
0989:                    minlys = 100000;
0990:                    for (int c = cs; c < ce; c++) {
0991:                        if (r < lys[c].length && lys[c][r] < minlys) {
0992:                            minlys = lys[c][r];
0993:                        }
0994:                    }
0995:
0996:                    for (int l = minlys; l < lye; l++) { //loop on layers
0997:                        for (int c = cs; c < ce; c++) {//loop on components
0998:                            if (r >= lys[c].length)
0999:                                continue;
1000:                            if (l < lys[c][r])
1001:                                continue;
1002:
1003:                            // If no more decomposition levels for this component
1004:                            if (r > mrl[c])
1005:                                continue;
1006:
1007:                            nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
1008:                            for (int p = 0; p < nPrec; p++) { // loop on precincts
1009:
1010:                                // set boolean sopUsed here (SOP markers)
1011:                                sopUsed = ((String) wp.getSOP().getTileDef(t))
1012:                                        .equals("true");
1013:                                // set boolean ephUsed here (EPH markers)
1014:                                ephUsed = ((String) wp.getEPH().getTileDef(t))
1015:                                        .equals("true");
1016:
1017:                                sb = src.getAnSubbandTree(t, c);
1018:                                for (int i = mrl[c]; i > r; i--) {
1019:                                    sb = sb.subb_LL;
1020:                                }
1021:
1022:                                threshold = layers[l].rdThreshold;
1023:                                findTruncIndices(l, c, r, t, sb, threshold, p);
1024:
1025:                                hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1026:                                        cblks[t][c][r], truncIdxs[t][l][c][r],
1027:                                        hBuff, bBuff, p);
1028:
1029:                                if (pktEnc.isPacketWritable()) {
1030:                                    bsWriter.writePacketHead(hBuff.getBuffer(),
1031:                                            hBuff.getLength(), false, sopUsed,
1032:                                            ephUsed);
1033:                                    bsWriter.writePacketBody(pktEnc
1034:                                            .getLastBodyBuf(), pktEnc
1035:                                            .getLastBodyLen(), false, pktEnc
1036:                                            .isROIinPkt(), pktEnc.getROILen());
1037:                                }
1038:
1039:                            } // End loop on precincts
1040:                        } // End loop on components
1041:                    } // End loop on layers
1042:                } // End loop on resolution levels
1043:            }
1044:
1045:            /** 
1046:             * Write a piece of bit stream according to the
1047:             * LY_RES_COMP_POS_PROG progression mode and between given bounds
1048:             *
1049:             * @param t Tile index.
1050:             *
1051:             * @param rs First resolution level index.
1052:             *
1053:             * @param re Last resolution level index.
1054:             *
1055:             * @param cs First component index.
1056:             *
1057:             * @param ce Last component index.
1058:             *
1059:             * @param lys First layer index for each component and resolution.
1060:             *
1061:             * @param lye Index of the last layer.
1062:             * */
1063:            public void writeLyResCompPos(int t, int rs, int re, int cs,
1064:                    int ce, int[][] lys, int lye) throws IOException {
1065:
1066:                boolean sopUsed; // Should SOP markers be used ?
1067:                boolean ephUsed; // Should EPH markers be used ?
1068:                int nc = src.getNumComps();
1069:                int mrl;
1070:                SubbandAn sb;
1071:                float threshold;
1072:                BitOutputBuffer hBuff = null;
1073:                byte[] bBuff = null;
1074:                int nPrec = 0;
1075:
1076:                int minlys = 100000; // minimum layer start index of each component
1077:                for (int c = cs; c < ce; c++) {
1078:                    for (int r = 0; r < lys.length; r++) {
1079:                        if (lys[c] != null && r < lys[c].length
1080:                                && lys[c][r] < minlys) {
1081:                            minlys = lys[c][r];
1082:                        }
1083:                    }
1084:                }
1085:
1086:                for (int l = minlys; l < lye; l++) { // loop on layers
1087:                    for (int r = rs; r < re; r++) { // loop on resolution level
1088:                        for (int c = cs; c < ce; c++) { // loop on components
1089:                            mrl = src.getAnSubbandTree(t, c).resLvl;
1090:                            if (r > mrl)
1091:                                continue;
1092:                            if (r >= lys[c].length)
1093:                                continue;
1094:                            if (l < lys[c][r])
1095:                                continue;
1096:                            nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
1097:                            for (int p = 0; p < nPrec; p++) { // loop on precincts
1098:
1099:                                // set boolean sopUsed here (SOP markers)
1100:                                sopUsed = ((String) wp.getSOP().getTileDef(t))
1101:                                        .equals("true");
1102:                                // set boolean ephUsed here (EPH markers)
1103:                                ephUsed = ((String) wp.getEPH().getTileDef(t))
1104:                                        .equals("true");
1105:
1106:                                sb = src.getAnSubbandTree(t, c);
1107:                                for (int i = mrl; i > r; i--) {
1108:                                    sb = sb.subb_LL;
1109:                                }
1110:
1111:                                threshold = layers[l].rdThreshold;
1112:                                findTruncIndices(l, c, r, t, sb, threshold, p);
1113:
1114:                                hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1115:                                        cblks[t][c][r], truncIdxs[t][l][c][r],
1116:                                        hBuff, bBuff, p);
1117:
1118:                                if (pktEnc.isPacketWritable()) {
1119:                                    bsWriter.writePacketHead(hBuff.getBuffer(),
1120:                                            hBuff.getLength(), false, sopUsed,
1121:                                            ephUsed);
1122:                                    bsWriter.writePacketBody(pktEnc
1123:                                            .getLastBodyBuf(), pktEnc
1124:                                            .getLastBodyLen(), false, pktEnc
1125:                                            .isROIinPkt(), pktEnc.getROILen());
1126:                                }
1127:                            } // end loop on precincts
1128:                        } // end loop on components
1129:                    } // end loop on resolution levels
1130:                } // end loop on layers
1131:            }
1132:
1133:            /** 
1134:             * Write a piece of bit stream according to the
1135:             * COMP_POS_RES_LY_PROG progression mode and between given bounds
1136:             *
1137:             * @param t Tile index.
1138:             *
1139:             * @param rs First resolution level index.
1140:             *
1141:             * @param re Last resolution level index.
1142:             *
1143:             * @param cs First component index.
1144:             *
1145:             * @param ce Last component index.
1146:             *
1147:             * @param lys First layer index for each component and resolution.
1148:             *
1149:             * @param lye Index of the last layer.
1150:             * */
1151:            public void writePosCompResLy(int t, int rs, int re, int cs,
1152:                    int ce, int[][] lys, int lye) throws IOException {
1153:
1154:                boolean sopUsed; // Should SOP markers be used ?
1155:                boolean ephUsed; // Should EPH markers be used ?
1156:                int nc = src.getNumComps();
1157:                int mrl;
1158:                SubbandAn sb;
1159:                float threshold;
1160:                BitOutputBuffer hBuff = null;
1161:                byte[] bBuff = null;
1162:
1163:                // Computes current tile offset in the reference grid
1164:                Point nTiles = src.getNumTiles(null);
1165:                Point tileI = src.getTile(null);
1166:                int x0siz = src.getImgULX();
1167:                int y0siz = src.getImgULY();
1168:                int xsiz = x0siz + src.getImgWidth();
1169:                int ysiz = y0siz + src.getImgHeight();
1170:                int xt0siz = src.getTilePartULX();
1171:                int yt0siz = src.getTilePartULY();
1172:                int xtsiz = src.getNomTileWidth();
1173:                int ytsiz = src.getNomTileHeight();
1174:                int tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
1175:                int ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
1176:                int tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
1177:                        * xtsiz : xsiz;
1178:                int ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
1179:                        * ytsiz : ysiz;
1180:
1181:                // Get precinct information (number,distance between two consecutive
1182:                // precincts in the reference grid) in each component and resolution
1183:                // level
1184:                PrecInfo prec; // temporary variable
1185:                int p; // Current precinct index
1186:                int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1187:                int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1188:                int nPrec = 0; // Total number of found precincts
1189:                int[][] nextPrec = new int[ce][]; // Next precinct index in each
1190:                // component and resolution level
1191:                int minlys = 100000; // minimum layer start index of each component
1192:                int minx = tx1; // Horiz. offset of the second precinct in the
1193:                // reference grid
1194:                int miny = ty1; // Vert. offset of the second precinct in the
1195:                // reference grid. 
1196:                int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1197:                int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1198:                for (int c = cs; c < ce; c++) {
1199:                    mrl = src.getAnSubbandTree(t, c).resLvl;
1200:                    nextPrec[c] = new int[mrl + 1];
1201:                    for (int r = rs; r < re; r++) {
1202:                        if (r > mrl)
1203:                            continue;
1204:                        if (r < lys[c].length && lys[c][r] < minlys) {
1205:                            minlys = lys[c][r];
1206:                        }
1207:                        p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
1208:                        for (; p >= 0; p--) {
1209:                            prec = pktEnc.getPrecInfo(t, c, r, p);
1210:                            if (prec.rgulx != tx0) {
1211:                                if (prec.rgulx < minx)
1212:                                    minx = prec.rgulx;
1213:                                if (prec.rgulx > maxx)
1214:                                    maxx = prec.rgulx;
1215:                            }
1216:                            if (prec.rguly != ty0) {
1217:                                if (prec.rguly < miny)
1218:                                    miny = prec.rguly;
1219:                                if (prec.rguly > maxy)
1220:                                    maxy = prec.rguly;
1221:                            }
1222:
1223:                            if (nPrec == 0) {
1224:                                gcd_x = prec.rgw;
1225:                                gcd_y = prec.rgh;
1226:                            } else {
1227:                                gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
1228:                                gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
1229:                            }
1230:                            nPrec++;
1231:                        } // precincts
1232:                    } // resolution levels
1233:                } // components
1234:                if (nPrec == 0) {
1235:                    throw new Error("Image cannot have no precinct");
1236:                }
1237:
1238:                int pyend = (maxy - miny) / gcd_y + 1;
1239:                int pxend = (maxx - minx) / gcd_x + 1;
1240:                int y = ty0;
1241:                int x = tx0;
1242:                for (int py = 0; py <= pyend; py++) { // Vertical precincts
1243:                    for (int px = 0; px <= pxend; px++) { // Horiz. precincts
1244:                        for (int c = cs; c < ce; c++) { // Components
1245:                            mrl = src.getAnSubbandTree(t, c).resLvl;
1246:                            for (int r = rs; r < re; r++) { // Resolution levels
1247:                                if (r > mrl)
1248:                                    continue;
1249:                                if (nextPrec[c][r] >= numPrec[t][c][r].x
1250:                                        * numPrec[t][c][r].y) {
1251:                                    continue;
1252:                                }
1253:                                prec = pktEnc.getPrecInfo(t, c, r,
1254:                                        nextPrec[c][r]);
1255:                                if ((prec.rgulx != x) || (prec.rguly != y)) {
1256:                                    continue;
1257:                                }
1258:                                for (int l = minlys; l < lye; l++) { // Layers
1259:                                    if (r >= lys[c].length)
1260:                                        continue;
1261:                                    if (l < lys[c][r])
1262:                                        continue;
1263:
1264:                                    // set boolean sopUsed here (SOP markers)
1265:                                    sopUsed = ((String) wp.getSOP().getTileDef(
1266:                                            t)).equals("true");
1267:                                    // set boolean ephUsed here (EPH markers)
1268:                                    ephUsed = ((String) wp.getEPH().getTileDef(
1269:                                            t)).equals("true");
1270:
1271:                                    sb = src.getAnSubbandTree(t, c);
1272:                                    for (int i = mrl; i > r; i--) {
1273:                                        sb = sb.subb_LL;
1274:                                    }
1275:
1276:                                    threshold = layers[l].rdThreshold;
1277:                                    findTruncIndices(l, c, r, t, sb, threshold,
1278:                                            nextPrec[c][r]);
1279:
1280:                                    hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1281:                                            cblks[t][c][r],
1282:                                            truncIdxs[t][l][c][r], hBuff,
1283:                                            bBuff, nextPrec[c][r]);
1284:
1285:                                    if (pktEnc.isPacketWritable()) {
1286:                                        bsWriter.writePacketHead(hBuff
1287:                                                .getBuffer(),
1288:                                                hBuff.getLength(), false,
1289:                                                sopUsed, ephUsed);
1290:                                        bsWriter.writePacketBody(pktEnc
1291:                                                .getLastBodyBuf(), pktEnc
1292:                                                .getLastBodyLen(), false,
1293:                                                pktEnc.isROIinPkt(), pktEnc
1294:                                                        .getROILen());
1295:                                    }
1296:                                } // layers
1297:                                nextPrec[c][r]++;
1298:                            } // Resolution levels
1299:                        } // Components
1300:                        if (px != pxend) {
1301:                            x = minx + px * gcd_x;
1302:                        } else {
1303:                            x = tx0;
1304:                        }
1305:                    } // Horizontal precincts
1306:                    if (py != pyend) {
1307:                        y = miny + py * gcd_y;
1308:                    } else {
1309:                        y = ty0;
1310:                    }
1311:                } // Vertical precincts
1312:
1313:                // Check that all precincts have been written
1314:                for (int c = cs; c < ce; c++) {
1315:                    mrl = src.getAnSubbandTree(t, c).resLvl;
1316:                    for (int r = rs; r < re; r++) {
1317:                        if (r > mrl)
1318:                            continue;
1319:                        if (nextPrec[c][r] < numPrec[t][c][r].x
1320:                                * numPrec[t][c][r].y - 1) {
1321:                            throw new Error(
1322:                                    "JJ2000 bug: One precinct at least has "
1323:                                            + "not been written for resolution level "
1324:                                            + r + " of component " + c
1325:                                            + " in tile " + t + ".");
1326:                        }
1327:                    }
1328:                }
1329:            }
1330:
1331:            /** 
1332:             * Write a piece of bit stream according to the
1333:             * COMP_POS_RES_LY_PROG progression mode and between given bounds
1334:             *
1335:             * @param t Tile index.
1336:             *
1337:             * @param rs First resolution level index.
1338:             *
1339:             * @param re Last resolution level index.
1340:             *
1341:             * @param cs First component index.
1342:             *
1343:             * @param ce Last component index.
1344:             *
1345:             * @param lys First layer index for each component and resolution.
1346:             *
1347:             * @param lye Index of the last layer.
1348:             * */
1349:            public void writeCompPosResLy(int t, int rs, int re, int cs,
1350:                    int ce, int[][] lys, int lye) throws IOException {
1351:
1352:                boolean sopUsed; // Should SOP markers be used ?
1353:                boolean ephUsed; // Should EPH markers be used ?
1354:                int nc = src.getNumComps();
1355:                int mrl;
1356:                SubbandAn sb;
1357:                float threshold;
1358:                BitOutputBuffer hBuff = null;
1359:                byte[] bBuff = null;
1360:
1361:                // Computes current tile offset in the reference grid
1362:                Point nTiles = src.getNumTiles(null);
1363:                Point tileI = src.getTile(null);
1364:                int x0siz = src.getImgULX();
1365:                int y0siz = src.getImgULY();
1366:                int xsiz = x0siz + src.getImgWidth();
1367:                int ysiz = y0siz + src.getImgHeight();
1368:                int xt0siz = src.getTilePartULX();
1369:                int yt0siz = src.getTilePartULY();
1370:                int xtsiz = src.getNomTileWidth();
1371:                int ytsiz = src.getNomTileHeight();
1372:                int tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
1373:                int ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
1374:                int tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
1375:                        * xtsiz : xsiz;
1376:                int ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
1377:                        * ytsiz : ysiz;
1378:
1379:                // Get precinct information (number,distance between two consecutive
1380:                // precincts in the reference grid) in each component and resolution
1381:                // level
1382:                PrecInfo prec; // temporary variable
1383:                int p; // Current precinct index
1384:                int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1385:                int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1386:                int nPrec = 0; // Total number of found precincts
1387:                int[][] nextPrec = new int[ce][]; // Next precinct index in each
1388:                // component and resolution level
1389:                int minlys = 100000; // minimum layer start index of each component
1390:                int minx = tx1; // Horiz. offset of the second precinct in the
1391:                // reference grid
1392:                int miny = ty1; // Vert. offset of the second precinct in the
1393:                // reference grid. 
1394:                int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1395:                int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1396:                for (int c = cs; c < ce; c++) {
1397:                    mrl = src.getAnSubbandTree(t, c).resLvl;
1398:                    for (int r = rs; r < re; r++) {
1399:                        if (r > mrl)
1400:                            continue;
1401:                        nextPrec[c] = new int[mrl + 1];
1402:                        if (r < lys[c].length && lys[c][r] < minlys) {
1403:                            minlys = lys[c][r];
1404:                        }
1405:                        p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
1406:                        for (; p >= 0; p--) {
1407:                            prec = pktEnc.getPrecInfo(t, c, r, p);
1408:                            if (prec.rgulx != tx0) {
1409:                                if (prec.rgulx < minx)
1410:                                    minx = prec.rgulx;
1411:                                if (prec.rgulx > maxx)
1412:                                    maxx = prec.rgulx;
1413:                            }
1414:                            if (prec.rguly != ty0) {
1415:                                if (prec.rguly < miny)
1416:                                    miny = prec.rguly;
1417:                                if (prec.rguly > maxy)
1418:                                    maxy = prec.rguly;
1419:                            }
1420:
1421:                            if (nPrec == 0) {
1422:                                gcd_x = prec.rgw;
1423:                                gcd_y = prec.rgh;
1424:                            } else {
1425:                                gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
1426:                                gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
1427:                            }
1428:                            nPrec++;
1429:                        } // precincts
1430:                    } // resolution levels
1431:                } // components
1432:                if (nPrec == 0) {
1433:                    throw new Error("Image cannot have no precinct");
1434:                }
1435:
1436:                int pyend = (maxy - miny) / gcd_y + 1;
1437:                int pxend = (maxx - minx) / gcd_x + 1;
1438:                int y;
1439:                int x;
1440:                for (int c = cs; c < ce; c++) { // Loop on components
1441:                    y = ty0;
1442:                    x = tx0;
1443:                    mrl = src.getAnSubbandTree(t, c).resLvl;
1444:                    for (int py = 0; py <= pyend; py++) { // Vertical precincts
1445:                        for (int px = 0; px <= pxend; px++) { // Horiz. precincts
1446:                            for (int r = rs; r < re; r++) { // Resolution levels
1447:                                if (r > mrl)
1448:                                    continue;
1449:                                if (nextPrec[c][r] >= numPrec[t][c][r].x
1450:                                        * numPrec[t][c][r].y) {
1451:                                    continue;
1452:                                }
1453:                                prec = pktEnc.getPrecInfo(t, c, r,
1454:                                        nextPrec[c][r]);
1455:                                if ((prec.rgulx != x) || (prec.rguly != y)) {
1456:                                    continue;
1457:                                }
1458:
1459:                                for (int l = minlys; l < lye; l++) { // Layers
1460:                                    if (r >= lys[c].length)
1461:                                        continue;
1462:                                    if (l < lys[c][r])
1463:                                        continue;
1464:
1465:                                    // set boolean sopUsed here (SOP markers)
1466:                                    sopUsed = ((String) wp.getSOP().getTileDef(
1467:                                            t)).equals("true");
1468:                                    // set boolean ephUsed here (EPH markers)
1469:                                    ephUsed = ((String) wp.getEPH().getTileDef(
1470:                                            t)).equals("true");
1471:
1472:                                    sb = src.getAnSubbandTree(t, c);
1473:                                    for (int i = mrl; i > r; i--) {
1474:                                        sb = sb.subb_LL;
1475:                                    }
1476:
1477:                                    threshold = layers[l].rdThreshold;
1478:                                    findTruncIndices(l, c, r, t, sb, threshold,
1479:                                            nextPrec[c][r]);
1480:
1481:                                    hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1482:                                            cblks[t][c][r],
1483:                                            truncIdxs[t][l][c][r], hBuff,
1484:                                            bBuff, nextPrec[c][r]);
1485:
1486:                                    if (pktEnc.isPacketWritable()) {
1487:                                        bsWriter.writePacketHead(hBuff
1488:                                                .getBuffer(),
1489:                                                hBuff.getLength(), false,
1490:                                                sopUsed, ephUsed);
1491:                                        bsWriter.writePacketBody(pktEnc
1492:                                                .getLastBodyBuf(), pktEnc
1493:                                                .getLastBodyLen(), false,
1494:                                                pktEnc.isROIinPkt(), pktEnc
1495:                                                        .getROILen());
1496:                                    }
1497:
1498:                                } // Layers
1499:                                nextPrec[c][r]++;
1500:                            } // Resolution levels                    
1501:                            if (px != pxend) {
1502:                                x = minx + px * gcd_x;
1503:                            } else {
1504:                                x = tx0;
1505:                            }
1506:                        } // Horizontal precincts
1507:                        if (py != pyend) {
1508:                            y = miny + py * gcd_y;
1509:                        } else {
1510:                            y = ty0;
1511:                        }
1512:                    } // Vertical precincts
1513:                } // components
1514:
1515:                // Check that all precincts have been written
1516:                for (int c = cs; c < ce; c++) {
1517:                    mrl = src.getAnSubbandTree(t, c).resLvl;
1518:                    for (int r = rs; r < re; r++) {
1519:                        if (r > mrl)
1520:                            continue;
1521:                        if (nextPrec[c][r] < numPrec[t][c][r].x
1522:                                * numPrec[t][c][r].y - 1) {
1523:                            throw new Error(
1524:                                    "JJ2000 bug: One precinct at least has "
1525:                                            + "not been written for resolution level "
1526:                                            + r + " of component " + c
1527:                                            + " in tile " + t + ".");
1528:                        }
1529:                    }
1530:                }
1531:            }
1532:
1533:            /** 
1534:             * Write a piece of bit stream according to the
1535:             * RES_POS_COMP_LY_PROG progression mode and between given bounds
1536:             *
1537:             * @param t Tile index.
1538:             *
1539:             * @param rs First resolution level index.
1540:             *
1541:             * @param re Last resolution level index.
1542:             *
1543:             * @param cs First component index.
1544:             *
1545:             * @param ce Last component index.
1546:             *
1547:             * @param lys First layer index for each component and resolution.
1548:             *
1549:             * @param lye Last layer index.
1550:             * */
1551:            public void writeResPosCompLy(int t, int rs, int re, int cs,
1552:                    int ce, int[][] lys, int lye) throws IOException {
1553:
1554:                boolean sopUsed; // Should SOP markers be used ?
1555:                boolean ephUsed; // Should EPH markers be used ?
1556:                int nc = src.getNumComps();
1557:                int mrl;
1558:                SubbandAn sb;
1559:                float threshold;
1560:                BitOutputBuffer hBuff = null;
1561:                byte[] bBuff = null;
1562:
1563:                // Computes current tile offset in the reference grid
1564:                Point nTiles = src.getNumTiles(null);
1565:                Point tileI = src.getTile(null);
1566:                int x0siz = src.getImgULX();
1567:                int y0siz = src.getImgULY();
1568:                int xsiz = x0siz + src.getImgWidth();
1569:                int ysiz = y0siz + src.getImgHeight();
1570:                int xt0siz = src.getTilePartULX();
1571:                int yt0siz = src.getTilePartULY();
1572:                int xtsiz = src.getNomTileWidth();
1573:                int ytsiz = src.getNomTileHeight();
1574:                int tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
1575:                int ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
1576:                int tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1)
1577:                        * xtsiz : xsiz;
1578:                int ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1)
1579:                        * ytsiz : ysiz;
1580:
1581:                // Get precinct information (number,distance between two consecutive
1582:                // precincts in the reference grid) in each component and resolution
1583:                // level
1584:                PrecInfo prec; // temporary variable
1585:                int p; // Current precinct index
1586:                int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
1587:                int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
1588:                int nPrec = 0; // Total number of found precincts
1589:                int[][] nextPrec = new int[ce][]; // Next precinct index in each
1590:                // component and resolution level
1591:                int minlys = 100000; // minimum layer start index of each component
1592:                int minx = tx1; // Horiz. offset of the second precinct in the
1593:                // reference grid
1594:                int miny = ty1; // Vert. offset of the second precinct in the
1595:                // reference grid. 
1596:                int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
1597:                int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
1598:                for (int c = cs; c < ce; c++) {
1599:                    mrl = src.getAnSubbandTree(t, c).resLvl;
1600:                    nextPrec[c] = new int[mrl + 1];
1601:                    for (int r = rs; r < re; r++) {
1602:                        if (r > mrl)
1603:                            continue;
1604:                        if (r < lys[c].length && lys[c][r] < minlys) {
1605:                            minlys = lys[c][r];
1606:                        }
1607:                        p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1;
1608:                        for (; p >= 0; p--) {
1609:                            prec = pktEnc.getPrecInfo(t, c, r, p);
1610:                            if (prec.rgulx != tx0) {
1611:                                if (prec.rgulx < minx)
1612:                                    minx = prec.rgulx;
1613:                                if (prec.rgulx > maxx)
1614:                                    maxx = prec.rgulx;
1615:                            }
1616:                            if (prec.rguly != ty0) {
1617:                                if (prec.rguly < miny)
1618:                                    miny = prec.rguly;
1619:                                if (prec.rguly > maxy)
1620:                                    maxy = prec.rguly;
1621:                            }
1622:
1623:                            if (nPrec == 0) {
1624:                                gcd_x = prec.rgw;
1625:                                gcd_y = prec.rgh;
1626:                            } else {
1627:                                gcd_x = MathUtil.gcd(gcd_x, prec.rgw);
1628:                                gcd_y = MathUtil.gcd(gcd_y, prec.rgh);
1629:                            }
1630:                            nPrec++;
1631:                        } // precincts
1632:                    } // resolution levels
1633:                } // components
1634:
1635:                if (nPrec == 0) {
1636:                    throw new Error("Image cannot have no precinct");
1637:                }
1638:
1639:                int pyend = (maxy - miny) / gcd_y + 1;
1640:                int pxend = (maxx - minx) / gcd_x + 1;
1641:                int x, y;
1642:                for (int r = rs; r < re; r++) { // Resolution levels
1643:                    y = ty0;
1644:                    x = tx0;
1645:                    for (int py = 0; py <= pyend; py++) { // Vertical precincts
1646:                        for (int px = 0; px <= pxend; px++) { // Horiz. precincts
1647:                            for (int c = cs; c < ce; c++) { // Components
1648:                                mrl = src.getAnSubbandTree(t, c).resLvl;
1649:                                if (r > mrl)
1650:                                    continue;
1651:                                if (nextPrec[c][r] >= numPrec[t][c][r].x
1652:                                        * numPrec[t][c][r].y) {
1653:                                    continue;
1654:                                }
1655:                                prec = pktEnc.getPrecInfo(t, c, r,
1656:                                        nextPrec[c][r]);
1657:                                if ((prec.rgulx != x) || (prec.rguly != y)) {
1658:                                    continue;
1659:                                }
1660:                                for (int l = minlys; l < lye; l++) {
1661:                                    if (r >= lys[c].length)
1662:                                        continue;
1663:                                    if (l < lys[c][r])
1664:                                        continue;
1665:
1666:                                    // set boolean sopUsed here (SOP markers)
1667:                                    sopUsed = ((String) wp.getSOP().getTileDef(
1668:                                            t)).equals("true");
1669:                                    // set boolean ephUsed here (EPH markers)
1670:                                    ephUsed = ((String) wp.getEPH().getTileDef(
1671:                                            t)).equals("true");
1672:
1673:                                    sb = src.getAnSubbandTree(t, c);
1674:                                    for (int i = mrl; i > r; i--) {
1675:                                        sb = sb.subb_LL;
1676:                                    }
1677:
1678:                                    threshold = layers[l].rdThreshold;
1679:                                    findTruncIndices(l, c, r, t, sb, threshold,
1680:                                            nextPrec[c][r]);
1681:
1682:                                    hBuff = pktEnc.encodePacket(l + 1, c, r, t,
1683:                                            cblks[t][c][r],
1684:                                            truncIdxs[t][l][c][r], hBuff,
1685:                                            bBuff, nextPrec[c][r]);
1686:
1687:                                    if (pktEnc.isPacketWritable()) {
1688:                                        bsWriter.writePacketHead(hBuff
1689:                                                .getBuffer(),
1690:                                                hBuff.getLength(), false,
1691:                                                sopUsed, ephUsed);
1692:                                        bsWriter.writePacketBody(pktEnc
1693:                                                .getLastBodyBuf(), pktEnc
1694:                                                .getLastBodyLen(), false,
1695:                                                pktEnc.isROIinPkt(), pktEnc
1696:                                                        .getROILen());
1697:                                    }
1698:
1699:                                } // layers
1700:                                nextPrec[c][r]++;
1701:                            } // Components
1702:                            if (px != pxend) {
1703:                                x = minx + px * gcd_x;
1704:                            } else {
1705:                                x = tx0;
1706:                            }
1707:                        } // Horizontal precincts
1708:                        if (py != pyend) {
1709:                            y = miny + py * gcd_y;
1710:                        } else {
1711:                            y = ty0;
1712:                        }
1713:                    } // Vertical precincts
1714:                } // Resolution levels
1715:
1716:                // Check that all precincts have been written
1717:                for (int c = cs; c < ce; c++) {
1718:                    mrl = src.getAnSubbandTree(t, c).resLvl;
1719:                    for (int r = rs; r < re; r++) {
1720:                        if (r > mrl)
1721:                            continue;
1722:                        if (nextPrec[c][r] < numPrec[t][c][r].x
1723:                                * numPrec[t][c][r].y - 1) {
1724:                            throw new Error(
1725:                                    "JJ2000 bug: One precinct at least has "
1726:                                            + "not been written for resolution level "
1727:                                            + r + " of component " + c
1728:                                            + " in tile " + t + ".");
1729:                        }
1730:                    }
1731:                }
1732:            }
1733:
1734:            /**
1735:             * This function implements the rate-distortion optimization algorithm.
1736:             * It saves the state of any previously generated bit-stream layers and
1737:             * then simulate the formation of a new layer in the bit stream as often
1738:             * as necessary to find the smallest rate-distortion threshold such that
1739:             * the total number of bytes required to represent the layer does not
1740:             * exceed `maxBytes' minus `prevBytes'.  It then restores the state of any
1741:             * previously generated bit-stream layers and returns the threshold.
1742:             *
1743:             * @param layerIdx The index of the current layer
1744:             *
1745:             * @param fmaxt The maximum admissible slope value. Normally the threshold
1746:             * slope of the previous layer.
1747:             *
1748:             * @param maxBytes The maximum number of bytes that can be written. It
1749:             * includes the length of the current layer bistream length and all the
1750:             * previous layers bit streams.
1751:             *
1752:             * @param prevBytes The number of bytes of all the previous layers.
1753:             *
1754:             * @return The value of the slope threshold.
1755:             * */
1756:            private float optimizeBitstreamLayer(int layerIdx, float fmaxt,
1757:                    int maxBytes, int prevBytes) throws IOException {
1758:
1759:                int nt; // The total number of tiles
1760:                int nc; // The total number of components
1761:                int numLvls; // The total number of resolution levels
1762:                int actualBytes; // Actual number of bytes for a layer
1763:                float fmint; // Minimum of the current threshold interval
1764:                float ft; // Current threshold
1765:                SubbandAn sb; // Current subband
1766:                BitOutputBuffer hBuff;// The packet head buffer
1767:                byte[] bBuff; // The packet body buffer
1768:                int sidx; // The index in the summary table
1769:                boolean sopUsed; // Should SOP markers be used ?
1770:                boolean ephUsed; // Should EPH markers be used ?
1771:                int precinctIdx; // Precinct index for current packet
1772:                int nPrec; // Number of precincts in the current resolution level
1773:
1774:                // Save the packet encoder state
1775:                pktEnc.save();
1776:
1777:                nt = src.getNumTiles();
1778:                nc = src.getNumComps();
1779:                hBuff = null;
1780:                bBuff = null;
1781:
1782:                // Estimate the minimum slope to start with from the summary
1783:                // information in 'RDSlopesRates'. This is a real minimum since it
1784:                // does not include the packet head overhead, which is always
1785:                // non-zero.
1786:
1787:                // Look for the summary entry that gives 'maxBytes' or more data
1788:                for (sidx = RD_SUMMARY_SIZE - 1; sidx > 0; sidx--) {
1789:                    if (RDSlopesRates[sidx] >= maxBytes) {
1790:                        break;
1791:                    }
1792:                }
1793:                // Get the corresponding minimum slope
1794:                fmint = getSlopeFromSIndex(sidx);
1795:                // Ensure that it is smaller the maximum slope
1796:                if (fmint >= fmaxt) {
1797:                    sidx--;
1798:                    fmint = getSlopeFromSIndex(sidx);
1799:                }
1800:                // If we are using the last entry of the summary, then that
1801:                // corresponds to all the data, Thus, set the minimum slope to 0.
1802:                if (sidx <= 0)
1803:                    fmint = 0;
1804:
1805:                // We look for the best threshold 'ft', which is the lowest threshold
1806:                // that generates no more than 'maxBytes' code bytes.
1807:
1808:                // The search is done iteratively using a binary split algorithm. We
1809:                // start with 'fmaxt' as the maximum possible threshold, and 'fmint'
1810:                // as the minimum threshold. The threshold 'ft' is calculated as the
1811:                // middle point of 'fmaxt'-'fmint' interval. The 'fmaxt' or 'fmint'
1812:                // bounds are moved according to the number of bytes obtained from a
1813:                // simulation, where 'ft' is used as the threshold.
1814:
1815:                // We stop whenever the interval is sufficiently small, and thus
1816:                // enough precision is achieved.
1817:
1818:                // Initialize threshold as the middle point of the interval.
1819:                ft = (fmaxt + fmint) / 2f;
1820:                // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are so
1821:                // close that the average is 'fmint', due to rounding. Force it to
1822:                // 'fmaxt' instead, since 'fmint' is normally an exclusive lower
1823:                // bound.
1824:                if (ft <= fmint)
1825:                    ft = fmaxt;
1826:
1827:                do {
1828:                    // Get the number of bytes used by this layer, if 'ft' is the
1829:                    // threshold, by simulation.
1830:                    actualBytes = prevBytes;
1831:                    src.setTile(0, 0);
1832:
1833:                    for (int t = 0; t < nt; t++) {
1834:                        for (int c = 0; c < nc; c++) {
1835:                            // set boolean sopUsed here (SOP markers)
1836:                            sopUsed = ((String) wp.getSOP().getTileDef(t))
1837:                                    .equalsIgnoreCase("true");
1838:                            // set boolean ephUsed here (EPH markers)
1839:                            ephUsed = ((String) wp.getEPH().getTileDef(t))
1840:                                    .equalsIgnoreCase("true");
1841:
1842:                            // Get LL subband
1843:                            sb = (SubbandAn) src.getAnSubbandTree(t, c);
1844:                            numLvls = sb.resLvl + 1;
1845:                            sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
1846:                            //loop on resolution levels
1847:                            for (int r = 0; r < numLvls; r++) {
1848:
1849:                                nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;
1850:                                for (int p = 0; p < nPrec; p++) {
1851:
1852:                                    findTruncIndices(layerIdx, c, r, t, sb, ft,
1853:                                            p);
1854:                                    hBuff = pktEnc.encodePacket(layerIdx + 1,
1855:                                            c, r, t, cblks[t][c][r],
1856:                                            truncIdxs[t][layerIdx][c][r],
1857:                                            hBuff, bBuff, p);
1858:
1859:                                    if (pktEnc.isPacketWritable()) {
1860:                                        bBuff = pktEnc.getLastBodyBuf();
1861:                                        actualBytes += bsWriter
1862:                                                .writePacketHead(hBuff
1863:                                                        .getBuffer(), hBuff
1864:                                                        .getLength(), true,
1865:                                                        sopUsed, ephUsed);
1866:                                        actualBytes += bsWriter
1867:                                                .writePacketBody(bBuff, pktEnc
1868:                                                        .getLastBodyLen(),
1869:                                                        true, pktEnc
1870:                                                                .isROIinPkt(),
1871:                                                        pktEnc.getROILen());
1872:                                    }
1873:                                } // end loop on precincts
1874:                                sb = sb.parent;
1875:                            } // End loop on resolution levels
1876:                        } // End loop on components
1877:                    } // End loop on tiles
1878:
1879:                    // Move the interval bounds according to simulation result
1880:                    if (actualBytes > maxBytes) {
1881:                        // 'ft' is too low and generates too many bytes, make it the
1882:                        // new minimum.
1883:                        fmint = ft;
1884:                    } else {
1885:                        // 'ft' is too high and does not generate as many bytes as we
1886:                        // are allowed too, make it the new maximum.
1887:                        fmaxt = ft;
1888:                    }
1889:
1890:                    // Update 'ft' for the new iteration as the middle point of the
1891:                    // new interval.
1892:                    ft = (fmaxt + fmint) / 2f;
1893:                    // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are
1894:                    // so close that the average is 'fmint', due to rounding. Force it
1895:                    // to 'fmaxt' instead, since 'fmint' is normally an exclusive
1896:                    // lower bound.
1897:                    if (ft <= fmint)
1898:                        ft = fmaxt;
1899:
1900:                    // Restore previous packet encoder state
1901:                    pktEnc.restore();
1902:
1903:                    // We continue to iterate, until the threshold reaches the upper
1904:                    // limit of the interval, within a FLOAT_REL_PRECISION relative
1905:                    // tolerance, or a FLOAT_ABS_PRECISION absolute tolerance. This is
1906:                    // the sign that the interval is sufficiently small.
1907:                } while (ft < fmaxt * (1f - FLOAT_REL_PRECISION)
1908:                        && ft < (fmaxt - FLOAT_ABS_PRECISION));
1909:
1910:                // If we have a threshold which is close to 0, set it to 0 so that
1911:                // everything is taken into the layer. This is to avoid not sending
1912:                // some least significant bit-planes in the lossless case. We use the
1913:                // FLOAT_ABS_PRECISION value as a measure of "close" to 0.
1914:                if (ft <= FLOAT_ABS_PRECISION) {
1915:                    ft = 0f;
1916:                } else {
1917:                    // Otherwise make the threshold 'fmaxt', just to be sure that we
1918:                    // will not send more bytes than allowed.
1919:                    ft = fmaxt;
1920:                }
1921:                return ft;
1922:            }
1923:
1924:            /**
1925:             * This function attempts to estimate a rate-distortion slope threshold
1926:             * which will achieve a target number of code bytes close the
1927:             * `targetBytes' value.
1928:             *
1929:             * @param targetBytes The target number of bytes for the current layer
1930:             *
1931:             * @param lastLayer The previous layer information.
1932:             *
1933:             * @return The value of the slope threshold for the estimated layer
1934:             * */
1935:            private float estimateLayerThreshold(int targetBytes,
1936:                    EBCOTLayer lastLayer) {
1937:                float log_sl1; // The log of the first slope used for interpolation
1938:                float log_sl2; // The log of the second slope used for interpolation
1939:                float log_len1; // The log of the first length used for interpolation
1940:                float log_len2; // The log of the second length used for interpolation
1941:                float log_isl; // The log of the interpolated slope
1942:                float log_ilen; // Log of the interpolated length
1943:                float log_ab; // Log of actual bytes in last layer
1944:                int sidx; // Index into the summary R-D info array
1945:                float log_off; // The log of the offset proportion
1946:                int tlen; // The corrected target layer length
1947:                float lthresh; // The threshold of the last layer
1948:                float eth; // The estimated threshold
1949:
1950:                // In order to estimate the threshold we base ourselves in the summary
1951:                // R-D info in RDSlopesRates. In order to use it we must compensate
1952:                // for the overhead of the packet heads. The proportion of overhead is
1953:                // estimated using the last layer simulation results.
1954:
1955:                // NOTE: the model used in this method is that the slope varies
1956:                // linearly with the log of the rate (i.e. length).
1957:
1958:                // NOTE: the model used in this method is that the distortion is
1959:                // proprotional to a power of the rate. Thus, the slope is also
1960:                // proportional to another power of the rate. This translates as the
1961:                // log of the slope varies linearly with the log of the rate, which is
1962:                // what we use.
1963:
1964:                // 1) Find the offset of the length predicted from the summary R-D
1965:                // information, to the actual length by using the last layer.
1966:
1967:                // We ensure that the threshold we use for estimation actually
1968:                // includes some data.
1969:                lthresh = lastLayer.rdThreshold;
1970:                if (lthresh > maxSlope)
1971:                    lthresh = maxSlope;
1972:                // If the slope of the last layer is too small then we just include
1973:                // all the rest (not possible to do better).
1974:                if (lthresh < FLOAT_ABS_PRECISION)
1975:                    return 0f;
1976:                sidx = getLimitedSIndexFromSlope(lthresh);
1977:                // If the index is outside of the summary info array use the last two,
1978:                // or first two, indexes, as appropriate
1979:                if (sidx >= RD_SUMMARY_SIZE - 1)
1980:                    sidx = RD_SUMMARY_SIZE - 2;
1981:
1982:                // Get the logs of the lengths and the slopes
1983:
1984:                if (RDSlopesRates[sidx + 1] == 0) {
1985:                    // Pathological case, we can not use log of 0. Add
1986:                    // RDSlopesRates[sidx]+1 bytes to the rates (just a crude simple
1987:                    // solution to this rare case)
1988:                    log_len1 = (float) Math.log((RDSlopesRates[sidx] << 1) + 1);
1989:                    log_len2 = (float) Math.log(RDSlopesRates[sidx] + 1);
1990:                    log_ab = (float) Math.log(lastLayer.actualBytes
1991:                            + RDSlopesRates[sidx] + 1);
1992:                } else {
1993:                    log_len1 = (float) Math.log(RDSlopesRates[sidx]);
1994:                    log_len2 = (float) Math.log(RDSlopesRates[sidx + 1]);
1995:                    log_ab = (float) Math.log(lastLayer.actualBytes);
1996:                }
1997:
1998:                log_sl1 = (float) Math.log(getSlopeFromSIndex(sidx));
1999:                log_sl2 = (float) Math.log(getSlopeFromSIndex(sidx + 1));
2000:
2001:                log_isl = (float) Math.log(lthresh);
2002:
2003:                log_ilen = log_len1 + (log_isl - log_sl1)
2004:                        * (log_len1 - log_len2) / (log_sl1 - log_sl2);
2005:
2006:                log_off = log_ab - log_ilen;
2007:
2008:                // Do not use negative offsets (i.e. offset proportion larger than 1)
2009:                // since that is probably a sign that our model is off. To be
2010:                // conservative use an offset of 0 (i.e. offset proportiojn 1).
2011:                if (log_off < 0)
2012:                    log_off = 0f;
2013:
2014:                // 2) Correct the target layer length by the offset.
2015:
2016:                tlen = (int) (targetBytes / (float) Math.exp(log_off));
2017:
2018:                // 3) Find, from the summary R-D info, the thresholds that generate
2019:                // lengths just above and below our corrected target layer length.
2020:
2021:                // Look for the index in the summary info array that gives the largest
2022:                // length smaller than the target length
2023:                for (sidx = RD_SUMMARY_SIZE - 1; sidx >= 0; sidx--) {
2024:                    if (RDSlopesRates[sidx] >= tlen)
2025:                        break;
2026:                }
2027:                sidx++;
2028:                // Correct if out of the array
2029:                if (sidx >= RD_SUMMARY_SIZE)
2030:                    sidx = RD_SUMMARY_SIZE - 1;
2031:                if (sidx <= 0)
2032:                    sidx = 1;
2033:
2034:                // Get the log of the lengths and the slopes that are just above and
2035:                // below the target length.
2036:
2037:                if (RDSlopesRates[sidx] == 0) {
2038:                    // Pathological case, we can not use log of 0. Add
2039:                    // RDSlopesRates[sidx-1]+1 bytes to the rates (just a crude simple
2040:                    // solution to this rare case)
2041:                    log_len1 = (float) Math.log(RDSlopesRates[sidx - 1] + 1);
2042:                    log_len2 = (float) Math
2043:                            .log((RDSlopesRates[sidx - 1] << 1) + 1);
2044:                    log_ilen = (float) Math.log(tlen + RDSlopesRates[sidx - 1]
2045:                            + 1);
2046:                } else {
2047:                    // Normal case, we can safely take the logs.
2048:                    log_len1 = (float) Math.log(RDSlopesRates[sidx]);
2049:                    log_len2 = (float) Math.log(RDSlopesRates[sidx - 1]);
2050:                    log_ilen = (float) Math.log(tlen);
2051:                }
2052:
2053:                log_sl1 = (float) Math.log(getSlopeFromSIndex(sidx));
2054:                log_sl2 = (float) Math.log(getSlopeFromSIndex(sidx - 1));
2055:
2056:                // 4) Interpolate the two thresholds to find the target threshold.
2057:
2058:                log_isl = log_sl1 + (log_ilen - log_len1) * (log_sl1 - log_sl2)
2059:                        / (log_len1 - log_len2);
2060:
2061:                eth = (float) Math.exp(log_isl);
2062:
2063:                // Correct out of bounds results
2064:                if (eth > lthresh)
2065:                    eth = lthresh;
2066:                if (eth < FLOAT_ABS_PRECISION)
2067:                    eth = 0f;
2068:
2069:                // Return the estimated threshold
2070:                return eth;
2071:            }
2072:
2073:            /**
2074:             * This function finds the new truncation points indices for a packet. It
2075:             * does so by including the data from the code-blocks in the component,
2076:             * resolution level and tile, associated with a R-D slope which is larger
2077:             * than or equal to 'fthresh'.
2078:             *
2079:             * @param layerIdx The index of the current layer
2080:             *
2081:             * @param compIdx The index of the current component
2082:             *
2083:             * @param lvlIdx The index of the current resolution level
2084:             *
2085:             * @param tileIdx The index of the current tile
2086:             *
2087:             * @param subb The LL subband in the resolution level lvlIdx, which is
2088:             * parent of all the subbands in the packet. Except for resolution level 0
2089:             * this subband is always a node.
2090:             *
2091:             * @param fthresh The value of the rate-distortion threshold
2092:             * */
2093:            private void findTruncIndices(int layerIdx, int compIdx,
2094:                    int lvlIdx, int tileIdx, SubbandAn subb, float fthresh,
2095:                    int precinctIdx) {
2096:                int minsbi, maxsbi, b, bIdx, n;
2097:                Point ncblks = null;
2098:                SubbandAn sb;
2099:                CBlkRateDistStats cur_cblk;
2100:                PrecInfo prec = pktEnc.getPrecInfo(tileIdx, compIdx, lvlIdx,
2101:                        precinctIdx);
2102:                Point cbCoord;
2103:
2104:                sb = subb;
2105:                while (sb.subb_HH != null) {
2106:                    sb = sb.subb_HH;
2107:                }
2108:                minsbi = (lvlIdx == 0) ? 0 : 1;
2109:                maxsbi = (lvlIdx == 0) ? 1 : 4;
2110:
2111:                int yend, xend;
2112:
2113:                sb = (SubbandAn) subb.getSubbandByIdx(lvlIdx, minsbi);
2114:                for (int s = minsbi; s < maxsbi; s++) { //loop on subbands
2115:                    yend = (prec.cblk[s] != null) ? prec.cblk[s].length : 0;
2116:                    for (int y = 0; y < yend; y++) {
2117:                        xend = (prec.cblk[s][y] != null) ? prec.cblk[s][y].length
2118:                                : 0;
2119:                        for (int x = 0; x < xend; x++) {
2120:                            cbCoord = prec.cblk[s][y][x].idx;
2121:                            b = cbCoord.x + cbCoord.y * sb.numCb.x;
2122:                            //Get the current code-block
2123:                            cur_cblk = cblks[tileIdx][compIdx][lvlIdx][s][b];
2124:                            for (n = 0; n < cur_cblk.nVldTrunc; n++) {
2125:                                if (cur_cblk.truncSlopes[n] < fthresh) {
2126:                                    break;
2127:                                } else {
2128:                                    continue;
2129:                                }
2130:                            }
2131:                            // Store the index in the code-block truncIdxs that gives
2132:                            // the real truncation index.
2133:                            truncIdxs[tileIdx][layerIdx][compIdx][lvlIdx][s][b] = n - 1;
2134:
2135:                        } // End loop on horizontal code-blocks
2136:                    } // End loop on vertical code-blocks
2137:                    sb = (SubbandAn) sb.nextSubband();
2138:                } // End loop on subbands
2139:            }
2140:
2141:            /**
2142:             * Returns the index of a slope for the summary table, limiting to the
2143:             * admissible values. The index is calculated as RD_SUMMARY_OFF plus the
2144:             * maximum exponent, base 2, that yields a value not larger than the slope
2145:             * itself.
2146:             *
2147:             * <P>If the value to return is lower than 0, 0 is returned. If it is
2148:             * larger than the maximum table index, then the maximum is returned.
2149:             *
2150:             * @param slope The slope value
2151:             *
2152:             * @return The index for the summary table of the slope.
2153:             * */
2154:            private static int getLimitedSIndexFromSlope(float slope) {
2155:                int idx;
2156:
2157:                idx = (int) Math.floor(Math.log(slope) / LOG2) + RD_SUMMARY_OFF;
2158:
2159:                if (idx < 0) {
2160:                    return 0;
2161:                } else if (idx >= RD_SUMMARY_SIZE) {
2162:                    return RD_SUMMARY_SIZE - 1;
2163:                } else {
2164:                    return idx;
2165:                }
2166:            }
2167:
2168:            /**
2169:             * Returns the minimum slope value associated with a summary table
2170:             * index. This minimum slope is just 2^(index-RD_SUMMARY_OFF).
2171:             *
2172:             * @param index The summary index value.
2173:             *
2174:             * @return The minimum slope value associated with a summary table index.
2175:             * */
2176:            private static float getSlopeFromSIndex(int index) {
2177:                return (float) Math.pow(2, (index - RD_SUMMARY_OFF));
2178:            }
2179:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.