All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jj2000.j2k.codestream.reader.HeaderDecoder Maven / Gradle / Ivy

Go to download

JPEG2000 support for Java Advanced Imaging Image I/O Tools API core. This module is licensed under the [JJ2000 license](LICENSE.txt) and is therefore NOT compatible with the GPL 3 license. It should be compatible with the LGPL 2.1 license.

There is a newer version: 1.4.0
Show newest version
/*
 * $RCSfile: HeaderDecoder.java,v $
 * $Revision: 1.2 $
 * $Date: 2006/09/28 00:55:20 $
 * $State: Exp $
 *
 * Class:                   HeaderDecoder
 *
 * Description:             Reads main and tile-part headers.
 *
 *
 *
 * COPYRIGHT:
 *
 * This software module was originally developed by Raphaël Grosbois and
 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
 * Centre France S.A) in the course of development of the JPEG2000
 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
 * software module is an implementation of a part of the JPEG 2000
 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
 * Partners) agree not to assert against ISO/IEC and users of the JPEG
 * 2000 Standard (Users) any of their rights under the copyright, not
 * including other intellectual property rights, for this software module
 * with respect to the usage by ISO/IEC and Users of this software module
 * or modifications thereof for use in hardware or software products
 * claiming conformance to the JPEG 2000 Standard. Those intending to use
 * this software module in hardware or software products are advised that
 * their use may infringe existing patents. The original developers of
 * this software module, JJ2000 Partners and ISO/IEC assume no liability
 * for use of this software module or modifications thereof. No license
 * or right to this software module is granted for non JPEG 2000 Standard
 * conforming products. JJ2000 Partners have full right to use this
 * software module for his/her own purpose, assign or donate this
 * software module to any third party and to inhibit third parties from
 * using this software module for non JPEG 2000 Standard conforming
 * products. This copyright notice must be included in all copies or
 * derivative works of this software module.
 *
 * Copyright (c) 1999/2000 JJ2000 Partners.
 * */
package jj2000.j2k.codestream.reader;
import java.awt.Point;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;

import jj2000.j2k.ModuleSpec;
import jj2000.j2k.NotImplementedError;
import jj2000.j2k.codestream.CorruptedCodestreamException;
import jj2000.j2k.codestream.HeaderInfo;
import jj2000.j2k.codestream.Markers;
import jj2000.j2k.codestream.ProgressionType;
import jj2000.j2k.decoder.DecoderSpecs;
import jj2000.j2k.entropy.StdEntropyCoderOptions;
import jj2000.j2k.entropy.decoder.CodedCBlkDataSrcDec;
import jj2000.j2k.entropy.decoder.EntropyDecoder;
import jj2000.j2k.entropy.decoder.StdEntropyDecoder;
import jj2000.j2k.io.RandomAccessIO;
import jj2000.j2k.quantization.dequantizer.CBlkQuantDataSrcDec;
import jj2000.j2k.quantization.dequantizer.Dequantizer;
import jj2000.j2k.quantization.dequantizer.StdDequantizer;
import jj2000.j2k.quantization.dequantizer.StdDequantizerParams;
import jj2000.j2k.roi.MaxShiftSpec;
import jj2000.j2k.roi.ROIDeScaler;
import jj2000.j2k.util.FacilityManager;
import jj2000.j2k.util.MsgLogger;
import jj2000.j2k.wavelet.FilterTypes;
import jj2000.j2k.wavelet.synthesis.SynWTFilter;
import jj2000.j2k.wavelet.synthesis.SynWTFilterFloatLift9x7;
import jj2000.j2k.wavelet.synthesis.SynWTFilterIntLift5x3;

import com.github.jaiimageio.jpeg2000.impl.J2KImageReadParamJava;

