package org.jcodec.codecs.h264.decode;
import org.jcodec.common.ArrayUtil;
import java.lang.IllegalArgumentException;
import java.util.Arrays;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Integer DCT 4x4 base implementation
*
* @author The JCodec project
*
*/
public class CoeffTransformer {
private static int[] fieldScan4x4 = { 0, 4, 1, 8, 12, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
private static int[] fieldScan8x8 = { 0, 8, 16, 1, 9, 24, 32, 17, 2, 25, 40, 48, 56, 33, 10, 3, 18, 41, 49, 57, 26, 11, 4,
19, 34, 42, 50, 58, 27, 12, 5, 20, 35, 43, 51, 58, 28, 13, 6, 21, 36, 44, 52, 60, 29, 14, 22, 37, 45, 53,
61, 30, 7, 15, 38, 46, 54, 62, 23, 31, 39, 47, 55, 63 };
public static int[] zigzag4x4 = { 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 };
static int[][] dequantCoef = { { 10, 13, 10, 13, 13, 16, 13, 16, 10, 13, 10, 13, 13, 16, 13, 16 },
{ 11, 14, 11, 14, 14, 18, 14, 18, 11, 14, 11, 14, 14, 18, 14, 18 },
{ 13, 16, 13, 16, 16, 20, 16, 20, 13, 16, 13, 16, 16, 20, 16, 20 },
{ 14, 18, 14, 18, 18, 23, 18, 23, 14, 18, 14, 18, 18, 23, 18, 23 },
{ 16, 20, 16, 20, 20, 25, 20, 25, 16, 20, 16, 20, 20, 25, 20, 25 },
{ 18, 23, 18, 23, 23, 29, 23, 29, 18, 23, 18, 23, 23, 29, 23, 29 } };
static int[][] dequantCoef8x8 = new int[6][64];
static int[][] initDequantCoeff8x8 = { { 20, 18, 32, 19, 25, 24 }, { 22, 19, 35, 21, 28, 26 },
{ 26, 23, 42, 24, 33, 31 }, { 28, 25, 45, 26, 35, 33 }, { 32, 28, 51, 30, 40, 38 },
{ 36, 32, 58, 34, 46, 43 } };
public static int[] zigzag8x8 = new int[] { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33,
40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44,
51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };
private static final int quantCoeff[][] = {
{ 13107, 8066, 13107, 8066, 8066, 5243, 8066, 5243, 13107, 8066, 13107, 8066, 8066, 5243, 8066, 5243 },
{ 11916, 7490, 11916, 7490, 7490, 4660, 7490, 4660, 11916, 7490, 11916, 7490, 7490, 4660, 7490, 4660 },
{ 10082, 6554, 10082, 6554, 6554, 4194, 6554, 4194, 10082, 6554, 10082, 6554, 6554, 4194, 6554, 4194 },
{ 9362, 5825, 9362, 5825, 5825, 3647, 5825, 3647, 9362, 5825, 9362, 5825, 5825, 3647, 5825, 3647 },
{ 8192, 5243, 8192, 5243, 5243, 3355, 5243, 3355, 8192, 5243, 8192, 5243, 5243, 3355, 5243, 3355 },
{ 7282, 4559, 7282, 4559, 4559, 2893, 4559, 2893, 7282, 4559, 7282, 4559, 4559, 2893, 4559, 2893 } };
static {
for (int g = 0; g < 6; g++) {
Arrays.fill(dequantCoef8x8[g], initDequantCoeff8x8[g][5]);
for (int i = 0; i < 8; i += 4)
for (int j = 0; j < 8; j += 4)
dequantCoef8x8[g][(i << 3) + j] = initDequantCoeff8x8[g][0];
for (int i = 1; i < 8; i += 2)
for (int j = 1; j < 8; j += 2)
dequantCoef8x8[g][(i << 3) + j] = initDequantCoeff8x8[g][1];
for (int i = 2; i < 8; i += 4)
for (int j = 2; j < 8; j += 4)
dequantCoef8x8[g][(i << 3) + j] = initDequantCoeff8x8[g][2];
for (int i = 0; i < 8; i += 4)
for (int j = 1; j < 8; j += 2)
dequantCoef8x8[g][(i << 3) + j] = initDequantCoeff8x8[g][3];
for (int i = 1; i < 8; i += 2)
for (int j = 0; j < 8; j += 4)
dequantCoef8x8[g][(i << 3) + j] = initDequantCoeff8x8[g][3];
for (int i = 0; i < 8; i += 4)
for (int j = 2; j < 8; j += 4)
dequantCoef8x8[g][(i << 3) + j] = initDequantCoeff8x8[g][4];
for (int i = 2; i < 8; i += 4)
for (int j = 0; j < 8; j += 4)
dequantCoef8x8[g][(i << 3) + j] = initDequantCoeff8x8[g][4];
}
}
public CoeffTransformer(int[][] scalingListMatrix) {
}
/**
* Inverce integer DCT transform for 4x4 block
*
* @param block
* @return
*/
public final static void idct4x4(int[] block) {
_idct4x4(block, block);
}
public static final void _idct4x4(int[] block, int[] out) {
// Horisontal
for (int i = 0; i < 16; i += 4) {
int e0 = block[i] + block[i + 2];
int e1 = block[i] - block[i + 2];
int e2 = (block[i + 1] >> 1) - block[i + 3];
int e3 = block[i + 1] + (block[i + 3] >> 1);
out[i] = e0 + e3;
out[i + 1] = e1 + e2;
out[i + 2] = e1 - e2;
out[i + 3] = e0 - e3;
}
// Vertical
for (int i = 0; i < 4; i++) {
int g0 = out[i] + out[i + 8];
int g1 = out[i] - out[i + 8];
int g2 = (out[i + 4] >> 1) - out[i + 12];
int g3 = out[i + 4] + (out[i + 12] >> 1);
out[i] = g0 + g3;
out[i + 4] = g1 + g2;
out[i + 8] = g1 - g2;
out[i + 12] = g0 - g3;
}
// scale down
for (int i = 0; i < 16; i++) {
out[i] = (out[i] + 32) >> 6;
}
}
public static void fdct4x4(int[] block) {
// Horizontal
for (int i = 0; i < 16; i += 4) {
int t0 = block[i] + block[i + 3];
int t1 = block[i + 1] + block[i + 2];
int t2 = block[i + 1] - block[i + 2];
int t3 = block[i] - block[i + 3];
block[i] = t0 + t1;
block[i + 1] = (t3 << 1) + t2;
block[i + 2] = t0 - t1;
block[i + 3] = t3 - (t2 << 1);
}
// Vertical
for (int i = 0; i < 4; i++) {
int t0 = block[i] + block[i + 12];
int t1 = block[i + 4] + block[i + 8];
int t2 = block[i + 4] - block[i + 8];
int t3 = block[i] - block[i + 12];
block[i] = t0 + t1;
block[i + 4] = t2 + (t3 << 1);
block[i + 8] = t0 - t1;
block[i + 12] = t3 - (t2 << 1);
}
}
/**
* Inverse Hadamard transform
*
* @param scaled
*/
public static void invDC4x4(int[] scaled) {
// Horisontal
for (int i = 0; i < 16; i += 4) {
int e0 = scaled[i] + scaled[i + 2];
int e1 = scaled[i] - scaled[i + 2];
int e2 = scaled[i + 1] - scaled[i + 3];
int e3 = scaled[i + 1] + scaled[i + 3];
scaled[i] = e0 + e3;
scaled[i + 1] = e1 + e2;
scaled[i + 2] = e1 - e2;
scaled[i + 3] = e0 - e3;
}
// Vertical
for (int i = 0; i < 4; i++) {
int g0 = scaled[i] + scaled[i + 8];
int g1 = scaled[i] - scaled[i + 8];
int g2 = scaled[i + 4] - scaled[i + 12];
int g3 = scaled[i + 4] + scaled[i + 12];
scaled[i] = g0 + g3;
scaled[i + 4] = g1 + g2;
scaled[i + 8] = g1 - g2;
scaled[i + 12] = g0 - g3;
}
}
/**
* Forward Hadamard transform
*
* @param scaled
*/
public static void fvdDC4x4(int[] scaled) {
// Horizontal
for (int i = 0; i < 16; i += 4) {
int t0 = scaled[i] + scaled[i + 3];
int t1 = scaled[i + 1] + scaled[i + 2];
int t2 = scaled[i + 1] - scaled[i + 2];
int t3 = scaled[i] - scaled[i + 3];
scaled[i] = t0 + t1;
scaled[i + 1] = t3 + t2;
scaled[i + 2] = t0 - t1;
scaled[i + 3] = t3 - t2;
}
// Vertical
for (int i = 0; i < 4; i++) {
int t0 = scaled[i] + scaled[i + 12];
int t1 = scaled[i + 4] + scaled[i + 8];
int t2 = scaled[i + 4] - scaled[i + 8];
int t3 = scaled[i] - scaled[i + 12];
scaled[i] = (t0 + t1) >> 1;
scaled[i + 4] = (t2 + t3) >> 1;
scaled[i + 8] = (t0 - t1) >> 1;
scaled[i + 12] = (t3 - t2) >> 1;
}
}
public static void dequantizeAC(int[] coeffs, int qp) {
int group = qp % 6;
if (qp >= 24) {
int qbits = qp / 6;
for (int i = 0; i < 16; i++)
coeffs[i] = (coeffs[i] * dequantCoef[group][i]) << qbits;
} else {
int qbits = 4 - qp / 6;
int addition = 1 << (3 - qp / 6);
for (int i = 0; i < 16; i++)
coeffs[i] = (coeffs[i] * (dequantCoef[group][i] << 4) + addition) >> qbits;
}
}
public static void quantizeAC(int[] coeffs, int qp) {
int level = qp / 6;
int offset = qp % 6;
int addition = 682 << (qp / 6 + 4);
int qbits = 15 + level;
if (qp < 10) {
for (int i = 0; i < 16; i++) {
int sign = (coeffs[i] >> 31);
coeffs[i] = (Math.min((((coeffs[i] ^ sign) - sign) * quantCoeff[offset][i] + addition) >> qbits, 2063) ^ sign)
- sign;
}
} else {
for (int i = 0; i < 16; i++) {
int sign = (coeffs[i] >> 31);
coeffs[i] = (((((coeffs[i] ^ sign) - sign) * quantCoeff[offset][i] + addition) >> qbits) ^ sign) - sign;
}
}
}
public static int[] unzigzagAC(int[] coeffs) {
int[] tab;
if (coeffs.length == 16) {
tab = zigzag4x4;
} else if (coeffs.length == 64) {
tab = zigzag8x8;
} else
throw new IllegalArgumentException("Coefficients array should be of either 16 or 64 length.");
int[] result = new int[coeffs.length];
for (int i = 0; i < coeffs.length; i++) {
result[tab[i]] = coeffs[i];
}
return result;
}
public static void dequantizeDC4x4(int[] coeffs, int qp) {
int group = qp % 6;
if (qp >= 36) {
int qbits = qp / 6 - 2;
for (int i = 0; i < 16; i++)
coeffs[i] = (coeffs[i] * dequantCoef[group][0]) << qbits;
} else {
int qbits = 6 - qp / 6;
int addition = 1 << (5 - qp / 6);
for (int i = 0; i < 16; i++)
coeffs[i] = (coeffs[i] * (dequantCoef[group][0] << 4) + addition) >> qbits;
}
}
public static void quantizeDC4x4(int[] coeffs, int qp) {
int level = qp / 6;
int offset = qp % 6;
int addition = 682 << (qp / 6 + 5);
int qbits = 16 + level;
if (qp < 10) {
for (int i = 0; i < 16; i++) {
int sign = (coeffs[i] >> 31);
coeffs[i] = (Math.min((((coeffs[i] ^ sign) - sign) * quantCoeff[offset][0] + addition) >> qbits, 2063) ^ sign)
- sign;
}
} else {
for (int i = 0; i < 16; i++) {
int sign = (coeffs[i] >> 31);
coeffs[i] = (((((coeffs[i] ^ sign) - sign) * quantCoeff[offset][0] + addition) >> qbits) ^ sign) - sign;
}
}
}
/**
* Inverse Hadamard 2x2
*
* @param block
*/
public static void invDC2x2(int[] block) {
int t0, t1, t2, t3;
t0 = block[0] + block[1];
t1 = block[0] - block[1];
t2 = block[2] + block[3];
t3 = block[2] - block[3];
block[0] = (t0 + t2);
block[1] = (t1 + t3);
block[2] = (t0 - t2);
block[3] = (t1 - t3);
}
/**
* Forward Hadamard 2x2
*
* @param dc2
*/
public static void fvdDC2x2(int[] block) {
invDC2x2(block);
}
public static void dequantizeDC2x2(int[] transformed, int qp) {
int group = qp % 6;
int shift = qp / 6;
for (int i = 0; i < 4; i++) {
transformed[i] = ((transformed[i] * dequantCoef[group][0]) << shift) >> 1;
}
}
public static void quantizeDC2x2(int[] coeffs, int qp) {
int level = qp / 6;
int offset = qp % 6;
int addition = 682 << (qp / 6 + 5);
int qbits = 16 + level;
if (qp < 4) {
for (int i = 0; i < 4; i++) {
int sign = (coeffs[i] >> 31);
coeffs[i] = (Math.min((((coeffs[i] ^ sign) - sign) * quantCoeff[offset][0] + addition) >> qbits, 2063) ^ sign)
- sign;
}
} else {
for (int i = 0; i < 4; i++) {
int sign = (coeffs[i] >> 31);
coeffs[i] = (((((coeffs[i] ^ sign) - sign) * quantCoeff[offset][0] + addition) >> qbits) ^ sign) - sign;
}
}
}
public static void reorderDC4x4(int[] dc) {
ArrayUtil.swap(dc, 2, 4);
ArrayUtil.swap(dc, 3, 5);
ArrayUtil.swap(dc, 10, 12);
ArrayUtil.swap(dc, 11, 13);
}
public static void fvdDC4x2(int[] dc) {
}
public static void quantizeDC4x2(int[] dc, int qp) {
}
public static void invDC4x2(int[] dc) {
// TODO Auto-generated method stub
}
public static void dequantizeDC4x2(int[] dc, int qp) {
// TODO Auto-generated method stub
}
/**
* Coefficients are <<4 on exit
*
* @param coeffs
* @param qp
*/
public static void dequantizeAC8x8(int[] coeffs, int qp) {
int group = qp % 6;
if (qp >= 36) {
int qbits = qp / 6 - 2;
for (int i = 0; i < 64; i++)
coeffs[i] = (coeffs[i] * dequantCoef8x8[group][i]) << qbits;
} else {
int qbits = 6 - qp / 6;
int addition = 1 << (5 - qp / 6);
for (int i = 0; i < 64; i++)
coeffs[i] = (coeffs[i] * (dequantCoef8x8[group][i] << 4) + addition) >> qbits;
}
}
public static void idct8x8(int[] ac) {
int off = 0;
// Horizontal
for (int row = 0; row < 8; row++) {
int e0 = ac[off] + ac[off + 4];
int e1 = -ac[off + 3] + ac[off + 5] - ac[off + 7] - (ac[off + 7] >> 1);
int e2 = ac[off] - ac[off + 4];
int e3 = ac[off + 1] + ac[off + 7] - ac[off + 3] - (ac[off + 3] >> 1);
int e4 = (ac[off + 2] >> 1) - ac[off + 6];
int e5 = -ac[off + 1] + ac[off + 7] + ac[off + 5] + (ac[off + 5] >> 1);
int e6 = ac[off + 2] + (ac[off + 6] >> 1);
int e7 = ac[off + 3] + ac[off + 5] + ac[off + 1] + (ac[off + 1] >> 1);
int f0 = e0 + e6;
int f1 = e1 + (e7 >> 2);
int f2 = e2 + e4;
int f3 = e3 + (e5 >> 2);
int f4 = e2 - e4;
int f5 = (e3 >> 2) - e5;
int f6 = e0 - e6;
int f7 = e7 - (e1 >> 2);
ac[off] = f0 + f7;
ac[off + 1] = f2 + f5;
ac[off + 2] = f4 + f3;
ac[off + 3] = f6 + f1;
ac[off + 4] = f6 - f1;
ac[off + 5] = f4 - f3;
ac[off + 6] = f2 - f5;
ac[off + 7] = f0 - f7;
off += 8;
}
// Vertical
for (int col = 0; col < 8; col++) {
int e0 = ac[col] + ac[col + 32];
int e1 = -ac[col + 24] + ac[col + 40] - ac[col + 56] - (ac[col + 56] >> 1);
int e2 = ac[col] - ac[col + 32];
int e3 = ac[col + 8] + ac[col + 56] - ac[col + 24] - (ac[col + 24] >> 1);
int e4 = (ac[col + 16] >> 1) - ac[col + 48];
int e5 = -ac[col + 8] + ac[col + 56] + ac[col + 40] + (ac[col + 40] >> 1);
int e6 = ac[col + 16] + (ac[col + 48] >> 1);
int e7 = ac[col + 24] + ac[col + 40] + ac[col + 8] + (ac[col + 8] >> 1);
int f0 = e0 + e6;
int f1 = e1 + (e7 >> 2);
int f2 = e2 + e4;
int f3 = e3 + (e5 >> 2);
int f4 = e2 - e4;
int f5 = (e3 >> 2) - e5;
int f6 = e0 - e6;
int f7 = e7 - (e1 >> 2);
ac[col] = f0 + f7;
ac[col + 8] = f2 + f5;
ac[col + 16] = f4 + f3;
ac[col + 24] = f6 + f1;
ac[col + 32] = f6 - f1;
ac[col + 40] = f4 - f3;
ac[col + 48] = f2 - f5;
ac[col + 56] = f0 - f7;
}
// scale down
for (int i = 0; i < 64; i++) {
ac[i] = (ac[i] + 32) >> 6;
}
}
}