package org.jcodec.codecs.common.biari;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* H264 CABAC M-Coder ( decoder module )
*
* @author The JCodec project
*
*/
public class MDecoder {
private ByteBuffer _in;
private int range;
private int code;
private int nBitsPending;
private int[][] cm;
public MDecoder(ByteBuffer _in, int[][] cm) {
this._in = _in;
this.range = 510;
this.cm = cm;
initCodeRegister();
}
/**
* Initializes code register. Loads 9 bits from the stream into working area
* of code register ( bits 8 - 16) leaving 7 bits in the pending area of
* code register (bits 0 - 7)
*
* @throws IOException
*/
protected void initCodeRegister() {
readOneByte();
if (nBitsPending != 8)
throw new RuntimeException("Empty stream");
code <<= 8;
readOneByte();
code <<= 1;
nBitsPending -= 9;
}
protected void readOneByte() {
if (!_in.hasRemaining())
return;
int b = _in.get() & 0xff;
code |= b;
nBitsPending += 8;
}
/**
* Decodes one bin from arithmetice code word
*
* @param cm
* @return
* @throws IOException
*/
public int decodeBin(int m) {
int bin;
int qIdx = (range >> 6) & 0x3;
int rLPS = MConst.rangeLPS[qIdx][cm[0][m]];
range -= rLPS;
int rs8 = range << 8;
if (code < rs8) {
// MPS
if (cm[0][m] < 62)
cm[0][m]++;
renormalize();
bin = cm[1][m];
} else {
// LPS
range = rLPS;
code -= rs8;
renormalize();
bin = 1 - cm[1][m];
if (cm[0][m] == 0)
cm[1][m] = 1 - cm[1][m];
cm[0][m] = MConst.transitLPS[cm[0][m]];
}
// System.out.println("CABAC BIT [" + m + "]: " + bin);
return bin;
}
/**
* Special decoding process for 'end of slice' flag. Uses probability state
* 63.
*
* @param cm
* @return
* @throws IOException
*/
public int decodeFinalBin() {
range -= 2;
if (code < (range << 8)) {
renormalize();
// System.out.println("CABAC BIT [-2]: 0");
return 0;
} else {
// System.out.println("CABAC BIT [-2]: 1");
return 1;
}
}
/**
* Special decoding process for symbols with uniform distribution
*
* @return
* @throws IOException
*/
public int decodeBinBypass() {
code <<= 1;
--nBitsPending;
if (nBitsPending <= 0)
readOneByte();
int tmp = code - (range << 8);
if (tmp < 0) {
// System.out.println("CABAC BIT [-1]: 0");
return 0;
} else {
// System.out.println("CABAC BIT [-1]: 1");
code = tmp;
return 1;
}
}
/**
* Shifts the current interval to either 1/2 or 0 (code = (code << 1) &
* 0x1ffff) and scales it by 2 (range << 1).
*
* Reads new byte from the input stream into code value if there are no more
* bits pending
*
* @throws IOException
*/
private void renormalize() {
while (range < 256) {
range <<= 1;
code <<= 1;
code &= 0x1ffff;
--nBitsPending;
if (nBitsPending <= 0)
readOneByte();
}
}
}