jj2000.j2k.entropy.decoder.StdEntropyDecoder Maven / Gradle / Ivy
Show all versions of jai-imageio-jpeg2000 Show documentation
/*
* $RCSfile: StdEntropyDecoder.java,v $
* $Revision: 1.1 $
* $Date: 2005/02/11 05:02:07 $
* $State: Exp $
*
* Class: StdEntropyDecoder
*
* Description: Entropy decoding engine of stripes in code-blocks
*
*
*
* 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.entropy.decoder;
import jj2000.j2k.decoder.DecoderSpecs;
import jj2000.j2k.entropy.StdEntropyCoderOptions;
import jj2000.j2k.image.DataBlk;
import jj2000.j2k.image.DataBlkInt;
import jj2000.j2k.util.ArrayUtil;
import jj2000.j2k.util.FacilityManager;
import jj2000.j2k.util.MsgLogger;
import jj2000.j2k.wavelet.Subband;
import jj2000.j2k.wavelet.synthesis.SubbandSyn;
/**
* This class implements the JPEG 2000 entropy decoder, which codes stripes in
* code-blocks. This entropy decoding engine decodes one code-block at a time.
*
* The code-block are rectangular, with dimensions which must be powers of
* 2. Each dimension has to be no smaller than 4 and no larger than 256. The
* product of the two dimensions (i.e. area of the code-block) may not exceed
* 4096.
*
* Context 0 of the MQ-coder is used as the uniform one (uniform, non-adaptive
* probability distribution). Context 1 is used for RLC coding. Contexts 2-10
* are used for zero-coding (ZC), contexts 11-15 are used for sign-coding (SC)
* and contexts 16-18 are used for magnitude-refinement (MR).
*
* This implementation also provides some timing features. They can be
* enabled by setting the 'DO_TIMING' constant of this class to true and
* recompiling. The timing uses the 'System.currentTimeMillis()' Java API
* call, which returns wall clock time, not the actual CPU time used. The
* timing results will be printed on the message output. Since the times
* reported are wall clock times and not CPU usage times they can not be added
* to find the total used time (i.e. some time might be counted in several
* places). When timing is disabled ('DO_TIMING' is false) there is no penalty
* if the compiler performs some basic optimizations. Even if not the penalty
* should be negligeable.
* */
public class StdEntropyDecoder extends EntropyDecoder
implements StdEntropyCoderOptions {
/** Whether to collect timing information or not: false. Used as a compile
* time directive. */
private final static boolean DO_TIMING = false;
/** The cumulative wall time for the entropy coding engine, for each
* component. */
private long time[];
/** The bit based input for arithmetic coding bypass (i.e. raw) coding */
private ByteToBitInput bin;
/** The MQ decoder to use. It has in as the underlying source of coded
* data. */
private MQDecoder mq;
/** The decoder spec */
private DecoderSpecs decSpec;
/** The options that are turned on, as flag bits. The options are
* 'OPT_TERM_PASS', 'OPT_RESET_MQ', 'OPT_VERT_STR_CAUSAL', 'OPT_BYPASS' and
* 'OPT_SEG_SYMBOLS' as defined in the StdEntropyCoderOptions interface
*
* @see StdEntropyCoderOptions
**/
private int options;
/** Flag to indicate if we should try to detect errors or just ignore any
* error resilient information */
private final boolean doer;
/** Flag to indicate if we should be verbose about bit stream errors
detected with the error resilience options */
private final boolean verber;
/** Number of bits used for the Zero Coding lookup table */
private static final int ZC_LUT_BITS = 8;
/** Zero Coding context lookup tables for the LH global orientation */
private static final int ZC_LUT_LH[] = new int[1<The state of a coefficient is stored in the following way in the
* lower 16 bits, where bit 0 is the least significant bit. Bit 15 is the
* significance of a coefficient (0 if non-significant, 1 otherwise). Bit
* 14 is the visited state (i.e. if a coefficient has been coded in the
* significance propagation pass of the current bit-plane). Bit 13 is the
* "non zero-context" state (i.e. if one of the eight immediate neighbors
* is significant it is 1, otherwise is 0). Bits 12 to 9 store the sign of
* the already significant left, right, up and down neighbors (1 for
* negative, 0 for positive or not yet significant). Bit 8 indicates if
* the magnitude refinement has already been applied to the
* coefficient. Bits 7 to 4 store the significance of the left, right, up
* and down neighbors (1 for significant, 0 for non significant). Bits 3
* to 0 store the significance of the diagonal coefficients (up-left,
* up-right, down-left and down-right; 1 for significant, 0 for non
* significant).
*
* The upper 16 bits the state is stored as in the lower 16 bits,
* but with the bits shifted up by 16.
*
*
The lower 16 bits are referred to as "row 1" ("R1") while the upper
* 16 bits are referred to as "row 2" ("R2").
* */
private final int state[];
/** The separation between the upper and lower bits in the state array: 16
* */
private static final int STATE_SEP = 16;
/** The flag bit for the significance in the state array, for row 1. */
private static final int STATE_SIG_R1 = 1<<15;
/** The flag bit for the "visited" bit in the state array, for row 1. */
private static final int STATE_VISITED_R1 = 1<<14;
/** The flag bit for the "not zero context" bit in the state array, for
* row 1. This bit is always the OR of bits STATE_H_L_R1, STATE_H_R_R1,
* STATE_V_U_R1, STATE_V_D_R1, STATE_D_UL_R1, STATE_D_UR_R1, STATE_D_DL_R1
* and STATE_D_DR_R1. */
private static final int STATE_NZ_CTXT_R1 = 1<<13;
/** The flag bit for the horizontal-left sign in the state array, for row
* 1. This bit can only be set if the STATE_H_L_R1 is also set. */
private static final int STATE_H_L_SIGN_R1 = 1<<12;
/** The flag bit for the horizontal-right sign in the state array, for
* row 1. This bit can only be set if the STATE_H_R_R1 is also set. */
private static final int STATE_H_R_SIGN_R1 = 1<<11;
/** The flag bit for the vertical-up sign in the state array, for row
* 1. This bit can only be set if the STATE_V_U_R1 is also set. */
private static final int STATE_V_U_SIGN_R1 = 1<<10;
/** The flag bit for the vertical-down sign in the state array, for row
* 1. This bit can only be set if the STATE_V_D_R1 is also set. */
private static final int STATE_V_D_SIGN_R1 = 1<<9;
/** The flag bit for the previous MR primitive applied in the state array,
for row 1. */
private static final int STATE_PREV_MR_R1 = 1<<8;
/** The flag bit for the horizontal-left significance in the state array,
for row 1. */
private static final int STATE_H_L_R1 = 1<<7;
/** The flag bit for the horizontal-right significance in the state array,
for row 1. */
private static final int STATE_H_R_R1 = 1<<6;
/** The flag bit for the vertical-up significance in the state array, for
row 1. */
private static final int STATE_V_U_R1 = 1<<5;
/** The flag bit for the vertical-down significance in the state array,
for row 1. */
private static final int STATE_V_D_R1 = 1<<4;
/** The flag bit for the diagonal up-left significance in the state array,
for row 1. */
private static final int STATE_D_UL_R1 = 1<<3;
/** The flag bit for the diagonal up-right significance in the state
array, for row 1.*/
private static final int STATE_D_UR_R1 = 1<<2;
/** The flag bit for the diagonal down-left significance in the state
array, for row 1. */
private static final int STATE_D_DL_R1 = 1<<1;
/** The flag bit for the diagonal down-right significance in the state
array , for row 1.*/
private static final int STATE_D_DR_R1 = 1;
/** The flag bit for the significance in the state array, for row 2. */
private static final int STATE_SIG_R2 = STATE_SIG_R1<> 1) & 0x01; // significance of up neighbor
rs = (i >> 2) & 0x01; // significance of right neighbor
ls = (i >> 3) & 0x01; // significance of left neighbor
dsgn = (i >> 5) & 0x01; // sign of down neighbor
usgn = (i >> 6) & 0x01; // sign of up neighbor
rsgn = (i >> 7) & 0x01; // sign of right neighbor
lsgn = (i >> 8) & 0x01; // sign of left neighbor
// Calculate 'h' and 'v' as in VM text
h = ls*(1-2*lsgn)+rs*(1-2*rsgn);
h = (h >= -1) ? h : -1;
h = (h <= 1) ? h : 1;
v = us*(1-2*usgn)+ds*(1-2*dsgn);
v = (v >= -1) ? v : -1;
v = (v <= 1) ? v : 1;
// Get context and sign predictor from 'inter_sc_lut'
SC_LUT[i] = inter_sc_lut[(h+1)<<3|(v+1)];
}
inter_sc_lut = null;
// Initialize the MR lookup tables
// None significant, prev MR off
MR_LUT[0] = 16;
// One or more significant, prev MR off
for (i=1; i<(1<<(MR_LUT_BITS-1)); i++) {
MR_LUT[i] = 17;
}
// Previous MR on, significance irrelevant
for (; i<(1<The returned code-block may be progressive, which is indicated by
* the 'progressive' variable of the returned 'DataBlk' object. If a
* code-block is progressive it means that in a later request to this
* method for the same code-block it is possible to retrieve data which is
* a better approximation, since meanwhile more data to decode for the
* code-block could have been received. If the code-block is not
* progressive then later calls to this method for the same code-block
* will return the exact same data values.
*
* The data returned by this method is always a copy of the internal
* data of this object, if any, and it can be modified "in place" without
* any problems after being returned. The 'offset' of the returned data is
* 0, and the 'scanw' is the same as the code-block width. See the
* 'DataBlk' class.
*
*
The 'ulx' and 'uly' members of the returned 'DataBlk' object
* contain the coordinates of the top-left corner of the block, with
* respect to the tile, not the subband.
*
* @param c The component for which to return the next code-block.
*
* @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 which the code-block to return is.
*
* @param cblk If non-null this object will be used to return the new
* code-block. If null a new one will be allocated and returned. If the
* "data" array of the object is non-null it will be reused, if possible,
* to return the data.
*
* @return The next code-block in the current tile for component 'n', or
* null if all code-blocks for the current tile have been returned.
*
* @see DataBlk
* */
public DataBlk getCodeBlock(int c, int m, int n, SubbandSyn sb,
DataBlk cblk) {
long stime = 0L; // Start time for timed sections
int zc_lut[]; // The ZC lookup table to use
int out_data[]; // The outupt data buffer
int npasses; // The number of coding passes to perform
int curbp; // The current magnitude bit-plane (starts at 30)
boolean error; // Error indicator
int tslen; // Length of first terminated segment
int tsidx; // Index of current terminated segment
ByteInputBuffer in = null;
boolean isterm;
// Get the code-block to decode
srcblk = src.getCodeBlock(c,m,n,sb,1,-1,srcblk);
if (DO_TIMING) stime = System.currentTimeMillis();
// Retrieve options from decSpec
options = ((Integer)decSpec.ecopts.
getTileCompVal(tIdx,c)).intValue();
// Reset state
ArrayUtil.intArraySet(state,0);
// Initialize output code-block
if (cblk==null) {
cblk = new DataBlkInt();
}
cblk.progressive = srcblk.prog;
cblk.ulx = srcblk.ulx;
cblk.uly = srcblk.uly;
cblk.w = srcblk.w;
cblk.h = srcblk.h;
cblk.offset = 0;
cblk.scanw = cblk.w;
out_data = (int[])cblk.getData();
if (out_data == null || out_data.length < srcblk.w*srcblk.h) {
out_data = new int[srcblk.w*srcblk.h];
cblk.setData(out_data);
} else {
// Set data values to 0
ArrayUtil.intArraySet(out_data,0);
}
if (srcblk.nl <= 0 || srcblk.nTrunc <= 0) {
// 0 layers => no data to decode => return all 0s
return cblk;
}
// Get the length of the first terminated segment
tslen = (srcblk.tsLengths == null) ? srcblk.dl : srcblk.tsLengths[0];
tsidx = 0;
// Initialize for decoding
npasses = srcblk.nTrunc;
if (mq == null) {
in = new ByteInputBuffer(srcblk.data,0,tslen);
mq = new MQDecoder(in ,NUM_CTXTS,MQ_INIT);
}
else {
// We always start by an MQ segment
mq.nextSegment(srcblk.data,0,tslen);
mq.resetCtxts();
}
error = false;
if ((options & OPT_BYPASS) != 0) {
if(bin==null){
if (in == null) in = mq.getByteInputBuffer();
bin = new ByteToBitInput(in);
}
}
// Choose correct ZC lookup table for global orientation
switch (sb.orientation) {
case Subband.WT_ORIENT_HL:
zc_lut = ZC_LUT_HL;
break;
case Subband.WT_ORIENT_LH:
case Subband.WT_ORIENT_LL:
zc_lut = ZC_LUT_LH;
break;
case Subband.WT_ORIENT_HH:
zc_lut = ZC_LUT_HH;
break;
default:
throw new Error("JJ2000 internal error");
}
// NOTE: we don't currently detect which is the last magnitude
// bit-plane so that 'isterm' is true for the last pass of it. Doing so
// would aid marginally in error detection with the predictable error
// resilient MQ termination. However, determining which is the last
// magnitude bit-plane is quite hard (due to ROI, quantization, etc.)
// and in any case the predictable error resilient termination used
// without the arithmetic coding bypass and/or regular termination
// modes is almost useless.
// Loop on bit-planes and passes
curbp = 30-srcblk.skipMSBP;
// Check for maximum number of bitplanes quit condition
if(mQuit != -1 && (mQuit*3-2) < npasses){
npasses = mQuit*3-2;
}
// First bit-plane has only the cleanup pass
if (curbp >= 0 && npasses > 0) {
isterm = (options & OPT_TERM_PASS) != 0 ||
((options & OPT_BYPASS) != 0 &&
(31-NUM_NON_BYPASS_MS_BP-srcblk.skipMSBP)>=curbp);
error = cleanuppass(cblk,mq,curbp,state,zc_lut,isterm);
npasses--;
if (!error || !doer) curbp--;
}
// Other bit-planes have the three coding passes
if (!error || !doer) {
while (curbp >= 0 && npasses > 0) {
if((options & OPT_BYPASS) != 0 &&
(curbp < 31-NUM_NON_BYPASS_MS_BP-srcblk.skipMSBP)){
// Use bypass decoding mode (only all bit-planes
// after the first 4 bit-planes).
// Here starts a new raw segment
bin.setByteArray(null,-1,srcblk.tsLengths[++tsidx]);
isterm = (options & OPT_TERM_PASS) != 0;
error = rawSigProgPass(cblk,bin,curbp,state,isterm);
npasses--;
if (npasses <= 0 || (error && doer)) break;
if ((options & OPT_TERM_PASS) != 0) {
// Start a new raw segment
bin.setByteArray(null,-1,srcblk.tsLengths[++tsidx]);
}
isterm = (options & OPT_TERM_PASS) != 0 ||
((options & OPT_BYPASS) != 0 &&
(31-NUM_NON_BYPASS_MS_BP-srcblk.skipMSBP>curbp));
error = rawMagRefPass(cblk,bin,curbp,state,isterm);
}
else {// Do not use bypass decoding mode
if ((options & OPT_TERM_PASS) != 0) {
// Here starts a new MQ segment
mq.nextSegment(null,-1,srcblk.tsLengths[++tsidx]);
}
isterm = (options & OPT_TERM_PASS) != 0;
error = sigProgPass(cblk,mq,curbp,state,zc_lut,isterm);
npasses--;
if (npasses <= 0 || (error && doer)) break;
if ((options & OPT_TERM_PASS) != 0) {
// Here starts a new MQ segment
mq.nextSegment(null,-1,srcblk.tsLengths[++tsidx]);
}
isterm = (options & OPT_TERM_PASS) != 0 ||
((options & OPT_BYPASS) != 0 &&
(31-NUM_NON_BYPASS_MS_BP-srcblk.skipMSBP>curbp));
error = magRefPass(cblk,mq,curbp,state,isterm);
}
npasses--;
if (npasses <= 0 || (error && doer)) break;
if ((options & OPT_TERM_PASS) != 0 ||
((options & OPT_BYPASS) != 0 &&
(curbp < 31-NUM_NON_BYPASS_MS_BP-srcblk.skipMSBP))) {
// Here starts a new MQ segment
mq.nextSegment(null,-1,srcblk.tsLengths[++tsidx]);
}
isterm = (options & OPT_TERM_PASS) != 0 ||
((options & OPT_BYPASS) != 0 &&
(31-NUM_NON_BYPASS_MS_BP-srcblk.skipMSBP)>=curbp);
error = cleanuppass(cblk,mq,curbp,state,zc_lut,isterm);
npasses--;
if (error) break;
// Goto next bit-plane
curbp--;
}
}
// If an error ocurred conceal it
if (error && doer) {
if (verber) {
FacilityManager.getMsgLogger().
printmsg(MsgLogger.WARNING,
"Error detected at bit-plane "+curbp+
" in code-block ("+m+","+n+"), sb_idx "+
sb.sbandIdx+", res. level "+sb.resLvl+
". Concealing...");
}
conceal(cblk,curbp);
}
if (DO_TIMING) time[c] += System.currentTimeMillis()-stime;
// Return decoded block
return cblk;
}
/**
* Returns the specified code-block in the current tile for the specified
* component (as a reference or copy).
*
*
The returned code-block may be progressive, which is indicated by
* the 'progressive' variable of the returned 'DataBlk'
* object. If a code-block is progressive it means that in a later request
* to this method for the same code-block it is possible to retrieve data
* which is a better approximation, since meanwhile more data to decode
* for the code-block could have been received. If the code-block is not
* progressive then later calls to this method for the same code-block
* will return the exact same data values.
*
*
The data returned by this method can be the data in the internal
* buffer of this object, if any, and thus can not be modified by the
* caller. The 'offset' and 'scanw' of the returned data can be
* arbitrary. See the 'DataBlk' class.
*
*
The 'ulx' and 'uly' members of the returned 'DataBlk' object
* contain the coordinates of the top-left corner of the block, with
* respect to the tile, not the subband.
*
* @param c The component for which to return the next code-block.
*
* @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 which the code-block to return is.
*
* @param cblk If non-null this object will be used to return the new
* code-block. If null a new one will be allocated and returned. If the
* "data" array of the object is non-null it will be reused, if possible,
* to return the data.
*
* @return The next code-block in the current tile for component 'n', or
* null if all code-blocks for the current tile have been returned.
*
* @see DataBlk
* */
public DataBlk getInternCodeBlock(int c, int m, int n, SubbandSyn sb,
DataBlk cblk) {
return getCodeBlock(c,m,n,sb,cblk);
}
/**
* Performs the significance propagation pass on the specified data and
* bit-plane. It decodes all insignificant samples which have, at least,
* one of its immediate eight neighbors already significant, using the ZC
* and SC primitives as needed. It toggles the "visited" state bit to 1
* for all those samples.
*
*
This method also checks for segmentation markers if those are
* present and returns true if an error is detected, or false
* otherwise. If an error is detected it means that the bit stream contains
* some erroneous bit that have led to the decoding of incorrect
* data. This data affects the whole last decoded bit-plane (i.e. 'bp'). If
* 'true' is returned the 'conceal' method should be called and no more
* passes should be decoded for this code-block's bit stream.
*
* @param cblk The code-block data to decode
*
* @param mq The MQ-coder to use
*
* @param bp The bit-plane to decode
*
* @param state The state information for the code-block
*
* @param zc_lut The ZC lookup table to use in ZC.
*
* @param isterm If this pass has been terminated. If the pass has been
* terminated it can be used to check error resilience.
*
* @return True if an error was detected in the bit stream, false otherwise.
* */
private boolean sigProgPass(DataBlk cblk, MQDecoder mq, int bp,
int state[], int zc_lut[], boolean isterm) {
int j,sj; // The state index for line and stripe
int k,sk; // The data index for line and stripe
int dscanw; // The data scan-width
int sscanw; // The state scan-width
int jstep; // Stripe to stripe step for 'sj'
int kstep; // Stripe to stripe step for 'sk'
int stopsk; // The loop limit on the variable sk
int csj; // Local copy (i.e. cached) of 'state[j]'
int setmask; // The mask to set current and lower bit-planes to 1/2
// approximation
int sym; // The symbol to code
int ctxt; // The context to use
int data[]; // The data buffer
int s; // The stripe index
boolean causal; // Flag to indicate if stripe-causal context
// formation is to be used
int nstripes; // The number of stripes in the code-block
int sheight; // Height of the current stripe
int off_ul,off_ur,off_dr,off_dl; // offsets
boolean error; // The error condition
// Initialize local variables
dscanw = cblk.scanw;
sscanw = cblk.w+2;
jstep = sscanw*STRIPE_HEIGHT/2-cblk.w;
kstep = dscanw*STRIPE_HEIGHT-cblk.w;
setmask = (3<>1;
data = (int[]) cblk.getData();
nstripes = (cblk.h+STRIPE_HEIGHT-1)/STRIPE_HEIGHT;
causal = (options & OPT_VERT_STR_CAUSAL) != 0;
// Pre-calculate offsets in 'state' for diagonal neighbors
off_ul = -sscanw-1; // up-left
off_ur = -sscanw+1; // up-right
off_dr = sscanw+1; // down-right
off_dl = sscanw-1; // down-left
// Decode stripe by stripe
sk = cblk.offset;
sj = sscanw+1;
for (s = nstripes-1; s >= 0; s--, sk+=kstep, sj+=jstep) {
sheight = (s != 0) ? STRIPE_HEIGHT :
cblk.h-(nstripes-1)*STRIPE_HEIGHT;
stopsk = sk+cblk.w;
// Scan by set of 1 stripe column at a time
for (; sk < stopsk; sk++, sj++) {
// Do half top of column
j = sj;
csj = state[j];
// If any of the two samples is not significant and has a
// non-zero context (i.e. some neighbor is significant) we can
// not skip them
if ((((~csj) & (csj<<2)) & SIG_MASK_R1R2) != 0) {
k = sk;
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_NZ_CTXT_R1)) ==
STATE_NZ_CTXT_R1) {
// Use zero coding
if (mq.decodeSymbol(zc_lut[csj&ZC_MASK]) != 0) {
// Became significant
// Use sign coding
ctxt = SC_LUT[(csj>>>SC_SHIFT_R1)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
if (!causal) {
// If in causal mode do not change contexts of
// previous stripe.
state[j+off_ul] |=
STATE_NZ_CTXT_R2|STATE_D_DR_R2;
state[j+off_ur] |=
STATE_NZ_CTXT_R2|STATE_D_DL_R2;
}
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|
STATE_V_U_R2|STATE_V_U_SIGN_R2;
if (!causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2|STATE_V_D_SIGN_R2;
}
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_H_L_SIGN_R1|
STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_H_R_SIGN_R1|
STATE_D_UR_R2;
}
else {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|STATE_V_U_R2;
if (!causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2;
}
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_D_UR_R2;
}
}
else {
csj |= STATE_VISITED_R1;
}
}
if (sheight < 2) {
state[j] = csj;
continue;
}
// Scan second row
if ((csj & (STATE_SIG_R2|STATE_NZ_CTXT_R2)) ==
STATE_NZ_CTXT_R2) {
k += dscanw;
// Use zero coding
if (mq.decodeSymbol(zc_lut[(csj>>>STATE_SEP)&
ZC_MASK]) != 0) {
// Became significant
// Use sign coding
ctxt = SC_LUT[(csj>>>SC_SHIFT_R2)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
state[j+off_dl] |= STATE_NZ_CTXT_R1|STATE_D_UR_R1;
state[j+off_dr] |= STATE_NZ_CTXT_R1|STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|
STATE_V_D_R1|STATE_V_D_SIGN_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1|STATE_V_U_SIGN_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|
STATE_H_L_R2|STATE_H_L_SIGN_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|
STATE_H_R_R2|STATE_H_R_SIGN_R2;
}
else {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|STATE_V_D_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|STATE_H_L_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|STATE_H_R_R2;
}
}
else {
csj |= STATE_VISITED_R2;
}
}
state[j] = csj;
}
// Do half bottom of column
if (sheight < 3) continue;
j += sscanw;
csj = state[j];
// If any of the two samples is not significant and has a
// non-zero context (i.e. some neighbor is significant) we can
// not skip them
if ((((~csj) & (csj<<2)) & SIG_MASK_R1R2) != 0) {
k = sk+(dscanw<<1);
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_NZ_CTXT_R1)) ==
STATE_NZ_CTXT_R1) {
// Use zero coding
if (mq.decodeSymbol(zc_lut[csj&ZC_MASK]) != 0) {
// Became significant
// Use sign coding
ctxt = SC_LUT[(csj>>>SC_SHIFT_R1)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
state[j+off_ul] |=
STATE_NZ_CTXT_R2|STATE_D_DR_R2;
state[j+off_ur] |=
STATE_NZ_CTXT_R2|STATE_D_DL_R2;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|
STATE_V_U_R2|STATE_V_U_SIGN_R2;
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2|STATE_V_D_SIGN_R2;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_H_L_SIGN_R1|
STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_H_R_SIGN_R1|
STATE_D_UR_R2;
}
else {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|STATE_V_U_R2;
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_D_UR_R2;
}
}
else {
csj |= STATE_VISITED_R1;
}
}
if (sheight < 4) {
state[j] = csj;
continue;
}
// Scan second row
if ((csj & (STATE_SIG_R2|STATE_NZ_CTXT_R2)) ==
STATE_NZ_CTXT_R2) {
k += dscanw;
// Use zero coding
if (mq.decodeSymbol(zc_lut[(csj>>>STATE_SEP)&
ZC_MASK]) != 0) {
// Became significant
// Use sign coding
ctxt = SC_LUT[(csj>>>SC_SHIFT_R2)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
state[j+off_dl] |= STATE_NZ_CTXT_R1|STATE_D_UR_R1;
state[j+off_dr] |= STATE_NZ_CTXT_R1|STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|
STATE_V_D_R1|STATE_V_D_SIGN_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1|STATE_V_U_SIGN_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|
STATE_H_L_R2|STATE_H_L_SIGN_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|
STATE_H_R_R2|STATE_H_R_SIGN_R2;
}
else {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|STATE_V_D_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|STATE_H_L_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|STATE_H_R_R2;
}
}
else {
csj |= STATE_VISITED_R2;
}
}
state[j] = csj;
}
}
}
error = false;
// Check the error resilient termination
if (isterm && (options & OPT_PRED_TERM) != 0) {
error = mq.checkPredTerm();
}
// Reset the MQ context states if we need to
if ((options & OPT_RESET_MQ) != 0) {
mq.resetCtxts();
}
// Return error condition
return error;
}
/**
* Performs the significance propagation pass on the specified data and
* bit-plane. It decodes all insignificant samples which have, at least, one
* of its immediate eight neighbors already significant, using the ZC and
* SC primitives as needed. It toggles the "visited" state bit to 1 for
* all those samples.
*
* This method bypasses the arithmetic coder and reads "raw" symbols
* from the bit stream.
*
*
This method also checks for segmentation markers if those are
* present and returns true if an error is detected, or false
* otherwise. If an error is detected it measn that the bit stream contains
* some erroneous bit that have led to the decoding of incorrect
* data. This data affects the whole last decoded bit-plane (i.e. 'bp'). If
* 'true' is returned the 'conceal' method should be called and no more
* passes should be decoded for this code-block's bit stream.
*
* @param cblk The code-block data to decode
*
* @param bin The raw bit based input
*
* @param bp The bit-plane to decode
*
* @param state The state information for the code-block
*
* @param isterm If this pass has been terminated. If the pass has been
* terminated it can be used to check error resilience.
*
* @return True if an error was detected in the bit stream, false otherwise.
* */
private boolean rawSigProgPass(DataBlk cblk, ByteToBitInput bin, int bp,
int state[], boolean isterm) {
int j,sj; // The state index for line and stripe
int k,sk; // The data index for line and stripe
int dscanw; // The data scan-width
int sscanw; // The state scan-width
int jstep; // Stripe to stripe step for 'sj'
int kstep; // Stripe to stripe step for 'sk'
int stopsk; // The loop limit on the variable sk
int csj; // Local copy (i.e. cached) of 'state[j]'
int setmask; // The mask to set current and lower bit-planes to 1/2
// approximation
int sym; // The symbol to code
int data[]; // The data buffer
int s; // The stripe index
boolean causal; // Flag to indicate if stripe-causal context
// formation is to be used
int nstripes; // The number of stripes in the code-block
int sheight; // Height of the current stripe
int off_ul,off_ur,off_dr,off_dl; // offsets
boolean error; // The error condition
// Initialize local variables
dscanw = cblk.scanw;
sscanw = cblk.w+2;
jstep = sscanw*STRIPE_HEIGHT/2-cblk.w;
kstep = dscanw*STRIPE_HEIGHT-cblk.w;
setmask = (3<>1;
data = (int[]) cblk.getData();
nstripes = (cblk.h+STRIPE_HEIGHT-1)/STRIPE_HEIGHT;
causal = (options & OPT_VERT_STR_CAUSAL) != 0;
// Pre-calculate offsets in 'state' for diagonal neighbors
off_ul = -sscanw-1; // up-left
off_ur = -sscanw+1; // up-right
off_dr = sscanw+1; // down-right
off_dl = sscanw-1; // down-left
// Decode stripe by stripe
sk = cblk.offset;
sj = sscanw+1;
for (s = nstripes-1; s >= 0; s--, sk+=kstep, sj+=jstep) {
sheight = (s != 0) ? STRIPE_HEIGHT :
cblk.h-(nstripes-1)*STRIPE_HEIGHT;
stopsk = sk+cblk.w;
// Scan by set of 1 stripe column at a time
for (; sk < stopsk; sk++, sj++) {
// Do half top of column
j = sj;
csj = state[j];
// If any of the two samples is not significant and has a
// non-zero context (i.e. some neighbor is significant) we can
// not skip them
if ((((~csj) & (csj<<2)) & SIG_MASK_R1R2) != 0) {
k = sk;
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_NZ_CTXT_R1)) ==
STATE_NZ_CTXT_R1) {
// Use zero coding
if (bin.readBit() != 0) {
// Became significant
// Use sign coding
sym = bin.readBit();
// Update data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
if (!causal) {
// If in causal mode do not change contexts of
// previous stripe.
state[j+off_ul] |=
STATE_NZ_CTXT_R2|STATE_D_DR_R2;
state[j+off_ur] |=
STATE_NZ_CTXT_R2|STATE_D_DL_R2;
}
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|
STATE_V_U_R2|STATE_V_U_SIGN_R2;
if (!causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2|STATE_V_D_SIGN_R2;
}
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_H_L_SIGN_R1|
STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_H_R_SIGN_R1|
STATE_D_UR_R2;
}
else {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|STATE_V_U_R2;
if (!causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2;
}
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_D_UR_R2;
}
}
else {
csj |= STATE_VISITED_R1;
}
}
if (sheight < 2) {
state[j] = csj;
continue;
}
if ((csj & (STATE_SIG_R2|STATE_NZ_CTXT_R2)) ==
STATE_NZ_CTXT_R2) {
k += dscanw;
// Use zero coding
if (bin.readBit() != 0) {
// Became significant
// Use sign coding
sym = bin.readBit();
// Update data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
state[j+off_dl] |= STATE_NZ_CTXT_R1|STATE_D_UR_R1;
state[j+off_dr] |= STATE_NZ_CTXT_R1|STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|
STATE_V_D_R1|STATE_V_D_SIGN_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1|STATE_V_U_SIGN_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|
STATE_H_L_R2|STATE_H_L_SIGN_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|
STATE_H_R_R2|STATE_H_R_SIGN_R2;
}
else {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|STATE_V_D_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|STATE_H_L_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|STATE_H_R_R2;
}
}
else {
csj |= STATE_VISITED_R2;
}
}
state[j] = csj;
}
// Do half bottom of column
if (sheight < 3) continue;
j += sscanw;
csj = state[j];
// If any of the two samples is not significant and has a
// non-zero context (i.e. some neighbor is significant) we can
// not skip them
if ((((~csj) & (csj<<2)) & SIG_MASK_R1R2) != 0) {
k = sk+(dscanw<<1);
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_NZ_CTXT_R1)) ==
STATE_NZ_CTXT_R1) {
// Use zero coding
if (bin.readBit() != 0) {
// Became significant
// Use sign coding
sym = bin.readBit();
// Update data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
state[j+off_ul] |=
STATE_NZ_CTXT_R2|STATE_D_DR_R2;
state[j+off_ur] |=
STATE_NZ_CTXT_R2|STATE_D_DL_R2;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|
STATE_V_U_R2|STATE_V_U_SIGN_R2;
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2|STATE_V_D_SIGN_R2;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_H_L_SIGN_R1|
STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_H_R_SIGN_R1|
STATE_D_UR_R2;
}
else {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|STATE_V_U_R2;
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_D_UR_R2;
}
}
else {
csj |= STATE_VISITED_R1;
}
}
if (sheight < 4) {
state[j] = csj;
continue;
}
// Scan second row
if ((csj & (STATE_SIG_R2|STATE_NZ_CTXT_R2)) ==
STATE_NZ_CTXT_R2) {
k += dscanw;
// Use zero coding
if (bin.readBit() != 0) {
// Became significant
// Use sign coding
sym = bin.readBit();
// Update data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
state[j+off_dl] |= STATE_NZ_CTXT_R1|STATE_D_UR_R1;
state[j+off_dr] |= STATE_NZ_CTXT_R1|STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|
STATE_V_D_R1|STATE_V_D_SIGN_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1|STATE_V_U_SIGN_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|
STATE_H_L_R2|STATE_H_L_SIGN_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|
STATE_H_R_R2|STATE_H_R_SIGN_R2;
}
else {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|STATE_V_D_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|STATE_H_L_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|STATE_H_R_R2;
}
}
else {
csj |= STATE_VISITED_R2;
}
}
state[j] = csj;
}
}
}
error = false;
// Check the byte padding if the pass is terminated
if (isterm) {
error = bin.checkBytePadding();
}
// Return error condition
return error;
}
/**
* Performs the magnitude refinement pass on the specified data and
* bit-plane. It decodes the samples which are significant and which do not
* have the "visited" state bit turned on, using the MR primitive. The
* "visited" state bit is not mofified for any samples.
*
* This method also checks for segmentation markers if those are
* present and returns true if an error is detected, or false
* otherwise. If an error is detected it means that the bit stream contains
* some erroneous bit that have led to the decoding of incorrect
* data. This data affects the whole last decoded bit-plane (i.e. 'bp'). If
* 'true' is returned the 'conceal' method should be called and no more
* passes should be decoded for this code-block's bit stream.
*
* @param cblk The code-block data to decode
*
* @param mq The MQ-decoder to use
*
* @param bp The bit-plane to decode
*
* @param state The state information for the code-block
*
* @param isterm If this pass has been terminated. If the pass has been
* terminated it can be used to check error resilience.
*
* @return True if an error was detected in the bit stream, false otherwise.
* */
private boolean magRefPass(DataBlk cblk, MQDecoder mq, int bp,
int state[], boolean isterm) {
int j,sj; // The state index for line and stripe
int k,sk; // The data index for line and stripe
int dscanw; // The data scan-width
int sscanw; // The state scan-width
int jstep; // Stripe to stripe step for 'sj'
int kstep; // Stripe to stripe step for 'sk'
int stopsk; // The loop limit on the variable sk
int csj; // Local copy (i.e. cached) of 'state[j]'
int setmask; // The mask to set lower bit-planes to 1/2 approximation
int resetmask; // The mask to reset approximation bit-planes
int sym; // The symbol to decode
int data[]; // The data buffer
int s; // The stripe index
int nstripes; // The number of stripes in the code-block
int sheight; // Height of the current stripe
boolean error; // The error condition
// Initialize local variables
dscanw = cblk.scanw;
sscanw = cblk.w+2;
jstep = sscanw*STRIPE_HEIGHT/2-cblk.w;
kstep = dscanw*STRIPE_HEIGHT-cblk.w;
setmask = (1<>1;
resetmask = (-1)<<(bp+1);
data = (int[]) cblk.getData();
nstripes = (cblk.h+STRIPE_HEIGHT-1)/STRIPE_HEIGHT;
// Decode stripe by stripe
sk = cblk.offset;
sj = sscanw+1;
for (s = nstripes-1; s >= 0; s--, sk+=kstep, sj+=jstep) {
sheight = (s != 0) ? STRIPE_HEIGHT :
cblk.h-(nstripes-1)*STRIPE_HEIGHT;
stopsk = sk+cblk.w;
// Scan by set of 1 stripe column at a time
for (; sk < stopsk; sk++, sj++) {
// Do half top of column
j = sj;
csj = state[j];
// If any of the two samples is significant and not yet
// visited in the current bit-plane we can not skip them
if ((((csj >>> 1) & (~csj)) & VSTD_MASK_R1R2) != 0) {
k = sk;
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_VISITED_R1)) ==
STATE_SIG_R1) {
// Use MR primitive
sym = mq.decodeSymbol(MR_LUT[csj&MR_MASK]);
// Update the data
data[k] &= resetmask;
data[k] |= (sym<>>STATE_SEP)&
MR_MASK]);
// Update the data
data[k] &= resetmask;
data[k] |= (sym<>> 1) & (~csj)) & VSTD_MASK_R1R2) != 0) {
k = sk+(dscanw<<1);
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_VISITED_R1)) ==
STATE_SIG_R1) {
// Use MR primitive
sym = mq.decodeSymbol(MR_LUT[csj&MR_MASK]);
// Update the data
data[k] &= resetmask;
data[k] |= (sym<>>STATE_SEP)&
MR_MASK]);
// Update the data
data[k] &= resetmask;
data[k] |= (sym<This method bypasses the arithmetic coder and reads "raw" symbols
* from the bit stream.
*
* This method also checks for segmentation markers if those are
* present and returns true if an error is detected, or false
* otherwise. If an error is detected it measn that the bit stream contains
* some erroneous bit that have led to the decoding of incorrect
* data. This data affects the whole last decoded bit-plane (i.e. 'bp'). If
* 'true' is returned the 'conceal' method should be called and no more
* passes should be decoded for this code-block's bit stream.
*
* @param cblk The code-block data to decode
*
* @param bin The raw bit based input
*
* @param bp The bit-plane to decode
*
* @param state The state information for the code-block
*
* @param isterm If this pass has been terminated. If the pass has been
* terminated it can be used to check error resilience.
*
* @return True if an error was detected in the bit stream, false otherwise.
* */
private boolean rawMagRefPass(DataBlk cblk, ByteToBitInput bin, int bp,
int state[], boolean isterm) {
int j,sj; // The state index for line and stripe
int k,sk; // The data index for line and stripe
int dscanw; // The data scan-width
int sscanw; // The state scan-width
int jstep; // Stripe to stripe step for 'sj'
int kstep; // Stripe to stripe step for 'sk'
int stopsk; // The loop limit on the variable sk
int csj; // Local copy (i.e. cached) of 'state[j]'
int setmask; // The mask to set lower bit-planes to 1/2 approximation
int resetmask; // The mask to reset approximation bit-planes
int sym; // The symbol to decode
int data[]; // The data buffer
int s; // The stripe index
int nstripes; // The number of stripes in the code-block
int sheight; // Height of the current stripe
boolean error; // The error condition
// Initialize local variables
dscanw = cblk.scanw;
sscanw = cblk.w+2;
jstep = sscanw*STRIPE_HEIGHT/2-cblk.w;
kstep = dscanw*STRIPE_HEIGHT-cblk.w;
setmask = (1<>1;
resetmask = (-1)<<(bp+1);
data = (int[]) cblk.getData();
nstripes = (cblk.h+STRIPE_HEIGHT-1)/STRIPE_HEIGHT;
// Decode stripe by stripe
sk = cblk.offset;
sj = sscanw+1;
for (s = nstripes-1; s >= 0; s--, sk+=kstep, sj+=jstep) {
sheight = (s != 0) ? STRIPE_HEIGHT :
cblk.h-(nstripes-1)*STRIPE_HEIGHT;
stopsk = sk+cblk.w;
// Scan by set of 1 stripe column at a time
for (; sk < stopsk; sk++, sj++) {
// Do half top of column
j = sj;
csj = state[j];
// If any of the two samples is significant and not yet
// visited in the current bit-plane we can not skip them
if ((((csj >>> 1) & (~csj)) & VSTD_MASK_R1R2) != 0) {
k = sk;
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_VISITED_R1)) ==
STATE_SIG_R1) {
// Read raw bit (no MR primative)
sym = bin.readBit();
// Update the data
data[k] &= resetmask;
data[k] |= (sym<>> 1) & (~csj)) & VSTD_MASK_R1R2) != 0) {
k = sk+(dscanw<<1);
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_VISITED_R1)) ==
STATE_SIG_R1) {
// Read raw bit (no MR primative)
sym = bin.readBit();
// Update the data
data[k] &= resetmask;
data[k] |= (sym<This method also checks for segmentation markers if those are
* present and returns true if an error is detected, or false
* otherwise. If an error is detected it measn that the bit stream
* contains some erroneous bit that have led to the decoding of incorrect
* data. This data affects the whole last decoded bit-plane
* (i.e. 'bp'). If 'true' is returned the 'conceal' method should be
* called and no more passes should be decoded for this code-block's bit
* stream.
*
* @param cblk The code-block data to code
*
* @param mq The MQ-coder to use
*
* @param bp The bit-plane to decode
*
* @param state The state information for the code-block
*
* @param zc_lut The ZC lookup table to use in ZC.
*
* @param isterm If this pass has been terminated. If the pass has been
* terminated it can be used to check error resilience.
*
* @return True if an error was detected in the bit stream, false
* otherwise.
* */
private boolean cleanuppass(DataBlk cblk, MQDecoder mq, int bp,
int state[], int zc_lut[], boolean isterm) {
int j,sj; // The state index for line and stripe
int k,sk; // The data index for line and stripe
int dscanw; // The data scan-width
int sscanw; // The state scan-width
int jstep; // Stripe to stripe step for 'sj'
int kstep; // Stripe to stripe step for 'sk'
int stopsk; // The loop limit on the variable sk
int csj; // Local copy (i.e. cached) of 'state[j]'
int setmask; // The mask to set current and lower bit-planes to 1/2
// approximation
int sym; // The decoded symbol
int rlclen; // Length of RLC
int ctxt; // The context to use
int data[]; // The data buffer
int s; // The stripe index
boolean causal; // Flag to indicate if stripe-causal context
// formation is to be used
int nstripes; // The number of stripes in the code-block
int sheight; // Height of the current stripe
int off_ul,off_ur,off_dr,off_dl; // offsets
boolean error; // The error condition
// Initialize local variables
dscanw = cblk.scanw;
sscanw = cblk.w+2;
jstep = sscanw*STRIPE_HEIGHT/2-cblk.w;
kstep = dscanw*STRIPE_HEIGHT-cblk.w;
setmask = (3<>1;
data = (int[]) cblk.getData();
nstripes = (cblk.h+STRIPE_HEIGHT-1)/STRIPE_HEIGHT;
causal = (options & OPT_VERT_STR_CAUSAL) != 0;
// Pre-calculate offsets in 'state' for diagonal neighbors
off_ul = -sscanw-1; // up-left
off_ur = -sscanw+1; // up-right
off_dr = sscanw+1; // down-right
off_dl = sscanw-1; // down-left
// Decode stripe by stripe
sk = cblk.offset;
sj = sscanw+1;
for (s = nstripes-1; s >= 0; s--, sk+=kstep, sj+=jstep) {
sheight = (s != 0) ? STRIPE_HEIGHT :
cblk.h-(nstripes-1)*STRIPE_HEIGHT;
stopsk = sk+cblk.w;
// Scan by set of 1 stripe column at a time
for (; sk < stopsk; sk++, sj++) {
// Start column
j = sj;
csj = state[j];
top_half:
{
// Check for RLC: if all samples are not significant, not
// visited and do not have a non-zero context, and column is
// full height, we do RLC.
if (csj == 0 && state[j+sscanw] == 0 &&
sheight == STRIPE_HEIGHT) {
if (mq.decodeSymbol(RLC_CTXT) != 0) {
// run-length is significant, decode length
rlclen = mq.decodeSymbol(UNIF_CTXT)<<1;
rlclen |= mq.decodeSymbol(UNIF_CTXT);
// Set 'k' and 'j' accordingly
k = sk+rlclen*dscanw;
if (rlclen > 1) {
j += sscanw;
csj = state[j];
}
}
else { // RLC is insignificant
// Goto next column
continue;
}
// We just decoded the length of a significant RLC
// and a sample became significant
// Use sign coding
if ((rlclen&0x01) == 0) {
// Sample that became significant is first row of
// its column half
ctxt = SC_LUT[(csj>>SC_SHIFT_R1)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update the data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors, sign
// of neighbors)
if (rlclen != 0 || !causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j+off_ul] |=
STATE_NZ_CTXT_R2|STATE_D_DR_R2;
state[j+off_ur] |=
STATE_NZ_CTXT_R2|STATE_D_DL_R2;
}
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|
STATE_V_U_R2|STATE_V_U_SIGN_R2;
if (rlclen != 0 || !causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2|STATE_V_D_SIGN_R2;
}
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_H_L_SIGN_R1|
STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_H_R_SIGN_R1|
STATE_D_UR_R2;
}
else {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|STATE_V_U_R2;
if (rlclen != 0 || !causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2;
}
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_D_UR_R2;
}
// Changes to csj are saved later
if ((rlclen>>1) != 0) {
// Sample that became significant is in
// bottom half of column => jump to bottom
// half
break top_half;
}
// Otherwise sample that became significant is in
// top half of column => continue on top half
}
else {
// Sample that became significant is second row of
// its column half
ctxt = SC_LUT[(csj>>SC_SHIFT_R2)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update the data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// neighbor significant bit of neighbors,
// non zero context of neighbors, sign of neighbors)
state[j+off_dl] |= STATE_NZ_CTXT_R1|STATE_D_UR_R1;
state[j+off_dr] |= STATE_NZ_CTXT_R1|STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R2|STATE_NZ_CTXT_R1|
STATE_V_D_R1|STATE_V_D_SIGN_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1|STATE_V_U_SIGN_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|
STATE_H_L_R2|STATE_H_L_SIGN_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|
STATE_H_R_R2|STATE_H_R_SIGN_R2;
}
else {
csj |= STATE_SIG_R2|STATE_NZ_CTXT_R1|
STATE_V_D_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|STATE_H_L_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|STATE_H_R_R2;
}
// Save changes to csj
state[j] = csj;
if ((rlclen>>1) != 0) {
// Sample that became significant is in bottom
// half of column => we're done with this
// column
continue;
}
// Otherwise sample that became significant is in
// top half of column => we're done with top
// column
j += sscanw;
csj = state[j];
break top_half;
}
}
// Do half top of column
// If any of the two samples is not significant and has
// not been visited in the current bit-plane we can not
// skip them
if ((((csj>>1)|csj) & VSTD_MASK_R1R2) != VSTD_MASK_R1R2) {
k = sk;
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_VISITED_R1)) == 0) {
// Use zero coding
if (mq.decodeSymbol(zc_lut[csj&ZC_MASK]) != 0) {
// Became significant
// Use sign coding
ctxt = SC_LUT[(csj>>>SC_SHIFT_R1)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update the data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors,
// sign of neighbors)
if (!causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j+off_ul] |=
STATE_NZ_CTXT_R2|STATE_D_DR_R2;
state[j+off_ur] |=
STATE_NZ_CTXT_R2|STATE_D_DL_R2;
}
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|
STATE_V_U_R2|STATE_V_U_SIGN_R2;
if (!causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2|STATE_V_D_SIGN_R2;
}
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_H_L_SIGN_R1|
STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_H_R_SIGN_R1|
STATE_D_UR_R2;
}
else {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|STATE_V_U_R2;
if (!causal) {
// If in causal mode do not change
// contexts of previous stripe.
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2;
}
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_D_UR_R2;
}
}
}
if (sheight < 2) {
csj &= ~(STATE_VISITED_R1|STATE_VISITED_R2);
state[j] = csj;
continue;
}
// Scan second row
if ((csj & (STATE_SIG_R2|STATE_VISITED_R2)) == 0) {
k += dscanw;
// Use zero coding
if (mq.decodeSymbol(zc_lut[(csj>>>STATE_SEP)&
ZC_MASK]) != 0) {
// Became significant
// Use sign coding
ctxt = SC_LUT[(csj>>>SC_SHIFT_R2)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update the data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors,
// sign of neighbors)
state[j+off_dl] |=
STATE_NZ_CTXT_R1|STATE_D_UR_R1;
state[j+off_dr] |=
STATE_NZ_CTXT_R1|STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|
STATE_V_D_R1|STATE_V_D_SIGN_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1|STATE_V_U_SIGN_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|
STATE_H_L_R2|STATE_H_L_SIGN_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|
STATE_H_R_R2|STATE_H_R_SIGN_R2;
}
else {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|STATE_V_D_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|STATE_H_L_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|STATE_H_R_R2;
}
}
}
}
csj &= ~(STATE_VISITED_R1|STATE_VISITED_R2);
state[j] = csj;
// Do half bottom of column
if (sheight < 3) continue;
j += sscanw;
csj = state[j];
} // end of 'top_half' block
// If any of the two samples is not significant and has
// not been visited in the current bit-plane we can not
// skip them
if ((((csj>>1)|csj) & VSTD_MASK_R1R2) != VSTD_MASK_R1R2) {
k = sk+(dscanw<<1);
// Scan first row
if ((csj & (STATE_SIG_R1|STATE_VISITED_R1)) == 0) {
// Use zero coding
if (mq.decodeSymbol(zc_lut[csj&ZC_MASK]) != 0) {
// Became significant
// Use sign coding
ctxt = SC_LUT[(csj>>SC_SHIFT_R1)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update the data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors,
// sign of neighbors)
state[j+off_ul] |=
STATE_NZ_CTXT_R2|STATE_D_DR_R2;
state[j+off_ur] |=
STATE_NZ_CTXT_R2|STATE_D_DL_R2;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|
STATE_V_U_R2|STATE_V_U_SIGN_R2;
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2|STATE_V_D_SIGN_R2;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_H_L_SIGN_R1|
STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_H_R_SIGN_R1|
STATE_D_UR_R2;
}
else {
csj |= STATE_SIG_R1|STATE_VISITED_R1|
STATE_NZ_CTXT_R2|STATE_V_U_R2;
state[j-sscanw] |= STATE_NZ_CTXT_R2|
STATE_V_D_R2;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_L_R1|STATE_D_UL_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_H_R_R1|STATE_D_UR_R2;
}
}
}
if (sheight < 4) {
csj &= ~(STATE_VISITED_R1|STATE_VISITED_R2);
state[j] = csj;
continue;
}
// Scan second row
if ((csj & (STATE_SIG_R2|STATE_VISITED_R2)) == 0) {
k += dscanw;
// Use zero coding
if (mq.decodeSymbol(zc_lut[(csj>>>STATE_SEP)&
ZC_MASK]) != 0) {
// Became significant
// Use sign coding
ctxt = SC_LUT[(csj>>>SC_SHIFT_R2)&SC_MASK];
sym = mq.decodeSymbol(ctxt & SC_LUT_MASK) ^
(ctxt>>>SC_SPRED_SHIFT);
// Update the data
data[k] = (sym<<31) | setmask;
// Update state information (significant bit,
// visited bit, neighbor significant bit of
// neighbors, non zero context of neighbors,
// sign of neighbors)
state[j+off_dl] |=
STATE_NZ_CTXT_R1|STATE_D_UR_R1;
state[j+off_dr] |=
STATE_NZ_CTXT_R1|STATE_D_UL_R1;
// Update sign state information of neighbors
if (sym != 0) {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|
STATE_V_D_R1|STATE_V_D_SIGN_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1|STATE_V_U_SIGN_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|
STATE_H_L_R2|STATE_H_L_SIGN_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|
STATE_H_R_R2|STATE_H_R_SIGN_R2;
}
else {
csj |= STATE_SIG_R2|STATE_VISITED_R2|
STATE_NZ_CTXT_R1|STATE_V_D_R1;
state[j+sscanw] |= STATE_NZ_CTXT_R1|
STATE_V_U_R1;
state[j+1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DL_R1|STATE_H_L_R2;
state[j-1] |=
STATE_NZ_CTXT_R1|STATE_NZ_CTXT_R2|
STATE_D_DR_R1|STATE_H_R_R2;
}
}
}
}
csj &= ~(STATE_VISITED_R1|STATE_VISITED_R2);
state[j] = csj;
}
}
// Decode segment marker if we need to
if ((options & OPT_SEG_SYMBOLS) != 0) {
sym = mq.decodeSymbol(UNIF_CTXT)<<3;
sym |= mq.decodeSymbol(UNIF_CTXT)<<2;
sym |= mq.decodeSymbol(UNIF_CTXT)<<1;
sym |= mq.decodeSymbol(UNIF_CTXT);
// Set error condition accordingly
error = sym != SEG_SYMBOL;
}
else { // We can not detect any errors
error = false;
}
// Check the error resilient termination
if (isterm && (options & OPT_PRED_TERM) != 0) {
error = mq.checkPredTerm();
}
// Reset the MQ context states if we need to
if ((options & OPT_RESET_MQ) != 0) {
mq.resetCtxts();
}
// Return error condition
return error;
}
/**
* Conceals decoding errors detected in the last bit-plane. The
* concealement resets the state of the decoded data to what it was before
* the decoding of bit-plane 'bp' started. No more data should be decoded
* after this method is called for this code-block's data to which it is
* applied.
*
* @param cblk The code-block's data
*
* @param bp The last decoded bit-plane (which contains errors).
* */
private void conceal(DataBlk cblk, int bp) {
int l; // line index
int k; // array index
int kmax; // 'k' limit
int dk; // Value of data[k]
int data[]; // the data array
int setmask; // Bitmask to set approximation to 1/2 of
// known interval on significant data
int resetmask; // Bitmask to erase all the data from
// bit-plane 'bp'
// Initialize masks
setmask = 1<=0; l--) {
for (kmax = k+cblk.w; k set the
// approximation for previous bit-plane
data[k] = (dk&resetmask)|setmask;
}
else {
// Was insignificant in previous bit-planes = set to zero
data[k] = 0;
}
}
k += cblk.scanw-cblk.w;
}
}
}