package org.jcodec.codecs.vpx; import org.jcodec.common.tools.MathUtil; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author The JCodec project * */ public class VPXBitstream { public static final int[] coeffBandMapping = { 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7 }; private int[][][][] tokenBinProbs; private int whtNzLeft = 0; private int[] whtNzTop; private int[][] dctNzLeft; private int[][] dctNzTop; public VPXBitstream(int[][][][] tokenBinProbs, int mbWidth) { this.dctNzLeft = new int[][] { new int[4], new int[2], new int[2] }; this.tokenBinProbs = tokenBinProbs; whtNzTop = new int[mbWidth]; dctNzTop = new int[][] { new int[mbWidth << 2], new int[mbWidth << 1], new int[mbWidth << 1] }; } public void encodeCoeffsWHT(VPXBooleanEncoder bc, int[] coeffs, int mbX) { int nCoeff = fastCountCoeffWHT(coeffs); encodeCoeffs(bc, coeffs, 0, nCoeff, 1, (mbX == 0 || whtNzLeft <= 0 ? 0 : 1) + (whtNzTop[mbX] > 0 ? 1 : 0)); whtNzLeft = nCoeff; whtNzTop[mbX] = nCoeff; } public void encodeCoeffsDCT15(VPXBooleanEncoder bc, int[] coeffs, int mbX, int blkX, int blkY) { int nCoeff = countCoeff(coeffs, 16); int blkAbsX = (mbX << 2) + blkX; encodeCoeffs(bc, coeffs, 1, nCoeff, 0, (blkAbsX == 0 || dctNzLeft[0][blkY] <= 0 ? 0 : 1) + (dctNzTop[0][blkAbsX] > 0 ? 1 : 0)); dctNzLeft[0][blkY] = Math.max(nCoeff - 1, 0); dctNzTop[0][blkAbsX] = Math.max(nCoeff - 1, 0); } public void encodeCoeffsDCT16(VPXBooleanEncoder bc, int[] coeffs, int mbX, int blkX, int blkY) { int nCoeff = countCoeff(coeffs, 16); int blkAbsX = (mbX << 2) + blkX; encodeCoeffs(bc, coeffs, 0, nCoeff, 3, (blkAbsX == 0 || dctNzLeft[0][blkY] <= 0 ? 0 : 1) + (dctNzTop[0][blkAbsX] > 0 ? 1 : 0)); dctNzLeft[0][blkY] = nCoeff; dctNzTop[0][blkAbsX] = nCoeff; } public void encodeCoeffsDCTUV(VPXBooleanEncoder bc, int[] coeffs, int comp, int mbX, int blkX, int blkY) { int nCoeff = countCoeff(coeffs, 16); int blkAbsX = (mbX << 1) + blkX; encodeCoeffs(bc, coeffs, 0, nCoeff, 2, (blkAbsX == 0 || dctNzLeft[comp][blkY] <= 0 ? 0 : 1) + (dctNzTop[comp][blkAbsX] > 0 ? 1 : 0)); dctNzLeft[comp][blkY] = nCoeff; dctNzTop[comp][blkAbsX] = nCoeff; } /** * Encodes DCT/WHT coefficients into the provided instance of a boolean * encoder * * @param bc * @param coeffs */ public void encodeCoeffs(VPXBooleanEncoder bc, int[] coeffs, int firstCoeff, int nCoeff, int blkType, int ctx) { boolean prevZero = false; int i; for (i = firstCoeff; i < nCoeff; i++) { int[] probs = tokenBinProbs[blkType][coeffBandMapping[i]][ctx]; int coeffAbs = MathUtil.abs(coeffs[i]); if (!prevZero) bc.writeBit(probs[0], 1); if (coeffAbs == 0) { bc.writeBit(probs[1], 0); ctx = 0; } else { bc.writeBit(probs[1], 1); if (coeffAbs == 1) { bc.writeBit(probs[2], 0); ctx = 1; } else { ctx = 2; bc.writeBit(probs[2], 1); if (coeffAbs <= 4) { bc.writeBit(probs[3], 0); if (coeffAbs == 2) bc.writeBit(probs[4], 0); else { bc.writeBit(probs[4], 1); bc.writeBit(probs[5], coeffAbs - 3); } } else { bc.writeBit(probs[3], 1); if (coeffAbs <= 10) { bc.writeBit(probs[6], 0); if (coeffAbs <= 6) { bc.writeBit(probs[7], 0); bc.writeBit(159, coeffAbs - 5); } else { bc.writeBit(probs[7], 1); int d = coeffAbs - 7; bc.writeBit(165, d >> 1); bc.writeBit(145, d & 1); } } else { bc.writeBit(probs[6], 1); if (coeffAbs <= 34) { bc.writeBit(probs[8], 0); if (coeffAbs <= 18) { bc.writeBit(probs[9], 0); writeCat3Ext(bc, coeffAbs); } else { bc.writeBit(probs[9], 1); writeCat4Ext(bc, coeffAbs); } } else { bc.writeBit(probs[8], 1); if (coeffAbs <= 66) { bc.writeBit(probs[10], 0); writeCatExt(bc, coeffAbs, 35, VPXConst.probCoeffExtCat5); } else { bc.writeBit(probs[10], 1); writeCatExt(bc, coeffAbs, 67, VPXConst.probCoeffExtCat6); } } } } } bc.writeBit(128, MathUtil.sign(coeffs[i])); } prevZero = coeffAbs == 0; } if (nCoeff < 16) { int[] probs = tokenBinProbs[blkType][coeffBandMapping[i]][ctx]; bc.writeBit(probs[0], 0); } } private static void writeCat3Ext(VPXBooleanEncoder bc, int coeff) { int d = coeff - 11; bc.writeBit(173, d >> 2); bc.writeBit(148, (d >> 1) & 1); bc.writeBit(140, d & 1); } private static void writeCat4Ext(VPXBooleanEncoder bc, int coeff) { int d = coeff - 19; bc.writeBit(176, d >> 3); bc.writeBit(155, (d >> 2) & 1); bc.writeBit(140, (d >> 1) & 1); bc.writeBit(135, d & 1); } private static final void writeCatExt(VPXBooleanEncoder bc, int coeff, int catOff, int[] cat) { int d = coeff - catOff; for (int b = cat.length - 1, i = 0; b >= 0; b--) { bc.writeBit(cat[i++], (d >> b) & 1); } } /** * Counts number of non-zero coefficients for a WHT block, with shortcut as * most of them are likely to be non-zero * * @param coeffs * @return */ private int fastCountCoeffWHT(int[] coeffs) { if (coeffs[15] != 0) return 16; else return countCoeff(coeffs, 15); } /** * Counts number of non-zero coefficients * * @param coeffs * @param nCoeff * @return */ private int countCoeff(int[] coeffs, int nCoeff) { while (nCoeff > 0) { --nCoeff; if (coeffs[nCoeff] != 0) return nCoeff + 1; } return nCoeff; } }