107 lines
3.3 KiB
Java
107 lines
3.3 KiB
Java
package org.jcodec.scale;
|
|
|
|
import org.jcodec.common.model.Picture;
|
|
import org.jcodec.common.model.Size;
|
|
import org.jcodec.common.tools.MathUtil;
|
|
|
|
public abstract class BaseResampler {
|
|
private final ThreadLocal<int[]> tempBuffers;
|
|
|
|
private Size toSize;
|
|
|
|
private Size fromSize;
|
|
|
|
private final double scaleFactorX;
|
|
|
|
private final double scaleFactorY;
|
|
|
|
public BaseResampler(Size from, Size to) {
|
|
this.toSize = to;
|
|
this.fromSize = from;
|
|
this.scaleFactorX = (double)from.getWidth() / (double)to.getWidth();
|
|
this.scaleFactorY = (double)from.getHeight() / (double)to.getHeight();
|
|
this.tempBuffers = new ThreadLocal<>();
|
|
}
|
|
|
|
private static byte getPel(Picture pic, int plane, int x, int y) {
|
|
if (x < 0)
|
|
x = 0;
|
|
if (y < 0)
|
|
y = 0;
|
|
int w = pic.getPlaneWidth(plane);
|
|
if (x > w - 1)
|
|
x = w - 1;
|
|
int h = pic.getPlaneHeight(plane);
|
|
if (y > h - 1)
|
|
y = h - 1;
|
|
return pic.getData()[plane][x + y * w];
|
|
}
|
|
|
|
protected abstract short[] getTapsX(int paramInt);
|
|
|
|
protected abstract short[] getTapsY(int paramInt);
|
|
|
|
protected abstract int nTaps();
|
|
|
|
public static void normalizeAndGenerateFixedPrecision(double[] taps, int precBits, short[] out) {
|
|
double sum = 0.0D;
|
|
for (int i = 0; i < taps.length; i++)
|
|
sum += taps[i];
|
|
int sumFix = 0;
|
|
int precNum = 1 << precBits;
|
|
for (int j = 0; j < taps.length; j++) {
|
|
double d = taps[j] * (double)precNum / sum + (double)precNum;
|
|
int s = (int)d;
|
|
taps[j] = d - (double)s;
|
|
out[j] = (short)(s - precNum);
|
|
sumFix += out[j];
|
|
}
|
|
long tapsTaken = 0L;
|
|
while (sumFix < precNum) {
|
|
int maxI = -1;
|
|
for (int m = 0; m < taps.length; m++) {
|
|
if ((tapsTaken & (long)(1 << m)) == 0L && (maxI == -1 || taps[m] > taps[maxI]))
|
|
maxI = m;
|
|
}
|
|
out[maxI] = (short)(out[maxI] + 1);
|
|
sumFix++;
|
|
tapsTaken |= (long)(1 << maxI);
|
|
}
|
|
for (int k = 0; k < taps.length; k++) {
|
|
taps[k] = taps[k] + (double)out[k];
|
|
if ((tapsTaken & (long)(1 << k)) != 0L)
|
|
taps[k] = taps[k] - 1.0D;
|
|
}
|
|
}
|
|
|
|
public void resample(Picture src, Picture dst) {
|
|
int[] temp = this.tempBuffers.get();
|
|
int taps = nTaps();
|
|
if (temp == null) {
|
|
temp = new int[this.toSize.getWidth() * (this.fromSize.getHeight() + taps)];
|
|
this.tempBuffers.set(temp);
|
|
}
|
|
for (int p = 0; p < (src.getColor()).nComp; p++) {
|
|
for (int i = 0; i < src.getPlaneHeight(p) + taps; i++) {
|
|
for (int x = 0; x < dst.getPlaneWidth(p); x++) {
|
|
short[] tapsXs = getTapsX(x);
|
|
int srcX = (int)(this.scaleFactorX * (double)x) - taps / 2 + 1;
|
|
int sum = 0;
|
|
for (int j = 0; j < taps; j++)
|
|
sum += (getPel(src, p, srcX + j, i - taps / 2 + 1) + 128) * tapsXs[j];
|
|
temp[i * this.toSize.getWidth() + x] = sum;
|
|
}
|
|
}
|
|
for (int y = 0; y < dst.getPlaneHeight(p); y++) {
|
|
for (int x = 0; x < dst.getPlaneWidth(p); x++) {
|
|
short[] tapsYs = getTapsY(y);
|
|
int srcY = (int)(this.scaleFactorY * (double)y);
|
|
int sum = 0;
|
|
for (int j = 0; j < taps; j++)
|
|
sum += temp[x + (srcY + j) * this.toSize.getWidth()] * tapsYs[j];
|
|
dst.getPlaneData(p)[y * dst.getPlaneWidth(p) + x] = (byte)(MathUtil.clip(sum + 8192 >> 14, 0, 255) - 128);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|