jj2000.j2k.codestream.reader.PktDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jai-imageio-jpeg2000 Show documentation
Show all versions of jai-imageio-jpeg2000 Show documentation
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.
/*
* $RCSfile: PktDecoder.java,v $
* $Revision: 1.1 $
* $Date: 2005/02/11 05:02:01 $
* $State: Exp $
*
* Class: PktDecoder
*
* Description: Reads packets heads and keeps location of
* code-blocks' codewords
*
*
*
* 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.EOFException;
import java.io.IOException;
import java.util.Vector;
import jj2000.j2k.codestream.CBlkCoordInfo;
import jj2000.j2k.codestream.Markers;
import jj2000.j2k.codestream.PrecInfo;
import jj2000.j2k.decoder.DecoderSpecs;
import jj2000.j2k.entropy.StdEntropyCoderOptions;
import jj2000.j2k.io.RandomAccessIO;
import jj2000.j2k.util.ArrayUtil;
import jj2000.j2k.util.MathUtil;
import jj2000.j2k.wavelet.synthesis.SubbandSyn;
/**
* This class is used to read packet's head and body. All the members must be
* re-initialized at the beginning of each tile thanks to the restart()
* method.
* */
public class PktDecoder implements StdEntropyCoderOptions{
/** Reference to the codestream reader agent */
private BitstreamReaderAgent src;
/** Flag indicating whether packed packet header was used for this tile*/
private boolean pph=false;
/** The packed packet header if it was used */
private ByteArrayInputStream pphbais;
/** Reference to decoder specifications */
private DecoderSpecs decSpec;
/** Reference to the HeaderDecoder */
private HeaderDecoder hd;
/** Initial value of the state variable associated with code-block
* length. */
private final int INIT_LBLOCK = 3;
/** The wrapper to read bits for the packet heads */
private PktHeaderBitReader bin;
/** Reference to the stream where to read from */
private RandomAccessIO ehs;
/**
* Maximum number of precincts :
*
*
* - 1st dim: component index.
* - 2nd dim: resolution level index.
*
* */
private Point[][] numPrec;
/** Index of the current tile */
private int tIdx;
/**
* Array containing the coordinates, width, height, indexes, ... of the
* precincts in the current tile:
*
*
* - 1st dim: component index.
* - 2nd dim: resolution level index.
* - 3rd dim: precinct index.
*
* */
private PrecInfo[][][] ppinfo;
/**
* Lblock value used to read code size information in each packet head:
*
*
* - 1st dim: component index.
* - 2nd dim: resolution level index.
* - 3rd dim: subband index.
* - 4th/5th dim: code-block index (vert. and horiz.).
*
* */
private int[][][][][] lblock;
/**
* Tag tree used to read inclusion informations in packet's head:
*
*
* - 1st dim: component index.
* - 2nd dim: resolution level index.
* - 3rd dim: precinct index.
* - 4th dim: subband index.
* */
private TagTreeDecoder[][][][] ttIncl;
/**
* Tag tree used to read bit-depth information in packet's head:
*
*
* - 1st dim: component index.
* - 2nd dim: resolution level index.
* - 3rd dim: precinct index.
* - 4th dim: subband index.
*
* */
private TagTreeDecoder[][][][] ttMaxBP;
/** Number of layers in t he current tile */
private int nl = 0;
/** The number of components */
private int nc;
/** Whether or not SOP marker segment are used */
private boolean sopUsed = false;
/** Whether or not EPH marker are used */
private boolean ephUsed = false;
/** Index of the current packet in the tile. Used with SOP marker
segment*/
private int pktIdx;
/** List of code-blocks found in last read packet head (one list
* per subband) */
private Vector[] cblks;
/** Number of codeblocks encountered. used for ncb quit condition*/
private int ncb;
/** Maximum number of codeblocks to read before ncb quit condition is
* reached */
private int maxCB;
/** Flag indicating whether ncb quit condition has been reached */
private boolean ncbQuit;
/** The tile in which the ncb quit condition was reached */
private int tQuit;
/** The component in which the ncb quit condition was reached */
private int cQuit;
/** The subband in which the ncb quit condition was reached */
private int sQuit;
/** The resolution in which the ncb quit condition was reached */
private int rQuit;
/** The x position of the last code block before ncb quit reached */
private int xQuit;
/** The y position of the last code block before ncb quit reached */
private int yQuit;
/** True if truncation mode is used. False if it is parsing mode */
private boolean isTruncMode;
/**
* Creates an empty PktDecoder object associated with given decoder
* specifications and HeaderDecoder. This object must be initialized
* thanks to the restart method before being used.
*
* @param decSpec The decoder specifications.
*
* @param hd The HeaderDecoder instance.
*
* @param ehs The stream where to read data from.
*
* @param src The bit stream reader agent.
*
* @param isTruncMode Whether or not truncation mode is required.
*
* @param maxCB The maximum number of code-blocks to read before ncbquit
*
* */
public PktDecoder(DecoderSpecs decSpec,HeaderDecoder hd,
RandomAccessIO ehs,BitstreamReaderAgent src,
boolean isTruncMode, int maxCB) {
this.decSpec = decSpec;
this.hd = hd;
this.ehs = ehs;
this.isTruncMode = isTruncMode;
bin = new PktHeaderBitReader(ehs);
this.src = src;
ncb = 0;
ncbQuit = false;
this.maxCB = maxCB;
}
/**
* Re-initialize the PktDecoder instance at the beginning of a new tile.
*
* @param nc The number of components in this tile
*
* @param mdl The maximum number of decomposition level in each component
* of this tile
*
* @param nl The number of layers in this tile
*
* @param cbI The code-blocks array
*
* @param pph Flag indicating whether packed packet headers was used
*
* @param pphbais Stream containing the packed packet headers
* */
public CBlkInfo[][][][][] restart(int nc,int[] mdl,int nl,
CBlkInfo[][][][][] cbI, boolean pph,
ByteArrayInputStream pphbais) {
this.nc = nc;
this.nl = nl;
this.tIdx = src.getTileIdx();
this.pph = pph;
this.pphbais = pphbais;
sopUsed = ((Boolean)decSpec.sops.getTileDef(tIdx)).booleanValue();
pktIdx = 0;
ephUsed = ((Boolean)decSpec.ephs.getTileDef(tIdx)).booleanValue();
cbI = new CBlkInfo[nc][][][][];
lblock = new int[nc][][][][];
ttIncl = new TagTreeDecoder[nc][][][];
ttMaxBP = new TagTreeDecoder[nc][][][];
numPrec = new Point[nc][];
ppinfo = new PrecInfo[nc][][];
// Used to compute the maximum number of precincts for each resolution
// level
int tcx0, tcy0, tcx1, tcy1; // Current tile position in the domain of
// the image component
int trx0, try0, trx1, try1; // Current tile position in the reduced
// resolution image domain
int xrsiz, yrsiz; // Component sub-sampling factors
SubbandSyn root,sb;
int mins,maxs;
Point nBlk = null;
int cb0x = src.getCbULX();
int cb0y = src.getCbULY();
for(int c=0; ctrx0) {
numPrec[c][r].x = (int)Math.ceil((trx1-cb0x)/twoppx)
- (int)Math.floor((trx0-cb0x)/twoppx);
} else {
numPrec[c][r].x = 0;
}
if (try1>try0) {
numPrec[c][r].y = (int)Math.ceil((try1-cb0y)/twoppy)
- (int)Math.floor((try0-cb0y)/twoppy);
} else {
numPrec[c][r].y = 0;
}
// First and last subbands indexes
mins = (r==0) ? 0 : 1;
maxs = (r==0) ? 1 : 4;
int maxPrec = numPrec[c][r].x * numPrec[c][r].y;
ttIncl[c][r] = new TagTreeDecoder[maxPrec][maxs+1];
ttMaxBP[c][r] = new TagTreeDecoder[maxPrec][maxs+1];
cbI[c][r] = new CBlkInfo[maxs+1][][];
lblock[c][r] = new int[maxs+1][][];
ppinfo[c][r] = new PrecInfo[maxPrec];
fillPrecInfo(c,r,mdl[c]);
root = (SubbandSyn)src.getSynSubbandTree(tIdx,c);
for(int s=mins; s=0;i--) {
ArrayUtil.intArraySet(lblock[c][r][s][i],INIT_LBLOCK);
}
} // loop on subbands
} // End loop on resolution levels
} // End loop on components
return cbI;
}
/**
* Retrives precincts and code-blocks coordinates in the given resolution,
* level and component. Finishes TagTreeEncoder initialization as well.
*
* @param c Component index.
*
* @param r Resolution level index.
*
* @param mdl Number of decomposition level in component c.
* */
private void fillPrecInfo(int c,int r,int mdl) {
if(ppinfo[c][r].length==0) return; // No precinct in this
// resolution level
Point tileI = src.getTile(null);
Point nTiles = src.getNumTiles(null);
int xsiz,ysiz,x0siz,y0siz;
int xt0siz,yt0siz;
int xtsiz,ytsiz;
xt0siz = src.getTilePartULX();
yt0siz = src.getTilePartULY();
xtsiz = src.getNomTileWidth();
ytsiz = src.getNomTileHeight();
x0siz = hd.getImgULX();
y0siz = hd.getImgULY();
xsiz = hd.getImgWidth();
ysiz = hd.getImgHeight();
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;
int xrsiz = hd.getCompSubsX(c);
int yrsiz = hd.getCompSubsY(c);
int tcx0 = src.getResULX(c,mdl);
int tcy0 = src.getResULY(c,mdl);
int tcx1 = tcx0 + src.getTileCompWidth(tIdx,c,mdl);
int tcy1 = tcy0 + src.getTileCompHeight(tIdx,c,mdl);
int ndl = mdl-r;
int trx0 = (int)Math.ceil(tcx0/(double)(1<sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x;
s0y = (p0ysb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y;
// Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
cw = sb.nomCBlkW;
ch = sb.nomCBlkH;
k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch);
kstart = (int)Math.floor((s0y-acb0y)/(double)ch);
kend = (int)Math.floor((s1y-1-acb0y)/(double)ch);
l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw);
lstart = (int)Math.floor((s0x-acb0x)/(double)cw);
lend = (int)Math.floor((s1x-1-acb0x)/(double)cw);
if(s1x-s0x<=0 || s1y-s0y<=0) {
ppinfo[c][r][nPrec].nblk[0] = 0;
ttIncl[c][r][nPrec][0] = new TagTreeDecoder(0,0);
ttMaxBP[c][r][nPrec][0] = new TagTreeDecoder(0,0);
} else {
ttIncl[c][r][nPrec][0] =
new TagTreeDecoder(kend-kstart+1,lend-lstart+1);
ttMaxBP[c][r][nPrec][0] =
new TagTreeDecoder(kend-kstart+1,lend-lstart+1);
ppinfo[c][r][nPrec].cblk[0] =
new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
ppinfo[c][r][nPrec].
nblk[0] = (kend-kstart+1)*(lend-lstart+1);
for(int k=kstart; k<=kend; k++) { // Vertical cblks
for(int l=lstart; l<=lend; l++) { // Horiz. cblks
cb = new CBlkCoordInfo(k-k0,l-l0);
if(l==l0) {
cb.ulx = sb.ulx;
} else {
cb.ulx = sb.ulx+l*cw-(sb.ulcx-acb0x);
}
if(k==k0) {
cb.uly = sb.uly;
} else {
cb.uly = sb.uly+k*ch-(sb.ulcy-acb0y);
}
tmp1 = acb0x+l*cw;
tmp1 = (tmp1>sb.ulcx) ? tmp1 : sb.ulcx;
tmp2 = acb0x+(l+1)*cw;
tmp2 = (tmp2>sb.ulcx+sb.w) ?
sb.ulcx+sb.w : tmp2;
cb.w = tmp2-tmp1;
tmp1 = acb0y+k*ch;
tmp1 = (tmp1>sb.ulcy) ? tmp1 : sb.ulcy;
tmp2 = acb0y+(k+1)*ch;
tmp2 = (tmp2>sb.ulcy+sb.h) ?
sb.ulcy+sb.h : tmp2;
cb.h = tmp2-tmp1;
ppinfo[c][r][nPrec].
cblk[0][k-kstart][l-lstart] = cb;
} // Horizontal code-blocks
} // Vertical code-blocks
}
} else { // HL, LH and HH subbands
// HL subband
acb0x = 0;
acb0y = cb0y;
p0x = acb0x+j*twoppx2;
p1x = p0x + twoppx2;
p0y = acb0y+i*twoppy2;
p1y = p0y + twoppy2;
sb = (SubbandSyn)root.getSubbandByIdx(r,1);
s0x = (p0xsb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x;
s0y = (p0ysb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y;
// Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
cw = sb.nomCBlkW;
ch = sb.nomCBlkH;
k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch);
kstart = (int)Math.floor((s0y-acb0y)/(double)ch);
kend = (int)Math.floor((s1y-1-acb0y)/(double)ch);
l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw);
lstart = (int)Math.floor((s0x-acb0x)/(double)cw);
lend = (int)Math.floor((s1x-1-acb0x)/(double)cw);
if(s1x-s0x<=0 || s1y-s0y<=0) {
ppinfo[c][r][nPrec].nblk[1] = 0;
ttIncl[c][r][nPrec][1] = new TagTreeDecoder(0,0);
ttMaxBP[c][r][nPrec][1] = new TagTreeDecoder(0,0);
} else {
ttIncl[c][r][nPrec][1] =
new TagTreeDecoder(kend-kstart+1,lend-lstart+1);
ttMaxBP[c][r][nPrec][1] =
new TagTreeDecoder(kend-kstart+1,lend-lstart+1);
ppinfo[c][r][nPrec].cblk[1] =
new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
ppinfo[c][r][nPrec].
nblk[1] = (kend-kstart+1)*(lend-lstart+1);
for(int k=kstart; k<=kend; k++) { // Vertical cblks
for(int l=lstart; l<=lend; l++) { // Horiz. cblks
cb = new CBlkCoordInfo(k-k0,l-l0);
if(l==l0) {
cb.ulx = sb.ulx;
} else {
cb.ulx = sb.ulx+l*cw-(sb.ulcx-acb0x);
}
if(k==k0) {
cb.uly = sb.uly;
} else {
cb.uly = sb.uly+k*ch-(sb.ulcy-acb0y);
}
tmp1 = acb0x+l*cw;
tmp1 = (tmp1>sb.ulcx) ? tmp1 : sb.ulcx;
tmp2 = acb0x+(l+1)*cw;
tmp2 = (tmp2>sb.ulcx+sb.w) ?
sb.ulcx+sb.w : tmp2;
cb.w = tmp2-tmp1;
tmp1 = acb0y+k*ch;
tmp1 = (tmp1>sb.ulcy) ? tmp1 : sb.ulcy;
tmp2 = acb0y+(k+1)*ch;
tmp2 = (tmp2>sb.ulcy+sb.h) ?
sb.ulcy+sb.h : tmp2;
cb.h = tmp2-tmp1;
ppinfo[c][r][nPrec].
cblk[1][k-kstart][l-lstart] = cb;
} // Horizontal code-blocks
} // Vertical code-blocks
}
// LH subband
acb0x = cb0x;
acb0y = 0;
p0x = acb0x+j*twoppx2;
p1x = p0x + twoppx2;
p0y = acb0y+i*twoppy2;
p1y = p0y + twoppy2;
sb = (SubbandSyn)root.getSubbandByIdx(r,2);
s0x = (p0xsb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x;
s0y = (p0ysb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y;
// Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
cw = sb.nomCBlkW;
ch = sb.nomCBlkH;
k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch);
kstart = (int)Math.floor((s0y-acb0y)/(double)ch);
kend = (int)Math.floor((s1y-1-acb0y)/(double)ch);
l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw);
lstart = (int)Math.floor((s0x-acb0x)/(double)cw);
lend = (int)Math.floor((s1x-1-acb0x)/(double)cw);
if(s1x-s0x<=0 || s1y-s0y<=0) {
ppinfo[c][r][nPrec].nblk[2] = 0;
ttIncl[c][r][nPrec][2] = new TagTreeDecoder(0,0);
ttMaxBP[c][r][nPrec][2] = new TagTreeDecoder(0,0);
} else {
ttIncl[c][r][nPrec][2] =
new TagTreeDecoder(kend-kstart+1,lend-lstart+1);
ttMaxBP[c][r][nPrec][2] =
new TagTreeDecoder(kend-kstart+1,lend-lstart+1);
ppinfo[c][r][nPrec].cblk[2] =
new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
ppinfo[c][r][nPrec].
nblk[2] = (kend-kstart+1)*(lend-lstart+1);
for(int k=kstart; k<=kend; k++) { // Vertical cblks
for(int l=lstart; l<=lend; l++) { // Horiz cblks
cb = new CBlkCoordInfo(k-k0,l-l0);
if(l==l0) {
cb.ulx = sb.ulx;
} else {
cb.ulx = sb.ulx+l*cw-(sb.ulcx-acb0x);
}
if(k==k0) {
cb.uly = sb.uly;
} else {
cb.uly = sb.uly+k*ch-(sb.ulcy-acb0y);
}
tmp1 = acb0x+l*cw;
tmp1 = (tmp1>sb.ulcx) ? tmp1 : sb.ulcx;
tmp2 = acb0x+(l+1)*cw;
tmp2 = (tmp2>sb.ulcx+sb.w) ?
sb.ulcx+sb.w : tmp2;
cb.w = tmp2-tmp1;
tmp1 = acb0y+k*ch;
tmp1 = (tmp1>sb.ulcy) ? tmp1 : sb.ulcy;
tmp2 = acb0y+(k+1)*ch;
tmp2 = (tmp2>sb.ulcy+sb.h) ?
sb.ulcy+sb.h : tmp2;
cb.h = tmp2-tmp1;
ppinfo[c][r][nPrec].
cblk[2][k-kstart][l-lstart] = cb;
} // Horizontal code-blocks
} // Vertical code-blocks
}
// HH subband
acb0x = 0;
acb0y = 0;
p0x = acb0x+j*twoppx2;
p1x = p0x + twoppx2;
p0y = acb0y+i*twoppy2;
p1y = p0y + twoppy2;
sb = (SubbandSyn)root.getSubbandByIdx(r,3);
s0x = (p0xsb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x;
s0y = (p0ysb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y;
// Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
cw = sb.nomCBlkW;
ch = sb.nomCBlkH;
k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch);
kstart = (int)Math.floor((s0y-acb0y)/(double)ch);
kend = (int)Math.floor((s1y-1-acb0y)/(double)ch);
l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw);
lstart = (int)Math.floor((s0x-acb0x)/(double)cw);
lend = (int)Math.floor((s1x-1-acb0x)/(double)cw);
if(s1x-s0x<=0 || s1y-s0y<=0) {
ppinfo[c][r][nPrec].nblk[3] = 0;
ttIncl[c][r][nPrec][3] = new TagTreeDecoder(0,0);
ttMaxBP[c][r][nPrec][3] = new TagTreeDecoder(0,0);
} else {
ttIncl[c][r][nPrec][3] =
new TagTreeDecoder(kend-kstart+1,lend-lstart+1);
ttMaxBP[c][r][nPrec][3] =
new TagTreeDecoder(kend-kstart+1,lend-lstart+1);
ppinfo[c][r][nPrec].cblk[3] =
new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
ppinfo[c][r][nPrec].
nblk[3] = (kend-kstart+1)*(lend-lstart+1);
for(int k=kstart; k<=kend; k++) { // Vertical cblks
for(int l=lstart; l<=lend; l++) { // Horiz cblks
cb = new CBlkCoordInfo(k-k0,l-l0);
if(l==l0) {
cb.ulx = sb.ulx;
} else {
cb.ulx = sb.ulx+l*cw-(sb.ulcx-acb0x);
}
if(k==k0) {
cb.uly = sb.uly;
} else {
cb.uly = sb.uly+k*ch-(sb.ulcy-acb0y);
}
tmp1 = acb0x+l*cw;
tmp1 = (tmp1>sb.ulcx) ? tmp1 : sb.ulcx;
tmp2 = acb0x+(l+1)*cw;
tmp2 = (tmp2>sb.ulcx+sb.w) ?
sb.ulcx+sb.w : tmp2;
cb.w = tmp2-tmp1;
tmp1 = acb0y+k*ch;
tmp1 = (tmp1>sb.ulcy) ? tmp1 : sb.ulcy;
tmp2 = acb0y+(k+1)*ch;
tmp2 = (tmp2>sb.ulcy+sb.h) ?
sb.ulcy+sb.h : tmp2;
cb.h = tmp2-tmp1;
ppinfo[c][r][nPrec].
cblk[3][k-kstart][l-lstart] = cb;
} // Horizontal code-blocks
} // Vertical code-blocks
}
}
} // Horizontal precincts
} // Vertical precincts
}
/**
* Gets the number of precincts in a given component and resolution level.
*
* @param c Component index
*
* @param r Resolution index
* */
public int getNumPrecinct(int c,int r) {
return numPrec[c][r].x*numPrec[c][r].y;
}
/**
* Read specified packet head and found length of each code-block's piece
* of codewords as well as number of skipped most significant bit-planes.
*
* @param l layer index
*
* @param r Resolution level index
*
* @param c Component index
*
* @param p Precinct index
*
* @param cbI CBlkInfo array of relevant component and resolution
* level.
*
* @param nb The number of bytes to read in each tile before reaching
* output rate (used by truncation mode)
*
* @return True if specified output rate or EOF is reached.
* */
public boolean readPktHead(int l,int r,int c,int p,CBlkInfo[][][] cbI,
int[] nb) throws IOException {
CBlkInfo ccb;
int nSeg; // number of segment to read
int cbLen; // Length of cblk's code-words
int ltp; // last truncation point index
int passtype; // coding pass type
TagTreeDecoder tdIncl,tdBD;
int tmp,tmp2,totnewtp,lblockCur,tpidx;
int sumtotnewtp = 0;
Point cbc;
int startPktHead = ehs.getPos();
if(startPktHead>=ehs.length()) {
// EOF reached at the beginning of this packet head
return true;
}
int tIdx = src.getTileIdx();
PktHeaderBitReader bin;
int mend,nend;
int b;
SubbandSyn sb;
SubbandSyn root = src.getSynSubbandTree(tIdx,c);
// If packed packet headers was used, use separate stream for reading
// of packet headers
if(pph) {
bin = new PktHeaderBitReader(pphbais);
} else {
bin = this.bin;
}
int mins = (r==0) ? 0 : 1;
int maxs = (r==0) ? 1 : 4;
boolean precFound = false;
for(int s=mins; snb[tIdx]) {
nb[tIdx] = 0;
return true;
} else {
nb[tIdx] -= tmp;
}
}
// Read EPH marker if needed
if(ephUsed) {
readEPHMarker(bin);
}
return false;
}
// Packet is not empty => decode info
// Loop on each subband in this resolution level
if(cblks==null || cblks.lengthl) { // Not included
continue;
}
// Read bitdepth using tag-tree
tmp = 1;// initialization
for(tmp2=1; tmp>=tmp2; tmp2++) {
tmp = tdBD.update(m,n,tmp2,bin);
}
ccb.msbSkipped = tmp2-2;
// New code-block => at least one truncation point
totnewtp = 1;
ccb.addNTP(l,0);
// Check whether ncb quit condition is reached
ncb++;
if(maxCB != -1 && !ncbQuit && ncb == maxCB){
// ncb quit contidion reached
ncbQuit = true;
tQuit = tIdx;
cQuit = c;
sQuit = s;
rQuit = r;
xQuit = cbc.x;
yQuit = cbc.y;
}
} else { // If code-block already included in one of
// the previous layers.
ccb.pktIdx[l] = pktIdx;
// If not inclused
if(bin.readBit()!=1) {
continue;
}
// At least 1 more truncation point than
// prev. packet
totnewtp = 1;
}
// Read new truncation points
if(bin.readBit()==1) {// if bit is 1
totnewtp++;
// if next bit is 0 do nothing
if(bin.readBit()==1) {//if is 1
totnewtp++;
tmp = bin.readBits(2);
totnewtp += tmp;
// If next 2 bits are not 11 do nothing
if(tmp==0x3) { //if 11
tmp = bin.readBits(5);
totnewtp += tmp;
// If next 5 bits are not 11111 do nothing
if(tmp==0x1F) { //if 11111
totnewtp += bin.readBits(7);
}
}
}
}
ccb.addNTP(l,totnewtp);
sumtotnewtp += totnewtp;
cblks[s].addElement(prec.cblk[s][m][n]);
// Code-block length
// -- Compute the number of bit to read to obtain
// code-block length.
// numBits = betaLamda + log2(totnewtp);
// The length is signalled for each segment in
// addition to the final one. The total length is the
// sum of all segment lengths.
// If regular termination in use, then there is one
// segment per truncation point present. Otherwise, if
// selective arithmetic bypass coding mode is present,
// then there is one termination per bypass/MQ and
// MQ/bypass transition. Otherwise the only
// termination is at the end of the code-block.
int options =
((Integer)decSpec.ecopts.getTileCompVal(tIdx,c)).
intValue();
if( (options&OPT_TERM_PASS) != 0) {
// Regular termination in use, one segment per new
// pass (i.e. truncation point)
nSeg = totnewtp;
} else if( (options&OPT_BYPASS) != 0) {
// Selective arithmetic coding bypass coding mode
// in use, but no regular termination 1 segment up
// to 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.ctp<=FIRST_BYPASS_PASS_IDX) {
nSeg = 1;
} else {
nSeg = 1; // One at least for last pass
// And one for each other terminated pass
for(tpidx = ccb.ctp-totnewtp;
tpidx < ccb.ctp-1; tpidx++) {
if(tpidx >= FIRST_BYPASS_PASS_IDX-1) {
passtype =
(tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%
NUM_PASSES;
if (passtype==1 || passtype==2) {
// bypass coding just before MQ
// pass or MQ pass just before
// bypass coding => terminated
nSeg++;
}
}
}
}
} else {
// Nothing special in use, just one segment
nSeg = 1;
}
// Reads lblock increment (common to all segments)
while(bin.readBit()!=0) {
lblock[c][r][s][cbc.y][cbc.x]++;
}
if(nSeg==1) { // Only one segment in packet
cbLen = bin.readBits(lblock[c][r][s][cbc.y][cbc.x]+
MathUtil.log2(totnewtp));
} else {
// We must read one length per segment
ccb.segLen[l] = new int[nSeg];
cbLen = 0;
int j;
if((options&OPT_TERM_PASS) != 0) {
// Regular termination: each pass is terminated
for(tpidx=ccb.ctp-totnewtp,j=0;
tpidx= FIRST_BYPASS_PASS_IDX-1) {
passtype =
(tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%
NUM_PASSES;
if (passtype==0) continue;
lblockCur =
lblock[c][r][s][cbc.y][cbc.x];
tmp =
bin.
readBits(lblockCur+
MathUtil.log2(tpidx-ltp));
ccb.segLen[l][j] = tmp;
cbLen += tmp;
ltp = tpidx;
j++;
}
}
// Last pass has always the length sent
lblockCur = lblock[c][r][s][cbc.y][cbc.x];
tmp = bin.readBits(lblockCur+
MathUtil.log2(tpidx-ltp));
cbLen += tmp;
ccb.segLen[l][j] = tmp;
}
}
ccb.len[l] = cbLen;
// If truncation mode, checks if output rate is reached
// unless ncb and lbody quit contitions used.
if(isTruncMode && maxCB==-1) {
tmp = ehs.getPos()-startPktHead;
if(tmp>nb[tIdx]) {
nb[tIdx] = 0;
// Remove found information in this code-block
if(l==0) {
cbI[s][cbc.y][cbc.x] = null;
} else {
ccb.off[l]=ccb.len[l]=0;
ccb.ctp -= ccb.ntp[l];
ccb.ntp[l] = 0;
ccb.pktIdx[l] = -1;
}
return true;
}
}
} catch(EOFException e) {
// Remove found information in this code-block
if(l==0) {
cbI[s][cbc.y][cbc.x] = null;
} else {
ccb.off[l]=ccb.len[l]=0;
ccb.ctp -= ccb.ntp[l];
ccb.ntp[l] = 0;
ccb.pktIdx[l] = -1;
}
// throw new EOFException();
return true;
}
} // End loop on horizontal code-blocks
} // End loop on vertical code-blocks
} // End loop on subbands
// Read EPH marker if needed
if(ephUsed) {
readEPHMarker(bin);
}
pktIdx++;
// If truncation mode, checks if output rate is reached
if(isTruncMode && maxCB == -1) {
tmp = ehs.getPos()-startPktHead;
if(tmp>nb[tIdx]) {
nb[tIdx] = 0;
return true;
} else {
nb[tIdx] -= tmp;
}
}
return false;
}
/**
* Reads specificied packet body in order to find offset of each
* code-block's piece of codeword. This use the list of found code-blocks
* in previous red packet head.
*
* @param l layer index
*
* @param r Resolution level index
*
* @param c Component index
*
* @param p Precinct index
*
* @param cbI CBlkInfo array of relevant component and resolution
* level.
*
* @param nb The remainding number of bytes to read from the bit stream in
* each tile before reaching the decoding rate (in truncation mode)
*
* @return True if decoding rate is reached
* */
public boolean readPktBody(int l,int r,int c,int p,CBlkInfo[][][] cbI,
int[] nb) throws IOException {
int curOff = ehs.getPos();
Point curCB;
CBlkInfo ccb;
boolean stopRead = false;
int tIdx = src.getTileIdx();
Point cbc;
boolean precFound = false;
int mins = (r==0) ? 0 : 1;
int maxs = (r==0) ? 1 : 4;
for(int s=mins; snb[tIdx]) {
// Remove found information in this code-block
if(l==0) {
cbI[s][cbc.y][cbc.x] = null;
} else {
ccb.off[l] = ccb.len[l] = 0;
ccb.ctp -= ccb.ntp[l];
ccb.ntp[l] = 0;
ccb.pktIdx[l] = -1;
}
stopRead = true;
}
if(!stopRead) {
nb[tIdx] -= ccb.len[l];
}
}
// If ncb quit condition reached
if(ncbQuit && r == rQuit && s == sQuit && cbc.x == xQuit &&
cbc.y == yQuit && tIdx == tQuit && c == cQuit) {
cbI[s][cbc.y][cbc.x] = null;
stopRead = true;
}
} // Loop on code-blocks
} // End loop on subbands
// Seek to the end of the packet
ehs.seek(curOff);
if(stopRead) {
return true;
} else {
return false;
}
}
/**
* Returns the precinct partition width for the specified component,
* resolution level and tile.
*
* @param t the tile index
*
* @param c The index of the component (between 0 and C-1)
*
* @param r The resolution level, from 0 to L.
*
* @return the precinct partition width for the specified component,
* resolution level and tile.
* */
public final int getPPX(int t,int c,int r){
return decSpec.pss.getPPX(t,c,r);
}
/**
* Returns the precinct partition height for the specified component,
* resolution level and tile.
*
* @param t the tile index
*
* @param c The index of the component (between 0 and C-1)
*
* @param rl The resolution level, from 0 to L.
*
* @return the precinct partition height in the specified component, for
* the specified resolution level, for the current tile.
* */
public final int getPPY(int t,int c,int rl) {
return decSpec.pss.getPPY(t,c,rl);
}
/**
* Try to read a SOP marker and check that its sequence number if not out
* of sequence. If so, an error is thrown.
*
* @param nBytes The number of bytes left to read from each tile
*
* @param p Precinct index
*
* @param r Resolution level index
*
* @param c Component index
* */
public boolean readSOPMarker(int[] nBytes,int p,int c,int r)
throws IOException {
int val;
byte sopArray[] = new byte[6];
int tIdx = src.getTileIdx();
int mins = (r==0) ? 0 : 1;
int maxs = (r==0) ? 1 : 4;
boolean precFound = false;
for(int s=mins; s