/*
* $RCSfile: FileBitstreamReaderAgent.java,v $
* $Revision: 1.4 $
* $Date: 2006/10/05 01:10:31 $
* $State: Exp $
*
* Class: FileBitstreamReaderAgent
*
* Description: Retrieve code-blocks codewords in the bit stream
*
*
*
* 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 jj2000.j2k.quantization.dequantizer.*;
import jj2000.j2k.wavelet.synthesis.*;
import jj2000.j2k.entropy.decoder.*;
import jj2000.j2k.codestream.*;
import jj2000.j2k.decoder.*;
import jj2000.j2k.entropy.*;
import jj2000.j2k.image.*;
import jj2000.j2k.util.*;
import jj2000.j2k.io.*;
import jj2000.j2k.*;
import java.util.*;
import java.io.*;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReadParamJava;
/**
* This class reads the bit stream (with the help of HeaderDecoder for tile
* headers and PktDecoder for packets header and body) and retrives location
* of all code-block's codewords.
*
* <P>Note: All tile-parts headers are read by the constructor whereas packets
* are processed when decoding related tile (when setTile method is called).
*
* <P>In parsing mode, the reader simulates a virtual layer-resolution
* progressive bit stream with the same truncation points in each code-block,
* whereas in truncation mode, only the first bytes are taken into account (it
* behaves like if it is a real truncated codestream).
*
* @see HeaderDecoder
* @see PktDecoder
* */
public class FileBitstreamReaderAgent extends BitstreamReaderAgent
implements Markers, ProgressionType, StdEntropyCoderOptions{
/** Whether or not the last read Psot value was zero. Only the Psot in the
* last tile-part in the codestream can have such a value. */
private boolean isPsotEqualsZero = true;
/** Reference to the PktDecoder instance */
public PktDecoder pktDec;
/** Reference to the J2KImageReadParamJava instance */
private J2KImageReadParamJava j2krparam;
/** The RandomAccessIO where to get data from */
private RandomAccessIO in;
/** The number of tiles in the image */
private int nt;
/** Offset of the first packet in each tile-part in each tile */
private int[][] firstPackOff;
/**
* Returns the number of tile-part found for a given tile
*
* @param t Tile index
*
* */
public int getNumTileParts(int t) {
if(firstPackOff==null || firstPackOff[t]==null) {
throw new Error("Tile "+t+" not found in input codestream.");
}
return firstPackOff[t].length;
}
/** Number of bytes allocated to each tile. In parsing mode, this number
* is related to the tile length in the codestream whereas in truncation
* mode all the rate is affected to the first tiles. */
private int[] nBytes;
/** Whether or not to print information found in codestream */
private boolean printInfo = false;
/**
* Backup of the number of bytes allocated to each tile. This array is
* used to restore the number of bytes to read in each tile when the
* codestream is read several times (for instance when decoding an R,G,B
* image to three output files)
* */
private int[] baknBytes;
/** Length of each tile-part (written in Psot) */
private int[][] tilePartLen;
/** Total length of each tile */
private int[] totTileLen;
/** Total length of tiles' header */
private int[] totTileHeadLen;
/** First tile part header length*/
private int firstTilePartHeadLen;
/** Total length of all tile parts in all tiles */
private double totAllTileLen;
/** Length of main header */
private int mainHeadLen;
/** Length of main and tile-parts headers */
private int headLen = 0;
/** Length of all tile-part headers */
private int[][] tilePartHeadLen;
/** Length of each packet head found in the tile */
private Vector pktHL;
/** True if truncation mode is used. False if parsing mode */
private boolean isTruncMode;
/** The number of tile-parts that remain to read */
private int remainingTileParts;
/** The number of tile-parts read so far for each tile */
private int[] tilePartsRead;
/** Thetotal number of tile-parts read so far */
private int totTilePartsRead=0;
/** The number of tile-parts in each tile */
private int[] tileParts;
/** The total number of tile-parts in each tile */
private int[] totTileParts;
/** The current tile part being used */
private int curTilePart;
/** The number of the tile-part in the codestream */
private int[][] tilePartNum;
/** Whether or not a EOC marker has been found instead of a SOT */
private boolean isEOCFound = false;
/** Reference to the HeaderInfo instance (used when reading SOT marker
* segments) */
private HeaderInfo hi;
/** Array containing info. for all the code-blocks:<br>
* - 1st dim: component index.<br>
* - 2nd dim: resolution level index.<br>
* - 3rd dim: subband index.<br>
* - 4th/5th dim: code-block index (vert. and horiz.).<br>
*/
private CBlkInfo[][][][][] cbI;
/** Gets the reference to the CBlkInfo array */
public CBlkInfo[][][][][] getCBlkInfo() {
return cbI;
}
/** The maximum number of layers to decode for any code-block */
private int lQuit;
/** Whether or not to use only first progression order */
private boolean usePOCQuit = false;
/**
* Reads all tiles headers and keep offset of their first
* packet. Finally it calls the rate allocation method.
*
* @param hd HeaderDecoder of the codestream.
*
* @param ehs The input stream where to read bit-stream.
*
* @param decSpec The decoder specifications
*
* @param j2krparam The J2KImageReadParam instance created from the
* command-line arguments.
*
* @param cdstrInfo Whether or not to print information found in
* codestream.
*
* @see #allocateRate
* */
public FileBitstreamReaderAgent(HeaderDecoder hd,RandomAccessIO ehs,
DecoderSpecs decSpec,
J2KImageReadParamJava j2krparam,
boolean cdstrInfo,HeaderInfo hi)
throws IOException {
super(hd,decSpec);
this.j2krparam = j2krparam;
this.printInfo = cdstrInfo;
this.hi = hi;
String strInfo = printInfo ?
"Codestream elements information in bytes "+
"(offset, total length, header length):\n\n" : null;
// Check whether quit conditiosn used
//usePOCQuit = j2krparam.getPOCQuit();
// Get decoding rate
if (j2krparam.getDecodingRate() == Double.MAX_VALUE)
tnbytes = Integer.MAX_VALUE;
else
tnbytes = (int)(j2krparam.getDecodingRate() * hd.getMaxCompImgWidth() *
hd.getMaxCompImgHeight()) / 8;
//isTruncMode = !j2krparam.getParsing();
isTruncMode = true;
// Check if quit conditions are being used
//int ncbQuit = j2krparam.getNCBQuit();
int ncbQuit = -1;
if(ncbQuit != -1 && !isTruncMode){
throw new Error("Cannot use -parsing and -ncb_quit condition at "+
"the same time.");
}
// lQuit = j2krparam.getLQuit();
lQuit = -1;
// initializations
nt = ntX * ntY;
in = ehs;
pktDec = new PktDecoder(decSpec,hd,ehs,this,isTruncMode, ncbQuit);
tileParts = new int[nt];
totTileParts = new int[nt];
totTileLen = new int[nt];
tilePartLen = new int[nt][];
tilePartNum = new int[nt][];
firstPackOff = new int[nt][];
tilePartsRead = new int[nt];
totTileHeadLen = new int[nt];
tilePartHeadLen = new int[nt][];
nBytes = new int[nt];
baknBytes = new int[nt];
hd.nTileParts = new int[nt];
this.isTruncMode = isTruncMode;
// Keeps main header's length, takes file format overhead into account
cdstreamStart = hd.mainHeadOff; // Codestream offset in the file
mainHeadLen = in.getPos() - cdstreamStart;
headLen = mainHeadLen;
// If ncb and lbody quit conditions are used, headers are not counted
if(ncbQuit == -1) {
anbytes = mainHeadLen;
} else {
anbytes = 0;
}
if(printInfo)
strInfo += "Main header length : "+cdstreamStart+", "+mainHeadLen+
", "+mainHeadLen+"\n";
// If cannot even read the first tile-part
if(anbytes>tnbytes) {
throw new Error("Requested bitrate is too small.");
}
// Initialize variables used when reading tile-part headers.
totAllTileLen = 0;
remainingTileParts = nt; // at least as many tile-parts as tiles
maxPos = lastPos = in.getPos();
// Update 'res' value according to the parameter and the main header.
if(j2krparam.getResolution()== -1) {
targetRes = decSpec.dls.getMin();
} else {
targetRes = j2krparam.getResolution();
if(targetRes<0) {
throw new
IllegalArgumentException("Specified negative "+
"resolution level index: "+
targetRes);
}
}
// Verify reduction in resolution level
int mdl = decSpec.dls.getMin();
if(targetRes>mdl) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.WARNING,
"Specified resolution level ("+targetRes+
") is larger"+
" than the maximum possible. Setting it to "+
mdl +" (maximum possible)");
targetRes = mdl;
}
// Initialize tile part positions from TLM marker segment.
initTLM();
}
// An array of the positions of tile parts:
// - length of tilePartPositions is nt.
// - length of tilePartPositions[i] is totTileParts[i].
long[][] tilePartPositions = null;
//
// Initialize the tilePartPositions positions array if a TLM marker
// segment is present in the main header. If no such marker segment
// is present the array will remain null. This method rewinds to the
// start of the codestream and scans until the first SOT marker is
// encountered. Before return the stream is returned to its position
// when the method was invoked.
//
private void initTLM() throws IOException {
// Save the position to return to at the end of this method.
int savePos = in.getPos();
// Array to store contents of TLM segments. The first index is
// Ztlm. The contents of tlmSegments[i] is the bytes in the TLM
// segment with Ztlm == i after the Ztlm byte.
byte[][] tlmSegments = null;
// Number of TLM segments. The first numTLM elements of tlmSegments
// should be non-null if the segments are correct.
int numTLM = 0;
try {
// Rewind to the start of the main header.
in.seek(cdstreamStart + 2); // skip SOC
// Loop over marker segments.
short marker;
while((marker = in.readShort()) != SOT) {
// Get the length (which includes the 2-byte length parameter).
int markerLength = in.readUnsignedShort();
// Process TLM segments.
if(marker == TLM) {
numTLM++;
if(tlmSegments == null) {
tlmSegments = new byte[256][]; // 0 <= Ztlm <= 255
}
// Save contents after Ztlm in array.
int Ztlm = in.read();
tlmSegments[Ztlm] = new byte[markerLength - 3];
in.readFully(tlmSegments[Ztlm], 0, markerLength - 3);
} else {
in.skipBytes(markerLength - 2);
}
}
} catch(IOException e) {
// Reset so that the TLM segments are not processed further.
tlmSegments = null;
}
if(tlmSegments != null) {
ArrayList[] tlmOffsets = null;
// Tiles start after the main header.
long tilePos = cdstreamStart + mainHeadLen;
// Tile counter for when tile indexes are not included.
int tileCounter = 0;
for(int itlm = 0; itlm < numTLM; itlm++) {
if(tlmSegments[itlm] == null) {
// Null segment among first numTLM entries: error.
tlmOffsets = null;
break;
} else if(tlmOffsets == null) {
tlmOffsets = new ArrayList[nt];
}
// Create a stream.
ByteArrayInputStream bais =
new ByteArrayInputStream(tlmSegments[itlm]);
ImageInputStream iis = new MemoryCacheImageInputStream(bais);
try {
int Stlm = iis.read();
int ST = (Stlm >> 4) & 0x3;
int SP = (Stlm >> 6) & 0x1;
int tlmLength = tlmSegments[itlm].length;
while(iis.getStreamPosition() < tlmLength) {
int tileIndex = tileCounter;
switch(ST) {
case 1:
tileIndex = iis.read();
break;
case 2:
tileIndex = iis.readUnsignedShort();
}
if(tlmOffsets[tileIndex] == null) {
tlmOffsets[tileIndex] = new ArrayList();
}
tlmOffsets[tileIndex].add(new Long(tilePos));
long tileLength = 0L;
switch(SP) {
case 0:
tileLength = iis.readUnsignedShort();
break;
case 1:
tileLength = iis.readUnsignedInt();
break;
}
tilePos += tileLength;
if(ST == 0) tileCounter++;
}
} catch(IOException e) {
// XXX?
}
}
if(tlmOffsets != null) {
tilePartPositions = new long[nt][];
for(int i = 0; i < nt; i++) {
if(tlmOffsets[i] == null) {
tilePartPositions = null;
break;
} else {
ArrayList list = tlmOffsets[i];
int count = list.size();
tilePartPositions[i] = new long[count];
long[] tpPos = tilePartPositions[i];
for(int j = 0; j < count; j++) {
tpPos[j] = ((Long)list.get(j)).longValue();
}
}
}
}
}
in.seek(savePos);
}
int cdstreamStart = 0;
int t=0, pos=-1, tp=0, tptot=0;
int tilePartStart = 0;
boolean rateReached = false;
int numtp = 0;
int maxTP = nt; // If maximum 1 tile part per tile specified
int lastPos = 0, maxPos = 0;
/**
* Read all tile-part headers of the requested tile. All tile-part
* headers prior to the last tile-part header of the current tile will
* also be read.
*
* @param tileNum The index of the tile for which to read tile-part
* headers.
*/
private void initTile(int tileNum) throws IOException {
if(tilePartPositions == null) in.seek(lastPos);
String strInfo = "";
int ncbQuit = -1;
boolean isTilePartRead = false;
boolean isEOFEncountered = false;
try {
int tpNum = 0;
while(remainingTileParts!=0 &&
(totTileParts[tileNum] == 0 ||
tilePartsRead[tileNum] < totTileParts[tileNum])) {
isTilePartRead = true;
if(tilePartPositions != null) {
in.seek((int)tilePartPositions[tileNum][tpNum++]);
}
tilePartStart = in.getPos();
// Read tile-part header
try {
t = readTilePartHeader();
if(isEOCFound) { // Some tiles are missing but the
// codestream is OK
break;
}
tp = tilePartsRead[t];
if(isPsotEqualsZero) { // Psot may equals zero for the
// last tile-part: it is assumed that this tile-part
// contain all data until EOC
tilePartLen[t][tp] = in.length()-2-tilePartStart;
}
} catch(EOFException e) {
firstPackOff[t][tp] = in.length();
throw e;
}
pos = in.getPos();
// In truncation mode, if target decoding rate is reached in
// tile-part header, skips the tile-part and stop reading
// unless the ncb and lbody quit condition is in use
if(isTruncMode && ncbQuit == -1) {
if((pos-cdstreamStart)>tnbytes) {
firstPackOff[t][tp] = in.length();
rateReached = true;
break;
}
}
// Set tile part position and header length
firstPackOff[t][tp] = pos;
tilePartHeadLen[t][tp] = (pos-tilePartStart);
if(printInfo)
strInfo += "Tile-part "+tp+" of tile "+t+" : "+tilePartStart
+", "+tilePartLen[t][tp]+", "+tilePartHeadLen[t][tp]+"\n";
// Update length counters
totTileLen[t] += tilePartLen[t][tp];
totTileHeadLen[t] += tilePartHeadLen[t][tp];
totAllTileLen += tilePartLen[t][tp];
if(isTruncMode) {
if(anbytes+tilePartLen[t][tp]>tnbytes) {
anbytes += tilePartHeadLen[t][tp];
headLen += tilePartHeadLen[t][tp];
rateReached = true;
nBytes[t] += (tnbytes-anbytes);
break;
} else {
anbytes += tilePartHeadLen[t][tp];
headLen += tilePartHeadLen[t][tp];
nBytes[t] += (tilePartLen[t][tp]-
tilePartHeadLen[t][tp]);
}
} else {
if(anbytes+tilePartHeadLen[t][tp]>tnbytes) {
break;
} else {
anbytes += tilePartHeadLen[t][tp];
headLen += tilePartHeadLen[t][tp];
}
}
// If this is first tile-part, remember header length
if(tptot==0)
firstTilePartHeadLen = tilePartHeadLen[t][tp];
// Go to the beginning of next tile part
tilePartsRead[t]++;
int nextMarkerPos = tilePartStart+tilePartLen[t][tp];
if(tilePartPositions == null) {
in.seek(nextMarkerPos);
}
if(nextMarkerPos > maxPos) {
maxPos = nextMarkerPos;
}
remainingTileParts--;
maxTP--;
tptot++;
// If Psot of the current tile-part was equal to zero, it is
// assumed that it contains all data until the EOC marker
if(isPsotEqualsZero) {
if(remainingTileParts!=0) {
FacilityManager.getMsgLogger().printmsg
(MsgLogger.WARNING,"Some tile-parts have not "+
"been found. The codestream may be corrupted.");
}
break;
}
}
} catch(EOFException e) {
isEOFEncountered = true;
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
FacilityManager.getMsgLogger().
printmsg(MsgLogger.WARNING,"Codestream truncated in tile "+t);
// Set specified rate to end of file if valid
int fileLen = in.length();
if(fileLen<tnbytes) {
tnbytes = fileLen;
trate = tnbytes*8f/hd.getMaxCompImgWidth()/
hd.getMaxCompImgHeight();
}
}
// If no tile-parts read then return.
if(!isTilePartRead) return;
/* XXX: BEGIN Updating the resolution here is logical when all tile-part
headers are read as was the case with the original version of this
class. With initTile() however the tiles could be read in random
order so modifying the resolution value could cause unexpected
results if a given tile-part has fewer levels than the main header
indicated.
// Update 'res' value once all tile-part headers are read
if(j2krparam.getResolution()== -1) {
targetRes = decSpec.dls.getMin();
} else {
targetRes = j2krparam.getResolution();
if(targetRes<0) {
throw new
IllegalArgumentException("Specified negative "+
"resolution level index: "+
targetRes);
}
}
// Verify reduction in resolution level
int mdl = decSpec.dls.getMin();
if(targetRes>mdl) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.WARNING,
"Specified resolution level ("+targetRes+
") is larger"+
" than the maximum possible. Setting it to "+
mdl +" (maximum possible)");
targetRes = mdl;
}
XXX: END */
if(!isEOFEncountered) {
if(printInfo) {
FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
}
if(remainingTileParts == 0) {
// Check presence of EOC marker is decoding rate not reached or
// if this marker has not been found yet
if(!isEOCFound && !isPsotEqualsZero && !rateReached) {
try {
int savePos = in.getPos();
in.seek(maxPos);
if(in.readShort()!=EOC) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.WARNING,"EOC marker not found. "+
"Codestream is corrupted.");
}
in.seek(savePos);
} catch(EOFException e) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.WARNING,"EOC marker is missing");
}
}
}
}
// Bit-rate allocation
if(!isTruncMode) {
allocateRate();
} else if(remainingTileParts == 0 && !isEOFEncountered) {
// Take EOC into account if rate is not reached
if(in.getPos()>=tnbytes)
anbytes += 2;
}
if(tilePartPositions == null) lastPos = in.getPos();
// Backup nBytes
for (int tIdx=0; tIdx<nt; tIdx++) {
baknBytes[tIdx] = nBytes[tIdx];
if(printInfo) {
FacilityManager.getMsgLogger().
println(""+hi.toStringTileHeader(tIdx,tilePartLen[tIdx].
length),2,2);
}
}
}
/**
* Allocates output bit-rate for each tile in parsing mode: The allocator
* simulates the truncation of a virtual layer-resolution progressive
* codestream.
* */
private void allocateRate() throws IOException {
int stopOff = tnbytes;
// In parsing mode, the bitrate is allocated related to each tile's
// length in the bit stream
// EOC marker's length
if(remainingTileParts == 0) anbytes += 2;
// If there are too few bytes to read the tile part headers throw an
// error
if(anbytes > stopOff){
throw new Error("Requested bitrate is too small for parsing");
}
// Calculate bitrate for each tile
int rem = stopOff-anbytes;
int totnByte = rem;
for(int t=nt-1; t>0; t--){
rem -= nBytes[t]=(int)(totnByte*(totTileLen[t]/totAllTileLen));
}
nBytes[0] = rem;
}
/**
* Reads SOT marker segment of the tile-part header and calls related
* methods of the HeaderDecoder to read other markers segments. The
* tile-part header is entirely read when a SOD marker is encountered.
*
* @return The tile number of the tile part that was read
* */
private int readTilePartHeader() throws IOException{
HeaderInfo.SOT ms = hi.getNewSOT();
// SOT marker
short marker = in.readShort();
if(marker!=SOT) {
if(marker==EOC) {
isEOCFound = true;
return -1;
} else {
throw new CorruptedCodestreamException("SOT tag not found "+
"in tile-part start");
}
}
isEOCFound = false;
// Lsot (shall equals 10)
int lsot = in.readUnsignedShort();
ms.lsot = lsot;
if(lsot!=10)
throw new CorruptedCodestreamException("Wrong length for "+
"SOT marker segment: "+
lsot);
// Isot
int tile = in.readUnsignedShort();
ms.isot = tile;
if(tile>65534){
throw new CorruptedCodestreamException("Tile index too high in "+
"tile-part.");
}
// Psot
int psot = in.readInt();
ms.psot = psot;
isPsotEqualsZero = (psot!=0) ? false : true;
if(psot<0) {
throw new NotImplementedError("Tile length larger "+
"than maximum supported");
}
// TPsot
int tilePart = in.read();
ms.tpsot = tilePart;
if( tilePart!=tilePartsRead[tile] || tilePart<0 || tilePart>254 ) {
throw new CorruptedCodestreamException("Out of order tile-part");
}
// TNsot
int nrOfTileParts = in.read();
ms.tnsot = nrOfTileParts;
hi.sot.put("t"+tile+"_tp"+tilePart,ms);
if(nrOfTileParts==0) { // The number of tile-part is not specified in
// this tile-part header.
// Assumes that there will be another tile-part in the codestream
// that will indicate the number of tile-parts for this tile)
int nExtraTp;
if(tileParts[tile]==0 || tileParts[tile]==tilePartLen.length ) {
// Then there are two tile-parts (one is the current and the
// other will indicate the number of tile-part for this tile)
nExtraTp = 2;
remainingTileParts += 1;
} else {
// There is already one scheduled extra tile-part. In this
// case just add place for the current one
nExtraTp = 1;
}
tileParts[tile] += nExtraTp;
nrOfTileParts = tileParts[tile];
FacilityManager.getMsgLogger().
printmsg(MsgLogger.WARNING,"Header of tile-part "+tilePart+
" of tile "+tile+", does not indicate the total"+
" number of tile-parts. Assuming that there are "+
nrOfTileParts+" tile-parts for this tile.");
// Increase and re-copy tilePartLen array
int[] tmpA = tilePartLen[tile];
tilePartLen[tile] = new int[nrOfTileParts];
for(int i=0; i<nrOfTileParts-nExtraTp; i++) {
tilePartLen[tile][i] = tmpA[i];
}
// Increase and re-copy tilePartNum array
tmpA = tilePartNum[tile];
tilePartNum[tile] = new int[nrOfTileParts];
for(int i=0; i<nrOfTileParts-nExtraTp; i++) {
tilePartNum[tile][i] = tmpA[i];
}
// Increase and re-copy firsPackOff array
tmpA = firstPackOff[tile];
firstPackOff[tile] = new int[nrOfTileParts];
for(int i=0; i<nrOfTileParts-nExtraTp; i++) {
firstPackOff[tile][i] = tmpA[i];
}
// Increase and re-copy tilePartHeadLen array
tmpA = tilePartHeadLen[tile];
tilePartHeadLen[tile] = new int[nrOfTileParts];
for(int i=0; i<nrOfTileParts-nExtraTp; i++) {
tilePartHeadLen[tile][i] = tmpA[i];
}
} else { // The number of tile-parts is specified in the tile-part
// header
totTileParts[tile] = nrOfTileParts;
// Check if it is consistant with what was found in previous
// tile-part headers
if(tileParts[tile]==0) { // First tile-part: OK
remainingTileParts += nrOfTileParts- 1;
tileParts[tile] = nrOfTileParts;
tilePartLen[tile] = new int[nrOfTileParts];
tilePartNum[tile] = new int[nrOfTileParts];
firstPackOff[tile] = new int[nrOfTileParts];
tilePartHeadLen[tile] = new int[nrOfTileParts];
} else if(tileParts[tile] > nrOfTileParts ) {
// Already found more tile-parts than signaled here
throw new CorruptedCodestreamException("Invalid number "+
"of tile-parts in"+
" tile "+tile+": "+
nrOfTileParts);
} else { // Signaled number of tile-part fits with number of
// previously found tile-parts
remainingTileParts += nrOfTileParts-tileParts[tile];
if(tileParts[tile]!=nrOfTileParts) {
// Increase and re-copy tilePartLen array
int[] tmpA = tilePartLen[tile];
tilePartLen[tile] = new int[nrOfTileParts];
for(int i=0; i<tileParts[tile]-1; i++) {
tilePartLen[tile][i] = tmpA[i];
}
// Increase and re-copy tilePartNum array
tmpA = tilePartNum[tile];
tilePartNum[tile] = new int[nrOfTileParts];
for(int i=0; i<tileParts[tile]-1; i++) {
tilePartNum[tile][i] = tmpA[i];
}
// Increase and re-copy firstPackOff array
tmpA = firstPackOff[tile];
firstPackOff[tile] = new int[nrOfTileParts];
for(int i=0; i<tileParts[tile]-1; i++) {
firstPackOff[tile][i] = tmpA[i];
}
// Increase and re-copy tilePartHeadLen array
tmpA = tilePartHeadLen[tile];
tilePartHeadLen[tile] = new int[nrOfTileParts];
for(int i=0; i<tileParts[tile]-1; i++) {
tilePartHeadLen[tile][i] = tmpA[i];
}
}
}
}
// Other markers
hd.resetHeaderMarkers();
hd.nTileParts[tile] = nrOfTileParts;
// Decode and store the tile-part header (i.e. until a SOD marker is
// found)
do {
hd.extractTilePartMarkSeg(in.readShort(),in,tile,tilePart);
} while ((hd.getNumFoundMarkSeg() & hd.SOD_FOUND)==0);
// Read each marker segment previously found
hd.readFoundTilePartMarkSeg(tile,tilePart);
tilePartLen[tile][tilePart] = psot;
tilePartNum[tile][tilePart] = totTilePartsRead;
totTilePartsRead++;
// Add to list of which tile each successive tile-part belongs.
// This list is needed if there are PPM markers used
hd.setTileOfTileParts(tile);
return tile;
}
/**
* Reads packets of the current tile according to the
* layer-resolution-component-position progressiveness.
*
* @param lys Index of the first layer for each component and resolution.
*
* @param lye Index of the last layer.
*
* @param ress Index of the first resolution level.
*
* @param rese Index of the last resolution level.
*
* @param comps Index of the first component.
*
* @param compe Index of the last component.
*
* @return True if rate has been reached.
* */
private boolean readLyResCompPos(int[][] lys,int lye,int ress,int rese,
int comps,int compe)
throws IOException {
int minlys = 10000;
for(int c=comps; c<compe; c++) { //loop on components
// Check if this component exists
if(c>=mdl.length) continue;
for(int r=ress; r<rese; r++) {//loop on resolution levels
if(lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
minlys = lys[c][r];
}
}
}
int t = getTileIdx();
int start;
boolean status = false;
int lastByte = firstPackOff[t][curTilePart]+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
int nPrec = 1;
int hlen,plen;
String strInfo = printInfo ?
"Tile "+getTileIdx()+" (tile-part:"+curTilePart+
"): offset, length, header length\n" : null;
boolean pph = false;
if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
pph = true;
}
for(int l=minlys; l<lye; l++) { // loop on layers
for(int r=ress; r<rese; r++) { // loop on resolution levels
for(int c=comps; c<compe; c++) { // loop on components
// Checks if component exists
if(c>=mdl.length) continue;
// Checks if resolution level exists
if(r>=lys[c].length) continue;
if(r>mdl[c]) continue;
// Checks if layer exists
if(l<lys[c][r] || l>=numLayers) continue;
nPrec = pktDec.getNumPrecinct(c,r);
for(int p=0; p<nPrec; p++) { // loop on precincts
start = in.getPos();
// If packed packet headers are used, there is no need
// to check that there are bytes enough to read header
if(pph) {
pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes);
}
// If we are about to read outside of tile-part,
// skip to next tile-part
if(start>lastByte &&
curTilePart<firstPackOff[t].length-1) {
curTilePart++;
in.seek(firstPackOff[t][curTilePart]);
lastByte = in.getPos()+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
}
// Read SOP marker segment if necessary
status = pktDec.readSOPMarker(nBytes,p,c,r);
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
if(!pph) {
status =
pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes);
}
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
// Store packet's head length
hlen = in.getPos()-start;
pktHL.addElement(new Integer(hlen));
// Reads packet's body
status = pktDec.readPktBody(l,r,c,p,cbI[c][r],nBytes);
plen = in.getPos()-start;
if(printInfo)
strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+p+": "+
start+", "+plen+", "+hlen+"\n";
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
} // end loop on precincts
} // end loop on components
} // end loop on resolution levels
} // end loop on layers
if(printInfo) {
FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
}
return false; // Decoding rate was not reached
}
/**
* Reads packets of the current tile according to the
* resolution-layer-component-position progressiveness.
*
* @param lys Index of the first layer for each component and resolution.
*
* @param lye Index of the last layer.
*
* @param ress Index of the first resolution level.
*
* @param rese Index of the last resolution level.
*
* @param comps Index of the first component.
*
* @param compe Index of the last component.
*
* @return True if rate has been reached.
* */
private boolean readResLyCompPos(int lys[][],int lye,int ress,int rese,
int comps,int compe)
throws IOException {
int t = getTileIdx(); // Current tile index
boolean status=false; // True if decoding rate is reached when
int lastByte = firstPackOff[t][curTilePart]+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
int minlys = 10000;
for(int c=comps; c<compe; c++) { //loop on components
// Check if this component exists
if(c>=mdl.length) continue;
for(int r=ress; r<rese; r++) {//loop on resolution levels
if(r>mdl[c]) continue;
if(lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
minlys = lys[c][r];
}
}
}
String strInfo = printInfo ?
"Tile "+getTileIdx()+" (tile-part:"+curTilePart+
"): offset, length, header length\n" : null;
int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
boolean pph = false;
if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
pph = true;
}
int nPrec = 1;
int start;
int hlen,plen;
for(int r=ress; r<rese; r++) { // loop on resolution levels
for(int l=minlys; l<lye; l++) { // loop on layers
for(int c=comps; c<compe; c++) { // loop on components
// Checks if component exists
if(c>=mdl.length) continue;
// Checks if resolution level exists
if(r>mdl[c]) continue;
if(r>=lys[c].length) continue;
// Checks if layer exists
if(l<lys[c][r] || l>=numLayers) continue;
nPrec = pktDec.getNumPrecinct(c,r);
for(int p=0; p<nPrec; p++) { // loop on precincts
start = in.getPos();
// If packed packet headers are used, there is no need
// to check that there are bytes enough to read header
if(pph) {
pktDec.readPktHead(l,r,c,p,cbI[c][r],nBytes);
}
// If we are about to read outside of tile-part,
// skip to next tile-part
if(start>lastByte &&
curTilePart<firstPackOff[t].length-1) {
curTilePart++;
in.seek(firstPackOff[t][curTilePart]);
lastByte = in.getPos()+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
}
// Read SOP marker segment if necessary
status = pktDec.readSOPMarker(nBytes,p,c,r);
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
if(!pph) {
status = pktDec.
readPktHead(l,r,c,p,cbI[c][r],nBytes);
}
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
// Output rate of EOF reached
return true;
}
// Store packet's head length
hlen = in.getPos()-start;
pktHL.addElement(new Integer(hlen));
// Reads packet's body
status = pktDec.readPktBody(l,r,c,p,cbI[c][r],nBytes);
plen = in.getPos()-start;
if(printInfo)
strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+p+": "+
start+", "+plen+", "+hlen+"\n";
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
// Output rate or EOF reached
return true;
}
} // end loop on precincts
} // end loop on components
} // end loop on layers
} // end loop on resolution levels
if(printInfo) {
FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
}
return false; // Decoding rate was not reached
}
/**
* Reads packets of the current tile according to the
* resolution-position-component-layer progressiveness.
*
* @param lys Index of the first layer for each component and resolution.
*
* @param lye Index of the last layer.
*
* @param ress Index of the first resolution level.
*
* @param rese Index of the last resolution level.
*
* @param comps Index of the first component.
*
* @param compe Index of the last component.
*
* @return True if rate has been reached.
* */
private boolean readResPosCompLy(int[][] lys,int lye,int ress,int rese,
int comps,int compe)
throws IOException {
// Computes current tile offset in the reference grid
Point nTiles = getNumTiles(null);
Point tileI = getTile(null);
int x0siz = hd.getImgULX();
int y0siz = hd.getImgULY();
int xsiz = x0siz + hd.getImgWidth();
int ysiz = y0siz + hd.getImgHeight();
int xt0siz = getTilePartULX();
int yt0siz = getTilePartULY();
int xtsiz = getNomTileWidth();
int ytsiz = getNomTileHeight();
int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
// Get precinct information (number,distance between two consecutive
// precincts in the reference grid) in each component and resolution
// level
int t = getTileIdx(); // Current tile index
PrecInfo prec; // temporary variable
int p; // Current precinct index
int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
int nPrec = 0; // Total number of found precincts
int[][] nextPrec = new int [compe][]; // Next precinct index in each
// component and resolution level
int minlys = 100000; // minimum layer start index of each component
int minx = tx1; // Horiz. offset of the second precinct in the
// reference grid
int miny = ty1; // Vert. offset of the second precinct in the
// reference grid.
int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
Point numPrec;
for(int c=comps; c<compe; c++) { // components
for(int r=ress; r<rese; r++) { // resolution levels
if(c>=mdl.length) continue;
if(r>mdl[c]) continue;
nextPrec[c] = new int[mdl[c]+1];
if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
minlys = lys[c][r];
}
p = pktDec.getNumPrecinct(c,r)-1;
for(; p>=0; p--) {
prec = pktDec.getPrecInfo(c,r,p);
if(prec.rgulx!=tx0) {
if(prec.rgulx<minx) minx = prec.rgulx;
if(prec.rgulx>maxx) maxx = prec.rgulx;
}
if(prec.rguly!=ty0) {
if(prec.rguly<miny) miny = prec.rguly;
if(prec.rguly>maxy) maxy = prec.rguly;
}
if(nPrec==0) {
gcd_x = prec.rgw;
gcd_y = prec.rgh;
} else {
gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
}
nPrec++;
} // precincts
} // resolution levels
} // components
if(nPrec==0) {
throw new Error("Image cannot have no precinct");
}
int pyend = (maxy-miny)/gcd_y+1;
int pxend = (maxx-minx)/gcd_x+1;
int x,y;
int hlen,plen;
int start;
boolean status = false;
int lastByte = firstPackOff[t][curTilePart]+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
String strInfo = printInfo ?
"Tile "+getTileIdx()+" (tile-part:"+curTilePart+
"): offset, length, header length\n" : null;
boolean pph = false;
if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
pph = true;
}
for(int r=ress; r<rese; r++) { // loop on resolution levels
y = ty0;
x = tx0;
for(int py=0; py<=pyend; py++) { // Vertical precincts
for(int px=0; px<=pxend; px++) { // Horiz. precincts
for(int c=comps; c<compe; c++) { // Components
if(c>=mdl.length) continue;
if(r>mdl[c]) continue;
if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) {
continue;
}
prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]);
if((prec.rgulx!=x) || (prec.rguly!=y)) {
continue;
}
for(int l=minlys; l<lye; l++) { // layers
if(r>=lys[c].length) continue;
if(l<lys[c][r] || l>=numLayers) continue;
start = in.getPos();
// If packed packet headers are used, there is no
// need to check that there are bytes enough to
// read header
if(pph) {
pktDec.readPktHead(l,r,c,nextPrec[c][r],
cbI[c][r],nBytes);
}
// If we are about to read outside of tile-part,
// skip to next tile-part
if(start>lastByte &&
curTilePart<firstPackOff[t].length-1) {
curTilePart++;
in.seek(firstPackOff[t][curTilePart]);
lastByte = in.getPos()+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
}
// Read SOP marker segment if necessary
status = pktDec.readSOPMarker(nBytes,
nextPrec[c][r],c,r);
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
if(!pph) {
status =
pktDec.readPktHead(l,r,c,
nextPrec[c][r],
cbI[c][r],nBytes);
}
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
// Store packet's head length
hlen = in.getPos()-start;
pktHL.addElement(new Integer(hlen));
// Reads packet's body
status = pktDec.readPktBody(l,r,c,nextPrec[c][r],
cbI[c][r],nBytes);
plen = in.getPos()-start;
if(printInfo)
strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+
nextPrec[c][r]+": "+
start+", "+plen+", "+hlen+"\n";
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
} // layers
nextPrec[c][r]++;
} // Components
if(px!=pxend) {
x = minx+px*gcd_x;
} else {
x = tx0;
}
} // Horizontal precincts
if(py!=pyend) {
y = miny+py*gcd_y;
} else {
y = ty0;
}
} // Vertical precincts
} // end loop on resolution levels
if(printInfo) {
FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
}
return false; // Decoding rate was not reached
}
/**
* Reads packets of the current tile according to the
* position-component-resolution-layer progressiveness.
*
* @param lys Index of the first layer for each component and resolution.
*
* @param lye Index of the last layer.
*
* @param ress Index of the first resolution level.
*
* @param rese Index of the last resolution level.
*
* @param comps Index of the first component.
*
* @param compe Index of the last component.
*
* @return True if rate has been reached.
* */
private boolean readPosCompResLy(int[][] lys,int lye,int ress,int rese,
int comps,int compe)
throws IOException {
Point nTiles = getNumTiles(null);
Point tileI = getTile(null);
int x0siz = hd.getImgULX();
int y0siz = hd.getImgULY();
int xsiz = x0siz + hd.getImgWidth();
int ysiz = y0siz + hd.getImgHeight();
int xt0siz = getTilePartULX();
int yt0siz = getTilePartULY();
int xtsiz = getNomTileWidth();
int ytsiz = getNomTileHeight();
int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
// Get precinct information (number,distance between two consecutive
// precincts in the reference grid) in each component and resolution
// level
int t = getTileIdx(); // Current tile index
PrecInfo prec; // temporary variable
int p; // Current precinct index
int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
int nPrec = 0; // Total number of found precincts
int[][] nextPrec = new int [compe][]; // Next precinct index in each
// component and resolution level
int minlys = 100000; // minimum layer start index of each component
int minx = tx1; // Horiz. offset of the second precinct in the
// reference grid
int miny = ty1; // Vert. offset of the second precinct in the
// reference grid.
int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
Point numPrec;
for(int c=comps; c<compe; c++) { // components
for(int r=ress; r<rese; r++) { // resolution levels
if(c>=mdl.length) continue;
if(r>mdl[c]) continue;
nextPrec[c] = new int[mdl[c]+1];
if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
minlys = lys[c][r];
}
p = pktDec.getNumPrecinct(c,r)-1;
for(; p>=0; p--) {
prec = pktDec.getPrecInfo(c,r,p);
if(prec.rgulx!=tx0) {
if(prec.rgulx<minx) minx = prec.rgulx;
if(prec.rgulx>maxx) maxx = prec.rgulx;
}
if(prec.rguly!=ty0) {
if(prec.rguly<miny) miny = prec.rguly;
if(prec.rguly>maxy) maxy = prec.rguly;
}
if(nPrec==0) {
gcd_x = prec.rgw;
gcd_y = prec.rgh;
} else {
gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
}
nPrec++;
} // precincts
} // resolution levels
} // components
if(nPrec==0) {
throw new Error("Image cannot have no precinct");
}
int pyend = (maxy-miny)/gcd_y+1;
int pxend = (maxx-minx)/gcd_x+1;
int hlen,plen;
int start;
boolean status = false;
int lastByte = firstPackOff[t][curTilePart]+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
String strInfo = printInfo ?
"Tile "+getTileIdx()+" (tile-part:"+curTilePart+
"): offset, length, header length\n" : null;
boolean pph = false;
if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
pph = true;
}
int y = ty0;
int x = tx0;
for(int py=0; py<=pyend; py++) { // Vertical precincts
for(int px=0; px<=pxend; px++) { // Horiz. precincts
for(int c=comps; c<compe; c++) { // Components
if(c>=mdl.length) continue;
for(int r=ress; r<rese; r++) { // Resolution levels
if(r>mdl[c]) continue;
if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) {
continue;
}
prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]);
if((prec.rgulx!=x) || (prec.rguly!=y)) {
continue;
}
for(int l=minlys; l<lye; l++) { // Layers
if(r>=lys[c].length) continue;
if(l<lys[c][r] || l>=numLayers) continue;
start = in.getPos();
// If packed packet headers are used, there is no
// need to check that there are bytes enough to
// read header
if(pph) {
pktDec.readPktHead(l,r,c,nextPrec[c][r],
cbI[c][r],nBytes);
}
// Read SOP marker segment if necessary
status = pktDec.readSOPMarker(nBytes,
nextPrec[c][r],c,r);
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
if(!pph) {
status =
pktDec.readPktHead(l,r,c,
nextPrec[c][r],
cbI[c][r],nBytes);
}
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
// Store packet's head length
hlen = in.getPos()-start;
pktHL.addElement(new Integer(hlen));
// Reads packet's body
status = pktDec.readPktBody(l,r,c,nextPrec[c][r],
cbI[c][r],nBytes);
plen = in.getPos()-start;
if(printInfo)
strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+
nextPrec[c][r]+": "+
start+", "+plen+", "+hlen+"\n";
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
} // layers
nextPrec[c][r]++;
} // Resolution levels
} // Components
if(px!=pxend) {
x = minx+px*gcd_x;
} else {
x = tx0;
}
} // Horizontal precincts
if(py!=pyend) {
y = miny+py*gcd_y;
} else {
y = ty0;
}
} // Vertical precincts
if(printInfo) {
FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
}
return false; // Decoding rate was not reached
}
/**
* Reads packets of the current tile according to the
* component-position-resolution-layer progressiveness.
*
* @param lys Index of the first layer for each component and resolution.
*
* @param lye Index of the last layer.
*
* @param ress Index of the first resolution level.
*
* @param rese Index of the last resolution level.
*
* @param comps Index of the first component.
*
* @param compe Index of the last component.
*
* @return True if rate has been reached.
* */
private boolean readCompPosResLy(int lys[][],int lye,int ress,int rese,
int comps,int compe)
throws IOException {
Point nTiles = getNumTiles(null);
Point tileI = getTile(null);
int x0siz = hd.getImgULX();
int y0siz = hd.getImgULY();
int xsiz = x0siz + hd.getImgWidth();
int ysiz = y0siz + hd.getImgHeight();
int xt0siz = getTilePartULX();
int yt0siz = getTilePartULY();
int xtsiz = getNomTileWidth();
int ytsiz = getNomTileHeight();
int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz;
int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz;
int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz;
int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz;
// Get precinct information (number,distance between two consecutive
// precincts in the reference grid) in each component and resolution
// level
int t = getTileIdx(); // Current tile index
PrecInfo prec; // temporary variable
int p; // Current precinct index
int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid
int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid
int nPrec = 0; // Total number of found precincts
int[][] nextPrec = new int [compe][]; // Next precinct index in each
// component and resolution level
int minlys = 100000; // minimum layer start index of each component
int minx = tx1; // Horiz. offset of the second precinct in the
// reference grid
int miny = ty1; // Vert. offset of the second precinct in the
// reference grid.
int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid
int maxy = ty0; // Max. vert. offset of precincts in the ref. grid
Point numPrec;
for(int c=comps; c<compe; c++) { // components
for(int r=ress; r<rese; r++) { // resolution levels
if(c>=mdl.length) continue;
if(r>mdl[c]) continue;
nextPrec[c] = new int[mdl[c]+1];
if (lys[c]!=null && r<lys[c].length && lys[c][r]<minlys) {
minlys = lys[c][r];
}
p = pktDec.getNumPrecinct(c,r)-1;
for(; p>=0; p--) {
prec = pktDec.getPrecInfo(c,r,p);
if(prec.rgulx!=tx0) {
if(prec.rgulx<minx) minx = prec.rgulx;
if(prec.rgulx>maxx) maxx = prec.rgulx;
}
if(prec.rguly!=ty0) {
if(prec.rguly<miny) miny = prec.rguly;
if(prec.rguly>maxy) maxy = prec.rguly;
}
if(nPrec==0) {
gcd_x = prec.rgw;
gcd_y = prec.rgh;
} else {
gcd_x = MathUtil.gcd(gcd_x,prec.rgw);
gcd_y = MathUtil.gcd(gcd_y,prec.rgh);
}
nPrec++;
} // precincts
} // resolution levels
} // components
if(nPrec==0) {
throw new Error("Image cannot have no precinct");
}
int pyend = (maxy-miny)/gcd_y+1;
int pxend = (maxx-minx)/gcd_x+1;
int hlen,plen;
int start;
boolean status = false;
int lastByte = firstPackOff[t][curTilePart]+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
String strInfo = printInfo ?
"Tile "+getTileIdx()+" (tile-part:"+curTilePart+
"): offset, length, header length\n" : null;
boolean pph = false;
if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
pph = true;
}
int x,y;
for(int c=comps; c<compe; c++) { // components
if(c>=mdl.length) continue;
y = ty0;
x = tx0;
for(int py=0; py<=pyend; py++) { // Vertical precincts
for(int px=0; px<=pxend; px++) { // Horiz. precincts
for(int r=ress; r<rese; r++) { // Resolution levels
if(r>mdl[c]) continue;
if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) {
continue;
}
prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]);
if((prec.rgulx!=x) || (prec.rguly!=y)) {
continue;
}
for(int l=minlys; l<lye; l++) { // Layers
if(r>=lys[c].length) continue;
if(l<lys[c][r]) continue;
start = in.getPos();
// If packed packet headers are used, there is no
// need to check that there are bytes enough to
// read header
if(pph) {
pktDec.readPktHead(l,r,c,nextPrec[c][r],
cbI[c][r],nBytes);
}
// If we are about to read outside of tile-part,
// skip to next tile-part
if(start>lastByte &&
curTilePart<firstPackOff[t].length-1) {
curTilePart++;
in.seek(firstPackOff[t][curTilePart]);
lastByte = in.getPos()+
tilePartLen[t][curTilePart]-1-
tilePartHeadLen[t][curTilePart];
}
// Read SOP marker segment if necessary
status = pktDec.readSOPMarker(nBytes,
nextPrec[c][r],c,r);
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
if(!pph) {
status =
pktDec.readPktHead(l,r,c,
nextPrec[c][r],
cbI[c][r],nBytes);
}
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
// Store packet's head length
hlen = in.getPos()-start;
pktHL.addElement(new Integer(hlen));
// Reads packet's body
status = pktDec.readPktBody(l,r,c,nextPrec[c][r],
cbI[c][r],nBytes);
plen = in.getPos()-start;
if(printInfo)
strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+
nextPrec[c][r]+": "+
start+", "+plen+", "+hlen+"\n";
if(status) {
if(printInfo) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.INFO,strInfo);
}
return true;
}
} // layers
nextPrec[c][r]++;
} // Resolution levels
if(px!=pxend) {
x = minx+px*gcd_x;
} else {
x = tx0;
}
} // Horizontal precincts
if(py!=pyend) {
y = miny+py*gcd_y;
} else {
y = ty0;
}
} // Vertical precincts
} // components
if(printInfo) {
FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo);
}
return false; // Decoding rate was not reached
}
/**
* Finish initialization of members for specified tile, reads packets head
* of each tile and keeps location of each code-block's codewords. The
* last 2 tasks are done by calling specific methods of PktDecoder.
*
* <p>Then, if a parsing output rate is defined, it keeps information of
* first layers only. This operation simulates a creation of a
* layer-resolution-component progressive bit-stream which will be next
* truncated and decoded.</p>
*
* @param t Tile index
*
* @see PktDecoder
* */
private void readTilePkts(int t) throws IOException {
pktHL = new Vector();
int oldNBytes = nBytes[t];
// Number of layers
int nl = ((Integer)decSpec.nls.getTileDef(t)).intValue();
// If packed packet headers was used, get the packet headers for this
// tile
if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) {
// Gets packed headers as separate input stream
ByteArrayInputStream pphbais = hd.getPackedPktHead(t);
// Restarts PktDecoder instance
cbI = pktDec.restart(nc,mdl,nl,cbI,true,pphbais);
} else {
// Restarts PktDecoder instance
cbI = pktDec.restart(nc,mdl,nl,cbI,false,null);
}
// Reads packets of the tile according to the progression order
int[][] pocSpec = ((int[][])decSpec.pcs.getTileDef(t));
int nChg = (pocSpec==null) ? 1 : pocSpec.length;
// Create an array containing information about changes (progression
// order type, layers index start, layer index end, resolution level
// start, resolution level end, component index start, component index
// end). There is one row per progresion order
int[][] change = new int[nChg][6];
int idx = 0; // Index of the current progression order
change[0][1] = 0; // layer start
if(pocSpec==null) {
change[idx][0] = ((Integer)decSpec.pos.getTileDef(t)).intValue();
// Progression type found in COx marker segments
change[idx][1] = nl; // Layer index end
change[idx][2] = 0; // resolution level start
change[idx][3] = decSpec.dls.getMaxInTile(t)+1; // res. level end
change[idx][4] = 0; // Component index start
change[idx][5] = nc; // Component index end
} else {
for(idx=0; idx<nChg; idx++){
change[idx][0] = pocSpec[idx][5];
change[idx][1] = pocSpec[idx][2]; // layer end
change[idx][2] = pocSpec[idx][0]; // res. lev. start
change[idx][3] = pocSpec[idx][3]; // res. lev. end
change[idx][4] = pocSpec[idx][1]; // Comp. index start
change[idx][5] = pocSpec[idx][4]; // Comp. index end
}
}
// Seeks to the first packet of the first tile-part
try {
// If in truncation mode, the first tile-part may be beyond the
// target decoding rate. In this case, the offset of the first
// packet is not defined.
if(isTruncMode && firstPackOff==null || firstPackOff[t]==null) {
return;
}
in.seek(firstPackOff[t][0]);
} catch(EOFException e) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.WARNING,"Codestream truncated in tile "+t);
return;
}
curTilePart = 0;
// Start and end indexes for layers, resolution levels and components.
int lye,ress,rese,comps,compe;
boolean status = false;
int nb = nBytes[t];
int[][] lys = new int[nc][];
for(int c=0; c<nc; c++) {
lys[c] = new int[((Integer)decSpec.dls.getTileCompVal(t,c)).
intValue()+1];
}
try {
for(int chg=0; chg<nChg; chg++) {
lye = change[chg][1];
ress = change[chg][2];
rese = change[chg][3];
comps = change[chg][4];
compe = change[chg][5];
switch(change[chg][0]) {
case LY_RES_COMP_POS_PROG:
status = readLyResCompPos(lys,lye,ress,rese,comps,compe);
break;
case RES_LY_COMP_POS_PROG:
status = readResLyCompPos(lys,lye,ress,rese,comps,compe);
break;
case RES_POS_COMP_LY_PROG:
status = readResPosCompLy(lys,lye,ress,rese,comps,compe);
break;
case POS_COMP_RES_LY_PROG:
status = readPosCompResLy(lys,lye,ress,rese,comps,compe);
break;
case COMP_POS_RES_LY_PROG:
status = readCompPosResLy(lys,lye,ress,rese,comps,compe);
break;
default:
throw new IllegalArgumentException("Not recognized "+
"progression type");
}
// Update next first layer index
for(int c=comps; c<compe; c++) {
if(c>=lys.length) continue;
for(int r=ress; r<rese; r++) {
if(r>=lys[c].length) continue;
lys[c][r] = lye;
}
}
if(status || usePOCQuit) {
break;
}
}
} catch(EOFException e) {
// Should never happen. Truncated codestream are normally found by
// the class constructor
throw e;
}
// In truncation mode, update the number of read bytes
if(isTruncMode) {
anbytes += nb-nBytes[t];
// If truncation rate is reached
if(status) {
nBytes[t] = 0;
}
} else if(nBytes[t]<(totTileLen[t]-totTileHeadLen[t])) {
// In parsing mode, if there is not enough rate to entirely read the
// tile. Then, parses the bit stream so as to create a virtual
// layer-resolution-component progressive bit stream that will be
// truncated and decoded afterwards.
CBlkInfo cb;
// Systematicaly reject all remaining code-blocks if one
// code-block, at least, is refused.
boolean reject;
// Stop reading any data from the bit stream
boolean stopCount = false;
// Length of each packet's head (in an array)
int[] pktHeadLen = new int[pktHL.size()];
for(int i=pktHL.size()-1;i>=0;i--) {
pktHeadLen[i] = ((Integer)pktHL.elementAt(i)).intValue();
}
// Parse each code-block, layer per layer until nBytes[t] is
// reached
reject = false;
for(int l=0; l<nl; l++) { // layers
if(cbI==null) continue;
int nc = cbI.length;
int mres = 0;
for(int c=0; c<nc; c++) {
if(cbI[c]!=null && cbI[c].length>mres)
mres = cbI[c].length;
}
for(int r=0; r<mres; r++) { // resolutions
int msub = 0;
for(int c=0; c<nc; c++) {
if(cbI[c]!=null && cbI[c][r]!=null
&& cbI[c][r].length>msub)
msub = cbI[c][r].length;
}
for(int s=0; s<msub; s++) { // subbands
// Only LL subband resolution level 0
if(r==0 && s!=0) {
continue;
} else if(r!=0 && s==0) {
// No LL subband in resolution level > 0
continue;
}
int mnby=0;
for(int c=0; c<nc; c++) {
if(cbI[c]!=null && cbI[c][r]!=null &&
cbI[c][r][s]!=null &&
cbI[c][r][s].length>mnby)
mnby = cbI[c][r][s].length;
}
for(int m=0; m<mnby; m++) {
int mnbx = 0;
for(int c=0; c<nc; c++) {
if(cbI[c]!=null && cbI[c][r]!=null &&
cbI[c][r][s]!=null && cbI[c][r][s][m]!=null
&& cbI[c][r][s][m].length>mnbx)
mnbx = cbI[c][r][s][m].length;
}
for(int n=0; n<mnbx; n++) {
for(int c=0; c<nc; c++) {
if(cbI[c]==null || cbI[c][r]==null ||
cbI[c][r][s]==null ||
cbI[c][r][s][m]==null ||
cbI[c][r][s][m][n]==null ) {
continue;
}
cb = cbI[c][r][s][m][n];
// If no code-block has been refused until
// now
if(!reject) {
// Rate is to low to allow reading of
// packet's head
if(nBytes[t]<pktHeadLen[cb.pktIdx[l]]){
// Stop parsing
stopCount = true;
// Reject all next
// code-blocks
reject=true;
} else {
// Rate is enough to read packet's
// head
if(!stopCount) {
//If parsing was not stopped
//Takes into account packet's
//head length
nBytes[t] -=
pktHeadLen[cb.pktIdx[l]];
anbytes +=
pktHeadLen[cb.pktIdx[l]];
// Set packet's head length to
// 0, so that it won't be
// taken into account next
// time
pktHeadLen[cb.pktIdx[l]]=0;
}
}
}
// Code-block has no data in this layer
if(cb.len[l]==0) {
continue;
}
// Accepts code-block if length is enough,
// if this code-block was not refused in a
// previous layer and if no code-block was
// refused in current component
if(cb.len[l]<nBytes[t]
&& !reject){
nBytes[t] -= cb.len[l];
anbytes += cb.len[l];
} else {
// Refuses code-block
// Forgets code-block's data
cb.len[l]=cb.off[l]=cb.ntp[l]= 0;
// Refuses all other code-block in
// current and next component
reject=true;
}
} // End loop on components
} // End loop on horiz. code-blocks
} // End loop on vert. code-blocks
} // End loop on subbands
} // End loop on resolutions
} // End loop on layers
} else {
// No parsing for this tile, adds tile's body to the total
// number of read bytes.
anbytes += totTileLen[t]-totTileHeadLen[t];
if(t<getNumTiles()-1) {
nBytes[t+1] += nBytes[t]-(totTileLen[t]-totTileHeadLen[t]);
}
}
// In this method nBytes[t] might be changed. This change will affect
// to decode this tile next time. So cache the old nByte[t] and
// recover it here. -- Qinghuai Gao
nBytes[t] = oldNBytes;
}
/**
* Changes the current tile, given the new indexes. An
* IllegalArgumentException is thrown if the indexes do not correspond to
* a valid tile.
*
* @param x The horizontal indexes the tile.
*
* @param y The vertical indexes of the new tile.
* */
public void setTile(int x,int y) {
int i; // counter
// Check validity of tile indexes
if (x<0 || y<0 || x>=ntX || y>=ntY) {
throw new IllegalArgumentException();
}
int t = (y*ntX+x);
try {
initTile(t);
} catch(IOException ioe) {
// XXX Do something!
}
// Reset number of read bytes if needed
if(t==0) {
anbytes = headLen;
if(!isTruncMode) {
anbytes += 2;
}
// Restore values of nBytes
for(int tIdx=0; tIdx<nt; tIdx++) {
nBytes[tIdx] = baknBytes[tIdx];
}
}
// Set the new current tile
ctX = x;
ctY = y;
// Calculate tile relative points
int ctox = (x == 0) ? ax : px+x*ntW;
int ctoy = (y == 0) ? ay : py+y*ntH;
for (i=nc-1; i>=0; i--) {
culx[i] = (ctox+hd.getCompSubsX(i)-1)/hd.getCompSubsX(i);
culy[i] = (ctoy+hd.getCompSubsY(i)-1)/hd.getCompSubsY(i);
offX[i] = (px+x*ntW+hd.getCompSubsX(i)-1)/hd.getCompSubsX(i);
offY[i] = (py+y*ntH+hd.getCompSubsY(i)-1)/hd.getCompSubsY(i);
}
// Initialize subband tree and number of resolution levels
subbTrees = new SubbandSyn[nc];
mdl = new int[nc];
derived = new boolean[nc];
params = new StdDequantizerParams[nc];
gb = new int[nc];
for(int c=0; c<nc; c++){
derived[c] = decSpec.qts.isDerived(t,c);
params[c] =
(StdDequantizerParams)decSpec.qsss.getTileCompVal(t,c);
gb[c] = ((Integer)decSpec.gbs.getTileCompVal(t,c)).intValue();
mdl[c] = ((Integer)decSpec.dls.getTileCompVal(t,c)).intValue();
subbTrees[c] =
new SubbandSyn(getTileCompWidth(t,c,mdl[c]),
getTileCompHeight(t,c,mdl[c]),
getResULX(c,mdl[c]),getResULY(c,mdl[c]),mdl[c],
decSpec.wfs.getHFilters(t,c),
decSpec.wfs.getVFilters(t,c));
initSubbandsFields(c,subbTrees[c]);
}
// Read tile's packets
try {
readTilePkts(t);
} catch(IOException e) {
e.printStackTrace();
throw new Error("IO Error when reading tile "+x+" x "+y);
}
}
/**
* Advances to the next tile, in standard scan-line order (by rows
* then columns). An NoNextElementException is thrown if the
* current tile is the last one (i.e. there is no next tile).
* */
public void nextTile(){
if (ctX == ntX-1 && ctY == ntY-1) { // Already at last tile
throw new NoNextElementException();
}
else if (ctX < ntX-1) { // If not at end of current tile line
setTile(ctX+1,ctY);
}
else { // Go to first tile at next line
setTile(0,ctY+1);
}
}
/**
* Returns the specified coded code-block, for the specified component, in
* the current tile. The first layer to return is indicated by 'fl'. The
* number of layers that is returned depends on 'nl' and the amount of
* available data.
*
* <p>The argument 'fl' is to be used by subsequent calls to this method
* for the same code-block. In this way supplemental data can be retrieved
* at a later time. The fact that data from more than one layer can be
* returned means that several packets from the same code-block, of the
* same component, and the same tile, have been concatenated.</p>
*
* <p>The returned compressed code-block can have its progressive
* attribute set. If this attribute is set it means that more data can be
* obtained by subsequent calls to this method (subject to transmission
* delays, etc). If the progressive attribute is not set it means that the
* returned data is all the data that can be obtained for the specified
* code-block.</p>
*
* <p>The compressed code-block is uniquely specified by the current tile,
* the component (identified by 'c'), the subband (indentified by 'sb')
* and the code-block vertical and horizontal indexes 'n' and 'm'.</p>
*
* <p>The 'ulx' and 'uly' members of the returned 'DecLyrdCBlk' object
* contain the coordinates of the top-left corner of the block, with
* respect to the tile, not the subband.</p>
*
* @param c The index of the component, from 0 to N-1.
*
* @param m The vertical index of the code-block to return, in the
* specified subband.
*
* @param n The horizontal index of the code-block to return, in the
* specified subband.
*
* @param sb The subband in whic the requested code-block is.
*
* @param fl The first layer to return.
*
* @param nl The number of layers to return, if negative all available
* layers are returned, starting at 'fl'.
*
* @param ccb If not null this object is used to return the compressed
* code-block. If null a new object is created and returned. If the data
* array in ccb is not null then it can be reused to return the compressed
* data.
* @return The compressed code-block, with a certain number of layers
* determined by the available data and 'nl'.
* */
public DecLyrdCBlk getCodeBlock(int c,int m,int n,SubbandSyn sb,int fl,
int nl,DecLyrdCBlk ccb) {
int t = getTileIdx();
CBlkInfo rcb; // requested code-block
int r = sb.resLvl; // Resolution level
int s = sb.sbandIdx; // Subband index
int tpidx;
int passtype;
// Number of layers
int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue();
int options = ((Integer)decSpec.ecopts.getTileCompVal(t,c)).intValue();
if(nl<0) {
nl = numLayers-fl+1;
}
// If the l quit condition is used, Make sure that no layer
// after lquit is returned
if(lQuit != -1 && fl+nl>lQuit){
nl = lQuit - fl;
}
// Check validity of resquested resolution level (according to the
// "-res" option).
int maxdl = getSynSubbandTree(t,c).resLvl;
/* XXX Suppress error check for speed performance reasons.
if(r>targetRes+maxdl-decSpec.dls.getMin()) {
throw new Error("JJ2000 error: requesting a code-block "+
"disallowed by the '-res' option.");
}
*/
// Check validity of all the arguments
try {
rcb = cbI[c][r][s][m][n];
if(fl<1 || fl>numLayers || fl+nl-1>numLayers) {
throw new IllegalArgumentException();
}
} catch(ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException("Code-block (t:"+t+", c:"+
c+", r:"+r+", s:"+s+", "+m+"x"+
+n+") not found in codestream");
} catch(NullPointerException e) {
throw new IllegalArgumentException("Code-block (t:"+t+", c:"+
c+", r:"+r+", s:"+s+", "+m+"x"
+n+") not found in bit stream");
}
// Create DecLyrdCBlk object if necessary
if(ccb==null) {
ccb = new DecLyrdCBlk();
}
ccb.m = m;
ccb.n = n;
ccb.nl = 0;
ccb.dl = 0;
ccb.nTrunc = 0;
if(rcb==null) {
// This code-block was skipped when reading. Returns no data
ccb.skipMSBP = 0;
ccb.prog = false;
ccb.w = ccb.h = ccb.ulx = ccb.uly = 0;
return ccb;
}
// ccb initialization
ccb.skipMSBP = rcb.msbSkipped;
ccb.ulx = rcb.ulx;
ccb.uly = rcb.uly;
ccb.w = rcb.w;
ccb.h = rcb.h;
ccb.ftpIdx = 0;
// Search for index of first truncation point (first layer where
// length of data is not zero)
int l=0;
while( (l<rcb.len.length) && (rcb.len[l]==0)) {
ccb.ftpIdx += rcb.ntp[l];
l++;
}
// Calculate total length, number of included layer and number of
// truncation points
for(l=fl-1; l<fl+nl-1; l++) {
ccb.nl++;
ccb.dl += rcb.len[l];
ccb.nTrunc += rcb.ntp[l];
}
// Calculate number of terminated segments
int nts;
if((options & OPT_TERM_PASS) != 0) {
// Regular termination in use One segment per pass
// (i.e. truncation point)
nts = ccb.nTrunc-ccb.ftpIdx;
} else if((options & OPT_BYPASS) != 0) {
// Selective arithmetic coding bypass mode in use, but no regular
// termination: 1 segment upto the end of the last pass of the 4th
// most significant bit-plane, and, in each following bit-plane,
// one segment upto the end of the 2nd pass and one upto the end
// of the 3rd pass.
if(ccb.nTrunc <= FIRST_BYPASS_PASS_IDX) {
nts = 1;
} else {
nts = 1;
// Adds one for each terminated pass
for (tpidx = ccb.ftpIdx; tpidx < ccb.nTrunc; tpidx++) {
if (tpidx >= FIRST_BYPASS_PASS_IDX-1) {
passtype =
(tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%NUM_PASSES;
if (passtype == 1 || passtype == 2) {
// lazy pass just before MQ pass or MQ pass just
// before lazy pass => terminated
nts++;
}
}
}
}
} else {
// Nothing special in use, just one terminated segment
nts = 1;
}
// ccb.data creation
if(ccb.data==null || ccb.data.length<ccb.dl) {
ccb.data = new byte[ccb.dl];
}
// ccb.tsLengths creation
if (nts>1 && (ccb.tsLengths==null || ccb.tsLengths.length<nts)) {
ccb.tsLengths = new int[nts];
} else if (nts>1 &&
(options & (OPT_BYPASS|OPT_TERM_PASS)) == OPT_BYPASS) {
ArrayUtil.intArraySet(ccb.tsLengths,0);
}
// Fill ccb with compressed data
int dataIdx = -1;
tpidx = ccb.ftpIdx;
int ctp = ccb.ftpIdx; // Cumulative number of truncation
// point for the current layer layer
int tsidx=0;
int j;
for(l=fl-1; l<fl+nl-1; l++) {
ctp += rcb.ntp[l];
// No data in this layer
if(rcb.len[l]==0) continue;
// Read data
// NOTE: we should never get an EOFException here since all
// data is checked to be within the file.
try {
in.seek(rcb.off[l]);
in.readFully(ccb.data,dataIdx+1,rcb.len[l]);
dataIdx += rcb.len[l];
} catch (IOException e) {
JJ2KExceptionHandler.handleException(e);
}
// Get the terminated segment lengths, if any
if(nts==1) continue;
if((options & OPT_TERM_PASS) != 0) {
// Regular termination => each pass is terminated
for(j=0; tpidx<ctp; j++,tpidx++) {
if(rcb.segLen[l]!=null) {
ccb.tsLengths[tsidx++] = rcb.segLen[l][j];
} else { // Only one terminated segment in packet
ccb.tsLengths[tsidx++] = rcb.len[l];
}
}
} else {
// Lazy coding without regular termination
for(j=0; tpidx<ctp; tpidx++) {
if(tpidx>=FIRST_BYPASS_PASS_IDX-1) {
passtype =
(tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%NUM_PASSES;
if(passtype!=0) {
// lazy pass just before MQ pass or MQ
// pass just before lazy pass =>
// terminated
if(rcb.segLen[l]!=null) {
ccb.tsLengths[tsidx++] += rcb.segLen[l][j++];
rcb.len[l] -= rcb.segLen[l][j-1];
} else { // Only one terminated segment in packet
ccb.tsLengths[tsidx++] += rcb.len[l];
rcb.len[l] = 0;
}
}
}
}
// Last length in packet always in (either terminated segment
// or contribution to terminated segment)
if(rcb.segLen[l]!=null && j<rcb.segLen[l].length) {
ccb.tsLengths[tsidx] += rcb.segLen[l][j];
rcb.len[l] -= rcb.segLen[l][j];
} else { // Only one terminated segment in packet
if(tsidx<nts) {
ccb.tsLengths[tsidx] += rcb.len[l];
rcb.len[l] = 0;
}
}
}
}
if(nts==1 && ccb.tsLengths!=null) {
ccb.tsLengths[0] = ccb.dl;
}
// Set the progressive flag
int lastlayer = fl+nl-1;
if(lastlayer<numLayers-1){
for(l=lastlayer+1; l<numLayers; l++){
// It remains data for this code-block in the bit stream
if(rcb.len[l]!=0){
ccb.prog = true;
}
}
}
return ccb;
}
}