package org.jcodec.codecs.h264.encode;
import static java.lang.Math.min;
import org.jcodec.common.model.Picture8Bit;
import org.jcodec.common.tools.MathUtil;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Estimates motion using diagonal search
*
* @author Stanislav Vitvitskyy
*/
public class MotionEstimator {
private int maxSearchRange;
public MotionEstimator(int maxSearchRange) {
this.maxSearchRange = maxSearchRange;
}
public int[] estimate(Picture8Bit ref, byte[] patch, int mbX, int mbY, int mvpx, int mvpy) {
byte[] searchPatch = new byte[(maxSearchRange * 2 + 16) * (maxSearchRange * 2 + 16)];
int startX = (mbX << 4) /* + (mvpx >> 2)*/;
int startY = (mbY << 4) /* + (mvpy >> 2)*/;
int patchTlX = Math.max(startX - maxSearchRange, 0);
int patchTlY = Math.max(startY - maxSearchRange, 0);
int patchBrX = Math.min(startX + maxSearchRange + 16, ref.getPlaneWidth(0));
int patchBrY = Math.min(startY + maxSearchRange + 16, ref.getPlaneHeight(0));
int centerX = startX - patchTlX;
int centerY = startY - patchTlY;
int patchW = patchBrX - patchTlX;
int patchH = patchBrY - patchTlY;
MBEncoderHelper.takeSafe(ref.getPlaneData(0), ref.getPlaneWidth(0), ref.getPlaneHeight(0), patchTlX, patchTlY,
searchPatch, patchW, patchH);
int bestMvX = centerX, bestMvY = centerY;
int bestScore = sad(searchPatch, patchW, patch, bestMvX, bestMvY);
// Diagonal search
for (int i = 0; i < maxSearchRange; i++) {
int score1 = bestMvX > 0 ? sad(searchPatch, patchW, patch, bestMvX - 1, bestMvY) : Integer.MAX_VALUE;
int score2 = bestMvX < patchW - 1 ? sad(searchPatch, patchW, patch, bestMvX + 1, bestMvY) : Integer.MAX_VALUE;
int score3 = bestMvY > 0 ? sad(searchPatch, patchW, patch, bestMvX, bestMvY - 1) : Integer.MAX_VALUE;
int score4 = bestMvY < patchH - 1 ? sad(searchPatch, patchW, patch, bestMvX, bestMvY + 1) : Integer.MAX_VALUE;
int min = min(min(min(score1, score2), score3), score4);
if (min > bestScore)
break;
bestScore = min;
if (score1 == min) {
--bestMvX;
} else if (score2 == min) {
++bestMvX;
} else if (score3 == min) {
--bestMvY;
} else {
++bestMvY;
}
}
return new int[] { ((bestMvX - centerX) << 2)/* + mvpx*/, ((bestMvY - centerY) << 2)/* + mvpy*/ };
}
private int sad(byte[] big, int bigStride, byte[] small, int offX, int offY) {
int score = 0, bigOff = offY * bigStride + offX, smallOff = 0;
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++, ++bigOff, ++smallOff) {
score += MathUtil.abs(big[bigOff] - small[smallOff]);
}
bigOff += bigStride - 16;
}
return score;
}
}