package org.jcodec.codecs.vpx; import static org.jcodec.codecs.vpx.VP8Util.PRED_BLOCK_127; import static org.jcodec.codecs.vpx.VP8Util.pickDefaultPrediction; import org.jcodec.api.NotImplementedException; import org.jcodec.api.NotSupportedException; import org.jcodec.codecs.vpx.VP8Util.QuantizationParams; import org.jcodec.codecs.vpx.VP8Util.SubblockConstants; import org.jcodec.common.model.Picture8Bit; import java.lang.System; import java.util.Arrays; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author The JCodec project * */ public class Macroblock { public int filterLevel; public int chromaMode; public int skipCoeff; public final Subblock[][] ySubblocks; public final Subblock y2; public final Subblock[][] uSubblocks; public final Subblock[][] vSubblocks; public final int Rrow; public final int column; public int lumaMode; boolean skipFilter; public int segment = 0; public boolean debug = true; public QuantizationParams quants; public Macroblock(int y, int x) { this.ySubblocks = new Subblock[4][4]; this.y2 = new Subblock(this, 0, 0, VP8Util.PLANE.Y2); this.uSubblocks = new Subblock[2][2]; this.vSubblocks = new Subblock[2][2]; this.Rrow = y; this.column = x; for (int row = 0; row < 4; row++) for (int col = 0; col < 4; col++) this.ySubblocks[row][col] = new Subblock(this, row, col, VP8Util.PLANE.Y1); for (int row = 0; row < 2; row++) for (int col = 0; col < 2; col++) { uSubblocks[row][col] = new Subblock(this, row, col, VP8Util.PLANE.U); vSubblocks[row][col] = new Subblock(this, row, col, VP8Util.PLANE.V); } } public void dequantMacroBlock(Macroblock[][] mbs) { QuantizationParams p = this.quants; if (this.lumaMode != SubblockConstants.B_PRED) { int acQValue = p.y2AC; int dcQValue = p.y2DC; int input[] = new int[16]; input[0] = this.y2.tokens[0] * dcQValue; for (int x = 1; x < 16; x++) input[x] = this.y2.tokens[x] * acQValue; /** * if (plane == PLANE.U || plane == PLANE.V) { QValue = p.chromaAC; if (i == 0) QValue = p.chromaDC; } else { QValue = p.yAC; if (i == 0) QValue = p.yDC; } */ this.y2.residue = VP8DCT.decodeWHT(input); for (int row = 0; row < 4; row++) for (int col = 0; col < 4; col++) this.ySubblocks[row][col].dequantSubblock(p.yDC, p.yAC, y2.residue[row * 4 + col]); this.predictY(mbs); this.predictUV(mbs); for (int row = 0; row < 2; row++) { for (int col = 0; col < 2; col++) { this.uSubblocks[row][col].dequantSubblock(p.chromaDC, p.chromaAC, null); this.vSubblocks[row][col].dequantSubblock(p.chromaDC, p.chromaAC, null); } } this.reconstruct(); } else { for (int row = 0; row < 4; row++) { for (int col = 0; col < 4; col++) { Subblock sb = this.ySubblocks[row][col]; sb.dequantSubblock(p.yDC, p.yAC, null); sb.predict(mbs); sb.reconstruct(); } } this.predictUV(mbs); for (int row = 0; row < 2; row++) { for (int col = 0; col < 2; col++) { Subblock sb = this.uSubblocks[row][col]; sb.dequantSubblock(p.chromaDC, p.chromaAC, null); sb.reconstruct(); } } for (int row = 0; row < 2; row++) { for (int col = 0; col < 2; col++) { Subblock sb = this.vSubblocks[row][col]; sb.dequantSubblock(p.chromaDC, p.chromaAC, null); sb.reconstruct(); } } } } public void reconstruct() { for (int row = 0; row < 4; row++) for (int col = 0; col < 4; col++) ySubblocks[row][col].reconstruct(); for (int row = 0; row < 2; row++) for (int col = 0; col < 2; col++) uSubblocks[row][col].reconstruct(); for (int row = 0; row < 2; row++) for (int col = 0; col < 2; col++) vSubblocks[row][col].reconstruct(); } public void predictUV(Macroblock[][] mbs) { Macroblock aboveMb = mbs[Rrow - 1][column]; Macroblock leftMb = mbs[Rrow][column - 1]; switch (this.chromaMode) { case SubblockConstants.DC_PRED: // System.out.println("UV DC_PRED"); boolean up_available = false; boolean left_available = false; int uAvg = 0; int vAvg = 0; int expected_udc = 128; int expected_vdc = 128; if (column > 1) left_available = true; if (Rrow > 1) up_available = true; if (up_available || left_available) { if (up_available) { for (int j = 0; j < 2; j++) { Subblock usb = aboveMb.uSubblocks[1][j]; Subblock vsb = aboveMb.vSubblocks[1][j]; for (int i = 0; i < 4; i++) { uAvg += usb.val[3 * 4 + i]; vAvg += vsb.val[3 * 4 + i]; } } } if (left_available) { for (int j = 0; j < 2; j++) { Subblock usb = leftMb.uSubblocks[j][1]; Subblock vsb = leftMb.vSubblocks[j][1]; for (int i = 0; i < 4; i++) { uAvg += usb.val[i * 4 + 3]; vAvg += vsb.val[i * 4 + 3]; } } } int shift = 2; if (up_available) shift++; if (left_available) shift++; expected_udc = (uAvg + (1 << (shift - 1))) >> shift; expected_vdc = (vAvg + (1 << (shift - 1))) >> shift; } int ufill[] = new int[16]; for (int aRow = 0; aRow < 4; aRow++) for (int aCol = 0; aCol < 4; aCol++) ufill[aRow * 4 + aCol] = expected_udc; int vfill[] = new int[16]; for (int aRow = 0; aRow < 4; aRow++) for (int aCol = 0; aCol < 4; aCol++) vfill[aRow * 4 + aCol] = expected_vdc; for (int aRow = 0; aRow < 2; aRow++) { for (int aCol = 0; aCol < 2; aCol++) { Subblock usb = uSubblocks[aRow][aCol]; Subblock vsb = vSubblocks[aRow][aCol]; usb._predict = ufill; vsb._predict = vfill; } } break; case SubblockConstants.V_PRED: // System.out.println("UV V_PRED"); Subblock[] aboveUSb = new Subblock[2]; Subblock[] aboveVSb = new Subblock[2]; for (int aCol = 0; aCol < 2; aCol++) { aboveUSb[aCol] = aboveMb.uSubblocks[1][aCol]; aboveVSb[aCol] = aboveMb.vSubblocks[1][aCol]; } for (int aRow = 0; aRow < 2; aRow++) for (int aCol = 0; aCol < 2; aCol++) { Subblock usb = uSubblocks[aRow][aCol]; Subblock vsb = vSubblocks[aRow][aCol]; int ublock[] = new int[16]; int vblock[] = new int[16]; for (int pRow = 0; pRow < 4; pRow++) // pRow for pixel row index for (int pCol = 0; pCol < 4; pCol++) { // pCol for pixel column index ublock[pRow * 4 + pCol] = aboveUSb[aCol].val != null ? aboveUSb[aCol].val[3 * 4 + pCol] : 127; vblock[pRow * 4 + pCol] = aboveVSb[aCol].val != null ? aboveVSb[aCol].val[3 * 4 + pCol] : 127; } usb._predict = ublock; vsb._predict = vblock; } break; case SubblockConstants.H_PRED: // System.out.println("UV H_PRED"); Subblock[] leftUSb = new Subblock[2]; Subblock[] leftVSb = new Subblock[2]; for (int aCol = 0; aCol < 2; aCol++) { leftUSb[aCol] = leftMb.uSubblocks[aCol][1]; leftVSb[aCol] = leftMb.vSubblocks[aCol][1]; } for (int aRow = 0; aRow < 2; aRow++) for (int aCol = 0; aCol < 2; aCol++) { Subblock usb = uSubblocks[aRow][aCol]; Subblock vsb = vSubblocks[aRow][aCol]; int ublock[] = new int[16]; int vblock[] = new int[16]; for (int pRow = 0; pRow < 4; pRow++) for (int pCol = 0; pCol < 4; pCol++) { ublock[pRow * 4 + pCol] = leftUSb[aRow].val != null ? leftUSb[aRow].val[pRow * 4 + 3] : 129; vblock[pRow * 4 + pCol] = leftVSb[aRow].val != null ? leftVSb[aRow].val[pRow * 4 + 3] : 129; } usb._predict = ublock; vsb._predict = vblock; } break; case SubblockConstants.TM_PRED: // TODO: // System.out.println("UV TM_PRED MB"); Macroblock ALMb = mbs[Rrow - 1][column - 1]; Subblock ALUSb = ALMb.uSubblocks[1][1]; int alu = ALUSb.val[3 * 4 + 3]; Subblock ALVSb = ALMb.vSubblocks[1][1]; int alv = ALVSb.val[3 * 4 + 3]; aboveUSb = new Subblock[2]; leftUSb = new Subblock[2]; aboveVSb = new Subblock[2]; leftVSb = new Subblock[2]; for (int x = 0; x < 2; x++) { aboveUSb[x] = aboveMb.uSubblocks[1][x]; leftUSb[x] = leftMb.uSubblocks[x][1]; aboveVSb[x] = aboveMb.vSubblocks[1][x]; leftVSb[x] = leftMb.vSubblocks[x][1]; } for (int sbRow = 0; sbRow < 2; sbRow++) { for (int pRow = 0; pRow < 4; pRow++) { for (int sbCol = 0; sbCol < 2; sbCol++) { if (uSubblocks[sbRow][sbCol].val == null) uSubblocks[sbRow][sbCol].val = new int[16]; if (vSubblocks[sbRow][sbCol].val == null) vSubblocks[sbRow][sbCol].val = new int[16]; for (int pCol = 0; pCol < 4; pCol++) { int upred = leftUSb[sbRow].val[pRow * 4 + 3] + aboveUSb[sbCol].val[3 * 4 + pCol] - alu; upred = QuantizationParams.clip255(upred); uSubblocks[sbRow][sbCol].val[pRow * 4 + pCol] = upred; int vpred = leftVSb[sbRow].val[pRow * 4 + 3] + aboveVSb[sbCol].val[3 * 4 + pCol] - alv; vpred = QuantizationParams.clip255(vpred); vSubblocks[sbRow][sbCol].val[pRow * 4 + pCol] = vpred; } } } } break; default: System.err.println("TODO predict_mb_uv: " + this.lumaMode); System.exit(0); } } private void predictY(Macroblock[][] mbs) { Macroblock aboveMb = mbs[Rrow - 1][column]; Macroblock leftMb = mbs[Rrow][column - 1]; switch (this.lumaMode) { case SubblockConstants.DC_PRED: predictLumaDC(aboveMb, leftMb); break; case SubblockConstants.V_PRED: predictLumaV(aboveMb); break; case SubblockConstants.H_PRED: predictLumaH(leftMb); break; case SubblockConstants.TM_PRED: Macroblock upperLeft = mbs[Rrow - 1][column - 1]; Subblock ALSb = upperLeft.ySubblocks[3][3]; int aboveLeft = ALSb.val[3 * 4 + 3]; predictLumaTM(aboveMb, leftMb, aboveLeft); break; default: System.err.println("TODO predict_mb_y: " + this.lumaMode); System.exit(0); } } private void predictLumaDC(Macroblock above, Macroblock left) { boolean hasAbove = Rrow > 1; boolean hasLeft = column > 1; int expected_dc = 128; if (hasAbove || hasLeft) { int average = 0; if (hasAbove) { for (int j = 0; j < 4; j++) { Subblock sb = above.ySubblocks[3][j]; for (int i = 0; i < 4; i++) average += sb.val[3 * 4 + i]; } } if (hasLeft) { for (int j = 0; j < 4; j++) { Subblock sb = left.ySubblocks[j][3]; for (int i = 0; i < 4; i++) average += sb.val[i * 4 + 3]; } } int shift = 3; if (hasAbove) shift++; if (hasLeft) shift++; expected_dc = (average + (1 << (shift - 1))) >> shift; } int fill[] = new int[16]; for (int i = 0; i < 16; i++) fill[i] = expected_dc; for (int y = 0; y < 4; y++) for (int x = 0; x < 4; x++) ySubblocks[y][x]._predict = fill; } private void predictLumaH(Macroblock leftMb) { Subblock[] leftYSb = new Subblock[4]; for (int row = 0; row < 4; row++) leftYSb[row] = leftMb.ySubblocks[row][3]; for (int row = 0; row < 4; row++) for (int col = 0; col < 4; col++) { Subblock sb = ySubblocks[row][col]; int block[] = new int[16]; for (int bRow = 0; bRow < 4; bRow++) for (int bCol = 0; bCol < 4; bCol++) { block[bRow * 4 + bCol] = leftYSb[row].val != null ? leftYSb[row].val[bRow * 4 + 3] : 129; } sb._predict = block; } } private void predictLumaTM(Macroblock above, Macroblock left, int aboveLeft) { Subblock[] leftYSb; Subblock[] aboveYSb = new Subblock[4]; leftYSb = new Subblock[4]; for (int col = 0; col < 4; col++) aboveYSb[col] = above.ySubblocks[3][col]; for (int row = 0; row < 4; row++) leftYSb[row] = left.ySubblocks[row][3]; for (int row = 0; row < 4; row++) for (int pRow = 0; pRow < 4; pRow++) for (int col = 0; col < 4; col++) { if (ySubblocks[row][col].val == null) ySubblocks[row][col].val = new int[16]; for (int pCol = 0; pCol < 4; pCol++) { int pred = leftYSb[row].val[pRow * 4 + 3] + aboveYSb[col].val[3 * 4 + pCol] - aboveLeft; ySubblocks[row][col].val[pRow * 4 + pCol] = QuantizationParams.clip255(pred); } } } private void predictLumaV(Macroblock above) { Subblock[] aboveYSb = new Subblock[4]; for (int col = 0; col < 4; col++) aboveYSb[col] = above.ySubblocks[3][col]; for (int row = 0; row < 4; row++) { for (int col = 0; col < 4; col++) { Subblock sb = ySubblocks[row][col]; int block[] = new int[16]; for (int j = 0; j < 4; j++) for (int i = 0; i < 4; i++) { block[j * 4 + i] = aboveYSb[col].val != null ? aboveYSb[col].val[3 * 4 + i] : 127; // block[j*4+i] = aboveYSb[x].getPredict(SubBlock.B_VE_PRED, false)[3*4+i]; } sb._predict = block; } } } public Subblock getBottomSubblock(int x, VP8Util.PLANE plane) { if (plane == VP8Util.PLANE.Y1) { return ySubblocks[3][x]; } else if (plane == VP8Util.PLANE.U) { return uSubblocks[1][x]; } else if (plane == VP8Util.PLANE.V) { return vSubblocks[1][x]; } else if (plane == VP8Util.PLANE.Y2) { return y2; } return null; } public Subblock getRightSubBlock(int y, VP8Util.PLANE plane) { if (plane == VP8Util.PLANE.Y1) { return ySubblocks[y][3]; } else if (plane == VP8Util.PLANE.U) { return uSubblocks[y][1]; } else if (plane == VP8Util.PLANE.V) { return vSubblocks[y][1]; } else if (plane == VP8Util.PLANE.Y2) { return y2; } return null; } public void decodeMacroBlock(Macroblock[][] mbs, VPXBooleanDecoder tockenDecoder, int[][][][] coefProbs) { if (this.skipCoeff > 0) { this.skipFilter = this.lumaMode != SubblockConstants.B_PRED; } else if (this.lumaMode != SubblockConstants.B_PRED) decodeMacroBlockTokens(true, mbs, tockenDecoder, coefProbs); else decodeMacroBlockTokens(false, mbs, tockenDecoder, coefProbs); } private void decodeMacroBlockTokens(boolean withY2, Macroblock[][] mbs, VPXBooleanDecoder decoder, int[][][][] coefProbs) { skipFilter = false; if (withY2) { skipFilter = skipFilter | decodePlaneTokens(1, VP8Util.PLANE.Y2, false, mbs, decoder, coefProbs); } skipFilter = skipFilter | decodePlaneTokens(4, VP8Util.PLANE.Y1, withY2, mbs, decoder, coefProbs); skipFilter = skipFilter | decodePlaneTokens(2, VP8Util.PLANE.U, false, mbs, decoder, coefProbs); skipFilter = skipFilter | decodePlaneTokens(2, VP8Util.PLANE.V, false, mbs, decoder, coefProbs); skipFilter = !skipFilter; } private boolean decodePlaneTokens(int dimentions, VP8Util.PLANE plane, boolean withY2, Macroblock[][] mbs, VPXBooleanDecoder decoder, int[][][][] coefProbs) { boolean r = false; for (int row = 0; row < dimentions; row++) { for (int col = 0; col < dimentions; col++) { int lc = 0; Subblock sb = null; //this.ySubblocks[row][col]; if (VP8Util.PLANE.Y1.equals(plane)) { sb = ySubblocks[row][col]; } else if (VP8Util.PLANE.U.equals(plane)) { sb = uSubblocks[row][col]; } else if (VP8Util.PLANE.V.equals(plane)) { sb = vSubblocks[row][col]; } else if (VP8Util.PLANE.Y2.equals(plane)) { sb = y2; } // System.out.println("mb["+mb.x+"]["+mb.y+"];"); // System.out.println("sb["+sb.x+"]["+sb.y+"];"); // System.out.println("int[] sb = "+sb.toString()+";"); Subblock l = sb.getLeft(plane, mbs); Subblock a = sb.getAbove(plane, mbs); lc = (l.someValuePresent ? 1 : 0) + (a.someValuePresent ? 1 : 0); sb.decodeSubBlock(decoder, coefProbs, lc, VP8Util.planeToType(plane, withY2), withY2); // System.out.println("int[] sb = "+sb.toString()+";"); r = r | sb.someValuePresent; } } return r; } public static class Subblock { public int[] val; public int[] _predict; public int[] residue; private int col; private int row; private VP8Util.PLANE plane; public int mode; public boolean someValuePresent; private int[] tokens; private Macroblock self; public Subblock(Macroblock self, int row, int col, VP8Util.PLANE plane) { this.self = self; this.row = row; this.col = col; this.plane = plane; this.tokens = new int[16]; } public void predict(Macroblock[][] mbs) { Subblock aboveSb = getAbove(plane, mbs); Subblock leftSb = getLeft(plane, mbs); int[] above = new int[4]; int[] left = new int[4]; int[] aboveValues = aboveSb.val != null ? aboveSb.val : PRED_BLOCK_127; above[0] = aboveValues[0 + 4 * 3]; above[1] = aboveValues[1 + 4 * 3]; above[2] = aboveValues[2 + 4 * 3]; above[3] = aboveValues[3 + 4 * 3]; int[] leftValues = leftSb.val != null ? leftSb.val : pickDefaultPrediction(this.mode); left[0] = leftValues[3 + 4 * 0]; left[1] = leftValues[3 + 4 * 1]; left[2] = leftValues[3 + 4 * 2]; left[3] = leftValues[3 + 4 * 3]; Subblock aboveLeftSb = aboveSb.getLeft(this.plane, mbs); int aboveLeft; if (leftSb.val == null && aboveSb.val == null) { aboveLeft = 127; // AL.getPredict(this.getMode(), false)[3][3]; } else if (aboveSb.val == null) { aboveLeft = 127; // AL.getPredict(this.getMode(), false)[3][3]; } else { aboveLeft = aboveLeftSb.val != null ? aboveLeftSb.val[3 + 4 * 3] : pickDefaultPrediction(this.mode)[3 + 4 * 3]; } int ar[] = getAboveRightLowestRow(mbs); switch (this.mode) { case SubblockConstants.B_DC_PRED: this._predict = VP8Util.predictDC(above, left); break; case SubblockConstants.B_TM_PRED: this._predict = VP8Util.predictTM(above, left, aboveLeft); break; case SubblockConstants.B_VE_PRED: this._predict = VP8Util.predictVE(above, aboveLeft, ar); break; case SubblockConstants.B_HE_PRED: this._predict = VP8Util.predictHE(left, aboveLeft); break; case SubblockConstants.B_LD_PRED: this._predict = VP8Util.predictLD(above, ar); break; case SubblockConstants.B_RD_PRED: this._predict = VP8Util.predictRD(above, left, aboveLeft); break; case SubblockConstants.B_VR_PRED: this._predict = VP8Util.predictVR(above, left, aboveLeft); break; case SubblockConstants.B_VL_PRED: this._predict = VP8Util.predictVL(above, ar); break; case SubblockConstants.B_HD_PRED: this._predict = VP8Util.predictHD(above, left, aboveLeft); break; case SubblockConstants.B_HU_PRED: this._predict = VP8Util.predictHU(left); break; default: throw new NotSupportedException("TODO: unknowwn mode: "+this.mode); } } public void reconstruct() { int aRow, aCol; int p[] = this.val != null ? this.val : this._predict; int[] dest = new int[16]; for (aRow = 0; aRow < 4; aRow++) { for (aCol = 0; aCol < 4; aCol++) { int a = QuantizationParams.clip255(this.residue[aRow * 4 + aCol] + p[aRow * 4 + aCol]); dest[aRow * 4 + aCol] = a; } } this.val = dest; } public Subblock getAbove(VP8Util.PLANE plane, Macroblock[][] mbs) { if (this.row > 0) if (VP8Util.PLANE.Y1.equals(this.plane)) return self.ySubblocks[this.row - 1][this.col]; else if (VP8Util.PLANE.U.equals(this.plane)) return self.uSubblocks[this.row - 1][this.col]; else if (VP8Util.PLANE.V.equals(this.plane)) return self.vSubblocks[this.row - 1][this.col]; int x = this.col; Macroblock mb2 = mbs[self.Rrow - 1][self.column]; if (plane == VP8Util.PLANE.Y2) { while (mb2.lumaMode == SubblockConstants.B_PRED) mb2 = mbs[mb2.Rrow - 1][mb2.column]; } return mb2.getBottomSubblock(x, plane); } public Subblock getLeft(VP8Util.PLANE p, Macroblock[][] mbs) { if (this.col > 0) if (VP8Util.PLANE.Y1.equals(this.plane)) return self.ySubblocks[this.row][this.col - 1]; else if (VP8Util.PLANE.U.equals(this.plane)) return self.uSubblocks[this.row][this.col - 1]; else if (VP8Util.PLANE.V.equals(this.plane)) return self.vSubblocks[this.row][this.col - 1]; int y = this.row; Macroblock mb2 = mbs[self.Rrow][self.column - 1]; if (p == VP8Util.PLANE.Y2) while (mb2.lumaMode == SubblockConstants.B_PRED) mb2 = mbs[mb2.Rrow][mb2.column - 1]; return mb2.getRightSubBlock(y, p); } private int[] getAboveRightLowestRow(Macroblock[][] mbs) { // this might break at right edge if( ! VP8Util.PLANE.Y1.equals(this.plane)) throw new NotImplementedException("Decoder.getAboveRight: not implemented for Y2 and chroma planes"); int[] aboveRightDistValues; if(row==0 && col<3) { // top row Macroblock mb2=mbs[self.Rrow-1][self.column]; Subblock aboveRight = mb2.ySubblocks[3][col+1]; aboveRightDistValues = aboveRight.val; } else if(row>0 && col<3) { //not right edge or top row Subblock aboveRight = self.ySubblocks[row-1][col+1]; aboveRightDistValues = aboveRight.val; } else if(row==0 && col==3) { //top right Macroblock aboveRightMb = mbs[self.Rrow-1][self.column+1]; if(aboveRightMb.column < (mbs[0].length-1)){ Subblock aboveRightSb = aboveRightMb.ySubblocks[3][0]; aboveRightDistValues = aboveRightSb.val; } else { aboveRightDistValues = new int [16]; int fillVal = aboveRightMb.Rrow==0 ? 127 : mbs[self.Rrow-1][self.column].ySubblocks[3][3].val[3*4+3]; Arrays.fill(aboveRightDistValues, fillVal); } } else { //else use top right Subblock sb2 = self.ySubblocks[0][3]; return sb2.getAboveRightLowestRow(mbs); } if (aboveRightDistValues == null) aboveRightDistValues = PRED_BLOCK_127; int ar[] = new int[4]; ar[0] = aboveRightDistValues[0 + 4 * 3]; ar[1] = aboveRightDistValues[1 + 4 * 3]; ar[2] = aboveRightDistValues[2 + 4 * 3]; ar[3] = aboveRightDistValues[3 + 4 * 3]; return ar; } public void decodeSubBlock(VPXBooleanDecoder decoder, int[][][][] allProbs, int ilc, int type, boolean withY2) { int startAt = 0; if (withY2) startAt = 1; int lc = ilc; int count = 0; int v = 1; boolean skip = false; someValuePresent = false; while (!(v == SubblockConstants.dct_eob) && count + startAt < 16) { int[] probs = allProbs[type][SubblockConstants.vp8CoefBands[count + startAt]][lc]; if (!skip){ v = decoder.readTree(SubblockConstants.vp8CoefTree, probs); } else { v = decoder.readTreeSkip(SubblockConstants.vp8CoefTree, probs, 1); } int dv = decodeToken(decoder, v); lc = 0; skip = false; if (dv == 1 || dv == -1) lc = 1; else if (dv > 1 || dv < -1) lc = 2; else if (dv == SubblockConstants.DCT_0) skip = true; if (v != SubblockConstants.dct_eob) tokens[SubblockConstants.vp8defaultZigZag1d[count + startAt]] = dv; count++; } for (int x = 0; x < 16; x++) if (tokens[x] != 0) someValuePresent = true; } private int decodeToken(VPXBooleanDecoder decoder, int initialValue) { int token = initialValue; if (initialValue == SubblockConstants.cat_5_6) { token = 5 + DCTextra(decoder, SubblockConstants.Pcat1); } if (initialValue == SubblockConstants.cat_7_10) { token = 7 + DCTextra(decoder, SubblockConstants.Pcat2); } if (initialValue == SubblockConstants.cat_11_18) { token = 11 + DCTextra(decoder, SubblockConstants.Pcat3); } if (initialValue == SubblockConstants.cat_19_34) { token = 19 + DCTextra(decoder, SubblockConstants.Pcat4); } if (initialValue == SubblockConstants.cat_35_66) { token = 35 + DCTextra(decoder, SubblockConstants.Pcat5); } if (initialValue == SubblockConstants.cat_67_2048) { token = 67 + DCTextra(decoder, SubblockConstants.Pcat6); } if (initialValue != SubblockConstants.DCT_0 && initialValue != SubblockConstants.dct_eob) { if (decoder.decodeBit() > 0) token = -token; } return token; } private int DCTextra(VPXBooleanDecoder decoder, int p[]) { int v = 0; int offset = 0; do { v += v + decoder.decodeBool(p[offset]); offset++; } while (p[offset] > 0); return v; } public void dequantSubblock(int dc, int ac, Integer Dc) { int[] adjustedValues = new int[16]; adjustedValues[0] = tokens[0] * dc; for (int i = 1; i < 16; i++) adjustedValues[i] = tokens[i] * ac; if (Dc != null) adjustedValues[0] = Dc; residue = VP8DCT.decodeDCT(adjustedValues); } } public void put(int mbRow, int mbCol, Picture8Bit p) { byte[] luma = p.getPlaneData(0); byte[] cb = p.getPlaneData(1); byte[] cr = p.getPlaneData(2); int strideLuma = p.getPlaneWidth(0); int strideChroma = p.getPlaneWidth(1); for (int lumaRow = 0; lumaRow < 4; lumaRow++) for (int lumaCol = 0; lumaCol < 4; lumaCol++) for (int lumaPRow = 0; lumaPRow < 4; lumaPRow++) for (int lumaPCol = 0; lumaPCol < 4; lumaPCol++) { int y = (mbRow << 4) + (lumaRow << 2) + lumaPRow; int x = (mbCol << 4) + (lumaCol << 2) + lumaPCol; if (x >= strideLuma || y >= luma.length / strideLuma) continue; int yy = ySubblocks[lumaRow][lumaCol].val[lumaPRow * 4 + lumaPCol]; luma[strideLuma * y + x] = (byte) (yy - 128); } for (int chromaRow = 0; chromaRow < 2; chromaRow++) for (int chromaCol = 0; chromaCol < 2; chromaCol++) for (int chromaPRow = 0; chromaPRow < 4; chromaPRow++) for (int chromaPCol = 0; chromaPCol < 4; chromaPCol++) { int y = (mbRow << 3) + (chromaRow << 2) + chromaPRow; int x = (mbCol << 3) + (chromaCol << 2) + chromaPCol; if (x >= strideChroma || y >= cb.length / strideChroma) continue; int u = uSubblocks[chromaRow][chromaCol].val[chromaPRow * 4 + chromaPCol]; int v = vSubblocks[chromaRow][chromaCol].val[chromaPRow * 4 + chromaPCol]; cb[strideChroma * y + x] = (byte) (u - 128); cr[strideChroma * y + x] = (byte) (v - 128); } } }