001/* 002 * $RCSfile: FileBitstreamReaderAgent.java,v $ 003 * $Revision: 1.4 $ 004 * $Date: 2006/10/05 01:10:31 $ 005 * $State: Exp $ 006 * 007 * Class: FileBitstreamReaderAgent 008 * 009 * Description: Retrieve code-blocks codewords in the bit stream 010 * 011 * 012 * 013 * COPYRIGHT: 014 * 015 * This software module was originally developed by Raphaël Grosbois and 016 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel 017 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David 018 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research 019 * Centre France S.A) in the course of development of the JPEG2000 020 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This 021 * software module is an implementation of a part of the JPEG 2000 022 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio 023 * Systems AB and Canon Research Centre France S.A (collectively JJ2000 024 * Partners) agree not to assert against ISO/IEC and users of the JPEG 025 * 2000 Standard (Users) any of their rights under the copyright, not 026 * including other intellectual property rights, for this software module 027 * with respect to the usage by ISO/IEC and Users of this software module 028 * or modifications thereof for use in hardware or software products 029 * claiming conformance to the JPEG 2000 Standard. Those intending to use 030 * this software module in hardware or software products are advised that 031 * their use may infringe existing patents. The original developers of 032 * this software module, JJ2000 Partners and ISO/IEC assume no liability 033 * for use of this software module or modifications thereof. No license 034 * or right to this software module is granted for non JPEG 2000 Standard 035 * conforming products. JJ2000 Partners have full right to use this 036 * software module for his/her own purpose, assign or donate this 037 * software module to any third party and to inhibit third parties from 038 * using this software module for non JPEG 2000 Standard conforming 039 * products. This copyright notice must be included in all copies or 040 * derivative works of this software module. 041 * 042 * Copyright (c) 1999/2000 JJ2000 Partners. 043 * */ 044package jj2000.j2k.codestream.reader; 045import java.awt.Point; 046 047import jj2000.j2k.quantization.dequantizer.*; 048import jj2000.j2k.wavelet.synthesis.*; 049import jj2000.j2k.entropy.decoder.*; 050import jj2000.j2k.codestream.*; 051import jj2000.j2k.decoder.*; 052import jj2000.j2k.entropy.*; 053import jj2000.j2k.image.*; 054import jj2000.j2k.util.*; 055import jj2000.j2k.io.*; 056import jj2000.j2k.*; 057 058import java.util.*; 059import java.io.*; 060import javax.imageio.stream.ImageInputStream; 061import javax.imageio.stream.MemoryCacheImageInputStream; 062 063import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReadParamJava; 064 065/** 066 * This class reads the bit stream (with the help of HeaderDecoder for tile 067 * headers and PktDecoder for packets header and body) and retrives location 068 * of all code-block's codewords. 069 * 070 * <P>Note: All tile-parts headers are read by the constructor whereas packets 071 * are processed when decoding related tile (when setTile method is called). 072 * 073 * <P>In parsing mode, the reader simulates a virtual layer-resolution 074 * progressive bit stream with the same truncation points in each code-block, 075 * whereas in truncation mode, only the first bytes are taken into account (it 076 * behaves like if it is a real truncated codestream). 077 * 078 * @see HeaderDecoder 079 * @see PktDecoder 080 * */ 081public class FileBitstreamReaderAgent extends BitstreamReaderAgent 082 implements Markers, ProgressionType, StdEntropyCoderOptions{ 083 084 /** Whether or not the last read Psot value was zero. Only the Psot in the 085 * last tile-part in the codestream can have such a value. */ 086 private boolean isPsotEqualsZero = true; 087 088 /** Reference to the PktDecoder instance */ 089 public PktDecoder pktDec; 090 091 /** Reference to the J2KImageReadParamJava instance */ 092 private J2KImageReadParamJava j2krparam; 093 094 /** The RandomAccessIO where to get data from */ 095 private RandomAccessIO in; 096 097 /** The number of tiles in the image */ 098 private int nt; 099 100 /** Offset of the first packet in each tile-part in each tile */ 101 private int[][] firstPackOff; 102 103 /** 104 * Returns the number of tile-part found for a given tile 105 * 106 * @param t Tile index 107 * 108 * */ 109 public int getNumTileParts(int t) { 110 if(firstPackOff==null || firstPackOff[t]==null) { 111 throw new Error("Tile "+t+" not found in input codestream."); 112 } 113 return firstPackOff[t].length; 114 } 115 116 /** Number of bytes allocated to each tile. In parsing mode, this number 117 * is related to the tile length in the codestream whereas in truncation 118 * mode all the rate is affected to the first tiles. */ 119 private int[] nBytes; 120 121 /** Whether or not to print information found in codestream */ 122 private boolean printInfo = false; 123 124 /** 125 * Backup of the number of bytes allocated to each tile. This array is 126 * used to restore the number of bytes to read in each tile when the 127 * codestream is read several times (for instance when decoding an R,G,B 128 * image to three output files) 129 * */ 130 private int[] baknBytes; 131 132 /** Length of each tile-part (written in Psot) */ 133 private int[][] tilePartLen; 134 135 /** Total length of each tile */ 136 private int[] totTileLen; 137 138 /** Total length of tiles' header */ 139 private int[] totTileHeadLen; 140 141 /** First tile part header length*/ 142 private int firstTilePartHeadLen; 143 144 /** Total length of all tile parts in all tiles */ 145 private double totAllTileLen; 146 147 /** Length of main header */ 148 private int mainHeadLen; 149 150 /** Length of main and tile-parts headers */ 151 private int headLen = 0; 152 153 /** Length of all tile-part headers */ 154 private int[][] tilePartHeadLen; 155 156 /** Length of each packet head found in the tile */ 157 private Vector pktHL; 158 159 /** True if truncation mode is used. False if parsing mode */ 160 private boolean isTruncMode; 161 162 /** The number of tile-parts that remain to read */ 163 private int remainingTileParts; 164 165 /** The number of tile-parts read so far for each tile */ 166 private int[] tilePartsRead; 167 168 /** Thetotal number of tile-parts read so far */ 169 private int totTilePartsRead=0; 170 171 /** The number of tile-parts in each tile */ 172 private int[] tileParts; 173 174 /** The total number of tile-parts in each tile */ 175 private int[] totTileParts; 176 177 /** The current tile part being used */ 178 private int curTilePart; 179 180 /** The number of the tile-part in the codestream */ 181 private int[][] tilePartNum; 182 183 /** Whether or not a EOC marker has been found instead of a SOT */ 184 private boolean isEOCFound = false; 185 186 /** Reference to the HeaderInfo instance (used when reading SOT marker 187 * segments) */ 188 private HeaderInfo hi; 189 190 /** Array containing info. for all the code-blocks:<br> 191 * - 1st dim: component index.<br> 192 * - 2nd dim: resolution level index.<br> 193 * - 3rd dim: subband index.<br> 194 * - 4th/5th dim: code-block index (vert. and horiz.).<br> 195 */ 196 private CBlkInfo[][][][][] cbI; 197 198 /** Gets the reference to the CBlkInfo array */ 199 public CBlkInfo[][][][][] getCBlkInfo() { 200 return cbI; 201 } 202 203 /** The maximum number of layers to decode for any code-block */ 204 private int lQuit; 205 206 /** Whether or not to use only first progression order */ 207 private boolean usePOCQuit = false; 208 209 /** 210 * Reads all tiles headers and keep offset of their first 211 * packet. Finally it calls the rate allocation method. 212 * 213 * @param hd HeaderDecoder of the codestream. 214 * 215 * @param ehs The input stream where to read bit-stream. 216 * 217 * @param decSpec The decoder specifications 218 * 219 * @param j2krparam The J2KImageReadParam instance created from the 220 * command-line arguments. 221 * 222 * @param cdstrInfo Whether or not to print information found in 223 * codestream. 224 * 225 * @see #allocateRate 226 * */ 227 public FileBitstreamReaderAgent(HeaderDecoder hd,RandomAccessIO ehs, 228 DecoderSpecs decSpec, 229 J2KImageReadParamJava j2krparam, 230 boolean cdstrInfo,HeaderInfo hi) 231 throws IOException { 232 super(hd,decSpec); 233 234 this.j2krparam = j2krparam; 235 this.printInfo = cdstrInfo; 236 this.hi = hi; 237 238 String strInfo = printInfo ? 239 "Codestream elements information in bytes "+ 240 "(offset, total length, header length):\n\n" : null; 241 242 // Check whether quit conditiosn used 243 //usePOCQuit = j2krparam.getPOCQuit(); 244 245 // Get decoding rate 246 if (j2krparam.getDecodingRate() == Double.MAX_VALUE) 247 tnbytes = Integer.MAX_VALUE; 248 else 249 tnbytes = (int)(j2krparam.getDecodingRate() * hd.getMaxCompImgWidth() * 250 hd.getMaxCompImgHeight()) / 8; 251 //isTruncMode = !j2krparam.getParsing(); 252 isTruncMode = true; 253 254 // Check if quit conditions are being used 255 //int ncbQuit = j2krparam.getNCBQuit(); 256 int ncbQuit = -1; 257 if(ncbQuit != -1 && !isTruncMode){ 258 throw new Error("Cannot use -parsing and -ncb_quit condition at "+ 259 "the same time."); 260 } 261 262// lQuit = j2krparam.getLQuit(); 263 lQuit = -1; 264 265 // initializations 266 nt = ntX * ntY; 267 in = ehs; 268 pktDec = new PktDecoder(decSpec,hd,ehs,this,isTruncMode, ncbQuit); 269 270 tileParts = new int[nt]; 271 totTileParts = new int[nt]; 272 totTileLen = new int[nt]; 273 tilePartLen = new int[nt][]; 274 tilePartNum = new int[nt][]; 275 firstPackOff = new int[nt][]; 276 tilePartsRead = new int[nt]; 277 totTileHeadLen = new int[nt]; 278 tilePartHeadLen = new int[nt][]; 279 nBytes = new int[nt]; 280 baknBytes = new int[nt]; 281 hd.nTileParts = new int[nt]; 282 283 284 this.isTruncMode = isTruncMode; 285 286 // Keeps main header's length, takes file format overhead into account 287 cdstreamStart = hd.mainHeadOff; // Codestream offset in the file 288 mainHeadLen = in.getPos() - cdstreamStart; 289 headLen = mainHeadLen; 290 291 // If ncb and lbody quit conditions are used, headers are not counted 292 if(ncbQuit == -1) { 293 anbytes = mainHeadLen; 294 } else { 295 anbytes = 0; 296 } 297 298 if(printInfo) 299 strInfo += "Main header length : "+cdstreamStart+", "+mainHeadLen+ 300 ", "+mainHeadLen+"\n"; 301 302 // If cannot even read the first tile-part 303 if(anbytes>tnbytes) { 304 throw new Error("Requested bitrate is too small."); 305 } 306 307 // Initialize variables used when reading tile-part headers. 308 totAllTileLen = 0; 309 remainingTileParts = nt; // at least as many tile-parts as tiles 310 maxPos = lastPos = in.getPos(); 311 312 // Update 'res' value according to the parameter and the main header. 313 if(j2krparam.getResolution()== -1) { 314 targetRes = decSpec.dls.getMin(); 315 } else { 316 targetRes = j2krparam.getResolution(); 317 if(targetRes<0) { 318 throw new 319 IllegalArgumentException("Specified negative "+ 320 "resolution level index: "+ 321 targetRes); 322 } 323 } 324 325 // Verify reduction in resolution level 326 int mdl = decSpec.dls.getMin(); 327 if(targetRes>mdl) { 328 FacilityManager.getMsgLogger(). 329 printmsg(MsgLogger.WARNING, 330 "Specified resolution level ("+targetRes+ 331 ") is larger"+ 332 " than the maximum possible. Setting it to "+ 333 mdl +" (maximum possible)"); 334 targetRes = mdl; 335 } 336 337 // Initialize tile part positions from TLM marker segment. 338 initTLM(); 339 } 340 341 // An array of the positions of tile parts: 342 // - length of tilePartPositions is nt. 343 // - length of tilePartPositions[i] is totTileParts[i]. 344 long[][] tilePartPositions = null; 345 346 // 347 // Initialize the tilePartPositions positions array if a TLM marker 348 // segment is present in the main header. If no such marker segment 349 // is present the array will remain null. This method rewinds to the 350 // start of the codestream and scans until the first SOT marker is 351 // encountered. Before return the stream is returned to its position 352 // when the method was invoked. 353 // 354 private void initTLM() throws IOException { 355 // Save the position to return to at the end of this method. 356 int savePos = in.getPos(); 357 358 // Array to store contents of TLM segments. The first index is 359 // Ztlm. The contents of tlmSegments[i] is the bytes in the TLM 360 // segment with Ztlm == i after the Ztlm byte. 361 byte[][] tlmSegments = null; 362 363 // Number of TLM segments. The first numTLM elements of tlmSegments 364 // should be non-null if the segments are correct. 365 int numTLM = 0; 366 367 try { 368 // Rewind to the start of the main header. 369 in.seek(cdstreamStart + 2); // skip SOC 370 371 // Loop over marker segments. 372 short marker; 373 while((marker = in.readShort()) != SOT) { 374 // Get the length (which includes the 2-byte length parameter). 375 int markerLength = in.readUnsignedShort(); 376 377 // Process TLM segments. 378 if(marker == TLM) { 379 numTLM++; 380 381 if(tlmSegments == null) { 382 tlmSegments = new byte[256][]; // 0 <= Ztlm <= 255 383 } 384 385 // Save contents after Ztlm in array. 386 int Ztlm = in.read(); 387 tlmSegments[Ztlm] = new byte[markerLength - 3]; 388 in.readFully(tlmSegments[Ztlm], 0, markerLength - 3); 389 } else { 390 in.skipBytes(markerLength - 2); 391 } 392 } 393 } catch(IOException e) { 394 // Reset so that the TLM segments are not processed further. 395 tlmSegments = null; 396 } 397 398 if(tlmSegments != null) { 399 ArrayList[] tlmOffsets = null; 400 401 // Tiles start after the main header. 402 long tilePos = cdstreamStart + mainHeadLen; 403 404 // Tile counter for when tile indexes are not included. 405 int tileCounter = 0; 406 407 for(int itlm = 0; itlm < numTLM; itlm++) { 408 if(tlmSegments[itlm] == null) { 409 // Null segment among first numTLM entries: error. 410 tlmOffsets = null; 411 break; 412 } else if(tlmOffsets == null) { 413 tlmOffsets = new ArrayList[nt]; 414 } 415 416 // Create a stream. 417 ByteArrayInputStream bais = 418 new ByteArrayInputStream(tlmSegments[itlm]); 419 ImageInputStream iis = new MemoryCacheImageInputStream(bais); 420 421 try { 422 int Stlm = iis.read(); 423 int ST = (Stlm >> 4) & 0x3; 424 int SP = (Stlm >> 6) & 0x1; 425 426 int tlmLength = tlmSegments[itlm].length; 427 while(iis.getStreamPosition() < tlmLength) { 428 int tileIndex = tileCounter; 429 switch(ST) { 430 case 1: 431 tileIndex = iis.read(); 432 break; 433 case 2: 434 tileIndex = iis.readUnsignedShort(); 435 } 436 437 if(tlmOffsets[tileIndex] == null) { 438 tlmOffsets[tileIndex] = new ArrayList(); 439 } 440 tlmOffsets[tileIndex].add(new Long(tilePos)); 441 442 long tileLength = 0L; 443 switch(SP) { 444 case 0: 445 tileLength = iis.readUnsignedShort(); 446 break; 447 case 1: 448 tileLength = iis.readUnsignedInt(); 449 break; 450 } 451 452 tilePos += tileLength; 453 454 if(ST == 0) tileCounter++; 455 } 456 } catch(IOException e) { 457 // XXX? 458 } 459 } 460 461 if(tlmOffsets != null) { 462 tilePartPositions = new long[nt][]; 463 for(int i = 0; i < nt; i++) { 464 if(tlmOffsets[i] == null) { 465 tilePartPositions = null; 466 break; 467 } else { 468 ArrayList list = tlmOffsets[i]; 469 int count = list.size(); 470 tilePartPositions[i] = new long[count]; 471 long[] tpPos = tilePartPositions[i]; 472 for(int j = 0; j < count; j++) { 473 tpPos[j] = ((Long)list.get(j)).longValue(); 474 } 475 } 476 } 477 } 478 } 479 480 in.seek(savePos); 481 } 482 483 int cdstreamStart = 0; 484 int t=0, pos=-1, tp=0, tptot=0; 485 int tilePartStart = 0; 486 boolean rateReached = false; 487 int numtp = 0; 488 int maxTP = nt; // If maximum 1 tile part per tile specified 489 int lastPos = 0, maxPos = 0; 490 491 /** 492 * Read all tile-part headers of the requested tile. All tile-part 493 * headers prior to the last tile-part header of the current tile will 494 * also be read. 495 * 496 * @param tileNum The index of the tile for which to read tile-part 497 * headers. 498 */ 499 private void initTile(int tileNum) throws IOException { 500 if(tilePartPositions == null) in.seek(lastPos); 501 String strInfo = ""; 502 int ncbQuit = -1; 503 boolean isTilePartRead = false; 504 boolean isEOFEncountered = false; 505 try { 506 int tpNum = 0; 507 while(remainingTileParts!=0 && 508 (totTileParts[tileNum] == 0 || 509 tilePartsRead[tileNum] < totTileParts[tileNum])) { 510 isTilePartRead = true; 511 512 if(tilePartPositions != null) { 513 in.seek((int)tilePartPositions[tileNum][tpNum++]); 514 } 515 tilePartStart = in.getPos(); 516 517 // Read tile-part header 518 try { 519 t = readTilePartHeader(); 520 if(isEOCFound) { // Some tiles are missing but the 521 // codestream is OK 522 break; 523 } 524 tp = tilePartsRead[t]; 525 if(isPsotEqualsZero) { // Psot may equals zero for the 526 // last tile-part: it is assumed that this tile-part 527 // contain all data until EOC 528 tilePartLen[t][tp] = in.length()-2-tilePartStart; 529 } 530 } catch(EOFException e) { 531 firstPackOff[t][tp] = in.length(); 532 throw e; 533 } 534 535 pos = in.getPos(); 536 537 // In truncation mode, if target decoding rate is reached in 538 // tile-part header, skips the tile-part and stop reading 539 // unless the ncb and lbody quit condition is in use 540 if(isTruncMode && ncbQuit == -1) { 541 if((pos-cdstreamStart)>tnbytes) { 542 firstPackOff[t][tp] = in.length(); 543 rateReached = true; 544 break; 545 } 546 } 547 548 // Set tile part position and header length 549 firstPackOff[t][tp] = pos; 550 tilePartHeadLen[t][tp] = (pos-tilePartStart); 551 552 if(printInfo) 553 strInfo += "Tile-part "+tp+" of tile "+t+" : "+tilePartStart 554 +", "+tilePartLen[t][tp]+", "+tilePartHeadLen[t][tp]+"\n"; 555 556 // Update length counters 557 totTileLen[t] += tilePartLen[t][tp]; 558 totTileHeadLen[t] += tilePartHeadLen[t][tp]; 559 totAllTileLen += tilePartLen[t][tp]; 560 if(isTruncMode) { 561 if(anbytes+tilePartLen[t][tp]>tnbytes) { 562 anbytes += tilePartHeadLen[t][tp]; 563 headLen += tilePartHeadLen[t][tp]; 564 rateReached = true; 565 nBytes[t] += (tnbytes-anbytes); 566 break; 567 } else { 568 anbytes += tilePartHeadLen[t][tp]; 569 headLen += tilePartHeadLen[t][tp]; 570 nBytes[t] += (tilePartLen[t][tp]- 571 tilePartHeadLen[t][tp]); 572 } 573 } else { 574 if(anbytes+tilePartHeadLen[t][tp]>tnbytes) { 575 break; 576 } else { 577 anbytes += tilePartHeadLen[t][tp]; 578 headLen += tilePartHeadLen[t][tp]; 579 } 580 } 581 582 // If this is first tile-part, remember header length 583 if(tptot==0) 584 firstTilePartHeadLen = tilePartHeadLen[t][tp]; 585 586 // Go to the beginning of next tile part 587 tilePartsRead[t]++; 588 int nextMarkerPos = tilePartStart+tilePartLen[t][tp]; 589 if(tilePartPositions == null) { 590 in.seek(nextMarkerPos); 591 } 592 if(nextMarkerPos > maxPos) { 593 maxPos = nextMarkerPos; 594 } 595 remainingTileParts--; 596 maxTP--; 597 tptot++; 598 // If Psot of the current tile-part was equal to zero, it is 599 // assumed that it contains all data until the EOC marker 600 if(isPsotEqualsZero) { 601 if(remainingTileParts!=0) { 602 FacilityManager.getMsgLogger().printmsg 603 (MsgLogger.WARNING,"Some tile-parts have not "+ 604 "been found. The codestream may be corrupted."); 605 } 606 break; 607 } 608 } 609 } catch(EOFException e) { 610 isEOFEncountered = true; 611 612 if(printInfo) { 613 FacilityManager.getMsgLogger(). 614 printmsg(MsgLogger.INFO,strInfo); 615 } 616 FacilityManager.getMsgLogger(). 617 printmsg(MsgLogger.WARNING,"Codestream truncated in tile "+t); 618 619 // Set specified rate to end of file if valid 620 int fileLen = in.length(); 621 if(fileLen<tnbytes) { 622 tnbytes = fileLen; 623 trate = tnbytes*8f/hd.getMaxCompImgWidth()/ 624 hd.getMaxCompImgHeight(); 625 } 626 } 627 628 // If no tile-parts read then return. 629 if(!isTilePartRead) return; 630 631 /* XXX: BEGIN Updating the resolution here is logical when all tile-part 632 headers are read as was the case with the original version of this 633 class. With initTile() however the tiles could be read in random 634 order so modifying the resolution value could cause unexpected 635 results if a given tile-part has fewer levels than the main header 636 indicated. 637 // Update 'res' value once all tile-part headers are read 638 if(j2krparam.getResolution()== -1) { 639 targetRes = decSpec.dls.getMin(); 640 } else { 641 targetRes = j2krparam.getResolution(); 642 if(targetRes<0) { 643 throw new 644 IllegalArgumentException("Specified negative "+ 645 "resolution level index: "+ 646 targetRes); 647 } 648 } 649 650 // Verify reduction in resolution level 651 int mdl = decSpec.dls.getMin(); 652 if(targetRes>mdl) { 653 FacilityManager.getMsgLogger(). 654 printmsg(MsgLogger.WARNING, 655 "Specified resolution level ("+targetRes+ 656 ") is larger"+ 657 " than the maximum possible. Setting it to "+ 658 mdl +" (maximum possible)"); 659 targetRes = mdl; 660 } 661 XXX: END */ 662 663 if(!isEOFEncountered) { 664 if(printInfo) { 665 FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo); 666 } 667 668 if(remainingTileParts == 0) { 669 // Check presence of EOC marker is decoding rate not reached or 670 // if this marker has not been found yet 671 if(!isEOCFound && !isPsotEqualsZero && !rateReached) { 672 try { 673 int savePos = in.getPos(); 674 in.seek(maxPos); 675 if(in.readShort()!=EOC) { 676 FacilityManager.getMsgLogger(). 677 printmsg(MsgLogger.WARNING,"EOC marker not found. "+ 678 "Codestream is corrupted."); 679 } 680 in.seek(savePos); 681 } catch(EOFException e) { 682 FacilityManager.getMsgLogger(). 683 printmsg(MsgLogger.WARNING,"EOC marker is missing"); 684 } 685 } 686 } 687 } 688 689 // Bit-rate allocation 690 if(!isTruncMode) { 691 allocateRate(); 692 } else if(remainingTileParts == 0 && !isEOFEncountered) { 693 // Take EOC into account if rate is not reached 694 if(in.getPos()>=tnbytes) 695 anbytes += 2; 696 } 697 698 if(tilePartPositions == null) lastPos = in.getPos(); 699 700 // Backup nBytes 701 for (int tIdx=0; tIdx<nt; tIdx++) { 702 baknBytes[tIdx] = nBytes[tIdx]; 703 if(printInfo) { 704 FacilityManager.getMsgLogger(). 705 println(""+hi.toStringTileHeader(tIdx,tilePartLen[tIdx]. 706 length),2,2); 707 } 708 } 709 } 710 711 /** 712 * Allocates output bit-rate for each tile in parsing mode: The allocator 713 * simulates the truncation of a virtual layer-resolution progressive 714 * codestream. 715 * */ 716 private void allocateRate() throws IOException { 717 int stopOff = tnbytes; 718 719 // In parsing mode, the bitrate is allocated related to each tile's 720 // length in the bit stream 721 722 // EOC marker's length 723 if(remainingTileParts == 0) anbytes += 2; 724 725 // If there are too few bytes to read the tile part headers throw an 726 // error 727 if(anbytes > stopOff){ 728 throw new Error("Requested bitrate is too small for parsing"); 729 } 730 731 // Calculate bitrate for each tile 732 int rem = stopOff-anbytes; 733 int totnByte = rem; 734 for(int t=nt-1; t>0; t--){ 735 rem -= nBytes[t]=(int)(totnByte*(totTileLen[t]/totAllTileLen)); 736 } 737 nBytes[0] = rem; 738 } 739 740 /** 741 * Reads SOT marker segment of the tile-part header and calls related 742 * methods of the HeaderDecoder to read other markers segments. The 743 * tile-part header is entirely read when a SOD marker is encountered. 744 * 745 * @return The tile number of the tile part that was read 746 * */ 747 private int readTilePartHeader() throws IOException{ 748 HeaderInfo.SOT ms = hi.getNewSOT(); 749 750 // SOT marker 751 short marker = in.readShort(); 752 if(marker!=SOT) { 753 if(marker==EOC) { 754 isEOCFound = true; 755 return -1; 756 } else { 757 throw new CorruptedCodestreamException("SOT tag not found "+ 758 "in tile-part start"); 759 } 760 } 761 isEOCFound = false; 762 763 // Lsot (shall equals 10) 764 int lsot = in.readUnsignedShort(); 765 ms.lsot = lsot; 766 if(lsot!=10) 767 throw new CorruptedCodestreamException("Wrong length for "+ 768 "SOT marker segment: "+ 769 lsot); 770 771 // Isot 772 int tile = in.readUnsignedShort(); 773 ms.isot = tile; 774 if(tile>65534){ 775 throw new CorruptedCodestreamException("Tile index too high in "+ 776 "tile-part."); 777 } 778 779 // Psot 780 int psot = in.readInt(); 781 ms.psot = psot; 782 isPsotEqualsZero = (psot!=0) ? false : true; 783 if(psot<0) { 784 throw new NotImplementedError("Tile length larger "+ 785 "than maximum supported"); 786 } 787 // TPsot 788 int tilePart = in.read(); 789 ms.tpsot = tilePart; 790 if( tilePart!=tilePartsRead[tile] || tilePart<0 || tilePart>254 ) { 791 throw new CorruptedCodestreamException("Out of order tile-part"); 792 } 793 // TNsot 794 int nrOfTileParts = in.read(); 795 ms.tnsot = nrOfTileParts; 796 hi.sot.put("t"+tile+"_tp"+tilePart,ms); 797 if(nrOfTileParts==0) { // The number of tile-part is not specified in 798 // this tile-part header. 799 800 // Assumes that there will be another tile-part in the codestream 801 // that will indicate the number of tile-parts for this tile) 802 int nExtraTp; 803 if(tileParts[tile]==0 || tileParts[tile]==tilePartLen.length ) { 804 // Then there are two tile-parts (one is the current and the 805 // other will indicate the number of tile-part for this tile) 806 nExtraTp = 2; 807 remainingTileParts += 1; 808 } else { 809 // There is already one scheduled extra tile-part. In this 810 // case just add place for the current one 811 nExtraTp = 1; 812 } 813 814 tileParts[tile] += nExtraTp; 815 nrOfTileParts = tileParts[tile]; 816 FacilityManager.getMsgLogger(). 817 printmsg(MsgLogger.WARNING,"Header of tile-part "+tilePart+ 818 " of tile "+tile+", does not indicate the total"+ 819 " number of tile-parts. Assuming that there are "+ 820 nrOfTileParts+" tile-parts for this tile."); 821 822 // Increase and re-copy tilePartLen array 823 int[] tmpA = tilePartLen[tile]; 824 tilePartLen[tile] = new int[nrOfTileParts]; 825 for(int i=0; i<nrOfTileParts-nExtraTp; i++) { 826 tilePartLen[tile][i] = tmpA[i]; 827 } 828 // Increase and re-copy tilePartNum array 829 tmpA = tilePartNum[tile]; 830 tilePartNum[tile] = new int[nrOfTileParts]; 831 for(int i=0; i<nrOfTileParts-nExtraTp; i++) { 832 tilePartNum[tile][i] = tmpA[i]; 833 } 834 835 // Increase and re-copy firsPackOff array 836 tmpA = firstPackOff[tile]; 837 firstPackOff[tile] = new int[nrOfTileParts]; 838 for(int i=0; i<nrOfTileParts-nExtraTp; i++) { 839 firstPackOff[tile][i] = tmpA[i]; 840 } 841 842 // Increase and re-copy tilePartHeadLen array 843 tmpA = tilePartHeadLen[tile]; 844 tilePartHeadLen[tile] = new int[nrOfTileParts]; 845 for(int i=0; i<nrOfTileParts-nExtraTp; i++) { 846 tilePartHeadLen[tile][i] = tmpA[i]; 847 } 848 } else { // The number of tile-parts is specified in the tile-part 849 // header 850 totTileParts[tile] = nrOfTileParts; 851 852 // Check if it is consistant with what was found in previous 853 // tile-part headers 854 855 if(tileParts[tile]==0) { // First tile-part: OK 856 remainingTileParts += nrOfTileParts- 1; 857 tileParts[tile] = nrOfTileParts; 858 tilePartLen[tile] = new int[nrOfTileParts]; 859 tilePartNum[tile] = new int[nrOfTileParts]; 860 firstPackOff[tile] = new int[nrOfTileParts]; 861 tilePartHeadLen[tile] = new int[nrOfTileParts]; 862 } else if(tileParts[tile] > nrOfTileParts ) { 863 // Already found more tile-parts than signaled here 864 throw new CorruptedCodestreamException("Invalid number "+ 865 "of tile-parts in"+ 866 " tile "+tile+": "+ 867 nrOfTileParts); 868 } else { // Signaled number of tile-part fits with number of 869 // previously found tile-parts 870 remainingTileParts += nrOfTileParts-tileParts[tile]; 871 872 if(tileParts[tile]!=nrOfTileParts) { 873 874 // Increase and re-copy tilePartLen array 875 int[] tmpA = tilePartLen[tile]; 876 tilePartLen[tile] = new int[nrOfTileParts]; 877 for(int i=0; i<tileParts[tile]-1; i++) { 878 tilePartLen[tile][i] = tmpA[i]; 879 } 880 881 // Increase and re-copy tilePartNum array 882 tmpA = tilePartNum[tile]; 883 tilePartNum[tile] = new int[nrOfTileParts]; 884 for(int i=0; i<tileParts[tile]-1; i++) { 885 tilePartNum[tile][i] = tmpA[i]; 886 } 887 888 // Increase and re-copy firstPackOff array 889 tmpA = firstPackOff[tile]; 890 firstPackOff[tile] = new int[nrOfTileParts]; 891 for(int i=0; i<tileParts[tile]-1; i++) { 892 firstPackOff[tile][i] = tmpA[i]; 893 } 894 895 // Increase and re-copy tilePartHeadLen array 896 tmpA = tilePartHeadLen[tile]; 897 tilePartHeadLen[tile] = new int[nrOfTileParts]; 898 for(int i=0; i<tileParts[tile]-1; i++) { 899 tilePartHeadLen[tile][i] = tmpA[i]; 900 } 901 } 902 } 903 } 904 905 // Other markers 906 hd.resetHeaderMarkers(); 907 hd.nTileParts[tile] = nrOfTileParts; 908 // Decode and store the tile-part header (i.e. until a SOD marker is 909 // found) 910 do { 911 hd.extractTilePartMarkSeg(in.readShort(),in,tile,tilePart); 912 } while ((hd.getNumFoundMarkSeg() & hd.SOD_FOUND)==0); 913 914 // Read each marker segment previously found 915 hd.readFoundTilePartMarkSeg(tile,tilePart); 916 917 tilePartLen[tile][tilePart] = psot; 918 919 tilePartNum[tile][tilePart] = totTilePartsRead; 920 totTilePartsRead++; 921 922 // Add to list of which tile each successive tile-part belongs. 923 // This list is needed if there are PPM markers used 924 hd.setTileOfTileParts(tile); 925 926 return tile; 927 928 } 929 930 /** 931 * Reads packets of the current tile according to the 932 * layer-resolution-component-position progressiveness. 933 * 934 * @param lys Index of the first layer for each component and resolution. 935 * 936 * @param lye Index of the last layer. 937 * 938 * @param ress Index of the first resolution level. 939 * 940 * @param rese Index of the last resolution level. 941 * 942 * @param comps Index of the first component. 943 * 944 * @param compe Index of the last component. 945 * 946 * @return True if rate has been reached. 947 * */ 948 private boolean readLyResCompPos(int[][] lys,int lye,int ress,int rese, 949 int comps,int compe) 950 throws IOException { 951 952 int minlys = 10000; 953 for(int c=comps; c<compe; c++) { //loop on components 954 // Check if this component exists 955 if(c>=mdl.length) continue; 956 957 for(int r=ress; r<rese; r++) {//loop on resolution levels 958 if(lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) { 959 minlys = lys[c][r]; 960 } 961 } 962 } 963 964 int t = getTileIdx(); 965 int start; 966 boolean status = false; 967 int lastByte = firstPackOff[t][curTilePart]+ 968 tilePartLen[t][curTilePart]-1- 969 tilePartHeadLen[t][curTilePart]; 970 int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); 971 int nPrec = 1; 972 int hlen,plen; 973 String strInfo = printInfo ? 974 "Tile "+getTileIdx()+" (tile-part:"+curTilePart+ 975 "): offset, length, header length\n" : null; 976 boolean pph = false; 977 if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { 978 pph = true; 979 } 980 for(int l=minlys; l<lye; l++) { // loop on layers 981 for(int r=ress; r<rese; r++) { // loop on resolution levels 982 for(int c=comps; c<compe; c++) { // loop on components 983 // Checks if component exists 984 if(c>=mdl.length) continue; 985 // Checks if resolution level exists 986 if(r>=lys[c].length) continue; 987 if(r>mdl[c]) continue; 988 // Checks if layer exists 989 if(l<lys[c][r] || l>=numLayers) continue; 990 991 nPrec = pktDec.getNumPrecinct(c,r); 992 for(int p=0; p<nPrec; p++) { // loop on precincts 993 start = in.getPos(); 994 995 // If packed packet headers are used, there is no need 996 // to check that there are bytes enough to read header 997 if(pph) { 998 pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes); 999 } 1000 1001 // If we are about to read outside of tile-part, 1002 // skip to next tile-part 1003 if(start>lastByte && 1004 curTilePart<firstPackOff[t].length-1) { 1005 curTilePart++; 1006 in.seek(firstPackOff[t][curTilePart]); 1007 lastByte = in.getPos()+ 1008 tilePartLen[t][curTilePart]-1- 1009 tilePartHeadLen[t][curTilePart]; 1010 } 1011 1012 // Read SOP marker segment if necessary 1013 status = pktDec.readSOPMarker(nBytes,p,c,r); 1014 1015 if(status) { 1016 if(printInfo) { 1017 FacilityManager.getMsgLogger(). 1018 printmsg(MsgLogger.INFO,strInfo); 1019 } 1020 return true; 1021 } 1022 1023 if(!pph) { 1024 status = 1025 pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes); 1026 } 1027 1028 if(status) { 1029 if(printInfo) { 1030 FacilityManager.getMsgLogger(). 1031 printmsg(MsgLogger.INFO,strInfo); 1032 } 1033 return true; 1034 } 1035 1036 // Store packet's head length 1037 hlen = in.getPos()-start; 1038 pktHL.addElement(new Integer(hlen)); 1039 1040 // Reads packet's body 1041 status = pktDec.readPktBody(l,r,c,p,cbI[c][r],nBytes); 1042 plen = in.getPos()-start; 1043 if(printInfo) 1044 strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+p+": "+ 1045 start+", "+plen+", "+hlen+"\n"; 1046 1047 if(status) { 1048 if(printInfo) { 1049 FacilityManager.getMsgLogger(). 1050 printmsg(MsgLogger.INFO,strInfo); 1051 } 1052 return true; 1053 } 1054 1055 } // end loop on precincts 1056 } // end loop on components 1057 } // end loop on resolution levels 1058 } // end loop on layers 1059 1060 if(printInfo) { 1061 FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo); 1062 } 1063 return false; // Decoding rate was not reached 1064 } 1065 1066 /** 1067 * Reads packets of the current tile according to the 1068 * resolution-layer-component-position progressiveness. 1069 * 1070 * @param lys Index of the first layer for each component and resolution. 1071 * 1072 * @param lye Index of the last layer. 1073 * 1074 * @param ress Index of the first resolution level. 1075 * 1076 * @param rese Index of the last resolution level. 1077 * 1078 * @param comps Index of the first component. 1079 * 1080 * @param compe Index of the last component. 1081 * 1082 * @return True if rate has been reached. 1083 * */ 1084 private boolean readResLyCompPos(int lys[][],int lye,int ress,int rese, 1085 int comps,int compe) 1086 throws IOException { 1087 1088 int t = getTileIdx(); // Current tile index 1089 boolean status=false; // True if decoding rate is reached when 1090 int lastByte = firstPackOff[t][curTilePart]+ 1091 tilePartLen[t][curTilePart]-1- 1092 tilePartHeadLen[t][curTilePart]; 1093 int minlys = 10000; 1094 for(int c=comps; c<compe; c++) { //loop on components 1095 // Check if this component exists 1096 if(c>=mdl.length) continue; 1097 1098 for(int r=ress; r<rese; r++) {//loop on resolution levels 1099 if(r>mdl[c]) continue; 1100 if(lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) { 1101 minlys = lys[c][r]; 1102 } 1103 } 1104 } 1105 1106 String strInfo = printInfo ? 1107 "Tile "+getTileIdx()+" (tile-part:"+curTilePart+ 1108 "): offset, length, header length\n" : null; 1109 int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); 1110 boolean pph = false; 1111 if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { 1112 pph = true; 1113 } 1114 int nPrec = 1; 1115 int start; 1116 int hlen,plen; 1117 for(int r=ress; r<rese; r++) { // loop on resolution levels 1118 for(int l=minlys; l<lye; l++) { // loop on layers 1119 for(int c=comps; c<compe; c++) { // loop on components 1120 // Checks if component exists 1121 if(c>=mdl.length) continue; 1122 // Checks if resolution level exists 1123 if(r>mdl[c]) continue; 1124 if(r>=lys[c].length) continue; 1125 // Checks if layer exists 1126 if(l<lys[c][r] || l>=numLayers) continue; 1127 1128 nPrec = pktDec.getNumPrecinct(c,r); 1129 1130 for(int p=0; p<nPrec; p++) { // loop on precincts 1131 start = in.getPos(); 1132 1133 // If packed packet headers are used, there is no need 1134 // to check that there are bytes enough to read header 1135 if(pph) { 1136 pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes); 1137 } 1138 1139 // If we are about to read outside of tile-part, 1140 // skip to next tile-part 1141 if(start>lastByte && 1142 curTilePart<firstPackOff[t].length-1) { 1143 curTilePart++; 1144 in.seek(firstPackOff[t][curTilePart]); 1145 lastByte = in.getPos()+ 1146 tilePartLen[t][curTilePart]-1- 1147 tilePartHeadLen[t][curTilePart]; 1148 } 1149 1150 // Read SOP marker segment if necessary 1151 status = pktDec.readSOPMarker(nBytes,p,c,r); 1152 1153 if(status) { 1154 if(printInfo) { 1155 FacilityManager.getMsgLogger(). 1156 printmsg(MsgLogger.INFO,strInfo); 1157 } 1158 return true; 1159 } 1160 1161 if(!pph) { 1162 status = pktDec. 1163 readPktHead(l,r,c,p,cbI[c][r],nBytes); 1164 } 1165 1166 if(status) { 1167 if(printInfo) { 1168 FacilityManager.getMsgLogger(). 1169 printmsg(MsgLogger.INFO,strInfo); 1170 } 1171 // Output rate of EOF reached 1172 return true; 1173 } 1174 1175 // Store packet's head length 1176 hlen = in.getPos()-start; 1177 pktHL.addElement(new Integer(hlen)); 1178 1179 // Reads packet's body 1180 status = pktDec.readPktBody(l,r,c,p,cbI[c][r],nBytes); 1181 plen = in.getPos()-start; 1182 if(printInfo) 1183 strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+p+": "+ 1184 start+", "+plen+", "+hlen+"\n"; 1185 1186 if(status) { 1187 if(printInfo) { 1188 FacilityManager.getMsgLogger(). 1189 printmsg(MsgLogger.INFO,strInfo); 1190 } 1191 // Output rate or EOF reached 1192 return true; 1193 } 1194 1195 } // end loop on precincts 1196 } // end loop on components 1197 } // end loop on layers 1198 } // end loop on resolution levels 1199 1200 if(printInfo) { 1201 FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo); 1202 } 1203 return false; // Decoding rate was not reached 1204 } 1205 1206 1207 /** 1208 * Reads packets of the current tile according to the 1209 * resolution-position-component-layer progressiveness. 1210 * 1211 * @param lys Index of the first layer for each component and resolution. 1212 * 1213 * @param lye Index of the last layer. 1214 * 1215 * @param ress Index of the first resolution level. 1216 * 1217 * @param rese Index of the last resolution level. 1218 * 1219 * @param comps Index of the first component. 1220 * 1221 * @param compe Index of the last component. 1222 * 1223 * @return True if rate has been reached. 1224 * */ 1225 private boolean readResPosCompLy(int[][] lys,int lye,int ress,int rese, 1226 int comps,int compe) 1227 throws IOException { 1228 // Computes current tile offset in the reference grid 1229 1230 Point nTiles = getNumTiles(null); 1231 Point tileI = getTile(null); 1232 int x0siz = hd.getImgULX(); 1233 int y0siz = hd.getImgULY(); 1234 int xsiz = x0siz + hd.getImgWidth(); 1235 int ysiz = y0siz + hd.getImgHeight(); 1236 int xt0siz = getTilePartULX(); 1237 int yt0siz = getTilePartULY(); 1238 int xtsiz = getNomTileWidth(); 1239 int ytsiz = getNomTileHeight(); 1240 int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz; 1241 int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz; 1242 int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz; 1243 int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz; 1244 1245 // Get precinct information (number,distance between two consecutive 1246 // precincts in the reference grid) in each component and resolution 1247 // level 1248 int t = getTileIdx(); // Current tile index 1249 PrecInfo prec; // temporary variable 1250 int p; // Current precinct index 1251 int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid 1252 int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid 1253 int nPrec = 0; // Total number of found precincts 1254 int[][] nextPrec = new int [compe][]; // Next precinct index in each 1255 // component and resolution level 1256 int minlys = 100000; // minimum layer start index of each component 1257 int minx = tx1; // Horiz. offset of the second precinct in the 1258 // reference grid 1259 int miny = ty1; // Vert. offset of the second precinct in the 1260 // reference grid. 1261 int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid 1262 int maxy = ty0; // Max. vert. offset of precincts in the ref. grid 1263 Point numPrec; 1264 for(int c=comps; c<compe; c++) { // components 1265 for(int r=ress; r<rese; r++) { // resolution levels 1266 if(c>=mdl.length) continue; 1267 if(r>mdl[c]) continue; 1268 nextPrec[c] = new int[mdl[c]+1]; 1269 if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) { 1270 minlys = lys[c][r]; 1271 } 1272 p = pktDec.getNumPrecinct(c,r)-1; 1273 for(; p>=0; p--) { 1274 prec = pktDec.getPrecInfo(c,r,p); 1275 if(prec.rgulx!=tx0) { 1276 if(prec.rgulx<minx) minx = prec.rgulx; 1277 if(prec.rgulx>maxx) maxx = prec.rgulx; 1278 } 1279 if(prec.rguly!=ty0) { 1280 if(prec.rguly<miny) miny = prec.rguly; 1281 if(prec.rguly>maxy) maxy = prec.rguly; 1282 } 1283 1284 if(nPrec==0) { 1285 gcd_x = prec.rgw; 1286 gcd_y = prec.rgh; 1287 } else { 1288 gcd_x = MathUtil.gcd(gcd_x,prec.rgw); 1289 gcd_y = MathUtil.gcd(gcd_y,prec.rgh); 1290 } 1291 nPrec++; 1292 } // precincts 1293 } // resolution levels 1294 } // components 1295 1296 if(nPrec==0) { 1297 throw new Error("Image cannot have no precinct"); 1298 } 1299 1300 int pyend = (maxy-miny)/gcd_y+1; 1301 int pxend = (maxx-minx)/gcd_x+1; 1302 int x,y; 1303 int hlen,plen; 1304 int start; 1305 boolean status = false; 1306 int lastByte = firstPackOff[t][curTilePart]+ 1307 tilePartLen[t][curTilePart]-1- 1308 tilePartHeadLen[t][curTilePart]; 1309 int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); 1310 String strInfo = printInfo ? 1311 "Tile "+getTileIdx()+" (tile-part:"+curTilePart+ 1312 "): offset, length, header length\n" : null; 1313 boolean pph = false; 1314 if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { 1315 pph = true; 1316 } 1317 for(int r=ress; r<rese; r++) { // loop on resolution levels 1318 y = ty0; 1319 x = tx0; 1320 for(int py=0; py<=pyend; py++) { // Vertical precincts 1321 for(int px=0; px<=pxend; px++) { // Horiz. precincts 1322 for(int c=comps; c<compe; c++) { // Components 1323 if(c>=mdl.length) continue; 1324 if(r>mdl[c]) continue; 1325 if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) { 1326 continue; 1327 } 1328 prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]); 1329 if((prec.rgulx!=x) || (prec.rguly!=y)) { 1330 continue; 1331 } 1332 for(int l=minlys; l<lye; l++) { // layers 1333 if(r>=lys[c].length) continue; 1334 if(l<lys[c][r] || l>=numLayers) continue; 1335 1336 start = in.getPos(); 1337 1338 // If packed packet headers are used, there is no 1339 // need to check that there are bytes enough to 1340 // read header 1341 if(pph) { 1342 pktDec.readPktHead(l,r,c,nextPrec[c][r], 1343 cbI[c][r],nBytes); 1344 } 1345 // If we are about to read outside of tile-part, 1346 // skip to next tile-part 1347 if(start>lastByte && 1348 curTilePart<firstPackOff[t].length-1) { 1349 curTilePart++; 1350 in.seek(firstPackOff[t][curTilePart]); 1351 lastByte = in.getPos()+ 1352 tilePartLen[t][curTilePart]-1- 1353 tilePartHeadLen[t][curTilePart]; 1354 } 1355 1356 // Read SOP marker segment if necessary 1357 status = pktDec.readSOPMarker(nBytes, 1358 nextPrec[c][r],c,r); 1359 1360 if(status) { 1361 if(printInfo) { 1362 FacilityManager.getMsgLogger(). 1363 printmsg(MsgLogger.INFO,strInfo); 1364 } 1365 return true; 1366 } 1367 1368 if(!pph) { 1369 status = 1370 pktDec.readPktHead(l,r,c, 1371 nextPrec[c][r], 1372 cbI[c][r],nBytes); 1373 } 1374 1375 if(status) { 1376 if(printInfo) { 1377 FacilityManager.getMsgLogger(). 1378 printmsg(MsgLogger.INFO,strInfo); 1379 } 1380 return true; 1381 } 1382 1383 // Store packet's head length 1384 hlen = in.getPos()-start; 1385 pktHL.addElement(new Integer(hlen)); 1386 1387 1388 // Reads packet's body 1389 status = pktDec.readPktBody(l,r,c,nextPrec[c][r], 1390 cbI[c][r],nBytes); 1391 plen = in.getPos()-start; 1392 if(printInfo) 1393 strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+ 1394 nextPrec[c][r]+": "+ 1395 start+", "+plen+", "+hlen+"\n"; 1396 1397 if(status) { 1398 if(printInfo) { 1399 FacilityManager.getMsgLogger(). 1400 printmsg(MsgLogger.INFO,strInfo); 1401 } 1402 return true; 1403 } 1404 } // layers 1405 nextPrec[c][r]++; 1406 } // Components 1407 if(px!=pxend) { 1408 x = minx+px*gcd_x; 1409 } else { 1410 x = tx0; 1411 } 1412 } // Horizontal precincts 1413 if(py!=pyend) { 1414 y = miny+py*gcd_y; 1415 } else { 1416 y = ty0; 1417 } 1418 } // Vertical precincts 1419 } // end loop on resolution levels 1420 1421 if(printInfo) { 1422 FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo); 1423 } 1424 return false; // Decoding rate was not reached 1425 } 1426 1427 /** 1428 * Reads packets of the current tile according to the 1429 * position-component-resolution-layer progressiveness. 1430 * 1431 * @param lys Index of the first layer for each component and resolution. 1432 * 1433 * @param lye Index of the last layer. 1434 * 1435 * @param ress Index of the first resolution level. 1436 * 1437 * @param rese Index of the last resolution level. 1438 * 1439 * @param comps Index of the first component. 1440 * 1441 * @param compe Index of the last component. 1442 * 1443 * @return True if rate has been reached. 1444 * */ 1445 private boolean readPosCompResLy(int[][] lys,int lye,int ress,int rese, 1446 int comps,int compe) 1447 throws IOException { 1448 Point nTiles = getNumTiles(null); 1449 Point tileI = getTile(null); 1450 int x0siz = hd.getImgULX(); 1451 int y0siz = hd.getImgULY(); 1452 int xsiz = x0siz + hd.getImgWidth(); 1453 int ysiz = y0siz + hd.getImgHeight(); 1454 int xt0siz = getTilePartULX(); 1455 int yt0siz = getTilePartULY(); 1456 int xtsiz = getNomTileWidth(); 1457 int ytsiz = getNomTileHeight(); 1458 int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz; 1459 int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz; 1460 int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz; 1461 int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz; 1462 1463 // Get precinct information (number,distance between two consecutive 1464 // precincts in the reference grid) in each component and resolution 1465 // level 1466 int t = getTileIdx(); // Current tile index 1467 PrecInfo prec; // temporary variable 1468 int p; // Current precinct index 1469 int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid 1470 int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid 1471 int nPrec = 0; // Total number of found precincts 1472 int[][] nextPrec = new int [compe][]; // Next precinct index in each 1473 // component and resolution level 1474 int minlys = 100000; // minimum layer start index of each component 1475 int minx = tx1; // Horiz. offset of the second precinct in the 1476 // reference grid 1477 int miny = ty1; // Vert. offset of the second precinct in the 1478 // reference grid. 1479 int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid 1480 int maxy = ty0; // Max. vert. offset of precincts in the ref. grid 1481 Point numPrec; 1482 for(int c=comps; c<compe; c++) { // components 1483 for(int r=ress; r<rese; r++) { // resolution levels 1484 if(c>=mdl.length) continue; 1485 if(r>mdl[c]) continue; 1486 nextPrec[c] = new int[mdl[c]+1]; 1487 if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) { 1488 minlys = lys[c][r]; 1489 } 1490 p = pktDec.getNumPrecinct(c,r)-1; 1491 for(; p>=0; p--) { 1492 prec = pktDec.getPrecInfo(c,r,p); 1493 if(prec.rgulx!=tx0) { 1494 if(prec.rgulx<minx) minx = prec.rgulx; 1495 if(prec.rgulx>maxx) maxx = prec.rgulx; 1496 } 1497 if(prec.rguly!=ty0) { 1498 if(prec.rguly<miny) miny = prec.rguly; 1499 if(prec.rguly>maxy) maxy = prec.rguly; 1500 } 1501 1502 if(nPrec==0) { 1503 gcd_x = prec.rgw; 1504 gcd_y = prec.rgh; 1505 } else { 1506 gcd_x = MathUtil.gcd(gcd_x,prec.rgw); 1507 gcd_y = MathUtil.gcd(gcd_y,prec.rgh); 1508 } 1509 nPrec++; 1510 } // precincts 1511 } // resolution levels 1512 } // components 1513 1514 if(nPrec==0) { 1515 throw new Error("Image cannot have no precinct"); 1516 } 1517 1518 int pyend = (maxy-miny)/gcd_y+1; 1519 int pxend = (maxx-minx)/gcd_x+1; 1520 int hlen,plen; 1521 int start; 1522 boolean status = false; 1523 int lastByte = firstPackOff[t][curTilePart]+ 1524 tilePartLen[t][curTilePart]-1- 1525 tilePartHeadLen[t][curTilePart]; 1526 int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); 1527 String strInfo = printInfo ? 1528 "Tile "+getTileIdx()+" (tile-part:"+curTilePart+ 1529 "): offset, length, header length\n" : null; 1530 boolean pph = false; 1531 if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { 1532 pph = true; 1533 } 1534 1535 int y = ty0; 1536 int x = tx0; 1537 for(int py=0; py<=pyend; py++) { // Vertical precincts 1538 for(int px=0; px<=pxend; px++) { // Horiz. precincts 1539 for(int c=comps; c<compe; c++) { // Components 1540 if(c>=mdl.length) continue; 1541 for(int r=ress; r<rese; r++) { // Resolution levels 1542 if(r>mdl[c]) continue; 1543 if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) { 1544 continue; 1545 } 1546 prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]); 1547 if((prec.rgulx!=x) || (prec.rguly!=y)) { 1548 continue; 1549 } 1550 for(int l=minlys; l<lye; l++) { // Layers 1551 if(r>=lys[c].length) continue; 1552 if(l<lys[c][r] || l>=numLayers) continue; 1553 1554 start = in.getPos(); 1555 1556 // If packed packet headers are used, there is no 1557 // need to check that there are bytes enough to 1558 // read header 1559 if(pph) { 1560 pktDec.readPktHead(l,r,c,nextPrec[c][r], 1561 cbI[c][r],nBytes); 1562 } 1563 // Read SOP marker segment if necessary 1564 status = pktDec.readSOPMarker(nBytes, 1565 nextPrec[c][r],c,r); 1566 1567 if(status) { 1568 if(printInfo) { 1569 FacilityManager.getMsgLogger(). 1570 printmsg(MsgLogger.INFO,strInfo); 1571 } 1572 return true; 1573 } 1574 1575 if(!pph) { 1576 status = 1577 pktDec.readPktHead(l,r,c, 1578 nextPrec[c][r], 1579 cbI[c][r],nBytes); 1580 } 1581 1582 if(status) { 1583 if(printInfo) { 1584 FacilityManager.getMsgLogger(). 1585 printmsg(MsgLogger.INFO,strInfo); 1586 } 1587 return true; 1588 } 1589 1590 // Store packet's head length 1591 hlen = in.getPos()-start; 1592 pktHL.addElement(new Integer(hlen)); 1593 1594 // Reads packet's body 1595 status = pktDec.readPktBody(l,r,c,nextPrec[c][r], 1596 cbI[c][r],nBytes); 1597 plen = in.getPos()-start; 1598 if(printInfo) 1599 strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+ 1600 nextPrec[c][r]+": "+ 1601 start+", "+plen+", "+hlen+"\n"; 1602 1603 if(status) { 1604 if(printInfo) { 1605 FacilityManager.getMsgLogger(). 1606 printmsg(MsgLogger.INFO,strInfo); 1607 } 1608 return true; 1609 } 1610 1611 } // layers 1612 nextPrec[c][r]++; 1613 } // Resolution levels 1614 } // Components 1615 if(px!=pxend) { 1616 x = minx+px*gcd_x; 1617 } else { 1618 x = tx0; 1619 } 1620 } // Horizontal precincts 1621 if(py!=pyend) { 1622 y = miny+py*gcd_y; 1623 } else { 1624 y = ty0; 1625 } 1626 } // Vertical precincts 1627 1628 if(printInfo) { 1629 FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo); 1630 } 1631 return false; // Decoding rate was not reached 1632 } 1633 1634 /** 1635 * Reads packets of the current tile according to the 1636 * component-position-resolution-layer progressiveness. 1637 * 1638 * @param lys Index of the first layer for each component and resolution. 1639 * 1640 * @param lye Index of the last layer. 1641 * 1642 * @param ress Index of the first resolution level. 1643 * 1644 * @param rese Index of the last resolution level. 1645 * 1646 * @param comps Index of the first component. 1647 * 1648 * @param compe Index of the last component. 1649 * 1650 * @return True if rate has been reached. 1651 * */ 1652 private boolean readCompPosResLy(int lys[][],int lye,int ress,int rese, 1653 int comps,int compe) 1654 throws IOException { 1655 Point nTiles = getNumTiles(null); 1656 Point tileI = getTile(null); 1657 int x0siz = hd.getImgULX(); 1658 int y0siz = hd.getImgULY(); 1659 int xsiz = x0siz + hd.getImgWidth(); 1660 int ysiz = y0siz + hd.getImgHeight(); 1661 int xt0siz = getTilePartULX(); 1662 int yt0siz = getTilePartULY(); 1663 int xtsiz = getNomTileWidth(); 1664 int ytsiz = getNomTileHeight(); 1665 int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz; 1666 int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz; 1667 int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz; 1668 int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz; 1669 1670 // Get precinct information (number,distance between two consecutive 1671 // precincts in the reference grid) in each component and resolution 1672 // level 1673 int t = getTileIdx(); // Current tile index 1674 PrecInfo prec; // temporary variable 1675 int p; // Current precinct index 1676 int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid 1677 int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid 1678 int nPrec = 0; // Total number of found precincts 1679 int[][] nextPrec = new int [compe][]; // Next precinct index in each 1680 // component and resolution level 1681 int minlys = 100000; // minimum layer start index of each component 1682 int minx = tx1; // Horiz. offset of the second precinct in the 1683 // reference grid 1684 int miny = ty1; // Vert. offset of the second precinct in the 1685 // reference grid. 1686 int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid 1687 int maxy = ty0; // Max. vert. offset of precincts in the ref. grid 1688 Point numPrec; 1689 for(int c=comps; c<compe; c++) { // components 1690 for(int r=ress; r<rese; r++) { // resolution levels 1691 if(c>=mdl.length) continue; 1692 if(r>mdl[c]) continue; 1693 nextPrec[c] = new int[mdl[c]+1]; 1694 if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) { 1695 minlys = lys[c][r]; 1696 } 1697 p = pktDec.getNumPrecinct(c,r)-1; 1698 for(; p>=0; p--) { 1699 prec = pktDec.getPrecInfo(c,r,p); 1700 if(prec.rgulx!=tx0) { 1701 if(prec.rgulx<minx) minx = prec.rgulx; 1702 if(prec.rgulx>maxx) maxx = prec.rgulx; 1703 } 1704 if(prec.rguly!=ty0) { 1705 if(prec.rguly<miny) miny = prec.rguly; 1706 if(prec.rguly>maxy) maxy = prec.rguly; 1707 } 1708 1709 if(nPrec==0) { 1710 gcd_x = prec.rgw; 1711 gcd_y = prec.rgh; 1712 } else { 1713 gcd_x = MathUtil.gcd(gcd_x,prec.rgw); 1714 gcd_y = MathUtil.gcd(gcd_y,prec.rgh); 1715 } 1716 nPrec++; 1717 } // precincts 1718 } // resolution levels 1719 } // components 1720 1721 if(nPrec==0) { 1722 throw new Error("Image cannot have no precinct"); 1723 } 1724 1725 int pyend = (maxy-miny)/gcd_y+1; 1726 int pxend = (maxx-minx)/gcd_x+1; 1727 int hlen,plen; 1728 int start; 1729 boolean status = false; 1730 int lastByte = firstPackOff[t][curTilePart]+ 1731 tilePartLen[t][curTilePart]-1- 1732 tilePartHeadLen[t][curTilePart]; 1733 int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); 1734 String strInfo = printInfo ? 1735 "Tile "+getTileIdx()+" (tile-part:"+curTilePart+ 1736 "): offset, length, header length\n" : null; 1737 boolean pph = false; 1738 if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { 1739 pph = true; 1740 } 1741 1742 int x,y; 1743 for(int c=comps; c<compe; c++) { // components 1744 if(c>=mdl.length) continue; 1745 y = ty0; 1746 x = tx0; 1747 for(int py=0; py<=pyend; py++) { // Vertical precincts 1748 for(int px=0; px<=pxend; px++) { // Horiz. precincts 1749 for(int r=ress; r<rese; r++) { // Resolution levels 1750 if(r>mdl[c]) continue; 1751 if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) { 1752 continue; 1753 } 1754 prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]); 1755 if((prec.rgulx!=x) || (prec.rguly!=y)) { 1756 continue; 1757 } 1758 1759 for(int l=minlys; l<lye; l++) { // Layers 1760 if(r>=lys[c].length) continue; 1761 if(l<lys[c][r]) continue; 1762 1763 start = in.getPos(); 1764 1765 // If packed packet headers are used, there is no 1766 // need to check that there are bytes enough to 1767 // read header 1768 if(pph) { 1769 pktDec.readPktHead(l,r,c,nextPrec[c][r], 1770 cbI[c][r],nBytes); 1771 } 1772 // If we are about to read outside of tile-part, 1773 // skip to next tile-part 1774 if(start>lastByte && 1775 curTilePart<firstPackOff[t].length-1) { 1776 curTilePart++; 1777 in.seek(firstPackOff[t][curTilePart]); 1778 lastByte = in.getPos()+ 1779 tilePartLen[t][curTilePart]-1- 1780 tilePartHeadLen[t][curTilePart]; 1781 } 1782 1783 // Read SOP marker segment if necessary 1784 status = pktDec.readSOPMarker(nBytes, 1785 nextPrec[c][r],c,r); 1786 1787 if(status) { 1788 if(printInfo) { 1789 FacilityManager.getMsgLogger(). 1790 printmsg(MsgLogger.INFO,strInfo); 1791 } 1792 return true; 1793 } 1794 1795 if(!pph) { 1796 status = 1797 pktDec.readPktHead(l,r,c, 1798 nextPrec[c][r], 1799 cbI[c][r],nBytes); 1800 } 1801 1802 if(status) { 1803 if(printInfo) { 1804 FacilityManager.getMsgLogger(). 1805 printmsg(MsgLogger.INFO,strInfo); 1806 } 1807 return true; 1808 } 1809 1810 // Store packet's head length 1811 hlen = in.getPos()-start; 1812 pktHL.addElement(new Integer(hlen)); 1813 1814 // Reads packet's body 1815 status = pktDec.readPktBody(l,r,c,nextPrec[c][r], 1816 cbI[c][r],nBytes); 1817 plen = in.getPos()-start; 1818 if(printInfo) 1819 strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+ 1820 nextPrec[c][r]+": "+ 1821 start+", "+plen+", "+hlen+"\n"; 1822 1823 if(status) { 1824 if(printInfo) { 1825 FacilityManager.getMsgLogger(). 1826 printmsg(MsgLogger.INFO,strInfo); 1827 } 1828 return true; 1829 } 1830 1831 } // layers 1832 nextPrec[c][r]++; 1833 } // Resolution levels 1834 if(px!=pxend) { 1835 x = minx+px*gcd_x; 1836 } else { 1837 x = tx0; 1838 } 1839 } // Horizontal precincts 1840 if(py!=pyend) { 1841 y = miny+py*gcd_y; 1842 } else { 1843 y = ty0; 1844 } 1845 } // Vertical precincts 1846 } // components 1847 1848 if(printInfo) { 1849 FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo); 1850 } 1851 return false; // Decoding rate was not reached 1852 } 1853 1854 /** 1855 * Finish initialization of members for specified tile, reads packets head 1856 * of each tile and keeps location of each code-block's codewords. The 1857 * last 2 tasks are done by calling specific methods of PktDecoder. 1858 * 1859 * <p>Then, if a parsing output rate is defined, it keeps information of 1860 * first layers only. This operation simulates a creation of a 1861 * layer-resolution-component progressive bit-stream which will be next 1862 * truncated and decoded.</p> 1863 * 1864 * @param t Tile index 1865 * 1866 * @see PktDecoder 1867 * */ 1868 private void readTilePkts(int t) throws IOException { 1869 pktHL = new Vector(); 1870 1871 int oldNBytes = nBytes[t]; 1872 1873 // Number of layers 1874 int nl = ((Integer)decSpec.nls.getTileDef(t)).intValue(); 1875 1876 // If packed packet headers was used, get the packet headers for this 1877 // tile 1878 if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { 1879 // Gets packed headers as separate input stream 1880 ByteArrayInputStream pphbais = hd.getPackedPktHead(t); 1881 1882 // Restarts PktDecoder instance 1883 cbI = pktDec.restart(nc,mdl,nl,cbI,true,pphbais); 1884 } else { 1885 // Restarts PktDecoder instance 1886 cbI = pktDec.restart(nc,mdl,nl,cbI,false,null); 1887 } 1888 1889 // Reads packets of the tile according to the progression order 1890 int[][] pocSpec = ((int[][])decSpec.pcs.getTileDef(t)); 1891 int nChg = (pocSpec==null) ? 1 : pocSpec.length; 1892 1893 // Create an array containing information about changes (progression 1894 // order type, layers index start, layer index end, resolution level 1895 // start, resolution level end, component index start, component index 1896 // end). There is one row per progresion order 1897 int[][] change = new int[nChg][6]; 1898 int idx = 0; // Index of the current progression order 1899 1900 change[0][1] = 0; // layer start 1901 1902 if(pocSpec==null) { 1903 change[idx][0] = ((Integer)decSpec.pos.getTileDef(t)).intValue(); 1904 // Progression type found in COx marker segments 1905 change[idx][1] = nl; // Layer index end 1906 change[idx][2] = 0; // resolution level start 1907 change[idx][3] = decSpec.dls.getMaxInTile(t)+1; // res. level end 1908 change[idx][4] = 0; // Component index start 1909 change[idx][5] = nc; // Component index end 1910 } else { 1911 for(idx=0; idx<nChg; idx++){ 1912 change[idx][0] = pocSpec[idx][5]; 1913 change[idx][1] = pocSpec[idx][2]; // layer end 1914 change[idx][2] = pocSpec[idx][0]; // res. lev. start 1915 change[idx][3] = pocSpec[idx][3]; // res. lev. end 1916 change[idx][4] = pocSpec[idx][1]; // Comp. index start 1917 change[idx][5] = pocSpec[idx][4]; // Comp. index end 1918 } 1919 } 1920 1921 // Seeks to the first packet of the first tile-part 1922 try { 1923 // If in truncation mode, the first tile-part may be beyond the 1924 // target decoding rate. In this case, the offset of the first 1925 // packet is not defined. 1926 if(isTruncMode && firstPackOff==null || firstPackOff[t]==null) { 1927 return; 1928 } 1929 in.seek(firstPackOff[t][0]); 1930 } catch(EOFException e) { 1931 FacilityManager.getMsgLogger(). 1932 printmsg(MsgLogger.WARNING,"Codestream truncated in tile "+t); 1933 return; 1934 } 1935 1936 curTilePart = 0; 1937 1938 // Start and end indexes for layers, resolution levels and components. 1939 int lye,ress,rese,comps,compe; 1940 boolean status = false; 1941 int nb = nBytes[t]; 1942 int[][] lys = new int[nc][]; 1943 for(int c=0; c<nc; c++) { 1944 lys[c] = new int[((Integer)decSpec.dls.getTileCompVal(t,c)). 1945 intValue()+1]; 1946 } 1947 1948 1949 try { 1950 for(int chg=0; chg<nChg; chg++) { 1951 1952 lye = change[chg][1]; 1953 ress = change[chg][2]; 1954 rese = change[chg][3]; 1955 comps = change[chg][4]; 1956 compe = change[chg][5]; 1957 1958 switch(change[chg][0]) { 1959 case LY_RES_COMP_POS_PROG: 1960 status = readLyResCompPos(lys,lye,ress,rese,comps,compe); 1961 break; 1962 case RES_LY_COMP_POS_PROG: 1963 status = readResLyCompPos(lys,lye,ress,rese,comps,compe); 1964 break; 1965 case RES_POS_COMP_LY_PROG: 1966 status = readResPosCompLy(lys,lye,ress,rese,comps,compe); 1967 break; 1968 case POS_COMP_RES_LY_PROG: 1969 status = readPosCompResLy(lys,lye,ress,rese,comps,compe); 1970 break; 1971 case COMP_POS_RES_LY_PROG: 1972 status = readCompPosResLy(lys,lye,ress,rese,comps,compe); 1973 break; 1974 default: 1975 throw new IllegalArgumentException("Not recognized "+ 1976 "progression type"); 1977 } 1978 1979 // Update next first layer index 1980 for(int c=comps; c<compe; c++) { 1981 if(c>=lys.length) continue; 1982 for(int r=ress; r<rese; r++) { 1983 if(r>=lys[c].length) continue; 1984 lys[c][r] = lye; 1985 } 1986 } 1987 1988 if(status || usePOCQuit) { 1989 break; 1990 } 1991 } 1992 } catch(EOFException e) { 1993 // Should never happen. Truncated codestream are normally found by 1994 // the class constructor 1995 throw e; 1996 } 1997 1998 // In truncation mode, update the number of read bytes 1999 if(isTruncMode) { 2000 anbytes += nb-nBytes[t]; 2001 2002 // If truncation rate is reached 2003 if(status) { 2004 nBytes[t] = 0; 2005 } 2006 } else if(nBytes[t]<(totTileLen[t]-totTileHeadLen[t])) { 2007 // In parsing mode, if there is not enough rate to entirely read the 2008 // tile. Then, parses the bit stream so as to create a virtual 2009 // layer-resolution-component progressive bit stream that will be 2010 // truncated and decoded afterwards. 2011 CBlkInfo cb; 2012 2013 // Systematicaly reject all remaining code-blocks if one 2014 // code-block, at least, is refused. 2015 boolean reject; 2016 // Stop reading any data from the bit stream 2017 boolean stopCount = false; 2018 // Length of each packet's head (in an array) 2019 int[] pktHeadLen = new int[pktHL.size()]; 2020 for(int i=pktHL.size()-1;i>=0;i--) { 2021 pktHeadLen[i] = ((Integer)pktHL.elementAt(i)).intValue(); 2022 } 2023 2024 // Parse each code-block, layer per layer until nBytes[t] is 2025 // reached 2026 reject = false; 2027 for(int l=0; l<nl; l++) { // layers 2028 if(cbI==null) continue; 2029 int nc = cbI.length; 2030 2031 int mres = 0; 2032 for(int c=0; c<nc; c++) { 2033 if(cbI[c]!=null && cbI[c].length>mres) 2034 mres = cbI[c].length; 2035 } 2036 for(int r=0; r<mres; r++) { // resolutions 2037 2038 2039 int msub = 0; 2040 for(int c=0; c<nc; c++) { 2041 if(cbI[c]!=null && cbI[c][r]!=null 2042 && cbI[c][r].length>msub) 2043 msub = cbI[c][r].length; 2044 } 2045 for(int s=0; s<msub; s++) { // subbands 2046 // Only LL subband resolution level 0 2047 if(r==0 && s!=0) { 2048 continue; 2049 } else if(r!=0 && s==0) { 2050 // No LL subband in resolution level > 0 2051 continue; 2052 } 2053 2054 int mnby=0; 2055 for(int c=0; c<nc; c++) { 2056 if(cbI[c]!=null && cbI[c][r]!=null && 2057 cbI[c][r][s]!=null && 2058 cbI[c][r][s].length>mnby) 2059 mnby = cbI[c][r][s].length; 2060 } 2061 for(int m=0; m<mnby; m++) { 2062 2063 int mnbx = 0; 2064 for(int c=0; c<nc; c++) { 2065 if(cbI[c]!=null && cbI[c][r]!=null && 2066 cbI[c][r][s]!=null && cbI[c][r][s][m]!=null 2067 && cbI[c][r][s][m].length>mnbx) 2068 mnbx = cbI[c][r][s][m].length; 2069 } 2070 for(int n=0; n<mnbx; n++) { 2071 2072 for(int c=0; c<nc; c++) { 2073 2074 if(cbI[c]==null || cbI[c][r]==null || 2075 cbI[c][r][s]==null || 2076 cbI[c][r][s][m]==null || 2077 cbI[c][r][s][m][n]==null ) { 2078 continue; 2079 } 2080 cb = cbI[c][r][s][m][n]; 2081 2082 // If no code-block has been refused until 2083 // now 2084 if(!reject) { 2085 // Rate is to low to allow reading of 2086 // packet's head 2087 if(nBytes[t]<pktHeadLen[cb.pktIdx[l]]){ 2088 // Stop parsing 2089 stopCount = true; 2090 // Reject all next 2091 // code-blocks 2092 reject=true; 2093 } else { 2094 // Rate is enough to read packet's 2095 // head 2096 if(!stopCount) { 2097 //If parsing was not stopped 2098 //Takes into account packet's 2099 //head length 2100 nBytes[t] -= 2101 pktHeadLen[cb.pktIdx[l]]; 2102 anbytes += 2103 pktHeadLen[cb.pktIdx[l]]; 2104 // Set packet's head length to 2105 // 0, so that it won't be 2106 // taken into account next 2107 // time 2108 pktHeadLen[cb.pktIdx[l]]=0; 2109 } 2110 } 2111 } 2112 // Code-block has no data in this layer 2113 if(cb.len[l]==0) { 2114 continue; 2115 } 2116 2117 // Accepts code-block if length is enough, 2118 // if this code-block was not refused in a 2119 // previous layer and if no code-block was 2120 // refused in current component 2121 if(cb.len[l]<nBytes[t] 2122 && !reject){ 2123 nBytes[t] -= cb.len[l]; 2124 anbytes += cb.len[l]; 2125 } else { 2126 // Refuses code-block 2127 // Forgets code-block's data 2128 cb.len[l]=cb.off[l]=cb.ntp[l]= 0; 2129 // Refuses all other code-block in 2130 // current and next component 2131 reject=true; 2132 } 2133 2134 } // End loop on components 2135 } // End loop on horiz. code-blocks 2136 } // End loop on vert. code-blocks 2137 } // End loop on subbands 2138 } // End loop on resolutions 2139 } // End loop on layers 2140 } else { 2141 // No parsing for this tile, adds tile's body to the total 2142 // number of read bytes. 2143 anbytes += totTileLen[t]-totTileHeadLen[t]; 2144 if(t<getNumTiles()-1) { 2145 nBytes[t+1] += nBytes[t]-(totTileLen[t]-totTileHeadLen[t]); 2146 } 2147 } 2148 2149 // In this method nBytes[t] might be changed. This change will affect 2150 // to decode this tile next time. So cache the old nByte[t] and 2151 // recover it here. -- Qinghuai Gao 2152 nBytes[t] = oldNBytes; 2153 } 2154 2155 /** 2156 * Changes the current tile, given the new indexes. An 2157 * IllegalArgumentException is thrown if the indexes do not correspond to 2158 * a valid tile. 2159 * 2160 * @param x The horizontal indexes the tile. 2161 * 2162 * @param y The vertical indexes of the new tile. 2163 * */ 2164 public void setTile(int x,int y) { 2165 2166 int i; // counter 2167 // Check validity of tile indexes 2168 if (x<0 || y<0 || x>=ntX || y>=ntY) { 2169 throw new IllegalArgumentException(); 2170 } 2171 int t = (y*ntX+x); 2172 try { 2173 initTile(t); 2174 } catch(IOException ioe) { 2175 // XXX Do something! 2176 } 2177 2178 // Reset number of read bytes if needed 2179 if(t==0) { 2180 anbytes = headLen; 2181 if(!isTruncMode) { 2182 anbytes += 2; 2183 } 2184 // Restore values of nBytes 2185 for(int tIdx=0; tIdx<nt; tIdx++) { 2186 nBytes[tIdx] = baknBytes[tIdx]; 2187 } 2188 } 2189 2190 // Set the new current tile 2191 ctX = x; 2192 ctY = y; 2193 // Calculate tile relative points 2194 int ctox = (x == 0) ? ax : px+x*ntW; 2195 int ctoy = (y == 0) ? ay : py+y*ntH; 2196 for (i=nc-1; i>=0; i--) { 2197 culx[i] = (ctox+hd.getCompSubsX(i)-1)/hd.getCompSubsX(i); 2198 culy[i] = (ctoy+hd.getCompSubsY(i)-1)/hd.getCompSubsY(i); 2199 offX[i] = (px+x*ntW+hd.getCompSubsX(i)-1)/hd.getCompSubsX(i); 2200 offY[i] = (py+y*ntH+hd.getCompSubsY(i)-1)/hd.getCompSubsY(i); 2201 } 2202 2203 // Initialize subband tree and number of resolution levels 2204 subbTrees = new SubbandSyn[nc]; 2205 mdl = new int[nc]; 2206 derived = new boolean[nc]; 2207 params = new StdDequantizerParams[nc]; 2208 gb = new int[nc]; 2209 2210 for(int c=0; c<nc; c++){ 2211 derived[c] = decSpec.qts.isDerived(t,c); 2212 params[c] = 2213 (StdDequantizerParams)decSpec.qsss.getTileCompVal(t,c); 2214 gb[c] = ((Integer)decSpec.gbs.getTileCompVal(t,c)).intValue(); 2215 mdl[c] = ((Integer)decSpec.dls.getTileCompVal(t,c)).intValue(); 2216 2217 subbTrees[c] = 2218 new SubbandSyn(getTileCompWidth(t,c,mdl[c]), 2219 getTileCompHeight(t,c,mdl[c]), 2220 getResULX(c,mdl[c]),getResULY(c,mdl[c]),mdl[c], 2221 decSpec.wfs.getHFilters(t,c), 2222 decSpec.wfs.getVFilters(t,c)); 2223 initSubbandsFields(c,subbTrees[c]); 2224 } 2225 2226 // Read tile's packets 2227 try { 2228 readTilePkts(t); 2229 } catch(IOException e) { 2230 e.printStackTrace(); 2231 throw new Error("IO Error when reading tile "+x+" x "+y); 2232 } 2233 } 2234 2235 2236 /** 2237 * Advances to the next tile, in standard scan-line order (by rows 2238 * then columns). An NoNextElementException is thrown if the 2239 * current tile is the last one (i.e. there is no next tile). 2240 * */ 2241 public void nextTile(){ 2242 if (ctX == ntX-1 && ctY == ntY-1) { // Already at last tile 2243 throw new NoNextElementException(); 2244 } 2245 else if (ctX < ntX-1) { // If not at end of current tile line 2246 setTile(ctX+1,ctY); 2247 } 2248 else { // Go to first tile at next line 2249 setTile(0,ctY+1); 2250 } 2251 } 2252 2253 /** 2254 * Returns the specified coded code-block, for the specified component, in 2255 * the current tile. The first layer to return is indicated by 'fl'. The 2256 * number of layers that is returned depends on 'nl' and the amount of 2257 * available data. 2258 * 2259 * <p>The argument 'fl' is to be used by subsequent calls to this method 2260 * for the same code-block. In this way supplemental data can be retrieved 2261 * at a later time. The fact that data from more than one layer can be 2262 * returned means that several packets from the same code-block, of the 2263 * same component, and the same tile, have been concatenated.</p> 2264 * 2265 * <p>The returned compressed code-block can have its progressive 2266 * attribute set. If this attribute is set it means that more data can be 2267 * obtained by subsequent calls to this method (subject to transmission 2268 * delays, etc). If the progressive attribute is not set it means that the 2269 * returned data is all the data that can be obtained for the specified 2270 * code-block.</p> 2271 * 2272 * <p>The compressed code-block is uniquely specified by the current tile, 2273 * the component (identified by 'c'), the subband (indentified by 'sb') 2274 * and the code-block vertical and horizontal indexes 'n' and 'm'.</p> 2275 * 2276 * <p>The 'ulx' and 'uly' members of the returned 'DecLyrdCBlk' object 2277 * contain the coordinates of the top-left corner of the block, with 2278 * respect to the tile, not the subband.</p> 2279 * 2280 * @param c The index of the component, from 0 to N-1. 2281 * 2282 * @param m The vertical index of the code-block to return, in the 2283 * specified subband. 2284 * 2285 * @param n The horizontal index of the code-block to return, in the 2286 * specified subband. 2287 * 2288 * @param sb The subband in whic the requested code-block is. 2289 * 2290 * @param fl The first layer to return. 2291 * 2292 * @param nl The number of layers to return, if negative all available 2293 * layers are returned, starting at 'fl'. 2294 * 2295 * @param ccb If not null this object is used to return the compressed 2296 * code-block. If null a new object is created and returned. If the data 2297 * array in ccb is not null then it can be reused to return the compressed 2298 * data. 2299 * @return The compressed code-block, with a certain number of layers 2300 * determined by the available data and 'nl'. 2301 * */ 2302 public DecLyrdCBlk getCodeBlock(int c,int m,int n,SubbandSyn sb,int fl, 2303 int nl,DecLyrdCBlk ccb) { 2304 2305 int t = getTileIdx(); 2306 CBlkInfo rcb; // requested code-block 2307 int r = sb.resLvl; // Resolution level 2308 int s = sb.sbandIdx; // Subband index 2309 int tpidx; 2310 int passtype; 2311 2312 // Number of layers 2313 int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); 2314 int options = ((Integer)decSpec.ecopts.getTileCompVal(t,c)).intValue(); 2315 if(nl<0) { 2316 nl = numLayers-fl+1; 2317 } 2318 2319 // If the l quit condition is used, Make sure that no layer 2320 // after lquit is returned 2321 if(lQuit != -1 && fl+nl>lQuit){ 2322 nl = lQuit - fl; 2323 } 2324 2325 // Check validity of resquested resolution level (according to the 2326 // "-res" option). 2327 int maxdl = getSynSubbandTree(t,c).resLvl; 2328 /* XXX Suppress error check for speed performance reasons. 2329 if(r>targetRes+maxdl-decSpec.dls.getMin()) { 2330 throw new Error("JJ2000 error: requesting a code-block "+ 2331 "disallowed by the '-res' option."); 2332 } 2333 */ 2334 2335 // Check validity of all the arguments 2336 try { 2337 rcb = cbI[c][r][s][m][n]; 2338 2339 if(fl<1 || fl>numLayers || fl+nl-1>numLayers) { 2340 throw new IllegalArgumentException(); 2341 } 2342 } catch(ArrayIndexOutOfBoundsException e) { 2343 throw new IllegalArgumentException("Code-block (t:"+t+", c:"+ 2344 c+", r:"+r+", s:"+s+", "+m+"x"+ 2345 +n+") not found in codestream"); 2346 } catch(NullPointerException e) { 2347 throw new IllegalArgumentException("Code-block (t:"+t+", c:"+ 2348 c+", r:"+r+", s:"+s+", "+m+"x" 2349 +n+") not found in bit stream"); 2350 } 2351 2352 // Create DecLyrdCBlk object if necessary 2353 if(ccb==null) { 2354 ccb = new DecLyrdCBlk(); 2355 } 2356 ccb.m = m; 2357 ccb.n = n; 2358 ccb.nl = 0; 2359 ccb.dl = 0; 2360 ccb.nTrunc = 0; 2361 2362 if(rcb==null) { 2363 // This code-block was skipped when reading. Returns no data 2364 ccb.skipMSBP = 0; 2365 ccb.prog = false; 2366 ccb.w = ccb.h = ccb.ulx = ccb.uly = 0; 2367 return ccb; 2368 } 2369 2370 // ccb initialization 2371 ccb.skipMSBP = rcb.msbSkipped; 2372 ccb.ulx = rcb.ulx; 2373 ccb.uly = rcb.uly; 2374 ccb.w = rcb.w; 2375 ccb.h = rcb.h; 2376 ccb.ftpIdx = 0; 2377 2378 // Search for index of first truncation point (first layer where 2379 // length of data is not zero) 2380 int l=0; 2381 while( (l<rcb.len.length) && (rcb.len[l]==0)) { 2382 ccb.ftpIdx += rcb.ntp[l]; 2383 l++; 2384 } 2385 2386 // Calculate total length, number of included layer and number of 2387 // truncation points 2388 for(l=fl-1; l<fl+nl-1; l++) { 2389 ccb.nl++; 2390 ccb.dl += rcb.len[l]; 2391 ccb.nTrunc += rcb.ntp[l]; 2392 } 2393 2394 // Calculate number of terminated segments 2395 int nts; 2396 if((options & OPT_TERM_PASS) != 0) { 2397 // Regular termination in use One segment per pass 2398 // (i.e. truncation point) 2399 nts = ccb.nTrunc-ccb.ftpIdx; 2400 } else if((options & OPT_BYPASS) != 0) { 2401 // Selective arithmetic coding bypass mode in use, but no regular 2402 // termination: 1 segment upto the end of the last pass of the 4th 2403 // most significant bit-plane, and, in each following bit-plane, 2404 // one segment upto the end of the 2nd pass and one upto the end 2405 // of the 3rd pass. 2406 2407 if(ccb.nTrunc <= FIRST_BYPASS_PASS_IDX) { 2408 nts = 1; 2409 } else { 2410 nts = 1; 2411 // Adds one for each terminated pass 2412 for (tpidx = ccb.ftpIdx; tpidx < ccb.nTrunc; tpidx++) { 2413 if (tpidx >= FIRST_BYPASS_PASS_IDX-1) { 2414 passtype = 2415 (tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%NUM_PASSES; 2416 if (passtype == 1 || passtype == 2) { 2417 // lazy pass just before MQ pass or MQ pass just 2418 // before lazy pass => terminated 2419 nts++; 2420 } 2421 } 2422 } 2423 } 2424 } else { 2425 // Nothing special in use, just one terminated segment 2426 nts = 1; 2427 } 2428 2429 // ccb.data creation 2430 if(ccb.data==null || ccb.data.length<ccb.dl) { 2431 ccb.data = new byte[ccb.dl]; 2432 } 2433 2434 // ccb.tsLengths creation 2435 if (nts>1 && (ccb.tsLengths==null || ccb.tsLengths.length<nts)) { 2436 ccb.tsLengths = new int[nts]; 2437 } else if (nts>1 && 2438 (options & (OPT_BYPASS|OPT_TERM_PASS)) == OPT_BYPASS) { 2439 ArrayUtil.intArraySet(ccb.tsLengths,0); 2440 } 2441 2442 // Fill ccb with compressed data 2443 int dataIdx = -1; 2444 tpidx = ccb.ftpIdx; 2445 int ctp = ccb.ftpIdx; // Cumulative number of truncation 2446 // point for the current layer layer 2447 int tsidx=0; 2448 int j; 2449 2450 for(l=fl-1; l<fl+nl-1; l++) { 2451 ctp += rcb.ntp[l]; 2452 // No data in this layer 2453 if(rcb.len[l]==0) continue; 2454 2455 // Read data 2456 // NOTE: we should never get an EOFException here since all 2457 // data is checked to be within the file. 2458 try { 2459 in.seek(rcb.off[l]); 2460 in.readFully(ccb.data,dataIdx+1,rcb.len[l]); 2461 dataIdx += rcb.len[l]; 2462 } catch (IOException e) { 2463 JJ2KExceptionHandler.handleException(e); 2464 } 2465 2466 // Get the terminated segment lengths, if any 2467 if(nts==1) continue; 2468 if((options & OPT_TERM_PASS) != 0) { 2469 // Regular termination => each pass is terminated 2470 for(j=0; tpidx<ctp; j++,tpidx++) { 2471 if(rcb.segLen[l]!=null) { 2472 ccb.tsLengths[tsidx++] = rcb.segLen[l][j]; 2473 } else { // Only one terminated segment in packet 2474 ccb.tsLengths[tsidx++] = rcb.len[l]; 2475 } 2476 } 2477 } else { 2478 // Lazy coding without regular termination 2479 for(j=0; tpidx<ctp; tpidx++) { 2480 if(tpidx>=FIRST_BYPASS_PASS_IDX-1) { 2481 passtype = 2482 (tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%NUM_PASSES; 2483 if(passtype!=0) { 2484 // lazy pass just before MQ pass or MQ 2485 // pass just before lazy pass => 2486 // terminated 2487 if(rcb.segLen[l]!=null) { 2488 ccb.tsLengths[tsidx++] += rcb.segLen[l][j++]; 2489 rcb.len[l] -= rcb.segLen[l][j-1]; 2490 } else { // Only one terminated segment in packet 2491 ccb.tsLengths[tsidx++] += rcb.len[l]; 2492 rcb.len[l] = 0; 2493 } 2494 } 2495 2496 } 2497 } 2498 2499 // Last length in packet always in (either terminated segment 2500 // or contribution to terminated segment) 2501 if(rcb.segLen[l]!=null && j<rcb.segLen[l].length) { 2502 ccb.tsLengths[tsidx] += rcb.segLen[l][j]; 2503 rcb.len[l] -= rcb.segLen[l][j]; 2504 } else { // Only one terminated segment in packet 2505 if(tsidx<nts) { 2506 ccb.tsLengths[tsidx] += rcb.len[l]; 2507 rcb.len[l] = 0; 2508 } 2509 } 2510 } 2511 } 2512 if(nts==1 && ccb.tsLengths!=null) { 2513 ccb.tsLengths[0] = ccb.dl; 2514 } 2515 2516 // Set the progressive flag 2517 int lastlayer = fl+nl-1; 2518 if(lastlayer<numLayers-1){ 2519 for(l=lastlayer+1; l<numLayers; l++){ 2520 // It remains data for this code-block in the bit stream 2521 if(rcb.len[l]!=0){ 2522 ccb.prog = true; 2523 } 2524 } 2525 } 2526 2527 return ccb; 2528 } 2529 2530}