package org.jcodec.codecs.mpeg12;
import org.jcodec.common.tools.MathUtil;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* MPEG 1/2 decoder interframe motion compensation routines, octal interpolation
*
* @author The JCodec project
*
*/
public class MPEGPredOct extends MPEGPred {
// Max block size is 16x16
private int[] tmp;
// TODO: this really implements interpolation for QUAD downsampling, add another linear step for OCT.
// This is also to be complient with MPEG spec which uses linear interpolation.
private static final int[][] COEFF = {
{ 0, 0, 128, 0, 0, 0 },
{ 0, -6, 123, 12, -1, 0 },
{ 2, -11, 108, 36, -8, 1 },
{ 0, -9, 93, 50, -6, 0 },
{ 3, -16, 77, 77, -16, 3 },
{ 0, -6, 50, 93, -9, 0 },
{ 1, -8, 36, 108, -11, 2 },
{ 0, -1, 12, 123, -6, 0 }
};
public MPEGPredOct(MPEGPred other) {
super(other.fCode, other.chromaFormat, other.topFieldFirst);
this.tmp = new int[16 * 21];
}
@Override
public void predictPlane(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff,
int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
int rx = refX >> 3, ry = refY >> 3;
tgtW >>= 3;
tgtH >>= 3;
boolean safe = rx >= 2 && ry >= 2 && rx + tgtW + 3 < refW && ((ry + tgtH + 3) << refVertStep) < refH;
if ((refX & 0x7) == 0) {
if ((refY & 0x7) == 0) {
if (safe)
predictFullXFullYSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH,
tgtVertStep);
else
predictFullXFullYUnSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH,
tgtVertStep);
} else {
if (safe)
predictFullXSubYSafe(ref, rx, ry, refY & 0x7, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW,
tgtH, tgtVertStep);
else
predictFullXSubYUnSafe(ref, rx, ry, refY & 0x7, refW, refH, refVertStep, refVertOff, tgt, tgtY,
tgtW, tgtH, tgtVertStep);
}
} else if ((refY & 0x7) == 0) {
if (safe)
predictSubXFullYSafe(ref, rx, refX & 0x7, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW,
tgtH, tgtVertStep);
else
predictSubXFullYUnSafe(ref, rx, refX & 0x7, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW,
tgtH, tgtVertStep);
} else {
if (safe)
predictSubXSubYSafe(ref, rx, refX & 0x7, ry, refY & 0x7, refW, refH, refVertStep, refVertOff, tgt,
tgtY, tgtW, tgtH, tgtVertStep);
else
predictSubXSubYUnSafe(ref, rx, refX & 0x7, ry, refY & 0x7, refW, refH, refVertStep, refVertOff, tgt,
tgtY, tgtW, tgtH, tgtVertStep);
}
}
protected int getPix6(byte[] ref, int refW, int refH, int x, int y, int refVertStep, int refVertOff, int[] coeff) {
int lastLine = refH - (1 << refVertStep) + refVertOff;
int x0 = MathUtil.clip(x - 2, 0, refW - 1);
int x1 = MathUtil.clip(x - 1, 0, refW - 1);
int x2 = MathUtil.clip(x, 0, refW - 1);
int x3 = MathUtil.clip(x + 1, 0, refW - 1);
int x4 = MathUtil.clip(x + 2, 0, refW - 1);
int x5 = MathUtil.clip(x + 3, 0, refW - 1);
int off = MathUtil.clip(y, refVertOff, lastLine) * refW;
return ref[off + x0] * coeff[0] + ref[off + x1] * coeff[1] + ref[off + x2] * coeff[2] + ref[off + x3]
* coeff[3] + ref[off + x4] * coeff[4] + ref[off + x5] * coeff[5] + 16384;
}
protected int getPix6Vert(byte[] ref, int refW, int refH, int x, int y, int refVertStep, int refVertOff, int[] coeff) {
int lastLine = refH - (1 << refVertStep) + refVertOff;
int y0 = MathUtil.clip(y - (2 << refVertStep), refVertOff, lastLine);
int y1 = MathUtil.clip(y - (1 << refVertStep), refVertOff, lastLine);
int y2 = MathUtil.clip(y, 0, lastLine);
int y3 = MathUtil.clip(y + (1 << refVertStep), refVertOff, lastLine);
int y4 = MathUtil.clip(y + (2 << refVertStep), refVertOff, lastLine);
int y5 = MathUtil.clip(y + (3 << refVertStep), refVertOff, lastLine);
x = MathUtil.clip(x, 0, refW - 1);
return ref[y0 * refW + x] * coeff[0] + ref[y1 * refW + x] * coeff[1] + ref[y2 * refW + x] * coeff[2]
+ ref[y3 * refW + x] * coeff[3] + ref[y4 * refW + x] * coeff[4] + ref[y5 * refW + x] * coeff[5] + 16384;
}
private void predictSubXSubYUnSafe(byte[] ref, int rx, int ix, int ry, int iy, int refW, int refH, int refVertStep,
int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
int offTgt = tgtW * tgtY;
int dblTgtW = tgtW << 1;
int tripleTgtW = dblTgtW + tgtW;
int lfTgt = tgtVertStep * tgtW;
int[] coeff = COEFF[ix];
for (int i = -2, offTmp = 0; i < tgtH + 3; i++) {
int y = ((i + ry) << refVertStep) + refVertOff;
for (int j = 0; j < tgtW; j++, ++offTmp) {
tmp[offTmp] = getPix6(ref, refW, refH, j + rx, y, refVertStep, refVertOff, coeff);
}
}
coeff = COEFF[iy];
for (int i = 0, offTmp = dblTgtW; i < tgtH; i++) {
for (int j = 0; j < tgtW; j++, ++offTmp, ++offTgt) {
tgt[offTgt] = (tmp[offTmp - dblTgtW] * coeff[0] + tmp[offTmp - tgtW] * coeff[1] + tmp[offTmp]
* coeff[2] + tmp[offTmp + tgtW] * coeff[3] + tmp[offTmp + dblTgtW] * coeff[4]
+ tmp[offTmp + tripleTgtW] * coeff[5] + 8192) >> 14;
}
offTgt += lfTgt;
}
}
private void predictSubXSubYSafe(byte[] ref, int rx, int ix, int ry, int iy, int refW, int refH, int refVertStep,
int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
int[] coeff = COEFF[ix];
int offRef = (((ry - 2) << refVertStep) + refVertOff) * refW + rx;
int offTgt = tgtW * tgtY;
int lfRef = (refW << refVertStep) - tgtW;
int lfTgt = tgtVertStep * tgtW;
int dblTgtW = tgtW << 1;
int tripleTgtW = dblTgtW + tgtW;
for (int i = 0, offTmp = 0; i < tgtH + 5; i++) {
for (int j = 0; j < tgtW; j++, ++offTmp, ++offRef) {
tmp[offTmp] = ref[offRef - 2] * coeff[0] + ref[offRef - 1] * coeff[1] + ref[offRef] * coeff[2]
+ ref[offRef + 1] * coeff[3] + ref[offRef + 2] * coeff[4] + ref[offRef + 3] * coeff[5];
}
offRef += lfRef;
}
coeff = COEFF[iy];
for (int i = 0, offTmp = dblTgtW; i < tgtH; i++) {
for (int j = 0; j < tgtW; j++, ++offTmp, ++offTgt) {
tgt[offTgt] = ((tmp[offTmp - dblTgtW] * coeff[0] + tmp[offTmp - tgtW] * coeff[1] + tmp[offTmp]
* coeff[2] + tmp[offTmp + tgtW] * coeff[3] + tmp[offTmp + dblTgtW] * coeff[4]
+ tmp[offTmp + tripleTgtW] * coeff[5] + 8192) >> 14) + 128;
}
offTgt += lfTgt;
}
}
private void predictSubXFullYUnSafe(byte[] ref, int rx, int ix, int ry, int refW, int refH, int refVertStep,
int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
int[] coeff = COEFF[ix];
int tgtOff = tgtW * tgtY;
int lfTgt = tgtVertStep * tgtW;
for (int i = 0; i < tgtH; i++) {
int y = ((i + ry) << refVertStep) + refVertOff;
for (int j = 0; j < tgtW; j++) {
tgt[tgtOff++] = (getPix6(ref, refW, refH, j + rx, y, refVertStep, refVertOff, coeff) + 64) >> 7;
}
tgtOff += lfTgt;
}
}
private void predictSubXFullYSafe(byte[] ref, int rx, int ix, int ry, int refW, int refH, int refVertStep,
int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
int[] coeff = COEFF[ix];
int offRef = ((ry << refVertStep) + refVertOff) * refW + rx;
int offTgt = tgtW * tgtY;
int lfRef = (refW << refVertStep) - tgtW;
int lfTgt = tgtVertStep * tgtW;
for (int i = 0; i < tgtH; i++) {
for (int j = 0; j < tgtW; j++, ++offRef) {
tgt[offTgt++] = ((ref[offRef - 2] * coeff[0] + ref[offRef - 1] * coeff[1] + ref[offRef] * coeff[2]
+ ref[offRef + 1] * coeff[3] + ref[offRef + 2] * coeff[4] + ref[offRef + 3] * coeff[5] + 64) >> 7) + 128;
}
offRef += lfRef;
offTgt += lfTgt;
}
}
private void predictFullXSubYUnSafe(byte[] ref, int rx, int ry, int iy, int refW, int refH, int refVertStep,
int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
int[] coeff = COEFF[iy];
int tgtOff = tgtW * tgtY;
int lfTgt = tgtVertStep * tgtW;
for (int i = 0; i < tgtH; i++) {
int y = ((i + ry) << refVertStep) + refVertOff;
for (int j = 0; j < tgtW; j++) {
tgt[tgtOff++] = (getPix6Vert(ref, refW, refH, j + rx, y, refVertStep, refVertOff, coeff) + 64) >> 7;
}
tgtOff += lfTgt;
}
}
private void predictFullXSubYSafe(byte[] ref, int rx, int ry, int iy, int refW, int refH, int refVertStep,
int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
int[] coeff = COEFF[iy];
int offTgt = tgtW * tgtY;
int offRef = ((ry << refVertStep) + refVertOff) * refW + rx;
int singleRefW = refW << refVertStep;
int dblRefW = refW << (1 + refVertStep);
int tripleRefW = dblRefW + singleRefW;
int lfTgt = tgtVertStep * tgtW;
int lfRef = (refW << refVertStep) - tgtW;
for (int i = 0; i < tgtH; i++) {
for (int j = 0; j < tgtW; ++j, ++offTgt, ++offRef) {
tgt[offTgt] = ((ref[offRef - dblRefW] * coeff[0] + ref[offRef - singleRefW] * coeff[1] + ref[offRef]
* coeff[2] + ref[offRef + singleRefW] * coeff[3] + ref[offRef + dblRefW] * coeff[4]
+ ref[offRef + tripleRefW] * coeff[5] + 64) >> 7) + 128;
}
offRef += lfRef;
offTgt += lfTgt;
}
}
}