package org.jcodec.codecs.h264.decode;
import static org.jcodec.common.tools.MathUtil.clip;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Builds intra prediction for intra 4x4 coded macroblocks
*
* @author The JCodec project
*
*/
public class Intra4x4PredictionBuilder {
public static void predictWithMode(int mode, int[] residual, boolean leftAvailable, boolean topAvailable,
boolean topRightAvailable, byte[] leftRow, byte[] topLine, byte topLeft[], int mbOffX, int blkX, int blkY,
byte[] pixOut) {
switch (mode) {
case 0:
predictVertical(residual, topAvailable, topLine, mbOffX, blkX, blkY, pixOut);
break;
case 1:
predictHorizontal(residual, leftAvailable, leftRow, mbOffX, blkX, blkY, pixOut);
break;
case 2:
predictDC(residual, leftAvailable, topAvailable, leftRow, topLine, mbOffX, blkX, blkY, pixOut);
break;
case 3:
predictDiagonalDownLeft(residual, topAvailable, topRightAvailable, topLine, mbOffX, blkX, blkY, pixOut);
break;
case 4:
predictDiagonalDownRight(residual, leftAvailable, topAvailable, leftRow, topLine, topLeft, mbOffX, blkX,
blkY, pixOut);
break;
case 5:
predictVerticalRight(residual, leftAvailable, topAvailable, leftRow, topLine, topLeft, mbOffX, blkX, blkY,
pixOut);
break;
case 6:
predictHorizontalDown(residual, leftAvailable, topAvailable, leftRow, topLine, topLeft, mbOffX, blkX, blkY,
pixOut);
break;
case 7:
predictVerticalLeft(residual, topAvailable, topRightAvailable, topLine, mbOffX, blkX, blkY, pixOut);
break;
case 8:
predictHorizontalUp(residual, leftAvailable, leftRow, mbOffX, blkX, blkY, pixOut);
break;
}
int oo1 = mbOffX + blkX;
int off1 = (blkY << 4) + blkX + 3;
topLeft[blkY >> 2] = topLine[oo1 + 3];
leftRow[blkY] = pixOut[off1];
leftRow[blkY + 1] = pixOut[off1 + 16];
leftRow[blkY + 2] = pixOut[off1 + 32];
leftRow[blkY + 3] = pixOut[off1 + 48];
int off2 = (blkY << 4) + blkX + 48;
topLine[oo1] = pixOut[off2];
topLine[oo1 + 1] = pixOut[off2 + 1];
topLine[oo1 + 2] = pixOut[off2 + 2];
topLine[oo1 + 3] = pixOut[off2 + 3];
}
public static void predictVertical(int[] residual, boolean topAvailable, byte[] topLine, int mbOffX, int blkX,
int blkY, byte[] pixOut) {
int pixOff = (blkY << 4) + blkX;
int toff = mbOffX + blkX;
int rOff = 0;
for (int j = 0; j < 4; ++j) {
pixOut[pixOff] = (byte) clip(residual[rOff] + topLine[toff], -128, 127);
pixOut[pixOff + 1] = (byte) clip(residual[rOff + 1] + topLine[toff + 1], -128, 127);
pixOut[pixOff + 2] = (byte) clip(residual[rOff + 2] + topLine[toff + 2], -128, 127);
pixOut[pixOff + 3] = (byte) clip(residual[rOff + 3] + topLine[toff + 3], -128, 127);
rOff += 4;
pixOff += 16;
}
}
public static void predictHorizontal(int[] residual, boolean leftAvailable, byte[] leftRow, int mbOffX, int blkX,
int blkY, byte[] pixOut) {
int pixOff = (blkY << 4) + blkX;
int rOff = 0;
for (int j = 0; j < 4; j++) {
int l = leftRow[blkY + j];
pixOut[pixOff] = (byte) clip(residual[rOff] + l, -128, 127);
pixOut[pixOff + 1] = (byte) clip(residual[rOff + 1] + l, -128, 127);
pixOut[pixOff + 2] = (byte) clip(residual[rOff + 2] + l, -128, 127);
pixOut[pixOff + 3] = (byte) clip(residual[rOff + 3] + l, -128, 127);
rOff += 4;
pixOff += 16;
}
}
public static void predictDC(int[] residual, boolean leftAvailable, boolean topAvailable, byte[] leftRow,
byte[] topLine, int mbOffX, int blkX, int blkY, byte[] pixOut) {
int val;
if (leftAvailable && topAvailable) {
val = (leftRow[blkY] + leftRow[blkY + 1] + leftRow[blkY + 2] + leftRow[blkY + 3] + topLine[mbOffX + blkX]
+ topLine[mbOffX + blkX + 1] + topLine[mbOffX + blkX + 2] + topLine[mbOffX + blkX + 3] + 4) >> 3;
} else if (leftAvailable) {
val = (leftRow[blkY] + leftRow[blkY + 1] + leftRow[blkY + 2] + leftRow[blkY + 3] + 2) >> 2;
} else if (topAvailable) {
val = (topLine[mbOffX + blkX] + topLine[mbOffX + blkX + 1] + topLine[mbOffX + blkX + 2]
+ topLine[mbOffX + blkX + 3] + 2) >> 2;
} else {
val = 0;
}
int pixOff = (blkY << 4) + blkX;
int rOff = 0;
for (int j = 0; j < 4; j++) {
pixOut[pixOff] = (byte) clip(residual[rOff] + val, -128, 127);
pixOut[pixOff + 1] = (byte) clip(residual[rOff + 1] + val, -128, 127);
pixOut[pixOff + 2] = (byte) clip(residual[rOff + 2] + val, -128, 127);
pixOut[pixOff + 3] = (byte) clip(residual[rOff + 3] + val, -128, 127);
pixOff += 16;
rOff += 4;
}
}
public static void predictDiagonalDownLeft(int[] residual, boolean topAvailable, boolean topRightAvailable,
byte[] topLine, int mbOffX, int blkX, int blkY, byte[] pixOut) {
int to = mbOffX + blkX;
int tr0 = topLine[to + 3], tr1 = topLine[to + 3], tr2 = topLine[to + 3], tr3 = topLine[to + 3];
if (topRightAvailable) {
tr0 = topLine[to + 4];
tr1 = topLine[to + 5];
tr2 = topLine[to + 6];
tr3 = topLine[to + 7];
}
int c0 = ((topLine[to] + topLine[to + 2] + (topLine[to + 1] << 1) + 2) >> 2);
int c1 = ((topLine[to + 1] + topLine[to + 3] + (topLine[to + 2] << 1) + 2) >> 2);
int c2 = ((topLine[to + 2] + tr0 + (topLine[to + 3] << 1) + 2) >> 2);
int c3 = ((topLine[to + 3] + tr1 + (tr0 << 1) + 2) >> 2);
int c4 = ((tr0 + tr2 + (tr1 << 1) + 2) >> 2);
int c5 = ((tr1 + tr3 + (tr2 << 1) + 2) >> 2);
int c6 = ((tr2 + 3 * (tr3) + 2) >> 2);
int off = (blkY << 4) + blkX;
pixOut[off] = (byte) clip(residual[0] + c0, -128, 127);
pixOut[off + 1] = (byte) clip(residual[1] + c1, -128, 127);
pixOut[off + 2] = (byte) clip(residual[2] + c2, -128, 127);
pixOut[off + 3] = (byte) clip(residual[3] + c3, -128, 127);
pixOut[off + 16] = (byte) clip(residual[4] + c1, -128, 127);
pixOut[off + 17] = (byte) clip(residual[5] + c2, -128, 127);
pixOut[off + 18] = (byte) clip(residual[6] + c3, -128, 127);
pixOut[off + 19] = (byte) clip(residual[7] + c4, -128, 127);
pixOut[off + 32] = (byte) clip(residual[8] + c2, -128, 127);
pixOut[off + 33] = (byte) clip(residual[9] + c3, -128, 127);
pixOut[off + 34] = (byte) clip(residual[10] + c4, -128, 127);
pixOut[off + 35] = (byte) clip(residual[11] + c5, -128, 127);
pixOut[off + 48] = (byte) clip(residual[12] + c3, -128, 127);
pixOut[off + 49] = (byte) clip(residual[13] + c4, -128, 127);
pixOut[off + 50] = (byte) clip(residual[14] + c5, -128, 127);
pixOut[off + 51] = (byte) clip(residual[15] + c6, -128, 127);
}
public static void predictDiagonalDownRight(int[] residual, boolean leftAvailable, boolean topAvailable,
byte[] leftRow, byte[] topLine, byte[] topLeft, int mbOffX, int blkX, int blkY, byte[] pixOut) {
int off = (blkY << 4) + blkX;
int c0 = ((topLine[mbOffX + blkX] + 2 * topLeft[blkY >> 2] + leftRow[blkY] + 2) >> 2);
int c1 = ((topLeft[blkY >> 2] + (topLine[mbOffX + blkX + 0] << 1) + topLine[mbOffX + blkX + 1] + 2) >> 2);
int c2 = ((topLine[mbOffX + blkX] + (topLine[mbOffX + blkX + 1] << 1) + topLine[mbOffX + blkX + 2] + 2) >> 2);
int c3 = ((topLine[mbOffX + blkX + 1] + (topLine[mbOffX + blkX + 2] << 1) + topLine[mbOffX + blkX + 3] + 2) >> 2);
pixOut[off] = (byte) clip(residual[0] + c0, -128, 127);
pixOut[off + 1] = (byte) clip(residual[1] + c1, -128, 127);
pixOut[off + 2] = (byte) clip(residual[2] + c2, -128, 127);
pixOut[off + 3] = (byte) clip(residual[3] + c3, -128, 127);
int c4 = ((topLeft[blkY >> 2] + (leftRow[blkY] << 1) + leftRow[blkY + 1] + 2) >> 2);
int c6 = ((topLeft[blkY >> 2] + (topLine[mbOffX + blkX] << 1) + topLine[mbOffX + blkX + 1] + 2) >> 2);
int c7 = ((topLine[mbOffX + blkX] + (topLine[mbOffX + blkX + 1] << 1) + topLine[mbOffX + blkX + 2] + 2) >> 2);
pixOut[off + 16] = (byte) clip(residual[4] + c4, -128, 127);
pixOut[off + 17] = (byte) clip(residual[5] + c0, -128, 127);
pixOut[off + 18] = (byte) clip(residual[6] + c6, -128, 127);
pixOut[off + 19] = (byte) clip(residual[7] + c7, -128, 127);
int c8 = ((leftRow[blkY + 0] + (leftRow[blkY + 1] << 1) + leftRow[blkY + 2] + 2) >> 2);
int c9 = ((topLeft[blkY >> 2] + (leftRow[blkY] << 1) + leftRow[blkY + 1] + 2) >> 2);
int c11 = ((topLeft[blkY >> 2] + (topLine[mbOffX + blkX] << 1) + topLine[mbOffX + blkX + 1] + 2) >> 2);
pixOut[off + 32] = (byte) clip(residual[8] + c8, -128, 127);
pixOut[off + 33] = (byte) clip(residual[9] + c9, -128, 127);
pixOut[off + 34] = (byte) clip(residual[10] + c0, -128, 127);
pixOut[off + 35] = (byte) clip(residual[11] + c11, -128, 127);
int c12 = ((leftRow[blkY + 1] + (leftRow[blkY + 2] << 1) + leftRow[blkY + 3] + 2) >> 2);
int c13 = ((leftRow[blkY] + (leftRow[blkY + 1] << 1) + leftRow[blkY + 2] + 2) >> 2);
int c14 = ((topLeft[blkY >> 2] + (leftRow[blkY] << 1) + leftRow[blkY + 1] + 2) >> 2);
pixOut[off + 48] = (byte) clip(residual[12] + c12, -128, 127);
pixOut[off + 49] = (byte) clip(residual[13] + c13, -128, 127);
pixOut[off + 50] = (byte) clip(residual[14] + c14, -128, 127);
pixOut[off + 51] = (byte) clip(residual[15] + c0, -128, 127);
}
public static void predictVerticalRight(int[] residual, boolean leftAvailable, boolean topAvailable,
byte[] leftRow, byte[] topLine, byte[] topLeft, int mbOffX, int blkX, int blkY, byte[] pixOut) {
int v1 = (topLeft[blkY >> 2] + topLine[mbOffX + blkX + 0] + 1) >> 1;
int v2 = (topLine[mbOffX + blkX + 0] + topLine[mbOffX + blkX + 1] + 1) >> 1;
int v3 = (topLine[mbOffX + blkX + 1] + topLine[mbOffX + blkX + 2] + 1) >> 1;
int v4 = (topLine[mbOffX + blkX + 2] + topLine[mbOffX + blkX + 3] + 1) >> 1;
int v5 = (leftRow[blkY] + 2 * topLeft[blkY >> 2] + topLine[mbOffX + blkX + 0] + 2) >> 2;
int v6 = (topLeft[blkY >> 2] + 2 * topLine[mbOffX + blkX + 0] + topLine[mbOffX + blkX + 1] + 2) >> 2;
int v7 = (topLine[mbOffX + blkX + 0] + 2 * topLine[mbOffX + blkX + 1] + topLine[mbOffX + blkX + 2] + 2) >> 2;
int v8 = (topLine[mbOffX + blkX + 1] + 2 * topLine[mbOffX + blkX + 2] + topLine[mbOffX + blkX + 3] + 2) >> 2;
int v9 = (topLeft[blkY >> 2] + 2 * leftRow[blkY] + leftRow[blkY + 1] + 2) >> 2;
int v10 = (leftRow[blkY] + 2 * leftRow[blkY + 1] + leftRow[blkY + 2] + 2) >> 2;
int off = (blkY << 4) + blkX;
pixOut[off] = (byte) clip(residual[0] + v1, -128, 127);
pixOut[off + 1] = (byte) clip(residual[1] + v2, -128, 127);
pixOut[off + 2] = (byte) clip(residual[2] + v3, -128, 127);
pixOut[off + 3] = (byte) clip(residual[3] + v4, -128, 127);
pixOut[off + 16] = (byte) clip(residual[4] + v5, -128, 127);
pixOut[off + 17] = (byte) clip(residual[5] + v6, -128, 127);
pixOut[off + 18] = (byte) clip(residual[6] + v7, -128, 127);
pixOut[off + 19] = (byte) clip(residual[7] + v8, -128, 127);
pixOut[off + 32] = (byte) clip(residual[8] + v9, -128, 127);
pixOut[off + 33] = (byte) clip(residual[9] + v1, -128, 127);
pixOut[off + 34] = (byte) clip(residual[10] + v2, -128, 127);
pixOut[off + 35] = (byte) clip(residual[11] + v3, -128, 127);
pixOut[off + 48] = (byte) clip(residual[12] + v10, -128, 127);
pixOut[off + 49] = (byte) clip(residual[13] + v5, -128, 127);
pixOut[off + 50] = (byte) clip(residual[14] + v6, -128, 127);
pixOut[off + 51] = (byte) clip(residual[15] + v7, -128, 127);
}
public static void predictHorizontalDown(int[] residual, boolean leftAvailable, boolean topAvailable,
byte[] leftRow, byte[] topLine, byte[] topLeft, int mbOffX, int blkX, int blkY, byte[] pixOut) {
int c0 = (topLeft[blkY >> 2] + leftRow[blkY] + 1) >> 1;
int c1 = (leftRow[blkY] + 2 * topLeft[blkY >> 2] + topLine[mbOffX + blkX + 0] + 2) >> 2;
int c2 = (topLeft[blkY >> 2] + 2 * topLine[mbOffX + blkX + 0] + topLine[mbOffX + blkX + 1] + 2) >> 2;
int c3 = (topLine[mbOffX + blkX + 0] + 2 * topLine[mbOffX + blkX + 1] + topLine[mbOffX + blkX + 2] + 2) >> 2;
int c4 = (leftRow[blkY] + leftRow[blkY + 1] + 1) >> 1;
int c5 = (topLeft[blkY >> 2] + 2 * leftRow[blkY] + leftRow[blkY + 1] + 2) >> 2;
int c6 = (leftRow[blkY + 1] + leftRow[blkY + 2] + 1) >> 1;
int c7 = (leftRow[blkY] + 2 * leftRow[blkY + 1] + leftRow[blkY + 2] + 2) >> 2;
int c8 = (leftRow[blkY + 2] + leftRow[blkY + 3] + 1) >> 1;
int c9 = (leftRow[blkY + 1] + 2 * leftRow[blkY + 2] + leftRow[blkY + 3] + 2) >> 2;
int off = (blkY << 4) + blkX;
pixOut[off] = (byte) clip(residual[0] + c0, -128, 127);
pixOut[off + 1] = (byte) clip(residual[1] + c1, -128, 127);
pixOut[off + 2] = (byte) clip(residual[2] + c2, -128, 127);
pixOut[off + 3] = (byte) clip(residual[3] + c3, -128, 127);
pixOut[off + 16] = (byte) clip(residual[4] + c4, -128, 127);
pixOut[off + 17] = (byte) clip(residual[5] + c5, -128, 127);
pixOut[off + 18] = (byte) clip(residual[6] + c0, -128, 127);
pixOut[off + 19] = (byte) clip(residual[7] + c1, -128, 127);
pixOut[off + 32] = (byte) clip(residual[8] + c6, -128, 127);
pixOut[off + 33] = (byte) clip(residual[9] + c7, -128, 127);
pixOut[off + 34] = (byte) clip(residual[10] + c4, -128, 127);
pixOut[off + 35] = (byte) clip(residual[11] + c5, -128, 127);
pixOut[off + 48] = (byte) clip(residual[12] + c8, -128, 127);
pixOut[off + 49] = (byte) clip(residual[13] + c9, -128, 127);
pixOut[off + 50] = (byte) clip(residual[14] + c6, -128, 127);
pixOut[off + 51] = (byte) clip(residual[15] + c7, -128, 127);
}
public static void predictVerticalLeft(int[] residual, boolean topAvailable, boolean topRightAvailable,
byte[] topLine, int mbOffX, int blkX, int blkY, byte[] pixOut) {
int to = mbOffX + blkX;
int tr0 = topLine[to + 3], tr1 = topLine[to + 3], tr2 = topLine[to + 3];
if (topRightAvailable) {
tr0 = topLine[to + 4];
tr1 = topLine[to + 5];
tr2 = topLine[to + 6];
}
int c0 = ((topLine[to] + topLine[to + 1] + 1) >> 1);
int c1 = ((topLine[to + 1] + topLine[to + 2] + 1) >> 1);
int c2 = ((topLine[to + 2] + topLine[to + 3] + 1) >> 1);
int c3 = ((topLine[to + 3] + tr0 + 1) >> 1);
int c4 = ((tr0 + tr1 + 1) >> 1);
int c5 = ((topLine[to] + 2 * topLine[to + 1] + topLine[to + 2] + 2) >> 2);
int c6 = ((topLine[to + 1] + 2 * topLine[to + 2] + topLine[to + 3] + 2) >> 2);
int c7 = ((topLine[to + 2] + 2 * topLine[to + 3] + tr0 + 2) >> 2);
int c8 = ((topLine[to + 3] + 2 * tr0 + tr1 + 2) >> 2);
int c9 = ((tr0 + 2 * tr1 + tr2 + 2) >> 2);
int off = (blkY << 4) + blkX;
pixOut[off] = (byte) clip(residual[0] + c0, -128, 127);
pixOut[off + 1] = (byte) clip(residual[1] + c1, -128, 127);
pixOut[off + 2] = (byte) clip(residual[2] + c2, -128, 127);
pixOut[off + 3] = (byte) clip(residual[3] + c3, -128, 127);
pixOut[off + 16] = (byte) clip(residual[4] + c5, -128, 127);
pixOut[off + 17] = (byte) clip(residual[5] + c6, -128, 127);
pixOut[off + 18] = (byte) clip(residual[6] + c7, -128, 127);
pixOut[off + 19] = (byte) clip(residual[7] + c8, -128, 127);
pixOut[off + 32] = (byte) clip(residual[8] + c1, -128, 127);
pixOut[off + 33] = (byte) clip(residual[9] + c2, -128, 127);
pixOut[off + 34] = (byte) clip(residual[10] + c3, -128, 127);
pixOut[off + 35] = (byte) clip(residual[11] + c4, -128, 127);
pixOut[off + 48] = (byte) clip(residual[12] + c6, -128, 127);
pixOut[off + 49] = (byte) clip(residual[13] + c7, -128, 127);
pixOut[off + 50] = (byte) clip(residual[14] + c8, -128, 127);
pixOut[off + 51] = (byte) clip(residual[15] + c9, -128, 127);
}
public static void predictHorizontalUp(int[] residual, boolean leftAvailable, byte[] leftRow, int mbOffX, int blkX,
int blkY, byte[] pixOut) {
int c0 = ((leftRow[blkY] + leftRow[blkY + 1] + 1) >> 1);
int c1 = ((leftRow[blkY] + (leftRow[blkY + 1] << 1) + leftRow[blkY + 2] + 2) >> 2);
int c2 = ((leftRow[blkY + 1] + leftRow[blkY + 2] + 1) >> 1);
int c3 = ((leftRow[blkY + 1] + (leftRow[blkY + 2] << 1) + leftRow[blkY + 3] + 2) >> 2);
int c4 = ((leftRow[blkY + 2] + leftRow[blkY + 3] + 1) >> 1);
int c5 = ((leftRow[blkY + 2] + (leftRow[blkY + 3] << 1) + leftRow[blkY + 3] + 2) >> 2);
int c6 = leftRow[blkY + 3];
int off = (blkY << 4) + blkX;
pixOut[off] = (byte) clip(residual[0] + c0, -128, 127);
pixOut[off + 1] = (byte) clip(residual[1] + c1, -128, 127);
pixOut[off + 2] = (byte) clip(residual[2] + c2, -128, 127);
pixOut[off + 3] = (byte) clip(residual[3] + c3, -128, 127);
pixOut[off + 16] = (byte) clip(residual[4] + c2, -128, 127);
pixOut[off + 17] = (byte) clip(residual[5] + c3, -128, 127);
pixOut[off + 18] = (byte) clip(residual[6] + c4, -128, 127);
pixOut[off + 19] = (byte) clip(residual[7] + c5, -128, 127);
pixOut[off + 32] = (byte) clip(residual[8] + c4, -128, 127);
pixOut[off + 33] = (byte) clip(residual[9] + c5, -128, 127);
pixOut[off + 34] = (byte) clip(residual[10] + c6, -128, 127);
pixOut[off + 35] = (byte) clip(residual[11] + c6, -128, 127);
pixOut[off + 48] = (byte) clip(residual[12] + c6, -128, 127);
pixOut[off + 49] = (byte) clip(residual[13] + c6, -128, 127);
pixOut[off + 50] = (byte) clip(residual[14] + c6, -128, 127);
pixOut[off + 51] = (byte) clip(residual[15] + c6, -128, 127);
}
}