C# Class CSJ2K.j2k.entropy.encoder.MQCoder

This class implements the MQ arithmetic coder. When initialized a specific state can be specified for each context, which may be adapted to the probability distribution that is expected for that context.

The type of length calculation and termination can be chosen at construction time. ---- Tricks that have been tried to improve speed ----

1) Merging Qe and mPS and doubling the lookup tables
Merge the mPS into Qe, as the sign bit (if Qe>=0 the sense of MPS is 0, if Qe<0 the sense is 1), and double the lookup tables. The first half of the lookup tables correspond to Qe>=0 (i.e. the sense of MPS is 0) and the second half to Qe<0 (i.e. the sense of MPS is 1). The nLPS lookup table is modified to incorporate the changes in the sense of MPS, by making it jump from the first to the second half and vice-versa, when a change is specified by the swicthLM lookup table. See JPEG book, section 13.2, page 225.
There is NO speed improvement in doing this, actually there is a slight decrease, probably due to the fact that often Q has to be negated. Also the fact that a brach of the type "if (bit==mPS[li])" is replaced by two simpler braches of the type "if (bit==0)" and "if (q<0)" may contribute to that.

2) Removing cT
It is possible to remove the cT counter by setting a flag bit in the high bits of the C register. This bit will be automatically shifted left whenever a renormalization shift occurs, which is equivalent to decreasing cT. When the flag bit reaches the sign bit (leftmost bit), which is equivalenet to cT==0, the byteOut() procedure is called. This test can be done efficiently with "c<0" since C is a signed quantity. Care must be taken in byteOut() to reset the bit in order to not interfere with other bits in the C register. See JPEG book, page 228.
There is NO speed improvement in doing this. I don't really know why since the number of operations whenever a renormalization occurs is decreased. Maybe it is due to the number of extra operations in the byteOut(), terminate() and getNumCodedBytes() procedures.

3) Change the convention of MPS and LPS.
Making the LPS interval be above the MPS interval (MQ coder convention is the opposite) can reduce the number of operations along the MPS path. In order to generate the same bit stream as with the MQ convention the output bytes need to be modified accordingly. The basic rule for this is that C = (C'^0xFF...FF)-A, where C is the codestream for the MQ convention and C' is the codestream generated by this other convention. Note that this affects bit-stuffing as well.
This has not been tested yet.

4) Removing normalization while loop on MPS path
Since in the MPS path Q is guaranteed to be always greater than 0x4000 (decimal 0.375) it is never necessary to do more than 1 renormalization shift. Therefore the test of the while loop, and the loop itself, can be removed.

5) Simplifying test on A register
Since A is always less than or equal to 0xFFFF, the test "(a & 0x8000)==0" can be replaced by the simplete test "a < 0x8000". This test is simpler in Java since it involves only 1 operation (although the original test can be converted to only one operation by smart Just-In-Time compilers)
This change has been integrated in the decoding procedures.

6) Speedup mode
Implemented a method that uses the speedup mode of the MQ-coder if possible. This should greately improve performance when coding long runs of MPS symbols that have high probability. However, to take advantage of this, the entropy coder implementation has to explicetely use it. The generated bit stream is the same as if no speedup mode would have been used.
Implemented but performance not tested yet.

7) Multiple-symbol coding
Since the time spent in a method call is non-negligable, coding several symbols with one method call reduces the overhead per coded symbol. The decodeSymbols() method implements this. However, to take advantage of it, the implementation of the entropy coder has to explicitely use it.
Implemented but performance not tested yet.

Show file Open project: cureos/csj2k Class Usage Examples

Public Methods

Method Description
MQCoder ( CSJ2K.j2k.entropy.encoder.ByteOutputBuffer oStream, int nrOfContexts, int init ) : System

Instantiates a new MQ-coder, with the specified number of contexts and initial states. The compressed bytestream is written to the 'oStream' object.

codeSymbol ( int bit, int context ) : void

This function performs the arithmetic encoding of one symbol. The function receives a bit that is to be encoded and a context with which to encode it.

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.

codeSymbols ( int bits, int cX, int n ) : void

This function performs the arithmetic encoding of several symbols together. The function receives an array of symbols that are to be encoded and an array containing the contexts with which to encode them.

The advantage of using this function is that the cost of the method call is amortized by the number of coded symbols per method call.

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.

fastCodeSymbols ( int bit, int ctxt, int n ) : void

This method performs the coding of the symbol 'bit', using context 'ctxt', 'n' times, using the MQ-coder speedup mode if possible.

If the symbol 'bit' is the current more probable symbol (MPS) and qe[ctxt]<=0x4000, and (A-0x8000)>=qe[ctxt], speedup mode will be used. Otherwise the normal mode will be used. The speedup mode can significantly improve the speed of arithmetic coding when several MPS symbols, with a high probability distribution, must be coded with the same context. The generated bit stream is the same as if the normal mode was used.

This method is also faster than the 'codeSymbols()' and 'codeSymbol()' ones, for coding the same symbols with the same context several times, when speedup mode can not be used, although not significantly.

finishLengthCalculation ( int rates, int n ) : void

Terminates the calculation of the required length for each coding pass. This method must be called just after the 'terminate()' one has been called for each terminated MQ segment.

The values in 'rates' must have been compensated for any offset due to previous terminated segments, so that the correct index to the stored coded data is used.

