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