/*
* Copyright (c) 2008-2010, Matthias Mann
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Matthias Mann nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package de.matthiasmann.jpegdecoder;
import java.nio.ByteBuffer;
/**
*
* @author Matthias Mann
*/
class IDCT_2D {
final int[] tmp2D = new int[64];
private static final int C0 = f2f( 0.541196100);
private static final int C1 = f2f(-1.847759065);
private static final int C2 = f2f( 0.765366865);
private static final int C3 = f2f( 1.175875602);
private static final int C4 = f2f( 0.298631336);
private static final int C5 = f2f( 2.053119869);
private static final int C6 = f2f( 3.072711026);
private static final int C7 = f2f( 1.501321110);
private static final int C8 = f2f(-0.899976223);
private static final int C9 = f2f(-2.562915447);
private static final int C10 = f2f(-1.961570560);
private static final int C11 = f2f(-0.390180644);
private void computeV(short[] data) {
final int[] tmp = tmp2D;
int i = 0;
do {
int s0 = data[i ];
int s1 = data[i+ 8];
int s2 = data[i+16];
int s3 = data[i+24];
int s4 = data[i+32];
int s5 = data[i+40];
int s6 = data[i+48];
int s7 = data[i+56];
int p1, p2, p3, p4, p5;
p1 = (s2+s6)*C0;
p2 = ((s0+s4) << 12) + 512;
p3 = ((s0-s4) << 12) + 512;
p4 = p1 + s6*C1;
p5 = p1 + s2*C2;
int x0 = p2+p5;
int x3 = p2-p5;
int x1 = p3+p4;
int x2 = p3-p4;
p1 = s7+s1;
p2 = s5+s3;
p3 = s7+s3;
p4 = s5+s1;
p5 = (p3+p4)*C3;
p1 = p5 + p1*C8;
p2 = p5 + p2*C9;
p3 = p3*C10;
p4 = p4*C11;
int t0 = s7*C4 + p1 + p3;
int t1 = s5*C5 + p2 + p4;
int t2 = s3*C6 + p2 + p3;
int t3 = s1*C7 + p1 + p4;
tmp[i ] = (x0+t3) >> 10;
tmp[i+56] = (x0-t3) >> 10;
tmp[i+ 8] = (x1+t2) >> 10;
tmp[i+48] = (x1-t2) >> 10;
tmp[i+16] = (x2+t1) >> 10;
tmp[i+40] = (x2-t1) >> 10;
tmp[i+24] = (x3+t0) >> 10;
tmp[i+32] = (x3-t0) >> 10;
} while(++i < 8);
}
public final void compute(ByteBuffer out, int outPos, int outStride, short[] data) {
computeV(data);
final int[] tmp = tmp2D;
for(int i=0 ; i<64 ; i+=8) {
int s0 = tmp[i ] + (257 << 4);
int s1 = tmp[i+1];
int s2 = tmp[i+2];
int s3 = tmp[i+3];
int s4 = tmp[i+4];
int s5 = tmp[i+5];
int s6 = tmp[i+6];
int s7 = tmp[i+7];
int p1, p2, p3, p4, p5;
p1 = (s2+s6)*C0;
p2 = (s0+s4) << 12;
p3 = (s0-s4) << 12;
p4 = p1 + s6*C1;
p5 = p1 + s2*C2;
int x0 = p2+p5;
int x3 = p2-p5;
int x1 = p3+p4;
int x2 = p3-p4;
p1 = s7+s1;
p2 = s5+s3;
p3 = s7+s3;
p4 = s5+s1;
p5 = (p3+p4)*C3;
p1 = p5 + p1*C8;
p2 = p5 + p2*C9;
p3 = p3*C10;
p4 = p4*C11;
int t0 = s7*C4 + p1 + p3;
int t1 = s5*C5 + p2 + p4;
int t2 = s3*C6 + p2 + p3;
int t3 = s1*C7 + p1 + p4;
out.put(outPos , clampShift17(x0+t3));
out.put(outPos+7, clampShift17(x0-t3));
out.put(outPos+1, clampShift17(x1+t2));
out.put(outPos+6, clampShift17(x1-t2));
out.put(outPos+2, clampShift17(x2+t1));
out.put(outPos+5, clampShift17(x2-t1));
out.put(outPos+3, clampShift17(x3+t0));
out.put(outPos+4, clampShift17(x3-t0));
outPos += outStride;
}
}
public final void compute(byte[] out, int outPos, int outStride, short[] data) {
computeV(data);
final int[] tmp = tmp2D;
for(int i=0 ; i<64 ; i+=8) {
int s0 = tmp[i ] + (257 << 4);
int s1 = tmp[i+1];
int s2 = tmp[i+2];
int s3 = tmp[i+3];
int s4 = tmp[i+4];
int s5 = tmp[i+5];
int s6 = tmp[i+6];
int s7 = tmp[i+7];
int p1, p2, p3, p4, p5;
p1 = (s2+s6)*C0;
p2 = (s0+s4) << 12;
p3 = (s0-s4) << 12;
p4 = p1 + s6*C1;
p5 = p1 + s2*C2;
int x0 = p2+p5;
int x3 = p2-p5;
int x1 = p3+p4;
int x2 = p3-p4;
p1 = s7+s1;
p2 = s5+s3;
p3 = s7+s3;
p4 = s5+s1;
p5 = (p3+p4)*C3;
p1 = p5 + p1*C8;
p2 = p5 + p2*C9;
p3 = p3*C10;
p4 = p4*C11;
int t0 = s7*C4 + p1 + p3;
int t1 = s5*C5 + p2 + p4;
int t2 = s3*C6 + p2 + p3;
int t3 = s1*C7 + p1 + p4;
out[outPos ] = clampShift17(x0+t3);
out[outPos+7] = clampShift17(x0-t3);
out[outPos+1] = clampShift17(x1+t2);
out[outPos+6] = clampShift17(x1-t2);
out[outPos+2] = clampShift17(x2+t1);
out[outPos+5] = clampShift17(x2-t1);
out[outPos+3] = clampShift17(x3+t0);
out[outPos+4] = clampShift17(x3-t0);
outPos += outStride;
}
}
private static byte clampShift17(int x) {
if(x < 0) {
return 0;
}
if(x > (255 << 17)) {
return (byte)255;
}
return (byte)(x >>> 17);
}
private static strictfp int f2f(double x) {
return (int)Math.round(Math.scalb(x, 12));
}
}