reset ( ) : void

Reinitializes the MQ coder and the underlying 'ByteOutputBuffer' buffer as if a new object was instantaited. All the data in the 'ByteOutputBuffer' buffer is erased and the state and contexts of the MQ coder are reinitialized). Additionally any saved MQ states are discarded.

resetCtxt ( int c ) : void

Resets a context to the original probability distribution, and sets its more probable symbol to 0.

resetCtxts ( ) : void

Resets all contexts to their original probability distribution and sets all more probable symbols to 0.

terminate ( ) : int

This function flushes the remaining encoded bits and makes sure that enough information is written to the bit stream to be able to finish decoding, and then it reinitializes the internal state of the MQ coder but without modifying the context states.

After calling this method the 'finishLengthCalculation()' method should be called, after compensating the returned length for the length of previous coded segments, so that the length calculation is finalized.

The type of termination used depends on the one specified at the constructor.

Private Methods

Method Description
byteOut ( ) : void

This function puts one byte of compressed bits in the output stream. The highest 8 bits of c are then put in b to be the next byte to write. This method delays the output of any 0xFF bytes until a non 0xFF byte has to be written to the output bit stream (the 'delFF' variable signals if there is a delayed 0xff byte).

saveState ( ) : void

Saves the current state of the MQ coder (just the registers, not the contexts) so that a near optimal length calculation can be performed later.

Method Details

MQCoder() public method

Instantiates a new MQ-coder, with the specified number of contexts and initial states. The compressed bytestream is written to the 'oStream' object.
public MQCoder ( CSJ2K.j2k.entropy.encoder.ByteOutputBuffer oStream, int nrOfContexts, int init ) : System
oStream CSJ2K.j2k.entropy.encoder.ByteOutputBuffer where to output the compressed data. /// ///
nrOfContexts int The number of contexts used by the MQ coder. /// ///
init int The initial state for each context. A reference is kept to /// this array to reinitialize the contexts whenever 'reset()' or /// 'resetCtxts()' is called. /// ///
return System

codeSymbol() public method

This function performs the arithmetic encoding of one symbol. The function receives a bit that is to be encoded and a context with which to encode it.

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.

public codeSymbol ( int bit, int context ) : void
bit int The symbol to be encoded, must be 0 or 1. /// ///
context int the context with which to encode the symbol. /// ///
return void

codeSymbols() public method

This function performs the arithmetic encoding of several symbols together. The function receives an array of symbols that are to be encoded and an array containing the contexts with which to encode them.

The advantage of using this function is that the cost of the method call is amortized by the number of coded symbols per method call.

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.

public codeSymbols ( int bits, int cX, int n ) : void
bits int An array containing the symbols to be encoded. Valid /// symbols are 0 and 1. /// ///
cX int The context for each of the symbols to be encoded. /// ///
n int The number of symbols to encode. /// ///
return void

fastCodeSymbols() public method

This method performs the coding of the symbol 'bit', using context 'ctxt', 'n' times, using the MQ-coder speedup mode if possible.

If the symbol 'bit' is the current more probable symbol (MPS) and qe[ctxt]<=0x4000, and (A-0x8000)>=qe[ctxt], speedup mode will be used. Otherwise the normal mode will be used. The speedup mode can significantly improve the speed of arithmetic coding when several MPS symbols, with a high probability distribution, must be coded with the same context. The generated bit stream is the same as if the normal mode was used.

This method is also faster than the 'codeSymbols()' and 'codeSymbol()' ones, for coding the same symbols with the same context several times, when speedup mode can not be used, although not significantly.

public fastCodeSymbols ( int bit, int ctxt, int n ) : void
bit int The symbol do code, 0 or 1. /// ///
ctxt int The context to us in coding the symbol. /// ///
n int The number of times that the symbol must be coded. /// ///
return void

finishLengthCalculation() public method

Terminates the calculation of the required length for each coding pass. This method must be called just after the 'terminate()' one has been called for each terminated MQ segment.

The values in 'rates' must have been compensated for any offset due to previous terminated segments, so that the correct index to the stored coded data is used.

public finishLengthCalculation ( int rates, int n ) : void
rates int The array containing the values returned by /// 'getNumCodedBytes()' for each coding pass. /// ///
n int The index in the 'rates' array of the last terminated length. /// ///
return void

reset() public method

Reinitializes the MQ coder and the underlying 'ByteOutputBuffer' buffer as if a new object was instantaited. All the data in the 'ByteOutputBuffer' buffer is erased and the state and contexts of the MQ coder are reinitialized). Additionally any saved MQ states are discarded.
public reset ( ) : void
return void

resetCtxt() public method

Resets a context to the original probability distribution, and sets its more probable symbol to 0.
public resetCtxt ( int c ) : void
c int The number of the context (it starts at 0). /// ///
return void

resetCtxts() public method

Resets all contexts to their original probability distribution and sets all more probable symbols to 0.
public resetCtxts ( ) : void
return void

terminate() public method

This function flushes the remaining encoded bits and makes sure that enough information is written to the bit stream to be able to finish decoding, and then it reinitializes the internal state of the MQ coder but without modifying the context states.

After calling this method the 'finishLengthCalculation()' method should be called, after compensating the returned length for the length of previous coded segments, so that the length calculation is finalized.

The type of termination used depends on the one specified at the constructor.

public terminate ( ) : int
return int