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