/**
 * This class reads Main and Tile-part headers from the codestream. It is
 * created by the run() method of the Decoder instance.
 *
 * 

A marker segment includes a marker and eventually marker segment * parameters. It is designed by the three letters code of the marker * associated with the marker segment. JPEG 2000 part 1 defines 6 types of * markers: * *

    *
  • Delimiting : SOC,SOT (read in FileBitstreamReaderAgent),SOD,EOC * (read in FileBitstreamReaderAgent).
  • Fixed information: SIZ.
  • * *
  • Functional: COD,COC,RGN,QCD,QCC,POC.
  • In bit-stream: * SOP,EPH.
  • * *
  • Pointer: TLM,PLM,PLT,PPM,PPT.
  • * *
  • Informational: CRG,COM.
  • *
* *

The main header is read when the constructor is called whereas tile-part * headers are read when the FileBitstreamReaderAgent instance is created. The * reading is done in 2 passes: * *

    *
  • All marker segments are buffered and their corresponding flag is * activated (extractMainMarkSeg and extractTilePartMarkSeg methods).
  • * *
  • Buffered marker segment are analyzed in a logical way and * specifications are stored in appropriate member of DecoderSpecs instance * (readFoundMainMarkSeg and readFoundTilePartMarkSeg methods).
  • *
* *

Whenever a marker segment is not recognized a warning message is * displayed and its length parameter is used to skip it. * * @see DecoderSpecs * @see Decoder * @see FileBitstreamReaderAgent * */ public class HeaderDecoder implements ProgressionType, Markers, StdEntropyCoderOptions { /** The prefix for header decoder options: 'H' */ public final static char OPT_PREFIX = 'H'; /** The list of parameters that is accepted for quantization. Options * for quantization start with 'Q'. */ private final static String [][] pinfo = null; /** The reference to the HeaderInfo instance holding the information found * in headers */ private HeaderInfo hi; /** Current header information in a string */ private String hdStr = ""; /** The J2KImageReadParamJava instance of the decoder */ private J2KImageReadParamJava j2krparam; /** The number of tiles within the image */ private int nTiles; /** The number of tile parts per tile */ public int[] nTileParts; /** Used to store which markers have been already read, by using flag * bits. The different markers are marked with XXX_FOUND flags, such as * SIZ_FOUND */ private int nfMarkSeg = 0; /** Counts number of COC markers found in the header */ private int nCOCMarkSeg = 0; /** Counts number of QCC markers found in the header */ private int nQCCMarkSeg = 0; /** Counts number of COM markers found in the header */ private int nCOMMarkSeg = 0; /** Counts number of RGN markers found in the header */ private int nRGNMarkSeg = 0; /** Counts number of PPM markers found in the header */ private int nPPMMarkSeg = 0; /** Counts number of PPT markers found in the header */ private int[][] nPPTMarkSeg = null; /** Flag bit for SIZ marker segment found */ private static final int SIZ_FOUND = 1; /** Flag bit for COD marker segment found */ private static final int COD_FOUND = 1<<1; /** Flag bit for COC marker segment found */ private static final int COC_FOUND = 1<<2; /** Flag bit for QCD marker segment found */ private static final int QCD_FOUND = 1<<3; /** Flag bit for TLM marker segment found */ private static final int TLM_FOUND = 1<<4; /** Flag bit for PLM marker segment found */ private static final int PLM_FOUND = 1<<5; /** Flag bit for SOT marker segment found */ private static final int SOT_FOUND = 1<<6; /** Flag bit for PLT marker segment found */ private static final int PLT_FOUND = 1<<7; /** Flag bit for QCC marker segment found */ private static final int QCC_FOUND = 1<<8; /** Flag bit for RGN marker segment found */ private static final int RGN_FOUND = 1<<9; /** Flag bit for POC marker segment found */ private static final int POC_FOUND = 1<<10; /** Flag bit for COM marker segment found */ private static final int COM_FOUND = 1<<11; /** Flag bit for SOD marker segment found */ public static final int SOD_FOUND = 1<<13; /** Flag bit for SOD marker segment found */ public static final int PPM_FOUND = 1<<14; /** Flag bit for SOD marker segment found */ public static final int PPT_FOUND = 1<<15; /** Flag bit for CRG marker segment found */ public static final int CRG_FOUND = 1<<16; /** The reset mask for new tiles */ private static final int TILE_RESET = ~(PLM_FOUND|SIZ_FOUND|RGN_FOUND); /** HashTable used to store marker segment byte buffers */ private Hashtable ht = null; /** The number of components in the image */ private int nComp; /** The horizontal code-block partition origin */ private int cb0x = -1; /** The vertical code-block partition origin */ private int cb0y = -1; /** The decoder specifications */ private DecoderSpecs decSpec; /** Is the precinct partition used */ boolean precinctPartitionIsUsed; /** The offset of the main header in the input stream */ public int mainHeadOff; /** Vector containing info as to which tile each tilepart belong */ public Vector tileOfTileParts; /** Array containing the Nppm and Ippm fields of the PPM marker segments*/ private byte[][] pPMMarkerData; /** Array containing the Ippm fields of the PPT marker segments */ private byte[][][][] tilePartPkdPktHeaders; /** The packed packet headers if the PPM or PPT markers are used */ private ByteArrayOutputStream[] pkdPktHeaders; /** * Return the maximum height among all components * * @return Maximum component height * */ public int getMaxCompImgHeight() { return hi.siz.getMaxCompHeight(); } /** * Return the maximum width among all components * * @return Maximum component width * */ public int getMaxCompImgWidth() { return hi.siz.getMaxCompWidth(); } /** * Returns the image width in the reference grid. * * @return The image width in the reference grid * */ public final int getImgWidth() { return hi.siz.xsiz-hi.siz.x0siz; } /** * Returns the image height in the reference grid. * * @return The image height in the reference grid * */ public final int getImgHeight() { return hi.siz.ysiz-hi.siz.y0siz; } /** * Return the horizontal upper-left coordinate of the image in the * reference grid. * * @return The horizontal coordinate of the image origin. * */ public final int getImgULX() { return hi.siz.x0siz; } /** * Return the vertical upper-left coordinate of the image in the reference * grid. * * @return The vertical coordinate of the image origin. * */ public final int getImgULY() { return hi.siz.y0siz; } /** * Returns the nominal width of the tiles in the reference grid. * * @return The nominal tile width, in the reference grid. * */ public final int getNomTileWidth() { return hi.siz.xtsiz; } /** * Returns the nominal width of the tiles in the reference grid. * * @return The nominal tile width, in the reference grid. * */ public final int getNomTileHeight() { return hi.siz.ytsiz; } /** * Returns the tiling origin, referred to as '(Px,Py)' in the 'ImgData' * interface. * * @param co If not null this object is used to return the information. If * null a new one is created and returned. * * @return The coordinate of the tiling origin, in the canvas system, on * the reference grid. * * @see jj2000.j2k.image.ImgData * */ public final Point getTilingOrigin(Point co) { if (co != null) { co.x = hi.siz.xt0siz; co.y = hi.siz.yt0siz; return co; } else { return new Point(hi.siz.xt0siz,hi.siz.yt0siz); } } /** * Returns true if the original data of the specified component was * signed. If the data was not signed a level shift has to be applied at * the end of the decompression chain. * * @param c The index of the component * * @return True if the original image component was signed. * */ public final boolean isOriginalSigned(int c) { return hi.siz.isOrigSigned(c); } /** * Returns the original bitdepth of the specified component. * * @param c The index of the component * * @return The bitdepth of the component * */ public final int getOriginalBitDepth(int c) { return hi.siz.getOrigBitDepth(c); } /** * Returns the number of components in the image. * * @return The number of components in the image. * */ public final int getNumComps() { return nComp; } /** * Returns the component sub-sampling factor, with respect to the * reference grid, along the horizontal direction for the specified * component. * * @param c The index of the component * * @return The component sub-sampling factor X-wise. * */ public final int getCompSubsX(int c) { return hi.siz.xrsiz[c]; } /** * Returns the component sub-sampling factor, with respect to the * reference grid, along the vertical direction for the specified * component. * * @param c The index of the component * * @return The component sub-sampling factor Y-wise. * */ public final int getCompSubsY(int c) { return hi.siz.yrsiz[c]; } /** * Returns the dequantizer parameters. Dequantizer parameters normally are * the quantization step sizes, see DequantizerParams. * * @param src The source of data for the dequantizer. * * @param rb The number of range bits for each component. Must be * the number of range bits of the mixed components. * * @param decSpec2 The DecoderSpecs instance after any image manipulation. * * @return The dequantizer * */ public final Dequantizer createDequantizer(CBlkQuantDataSrcDec src, int rb[], DecoderSpecs decSpec2) { return new StdDequantizer(src,rb,decSpec2); } /** * Returns the horizontal code-block partition origin.Allowable values are * 0 and 1, nothing else. * */ public final int getCbULX() { return cb0x; } /** * Returns the vertical code-block partition origin. Allowable values are * 0 and 1, nothing else. * */ public final int getCbULY() { return cb0y; } /** * Returns the precinct partition width for the specified tile-component * and resolution level. * * @param c the component index * * @param t the tile index * * @param rl the resolution level * * @return The precinct partition width for the specified tile-component * and resolution level * */ public final int getPPX(int t,int c,int rl) { return decSpec.pss.getPPX(t,c,rl); } /** * Returns the precinct partition height for the specified component, tile * and resolution level. * * @param c the component * * @param t the tile index * * @param rl the resolution level * * @return The precinct partition height for the specified component, * tile and resolution level * */ public final int getPPY(int t, int c, int rl) { return decSpec.pss.getPPY(t, c, rl); } /** * Returns the boolean used to know if the precinct partition is used **/ public final boolean precinctPartitionUsed() { return precinctPartitionIsUsed; } /** * Reads a wavelet filter from the codestream and returns the filter * object that implements it. * * @param ehs The encoded header stream from where to read the info * * @param filtIdx Int array of one element to return the type of the * wavelet filter. * */ private SynWTFilter readFilter(DataInputStream ehs,int[] filtIdx) throws IOException { int kid; // the filter id kid = filtIdx[0] = ehs.readUnsignedByte(); if (kid >= (1<<7)) { throw new NotImplementedError("Custom filters not supported"); } // Return filter based on ID switch (kid) { case FilterTypes.W9X7: return new SynWTFilterFloatLift9x7(); case FilterTypes.W5X3: return new SynWTFilterIntLift5x3(); default: throw new CorruptedCodestreamException("Specified wavelet filter "+ "not"+ " JPEG 2000 part I "+ "compliant"); } } /** * Checks that the marker segment length is correct. * * @param ehs The encoded header stream * * @param str The string identifying the marker, such as "SIZ marker" * * @exception IOException If an I/O error occurs * */ public void checkMarkerLength(DataInputStream ehs, String str) throws IOException { if (ehs.available()!=0) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING, str+" length was short, attempting to resync."); } } /** * Reads the SIZ marker segment and realigns the codestream at the point * where the next marker segment should be found. * *

SIZ is a fixed information marker segment containing informations * about image and tile sizes. It is required in the main header * immediately after SOC.

* * @param ehs The encoded header stream * * @exception IOException If an I/O error occurs while reading from the * encoded header stream * */ private void readSIZ (DataInputStream ehs) throws IOException { HeaderInfo.SIZ ms = hi.getNewSIZ(); hi.siz = ms; // Read the length of SIZ marker segment (Lsiz) ms.lsiz = ehs.readUnsignedShort(); // Read the capability of the codestream (Rsiz) ms.rsiz = ehs.readUnsignedShort(); if (ms.rsiz > 2) { throw new Error("Codestream capabiities not JPEG 2000 - Part I"+ " compliant"); } // Read image size ms.xsiz = ehs.readInt(); ms.ysiz = ehs.readInt(); if ( ms.xsiz<=0 || ms.ysiz<=0 ) { throw new IOException("JJ2000 does not support images whose "+ "width and/or height not in the "+ "range: 1 -- (2^31)-1"); } // Read image offset ms.x0siz = ehs.readInt(); ms.y0siz = ehs.readInt(); if ( ms.x0siz<0 || ms.y0siz<0 ) { throw new IOException("JJ2000 does not support images offset "+ "not in the range: 0 -- (2^31)-1"); } // Read size of tile ms.xtsiz = ehs.readInt(); ms.ytsiz = ehs.readInt(); if ( ms.xtsiz<=0 || ms.ytsiz<=0 ) { throw new IOException("JJ2000 does not support tiles whose "+ "width and/or height are not in "+ "the range: 1 -- (2^31)-1"); } // Read upper-left tile offset ms.xt0siz = ehs.readInt(); ms.yt0siz = ehs.readInt(); if ( ms.xt0siz<0 || ms.yt0siz<0 ){ throw new IOException("JJ2000 does not support tiles whose "+ "offset is not in "+ "the range: 0 -- (2^31)-1"); } // Read number of components and initialize related arrays nComp = ms.csiz = ehs.readUnsignedShort(); if (nComp<1 || nComp>16384) { throw new IllegalArgumentException("Number of component out of "+ "range 1--16384: "+nComp); } ms.ssiz = new int[nComp]; ms.xrsiz = new int[nComp]; ms.yrsiz = new int[nComp]; // Read bit-depth and down-sampling factors of each component for(int i = 0; i maxrl-rl) { hpd -= maxrl-rl; } else { hpd = 1; } // Determine max and min subband index minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) maxb = 1<<(hpd<<1); // maxb = 4^hpd } // Allocate array for subbands in resolution level exp[rl] = new int[maxb]; for(j=minb; j>SQCX_EXP_SHIFT)&SQCX_EXP_MASK; } }// end for rl } else { int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0 : ( mainh ? ((Integer)decSpec.dls.getDefault()).intValue() : ((Integer)decSpec.dls.getTileDef(tileIdx)).intValue()); int i,j,rl; int minb,maxb,hpd; int tmp; exp = qParms.exp = new int[maxrl+1][]; nStep = qParms.nStep = new float[maxrl+1][]; ms.spqcd = new int[maxrl+1][4]; for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels // Find the number of subbands in the resolution level if (rl == 0) { // Only the LL subband minb = 0; maxb = 1; } else { // Dyadic decomposition hpd = 1; // Adapt hpd to resolution level if (hpd > maxrl-rl) { hpd -= maxrl-rl; } else { hpd = 1; } // Determine max and min subband index minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) maxb = 1<<(hpd<<1); // maxb = 4^hpd } // Allocate array for subbands in resolution level exp[rl] = new int[maxb]; nStep[rl] = new float[maxb]; for(j=minb; j>11) & 0x1f; // NOTE: the formula below does not support more than 5 // bits for the exponent, otherwise (-1<= nComp) { throw new CorruptedCodestreamException("Invalid component "+ "index in QCC marker"); } // Sqcc (quantization style) ms.sqcc = ehs.readUnsignedByte(); int guardBits = ms.getNumGuardBits(); int qType = ms.getQuantType(); if(mainh) { hi.qcc.put("main_c"+cComp,ms); // If main header is being read, set default for component in all // tiles switch (qType) { case SQCX_NO_QUANTIZATION: decSpec.qts.setCompDef(cComp,"reversible"); break; case SQCX_SCALAR_DERIVED: decSpec.qts.setCompDef(cComp,"derived"); break; case SQCX_SCALAR_EXPOUNDED: decSpec.qts.setCompDef(cComp,"expounded"); break; default: throw new CorruptedCodestreamException("Unknown or "+ "unsupported "+ "quantization style "+ "in Sqcd field, QCD "+ "marker, main header"); } } else { hi.qcc.put("t"+tileIdx+"_c"+cComp,ms); // If tile header is being read, set value for component in // this tiles switch (qType) { case SQCX_NO_QUANTIZATION: decSpec.qts.setTileCompVal(tileIdx, cComp,"reversible"); break; case SQCX_SCALAR_DERIVED: decSpec.qts.setTileCompVal(tileIdx, cComp,"derived"); break; case SQCX_SCALAR_EXPOUNDED: decSpec.qts.setTileCompVal(tileIdx, cComp,"expounded"); break; default: throw new CorruptedCodestreamException("Unknown or "+ "unsupported "+ "quantization style "+ "in Sqcd field, QCD "+ "marker, main header"); } } // Decode all dequantizer params qParms = new StdDequantizerParams(); if (qType == SQCX_NO_QUANTIZATION) { int maxrl = ( mainh ? ((Integer)decSpec.dls.getCompDef(cComp)).intValue() : ((Integer)decSpec.dls.getTileCompVal(tileIdx,cComp)). intValue()); int i,j,rl; int minb,maxb,hpd; expC = qParms.exp = new int[maxrl+1][]; ms.spqcc = new int[maxrl+1][4]; for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels // Find the number of subbands in the resolution level if (rl == 0) { // Only the LL subband minb = 0; maxb = 1; } else { // Dyadic decomposition hpd = 1; // Adapt hpd to resolution level if (hpd > maxrl-rl) { hpd -= maxrl-rl; } else { hpd = 1; } // Determine max and min subband index minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) maxb = 1<<(hpd<<1); // maxb = 4^hpd } // Allocate array for subbands in resolution level expC[rl] = new int[maxb]; for(j=minb; j>SQCX_EXP_SHIFT)&SQCX_EXP_MASK; } }// end for rl } else { int maxrl = (qType == SQCX_SCALAR_DERIVED) ? 0 : ( mainh ? ((Integer)decSpec.dls.getCompDef(cComp)).intValue() : ((Integer)decSpec.dls.getTileCompVal(tileIdx,cComp)). intValue()); int i,j,rl; int minb,maxb,hpd; nStepC = qParms.nStep = new float[maxrl+1][]; expC = qParms.exp = new int[maxrl+1][]; ms.spqcc = new int[maxrl+1][4]; for (rl=0; rl <= maxrl; rl++) { // Loop on resolution levels // Find the number of subbands in the resolution level if (rl == 0) { // Only the LL subband minb = 0; maxb = 1; } else { // Dyadic decomposition hpd = 1; // Adapt hpd to resolution level if (hpd > maxrl-rl) { hpd -= maxrl-rl; } else { hpd = 1; } // Determine max and min subband index minb = 1<<((hpd-1)<<1); // minb = 4^(hpd-1) maxb = 1<<(hpd<<1); // maxb = 4^hpd } // Allocate array for subbands in resolution level expC[rl] = new int[maxb]; nStepC[rl] = new float[maxb]; for(j=minb; j>11) & 0x1f; // NOTE: the formula below does not support more than 5 // bits for the exponent, otherwise (-1<65535 ) { throw new CorruptedCodestreamException("Number of layers out of "+ "range: 1--65535"); } // Multiple component transform ms.sgcod_mct = ehs.readUnsignedByte(); // SPcod // decomposition levels int mrl = ms.spcod_ndl = ehs.readUnsignedByte(); if( mrl>32 ){ throw new CorruptedCodestreamException("Number of decomposition "+ "levels out of range: "+ "0--32"); } // Read the code-blocks dimensions cblk = new Integer[2]; ms.spcod_cw = ehs.readUnsignedByte(); cblk[0] = new Integer(1<<(ms.spcod_cw+2)); if ( cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { errMsg = "Non-valid code-block width in SPcod field, "+ "COD marker"; throw new CorruptedCodestreamException(errMsg); } ms.spcod_ch = ehs.readUnsignedByte(); cblk[1] = new Integer(1<<(ms.spcod_ch+2)); if ( cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { errMsg = "Non-valid code-block height in SPcod field, "+ "COD marker"; throw new CorruptedCodestreamException(errMsg); } if ( (cblk[0].intValue()*cblk[1].intValue()) > StdEntropyCoderOptions.MAX_CB_AREA ) { errMsg = "Non-valid code-block area in SPcod field, "+ "COD marker"; throw new CorruptedCodestreamException(errMsg); } if ( mainh ) { decSpec.cblks.setDefault(cblk); } else { decSpec.cblks.setTileDef(tileIdx, cblk); } // Style of the code-block coding passes int ecOptions = ms.spcod_cs = ehs.readUnsignedByte(); if ((ecOptions & ~(OPT_BYPASS|OPT_RESET_MQ|OPT_TERM_PASS| OPT_VERT_STR_CAUSAL|OPT_PRED_TERM | OPT_SEG_SYMBOLS)) != 0){ throw new CorruptedCodestreamException("Unknown \"code-block "+ "style\" in SPcod field, "+ "COD marker: 0x"+ Integer. toHexString(ecOptions)); } // Read wavelet filter for tile or image hfilters = new SynWTFilter[1]; vfilters = new SynWTFilter[1]; hfilters[0] = readFilter(ehs,ms.spcod_t); vfilters[0] = hfilters[0]; // Fill the filter spec // If this is the main header, set the default value, if it is the // tile header, set default for this tile SynWTFilter[][] hvfilters = new SynWTFilter[2][]; hvfilters[0]=hfilters; hvfilters[1]=vfilters; // Get precinct partition sizes Vector v[] = new Vector[2]; v[0] = new Vector(); v[1] = new Vector(); int val = PRECINCT_PARTITION_DEF_SIZE; if ( !precinctPartitionIsUsed ) { Integer w, h; w = new Integer(1<<(val & 0x000F)); v[0].addElement(w); h = new Integer(1<<(((val & 0x00F0)>>4))); v[1].addElement(h); } else { ms.spcod_ps = new int[mrl+1]; for (int rl=mrl ;rl>=0 ;rl--) { Integer w, h; val = ms.spcod_ps[mrl-rl] = ehs.readUnsignedByte(); w = new Integer(1<<(val & 0x000F)); v[0].insertElementAt(w,0); h = new Integer(1<<(((val & 0x00F0)>>4))); v[1].insertElementAt(h,0); } } if (mainh) { decSpec.pss.setDefault(v); } else { decSpec.pss.setTileDef(tileIdx, v); } precinctPartitionIsUsed = true; // Check marker length checkMarkerLength(ehs,"COD marker"); // Store specifications in decSpec if(mainh){ decSpec.wfs.setDefault(hvfilters); decSpec.dls.setDefault(new Integer(mrl)); decSpec.ecopts.setDefault(new Integer(ecOptions)); decSpec.cts.setDefault(new Integer(ms.sgcod_mct)); decSpec.nls.setDefault(new Integer(ms.sgcod_nl)); decSpec.pos.setDefault(new Integer(ms.sgcod_po)); } else{ decSpec.wfs.setTileDef(tileIdx, hvfilters); decSpec.dls.setTileDef(tileIdx,new Integer(mrl)); decSpec.ecopts.setTileDef(tileIdx,new Integer(ecOptions)); decSpec.cts.setTileDef(tileIdx,new Integer(ms.sgcod_mct)); decSpec.nls.setTileDef(tileIdx,new Integer(ms.sgcod_nl)); decSpec.pos.setTileDef(tileIdx,new Integer(ms.sgcod_po)); } } /** * Reads the COC marker segment and realigns the codestream where the next * marker should be found. * * @param ehs The encoder header stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param tileIdx The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readCOC (DataInputStream ehs, boolean mainh, int tileIdx, int tpIdx) throws IOException { int cComp; // current component SynWTFilter hfilters[],vfilters[]; int tmp,l; int ecOptions; Integer cblk[]; String errMsg; HeaderInfo.COC ms = hi.getNewCOC(); // Lcoc (marker length) ms.lcoc = ehs.readUnsignedShort(); // Ccoc if (nComp < 257) { cComp = ms.ccoc = ehs.readUnsignedByte(); } else { cComp = ms.ccoc = ehs.readUnsignedShort(); } if (cComp >= nComp) { throw new CorruptedCodestreamException("Invalid component index "+ "in QCC marker"); } // Scoc (block style) int cstyle = ms.scoc = ehs.readUnsignedByte(); if( (cstyle&SCOX_PRECINCT_PARTITION) != 0 ){ precinctPartitionIsUsed = true; // Remove flag cstyle &= ~(SCOX_PRECINCT_PARTITION); } else { precinctPartitionIsUsed = false; } // SPcoc // decomposition levels int mrl = ms.spcoc_ndl = ehs.readUnsignedByte(); // Read the code-blocks dimensions cblk = new Integer[2]; ms.spcoc_cw = ehs.readUnsignedByte(); cblk[0] = new Integer(1<<(ms.spcoc_cw+2)); if ( cblk[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || cblk[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { errMsg = "Non-valid code-block width in SPcod field, "+ "COC marker"; throw new CorruptedCodestreamException(errMsg); } ms.spcoc_ch = ehs.readUnsignedByte(); cblk[1] = new Integer(1<<(ms.spcoc_ch+2)); if ( cblk[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM || cblk[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM ) { errMsg = "Non-valid code-block height in SPcod field, "+ "COC marker"; throw new CorruptedCodestreamException(errMsg); } if ( (cblk[0].intValue()*cblk[1].intValue()) > StdEntropyCoderOptions.MAX_CB_AREA ) { errMsg = "Non-valid code-block area in SPcod field, "+ "COC marker"; throw new CorruptedCodestreamException(errMsg); } if ( mainh ) { decSpec.cblks.setCompDef(cComp,cblk); } else { decSpec.cblks.setTileCompVal(tileIdx,cComp,cblk); } // Read entropy block mode options // NOTE: currently OPT_SEG_SYMBOLS is not included here ecOptions = ms.spcoc_cs = ehs.readUnsignedByte(); if ((ecOptions & ~(OPT_BYPASS|OPT_RESET_MQ|OPT_TERM_PASS| OPT_VERT_STR_CAUSAL|OPT_PRED_TERM|OPT_SEG_SYMBOLS)) != 0){ throw new CorruptedCodestreamException("Unknown \"code-block "+ "context\" in SPcoc field, "+ "COC marker: 0x"+ Integer. toHexString(ecOptions)); } // Read wavelet filter for tile or image hfilters = new SynWTFilter[1]; vfilters = new SynWTFilter[1]; hfilters[0] = readFilter(ehs,ms.spcoc_t); vfilters[0] = hfilters[0]; // Fill the filter spec // If this is the main header, set the default value, if it is the // tile header, set default for this tile SynWTFilter[][] hvfilters = new SynWTFilter[2][]; hvfilters[0]=hfilters; hvfilters[1]=vfilters; // Get precinct partition sizes Vector v[] = new Vector[2]; v[0] = new Vector(); v[1] = new Vector(); int val = PRECINCT_PARTITION_DEF_SIZE; if ( !precinctPartitionIsUsed ) { Integer w, h; w = new Integer(1<<(val & 0x000F)); v[0].addElement(w); h = new Integer(1<<(((val & 0x00F0)>>4))); v[1].addElement(h); } else { ms.spcoc_ps = new int[mrl+1]; for ( int rl=mrl ; rl>=0 ; rl-- ) { Integer w, h; val = ms.spcoc_ps[rl] = ehs.readUnsignedByte(); w = new Integer(1<<(val & 0x000F)); v[0].insertElementAt(w,0); h = new Integer(1<<(((val & 0x00F0)>>4))); v[1].insertElementAt(h,0); } } if (mainh) { decSpec.pss.setCompDef(cComp,v); } else { decSpec.pss.setTileCompVal(tileIdx,cComp,v); } precinctPartitionIsUsed = true; // Check marker length checkMarkerLength(ehs,"COD marker"); if(mainh){ hi.coc.put("main_c"+cComp,ms); decSpec.wfs.setCompDef(cComp,hvfilters); decSpec.dls.setCompDef(cComp,new Integer(mrl)); decSpec.ecopts.setCompDef(cComp,new Integer(ecOptions)); } else { hi.coc.put("t"+tileIdx+"_c"+cComp,ms); decSpec.wfs.setTileCompVal(tileIdx,cComp,hvfilters); decSpec.dls.setTileCompVal(tileIdx,cComp,new Integer(mrl)); decSpec.ecopts.setTileCompVal(tileIdx,cComp, new Integer(ecOptions)); } } /** * Reads the POC marker segment and realigns the codestream where the next * marker should be found. * * @param ehs The encoder header stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param t The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readPOC(DataInputStream ehs,boolean mainh,int t,int tpIdx) throws IOException { boolean useShort = (nComp>=256) ? true : false; int tmp; int nOldChg = 0; HeaderInfo.POC ms; if(mainh || hi.poc.get("t"+t)==null) { ms = hi.getNewPOC(); } else { ms = (HeaderInfo.POC)hi.poc.get("t"+t); nOldChg = ms.rspoc.length; } // Lpoc ms.lpoc = ehs.readUnsignedShort(); // Compute the number of new progression changes // newChg = (lpoc - Lpoc(2)) / (RSpoc(1) + CSpoc(2) + // LYEpoc(2) + REpoc(1) + CEpoc(2) + Ppoc (1) ) int newChg = (ms.lpoc-2)/(5+ (useShort?4:2)); int ntotChg = nOldChg+newChg; int[][] change; if(nOldChg!=0) { // Creates new arrays change = new int[ntotChg][6]; int[] tmprspoc = new int[ntotChg]; int[] tmpcspoc = new int[ntotChg]; int[] tmplyepoc = new int[ntotChg]; int[] tmprepoc = new int[ntotChg]; int[] tmpcepoc = new int[ntotChg]; int[] tmpppoc = new int[ntotChg]; // Copy old values int[][] prevChg = (int[][])decSpec.pcs.getTileDef(t); for(int chg=0; chgMay be used in tile or main header. If used in main header, it * refers to the maxshift value of a component in all tiles. When used in * tile header, only the particular tile-component is affected.

* * @param ehs The encoder header stream. * * @param mainh Flag indicating whether or not this marker segment is read * from the main header. * * @param tileIdx The index of the current tile * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readRGN(DataInputStream ehs, boolean mainh, int tileIdx, int tpIdx) throws IOException { int comp; // ROI component int i; // loop variable int tempComp; // Component for HeaderInfo.RGN ms = hi.getNewRGN(); // Lrgn (marker length) ms.lrgn = ehs.readUnsignedShort(); // Read component ms.crgn = comp = (nComp < 257) ? ehs.readUnsignedByte(): ehs.readUnsignedShort(); if (comp >= nComp) { throw new CorruptedCodestreamException("Invalid component "+ "index in RGN marker"+ comp); } // Read type of RGN.(Srgn) ms.srgn = ehs.readUnsignedByte(); // Check that we can handle it. if(ms.srgn != SRGN_IMPLICIT) throw new CorruptedCodestreamException("Unknown or unsupported "+ "Srgn parameter in ROI "+ "marker"); if(decSpec.rois==null) { // No maxshift spec defined // Create needed ModuleSpec decSpec.rois=new MaxShiftSpec(nTiles,nComp, ModuleSpec.SPEC_TYPE_TILE_COMP, "null"); } // SPrgn ms.sprgn = ehs.readUnsignedByte(); if(mainh) { hi.rgn.put("main_c"+comp,ms); decSpec.rois.setCompDef(comp, new Integer(ms.sprgn)); } else { hi.rgn.put("t"+tileIdx+"_c"+comp,ms); decSpec.rois.setTileCompVal(tileIdx,comp,new Integer(ms.sprgn)); } // Check marker length checkMarkerLength(ehs,"RGN marker"); } /** * Reads the PPM marker segment of the main header. * * @param ehs The encoder header stream. * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readPPM(DataInputStream ehs) throws IOException { int curMarkSegLen; int i,indx,len,off; int remSegLen; byte[] b; // If first time readPPM method is called allocate arrays for packed // packet data if(pPMMarkerData==null) { pPMMarkerData = new byte[nPPMMarkSeg][]; tileOfTileParts = new Vector(); decSpec.pphs.setDefault(new Boolean(true)); } // Lppm (marker length) curMarkSegLen = ehs.readUnsignedShort(); remSegLen = curMarkSegLen - 3; // Zppm (index of PPM marker) indx = ehs.readUnsignedByte(); // Read Nppm and Ippm data pPMMarkerData[indx] = new byte[remSegLen]; ehs.read(pPMMarkerData[indx],0,remSegLen); // Check marker length checkMarkerLength(ehs,"PPM marker"); } /** * Teads the PPT marker segment of the main header. * * @param ehs The encoder header stream. * * @param tile The tile to which the current tile part belongs * * @param tpIdx Tile-part index * * @exception IOException If an I/O error occurs while reading from the * encoder header stream * */ private void readPPT(DataInputStream ehs,int tile,int tpIdx) throws IOException { int curMarkSegLen; int indx,len=0; byte[] temp; if(tilePartPkdPktHeaders == null){ tilePartPkdPktHeaders = new byte[nTiles][][][]; } if(tilePartPkdPktHeaders[tile] == null){ tilePartPkdPktHeaders[tile] = new byte[nTileParts[tile]][][]; } if(tilePartPkdPktHeaders[tile][tpIdx] == null){ tilePartPkdPktHeaders[tile][tpIdx] = new byte[nPPTMarkSeg[tile][tpIdx]][]; } // Lppt (marker length) curMarkSegLen = ehs.readUnsignedShort(); // Zppt (index of PPT marker) indx = ehs.readUnsignedByte(); // Ippt (packed packet headers) temp = new byte[curMarkSegLen-3]; ehs.read(temp); tilePartPkdPktHeaders[tile][tpIdx][indx]=temp; // Check marker length checkMarkerLength(ehs,"PPT marker"); decSpec.pphs.setTileDef(tile, new Boolean(true)); } /** * This method extract a marker segment from the main header and stores it * into a byte buffer for the second pass. The marker segment is first * identified. Then its flag is activated. Finally, its content is * buffered into a byte array stored in an hashTable. * *

If the marker is not recognized, it prints a warning and skips it * according to its length.

* *

SIZ marker segment shall be the first encountered marker segment.

* * @param marker The marker segment to process * * @param ehs The encoded header stream * */ private void extractMainMarkSeg(short marker,RandomAccessIO ehs) throws IOException { if(nfMarkSeg == 0) { // First non-delimiting marker of the header // JPEG 2000 part 1 specify that it must be SIZ if(marker != SIZ) { throw new CorruptedCodestreamException("First marker after "+ "SOC "+ "must be SIZ "+ Integer. toHexString(marker)); } } String htKey=""; // Name used as a key for the hash-table if(ht==null) { ht = new Hashtable(); } switch(marker){ case SIZ: if ((nfMarkSeg & SIZ_FOUND) != 0) { throw new CorruptedCodestreamException("More than one SIZ marker "+ "segment found in main "+ "header"); } nfMarkSeg |= SIZ_FOUND; htKey = "SIZ"; break; case SOD: throw new CorruptedCodestreamException("SOD found in main header"); case EOC: throw new CorruptedCodestreamException("EOC found in main header"); case SOT: if ((nfMarkSeg & SOT_FOUND) != 0) { throw new CorruptedCodestreamException("More than one SOT "+ "marker "+ "found right after "+ "main "+ "or tile header"); } nfMarkSeg |= SOT_FOUND; return; case COD: if((nfMarkSeg & COD_FOUND) != 0) { throw new CorruptedCodestreamException("More than one COD "+ "marker "+ "found in main header"); } nfMarkSeg |= COD_FOUND; htKey = "COD"; break; case COC: nfMarkSeg |= COC_FOUND; htKey = "COC"+(nCOCMarkSeg++); break; case QCD: if((nfMarkSeg & QCD_FOUND) != 0) { throw new CorruptedCodestreamException("More than one QCD "+ "marker "+ "found in main header"); } nfMarkSeg |= QCD_FOUND; htKey = "QCD"; break; case QCC: nfMarkSeg |= QCC_FOUND; htKey = "QCC"+(nQCCMarkSeg++); break; case RGN: nfMarkSeg |= RGN_FOUND; htKey = "RGN"+(nRGNMarkSeg++); break; case COM: nfMarkSeg |= COM_FOUND; htKey = "COM"+(nCOMMarkSeg++); break; case CRG: if((nfMarkSeg & CRG_FOUND) != 0) { throw new CorruptedCodestreamException("More than one CRG "+ "marker "+ "found in main header"); } nfMarkSeg |= CRG_FOUND; htKey = "CRG"; break; case PPM: nfMarkSeg |= PPM_FOUND; htKey = "PPM"+(nPPMMarkSeg++); break; case TLM: if((nfMarkSeg & TLM_FOUND) != 0) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO, "More than one TLM "+ "marker "+ "found in main header"); /** XXX It is legal to have multiple TLM segments. throw new CorruptedCodestreamException("More than one TLM "+ "marker "+ "found in main header"); */ } nfMarkSeg |= TLM_FOUND; break; case PLM: if((nfMarkSeg & PLM_FOUND) != 0) { throw new CorruptedCodestreamException("More than one PLM "+ "marker "+ "found in main header"); } FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"PLM marker segment found but "+ "not used by by JJ2000 decoder."); nfMarkSeg |= PLM_FOUND; htKey = "PLM"; break; case POC: if( (nfMarkSeg&POC_FOUND)!=0) { throw new CorruptedCodestreamException("More than one POC "+ "marker segment found "+ "in main header"); } nfMarkSeg |= POC_FOUND; htKey = "POC"; break; case PLT: throw new CorruptedCodestreamException("PLT found in main header"); case PPT: throw new CorruptedCodestreamException("PPT found in main header"); default: htKey = "UNKNOWN"; FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"Non recognized marker segment (0x"+ Integer.toHexString(marker)+") in main header!"); break; } if(marker < 0xffffff30 || marker > 0xffffff3f){ // Read marker segment length and create corresponding byte buffer int markSegLen = ehs.readUnsignedShort(); byte[] buf = new byte[markSegLen]; // Copy data (after re-insertion of the marker segment length); buf[0]= (byte)((markSegLen>>8) & 0xFF); buf[1]= (byte)(markSegLen & 0xFF); ehs.readFully(buf,2,markSegLen-2); if(!htKey.equals("UNKNOWN")) { // Store array in hashTable ht.put(htKey,buf); } } } /** * This method extracts a marker segment in a tile-part header and stores * it into a byte buffer for the second pass. The marker is first * recognized, then its flag is activated and, finally, its content is * buffered in an element of byte arrays accessible thanks to a hashTable. * If a marker segment is not recognized, it prints a warning and skip it * according to its length. * * @param marker The marker to process * * @param ehs The encoded header stream * * @param tileIdx The index of the current tile * * @param tilePartIdx The index of the current tile part * */ public void extractTilePartMarkSeg(short marker, RandomAccessIO ehs, int tileIdx, int tilePartIdx) throws IOException { String htKey=""; // Name used as a hash-table key if(ht==null) { ht = new Hashtable(); } switch(marker) { case SOT: throw new CorruptedCodestreamException("Second SOT marker "+ "segment found in tile-"+ "part header"); case SIZ: throw new CorruptedCodestreamException("SIZ found in tile-part"+ " header"); case EOC: throw new CorruptedCodestreamException("EOC found in tile-part"+ " header"); case TLM: throw new CorruptedCodestreamException("TLM found in tile-part"+ " header"); case PPM: throw new CorruptedCodestreamException("PPM found in tile-part"+ " header"); case COD: if((nfMarkSeg & COD_FOUND) != 0) { throw new CorruptedCodestreamException("More than one COD "+ "marker "+ "found in tile-part"+ " header"); } nfMarkSeg |= COD_FOUND; htKey = "COD"; break; case COC: nfMarkSeg |= COC_FOUND; htKey = "COC"+(nCOCMarkSeg++); break; case QCD: if((nfMarkSeg & QCD_FOUND) != 0) { throw new CorruptedCodestreamException("More than one QCD "+ "marker "+ "found in tile-part"+ " header"); } nfMarkSeg |= QCD_FOUND; htKey = "QCD"; break; case QCC: nfMarkSeg |= QCC_FOUND; htKey = "QCC"+(nQCCMarkSeg++); break; case RGN: nfMarkSeg |= RGN_FOUND; htKey = "RGN"+(nRGNMarkSeg++); break; case COM: nfMarkSeg |= COM_FOUND; htKey = "COM"+(nCOMMarkSeg++); break; case CRG: throw new CorruptedCodestreamException("CRG marker found in "+ "tile-part header"); case PPT: nfMarkSeg |= PPT_FOUND; if(nPPTMarkSeg == null){ nPPTMarkSeg = new int[nTiles][]; } if(nPPTMarkSeg[tileIdx] == null){ nPPTMarkSeg[tileIdx] = new int[nTileParts[tileIdx]]; } htKey = "PPT"+(nPPTMarkSeg[tileIdx][tilePartIdx]++); break; case SOD: nfMarkSeg |= SOD_FOUND; return; case POC: if( (nfMarkSeg&POC_FOUND) != 0) throw new CorruptedCodestreamException("More than one POC "+ "marker segment found "+ "in tile-part"+ " header"); nfMarkSeg |= POC_FOUND; htKey = "POC"; break; case PLT: if((nfMarkSeg & PLM_FOUND) != 0) { throw new CorruptedCodestreamException("PLT marker found even"+ "though PLM marker "+ "found in main header"); } FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"PLT marker segment found but "+ "not used by JJ2000 decoder."); htKey = "UNKNOWN"; break; default: htKey = "UNKNOWN"; FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"Non recognized marker segment (0x"+ Integer.toHexString(marker)+") in tile-part header"+ " of tile "+tileIdx+" !"); break; } // Read marker segment length and create corresponding byte buffer int markSegLen = ehs.readUnsignedShort(); byte[] buf = new byte[markSegLen]; // Copy data (after re-insertion of marker segment length); buf[0]= (byte)((markSegLen>>8) & 0xFF); buf[1]= (byte)(markSegLen & 0xFF); ehs.readFully(buf,2,markSegLen-2); if(!htKey.equals("UNKNOWN")) { // Store array in hashTable ht.put(htKey,buf); } } /** * Retrieves and reads all marker segments found in the main header during * the first pass. * */ private void readFoundMainMarkSeg() throws IOException { DataInputStream dis; ByteArrayInputStream bais; // SIZ marker segment if((nfMarkSeg&SIZ_FOUND) != 0) { bais = new ByteArrayInputStream( (byte[])(ht.get("SIZ"))); readSIZ(new DataInputStream(bais)); } // COM marker segments if((nfMarkSeg&COM_FOUND) != 0) { for(int i=0; i=0; i--) { pkdPktHeaders[i] = new ByteArrayOutputStream(); } if(nPPMMarkSeg!=0) { // If this is first time packed packet headers are requested, // create packed packet headers from Nppm and Ippm fields int nppm; int nTileParts = tileOfTileParts.size(); byte[] temp; ByteArrayInputStream pph; ByteArrayOutputStream allNppmIppm = new ByteArrayOutputStream(); // Concatenate all Nppm and Ippm fields for(i=0 ; i=0; t--) { for(tp=0; tp




© 2015 - 2024 Weber Informatics LLC | Privacy Policy