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 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); } } } } }