jj2000.j2k.codestream.writer.PktEncoder Maven / Gradle / Ivy
Show all versions of jai-imageio-jpeg2000 Show documentation
/*
* $RCSfile: PktEncoder.java,v $
* $Revision: 1.1 $
* $Date: 2005/02/11 05:02:03 $
* $State: Exp $
*
* Class: PktEncoder
*
* Description: Builds bit stream packets and keeps
* interpacket dependencies.
*
*
*
* 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.writer;
import java.awt.Point;
import java.util.Vector;
import jj2000.j2k.codestream.CBlkCoordInfo;
import jj2000.j2k.codestream.PrecInfo;
import jj2000.j2k.entropy.encoder.CBlkRateDistStats;
import jj2000.j2k.entropy.encoder.CodedCBlkDataSrcEnc;
import jj2000.j2k.util.ArrayUtil;
import jj2000.j2k.util.MathUtil;
import jj2000.j2k.wavelet.analysis.SubbandAn;
import com.github.jaiimageio.jpeg2000.impl.J2KImageWriteParamJava;
/**
* This class builds packets and keeps the state information of packet
* interdependencies. It also supports saving the state and reverting
* (restoring) to the last saved state, with the save() and restore() methods.
*
* Each time the encodePacket() method is called a new packet is encoded,
* the packet header is returned by the method, and the packet body can be
* obtained with the getLastBodyBuf() and getLastBodyLen() methods.
* */
public class PktEncoder {
/** The prefix for packet encoding options: 'P' */
public final static char OPT_PREFIX = 'P';
/** The list of parameters that is accepted for packet encoding.*/
private final static String [][] pinfo = {
{ "Psop", "[] true|false"+
"[ [] true|false ...]",
"Specifies whether start of packet (SOP) markers should be used. "+
"'true' enables, 'false' disables it.","false"},
{ "Peph", "[] true|false"+
"[ [] true|false ...]",
"Specifies whether end of packet header (EPH) markers should be "+
" used. 'true' enables, 'false' disables it.","false"}
};
/** The initial value for the lblock */
private final static int INIT_LBLOCK = 3;
/** The source object */
private CodedCBlkDataSrcEnc infoSrc;
/** The encoder specs */
J2KImageWriteParamJava wp;
/**
* The tag tree for inclusion information. The indexes are outlined
* below. Note that the layer indexes start at 1, therefore, the layer
* index minus 1 is used. The subband indices are used as they are defined
* in the Subband class. The tile indices start at 0 and follow a
* lexicographical order.
*
*
* - 1st index: tile index, in lexicographical order
* - 2nd index: component index
* - 3rd index: resolution level
* - 4th index: subband index
* - 5th index: precinct index
*
**/
private TagTreeEncoder ttIncl[][][][][];
/**
* The tag tree for the maximum significant bit-plane. The indexes are
* outlined below. Note that the layer indexes start at 1, therefore, the
* layer index minus 1 is used. The subband indices are used as they are
* defined in the Subband class. The tile indices start at 0 and follow a
* lexicographical order.
*
*
* - 1st index: tile index, in lexicographical order
* - 2nd index: component index
* - 3rd index: resolution level
* - 4th index: subband index - subband index offset
* - 5th index: precinct index
*
* */
private TagTreeEncoder ttMaxBP[][][][][];
/**
* The base number of bits for sending code-block length information
* (referred as Lblock in the JPEG 2000 standard). The indexes are
* outlined below. Note that the layer indexes start at 1, therefore, the
* layer index minus 1 is used. The subband indices are used as they are
* defined in the Subband class. The tile indices start at 0 and follow a
* lexicographical order.
*
*
* - 1st index: tile index, in lexicographical order
* - 2nd index: component index
* - 3rd index: resolution level
* - 4th index: subband index - subband index offset
* - 5th index: code-block index, in lexicographical order
*
* */
private int lblock[][][][][];
/**
* The last encoded truncation point for each code-block. A negative value
* means that no information has been included for the block, yet. The
* indexes are outlined below. The subband indices are used as they are
* defined in the Subband class. The tile indices start at 0 and follow a
* lexicographical order. The code-block indices follow a lexicographical
* order within the subband tile.
*
* What is actually stored is the index of the element in
* CBlkRateDistStats.truncIdxs that gives the real truncation point.
*
*
* - 1st index: tile index, in lexicographical order
* - 2nd index: component index
* - 3rd index: resolution level
* - 4th index: subband index - subband index offset
* - 5th index: code-block index, in lexicographical order
*
* */
private int prevtIdxs[][][][][];
/**
* The saved base number of bits for sending code-block length
* information. It is used for restoring previous saved state by
* restore(). The indexes are outlined below. Note that the layer indexes
* start at 1, therefore, the layer index minus 1 is used. The subband
* indices are used as they are defined in the Subband class. The tile
* indices start at 0 and follow a lexicographical order.
*
*
* - 1st index: tile index, in lexicographical order
* - 2nd index: component index
* - 3rd index: resolution level
* - 4th index: subband index - subband index offset
* - 5th index: code-block index, in lexicographical order
*
* */
private int bak_lblock[][][][][];
/**
* The saved last encoded truncation point for each code-block. It is used
* for restoring previous saved state by restore(). A negative value means
* that no information has been included for the block, yet. The indexes
* are outlined below. The subband indices are used as they are defined in
* the Subband class. The tile indices start at 0 and follow a
* lexicographical order. The code-block indices follow a lexicographical
* order within the subband tile.
*
*
* - 1st index: tile index, in lexicographical order
* - 2nd index: component index
* - 3rd index: resolution level
* - 4th index: subband index - subband index offset
* - 5th index: code-block index, in lexicographical order
*
* */
private int bak_prevtIdxs[][][][][];
/** The body buffer of the last encoded packet */
private byte[] lbbuf;
/** The body length of the last encoded packet */
private int lblen;
/** The saved state */
private boolean saved;
/** Whether or not there is ROI information in the last encoded Packet */
private boolean roiInPkt = false;
/** Length to read in current packet body to get all the ROI information */
private int roiLen = 0;
/**
* Array containing the coordinates, width, height, indexes, ... of the
* precincts.
*
*
* - 1st dim: tile index.
* - 2nd dim: component index.
* - 3rd dim: resolution level index.
* - 4th dim: precinct index.
*
* */
private PrecInfo ppinfo[][][][];
/** Whether or not the current packet is writable */
private boolean packetWritable;
/**
* Creates a new packet header encoder, using the information from the
* 'infoSrc' object. The information used is the number of components,
* number of tiles, subband decomposition, etc.
*
* Note that this constructor visits all the tiles in the 'infoSrc'
* object. The 'infoSrc' object is left at the original tile (i.e. the
* current tile before calling this constructor), but any side effects of
* visiting the tiles is not reverted.
*
* @param infoSrc The source of information to construct the
* object.
*
* @param encSpec The parameters for the encoding
*
* @param maxNumPrec Maximum number of precinct in each tile, component
* and resolution level.
*
* @param pl ParameterList instance that holds command line options
* */
public PktEncoder(CodedCBlkDataSrcEnc infoSrc, J2KImageWriteParamJava wp,
Point[][][] numPrec) {
this.infoSrc = infoSrc;
this.wp = wp;
// this.numPrec = numPrec;
// Get number of components and tiles
int nc = infoSrc.getNumComps();
int nt = infoSrc.getNumTiles();
// Do initial allocation
ttIncl = new TagTreeEncoder[nt][nc][][][];
ttMaxBP = new TagTreeEncoder[nt][nc][][][];
lblock = new int[nt][nc][][][];
prevtIdxs = new int[nt][nc][][][];
ppinfo = new PrecInfo[nt][nc][][];
// Finish allocation
SubbandAn root,sb;
int maxs,mins;
int mrl;
Point tmpCoord = null;
int numcb; // Number of code-blocks
Vector cblks = null;
infoSrc.setTile(0,0);
for (int t=0; tsb.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[t][c][r][nPrec].nblk[0] = 0;
ttIncl[t][c][r][nPrec][0] = new TagTreeEncoder(0,0);
ttMaxBP[t][c][r][nPrec][0] = new TagTreeEncoder(0,0);
} else {
ttIncl[t][c][r][nPrec][0] =
new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
ttMaxBP[t][c][r][nPrec][0] =
new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
ppinfo[t][c][r][nPrec].cblk[0] =
new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
ppinfo[t][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);
ppinfo[t][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 = (SubbandAn)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[t][c][r][nPrec].nblk[1] = 0;
ttIncl[t][c][r][nPrec][1] = new TagTreeEncoder(0,0);
ttMaxBP[t][c][r][nPrec][1] = new TagTreeEncoder(0,0);
} else {
ttIncl[t][c][r][nPrec][1] =
new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
ttMaxBP[t][c][r][nPrec][1] =
new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
ppinfo[t][c][r][nPrec].cblk[1] =
new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
ppinfo[t][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);
ppinfo[t][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 = (SubbandAn)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[t][c][r][nPrec].nblk[2] = 0;
ttIncl[t][c][r][nPrec][2] = new TagTreeEncoder(0,0);
ttMaxBP[t][c][r][nPrec][2] = new TagTreeEncoder(0,0);
} else {
ttIncl[t][c][r][nPrec][2] =
new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
ttMaxBP[t][c][r][nPrec][2] =
new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
ppinfo[t][c][r][nPrec].cblk[2] =
new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
ppinfo[t][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);
ppinfo[t][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 = (SubbandAn)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[t][c][r][nPrec].nblk[3] = 0;
ttIncl[t][c][r][nPrec][3] = new TagTreeEncoder(0,0);
ttMaxBP[t][c][r][nPrec][3] = new TagTreeEncoder(0,0);
} else {
ttIncl[t][c][r][nPrec][3] =
new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
ttMaxBP[t][c][r][nPrec][3] =
new TagTreeEncoder(kend-kstart+1,lend-lstart+1);
ppinfo[t][c][r][nPrec].cblk[3] =
new CBlkCoordInfo[kend-kstart+1][lend-lstart+1];
ppinfo[t][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);
ppinfo[t][c][r][nPrec].
cblk[3][k-kstart][l-lstart] = cb;
} // Horizontal code-blocks
} // Vertical code-blocks
}
}
} // Horizontal precincts
} // Vertical precincts
}
/**
* Encodes a packet and returns the buffer containing the encoded packet
* header. The code-blocks appear in a 3D array of CBlkRateDistStats,
* 'cbs'. The first index is the tile index in lexicographical order, the
* second index is the subband index (as defined in the Subband class),
* and the third index is the code-block index (whithin the subband tile)
* in lexicographical order as well. The indexes of the new truncation
* points for each code-block are specified by the 3D array of int
* 'tIndx'. The indices of this array are the same as for cbs. The
* truncation point indices in 'tIndx' are the indices of the elements of
* the 'truncIdxs' array, of the CBlkRateDistStats class, that give the
* real truncation points. If a truncation point index is negative it
* means that the code-block has not been included in any layer yet. If
* the truncation point is less than or equal to the highest truncation
* point used in previous layers then the code-block is not included in
* the packet. Otherwise, if larger, the code-block is included in the
* packet. The body of the packet can be obtained with the
* getLastBodyBuf() and getLastBodyLen() methods.
*
* Layers must be coded in increasing order, in consecutive manner, for
* each tile, component and resolution level (e.g., layer 1, then layer 2,
* etc.). For different tile, component and/or resolution level no
* particular order must be followed.
*
* @param ly The layer index (starts at 1).
*
* @param c The component index.
*
* @param r The resolution level
*
* @param t Index of the current tile
*
* @param cbs The 3D array of coded code-blocks.
*
* @param tIndx The truncation point indices for each code-block.
*
* @param hbuf The header buffer. If null a new BitOutputBuffer is created
* and returned. This buffer is reset before anything is written to it.
*
* @param bbuf The body buffer. If null a new one is created. If not large
* enough a new one is created.
*
* @param pIdx The precinct index.
*
* @return The buffer containing the packet header.
* */
public BitOutputBuffer encodePacket(int ly,int c,int r,int t,
CBlkRateDistStats cbs[][],
int tIndx[][],BitOutputBuffer hbuf,
byte bbuf[],int pIdx) {
int b,i,maxi;
int ncb;
int thmax;
int newtp;
int cblen;
int prednbits,nbits,deltabits;
TagTreeEncoder cur_ttIncl,cur_ttMaxBP; // inclusion and bit-depth tag
// trees
int cur_prevtIdxs[]; // last encoded truncation points
CBlkRateDistStats cur_cbs[];
int cur_tIndx[]; // truncation points to encode
int minsb = (r==0) ? 0 : 1;
int maxsb = (r==0) ? 1 : 4;
Point cbCoord = null;
SubbandAn root = infoSrc.getAnSubbandTree(t,c);
SubbandAn sb;
roiInPkt = false;
roiLen = 0;
int mend,nend;
// Checks if a precinct with such an index exists in this resolution
// level
if(pIdx>=ppinfo[t][c][r].length) {
packetWritable = false;
return hbuf;
}
PrecInfo prec = ppinfo[t][c][r][pIdx];
// First, we check if packet is empty (i.e precinct 'pIdx' has no
// code-block in any of the subbands)
boolean isPrecVoid = true;
for(int s=minsb; s
// stop
isPrecVoid = false;
break;
}
}
if(isPrecVoid) {
packetWritable = true;
if(hbuf == null) {
hbuf = new BitOutputBuffer();
} else {
hbuf.reset();
}
if (bbuf == null) {
lbbuf = bbuf = new byte[1];
}
hbuf.writeBit(0);
lblen = 0;
return hbuf;
}
if(hbuf == null) {
hbuf = new BitOutputBuffer();
} else {
hbuf.reset();
}
// Invalidate last body buffer
lbbuf = null;
lblen = 0;
// Signal that packet is present
hbuf.writeBit(1);
for(int s=minsb; scur_prevtIdxs[b] && cur_prevtIdxs[b]<0) {
// First inclusion
cur_ttIncl.setValue(m,n,ly-1);
}
if (ly==1) { // First layer, need to set the skip of MSBP
cur_ttMaxBP.setValue(m,n,cur_cbs[b].skipMSBP);
}
}
}
// Now encode the information
for(int m=0; mcur_prevtIdxs[b]) {
// Code-block included in this layer
if (cur_prevtIdxs[b]<0) { // First inclusion
// Encode layer info
cur_ttIncl.encode(m,n,ly,hbuf);
// 2) Max bitdepth info. Encode value
thmax = cur_cbs[b].skipMSBP+1;
for (i=1; i<=thmax; i++) {
cur_ttMaxBP.encode(m,n,i,hbuf);
}
// Count body size for packet
lblen += cur_cbs[b].
truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
} else { // Already in previous layer
// Send "1" bit
hbuf.writeBit(1);
// Count body size for packet
lblen +=
cur_cbs[b].
truncRates[cur_cbs[b].
truncIdxs[cur_tIndx[b]]] -
cur_cbs[b].
truncRates[cur_cbs[b].
truncIdxs[cur_prevtIdxs[b]]];
}
// 3) Truncation point information
if (cur_prevtIdxs[b]<0) {
newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]];
} else {
newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]]-
cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]-1;
}
// Mix of switch and if is faster
switch (newtp) {
case 0:
hbuf.writeBit(0); // Send one "0" bit
break;
case 1:
hbuf.writeBits(2,2); // Send one "1" and one "0"
break;
case 2:
case 3:
case 4:
// Send two "1" bits followed by 2 bits
// representation of newtp-2
hbuf.writeBits((3<<2)|(newtp-2),4);
break;
default:
if (newtp <= 35) {
// Send four "1" bits followed by a five bits
// representation of newtp-5
hbuf.writeBits((15<<5)|(newtp-5),9);
} else if (newtp <= 163) {
// Send nine "1" bits followed by a seven bits
// representation of newtp-36
hbuf.writeBits((511<<7)|(newtp-36),16);
} else {
throw new
ArithmeticException("Maximum number "+
"of truncation "+
"points exceeded");
}
}
} else { // Block not included in this layer
if (cur_prevtIdxs[b]>=0) {
// Already in previous layer. Send "0" bit
hbuf.writeBit(0);
} else { // Not in any previous layers
cur_ttIncl.encode(m,n,ly,hbuf);
}
// Go to the next one.
continue;
}
// Code-block length
// We need to compute the maximum number of bits needed to
// signal the length of each terminated segment and the
// final truncation point.
newtp = 1;
maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
cblen = (cur_prevtIdxs[b]<0) ? 0 :
cur_cbs[b].truncRates[cur_cbs[b].
truncIdxs[cur_prevtIdxs[b]]];
// Loop on truncation points
i = (cur_prevtIdxs[b]<0) ? 0 :
cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]+1;
int minbits = 0;
for (; i0) ? MathUtil.log2(cblen) : 0)+1;
// Update Lblock increment if needed
for(int j=prednbits; j0) ? MathUtil.log2(cblen) : 0)+1;
// Update Lblock increment if needed
for(int j=prednbits; j Copy the data to the body buffer
// Ensure size for body data
if (bbuf==null || bbuf.lengthcur_prevtIdxs[b]) {
// Block included in this precinct -> Copy data to
// body buffer and get code-size
if (cur_prevtIdxs[b]<0) {
cblen = cur_cbs[b].
truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
System.arraycopy(cur_cbs[b].data,0,
lbbuf,lblen,cblen);
} else {
cblen = cur_cbs[b].
truncRates[cur_cbs[b].
truncIdxs[cur_tIndx[b]]] -
cur_cbs[b].
truncRates[cur_cbs[b].
truncIdxs[cur_prevtIdxs[b]]];
System.
arraycopy(cur_cbs[b].data,
cur_cbs[b].
truncRates[cur_cbs[b].
truncIdxs[cur_prevtIdxs
[b]]],
lbbuf,lblen,cblen);
}
lblen += cblen;
// Verifies if this code-block contains new ROI
// information
if(cur_cbs[b].nROIcoeff!=0 &&
(cur_prevtIdxs[b]==-1 ||
cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] <=
cur_cbs[b].nROIcp-1) ) {
roiInPkt = true;
roiLen = lblen;
}
// Update truncation point
cur_prevtIdxs[b] = cur_tIndx[b];
}
} // End loop on horizontal code-blocks
} // End loop on vertical code-blocks
} // End loop on subbands
packetWritable = true;
// Must never happen
if(hbuf.getLength()==0) {
throw new Error("You have found a bug in PktEncoder, method:"+
" encodePacket");
}
return hbuf;
}
/**
* Returns the buffer of the body of the last encoded packet. The length
* of the body can be retrieved with the getLastBodyLen() method. The
* length of the array returned by this method may be larger than the
* actual body length.
*
* @return The buffer of body of the last encoded packet.
*
* @exception IllegalArgumentException If no packet has been coded since
* last reset(), last restore(), or object creation.
*
* @see #getLastBodyLen
* */
public byte[] getLastBodyBuf() {
if (lbbuf == null) {
throw new IllegalArgumentException();
}
return lbbuf;
}
/**
* Returns the length of the body of the last encoded packet, in
* bytes. The body itself can be retrieved with the getLastBodyBuf()
* method.
*
* @return The length of the body of last encoded packet, in bytes.
*
* @see #getLastBodyBuf
* */
public int getLastBodyLen() {
return lblen;
}
/**
* Saves the current state of this object. The last saved state
* can be restored with the restore() method.
*
* @see #restore
* */
public void save() {
int maxsbi,minsbi;
// Have we done any save yet?
if (bak_lblock==null) {
// Allocate backup buffers
bak_lblock = new int[ttIncl.length][][][][];
bak_prevtIdxs = new int[ttIncl.length][][][][];
for (int t=ttIncl.length-1; t>=0; t--) {
bak_lblock[t] = new int[ttIncl[t].length][][][];
bak_prevtIdxs[t] = new int[ttIncl[t].length][][][];
for (int c=ttIncl[t].length-1; c>=0; c--) {
bak_lblock[t][c] = new int[lblock[t][c].length][][];
bak_prevtIdxs[t][c] = new int[ttIncl[t][c].length][][];
for (int r=lblock[t][c].length-1; r>=0; r--) {
bak_lblock[t][c][r] =
new int[lblock[t][c][r].length][];
bak_prevtIdxs[t][c][r] =
new int[prevtIdxs[t][c][r].length][];
minsbi = (r==0) ? 0 : 1;
maxsbi = (r==0) ? 1 : 4;
for (int s=minsbi; s=0; t--) {
// Loop on components
for (int c=ttIncl[t].length-1; c>=0; c--) {
// Initialize reference caches
lblock_t_c = lblock[t][c];
bak_lblock_t_c = bak_lblock[t][c];
ttIncl_t_c = ttIncl[t][c];
ttMaxBP_t_c = ttMaxBP[t][c];
// Loop on resolution levels
for (int r=lblock_t_c.length-1; r>=0; r--) {
// Initialize reference caches
ttIncl_t_c_r = ttIncl_t_c[r];
ttMaxBP_t_c_r = ttMaxBP_t_c[r];
prevtIdxs_t_c_r = prevtIdxs[t][c][r];
bak_prevtIdxs_t_c_r = bak_prevtIdxs[t][c][r];
// Loop on subbands
minsbi = (r==0) ? 0 : 1;
maxsbi = (r==0) ? 1 : 4;
for (int s=minsbi; s=0; p--) {
if(p=0; t--) {
// Loop on components
for (int c=ttIncl[t].length-1; c>=0; c--) {
// Initialize reference caches
lblock_t_c = lblock[t][c];
bak_lblock_t_c = bak_lblock[t][c];
ttIncl_t_c = ttIncl[t][c];
ttMaxBP_t_c = ttMaxBP[t][c];
// Loop on resolution levels
for (int r=lblock_t_c.length-1; r>=0; r--) {
// Initialize reference caches
ttIncl_t_c_r = ttIncl_t_c[r];
ttMaxBP_t_c_r = ttMaxBP_t_c[r];
prevtIdxs_t_c_r = prevtIdxs[t][c][r];
bak_prevtIdxs_t_c_r = bak_prevtIdxs[t][c][r];
// Loop on subbands
minsbi = (r==0) ? 0 : 1;
maxsbi = (r==0) ? 1 : 4;
for (int s=minsbi; s=0; p--) {
if(p=0; t--) {
// Loop on components
for (int c=ttIncl[t].length-1; c>=0; c--) {
// Initialize reference caches
lblock_t_c = lblock[t][c];
ttIncl_t_c = ttIncl[t][c];
ttMaxBP_t_c = ttMaxBP[t][c];
// Loop on resolution levels
for (int r=lblock_t_c.length-1; r>=0; r--) {
// Initialize reference caches
ttIncl_t_c_r = ttIncl_t_c[r];
ttMaxBP_t_c_r = ttMaxBP_t_c[r];
prevtIdxs_t_c_r = prevtIdxs[t][c][r];
// Loop on subbands
minsbi = (r==0) ? 0 : 1;
maxsbi = (r==0) ? 1 : 4;
for (int s=minsbi; s=0; p--) {
if(p