noVNC/core/ast2100/ast2100idct.js

215 lines
7.4 KiB
JavaScript

/* (c) Copyright 2015-2017 Kevin Kelley <kelleyk@kelleyk.net>. */
var AST2100IDCT;
// N.B.: These values assume CONST_BITS == 8
var FIX_1_082392200 = 277; // fix(1.082392200)
var FIX_1_414213562 = 362; // fix(1.414213562)
var FIX_1_847759065 = 473; // fix(1.847759065)
var FIX_2_613125930 = 669; // fix(2.613125930)
var MAXJSAMPLE = 255; // largest value of a sample; 8-bit, so 2**8-1
var CONST_BITS = 8;
var PASS1_BITS = 0;
// This is like clamp() except that it also adds the MAXJSAMPLE/2 offset.
var range_limit = function (x) {
// XXX(kelleyk): This offset is baked into the range limit table in the ATEN
// stuff and in libjpeg; see commpent above prepare_range_limit_table() in
// jdmaster.c.
x += 128;
return Math.max(0, Math.min(255, x));
};
// Convert float to fixed-point.
var fix = function (x) {
return ~~(x * (1 << CONST_BITS) + 0.5);
};
var fixed_dequant = function (scaled_quant_table, buf, i) {
// N.B.: The data in buf is unscaled; the data in scaled_quant_table has
// been scaled by 1<<16.
return fixed_mul(scaled_quant_table[i], buf[i]);
};
var descale = function (x, n) {
// console.log([x, x>>n, (x>>n)+128]);
return x >> n;
};
// if not accurate rounding mode...
var idescale = descale;
// else use better implementation
// N.B.(kelleyk): This isn't a libjpeg parameter; it just means that ATEN
// downshifts all the way back to "normal ints" at the end of pass 1.
var END_PASS1_DESCALE_BITS = CONST_BITS;
var fixed_mul = function (a, b) {
return descale(a * b, CONST_BITS);
};
(function () {
"use strict";
AST2100IDCT = {
// Uses the 16/16 integer representation that ATEN and libjpeg's
// jidctfst.c ("fast, not-so-accurate integer IDCT") do. Note that, for
// performance, this routine *also* incorporates the dequantization
// step, which is why it takes scaled_quant_table as an argument. (This
// argument does not actually contain "just" a scaled quant table; some
// constants have been pre-multiplied into it. See the function that
// loads quant tables for more details.)
idct_fixed_aan: function (scaled_quant_table, buf, dstBuf) {
// ATEN rounds things off early, at a cost to precision: the int32
// values in 'workspace' are not scaled at all.
var workspace = new Int32Array(64);
for (var x = 0; x < 8; ++x)
AST2100IDCT._aan_idct_col(scaled_quant_table, buf, workspace, x);
for (var y = 0; y < 8; ++y)
AST2100IDCT._aan_idct_row(scaled_quant_table, dstBuf, workspace, y);
return dstBuf;
},
// Columns; aka "Pass 1".
_aan_idct_col: function(scaled_quant_table, buf, workspace, x) {
var dequant = function (idx) { return fixed_dequant(scaled_quant_table, buf, idx); };
var mul = fixed_mul;
var y;
var all_ac_zero = true;
for (y = 1; y < 8; ++y) {
if (buf[8 * y + x] != 0) {
all_ac_zero = false;
break;
}
}
if (all_ac_zero) {
var raw_dcval = buf[8 * 0 + x];
var quant_val = scaled_quant_table[8 * 0 + x];
var dcval = idescale(dequant(8 * 0 + x), END_PASS1_DESCALE_BITS); // in total, >> 16
for (y = 0; y < 8; ++y)
workspace[8 * y + x] = dcval;
return;
}
// Even part.
var tmp0 = dequant(8 * 0 + x);
var tmp1 = dequant(8 * 2 + x);
var tmp2 = dequant(8 * 4 + x);
var tmp3 = dequant(8 * 6 + x);
var tmp10 = tmp0 + tmp2; // Phase 3
var tmp11 = tmp0 - tmp2;
var tmp13 = tmp1 + tmp3; // Phases 5-3
var tmp12 = mul((tmp1 - tmp3), FIX_1_414213562) - tmp13; // 2 * c4
tmp0 = tmp10 + tmp13;
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
// Odd part.
var tmp4 = dequant(8 * 1 + x);
var tmp5 = dequant(8 * 3 + x);
var tmp6 = dequant(8 * 5 + x);
var tmp7 = dequant(8 * 7 + x);
var z13 = tmp6 + tmp5; // Phase 6
var z10 = tmp6 - tmp5;
var z11 = tmp4 + tmp7;
var z12 = tmp4 - tmp7;
tmp7 = z11 + z13; // Phase 5
tmp11 = mul((z11 - z13), FIX_1_414213562); // 2 * c4
var z5 = mul((z10 + z12), FIX_1_847759065); // 2 * c2
tmp10 = mul(FIX_1_082392200, z12) - z5; // 2 * (c2-c6)
tmp12 = mul(-FIX_2_613125930, z10) + z5;
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
workspace[x + 8 * 0] = idescale(tmp0 + tmp7, END_PASS1_DESCALE_BITS);
workspace[x + 8 * 7] = idescale(tmp0 - tmp7, END_PASS1_DESCALE_BITS);
workspace[x + 8 * 1] = idescale(tmp1 + tmp6, END_PASS1_DESCALE_BITS);
workspace[x + 8 * 6] = idescale(tmp1 - tmp6, END_PASS1_DESCALE_BITS);
workspace[x + 8 * 2] = idescale(tmp2 + tmp5, END_PASS1_DESCALE_BITS);
workspace[x + 8 * 5] = idescale(tmp2 - tmp5, END_PASS1_DESCALE_BITS);
workspace[x + 8 * 4] = idescale(tmp3 + tmp4, END_PASS1_DESCALE_BITS);
workspace[x + 8 * 3] = idescale(tmp3 - tmp4, END_PASS1_DESCALE_BITS);
},
// Rows; aka "Pass 2".
_aan_idct_row: function(scaled_quant_table, buf, workspace, y) {
var wsptr = function (x) { return workspace[8 * y + x]; };
var mul = fixed_mul;
// Even part.
var tmp10 = wsptr(0) + wsptr(4);
var tmp11 = wsptr(0) - wsptr(4);
var tmp13 = wsptr(2) + wsptr(6);
var tmp12 = mul((wsptr(2) - wsptr(6)), FIX_1_414213562) - tmp13;
var tmp0 = tmp10 + tmp13;
var tmp3 = tmp10 - tmp13;
var tmp1 = tmp11 + tmp12;
var tmp2 = tmp11 - tmp12;
// Odd part.
var z13 = wsptr(5) + wsptr(3);
var z10 = wsptr(5) - wsptr(3);
var z11 = wsptr(1) + wsptr(7);
var z12 = wsptr(1) - wsptr(7);
var tmp7 = z11 + z13;
tmp11 = mul((z11 - z13), FIX_1_414213562);
var z5 = mul((z10 + z12), FIX_1_847759065); // 2 * c2
tmp10 = mul(FIX_1_082392200, z12) - z5; // 2 * (c2-c6)
tmp12 = mul(-FIX_2_613125930, z10) + z5;
var tmp6 = tmp12 - tmp7;
var tmp5 = tmp11 - tmp6;
var tmp4 = tmp10 + tmp5;
var set_out = function (x, val) {
// Shift right by PASS1_BITS bits to convert back to a normal
// int, and then by another 3 to divide by 8.
val = idescale(val, PASS1_BITS + 3);
val = range_limit(val); // This also applies the +128 offset.
buf[y * 8 + x] = val;
};
// Final output stage: scale down by a factor of 8 and range-limit
set_out(0, tmp0 + tmp7);
set_out(7, tmp0 - tmp7);
set_out(1, tmp1 + tmp6);
set_out(6, tmp0 - tmp6);
set_out(2, tmp2 + tmp5);
set_out(5, tmp2 - tmp5);
set_out(4, tmp3 + tmp4);
set_out(3, tmp3 - tmp4);
}
};
})();