jj2000.j2k.entropy.decoder.MQDecoder Maven / Gradle / Ivy
Show all versions of jai-imageio-jpeg2000 Show documentation
/*
* $RCSfile: MQDecoder.java,v $
* $Revision: 1.1 $
* $Date: 2005/02/11 05:02:06 $
* $State: Exp $
*
* Class: MQDecoder
*
* Description: Class that encodes a number of bits using the
* MQ arithmetic decoder
*
*
*
* 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.util.ArrayUtil;
/**
* This class implements the MQ arithmetic decoder. It is implemented using
* the software conventions decoder for better performance (i.e. execution
* time performance). The initial states for each context of the MQ-coder are
* specified in the constructor.
*
*/
// A trick to test for increased speed: merge the Qe and mPS into 1 thing by
// using the sign bit of Qe to signal mPS (positive-or-0 is 0, negative is 1),
// and doubling the Qe, nMPS and nLPS tables. This gets rid of the swicthLM
// table since it can be integrated as special cases in the doubled nMPS and
// nLPS tables. See the JPEG book, chapter 13. The decoded decision can be
// calculated as (q>>>31).
public class MQDecoder {
/** The data structures containing the probabilities for the LPS */
final static
int qe[]={0x5601, 0x3401, 0x1801, 0x0ac1, 0x0521, 0x0221, 0x5601,
0x5401, 0x4801, 0x3801, 0x3001, 0x2401, 0x1c01, 0x1601,
0x5601, 0x5401, 0x5101, 0x4801, 0x3801, 0x3401, 0x3001,
0x2801, 0x2401, 0x2201, 0x1c01, 0x1801, 0x1601, 0x1401,
0x1201, 0x1101, 0x0ac1, 0x09c1, 0x08a1, 0x0521, 0x0441,
0x02a1, 0x0221, 0x0141, 0x0111, 0x0085, 0x0049, 0x0025,
0x0015, 0x0009, 0x0005, 0x0001, 0x5601 };
/** The indexes of the next MPS */
final static
int nMPS[]={ 1 , 2, 3, 4, 5,38, 7, 8, 9,10,11,12,13,29,15,16,17,
18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,
35,36,37,38,39,40,41,42,43,44,45,45,46 };
/** The indexes of the next LPS */
final static
int nLPS[]={ 1 , 6, 9,12,29,33, 6,14,14,14,17,18,20,21,14,14,15,
16,17,18,19,19,20,21,22,23,24,25,26,27,28,29,30,31,
32,33,34,35,36,37,38,39,40,41,42,43,46 };
/** Whether LPS and MPS should be switched */
final static
int switchLM[]={ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
/** The ByteInputBuffer used to read the compressed bit stream. */
ByteInputBuffer in;
/** The current most probable signal for each context */
int[] mPS;
/** The current index of each context */
int[] I;
/** The current bit code */
int c;
/** The bit code counter */
int cT;
/** The current interval */
int a;
/** The last byte read */
int b;
/** Flag indicating if a marker has been found */
boolean markerFound;
/** The initial state of each context */
final int initStates[];
/**
* Instantiates a new MQ-decoder, with the specified number of contexts and
* initial states. The compressed bytestream is read from the 'iStream'
* object.
*
* @param iStream the stream that contains the coded bits
*
* @param nrOfContexts The number of contexts used
*
* @param initStates The initial state for each context. A reference is
* kept to this array to reinitialize the contexts whenever 'reset()' or
* 'resetCtxts()' is called.
*
*
*
*/
public MQDecoder(ByteInputBuffer iStream, int nrOfContexts,
int initStates[]){
in = iStream;
// Default initialization of the statistics bins is MPS=0 and
// I=0
I=new int[nrOfContexts];
mPS=new int[nrOfContexts];
// Save the initial states
this.initStates = initStates;
// Initialize
init();
// Set the contexts
resetCtxts();
}
/**
* Decodes 'n' symbols from the bit stream using the same context
* 'ctxt'. If possible the MQ-coder speedup mode will be used to speed up
* decoding. The speedup mode is used if Q (the LPS probability for 'ctxt'
* is low enough) and the A and C registers permit decoding several MPS
* symbols without renormalization.
*
* Speedup mode should be used when decoding long runs of MPS with high
* probability with the same context.
*
*
This methiod will return the decoded symbols differently if speedup
* mode was used or not. If true is returned, then speedup mode was used
* and the 'n' decoded symbols are all the same and it is returned ain
* bits[0] only. If false is returned then speedup mode was not used, the
* decoded symbols are probably not all the same and they are returned in
* bits[0], bits[1], ... bits[n-1].
*
* @param bits The array where to put the decoded symbols. Must be of
* length 'n' or more.
*
* @param ctxt The context to use in decoding the symbols.
*
* @param n The number of symbols to decode.
*
* @return True if speedup mode was used, false if not. If speedup mode
* was used then all the decoded symbols are the same and its value is
* returned in 'bits[0]' only (not in bits[1], bits[2], etc.).
*
*
* */
public final boolean fastDecodeSymbols(int[] bits, int ctxt, int n) {
int q; // LPS probability for context
int idx; // Index of current state
int la; // cache for A register
int i; // counter
idx = I[ctxt];
q = qe[idx];
// This is a first attempt to implement speedup mode, it is probably
// not the most efficient way of doing it.
if ((q<0x4000) && (n <= (a-(c>>>16)-1)/q) &&
(n <= (a-0x8000)/q+1)) {
// Q is small enough. There will be no modification of C that
// affects decoding, and Q can be substracted from A several
// times. We will decode all MPS.
a -= n*q;
if (a >= 0x8000) { // No renormalization needed
bits[0] = mPS[ctxt];
return true; // Done, used speedup mode
}
else { // renormalization needed
I[ctxt] = nMPS[idx];
// Renormalize (MPS: no need for while loop)
if (cT == 0)
byteIn();
a <<= 1;
c <<= 1;
cT--;
// End renormalization
bits[0] = mPS[ctxt];
return true; // Done, used speedup mode
}
}
else { // Normal mode
la = a; // cache A register
for (i=0; i>>16) < la) {
if(la >= 0x8000){
bits[i] = mPS[ctxt];
}
else {
// -- MPS Exchange
if(la >= q){
bits[i] = mPS[ctxt];
idx = nMPS[idx];
q = qe[idx];
// I[ctxt] set at end of loop
// -- Renormalize (MPS: no need for while loop)
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
// -- End renormalization
}
else{
bits[i] = 1-mPS[ctxt];
if(switchLM[idx]==1)
mPS[ctxt] = 1-mPS[ctxt];
idx = nLPS[idx];
q = qe[idx];
// I[ctxt] set at end of loop
// -- Renormalize
do{
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
}while(la < 0x8000);
// -- End renormalization
}
// -- End MPS Exchange
}
}
else {
c -= (la<<16);
// -- LPS Exchange
if(la < q){
la = q;
bits[i] = mPS[ctxt];
idx = nMPS[idx];
q = qe[idx];
// I[ctxt] set at end of loop
// -- Renormalize (MPS: no need for while loop)
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
// -- End renormalization
}
else {
la = q;
bits[i] = 1-mPS[ctxt];
if(switchLM[idx] == 1)
mPS[ctxt] = 1-mPS[ctxt];
idx = nLPS[idx];
q = qe[idx];
// I[ctxt] set at end of loop
// -- Renormalize
do{
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
} while (la < 0x8000);
// -- End renormalization
}
// -- End LPS Exchange
}
}
a = la; // save cached A register
I[ctxt] = idx; // save current index for context
return false; // done, did not use speedup mode
} // End normal mode
}
/**
* This function performs the arithmetic decoding. The function receives
* an array in which to put the decoded symbols and an array of contexts
* with which to decode them.
*
* Each context has a current MPS and an index describing what the
* current probability is for the LPS. Each bit is decoded and if the
* probability of the LPS exceeds .5, the MPS and LPS are switched.
*
* @param bits The array where to place the decoded symbols. It should be
* long enough to contain 'n' elements.
*
* @param cX The context to use in decoding each symbol.
*
* @param n The number of symbols to decode
*
*
*/
public final void decodeSymbols(int[] bits, int[] cX, int n){
int q;
int ctxt;
int la; // cache for A register value
int index;
int i;
// NOTE: (a < 0x8000) is equivalent to ((a & 0x8000)==0)
// since 'a' is always less than or equal to 0xFFFF
// NOTE: conditional exchange guarantees that A for MPS is
// always greater than 0x4000 (i.e. 0.375)
// => one renormalization shift is enough for MPS
// => no need to do a renormalization while loop for MPS
for (i=0; i>>16) < a) {
if(a >= 0x8000){
bits[i] = mPS[ctxt];
}
else {
la = a;
// -- MPS Exchange
if(la >= q){
bits[i] = mPS[ctxt];
I[ctxt] = nMPS[index];
// -- Renormalize (MPS: no need for while loop)
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
// -- End renormalization
}
else{
bits[i] = 1-mPS[ctxt];
if(switchLM[index]==1)
mPS[ctxt] = 1-mPS[ctxt];
I[ctxt] = nLPS[index];
// -- Renormalize
do{
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
}while(la < 0x8000);
// -- End renormalization
}
// -- End MPS Exchange
a = la;
}
}
else {
la = a;
c -= (la<<16);
// -- LPS Exchange
if(la < q){
la = q;
bits[i] = mPS[ctxt];
I[ctxt] = nMPS[index];
// -- Renormalize (MPS: no need for while loop)
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
// -- End renormalization
}
else {
la = q;
bits[i] = 1-mPS[ctxt];
if(switchLM[index] == 1)
mPS[ctxt] = 1-mPS[ctxt];
I[ctxt] = nLPS[index];
// -- Renormalize
do{
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
} while (la < 0x8000);
// -- End renormalization
}
// -- End LPS Exchange
a = la;
}
}
}
/**
* Arithmetically decodes one symbol from the bit stream with the given
* context and returns its decoded value.
*
* Each context has a current MPS and an index describing what the
* current probability is for the LPS. Each bit is encoded and if the
* probability of the LPS exceeds .5, the MPS and LPS are switched.
*
* @param context The context to use in decoding the symbol
*
* @return The decoded symbol, 0 or 1.
*
*
*/
public final int decodeSymbol(int context){
int q;
int la;
int index;
int decision;
index = I[context];
q = qe[index];
// NOTE: (a < 0x8000) is equivalent to ((a & 0x8000)==0)
// since 'a' is always less than or equal to 0xFFFF
// NOTE: conditional exchange guarantees that A for MPS is
// always greater than 0x4000 (i.e. 0.375)
// => one renormalization shift is enough for MPS
// => no need to do a renormalization while loop for MPS
a -= q;
if ((c>>>16) < a) {
if(a >= 0x8000){
decision = mPS[context];
}
else {
la = a;
// -- MPS Exchange
if(la >= q){
decision = mPS[context];
I[context] = nMPS[index];
// -- Renormalize (MPS: no need for while loop)
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
// -- End renormalization
}
else{
decision = 1-mPS[context];
if(switchLM[index]==1)
mPS[context] = 1-mPS[context];
I[context] = nLPS[index];
// -- Renormalize
do{
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
}while(la < 0x8000);
// -- End renormalization
}
// -- End MPS Exchange
a = la;
}
}
else {
la = a;
c -= (la<<16);
// -- LPS Exchange
if(la < q){
la = q;
decision = mPS[context];
I[context] = nMPS[index];
// -- Renormalize (MPS: no need for while loop)
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
// -- End renormalization
}
else {
la = q;
decision = 1-mPS[context];
if(switchLM[index] == 1)
mPS[context] = 1-mPS[context];
I[context] = nLPS[index];
// -- Renormalize
do{
if(cT==0)
byteIn();
la<<=1;
c<<=1;
cT--;
} while (la < 0x8000);
// -- End renormalization
}
// -- End LPS Exchange
a = la;
}
return decision;
}
/**
* Checks for past errors in the decoding process using the predictable
* error resilient termination. This works only if the encoder used the
* predictable error resilient MQ termination, otherwise it reports wrong
* results. If an error is detected it means that the MQ bit stream has
* been wrongly decoded or that the MQ terminated segment length is too
* long. If no errors are detected it does not necessarily mean that the
* MQ bit stream has been correctly decoded.
*
* @return True if errors are found, false otherwise.
* */
public boolean checkPredTerm() {
int k; // Number of bits that where added in the termination process
int q;
// 1) if everything has been OK, 'b' must be 0xFF if a terminating
// marker has not yet been found
if (b != 0xFF && !markerFound) return true;
// 2) if cT is not 0, we must have already reached the terminating
// marker
if (cT != 0 && !markerFound) return true;
// 3) If cT is 1 there where no spare bits at the encoder, this is all
// that we can check
if (cT == 1) return false;
// 4) if cT is 0, then next byte must be the second byte of a
// terminating marker (i.e. larger than 0x8F) if the terminating
// marker has not been reached yet
if (cT == 0) {
if (!markerFound) {
// Get next byte and check
b=in.read()&0xFF;
if (b <= 0x8F) return true;
}
// Adjust cT for last byte
cT = 8;
}
// 5) Now we can calculate the number 'k' of bits having error
// resilience information, which is the number of bits left to
// normalization in the C register, minus 1.
k = cT-1;
// 6) The predictable termination policy is as if an LPS interval was
// coded that caused a renormalization of 'k' bits, before the
// termination marker started
// We first check if an LPS is decoded, that causes a renormalization
// of 'k' bits. Worst case is smallest LPS probability 'q' that causes
// a renormalization of 'k' bits.
q = 0x8000>>k;
// Check that we can decode an LPS interval of probability 'q'
a -= q;
if ((c>>>16) < a) {
// Error: MPS interval decoded
return true;
}
// OK: LPS interval decoded
c -= (a<<16);
// -- LPS Exchange
// Here 'a' can not be smaller than 'q' because the minimum value
// for 'a' is 0x8000-0x4000=0x4000 and 'q' is set to a value equal
// to or smaller than that.
a = q;
// -- Renormalize
do{
if(cT==0) byteIn();
a<<=1;
c<<=1;
cT--;
} while (a < 0x8000);
// -- End renormalization
// -- End LPS Exchange
// 7) Everything seems OK, we have checked the C register for the LPS
// symbols and ensured that it is followed by bits synthetized by the
// termination marker.
return false;
}
/**
* This function gets one byte of compressed bits from the in-stream.
* the byte is added to c. If the byte is 0xFF and the next byte is greater
* than 0x8F, the byte after 0xFF is a marker.
*
*
*
*/
private void byteIn(){
if(!markerFound){
if(b==0xFF){
b=in.read()&0xFF; // Convert EOFs (-1) to 0xFF
if(b>0x8F){
markerFound=true;
// software-convention decoder: c unchanged
cT=8;
}else{
c += 0xFE00 - (b<<9);
cT=7;
}
}else{
b=in.read()&0xFF; // Convert EOFs (-1) to 0xFF
c += 0xFF00 - (b<<8);
cT=8;
}
}
else{
// software-convention decoder: c unchanged
cT=8;
}
}
/**
* Returns the number of contexts in the arithmetic coder.
*
* @return The number of contexts
*
*
**/
public final int getNumCtxts(){
return I.length;
}
/**
* Resets a context to the original probability distribution.
*
* @param c The number of the context (it starts at 0).
*
*
*
*/
public final void resetCtxt(int c){
I[c] = initStates[c];
mPS[c] = 0;
}
/**
* Resets a context to the original probability distribution. The
* original probability distribution depends on the actual
* implementation of the arithmetic coder or decoder.
*
* @param c The index of the context (it starts at 0).
*
*
*
*/
public final void resetCtxts(){
System.arraycopy(initStates,0,I,0,I.length);
ArrayUtil.intArraySet(mPS,0);
}
/**
* Resets the MQ decoder to start a new segment. This is like recreating a
* new MQDecoder object with new input data.
*
* @param buf The byte array containing the MQ encoded data. If null the
* current byte array is assumed.
*
* @param off The index of the first element in 'buf' to be decoded. If
* negative the byte just after the previous segment is assumed, only
* valid if 'buf' is null.
*
* @param len The number of bytes in 'buf' to be decoded. Any subsequent
* bytes are taken to be 0xFF.
*
*
* */
public final void nextSegment(byte buf[], int off, int len) {
// Set the new input
in.setByteArray(buf,off,len);
// Reinitialize MQ
init();
}
/**
* Returns the underlying 'ByteInputBuffer' from where the MQ
* coded input bytes are read.
*
* @return The underlying ByteInputBuffer.
*
* */
public ByteInputBuffer getByteInputBuffer() {
return in;
}
/**
* Initializes the state of the MQ coder, without modifying the current
* context states. It sets the registers (A,C,B) and the "marker found"
* state to the initial state, to start the decoding of a new segment.
*
*
To have a complete reset of the MQ (as if a new MQDecoder object was
* created) 'resetCtxts()' should be called after this method.
*
*
* */
private void init() {
// --- INITDEC
markerFound = false;
// Read first byte
b=in.read()&0xFF;
// Software conventions decoder
c=(b^0xFF)<<16;
byteIn();
c=c<<7;
cT=cT-7;
a=0x8000;
// End of INITDEC ---
}
}