001/* 002 * $RCSfile: HeaderDecoder.java,v $ 003 * $Revision: 1.2 $ 004 * $Date: 2006/09/28 00:55:20 $ 005 * $State: Exp $ 006 * 007 * Class: HeaderDecoder 008 * 009 * Description: Reads main and tile-part headers. 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; 046import java.io.ByteArrayInputStream; 047import java.io.ByteArrayOutputStream; 048import java.io.DataInputStream; 049import java.io.EOFException; 050import java.io.IOException; 051import java.util.Hashtable; 052import java.util.Vector; 053 054import jj2000.j2k.ModuleSpec; 055import jj2000.j2k.NotImplementedError; 056import jj2000.j2k.codestream.CorruptedCodestreamException; 057import jj2000.j2k.codestream.HeaderInfo; 058import jj2000.j2k.codestream.Markers; 059import jj2000.j2k.codestream.ProgressionType; 060import jj2000.j2k.decoder.DecoderSpecs; 061import jj2000.j2k.entropy.StdEntropyCoderOptions; 062import jj2000.j2k.entropy.decoder.CodedCBlkDataSrcDec; 063import jj2000.j2k.entropy.decoder.EntropyDecoder; 064import jj2000.j2k.entropy.decoder.StdEntropyDecoder; 065import jj2000.j2k.io.RandomAccessIO; 066import jj2000.j2k.quantization.dequantizer.CBlkQuantDataSrcDec; 067import jj2000.j2k.quantization.dequantizer.Dequantizer; 068import jj2000.j2k.quantization.dequantizer.StdDequantizer; 069import jj2000.j2k.quantization.dequantizer.StdDequantizerParams; 070import jj2000.j2k.roi.MaxShiftSpec; 071import jj2000.j2k.roi.ROIDeScaler; 072import jj2000.j2k.util.FacilityManager; 073import jj2000.j2k.util.MsgLogger; 074import jj2000.j2k.wavelet.FilterTypes; 075import jj2000.j2k.wavelet.synthesis.SynWTFilter; 076import jj2000.j2k.wavelet.synthesis.SynWTFilterFloatLift9x7; 077import jj2000.j2k.wavelet.synthesis.SynWTFilterIntLift5x3; 078 079import com.github.jaiimageio.jpeg2000.impl.J2KImageReadParamJava; 080 081/** 082 * This class reads Main and Tile-part headers from the codestream. It is 083 * created by the run() method of the Decoder instance. 084 * 085 * <p>A marker segment includes a marker and eventually marker segment 086 * parameters. It is designed by the three letters code of the marker 087 * associated with the marker segment. JPEG 2000 part 1 defines 6 types of 088 * markers: 089 * 090 * <ul> 091 * <li> Delimiting : SOC,SOT (read in FileBitstreamReaderAgent),SOD,EOC 092 * (read in FileBitstreamReaderAgent).</li> <li> Fixed information: SIZ.</li> 093 * 094 * <li> Functional: COD,COC,RGN,QCD,QCC,POC.</li> <li> In bit-stream: 095 * SOP,EPH.</li> 096 * 097 * <li> Pointer: TLM,PLM,PLT,PPM,PPT.</li> 098 * 099 * <li> Informational: CRG,COM.</li> 100 * </ul> 101 * 102 * <p>The main header is read when the constructor is called whereas tile-part 103 * headers are read when the FileBitstreamReaderAgent instance is created. The 104 * reading is done in 2 passes: 105 * 106 * <ul> 107 * <li>All marker segments are buffered and their corresponding flag is 108 * activated (extractMainMarkSeg and extractTilePartMarkSeg methods).</li> 109 * 110 * <li>Buffered marker segment are analyzed in a logical way and 111 * specifications are stored in appropriate member of DecoderSpecs instance 112 * (readFoundMainMarkSeg and readFoundTilePartMarkSeg methods).</li> 113 * </ul> 114 * 115 * <p>Whenever a marker segment is not recognized a warning message is 116 * displayed and its length parameter is used to skip it. 117 * 118 * @see DecoderSpecs 119 * @see Decoder 120 * @see FileBitstreamReaderAgent 121 * */ 122public class HeaderDecoder implements ProgressionType, Markers, 123 StdEntropyCoderOptions { 124 125 /** The prefix for header decoder options: 'H' */ 126 public final static char OPT_PREFIX = 'H'; 127 128 /** The list of parameters that is accepted for quantization. Options 129 * for quantization start with 'Q'. */ 130 private final static String [][] pinfo = null; 131 132 /** The reference to the HeaderInfo instance holding the information found 133 * in headers */ 134 private HeaderInfo hi; 135 136 /** Current header information in a string */ 137 private String hdStr = ""; 138 139 /** The J2KImageReadParamJava instance of the decoder */ 140 private J2KImageReadParamJava j2krparam; 141 142 /** The number of tiles within the image */ 143 private int nTiles; 144 145 /** The number of tile parts per tile */ 146 public int[] nTileParts; 147 148 /** Used to store which markers have been already read, by using flag 149 * bits. The different markers are marked with XXX_FOUND flags, such as 150 * SIZ_FOUND */ 151 private int nfMarkSeg = 0; 152 153 /** Counts number of COC markers found in the header */ 154 private int nCOCMarkSeg = 0; 155 156 /** Counts number of QCC markers found in the header */ 157 private int nQCCMarkSeg = 0; 158 159 /** Counts number of COM markers found in the header */ 160 private int nCOMMarkSeg = 0; 161 162 /** Counts number of RGN markers found in the header */ 163 private int nRGNMarkSeg = 0; 164 165 /** Counts number of PPM markers found in the header */ 166 private int nPPMMarkSeg = 0; 167 168 /** Counts number of PPT markers found in the header */ 169 private int[][] nPPTMarkSeg = null; 170 171 /** Flag bit for SIZ marker segment found */ 172 private static final int SIZ_FOUND = 1; 173 174 /** Flag bit for COD marker segment found */ 175 private static final int COD_FOUND = 1<<1; 176 177 /** Flag bit for COC marker segment found */ 178 private static final int COC_FOUND = 1<<2; 179 180 /** Flag bit for QCD marker segment found */ 181 private static final int QCD_FOUND = 1<<3; 182 183 /** Flag bit for TLM marker segment found */ 184 private static final int TLM_FOUND = 1<<4; 185 186 /** Flag bit for PLM marker segment found */ 187 private static final int PLM_FOUND = 1<<5; 188 189 /** Flag bit for SOT marker segment found */ 190 private static final int SOT_FOUND = 1<<6; 191 192 /** Flag bit for PLT marker segment found */ 193 private static final int PLT_FOUND = 1<<7; 194 195 /** Flag bit for QCC marker segment found */ 196 private static final int QCC_FOUND = 1<<8; 197 198 /** Flag bit for RGN marker segment found */ 199 private static final int RGN_FOUND = 1<<9; 200 201 /** Flag bit for POC marker segment found */ 202 private static final int POC_FOUND = 1<<10; 203 204 /** Flag bit for COM marker segment found */ 205 private static final int COM_FOUND = 1<<11; 206 207 /** Flag bit for SOD marker segment found */ 208 public static final int SOD_FOUND = 1<<13; 209 210 /** Flag bit for SOD marker segment found */ 211 public static final int PPM_FOUND = 1<<14; 212 213 /** Flag bit for SOD marker segment found */ 214 public static final int PPT_FOUND = 1<<15; 215 216 /** Flag bit for CRG marker segment found */ 217 public static final int CRG_FOUND = 1<<16; 218 219 /** The reset mask for new tiles */ 220 private static final int TILE_RESET = ~(PLM_FOUND|SIZ_FOUND|RGN_FOUND); 221 222 /** HashTable used to store marker segment byte buffers */ 223 private Hashtable ht = null; 224 225 /** The number of components in the image */ 226 private int nComp; 227 228 /** The horizontal code-block partition origin */ 229 private int cb0x = -1; 230 231 /** The vertical code-block partition origin */ 232 private int cb0y = -1; 233 234 /** The decoder specifications */ 235 private DecoderSpecs decSpec; 236 237 /** Is the precinct partition used */ 238 boolean precinctPartitionIsUsed; 239 240 /** The offset of the main header in the input stream */ 241 public int mainHeadOff; 242 243 /** Vector containing info as to which tile each tilepart belong */ 244 public Vector tileOfTileParts; 245 246 /** Array containing the Nppm and Ippm fields of the PPM marker segments*/ 247 private byte[][] pPMMarkerData; 248 249 /** Array containing the Ippm fields of the PPT marker segments */ 250 private byte[][][][] tilePartPkdPktHeaders; 251 252 /** The packed packet headers if the PPM or PPT markers are used */ 253 private ByteArrayOutputStream[] pkdPktHeaders; 254 255 /** 256 * Return the maximum height among all components 257 * 258 * @return Maximum component height 259 * */ 260 public int getMaxCompImgHeight() { return hi.siz.getMaxCompHeight(); } 261 262 /** 263 * Return the maximum width among all components 264 * 265 * @return Maximum component width 266 * */ 267 public int getMaxCompImgWidth() { return hi.siz.getMaxCompWidth(); } 268 269 /** 270 * Returns the image width in the reference grid. 271 * 272 * @return The image width in the reference grid 273 * */ 274 public final int getImgWidth() { return hi.siz.xsiz-hi.siz.x0siz; } 275 276 /** 277 * Returns the image height in the reference grid. 278 * 279 * @return The image height in the reference grid 280 * */ 281 public final int getImgHeight() { return hi.siz.ysiz-hi.siz.y0siz; } 282 283 /** 284 * Return the horizontal upper-left coordinate of the image in the 285 * reference grid. 286 * 287 * @return The horizontal coordinate of the image origin. 288 * */ 289 public final int getImgULX() { return hi.siz.x0siz; } 290 291 /** 292 * Return the vertical upper-left coordinate of the image in the reference 293 * grid. 294 * 295 * @return The vertical coordinate of the image origin. 296 * */ 297 public final int getImgULY() { return hi.siz.y0siz; } 298 299 /** 300 * Returns the nominal width of the tiles in the reference grid. 301 * 302 * @return The nominal tile width, in the reference grid. 303 * */ 304 public final int getNomTileWidth() { return hi.siz.xtsiz; } 305 306 /** 307 * Returns the nominal width of the tiles in the reference grid. 308 * 309 * @return The nominal tile width, in the reference grid. 310 * */ 311 public final int getNomTileHeight() { return hi.siz.ytsiz; } 312 313 /** 314 * Returns the tiling origin, referred to as '(Px,Py)' in the 'ImgData' 315 * interface. 316 * 317 * @param co If not null this object is used to return the information. If 318 * null a new one is created and returned. 319 * 320 * @return The coordinate of the tiling origin, in the canvas system, on 321 * the reference grid. 322 * 323 * @see jj2000.j2k.image.ImgData 324 * */ 325 public final Point getTilingOrigin(Point co) { 326 if (co != null) { 327 co.x = hi.siz.xt0siz; 328 co.y = hi.siz.yt0siz; 329 return co; 330 } 331 else { 332 return new Point(hi.siz.xt0siz,hi.siz.yt0siz); 333 } 334 } 335 336 /** 337 * Returns true if the original data of the specified component was 338 * signed. If the data was not signed a level shift has to be applied at 339 * the end of the decompression chain. 340 * 341 * @param c The index of the component 342 * 343 * @return True if the original image component was signed. 344 * */ 345 public final boolean isOriginalSigned(int c) { 346 return hi.siz.isOrigSigned(c); 347 } 348 349 /** 350 * Returns the original bitdepth of the specified component. 351 * 352 * @param c The index of the component 353 * 354 * @return The bitdepth of the component 355 * */ 356 public final int getOriginalBitDepth(int c) { 357 return hi.siz.getOrigBitDepth(c); 358 } 359 360 /** 361 * Returns the number of components in the image. 362 * 363 * @return The number of components in the image. 364 * */ 365 public final int getNumComps() { 366 return nComp; 367 } 368 369 /** 370 * Returns the component sub-sampling factor, with respect to the 371 * reference grid, along the horizontal direction for the specified 372 * component. 373 * 374 * @param c The index of the component 375 * 376 * @return The component sub-sampling factor X-wise. 377 * */ 378 public final int getCompSubsX(int c) { return hi.siz.xrsiz[c]; } 379 380 /** 381 * Returns the component sub-sampling factor, with respect to the 382 * reference grid, along the vertical direction for the specified 383 * component. 384 * 385 * @param c The index of the component 386 * 387 * @return The component sub-sampling factor Y-wise. 388 * */ 389 public final int getCompSubsY(int c) { return hi.siz.yrsiz[c]; } 390 391 /** 392 * Returns the dequantizer parameters. Dequantizer parameters normally are 393 * the quantization step sizes, see DequantizerParams. 394 * 395 * @param src The source of data for the dequantizer. 396 * 397 * @param rb The number of range bits for each component. Must be 398 * the number of range bits of the mixed components. 399 * 400 * @param decSpec2 The DecoderSpecs instance after any image manipulation. 401 * 402 * @return The dequantizer 403 * */ 404 public final Dequantizer createDequantizer(CBlkQuantDataSrcDec src, 405 int rb[], 406 DecoderSpecs decSpec2) { 407 return new StdDequantizer(src,rb,decSpec2); 408 } 409 410 /** 411 * Returns the horizontal code-block partition origin.Allowable values are 412 * 0 and 1, nothing else. 413 * */ 414 public final int getCbULX() { 415 return cb0x; 416 } 417 418 /** 419 * Returns the vertical code-block partition origin. Allowable values are 420 * 0 and 1, nothing else. 421 * */ 422 public final int getCbULY() { 423 return cb0y; 424 } 425 426 /** 427 * Returns the precinct partition width for the specified tile-component 428 * and resolution level. 429 * 430 * @param c the component index 431 * 432 * @param t the tile index 433 * 434 * @param rl the resolution level 435 * 436 * @return The precinct partition width for the specified tile-component 437 * and resolution level 438 * */ 439 public final int getPPX(int t,int c,int rl) { 440 return decSpec.pss.getPPX(t,c,rl); 441 } 442 443 /** 444 * Returns the precinct partition height for the specified component, tile 445 * and resolution level. 446 * 447 * @param c the component 448 * 449 * @param t the tile index 450 * 451 * @param rl the resolution level 452 * 453 * @return The precinct partition height for the specified component, 454 * tile and resolution level 455 * */ 456 public final int getPPY(int t, int c, int rl) { 457 return decSpec.pss.getPPY(t, c, rl); 458 } 459 460 /** 461 * Returns the boolean used to know if the precinct partition is used 462 **/ 463 public final boolean precinctPartitionUsed() { 464 return precinctPartitionIsUsed; 465 } 466 467 /** 468 * Reads a wavelet filter from the codestream and returns the filter 469 * object that implements it. 470 * 471 * @param ehs The encoded header stream from where to read the info 472 * 473 * @param filtIdx Int array of one element to return the type of the 474 * wavelet filter. 475 * */ 476 private SynWTFilter readFilter(DataInputStream ehs,int[] filtIdx) 477 throws IOException { 478 int kid; // the filter id 479 480 kid = filtIdx[0] = ehs.readUnsignedByte(); 481 if (kid >= (1<<7)) { 482 throw new NotImplementedError("Custom filters not supported"); 483 } 484 // Return filter based on ID 485 switch (kid) { 486 case FilterTypes.W9X7: 487 return new SynWTFilterFloatLift9x7(); 488 case FilterTypes.W5X3: 489 return new SynWTFilterIntLift5x3(); 490 default: 491 throw new CorruptedCodestreamException("Specified wavelet filter "+ 492 "not"+ 493 " JPEG 2000 part I "+ 494 "compliant"); 495 } 496 } 497 498 /** 499 * Checks that the marker segment length is correct. 500 * 501 * @param ehs The encoded header stream 502 * 503 * @param str The string identifying the marker, such as "SIZ marker" 504 * 505 * @exception IOException If an I/O error occurs 506 * */ 507 public void checkMarkerLength(DataInputStream ehs, String str) 508 throws IOException { 509 if (ehs.available()!=0) { 510 FacilityManager.getMsgLogger(). 511 printmsg(MsgLogger.WARNING, 512 str+" length was short, attempting to resync."); 513 } 514 } 515 516 /** 517 * Reads the SIZ marker segment and realigns the codestream at the point 518 * where the next marker segment should be found. 519 * 520 * <p>SIZ is a fixed information marker segment containing informations 521 * about image and tile sizes. It is required in the main header 522 * immediately after SOC.</p> 523 * 524 * @param ehs The encoded header stream 525 * 526 * @exception IOException If an I/O error occurs while reading from the 527 * encoded header stream 528 * */ 529 private void readSIZ (DataInputStream ehs) throws IOException { 530 HeaderInfo.SIZ ms = hi.getNewSIZ(); 531 hi.siz = ms; 532 533 // Read the length of SIZ marker segment (Lsiz) 534 ms.lsiz = ehs.readUnsignedShort(); 535 536 // Read the capability of the codestream (Rsiz) 537 ms.rsiz = ehs.readUnsignedShort(); 538 if (ms.rsiz > 2) { 539 throw new Error("Codestream capabiities not JPEG 2000 - Part I"+ 540 " compliant"); 541 } 542 543 // Read image size 544 ms.xsiz = ehs.readInt(); 545 ms.ysiz = ehs.readInt(); 546 if ( ms.xsiz<=0 || ms.ysiz<=0 ) { 547 throw new IOException("JJ2000 does not support images whose "+ 548 "width and/or height not in the "+ 549 "range: 1 -- (2^31)-1"); 550 } 551 552 // Read image offset 553 ms.x0siz = ehs.readInt(); 554 ms.y0siz = ehs.readInt(); 555 if ( ms.x0siz<0 || ms.y0siz<0 ) { 556 throw new IOException("JJ2000 does not support images offset "+ 557 "not in the range: 0 -- (2^31)-1"); 558 } 559 560 // Read size of tile 561 ms.xtsiz = ehs.readInt(); 562 ms.ytsiz = ehs.readInt(); 563 if ( ms.xtsiz<=0 || ms.ytsiz<=0 ) { 564 throw new IOException("JJ2000 does not support tiles whose "+ 565 "width and/or height are not in "+ 566 "the range: 1 -- (2^31)-1"); 567 } 568 569 // Read upper-left tile offset 570 ms.xt0siz = ehs.readInt(); 571 ms.yt0siz = ehs.readInt(); 572 if ( ms.xt0siz<0 || ms.yt0siz<0 ){ 573 throw new IOException("JJ2000 does not support tiles whose "+ 574 "offset is not in "+ 575 "the range: 0 -- (2^31)-1"); 576 } 577 578 // Read number of components and initialize related arrays 579 nComp = ms.csiz = ehs.readUnsignedShort(); 580 if (nComp<1 || nComp>16384) { 581 throw new IllegalArgumentException("Number of component out of "+ 582 "range 1--16384: "+nComp); 583 } 584 585 ms.ssiz = new int[nComp]; 586 ms.xrsiz = new int[nComp]; 587 ms.yrsiz = new int[nComp]; 588 589 // Read bit-depth and down-sampling factors of each component 590 for(int i = 0; i<nComp; i++) { 591 ms.ssiz[i] = ehs.readUnsignedByte(); 592 ms.xrsiz[i] = ehs.readUnsignedByte(); 593 ms.yrsiz[i] = ehs.readUnsignedByte(); 594 } 595 596 // Check marker length 597 checkMarkerLength(ehs,"SIZ marker"); 598 599 // Create needed ModuleSpec 600 nTiles = ms.getNumTiles(); 601 602 // Finish initialization of decSpec 603 decSpec = new DecoderSpecs(nTiles,nComp); 604 } 605 606 /** 607 * Reads a CRG marker segment and checks its length. CRG is an 608 * informational marker segment that allows specific registration of 609 * components with respect to each other. 610 * 611 * @param ehs The encoded header stream 612 * */ 613 private void readCRG (DataInputStream ehs) throws IOException { 614 HeaderInfo.CRG ms = hi.getNewCRG(); 615 hi.crg = ms; 616 617 ms.lcrg = ehs.readUnsignedShort(); 618 ms.xcrg = new int[nComp]; 619 ms.ycrg = new int[nComp]; 620 621 FacilityManager.getMsgLogger(). 622 printmsg(MsgLogger.WARNING,"Information in CRG marker segment "+ 623 "not taken into account. This may affect the display "+ 624 "of the decoded image."); 625 for(int c=0; c<nComp; c++) { 626 ms.xcrg[c] = ehs.readUnsignedShort(); 627 ms.ycrg[c] = ehs.readUnsignedShort(); 628 } 629 630 // Check marker length 631 checkMarkerLength(ehs,"CRG marker"); 632 } 633 634 635 /** 636 * Reads a COM marker segments and realigns the bit stream at the point 637 * where the next marker segment should be found. COM is an informational 638 * marker segment that allows to include unstructured data in the main and 639 * tile-part headers. 640 * 641 * @param ehs The encoded header stream 642 * 643 * @param mainh Flag indicating whether or not this marker segment is read 644 * from the main header. 645 * 646 * @param tileIdx The index of the current tile 647 * 648 * @param comIdx Occurence of this COM marker in eith main or tile-part 649 * header 650 * 651 * @exception IOException If an I/O error occurs while reading from the 652 * encoded header stream 653 * */ 654 private void readCOM (DataInputStream ehs, boolean mainh, int tileIdx, 655 int comIdx) throws IOException { 656 HeaderInfo.COM ms = hi.getNewCOM(); 657 658 // Read length of COM field 659 ms.lcom = ehs.readUnsignedShort(); 660 661 // Read the registration value of the COM marker segment 662 ms.rcom = ehs.readUnsignedShort(); 663 switch(ms.rcom) { 664 case RCOM_GEN_USE: 665 ms.ccom = new byte[ms.lcom-4]; 666 for(int i=0; i<ms.lcom-4; i++) { 667 ms.ccom[i] = ehs.readByte(); 668 } 669 break; 670 default: 671 // --- Unknown or unsupported markers --- 672 // (skip them and see if we can get way with it) 673 FacilityManager.getMsgLogger(). 674 printmsg(MsgLogger.WARNING, 675 "COM marker registered as 0x"+Integer. 676 toHexString(ms.rcom)+ 677 " unknown, ignoring (this might crash the "+ 678 "decoder or decode a quality degraded or even "+ 679 "useless image)"); 680 ehs.skipBytes(ms.lcom-4); //Ignore this field for the moment 681 break; 682 } 683 684 if (mainh) { 685 hi.com.put("main_"+comIdx,ms); 686 } else { 687 hi.com.put("t"+tileIdx+"_"+comIdx,ms); 688 } 689 690 // Check marker length 691 checkMarkerLength(ehs,"COM marker"); 692 } 693 694 /** 695 * Reads a QCD marker segment and realigns the codestream at the point 696 * where the next marker should be found. QCD is a functional marker 697 * segment that describes the quantization default. 698 * 699 * @param ehs The encoded stream. 700 * 701 * @param mainh Flag indicating whether or not this marker segment is read 702 * from the main header. 703 * 704 * @param tileIdx The index of the current tile 705 * 706 * @param tpIdx Tile-part index 707 * 708 * @exception IOException If an I/O error occurs while reading from the 709 * encoded header stream. 710 * */ 711 private void readQCD (DataInputStream ehs, boolean mainh, int tileIdx, 712 int tpIdx) throws IOException { 713 StdDequantizerParams qParms; 714 int guardBits; 715 int[][] exp; 716 float[][] nStep = null; 717 HeaderInfo.QCD ms = hi.getNewQCD(); 718 719 // Lqcd (length of QCD field) 720 ms.lqcd = ehs.readUnsignedShort(); 721 722 // Sqcd (quantization style) 723 ms.sqcd = ehs.readUnsignedByte(); 724 725 guardBits = ms.getNumGuardBits(); 726 int qType = ms.getQuantType(); 727 728 if(mainh){ 729 hi.qcd.put("main",ms); 730 // If the main header is being read set default value of 731 // dequantization spec 732 switch (qType) { 733 case SQCX_NO_QUANTIZATION: 734 decSpec.qts.setDefault("reversible"); 735 break; 736 case SQCX_SCALAR_DERIVED: 737 decSpec.qts.setDefault("derived"); 738 break; 739 case SQCX_SCALAR_EXPOUNDED: 740 decSpec.qts.setDefault("expounded"); 741 break; 742 default: 743 throw new CorruptedCodestreamException("Unknown or "+ 744 "unsupported "+ 745 "quantization style "+ 746 "in Sqcd field, QCD "+ 747 "marker main header"); 748 } 749 } else { 750 hi.qcd.put("t"+tileIdx,ms); 751 // If the tile header is being read set default value of 752 // dequantization spec for tile 753 switch (qType) { 754 case SQCX_NO_QUANTIZATION: 755 decSpec.qts.setTileDef(tileIdx, "reversible"); 756 break; 757 case SQCX_SCALAR_DERIVED: 758 decSpec.qts.setTileDef(tileIdx, "derived"); 759 break; 760 case SQCX_SCALAR_EXPOUNDED: 761 decSpec.qts.setTileDef(tileIdx, "expounded"); 762 break; 763 default: 764 throw new CorruptedCodestreamException("Unknown or "+ 765 "unsupported "+ 766 "quantization style "+ 767 "in Sqcd field, QCD "+ 768 "marker, tile header"); 769 } 770 } 771 772 qParms = new StdDequantizerParams(); 773 774 if(qType == SQCX_NO_QUANTIZATION) { 775 int maxrl = 776 ( mainh ? 777 ((Integer)decSpec.dls.getDefault()).intValue() : 778 ((Integer)decSpec.dls.getTileDef(tileIdx)).intValue()); 779 int i,j,rl; 780 int minb,maxb,hpd; 781 int tmp; 782 783 exp = qParms.exp = new int[maxrl+1][]; 784 ms.spqcd = new int[maxrl+1][4]; 785 786 for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels 787 // Find the number of subbands in the resolution level 788 if (rl == 0) { // Only the LL subband 789 minb = 0; 790 maxb = 1; 791 } else { 792 // Dyadic decomposition 793 hpd = 1; 794 795 // Adapt hpd to resolution level 796 if (hpd > maxrl-rl) { 797 hpd -= maxrl-rl; 798 } 799 else { 800 hpd = 1; 801 } 802 // Determine max and min subband index 803 minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) 804 maxb = 1<<(hpd<<1); // maxb = 4^hpd 805 } 806 // Allocate array for subbands in resolution level 807 exp[rl] = new int[maxb]; 808 809 for(j=minb; j<maxb; j++) { 810 tmp = ms.spqcd[rl][j] = ehs.readUnsignedByte(); 811 exp[rl][j] = (tmp>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK; 812 } 813 }// end for rl 814 } else { 815 int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0 : 816 ( mainh ? 817 ((Integer)decSpec.dls.getDefault()).intValue() : 818 ((Integer)decSpec.dls.getTileDef(tileIdx)).intValue()); 819 int i,j,rl; 820 int minb,maxb,hpd; 821 int tmp; 822 823 exp = qParms.exp = new int[maxrl+1][]; 824 nStep = qParms.nStep = new float[maxrl+1][]; 825 ms.spqcd = new int[maxrl+1][4]; 826 827 for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels 828 // Find the number of subbands in the resolution level 829 if (rl == 0) { // Only the LL subband 830 minb = 0; 831 maxb = 1; 832 } else { 833 // Dyadic decomposition 834 hpd = 1; 835 836 // Adapt hpd to resolution level 837 if (hpd > maxrl-rl) { 838 hpd -= maxrl-rl; 839 } else { 840 hpd = 1; 841 } 842 // Determine max and min subband index 843 minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) 844 maxb = 1<<(hpd<<1); // maxb = 4^hpd 845 } 846 // Allocate array for subbands in resolution level 847 exp[rl] = new int[maxb]; 848 nStep[rl] = new float[maxb]; 849 850 for(j=minb; j<maxb; j++) { 851 tmp = ms.spqcd[rl][j] = ehs.readUnsignedShort(); 852 exp[rl][j] = (tmp>>11) & 0x1f; 853 // NOTE: the formula below does not support more than 5 854 // bits for the exponent, otherwise (-1<<exp) might 855 // overflow (the - is used to be able to represent 2**31) 856 nStep[rl][j] = 857 (-1f-((float)(tmp & 0x07ff))/(1<<11))/ 858 (-1<<exp[rl][j]); 859 } 860 }// end for rl 861 } // end if (qType != SQCX_NO_QUANTIZATION) 862 863 // Fill qsss, gbs 864 if(mainh){ 865 decSpec.qsss.setDefault(qParms); 866 decSpec.gbs.setDefault(new Integer(guardBits)); 867 } 868 else{ 869 decSpec.qsss.setTileDef(tileIdx,qParms); 870 decSpec.gbs.setTileDef(tileIdx,new Integer(guardBits)); 871 } 872 873 // Check marker length 874 checkMarkerLength(ehs,"QCD marker"); 875 } 876 877 /** 878 * Reads a QCC marker segment and realigns the codestream at the point 879 * where the next marker should be found. QCC is a functional marker 880 * segment that describes the quantization of one component. 881 * 882 * @param ehs The encoded stream. 883 * 884 * @param mainh Flag indicating whether or not this marker segment is read 885 * from the main header. 886 * 887 * @param tileIdx The index of the current tile 888 * 889 * @param tpIdx Tile-part index 890 * 891 * @exception IOException If an I/O error occurs while reading from the 892 * encoded header stream. 893 * */ 894 private void readQCC (DataInputStream ehs, boolean mainh, int tileIdx, 895 int tpIdx) throws IOException { 896 int cComp; // current component 897 int tmp; 898 StdDequantizerParams qParms; 899 int[][] expC; 900 float[][] nStepC = null; 901 HeaderInfo.QCC ms = hi.getNewQCC(); 902 903 // Lqcc (length of QCC field) 904 ms.lqcc = ehs.readUnsignedShort(); 905 906 // Cqcc 907 if (nComp < 257) { 908 cComp = ms.cqcc = ehs.readUnsignedByte(); 909 } else { 910 cComp = ms.cqcc = ehs.readUnsignedShort(); 911 } 912 if (cComp >= nComp) { 913 throw new CorruptedCodestreamException("Invalid component "+ 914 "index in QCC marker"); 915 } 916 917 // Sqcc (quantization style) 918 ms.sqcc = ehs.readUnsignedByte(); 919 int guardBits = ms.getNumGuardBits(); 920 int qType = ms.getQuantType(); 921 922 if(mainh) { 923 hi.qcc.put("main_c"+cComp,ms); 924 // If main header is being read, set default for component in all 925 // tiles 926 switch (qType) { 927 case SQCX_NO_QUANTIZATION: 928 decSpec.qts.setCompDef(cComp,"reversible"); 929 break; 930 case SQCX_SCALAR_DERIVED: 931 decSpec.qts.setCompDef(cComp,"derived"); 932 break; 933 case SQCX_SCALAR_EXPOUNDED: 934 decSpec.qts.setCompDef(cComp,"expounded"); 935 break; 936 default: 937 throw new CorruptedCodestreamException("Unknown or "+ 938 "unsupported "+ 939 "quantization style "+ 940 "in Sqcd field, QCD "+ 941 "marker, main header"); 942 } 943 } else { 944 hi.qcc.put("t"+tileIdx+"_c"+cComp,ms); 945 // If tile header is being read, set value for component in 946 // this tiles 947 switch (qType) { 948 case SQCX_NO_QUANTIZATION: 949 decSpec.qts.setTileCompVal(tileIdx, cComp,"reversible"); 950 break; 951 case SQCX_SCALAR_DERIVED: 952 decSpec.qts.setTileCompVal(tileIdx, cComp,"derived"); 953 break; 954 case SQCX_SCALAR_EXPOUNDED: 955 decSpec.qts.setTileCompVal(tileIdx, cComp,"expounded"); 956 break; 957 default: 958 throw new CorruptedCodestreamException("Unknown or "+ 959 "unsupported "+ 960 "quantization style "+ 961 "in Sqcd field, QCD "+ 962 "marker, main header"); 963 } 964 } 965 966 // Decode all dequantizer params 967 qParms = new StdDequantizerParams(); 968 969 if (qType == SQCX_NO_QUANTIZATION) { 970 int maxrl = ( mainh ? 971 ((Integer)decSpec.dls.getCompDef(cComp)).intValue() : 972 ((Integer)decSpec.dls.getTileCompVal(tileIdx,cComp)). 973 intValue()); 974 int i,j,rl; 975 int minb,maxb,hpd; 976 977 expC = qParms.exp = new int[maxrl+1][]; 978 ms.spqcc = new int[maxrl+1][4]; 979 980 for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels 981 // Find the number of subbands in the resolution level 982 if (rl == 0) { // Only the LL subband 983 minb = 0; 984 maxb = 1; 985 } else { 986 // Dyadic decomposition 987 hpd = 1; 988 989 // Adapt hpd to resolution level 990 if (hpd > maxrl-rl) { 991 hpd -= maxrl-rl; 992 } else { 993 hpd = 1; 994 } 995 // Determine max and min subband index 996 minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) 997 maxb = 1<<(hpd<<1); // maxb = 4^hpd 998 } 999 // Allocate array for subbands in resolution level 1000 expC[rl] = new int[maxb]; 1001 1002 for(j=minb; j<maxb; j++) { 1003 tmp = ms.spqcc[rl][j] = ehs.readUnsignedByte(); 1004 expC[rl][j] = (tmp>>SQCX_EXP_SHIFT)&SQCX_EXP_MASK; 1005 } 1006 }// end for rl 1007 } else { 1008 int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0 : 1009 ( mainh ? 1010 ((Integer)decSpec.dls.getCompDef(cComp)).intValue() : 1011 ((Integer)decSpec.dls.getTileCompVal(tileIdx,cComp)). 1012 intValue()); 1013 int i,j,rl; 1014 int minb,maxb,hpd; 1015 1016 nStepC = qParms.nStep = new float[maxrl+1][]; 1017 expC = qParms.exp = new int[maxrl+1][]; 1018 ms.spqcc = new int[maxrl+1][4]; 1019 1020 for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels 1021 // Find the number of subbands in the resolution level 1022 if (rl == 0) { // Only the LL subband 1023 minb = 0; 1024 maxb = 1; 1025 } else { 1026 // Dyadic decomposition 1027 hpd = 1; 1028 1029 // Adapt hpd to resolution level 1030 if (hpd > maxrl-rl) { 1031 hpd -= maxrl-rl; 1032 } else { 1033 hpd = 1; 1034 } 1035 // Determine max and min subband index 1036 minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) 1037 maxb = 1<<(hpd<<1); // maxb = 4^hpd 1038 } 1039 // Allocate array for subbands in resolution level 1040 expC[rl] = new int[maxb]; 1041 nStepC[rl] = new float[maxb]; 1042 1043 for(j=minb; j<maxb; j++) { 1044 tmp = ms.spqcc[rl][j] = ehs.readUnsignedShort(); 1045 expC[rl][j] = (tmp>>11) & 0x1f; 1046 // NOTE: the formula below does not support more than 5 1047 // bits for the exponent, otherwise (-1<<exp) might 1048 // overflow (the - is used to be able to represent 2**31) 1049 nStepC[rl][j] = 1050 (-1f-((float)(tmp & 0x07ff))/(1<<11))/ 1051 (-1<<expC[rl][j]); 1052 } 1053 }// end for rl 1054 } // end if (qType != SQCX_NO_QUANTIZATION) 1055 1056 // Fill qsss, gbs 1057 if(mainh){ 1058 decSpec.qsss.setCompDef(cComp,qParms); 1059 decSpec.gbs.setCompDef(cComp,new Integer(guardBits)); 1060 } 1061 else{ 1062 decSpec.qsss.setTileCompVal(tileIdx,cComp,qParms); 1063 decSpec.gbs.setTileCompVal(tileIdx,cComp,new Integer(guardBits)); 1064 } 1065 1066 // Check marker length 1067 checkMarkerLength(ehs,"QCC marker"); 1068 } 1069 1070 /** 1071 * Reads a COD marker segment and realigns the codestream where the next 1072 * marker should be found. 1073 * 1074 * @param ehs The encoder header stream. 1075 * 1076 * @param mainh Flag indicating whether or not this marker segment is read 1077 * from the main header. 1078 * 1079 * @param tileIdx The index of the current tile 1080 * 1081 * @param tpIdx Tile-part index 1082 * 1083 * @exception IOException If an I/O error occurs while reading from the 1084 * encoder header stream 1085 * */ 1086 private void readCOD (DataInputStream ehs, boolean mainh, int tileIdx, 1087 int tpIdx) throws IOException { 1088 int cstyle; // The block style 1089 SynWTFilter hfilters[],vfilters[]; 1090 int l; 1091 Integer cblk[]; 1092 String errMsg; 1093 boolean sopUsed = false; 1094 boolean ephUsed = false; 1095 HeaderInfo.COD ms = hi.getNewCOD(); 1096 1097 // Lcod (marker length) 1098 ms.lcod = ehs.readUnsignedShort(); 1099 1100 // Scod (block style) 1101 // We only support wavelet transformed data 1102 cstyle = ms.scod = ehs.readUnsignedByte(); 1103 1104 if( (cstyle&SCOX_PRECINCT_PARTITION) != 0 ){ 1105 precinctPartitionIsUsed = true; 1106 // Remove flag 1107 cstyle &= ~(SCOX_PRECINCT_PARTITION); 1108 } else { 1109 precinctPartitionIsUsed = false; 1110 } 1111 1112 // SOP markers 1113 if (mainh) { 1114 hi.cod.put("main",ms); 1115 1116 if( (cstyle&SCOX_USE_SOP) != 0 ){ 1117 // SOP markers are used 1118 decSpec.sops.setDefault(new Boolean("true")); 1119 sopUsed = true; 1120 // Remove flag 1121 cstyle &= ~(SCOX_USE_SOP); 1122 } else { 1123 // SOP markers are not used 1124 decSpec.sops.setDefault(new Boolean("false")); 1125 } 1126 } else { 1127 hi.cod.put("t"+tileIdx,ms); 1128 1129 if( (cstyle&SCOX_USE_SOP) != 0 ){ 1130 // SOP markers are used 1131 decSpec.sops.setTileDef(tileIdx, new Boolean("true")); 1132 sopUsed = true; 1133 // Remove flag 1134 cstyle &= ~(SCOX_USE_SOP); 1135 } 1136 else { 1137 // SOP markers are not used 1138 decSpec.sops.setTileDef(tileIdx, new Boolean("false")); 1139 } 1140 } 1141 1142 // EPH markers 1143 if (mainh) { 1144 if( (cstyle&SCOX_USE_EPH) != 0 ){ 1145 // EPH markers are used 1146 decSpec.ephs.setDefault(new Boolean("true")); 1147 ephUsed = true; 1148 // Remove flag 1149 cstyle &= ~(SCOX_USE_EPH); 1150 } else { 1151 // EPH markers are not used 1152 decSpec.ephs.setDefault(new Boolean("false")); 1153 } 1154 } else { 1155 if( (cstyle&SCOX_USE_EPH) != 0 ){ 1156 // EPH markers are used 1157 decSpec.ephs.setTileDef(tileIdx, new Boolean("true")); 1158 ephUsed = true; 1159 // Remove flag 1160 cstyle &= ~(SCOX_USE_EPH); 1161 } else { 1162 // EPH markers are not used 1163 decSpec.ephs.setTileDef(tileIdx, new Boolean("false")); 1164 } 1165 } 1166 1167 // Code-block partition origin 1168 if( (cstyle&(SCOX_HOR_CB_PART|SCOX_VER_CB_PART)) != 0) { 1169 FacilityManager.getMsgLogger(). 1170 printmsg(MsgLogger.WARNING,"Code-block partition origin "+ 1171 "different from (0,0). This is defined in JPEG 2000"+ 1172 " part 2 and may not be supported by all JPEG "+ 1173 "2000 decoders."); 1174 } 1175 if( (cstyle&SCOX_HOR_CB_PART)!= 0) { 1176 if(cb0x!=-1 && cb0x==0) { 1177 throw new IllegalArgumentException("Code-block partition "+ 1178 "origin redefined in new"+ 1179 " COD marker segment. Not"+ 1180 " supported by JJ2000"); 1181 } 1182 cb0x = 1; 1183 cstyle &= ~(SCOX_HOR_CB_PART); 1184 } else { 1185 if(cb0x!=-1 && cb0x==1) { 1186 throw new IllegalArgumentException("Code-block partition "+ 1187 "origin redefined in new"+ 1188 " COD marker segment. Not"+ 1189 " supported by JJ2000"); 1190 } 1191 cb0x = 0; 1192 } 1193 if( (cstyle&SCOX_VER_CB_PART)!= 0) { 1194 if(cb0y!=-1 && cb0y==0) { 1195 throw new IllegalArgumentException("Code-block partition "+ 1196 "origin redefined in new"+ 1197 " COD marker segment. Not"+ 1198 " supported by JJ2000"); 1199 } 1200 cb0y = 1; 1201 cstyle &= ~(SCOX_VER_CB_PART); 1202 } else { 1203 if(cb0y!=-1 && cb0y==1) { 1204 throw new IllegalArgumentException("Code-block partition "+ 1205 "origin redefined in new"+ 1206 " COD marker segment. Not"+ 1207 " supported by JJ2000"); 1208 } 1209 cb0y = 0; 1210 } 1211 1212 // SGcod 1213 // Read the progressive order 1214 ms.sgcod_po = ehs.readUnsignedByte(); 1215 1216 // Read the number of layers 1217 ms.sgcod_nl = ehs.readUnsignedShort(); 1218 if (ms.sgcod_nl<=0 || ms.sgcod_nl>65535 ) { 1219 throw new CorruptedCodestreamException("Number of layers out of "+ 1220 "range: 1--65535"); 1221 } 1222 1223 // Multiple component transform 1224 ms.sgcod_mct = ehs.readUnsignedByte(); 1225 1226 // SPcod 1227 // decomposition levels 1228 int mrl = ms.spcod_ndl = ehs.readUnsignedByte(); 1229 if( mrl>32 ){ 1230 throw new CorruptedCodestreamException("Number of decomposition "+ 1231 "levels out of range: "+ 1232 "0--32"); 1233 } 1234 1235 // Read the code-blocks dimensions 1236 cblk = new Integer[2]; 1237 ms.spcod_cw = ehs.readUnsignedByte(); 1238 cblk[0] = new Integer(1<<(ms.spcod_cw+2)); 1239 if ( cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || 1240 cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { 1241 errMsg = "Non-valid code-block width in SPcod field, "+ 1242 "COD marker"; 1243 throw new CorruptedCodestreamException(errMsg); 1244 } 1245 ms.spcod_ch = ehs.readUnsignedByte(); 1246 cblk[1] = new Integer(1<<(ms.spcod_ch+2)); 1247 if ( cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || 1248 cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { 1249 errMsg = "Non-valid code-block height in SPcod field, "+ 1250 "COD marker"; 1251 throw new CorruptedCodestreamException(errMsg); 1252 } 1253 if ( (cblk[0].intValue()*cblk[1].intValue()) > 1254 StdEntropyCoderOptions.MAX_CB_AREA ) { 1255 errMsg = "Non-valid code-block area in SPcod field, "+ 1256 "COD marker"; 1257 throw new CorruptedCodestreamException(errMsg); 1258 } 1259 if ( mainh ) { 1260 decSpec.cblks.setDefault(cblk); 1261 } 1262 else { 1263 decSpec.cblks.setTileDef(tileIdx, cblk); 1264 } 1265 1266 // Style of the code-block coding passes 1267 int ecOptions = ms.spcod_cs = ehs.readUnsignedByte(); 1268 if ((ecOptions & 1269 ~(OPT_BYPASS|OPT_RESET_MQ|OPT_TERM_PASS| 1270 OPT_VERT_STR_CAUSAL|OPT_PRED_TERM | OPT_SEG_SYMBOLS)) != 0){ 1271 throw 1272 new CorruptedCodestreamException("Unknown \"code-block "+ 1273 "style\" in SPcod field, "+ 1274 "COD marker: 0x"+ 1275 Integer. 1276 toHexString(ecOptions)); 1277 } 1278 1279 // Read wavelet filter for tile or image 1280 hfilters = new SynWTFilter[1]; 1281 vfilters = new SynWTFilter[1]; 1282 hfilters[0] = readFilter(ehs,ms.spcod_t); 1283 vfilters[0] = hfilters[0]; 1284 1285 // Fill the filter spec 1286 // If this is the main header, set the default value, if it is the 1287 // tile header, set default for this tile 1288 SynWTFilter[][] hvfilters = new SynWTFilter[2][]; 1289 hvfilters[0]=hfilters; 1290 hvfilters[1]=vfilters; 1291 1292 // Get precinct partition sizes 1293 Vector v[] = new Vector[2]; 1294 v[0] = new Vector(); 1295 v[1] = new Vector(); 1296 int val = PRECINCT_PARTITION_DEF_SIZE; 1297 if ( !precinctPartitionIsUsed ) { 1298 Integer w, h; 1299 w = new Integer(1<<(val & 0x000F)); 1300 v[0].addElement(w); 1301 h = new Integer(1<<(((val & 0x00F0)>>4))); 1302 v[1].addElement(h); 1303 } else { 1304 ms.spcod_ps = new int[mrl+1]; 1305 for (int rl=mrl ;rl>=0 ;rl--) { 1306 Integer w, h; 1307 val = ms.spcod_ps[mrl-rl] = ehs.readUnsignedByte(); 1308 w = new Integer(1<<(val & 0x000F)); 1309 v[0].insertElementAt(w,0); 1310 h = new Integer(1<<(((val & 0x00F0)>>4))); 1311 v[1].insertElementAt(h,0); 1312 } 1313 } 1314 if (mainh) { 1315 decSpec.pss.setDefault(v); 1316 } else { 1317 decSpec.pss.setTileDef(tileIdx, v); 1318 } 1319 precinctPartitionIsUsed = true; 1320 1321 // Check marker length 1322 checkMarkerLength(ehs,"COD marker"); 1323 1324 // Store specifications in decSpec 1325 if(mainh){ 1326 decSpec.wfs.setDefault(hvfilters); 1327 decSpec.dls.setDefault(new Integer(mrl)); 1328 decSpec.ecopts.setDefault(new Integer(ecOptions)); 1329 decSpec.cts.setDefault(new Integer(ms.sgcod_mct)); 1330 decSpec.nls.setDefault(new Integer(ms.sgcod_nl)); 1331 decSpec.pos.setDefault(new Integer(ms.sgcod_po)); 1332 } 1333 else{ 1334 decSpec.wfs.setTileDef(tileIdx, hvfilters); 1335 decSpec.dls.setTileDef(tileIdx,new Integer(mrl)); 1336 decSpec.ecopts.setTileDef(tileIdx,new Integer(ecOptions)); 1337 decSpec.cts.setTileDef(tileIdx,new Integer(ms.sgcod_mct)); 1338 decSpec.nls.setTileDef(tileIdx,new Integer(ms.sgcod_nl)); 1339 decSpec.pos.setTileDef(tileIdx,new Integer(ms.sgcod_po)); 1340 } 1341 } 1342 1343 /** 1344 * Reads the COC marker segment and realigns the codestream where the next 1345 * marker should be found. 1346 * 1347 * @param ehs The encoder header stream. 1348 * 1349 * @param mainh Flag indicating whether or not this marker segment is read 1350 * from the main header. 1351 * 1352 * @param tileIdx The index of the current tile 1353 * 1354 * @param tpIdx Tile-part index 1355 * 1356 * @exception IOException If an I/O error occurs while reading from the 1357 * encoder header stream 1358 * */ 1359 private void readCOC (DataInputStream ehs, boolean mainh, int tileIdx, 1360 int tpIdx) throws IOException { 1361 int cComp; // current component 1362 SynWTFilter hfilters[],vfilters[]; 1363 int tmp,l; 1364 int ecOptions; 1365 Integer cblk[]; 1366 String errMsg; 1367 HeaderInfo.COC ms = hi.getNewCOC(); 1368 1369 // Lcoc (marker length) 1370 ms.lcoc = ehs.readUnsignedShort(); 1371 1372 // Ccoc 1373 if (nComp < 257) { 1374 cComp = ms.ccoc = ehs.readUnsignedByte(); 1375 } else { 1376 cComp = ms.ccoc = ehs.readUnsignedShort(); 1377 } 1378 if (cComp >= nComp) { 1379 throw new CorruptedCodestreamException("Invalid component index "+ 1380 "in QCC marker"); 1381 } 1382 1383 // Scoc (block style) 1384 int cstyle = ms.scoc = ehs.readUnsignedByte(); 1385 if( (cstyle&SCOX_PRECINCT_PARTITION) != 0 ){ 1386 precinctPartitionIsUsed = true; 1387 // Remove flag 1388 cstyle &= ~(SCOX_PRECINCT_PARTITION); 1389 } else { 1390 precinctPartitionIsUsed = false; 1391 } 1392 1393 // SPcoc 1394 1395 // decomposition levels 1396 int mrl = ms.spcoc_ndl = ehs.readUnsignedByte(); 1397 1398 // Read the code-blocks dimensions 1399 cblk = new Integer[2]; 1400 ms.spcoc_cw = ehs.readUnsignedByte(); 1401 cblk[0] = new Integer(1<<(ms.spcoc_cw+2)); 1402 if ( cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || 1403 cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { 1404 errMsg = "Non-valid code-block width in SPcod field, "+ 1405 "COC marker"; 1406 throw new CorruptedCodestreamException(errMsg); 1407 } 1408 ms.spcoc_ch = ehs.readUnsignedByte(); 1409 cblk[1] = new Integer(1<<(ms.spcoc_ch+2)); 1410 if ( cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || 1411 cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { 1412 errMsg = "Non-valid code-block height in SPcod field, "+ 1413 "COC marker"; 1414 throw new CorruptedCodestreamException(errMsg); 1415 } 1416 if ( (cblk[0].intValue()*cblk[1].intValue()) > 1417 StdEntropyCoderOptions.MAX_CB_AREA ) { 1418 errMsg = "Non-valid code-block area in SPcod field, "+ 1419 "COC marker"; 1420 throw new CorruptedCodestreamException(errMsg); 1421 } 1422 if ( mainh ) { 1423 decSpec.cblks.setCompDef(cComp,cblk); 1424 } else { 1425 decSpec.cblks.setTileCompVal(tileIdx,cComp,cblk); 1426 } 1427 1428 // Read entropy block mode options 1429 // NOTE: currently OPT_SEG_SYMBOLS is not included here 1430 ecOptions = ms.spcoc_cs = ehs.readUnsignedByte(); 1431 if ((ecOptions & 1432 ~(OPT_BYPASS|OPT_RESET_MQ|OPT_TERM_PASS| 1433 OPT_VERT_STR_CAUSAL|OPT_PRED_TERM|OPT_SEG_SYMBOLS)) != 0){ 1434 throw 1435 new CorruptedCodestreamException("Unknown \"code-block "+ 1436 "context\" in SPcoc field, "+ 1437 "COC marker: 0x"+ 1438 Integer. 1439 toHexString(ecOptions)); 1440 } 1441 1442 // Read wavelet filter for tile or image 1443 hfilters = new SynWTFilter[1]; 1444 vfilters = new SynWTFilter[1]; 1445 hfilters[0] = readFilter(ehs,ms.spcoc_t); 1446 vfilters[0] = hfilters[0]; 1447 1448 // Fill the filter spec 1449 // If this is the main header, set the default value, if it is the 1450 // tile header, set default for this tile 1451 SynWTFilter[][] hvfilters = new SynWTFilter[2][]; 1452 hvfilters[0]=hfilters; 1453 hvfilters[1]=vfilters; 1454 1455 // Get precinct partition sizes 1456 Vector v[] = new Vector[2]; 1457 v[0] = new Vector(); 1458 v[1] = new Vector(); 1459 int val = PRECINCT_PARTITION_DEF_SIZE; 1460 if ( !precinctPartitionIsUsed ) { 1461 Integer w, h; 1462 w = new Integer(1<<(val & 0x000F)); 1463 v[0].addElement(w); 1464 h = new Integer(1<<(((val & 0x00F0)>>4))); 1465 v[1].addElement(h); 1466 } else { 1467 ms.spcoc_ps = new int[mrl+1]; 1468 for ( int rl=mrl ; rl>=0 ; rl-- ) { 1469 Integer w, h; 1470 val = ms.spcoc_ps[rl] = ehs.readUnsignedByte(); 1471 w = new Integer(1<<(val & 0x000F)); 1472 v[0].insertElementAt(w,0); 1473 h = new Integer(1<<(((val & 0x00F0)>>4))); 1474 v[1].insertElementAt(h,0); 1475 } 1476 } 1477 if (mainh) { 1478 decSpec.pss.setCompDef(cComp,v); 1479 } else { 1480 decSpec.pss.setTileCompVal(tileIdx,cComp,v); 1481 } 1482 precinctPartitionIsUsed = true; 1483 1484 // Check marker length 1485 checkMarkerLength(ehs,"COD marker"); 1486 1487 if(mainh){ 1488 hi.coc.put("main_c"+cComp,ms); 1489 decSpec.wfs.setCompDef(cComp,hvfilters); 1490 decSpec.dls.setCompDef(cComp,new Integer(mrl)); 1491 decSpec.ecopts.setCompDef(cComp,new Integer(ecOptions)); 1492 } else { 1493 hi.coc.put("t"+tileIdx+"_c"+cComp,ms); 1494 decSpec.wfs.setTileCompVal(tileIdx,cComp,hvfilters); 1495 decSpec.dls.setTileCompVal(tileIdx,cComp,new Integer(mrl)); 1496 decSpec.ecopts.setTileCompVal(tileIdx,cComp, 1497 new Integer(ecOptions)); 1498 } 1499 } 1500 1501 /** 1502 * Reads the POC marker segment and realigns the codestream where the next 1503 * marker should be found. 1504 * 1505 * @param ehs The encoder header stream. 1506 * 1507 * @param mainh Flag indicating whether or not this marker segment is read 1508 * from the main header. 1509 * 1510 * @param t The index of the current tile 1511 * 1512 * @param tpIdx Tile-part index 1513 * 1514 * @exception IOException If an I/O error occurs while reading from the 1515 * encoder header stream 1516 * */ 1517 private void readPOC(DataInputStream ehs,boolean mainh,int t,int tpIdx) 1518 throws IOException { 1519 1520 boolean useShort = (nComp>=256) ? true : false; 1521 int tmp; 1522 int nOldChg = 0; 1523 HeaderInfo.POC ms; 1524 if(mainh || hi.poc.get("t"+t)==null) { 1525 ms = hi.getNewPOC(); 1526 } else { 1527 ms = (HeaderInfo.POC)hi.poc.get("t"+t); 1528 nOldChg = ms.rspoc.length; 1529 } 1530 1531 // Lpoc 1532 ms.lpoc = ehs.readUnsignedShort(); 1533 1534 // Compute the number of new progression changes 1535 // newChg = (lpoc - Lpoc(2)) / (RSpoc(1) + CSpoc(2) + 1536 // LYEpoc(2) + REpoc(1) + CEpoc(2) + Ppoc (1) ) 1537 int newChg = (ms.lpoc-2)/(5+ (useShort?4:2)); 1538 int ntotChg = nOldChg+newChg; 1539 1540 int[][] change; 1541 if(nOldChg!=0) { 1542 // Creates new arrays 1543 change = new int[ntotChg][6]; 1544 int[] tmprspoc = new int[ntotChg]; 1545 int[] tmpcspoc = new int[ntotChg]; 1546 int[] tmplyepoc = new int[ntotChg]; 1547 int[] tmprepoc = new int[ntotChg]; 1548 int[] tmpcepoc = new int[ntotChg]; 1549 int[] tmpppoc = new int[ntotChg]; 1550 1551 // Copy old values 1552 int[][] prevChg = (int[][])decSpec.pcs.getTileDef(t); 1553 for(int chg=0; chg<nOldChg; chg++) { 1554 change[chg] = prevChg[chg]; 1555 tmprspoc[chg] = ms.rspoc[chg]; 1556 tmpcspoc[chg] = ms.cspoc[chg]; 1557 tmplyepoc[chg] = ms.lyepoc[chg]; 1558 tmprepoc[chg] = ms.repoc[chg]; 1559 tmpcepoc[chg] = ms.cepoc[chg]; 1560 tmpppoc[chg] = ms.ppoc[chg]; 1561 } 1562 ms.rspoc = tmprspoc; 1563 ms.cspoc = tmpcspoc; 1564 ms.lyepoc = tmplyepoc; 1565 ms.repoc = tmprepoc; 1566 ms.cepoc = tmpcepoc; 1567 ms.ppoc = tmpppoc; 1568 } else { 1569 change = new int[newChg][6]; 1570 ms.rspoc = new int[newChg]; 1571 ms.cspoc = new int[newChg]; 1572 ms.lyepoc = new int[newChg]; 1573 ms.repoc = new int[newChg]; 1574 ms.cepoc = new int[newChg]; 1575 ms.ppoc = new int[newChg]; 1576 } 1577 1578 for(int chg=nOldChg; chg<ntotChg; chg++) { 1579 // RSpoc 1580 change[chg][0] = ms.rspoc[chg] = ehs.readUnsignedByte(); 1581 1582 // CSpoc 1583 if(useShort) { 1584 change[chg][1] = ms.cspoc[chg] = ehs.readUnsignedShort(); 1585 } else { 1586 change[chg][1] = ms.cspoc[chg] = ehs.readUnsignedByte(); 1587 } 1588 1589 // LYEpoc 1590 change[chg][2] = ms.lyepoc[chg] = ehs.readUnsignedShort(); 1591 if(change[chg][2]<1) { 1592 throw new CorruptedCodestreamException 1593 ("LYEpoc value must be greater than 1 in POC marker "+ 1594 "segment of tile "+t+", tile-part "+tpIdx); 1595 } 1596 1597 // REpoc 1598 change[chg][3] = ms.repoc[chg] = ehs.readUnsignedByte(); 1599 if(change[chg][3]<=change[chg][0]) { 1600 throw new CorruptedCodestreamException 1601 ("REpoc value must be greater than RSpoc in POC marker "+ 1602 "segment of tile "+t+", tile-part "+tpIdx); 1603 } 1604 1605 // CEpoc 1606 if(useShort) { 1607 change[chg][4] = ms.cepoc[chg] = ehs.readUnsignedShort(); 1608 } else { 1609 tmp = ms.cepoc[chg] = ehs.readUnsignedByte(); 1610 if(tmp==0) { 1611 change[chg][4] = 0; 1612 } else { 1613 change[chg][4] = tmp; 1614 } 1615 } 1616 if(change[chg][4]<=change[chg][1]) { 1617 throw new CorruptedCodestreamException 1618 ("CEpoc value must be greater than CSpoc in POC marker "+ 1619 "segment of tile "+t+", tile-part "+tpIdx); 1620 } 1621 1622 // Ppoc 1623 change[chg][5] = ms.ppoc[chg] = ehs.readUnsignedByte(); 1624 } 1625 1626 // Check marker length 1627 checkMarkerLength(ehs,"POC marker"); 1628 1629 // Register specifications 1630 if(mainh) { 1631 hi.poc.put("main",ms); 1632 decSpec.pcs.setDefault(change); 1633 } else { 1634 hi.poc.put("t"+t,ms); 1635 decSpec.pcs.setTileDef(t,change); 1636 } 1637 } 1638 1639 /** 1640 * Reads TLM marker segment and realigns the codestream where the next 1641 * marker should be found. Informations stored in these fields are 1642 * currently NOT taken into account. 1643 * 1644 * @param ehs The encoder header stream. 1645 * 1646 * @exception IOException If an I/O error occurs while reading from the 1647 * encoder header stream 1648 * */ 1649 private void readTLM(DataInputStream ehs) throws IOException { 1650 int length; 1651 1652 length = ehs.readUnsignedShort(); 1653 //Ignore all informations contained 1654 ehs.skipBytes(length-2); 1655 1656 FacilityManager.getMsgLogger(). 1657 printmsg(MsgLogger.INFO,"Skipping unsupported TLM marker"); 1658 } 1659 1660 /** 1661 * Reads PLM marker segment and realigns the codestream where the next 1662 * marker should be found. Informations stored in these fields are 1663 * currently not taken into account. 1664 * 1665 * @param ehs The encoder header stream. 1666 * 1667 * @exception IOException If an I/O error occurs while reading from the 1668 * encoder header stream 1669 * */ 1670 private void readPLM(DataInputStream ehs) throws IOException{ 1671 int length; 1672 1673 length = ehs.readUnsignedShort(); 1674 //Ignore all informations contained 1675 ehs.skipBytes(length-2); 1676 1677 FacilityManager.getMsgLogger(). 1678 printmsg(MsgLogger.INFO,"Skipping unsupported PLM marker"); 1679 } 1680 1681 /** 1682 * Reads the PLT fields and realigns the codestream where the next marker 1683 * should be found. Informations stored in these fields are currently NOT 1684 * taken into account. 1685 * 1686 * @param ehs The encoder header stream. 1687 * 1688 * @exception IOException If an I/O error occurs while reading from the 1689 * encoder header stream 1690 * */ 1691 private void readPLTFields(DataInputStream ehs) throws IOException{ 1692 int length; 1693 1694 length = ehs.readUnsignedShort(); 1695 //Ignore all informations contained 1696 ehs.skipBytes(length-2); 1697 1698 FacilityManager.getMsgLogger(). 1699 printmsg(MsgLogger.INFO,"Skipping unsupported PLT marker"); 1700 } 1701 1702 /** 1703 * Reads the RGN marker segment of the codestream header. 1704 * 1705 * <p>May be used in tile or main header. If used in main header, it 1706 * refers to the maxshift value of a component in all tiles. When used in 1707 * tile header, only the particular tile-component is affected.</p> 1708 * 1709 * @param ehs The encoder header stream. 1710 * 1711 * @param mainh Flag indicating whether or not this marker segment is read 1712 * from the main header. 1713 * 1714 * @param tileIdx The index of the current tile 1715 * 1716 * @param tpIdx Tile-part index 1717 * 1718 * @exception IOException If an I/O error occurs while reading from the 1719 * encoder header stream 1720 * */ 1721 private void readRGN(DataInputStream ehs, boolean mainh, int tileIdx, 1722 int tpIdx) throws IOException { 1723 int comp; // ROI component 1724 int i; // loop variable 1725 int tempComp; // Component for 1726 HeaderInfo.RGN ms = hi.getNewRGN(); 1727 1728 // Lrgn (marker length) 1729 ms.lrgn = ehs.readUnsignedShort(); 1730 1731 // Read component 1732 ms.crgn = comp = (nComp < 257) ? ehs.readUnsignedByte(): 1733 ehs.readUnsignedShort(); 1734 if (comp >= nComp) { 1735 throw new CorruptedCodestreamException("Invalid component "+ 1736 "index in RGN marker"+ 1737 comp); 1738 } 1739 1740 // Read type of RGN.(Srgn) 1741 ms.srgn = ehs.readUnsignedByte(); 1742 1743 // Check that we can handle it. 1744 if(ms.srgn != SRGN_IMPLICIT) 1745 throw new CorruptedCodestreamException("Unknown or unsupported "+ 1746 "Srgn parameter in ROI "+ 1747 "marker"); 1748 1749 if(decSpec.rois==null) { // No maxshift spec defined 1750 // Create needed ModuleSpec 1751 decSpec.rois=new MaxShiftSpec(nTiles,nComp, 1752 ModuleSpec.SPEC_TYPE_TILE_COMP, "null"); 1753 } 1754 1755 // SPrgn 1756 ms.sprgn = ehs.readUnsignedByte(); 1757 1758 if(mainh) { 1759 hi.rgn.put("main_c"+comp,ms); 1760 decSpec.rois.setCompDef(comp, new Integer(ms.sprgn)); 1761 } else { 1762 hi.rgn.put("t"+tileIdx+"_c"+comp,ms); 1763 decSpec.rois.setTileCompVal(tileIdx,comp,new Integer(ms.sprgn)); 1764 } 1765 1766 // Check marker length 1767 checkMarkerLength(ehs,"RGN marker"); 1768 } 1769 1770 /** 1771 * Reads the PPM marker segment of the main header. 1772 * 1773 * @param ehs The encoder header stream. 1774 * 1775 * @exception IOException If an I/O error occurs while reading from the 1776 * encoder header stream 1777 * */ 1778 private void readPPM(DataInputStream ehs) throws IOException { 1779 int curMarkSegLen; 1780 int i,indx,len,off; 1781 int remSegLen; 1782 byte[] b; 1783 1784 // If first time readPPM method is called allocate arrays for packed 1785 // packet data 1786 if(pPMMarkerData==null) { 1787 pPMMarkerData = new byte[nPPMMarkSeg][]; 1788 tileOfTileParts = new Vector(); 1789 decSpec.pphs.setDefault(new Boolean(true)); 1790 } 1791 1792 // Lppm (marker length) 1793 curMarkSegLen = ehs.readUnsignedShort(); 1794 remSegLen = curMarkSegLen - 3; 1795 1796 // Zppm (index of PPM marker) 1797 indx = ehs.readUnsignedByte(); 1798 1799 // Read Nppm and Ippm data 1800 pPMMarkerData[indx] = new byte[remSegLen]; 1801 ehs.read(pPMMarkerData[indx],0,remSegLen); 1802 1803 // Check marker length 1804 checkMarkerLength(ehs,"PPM marker"); 1805 } 1806 1807 /** 1808 * Teads the PPT marker segment of the main header. 1809 * 1810 * @param ehs The encoder header stream. 1811 * 1812 * @param tile The tile to which the current tile part belongs 1813 * 1814 * @param tpIdx Tile-part index 1815 * 1816 * @exception IOException If an I/O error occurs while reading from the 1817 * encoder header stream 1818 * */ 1819 private void readPPT(DataInputStream ehs,int tile,int tpIdx) 1820 throws IOException { 1821 int curMarkSegLen; 1822 int indx,len=0; 1823 byte[] temp; 1824 1825 if(tilePartPkdPktHeaders == null){ 1826 tilePartPkdPktHeaders = new byte[nTiles][][][]; 1827 } 1828 1829 if(tilePartPkdPktHeaders[tile] == null){ 1830 tilePartPkdPktHeaders[tile] = new byte[nTileParts[tile]][][]; 1831 } 1832 1833 if(tilePartPkdPktHeaders[tile][tpIdx] == null){ 1834 tilePartPkdPktHeaders[tile][tpIdx] = 1835 new byte[nPPTMarkSeg[tile][tpIdx]][]; 1836 } 1837 1838 // Lppt (marker length) 1839 curMarkSegLen = ehs.readUnsignedShort(); 1840 1841 // Zppt (index of PPT marker) 1842 indx = ehs.readUnsignedByte(); 1843 1844 // Ippt (packed packet headers) 1845 temp = new byte[curMarkSegLen-3]; 1846 ehs.read(temp); 1847 tilePartPkdPktHeaders[tile][tpIdx][indx]=temp; 1848 1849 // Check marker length 1850 checkMarkerLength(ehs,"PPT marker"); 1851 1852 decSpec.pphs.setTileDef(tile, new Boolean(true)); 1853 } 1854 1855 /** 1856 * This method extract a marker segment from the main header and stores it 1857 * into a byte buffer for the second pass. The marker segment is first 1858 * identified. Then its flag is activated. Finally, its content is 1859 * buffered into a byte array stored in an hashTable. 1860 * 1861 * <p>If the marker is not recognized, it prints a warning and skips it 1862 * according to its length.</p> 1863 * 1864 * <p>SIZ marker segment shall be the first encountered marker segment.</p> 1865 * 1866 * @param marker The marker segment to process 1867 * 1868 * @param ehs The encoded header stream 1869 * */ 1870 private void extractMainMarkSeg(short marker,RandomAccessIO ehs) 1871 throws IOException { 1872 if(nfMarkSeg == 0) { // First non-delimiting marker of the header 1873 // JPEG 2000 part 1 specify that it must be SIZ 1874 if(marker != SIZ) { 1875 throw new CorruptedCodestreamException("First marker after "+ 1876 "SOC "+ 1877 "must be SIZ "+ 1878 Integer. 1879 toHexString(marker)); 1880 } 1881 } 1882 1883 String htKey=""; // Name used as a key for the hash-table 1884 if(ht==null) { 1885 ht = new Hashtable(); 1886 } 1887 1888 switch(marker){ 1889 case SIZ: 1890 if ((nfMarkSeg & SIZ_FOUND) != 0) { 1891 throw 1892 new CorruptedCodestreamException("More than one SIZ marker "+ 1893 "segment found in main "+ 1894 "header"); 1895 } 1896 nfMarkSeg |= SIZ_FOUND; 1897 htKey = "SIZ"; 1898 break; 1899 case SOD: 1900 throw new CorruptedCodestreamException("SOD found in main header"); 1901 case EOC: 1902 throw new CorruptedCodestreamException("EOC found in main header"); 1903 case SOT: 1904 if ((nfMarkSeg & SOT_FOUND) != 0) { 1905 throw new CorruptedCodestreamException("More than one SOT "+ 1906 "marker "+ 1907 "found right after "+ 1908 "main "+ 1909 "or tile header"); 1910 } 1911 nfMarkSeg |= SOT_FOUND; 1912 return; 1913 case COD: 1914 if((nfMarkSeg & COD_FOUND) != 0) { 1915 throw new CorruptedCodestreamException("More than one COD "+ 1916 "marker "+ 1917 "found in main header"); 1918 } 1919 nfMarkSeg |= COD_FOUND; 1920 htKey = "COD"; 1921 break; 1922 case COC: 1923 nfMarkSeg |= COC_FOUND; 1924 htKey = "COC"+(nCOCMarkSeg++); 1925 break; 1926 case QCD: 1927 if((nfMarkSeg & QCD_FOUND) != 0) { 1928 throw new CorruptedCodestreamException("More than one QCD "+ 1929 "marker "+ 1930 "found in main header"); 1931 } 1932 nfMarkSeg |= QCD_FOUND; 1933 htKey = "QCD"; 1934 break; 1935 case QCC: 1936 nfMarkSeg |= QCC_FOUND; 1937 htKey = "QCC"+(nQCCMarkSeg++); 1938 break; 1939 case RGN: 1940 nfMarkSeg |= RGN_FOUND; 1941 htKey = "RGN"+(nRGNMarkSeg++); 1942 break; 1943 case COM: 1944 nfMarkSeg |= COM_FOUND; 1945 htKey = "COM"+(nCOMMarkSeg++); 1946 break; 1947 case CRG: 1948 if((nfMarkSeg & CRG_FOUND) != 0) { 1949 throw new CorruptedCodestreamException("More than one CRG "+ 1950 "marker "+ 1951 "found in main header"); 1952 } 1953 nfMarkSeg |= CRG_FOUND; 1954 htKey = "CRG"; 1955 break; 1956 case PPM: 1957 nfMarkSeg |= PPM_FOUND; 1958 htKey = "PPM"+(nPPMMarkSeg++); 1959 break; 1960 case TLM: 1961 if((nfMarkSeg & TLM_FOUND) != 0) { 1962 FacilityManager.getMsgLogger(). 1963 printmsg(MsgLogger.INFO, 1964 "More than one TLM "+ 1965 "marker "+ 1966 "found in main header"); 1967 /** XXX It is legal to have multiple TLM segments. 1968 throw new CorruptedCodestreamException("More than one TLM "+ 1969 "marker "+ 1970 "found in main header"); 1971 */ 1972 } 1973 nfMarkSeg |= TLM_FOUND; 1974 break; 1975 case PLM: 1976 if((nfMarkSeg & PLM_FOUND) != 0) { 1977 throw new CorruptedCodestreamException("More than one PLM "+ 1978 "marker "+ 1979 "found in main header"); 1980 } 1981 FacilityManager.getMsgLogger(). 1982 printmsg(MsgLogger.WARNING,"PLM marker segment found but "+ 1983 "not used by by JJ2000 decoder."); 1984 nfMarkSeg |= PLM_FOUND; 1985 htKey = "PLM"; 1986 break; 1987 case POC: 1988 if( (nfMarkSeg&POC_FOUND)!=0) { 1989 throw new CorruptedCodestreamException("More than one POC "+ 1990 "marker segment found "+ 1991 "in main header"); 1992 } 1993 nfMarkSeg |= POC_FOUND; 1994 htKey = "POC"; 1995 break; 1996 case PLT: 1997 throw new CorruptedCodestreamException("PLT found in main header"); 1998 case PPT: 1999 throw new CorruptedCodestreamException("PPT found in main header"); 2000 default: 2001 htKey = "UNKNOWN"; 2002 FacilityManager.getMsgLogger(). 2003 printmsg(MsgLogger.WARNING,"Non recognized marker segment (0x"+ 2004 Integer.toHexString(marker)+") in main header!"); 2005 break; 2006 } 2007 2008 if(marker < 0xffffff30 || marker > 0xffffff3f){ 2009 // Read marker segment length and create corresponding byte buffer 2010 int markSegLen = ehs.readUnsignedShort(); 2011 byte[] buf = new byte[markSegLen]; 2012 2013 // Copy data (after re-insertion of the marker segment length); 2014 buf[0]= (byte)((markSegLen>>8) & 0xFF); 2015 buf[1]= (byte)(markSegLen & 0xFF); 2016 ehs.readFully(buf,2,markSegLen-2); 2017 2018 if(!htKey.equals("UNKNOWN")) { 2019 // Store array in hashTable 2020 ht.put(htKey,buf); 2021 } 2022 } 2023 } 2024 2025 /** 2026 * This method extracts a marker segment in a tile-part header and stores 2027 * it into a byte buffer for the second pass. The marker is first 2028 * recognized, then its flag is activated and, finally, its content is 2029 * buffered in an element of byte arrays accessible thanks to a hashTable. 2030 * If a marker segment is not recognized, it prints a warning and skip it 2031 * according to its length. 2032 * 2033 * @param marker The marker to process 2034 * 2035 * @param ehs The encoded header stream 2036 * 2037 * @param tileIdx The index of the current tile 2038 * 2039 * @param tilePartIdx The index of the current tile part 2040 * */ 2041 public void extractTilePartMarkSeg(short marker, RandomAccessIO ehs, 2042 int tileIdx, int tilePartIdx) 2043 throws IOException { 2044 2045 String htKey=""; // Name used as a hash-table key 2046 if(ht==null) { 2047 ht = new Hashtable(); 2048 } 2049 2050 switch(marker) { 2051 case SOT: 2052 throw new CorruptedCodestreamException("Second SOT marker "+ 2053 "segment found in tile-"+ 2054 "part header"); 2055 case SIZ: 2056 throw new CorruptedCodestreamException("SIZ found in tile-part"+ 2057 " header"); 2058 case EOC: 2059 throw new CorruptedCodestreamException("EOC found in tile-part"+ 2060 " header"); 2061 case TLM: 2062 throw new CorruptedCodestreamException("TLM found in tile-part"+ 2063 " header"); 2064 case PPM: 2065 throw new CorruptedCodestreamException("PPM found in tile-part"+ 2066 " header"); 2067 case COD: 2068 if((nfMarkSeg & COD_FOUND) != 0) { 2069 throw new CorruptedCodestreamException("More than one COD "+ 2070 "marker "+ 2071 "found in tile-part"+ 2072 " header"); 2073 } 2074 nfMarkSeg |= COD_FOUND; 2075 htKey = "COD"; 2076 break; 2077 case COC: 2078 nfMarkSeg |= COC_FOUND; 2079 htKey = "COC"+(nCOCMarkSeg++); 2080 break; 2081 case QCD: 2082 if((nfMarkSeg & QCD_FOUND) != 0) { 2083 throw new CorruptedCodestreamException("More than one QCD "+ 2084 "marker "+ 2085 "found in tile-part"+ 2086 " header"); 2087 } 2088 nfMarkSeg |= QCD_FOUND; 2089 htKey = "QCD"; 2090 break; 2091 case QCC: 2092 nfMarkSeg |= QCC_FOUND; 2093 htKey = "QCC"+(nQCCMarkSeg++); 2094 break; 2095 case RGN: 2096 nfMarkSeg |= RGN_FOUND; 2097 htKey = "RGN"+(nRGNMarkSeg++); 2098 break; 2099 case COM: 2100 nfMarkSeg |= COM_FOUND; 2101 htKey = "COM"+(nCOMMarkSeg++); 2102 break; 2103 case CRG: 2104 throw new CorruptedCodestreamException("CRG marker found in "+ 2105 "tile-part header"); 2106 case PPT: 2107 nfMarkSeg |= PPT_FOUND; 2108 if(nPPTMarkSeg == null){ 2109 nPPTMarkSeg = new int[nTiles][]; 2110 } 2111 if(nPPTMarkSeg[tileIdx] == null){ 2112 nPPTMarkSeg[tileIdx] = new int[nTileParts[tileIdx]]; 2113 } 2114 htKey = "PPT"+(nPPTMarkSeg[tileIdx][tilePartIdx]++); 2115 break; 2116 case SOD: 2117 nfMarkSeg |= SOD_FOUND; 2118 return; 2119 case POC: 2120 if( (nfMarkSeg&POC_FOUND) != 0) 2121 throw new CorruptedCodestreamException("More than one POC "+ 2122 "marker segment found "+ 2123 "in tile-part"+ 2124 " header"); 2125 nfMarkSeg |= POC_FOUND; 2126 htKey = "POC"; 2127 break; 2128 case PLT: 2129 if((nfMarkSeg & PLM_FOUND) != 0) { 2130 throw new CorruptedCodestreamException("PLT marker found even"+ 2131 "though PLM marker "+ 2132 "found in main header"); 2133 } 2134 FacilityManager.getMsgLogger(). 2135 printmsg(MsgLogger.WARNING,"PLT marker segment found but "+ 2136 "not used by JJ2000 decoder."); 2137 htKey = "UNKNOWN"; 2138 break; 2139 default: 2140 htKey = "UNKNOWN"; 2141 FacilityManager.getMsgLogger(). 2142 printmsg(MsgLogger.WARNING,"Non recognized marker segment (0x"+ 2143 Integer.toHexString(marker)+") in tile-part header"+ 2144 " of tile "+tileIdx+" !"); 2145 break; 2146 } 2147 2148 // Read marker segment length and create corresponding byte buffer 2149 int markSegLen = ehs.readUnsignedShort(); 2150 byte[] buf = new byte[markSegLen]; 2151 2152 // Copy data (after re-insertion of marker segment length); 2153 buf[0]= (byte)((markSegLen>>8) & 0xFF); 2154 buf[1]= (byte)(markSegLen & 0xFF); 2155 ehs.readFully(buf,2,markSegLen-2); 2156 2157 if(!htKey.equals("UNKNOWN")) { 2158 // Store array in hashTable 2159 ht.put(htKey,buf); 2160 } 2161 } 2162 2163 2164 2165 /** 2166 * Retrieves and reads all marker segments found in the main header during 2167 * the first pass. 2168 * */ 2169 private void readFoundMainMarkSeg() throws IOException { 2170 DataInputStream dis; 2171 ByteArrayInputStream bais; 2172 2173 // SIZ marker segment 2174 if((nfMarkSeg&SIZ_FOUND) != 0) { 2175 bais = new ByteArrayInputStream( (byte[])(ht.get("SIZ"))); 2176 readSIZ(new DataInputStream(bais)); 2177 } 2178 2179 // COM marker segments 2180 if((nfMarkSeg&COM_FOUND) != 0) { 2181 for(int i=0; i<nCOMMarkSeg; i++) { 2182 bais = new ByteArrayInputStream( (byte[])(ht.get("COM"+i))); 2183 readCOM(new DataInputStream(bais),true,0,i); 2184 } 2185 } 2186 2187 // CRG marker segment 2188 if((nfMarkSeg&CRG_FOUND) != 0) { 2189 bais = new ByteArrayInputStream( (byte[])(ht.get("CRG"))); 2190 readCRG(new DataInputStream(bais)); 2191 } 2192 2193 // COD marker segment 2194 if((nfMarkSeg&COD_FOUND) != 0) { 2195 bais = new ByteArrayInputStream( (byte[])(ht.get("COD"))); 2196 readCOD(new DataInputStream(bais),true,0,0); 2197 } 2198 2199 // COC marker segments 2200 if((nfMarkSeg&COC_FOUND) != 0) { 2201 for(int i=0; i<nCOCMarkSeg; i++) { 2202 bais = new ByteArrayInputStream( (byte[])(ht.get("COC"+i))); 2203 readCOC(new DataInputStream(bais),true,0,0); 2204 } 2205 } 2206 2207 // RGN marker segment 2208 if((nfMarkSeg&RGN_FOUND) != 0) { 2209 for(int i=0; i<nRGNMarkSeg; i++) { 2210 bais = new ByteArrayInputStream( (byte[])(ht.get("RGN"+i))); 2211 readRGN(new DataInputStream(bais),true,0,0); 2212 } 2213 } 2214 2215 // QCD marker segment 2216 if((nfMarkSeg&QCD_FOUND) != 0) { 2217 bais = new ByteArrayInputStream( (byte[])(ht.get("QCD"))); 2218 readQCD(new DataInputStream(bais),true,0,0); 2219 } 2220 2221 // QCC marker segments 2222 if((nfMarkSeg&QCC_FOUND) != 0) { 2223 for(int i=0;i<nQCCMarkSeg; i++) { 2224 bais = new ByteArrayInputStream( (byte[])(ht.get("QCC"+i))); 2225 readQCC(new DataInputStream(bais),true,0,0); 2226 } 2227 } 2228 2229 // POC marker segment 2230 if( (nfMarkSeg&POC_FOUND) != 0) { 2231 bais = new ByteArrayInputStream( (byte[])(ht.get("POC"))); 2232 readPOC(new DataInputStream(bais),true,0,0); 2233 } 2234 2235 // PPM marker segments 2236 if((nfMarkSeg&PPM_FOUND) != 0) { 2237 for(int i=0;i<nPPMMarkSeg; i++) { 2238 bais = new ByteArrayInputStream( (byte[])(ht.get("PPM"+i))); 2239 readPPM(new DataInputStream(bais)); 2240 } 2241 } 2242 2243 // Reset the hashtable 2244 ht = null; 2245 } 2246 2247 2248 /** 2249 * Return the DecoderSpecs instance filled when reading the headers 2250 * 2251 * @retrieves and reads all marker segments previously found in the 2252 * tile-part header. 2253 * 2254 * @param tileIdx The index of the current tile 2255 * 2256 * @param tpIdx Index of the current tile-part 2257 * */ 2258 public void readFoundTilePartMarkSeg(int tileIdx,int tpIdx) 2259 throws IOException { 2260 2261 DataInputStream dis; 2262 ByteArrayInputStream bais; 2263 2264 // COD marker segment 2265 if((nfMarkSeg&COD_FOUND) != 0) { 2266 bais = new ByteArrayInputStream( (byte[])(ht.get("COD")) ); 2267 readCOD(new DataInputStream(bais),false,tileIdx,tpIdx); 2268 } 2269 2270 // COC marker segments 2271 if((nfMarkSeg&COC_FOUND) != 0) { 2272 for(int i=0; i<nCOCMarkSeg; i++) { 2273 bais = new ByteArrayInputStream( (byte[])(ht.get("COC"+i)) ); 2274 readCOC(new DataInputStream(bais),false,tileIdx,tpIdx); 2275 } 2276 } 2277 2278 // RGN marker segment 2279 if((nfMarkSeg&RGN_FOUND) != 0) { 2280 for(int i=0; i<nRGNMarkSeg; i++) { 2281 bais = new ByteArrayInputStream( (byte[])(ht.get("RGN"+i)) ); 2282 readRGN(new DataInputStream(bais),false,tileIdx,tpIdx); 2283 } 2284 } 2285 2286 // QCD marker segment 2287 if((nfMarkSeg&QCD_FOUND) != 0) { 2288 bais = new ByteArrayInputStream( (byte[])(ht.get("QCD")) ); 2289 readQCD(new DataInputStream(bais),false,tileIdx,tpIdx); 2290 } 2291 2292 // QCC marker segments 2293 if((nfMarkSeg&QCC_FOUND) != 0) { 2294 for(int i=0;i<nQCCMarkSeg; i++) { 2295 bais = new ByteArrayInputStream( (byte[])(ht.get("QCC"+i)) ); 2296 readQCC(new DataInputStream(bais),false,tileIdx,tpIdx); 2297 } 2298 } 2299 // POC marker segment 2300 if( (nfMarkSeg&POC_FOUND) != 0) { 2301 bais = new ByteArrayInputStream( (byte[])(ht.get("POC"))); 2302 readPOC(new DataInputStream(bais),false,tileIdx,tpIdx); 2303 } 2304 2305 // COM marker segments 2306 if((nfMarkSeg&COM_FOUND) != 0) { 2307 for(int i=0; i<nCOMMarkSeg; i++) { 2308 bais = new ByteArrayInputStream( (byte[])(ht.get("COM"+i)) ); 2309 readCOM(new DataInputStream(bais),false,tileIdx,i); 2310 } 2311 } 2312 2313 // PPT marker segments 2314 if((nfMarkSeg&PPT_FOUND) != 0) { 2315 for(int i=0;i<nPPTMarkSeg[tileIdx][tpIdx]; i++) { 2316 bais = new ByteArrayInputStream( (byte[])(ht.get("PPT"+i)) ); 2317 readPPT(new DataInputStream(bais),tileIdx,tpIdx); 2318 } 2319 } 2320 2321 // Reset ht 2322 ht = null; 2323 } 2324 2325 2326 /** 2327 * Return the DecoderSpecs instance filled when reading the headers 2328 * 2329 * @return The DecoderSpecs of the decoder 2330 * */ 2331 public DecoderSpecs getDecoderSpecs(){ 2332 return decSpec; 2333 } 2334 2335 /** 2336 * Creates a HeaderDecoder instance and read in two passes the main header 2337 * of the codestream. The first and last marker segments shall be 2338 * respectively SOC and SOT. 2339 * 2340 * @param ehs The encoded header stream where marker segment are 2341 * extracted. 2342 * 2343 * @param j2krparam The parameter list of the decoder 2344 * 2345 * @param hi The HeaderInfo holding information found in marker segments 2346 * 2347 * @exception IOException If an I/O error occurs while reading from the 2348 * encoded header stream. 2349 * 2350 * @exception EOFException If the end of the encoded header stream is 2351 * reached before getting all the data. 2352 * 2353 * @exception CorruptedCodestreamException If invalid data is found in the 2354 * codestream main header. 2355 * */ 2356 public HeaderDecoder(RandomAccessIO ehs, 2357 J2KImageReadParamJava j2krparam, 2358 HeaderInfo hi) 2359 throws IOException { 2360 2361 this.hi = hi; 2362 this.j2krparam = j2krparam; 2363 mainHeadOff = ehs.getPos(); 2364 if( ((short)ehs.readShort()) != Markers.SOC ) { 2365 throw new CorruptedCodestreamException("SOC marker segment not "+ 2366 " found at the "+ 2367 "beginning of the "+ 2368 "codestream."); 2369 } 2370 2371 // First Pass: Decode and store main header information until the SOT 2372 // marker segment is found 2373 nfMarkSeg = 0; 2374 do { 2375 extractMainMarkSeg(ehs.readShort(),ehs); 2376 } while ((nfMarkSeg & SOT_FOUND)==0); //Stop when SOT is found 2377 ehs.seek(ehs.getPos()-2); // Realign codestream on SOT marker 2378 2379 // Second pass: Read each marker segment previously found 2380 readFoundMainMarkSeg(); 2381 } 2382 2383 /** 2384 * Creates and returns the entropy decoder corresponding to the 2385 * information read from the codestream header and with the special 2386 * additional parameters from the parameter list. 2387 * 2388 * @param src The bit stream reader agent where to get code-block data 2389 * from. 2390 * 2391 * @param j2krparam The parameter list containing parameters applicable to the 2392 * entropy decoder (other parameters can also be present). 2393 * 2394 * @return The entropy decoder 2395 * */ 2396 public EntropyDecoder createEntropyDecoder(CodedCBlkDataSrcDec src, 2397 J2KImageReadParamJava j2krparam) { 2398 // Get error detection option 2399 // boolean doer = j2krparam.getCer();; 2400 boolean doer = true; 2401 // Get verbose error detection option 2402 //boolean verber = j2krparam.getVerbose(); 2403 boolean verber = false; 2404 2405 // Get maximum number of bit planes from m quit condition 2406// int mMax = j2krparam.getMQuit(); 2407 int mMax = -1; 2408 return new StdEntropyDecoder(src,decSpec,doer,verber,mMax); 2409 } 2410 2411 2412 /** 2413 * Creates and returns the EnumeratedColorSpaceMapper 2414 * corresponding to the information read from the JP2 image file 2415 * via the ColorSpace parameter. 2416 * 2417 * @param src The bit stream reader agent where to get code-block 2418 * data from. 2419 * @param csMap provides color space information from the image file 2420 * 2421 * @return The color space mapping object 2422 * @exception IOException image access exception 2423 * @exception ICCProfileException if image contains a bad icc profile 2424 * @exception ColorSpaceException if image contains a bad colorspace box 2425 **/ 2426/* 2427 public BlkImgDataSrc createColorSpaceMapper(BlkImgDataSrc src, 2428 ColorSpace csMap) 2429 throws IOException, ICCProfileException, ColorSpaceException { 2430 return ColorSpaceMapper.createInstance(src,csMap); 2431 } 2432*/ 2433 /** 2434 * Creates and returns the ChannelDefinitonMapper which maps the 2435 * input channels to the channel definition for the appropriate 2436 * colorspace. 2437 * 2438 * @param src The bit stream reader agent where to get code-block 2439 * data from. 2440 * @param csMap provides color space information from the image file 2441 * 2442 * @return The channel definition mapping object 2443 * @exception IOException image access exception 2444 * @exception ColorSpaceException if image contains a bad colorspace box 2445 **/ 2446/* 2447 public BlkImgDataSrc createChannelDefinitionMapper(BlkImgDataSrc src, 2448 ColorSpace csMap) 2449 throws IOException, ColorSpaceException { 2450 return ChannelDefinitionMapper.createInstance(src,csMap); 2451 } 2452*/ 2453 /** 2454 * Creates and returns the PalettizedColorSpaceMapper which uses 2455 * the input samples as indicies into a sample palette to 2456 * construct the output. 2457 * 2458 * @param src The bit stream reader agent where to get code-block 2459 * data from. 2460 * @param csMap provides color space information from the image file 2461 * 2462 * @return a PalettizedColorSpaceMapper instance 2463 * @exception IOException image access exception 2464 * @exception ColorSpaceException if image contains a bad colorspace box 2465 **/ 2466/* 2467 public BlkImgDataSrc createPalettizedColorSpaceMapper(BlkImgDataSrc src, 2468 ColorSpace csMap) 2469 throws IOException, ColorSpaceException { 2470 return PalettizedColorSpaceMapper.createInstance(src, csMap); } 2471*/ 2472 /** 2473 * Creates and returns the Resampler which converts the input 2474 * source to one in which all channels have the same number of 2475 * samples. This is required for colorspace conversions. 2476 * 2477 * @param src The bit stream reader agent where to get code-block 2478 * data from. 2479 * @param csMap provides color space information from the image file 2480 * 2481 * @return The resampled BlkImgDataSrc 2482 * @exception IOException image access exception 2483 * @exception ColorSpaceException if image contains a bad colorspace box 2484 **/ 2485/* 2486 public BlkImgDataSrc createResampler(BlkImgDataSrc src, 2487 ColorSpace csMap) 2488 throws IOException, ColorSpaceException { 2489 return Resampler.createInstance(src, csMap); } 2490*/ 2491 /** 2492 * Creates and returns the ROIDeScaler corresponding to the information 2493 * read from the codestream header and with the special additional 2494 * parameters from the parameter list. 2495 * 2496 * @param src The bit stream reader agent where to get code-block data 2497 * from. 2498 * 2499 * @param pl The parameter list containing parameters applicable to the 2500 * entropy decoder (other parameters can also be present). 2501 * 2502 * @return The ROI descaler 2503 * */ 2504 public ROIDeScaler createROIDeScaler(CBlkQuantDataSrcDec src, 2505 J2KImageReadParamJava j2krparam, 2506 DecoderSpecs decSpec2){ 2507 return ROIDeScaler.createInstance(src, j2krparam, decSpec2); 2508 } 2509 2510 /** 2511 * Method that resets members indicating which markers have already been 2512 * found 2513 * */ 2514 public void resetHeaderMarkers() { 2515 // The found status of PLM remains since only PLM OR PLT allowed 2516 // Same goes for PPM and PPT 2517 nfMarkSeg = nfMarkSeg & (PLM_FOUND | PPM_FOUND); 2518 nCOCMarkSeg = 0; 2519 nQCCMarkSeg = 0; 2520 nCOMMarkSeg = 0; 2521 nRGNMarkSeg = 0; 2522 } 2523 2524 2525 /** 2526 * Print information about the current header. 2527 * 2528 * @return Information in a String 2529 * */ 2530 public String toString(){ 2531 return hdStr; 2532 } 2533 2534 /** 2535 * Returns the parameters that are used in this class. It returns a 2D 2536 * String array. Each of the 1D arrays is for a different option, and they 2537 * have 3 elements. The first element is the option name, the second one 2538 * is the synopsis and the third one is a long description of what the 2539 * parameter is. The synopsis or description may be 'null', in which case 2540 * it is assumed that there is no synopsis or description of the option, 2541 * respectively. 2542 * 2543 * @return the options name, their synopsis and their explanation. 2544 * */ 2545 public static String[][] getParameterInfo() { 2546 return pinfo; 2547 } 2548 2549 /** 2550 * Return the number of tiles in the image 2551 * 2552 * @return The number of tiles 2553 * */ 2554 public int getNumTiles(){ 2555 return nTiles; 2556 } 2557 2558 /** 2559 * Return the packed packet headers for a given tile. 2560 * 2561 * @return An input stream containing the packed packet headers for a 2562 * particular tile 2563 * 2564 * @exception IOException If an I/O error occurs while reading from the 2565 * encoder header stream 2566 * */ 2567 public ByteArrayInputStream getPackedPktHead(int tile) 2568 throws IOException { 2569 2570 if(pkdPktHeaders==null) { 2571 int i,t; 2572 pkdPktHeaders = new ByteArrayOutputStream[nTiles]; 2573 for(i=nTiles-1; i>=0; i--) { 2574 pkdPktHeaders[i] = new ByteArrayOutputStream(); 2575 } 2576 if(nPPMMarkSeg!=0) { 2577 // If this is first time packed packet headers are requested, 2578 // create packed packet headers from Nppm and Ippm fields 2579 int nppm; 2580 int nTileParts = tileOfTileParts.size(); 2581 byte[] temp; 2582 ByteArrayInputStream pph; 2583 ByteArrayOutputStream allNppmIppm = 2584 new ByteArrayOutputStream(); 2585 2586 // Concatenate all Nppm and Ippm fields 2587 for(i=0 ; i<nPPMMarkSeg ; i++) { 2588 allNppmIppm.write(pPMMarkerData[i]); 2589 } 2590 pph = new ByteArrayInputStream(allNppmIppm.toByteArray()); 2591 2592 // Read all packed packet headers and concatenate for each 2593 // tile part 2594 for(i=0; i<nTileParts ; i++) { 2595 t = ((Integer)tileOfTileParts.elementAt(i)).intValue(); 2596 // get Nppm value 2597 nppm = (pph.read()<<24)|(pph.read()<<16)| 2598 (pph.read()<<8)|(pph.read()); 2599 2600 temp = new byte[nppm]; 2601 // get ippm field 2602 pph.read(temp); 2603 pkdPktHeaders[t].write(temp); 2604 } 2605 } else { 2606 int tp; 2607 // Write all packed packet headers to pkdPktHeaders 2608 for(t=nTiles-1; t>=0; t--) { 2609 for(tp=0; tp<nTileParts[t]; tp++){ 2610 for(i=0 ; i<nPPTMarkSeg[t][tp] ; i++) { 2611 pkdPktHeaders[t]. 2612 write(tilePartPkdPktHeaders[t][tp][i]); 2613 } 2614 } 2615 } 2616 } 2617 } 2618 2619 return new ByteArrayInputStream(pkdPktHeaders[tile].toByteArray()); 2620 } 2621 2622 /** 2623 * Sets the tile of each tile part in order. This information is needed 2624 * for identifying which packet header belongs to which tile when using 2625 * the PPM marker. 2626 * 2627 * @param tile The tile number that the present tile part belongs to. 2628 * */ 2629 public void setTileOfTileParts(int tile) { 2630 if(nPPMMarkSeg!=0) { 2631 tileOfTileParts.addElement(new Integer(tile)); 2632 } 2633 } 2634 2635 /** 2636 * Returns the number of found marker segments in the current header. 2637 * 2638 * @return The number of marker segments found in the current header. 2639 * */ 2640 public int getNumFoundMarkSeg() { 2641 return nfMarkSeg; 2642 } 2643 2644}