All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jj2000.j2k.entropy.decoder.MQDecoder Maven / Gradle / Ivy

Go to download

JPEG2000 support for Java Advanced Imaging Image I/O Tools API core. This module is licensed under the [JJ2000 license](LICENSE.txt) and is therefore NOT compatible with the GPL 3 license. It should be compatible with the LGPL 2.1 license.

There is a newer version: 1.4.0
Show newest version
/*
 * $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 --- } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy