scummvm/engines/icb/jpeg.cpp
2020-10-06 14:32:14 +02:00

1308 lines
38 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//
// Copyright (c) 1997,1998 Colosseum Builders, Inc.
// All rights reserved.
//
// Colosseum Builders, Inc. makes no warranty, expressed or implied
// with regards to this software. It is provided as is.
//
// See the README.TXT file that came with this software for restrictions
// on the use and redistribution of this file or send E-mail to
// info@colosseumbuilders.com
//
#include "engines/icb/jpeg.h"
#include "engines/icb/global_objects_pc.h"
#ifndef _WIN32
#define _flushall() fflush(NULL)
#endif
namespace ICB {
// A.3.6 Figure A.6
// These values are the inverse of those shown in the
// JPEG standard.
const unsigned int JpegZigZagInputOrderCodes[JpegSampleSize] = {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};
const unsigned int JpegZigZagOutputOrderCodes[JpegSampleSize] = {0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30,
41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 21, 33, 38,
46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63};
JpegDecoder::JpegDecoder() {
Initialize();
return;
}
JpegDecoder::~JpegDecoder() {
delete[] ac_tables;
ac_tables = NULL;
delete[] dc_tables;
dc_tables = NULL;
delete[] quantization_tables;
quantization_tables = NULL;
delete[] components;
components = NULL;
delete[] component_indices;
component_indices = NULL;
delete[] scan_components;
scan_components = NULL;
}
void JpegDecoder::Initialize() {
ac_tables = new JpegHuffmanDecoder[JpegMaxHuffmanTables];
dc_tables = new JpegHuffmanDecoder[JpegMaxHuffmanTables];
quantization_tables = new JpegDecoderQuantizationTable[MaxQuantizationTables];
components = new JpegDecoderComponent[JpegMaxComponentsPerFrame];
component_indices = new unsigned int[JpegMaxComponentsPerFrame];
scan_components = new JpegDecoderComponent *[JpegMaxComponentsPerScan];
bit_position = 0;
}
void JpegDecoder::ReadMarker() {
while (1) {
uint8 type = ReadByte();
switch (type) {
case SOI:
return; // SOI has no data.
case DQT:
ReadQuantization();
return;
// The only difference between a Sequential DCT Frame
// (SOF0) and an extended Sequential DCT Frame (SOF1)
// is that a baseline frame may only have 2 DC and 2 AC
// Huffman tables per scan (F.1.2) and and extended
// Sequential Frame may have up to 4 DC and 4 AC Huffman
// tables per scan (F.1.3). Both are decoded identically
// for 8-bit precision. Extended Sequential frames may
// use 12-bit precision (F, Table B.2) which we do not
// support.
case SOF0:
case SOF1:
ReadStartOfFrame(type);
return;
// These are markers for frames using arithmetic coding.
// Arithmetic coding is covered by patents so we ignore
// this type.
case SOF9:
case SOFA:
case SOFB:
case SOFD:
case SOFE:
case DHT:
ReadHuffmanTable();
return;
case SOS:
ReadStartOfScan();
return;
case EOI:
eoi_found = true;
return; // End of Image marker has no data
default:
// We call ReadByte to make sure the problem
// is not a premature EOF.
(void)ReadByte();
_flushall();
// throw ("Unknown, unsupported, or reserved marker encountered");
}
}
_flushall();
}
void JpegDecoder::ReadHuffmanTable() {
// Section B.2.4.2
uint16 length = ReadWord();
unsigned int remaining = length - sizeof(length);
while (remaining > 0) {
uint8 data = ReadByte();
--remaining;
// Tc in standard 0=>DC, 1=>AC
unsigned int tableclass = data >> 4;
unsigned int id = data & 0x0F; // Th in standard
JpegHuffmanDecoder *table;
if (tableclass != 0)
table = &ac_tables[id];
else
table = &dc_tables[id];
// Read the table data into the table object
remaining -= table->ReadTable(*this);
}
}
void JpegDecoder::ReadQuantization() {
// Defined in Section B.2.4.1
uint16 length = ReadWord();
uint8 data;
// Maintain a counter for the number of bytes remaining to be read in
// the quantization table.
int remaining = length - sizeof(length);
while (remaining > 0) {
data = ReadByte();
--remaining;
unsigned int precision = data >> 4; // Pq in standard
unsigned int index = data & 0x0F; // Tq in standard
switch (precision) {
case 1:
remaining -= sizeof(uint16) * JpegSampleSize;
break;
case 0:
remaining -= sizeof(uint8) * JpegSampleSize;
break;
}
// Read the table data into the table object
quantization_tables[index].ReadTable(*this, precision);
}
}
void JpegDecoder::ReadStartOfFrame(uint8 type) {
// Section B.2.2
// Read in the image dimensions
/* unsigned int length = */ ReadWord();
/* unsigned int dataprecision = */ ReadByte(); // P in standard
component_count = ReadByte(); // Nf in standard
frame_type = type;
// Rread the component descriptions
max_horizontal_frequency = 0;
max_vertical_frequency = 0;
for (unsigned int ii = 0; ii < component_count; ++ii) {
unsigned int ID = ReadByte(); // Ci in standard
unsigned int qtable;
component_indices[ii] = ID;
uint8 data = ReadByte();
components[ID].horizontal_frequency = (data >> 4); // Hi in standard
components[ID].vertical_frequency = (data & 0xF); // Vi in standard
qtable = ReadByte(); // Tqi in standard
components[ID].SetQuantizationTable(quantization_tables[qtable]);
// Keep track of the largest values for horizontal and vertical
// frequency.
if (components[ID].horizontal_frequency > max_horizontal_frequency) {
max_horizontal_frequency = components[ID].horizontal_frequency;
}
if (components[ID].vertical_frequency > max_vertical_frequency) {
max_vertical_frequency = components[ID].vertical_frequency;
}
}
CalculateMcuDimensions();
sof_found = true;
}
void JpegDecoder::ReadStartOfScan() {
unsigned int ii;
// Section B.2.3
/*uint16 length = */ ReadWord();
scan_component_count = ReadByte(); // Ns in standard
// Right now we can only handle up to three components.
for (ii = 0; ii < scan_component_count; ++ii) {
uint8 componentID = ReadByte(); // Csi in standard
scan_components[ii] = &components[componentID];
// If the horizontal frequency is zero then the component was not
// defined in the SOFx marker.
uint8 rb = ReadByte();
unsigned int actable = rb & 0x0F;
unsigned int dctable = rb >> 4;
scan_components[ii]->SetHuffmanTables(dc_tables[dctable], ac_tables[actable]);
}
/* unsigned int spectralselectionstart =*/ReadByte(); // Ss in standard
/* unsigned int spectralselectionend = */ ReadByte(); // Se in standard
/* uint8 ssa = */ ReadByte();
// unsigned int successiveapproximationhigh = ssa >> 4; // Ah in standard
// unsigned int successiveapproximationlow = ssa & 0x0F; // Al in standard
for (ii = 0; ii < scan_component_count; ++ii) {
scan_components[ii]->AllocateComponentBuffers(*this);
}
++current_scan;
ReadSequentialNonInterleavedScan();
}
void JpegDecoder::CalculateMcuDimensions() {
mcu_height = max_vertical_frequency * JpegSampleWidth;
mcu_width = max_horizontal_frequency * JpegSampleWidth;
mcu_rows = (480 + mcu_height - 1) / mcu_height;
mcu_cols = (640 + mcu_width - 1) / mcu_width;
return;
}
void JpegDecoder::ReadSequentialNonInterleavedScan() {
ResetDcDifferences();
for (unsigned int row = 0; row < scan_components[0]->noninterleaved_rows; ++row) {
for (unsigned int col = 0; col < scan_components[0]->noninterleaved_cols; ++col) {
scan_components[0]->DecodeSequential(*this, row, col);
}
}
}
void JpegDecoder::ResetDcDifferences() {
for (unsigned int ii = 0; ii < scan_component_count; ++ii)
scan_components[ii]->last_dc_value = 0;
}
void JpegDecoder::ReadImage(unsigned char *inputData, uint32 surface_Id) {
uint8 data;
input_buffer = inputData;
surfaceId = surface_Id;
iPos = 0;
current_scan = 0;
scan_count = 0;
eoi_found = false;
sof_found = false;
_bit_count = 0;
_buf_pointer = (uint32 *)input_buffer;
_end_buf = (uint32 *)(input_buffer + (1024 * 1024)); // blantantly wrong... need to make cash sized buffer
data = ReadByte();
while (!eoi_found) {
if (data == SOB) {
ReadMarker();
if (eoi_found)
break;
} else
data = 0xff;
data = ReadByte();
}
UpdateImage();
FreeAllocatedResources();
return;
}
void JpegDecoder::UpdateImage() {
components[component_indices[0]].Upsample();
components[component_indices[1]].Upsample();
components[component_indices[2]].Upsample();
JpegDecoderComponent::RGBConvert(components[component_indices[0]], components[component_indices[1]], components[component_indices[2]], surfaceId);
}
void JpegDecoder::FreeAllocatedResources() {
for (unsigned int ii = 0; ii < component_count; ++ii) {
components[component_indices[ii]].FreeComponentBuffers();
}
}
int JpegDecoder::cGetBit() {
// Section F.2.2.5 Figure F.18.
// CNT is called bitposition
// B is called bitdata
if (bit_position == 0) {
// We are out of data so read the next byte from the input stream.
bit_data = input_buffer[iPos++];
// Reset the bit read position starting with the highest order bit. We
// read high to low.
bit_position = sizeof(bit_data) << 3;
// The value FF is stored as FF00 to distinguish it from markers.
// So this bit of code skips the following 0x00 after the 0xff
// if (bit_data == 0xFF)
// iPos++;
}
// Consume one bit of the input.
--bit_position;
// Shift the value to the low order bit position.
uint8 result = (uint8)((bit_data >> bit_position) & 1);
return result;
}
int JpegDecoder::NextBit() {
int result = cGetBit();
return result;
}
// Extracts the next "count" bits from the input stream.
int JpegDecoder::Receive(unsigned int count) {
int result = 0;
for (unsigned int ii = 0; ii < count; ++ii) {
result <<= 1;
result |= cGetBit();
}
return result;
}
JpegHuffmanDecoder::JpegHuffmanDecoder() {}
unsigned int JpegHuffmanDecoder::ReadTable(JpegDecoder &decoder) {
// We declare this here because MSVC++ does not handle for
// statement scoping rules correctly.
unsigned int jj;
// B.2.4.2
uint8 huffbits[JpegMaxHuffmanCodeLength];
unsigned int count = 0; // Count of codes in the Huffman table.
// Read the 16 1-byte length counts and count the number of
// codes in the table.
for (jj = 0; jj < JpegMaxHuffmanCodeLength; ++jj) {
// These values are called Li in the standard.
huffbits[jj] = decoder.ReadByte();
count += huffbits[jj];
}
// Read the Huffman values.
for (jj = 0; jj < count; ++jj) {
// These values are called Vi in the standard.
huff_values[jj] = decoder.ReadByte();
}
// Generate the Structures for Huffman Decoding.
MakeTable(huffbits);
return JpegMaxHuffmanCodeLength + count;
}
void JpegHuffmanDecoder::MakeTable(uint8 huffbits[JpegMaxHuffmanCodeLength]) {
// We have to declare the loop indices here because MSVC++ does not
// handle scoping in for statements correctly.
unsigned int ii, jj, kk;
// These values in these arrays correspond to the elements of the
// "values" array. The Huffman code for values [N] is huffcodes [N]
// and the length of the code is huffsizes [N].
uint16 huffcodes[JpegMaxNumberOfHuffmanCodes];
unsigned int huffsizes[JpegMaxNumberOfHuffmanCodes + 1];
// Section C.2 Figure C.1
// Convert the array "huff_bits" containing the count of codes
// for each length 1..16 into an array containing the length for each
// code.
for (ii = 0, kk = 0; ii < JpegMaxHuffmanCodeLength; ++ii) {
for (jj = 0; jj < huffbits[ii]; ++jj) {
huffsizes[kk] = ii + 1;
++kk;
}
huffsizes[kk] = 0;
}
// Section C.2 Figure C.2
// Calculate the Huffman code for each Huffman value.
uint16 code = 0;
unsigned int si;
for (kk = 0, si = huffsizes[0]; huffsizes[kk] != 0; ++si, code <<= 1) {
for (; huffsizes[kk] == si; ++code, ++kk) {
huffcodes[kk] = code;
}
}
// Section F.2.2. Figure F.15
// Create three arrays.
// mincode [n] : The smallest Huffman code of length n + 1.
// maxcode [n] : The largest Huffman code of length n + 1.
// valptr [n] : Index into the values array. First value with a code
// of length n + 1.
for (ii = 0, jj = 0; ii < JpegMaxHuffmanCodeLength; ++ii) {
// ii is the index into Huffman code lengths
// jj is the index into Huffman code values
if (huffbits[ii] != 0) {
// The jj'th Huffman value is the first with a Huffman code
// of length ii.
valptr[ii] = (uint8)jj;
mincode[ii] = huffcodes[jj];
jj += huffbits[ii];
maxcode[ii] = huffcodes[jj - 1];
} else {
// There are no Huffman codes of length (ii + 1).
maxcode[ii] = -1;
// An illegal value > maxcode[]
mincode[ii] = JpegMaxNumberOfHuffmanCodes + 1;
valptr[ii] = 0;
}
}
}
int JpegHuffmanDecoder::Decode(JpegDecoder &decoder) {
// This function decodes the next byte in the input stream using this
// Huffman table.
// Section A F.2.2.3 Figure F.16
uint16 code = (uint16)decoder.NextBit();
int codelength; // Called I in the standard.
// Here we are taking advantage of the fact that 1 bits are used as
// a prefix to the longer codes.
for (codelength = 0; (code > maxcode[codelength] && codelength < JpegMaxHuffmanCodeLength); ++codelength) {
code = (uint16)((code << 1) | decoder.NextBit());
}
// Now we have a Huffman code of length (codelength + 1) that
// is somewhere in the range
// mincode [codelength]..maxcode [codelength].
// This code is the (offset + 1)'th code of (codelength + 1);
int offset = code - mincode[codelength];
// valptr [codelength] is the first code of length (codelength + 1)
// so now we can look up the value for the Huffman code in the table.
int index = valptr[codelength] + offset;
return huff_values[index];
}
//
// Description:
//
// This function tells if the Huffman table has been defined
// by the JPEG input stream. It is used to detect corrupt
// streams that have scans that use a Huffman table before
// it has been defined.
//
// Return Value:
//
// true => The table has been defind
// false => The table has not been defined
//
// JPEG Decoder Quantization Table Class Implementation
//
// This table consists of the values
//
// F (i, j) = X (i) X (j) / 8
//
// where
//
// X (n) = 1, n = 0, 4
// X (n) = 1 / sqrt(2) / cos (n*PI/16)
//
static const double floatscaling[JpegSampleWidth][JpegSampleWidth] = {
{
0.125, 0.09011997775086849627, 0.09567085809127244544, 0.1063037618459070632, 0.125, 0.159094822571604233, 0.2309698831278216846, 0.4530637231764438333,
},
{
0.09011997775086849627, 0.0649728831185362593, 0.0689748448207357645, 0.07664074121909414394, 0.09011997775086849627, 0.1147009749634507608, 0.1665200058287998886,
0.3266407412190940884,
},
{
0.09567085809127244544, 0.0689748448207357645, 0.0732233047033631207, 0.08136137691302557096, 0.09567085809127244544, 0.1217659055464329343, 0.1767766952966368932,
0.3467599613305368256,
},
{
0.1063037618459070632, 0.07664074121909414394, 0.08136137691302557096, 0.09040391826073060355, 0.1063037618459070632, 0.135299025036549253, 0.1964237395967755595,
0.3852990250365491698,
},
{
0.125, 0.09011997775086849627, 0.09567085809127244544, 0.1063037618459070632, 0.125, 0.159094822571604233, 0.2309698831278216846, 0.4530637231764438333,
},
{
0.159094822571604233, 0.1147009749634507608, 0.1217659055464329343, 0.135299025036549253, 0.159094822571604233, 0.2024893005527218515, 0.2939689006048396558,
0.5766407412190940329,
},
{
0.2309698831278216846, 0.1665200058287998886, 0.1767766952966368932, 0.1964237395967755595, 0.2309698831278216846, 0.2939689006048396558, 0.4267766952966368654,
0.8371526015321518744,
},
{
0.4530637231764438333, 0.3266407412190940884, 0.3467599613305368256, 0.3852990250365491698, 0.4530637231764438333, 0.5766407412190940329, 0.8371526015321518744,
1.642133898068010689,
},
};
//
// Description:
//
// Class Default Constructor
//
JpegDecoderQuantizationTable::JpegDecoderQuantizationTable() { memset(data_values, 0, sizeof(data_values)); }
//
// Description:
//
// This function reads a quantization table from a JPEG stream.
//
// Parameters:
// decoder: The JPEG decoder that owns the table and the JPEG stream.
// precision: The quantization table precision
//
void JpegDecoderQuantizationTable::ReadTable(JpegDecoder &decoder, unsigned int) {
// Read 8-bit values.
for (unsigned int ii = 0; ii < JpegSampleSize; ++ii) {
data_values[ii] = decoder.ReadByte();
}
BuildScaledTables();
}
//
// Description:
//
// This function creates scaled quantization tables that
// allow quantization to be merged with the IDCT process.
// We factor the DCT matrix so that the first step in the
// IDCT is to multiply each value by a constant. Here we
// merge that constant with the quantization table valus.
//
void JpegDecoderQuantizationTable::BuildScaledTables() {
unsigned int ii; // Overcome MSVC++ Wierdness
for (ii = 0; ii < JpegSampleWidth; ++ii) {
for (int jj = 0; jj < JpegSampleWidth; ++jj) {
float_scaling[ii][jj] = data_values[JpegZigZagOutputOrderCodes[ii * 8 + jj]] * floatscaling[ii][jj];
}
}
for (ii = 0; ii < JpegSampleWidth; ++ii) {
for (int jj = 0; jj < JpegSampleWidth; ++jj) {
integer_scaling[ii][jj] = (int32)((1 << QuantizationIntegerScale) * floatscaling[ii][jj] * data_values[JpegZigZagOutputOrderCodes[ii * 8 + jj]]);
}
}
}
//
// JPEG Decoder Data Unit class implementation
//
// This class represents an 8x8 sample block for one
// component of the JPEG image. Its main function is to perform the
// Inverse Discrete Cosine Transform.
//
// We have two IDCT implementation defined here. One uses floating point
// and the other uses scaled integers. The integer implementation is much
// faster but it is slightly less precise than the floating point.
//
// (Right now the choice of the two is made at compile time. In the
// future there may be a run-time switch).
//
// The algorithm is a matrix factorization that makes use extensive of the
// cosine product formula. The first phase of the IDCT is merged with
// quantization.
//
JpegDecoderDataUnit::IDctFunction JpegDecoderDataUnit::idct_function = &JpegDecoderDataUnit::IntegerInverseDCT;
const int IntegerScale = 6;
const int32 IC4 = (int32)((1 << IntegerScale) * cos(M_PI * 4.0 / 16.0));
const int32 ISEC2 = (int32)((1 << (IntegerScale - 1)) / cos(M_PI * 2.0 / 16.0));
const int32 ISEC6 = (int32)((1 << (IntegerScale - 1)) / cos(M_PI * 6.0 / 16.0));
const double FC4 = cos(M_PI * 4.0 / 16.0);
const double FSEC2 = 0.5 / cos(M_PI * 2.0 / 16.0);
const double FSEC6 = 0.5 / cos(M_PI * 6.0 / 16.0);
//
// Description:
//
// This is a floating point implementation of the Inverse
// Discrete Cosine Transform (IDCT).
//
// This implementation uses a factorization of the DCT matrix.
// The first steps in this factorization is a matrix multiplication
// is the multiplication of each row/column by a scale. This
// scalor multipliation has been combined with quantization
// to eliminate 128 multiplication steps.
//
// We use a lot of temporaries here in order to clearly
// show the matrix multiplication steps. Hopefully
// your compiler will optimize out the unnecessary
// intermediate variables.
//
// If your compiler does not aggressively optimize. It is possible
// to reorder the operations to reduce the number of temporaries
// required.
//
// Parameters:
// data: The 8x8 matrix to perform the IDCT on.
// qt: The prescaled quantization table.
//
JpegDecoderDataUnit &JpegDecoderDataUnit::FloatInverseDCT(JpegDecoderCoefficientBlock data, const JpegDecoderQuantizationTable &qt) {
double tmp[JpegSampleWidth][JpegSampleWidth];
unsigned int ii;
for (ii = 0; ii < JpegSampleWidth; ++ii) {
double a0 = data[ii][0] * qt.float_scaling[ii][0];
double a1 = data[ii][4] * qt.float_scaling[ii][4];
double a2 = data[ii][2] * qt.float_scaling[ii][2];
double a3 = data[ii][6] * qt.float_scaling[ii][6];
double a4 = data[ii][1] * qt.float_scaling[ii][1];
double a5 = data[ii][5] * qt.float_scaling[ii][5];
double a6 = data[ii][3] * qt.float_scaling[ii][3];
double a7 = data[ii][7] * qt.float_scaling[ii][7];
double b0 = a0;
double b1 = a1;
double b2 = a2 - a3;
double b3 = a2 + a3;
double b4 = a4 - a7;
double b5 = a5 + a6;
double b6 = a5 - a6;
double b7 = a4 + a7;
double c0 = b0;
double c1 = b1;
double c2 = b2;
double c3 = b3;
double c4 = FSEC2 * b4;
double c5 = b7 - b5;
double c6 = FSEC6 * b6;
double c7 = b5 + b7;
double d0 = c0;
double d1 = c1;
double d2 = c2;
double d3 = c3;
double d4 = c4 + c6;
double d5 = c5;
double d6 = c4 - c6;
double d7 = c7;
double e0 = d0 + d1;
double e1 = d0 - d1;
double e2 = d2 * FC4;
double e3 = d3;
double e4 = d4 * FC4;
double e5 = d5 * FC4;
double e6 = d6;
double e7 = d7;
double f0 = e0;
double f1 = e1;
double f2 = e2;
double f3 = e3;
double f4 = e4;
double f5 = e5;
double f6 = e4 + e6;
double f7 = e7;
double g0 = f0;
double g1 = f1;
double g2 = f2;
double g3 = f2 + f3;
double g4 = f4;
double g5 = f4 + f5;
double g6 = f5 + f6;
double g7 = f6 + f7;
double h0 = g0 + g3;
double h1 = g1 + g2;
double h2 = g1 - g2;
double h3 = g0 - g3;
double h4 = g4;
double h5 = g5;
double h6 = g6;
double h7 = g7;
tmp[ii][0] = h0 + h7;
tmp[ii][1] = h1 + h6;
tmp[ii][2] = h2 + h5;
tmp[ii][3] = h3 + h4;
tmp[ii][4] = h3 - h4;
tmp[ii][5] = h2 - h5;
tmp[ii][6] = h1 - h6;
tmp[ii][7] = h0 - h7;
}
for (ii = 0; ii < JpegSampleWidth; ++ii) {
double a0 = tmp[0][ii];
double a1 = tmp[4][ii];
double a2 = tmp[2][ii];
double a3 = tmp[6][ii];
double a4 = tmp[1][ii];
double a5 = tmp[5][ii];
double a6 = tmp[3][ii];
double a7 = tmp[7][ii];
double b0 = a0;
double b1 = a1;
double b2 = a2 - a3;
double b3 = a2 + a3;
double b4 = a4 - a7;
double b5 = a5 + a6;
double b6 = a5 - a6;
double b7 = a4 + a7;
double c0 = b0;
double c1 = b1;
double c2 = b2;
double c3 = b3;
double c4 = FSEC2 * b4;
double c5 = b7 - b5;
double c6 = FSEC6 * b6;
double c7 = b5 + b7;
double d0 = c0;
double d1 = c1;
double d2 = c2;
double d3 = c3;
double d4 = c4 + c6;
double d5 = c5;
double d6 = c4 - c6;
double d7 = c7;
double e0 = d0 + d1;
double e1 = d0 - d1;
double e2 = d2 * FC4;
double e3 = d3;
double e4 = d4 * FC4;
double e5 = d5 * FC4;
double e6 = d6;
double e7 = d7;
double f0 = e0;
double f1 = e1;
double f2 = e2;
double f3 = e3;
double f4 = e4;
double f5 = e5;
double f6 = e4 + e6;
double f7 = e7;
double g0 = f0;
double g1 = f1;
double g2 = f2;
double g3 = f2 + f3;
double g4 = f4;
double g5 = f4 + f5;
double g6 = f5 + f6;
double g7 = f6 + f7;
double h0 = g0 + g3;
double h1 = g1 + g2;
double h2 = g1 - g2;
double h3 = g0 - g3;
double h4 = g4;
double h5 = g5;
double h6 = g6;
double h7 = g7;
static const double rounding = JpegMidpointSampleValue + 0.5;
values[0][ii] = SampleRange((int32)((h0 + h7) + rounding));
values[1][ii] = SampleRange((int32)((h1 + h6) + rounding));
values[2][ii] = SampleRange((int32)((h2 + h5) + rounding));
values[3][ii] = SampleRange((int32)((h3 + h4) + rounding));
values[4][ii] = SampleRange((int32)((h3 - h4) + rounding));
values[5][ii] = SampleRange((int32)((h2 - h5) + rounding));
values[6][ii] = SampleRange((int32)((h1 - h6) + rounding));
values[7][ii] = SampleRange((int32)((h0 - h7) + rounding));
}
return *this;
}
//
// Description:
//
// This is a scaled integer implementation of the Inverse
// Discrete Cosine Transform (IDCT).
//
// This implementation uses a factorization of the DCT matrix.
// The first steps in this factorization is a matrix multiplication
// is the multiplication of each row/column by a scale. This
// scalor multipliation has been combined with quantization
// to eliminate 128 multiplication steps.
//
// We use a lot of temporaries here in order to clearly
// show the matrix multiplication steps. Hopefully
// your compiler will optimize out the unnecessary
// intermediate variables.
//
// If your compiler does not aggressively optimize. It is possible
// to reorder the operations to reduce the number of temporaries
// required.
//
// Parameters:
// data: The 8x8 matrix to perform the IDCT on.
// qt: The prescaled quantization table.
//
JpegDecoderDataUnit &JpegDecoderDataUnit::IntegerInverseDCT(JpegDecoderCoefficientBlock data, const JpegDecoderQuantizationTable &qt) {
unsigned int ii;
int32 tmp[JpegSampleWidth][JpegSampleWidth];
for (ii = 0; ii < JpegSampleWidth; ++ii) {
// This optimization does not seem to be worth the trouble in the
// second loop.
if ((data[ii][1] | data[ii][2] | data[ii][3] | data[ii][4] | data[ii][5] | data[ii][6] | data[ii][7]) == 0) {
tmp[ii][0] = data[ii][0] * qt.integer_scaling[ii][0];
tmp[ii][1] = tmp[ii][0];
tmp[ii][2] = tmp[ii][0];
tmp[ii][3] = tmp[ii][0];
tmp[ii][4] = tmp[ii][0];
tmp[ii][5] = tmp[ii][0];
tmp[ii][6] = tmp[ii][0];
tmp[ii][7] = tmp[ii][0];
} else {
int32 a0 = data[ii][0] * qt.integer_scaling[ii][0];
int32 a1 = data[ii][4] * qt.integer_scaling[ii][4];
int32 a2 = data[ii][2] * qt.integer_scaling[ii][2];
int32 a3 = data[ii][6] * qt.integer_scaling[ii][6];
int32 a4 = data[ii][1] * qt.integer_scaling[ii][1];
int32 a5 = data[ii][5] * qt.integer_scaling[ii][5];
int32 a6 = data[ii][3] * qt.integer_scaling[ii][3];
int32 a7 = data[ii][7] * qt.integer_scaling[ii][7];
int32 b2 = a2 - a3;
int32 b3 = a2 + a3;
int32 b4 = a4 - a7;
int32 b5 = a5 + a6;
int32 b6 = a5 - a6;
int32 b7 = a4 + a7;
int32 c4 = (ISEC2 * b4) >> IntegerScale;
int32 c5 = b7 - b5;
int32 c6 = (ISEC6 * b6) >> IntegerScale;
int32 c7 = b5 + b7;
int32 d4 = c4 + c6;
int32 d6 = c4 - c6;
int32 e0 = a0 + a1;
int32 e1 = a0 - a1;
int32 e2 = (b2 * IC4) >> IntegerScale;
int32 e4 = (d4 * IC4) >> IntegerScale;
int32 e5 = (c5 * IC4) >> IntegerScale;
int32 f6 = e4 + d6;
int32 g3 = e2 + b3;
int32 g5 = e4 + e5;
int32 g6 = e5 + f6;
int32 g7 = f6 + c7;
int32 h0 = e0 + g3;
int32 h1 = e1 + e2;
int32 h2 = e1 - e2;
int32 h3 = e0 - g3;
tmp[ii][0] = h0 + g7;
tmp[ii][1] = h1 + g6;
tmp[ii][2] = h2 + g5;
tmp[ii][3] = h3 + e4;
tmp[ii][4] = h3 - e4;
tmp[ii][5] = h2 - g5;
tmp[ii][6] = h1 - g6;
tmp[ii][7] = h0 - g7;
}
}
for (ii = 0; ii < JpegSampleWidth; ++ii) {
int32 a0 = tmp[0][ii];
int32 a1 = tmp[4][ii];
int32 a2 = tmp[2][ii];
int32 a3 = tmp[6][ii];
int32 a4 = tmp[1][ii];
int32 a5 = tmp[5][ii];
int32 a6 = tmp[3][ii];
int32 a7 = tmp[7][ii];
int32 b2 = a2 - a3;
int32 b3 = a2 + a3;
int32 b4 = a4 - a7;
int32 b5 = a5 + a6;
int32 b6 = a5 - a6;
int32 b7 = a4 + a7;
int32 c4 = (ISEC2 * b4) >> IntegerScale;
int32 c5 = b7 - b5;
int32 c6 = (ISEC6 * b6) >> IntegerScale;
int32 c7 = b5 + b7;
int32 d4 = c4 + c6;
int32 d6 = c4 - c6;
int32 e0 = a0 + a1;
int32 e1 = a0 - a1;
int32 e2 = (b2 * IC4) >> IntegerScale;
int32 e4 = (d4 * IC4) >> IntegerScale;
int32 e5 = (c5 * IC4) >> IntegerScale;
int32 f6 = e4 + d6;
const int32 rounding = (JpegMaxSampleValue + 2) << (JpegDecoderQuantizationTable::QuantizationIntegerScale - 1);
int32 g0 = e0 + rounding;
int32 g1 = e1 + rounding;
int32 g3 = e2 + b3;
int32 g5 = e4 + e5;
int32 g6 = e5 + f6;
int32 g7 = f6 + c7;
int32 h0 = g0 + g3;
int32 h1 = g1 + e2;
int32 h2 = g1 - e2;
int32 h3 = g0 - g3;
values[0][ii] = SampleRange((h0 + g7) >> JpegDecoderQuantizationTable::QuantizationIntegerScale);
values[1][ii] = SampleRange((h1 + g6) >> JpegDecoderQuantizationTable::QuantizationIntegerScale);
values[2][ii] = SampleRange((h2 + g5) >> JpegDecoderQuantizationTable::QuantizationIntegerScale);
values[3][ii] = SampleRange((h3 + e4) >> JpegDecoderQuantizationTable::QuantizationIntegerScale);
values[4][ii] = SampleRange((h3 - e4) >> JpegDecoderQuantizationTable::QuantizationIntegerScale);
values[5][ii] = SampleRange((h2 - g5) >> JpegDecoderQuantizationTable::QuantizationIntegerScale);
values[6][ii] = SampleRange((h1 - g6) >> JpegDecoderQuantizationTable::QuantizationIntegerScale);
values[7][ii] = SampleRange((h0 - g7) >> JpegDecoderQuantizationTable::QuantizationIntegerScale);
}
return *this;
}
// JPEG Decoder Component Class Implementation
//
// Description:
//
// SequentialOnly
//
// This function extends the sign bit of a decoded value.
//
// Parameters:
// vv: The bit value
// tt: The length of the bit value
//
static inline int Extend(int vv, int t) {
// Extend function defined in Section F.2.2.1 Figure F.12
// The tt'th bit of vv is the sign bit. One is for
// positive values and zero is for negative values.
int vt = 1 << (t - 1);
if (vv < vt) {
vt = (-1 << t) + 1;
return vv + vt;
} else {
return vv;
}
}
//
// Description:
//
// Class default constructor
//
JpegDecoderComponent::JpegDecoderComponent() {
horizontal_frequency = 0;
vertical_frequency = 0;
v_sampling = 0;
h_sampling = 0;
last_dc_value = 0;
ac_table = NULL;
dc_table = NULL;
quantization_table = NULL;
noninterleaved_rows = 0;
noninterleaved_cols = 0;
data_units = NULL;
upsample_data = NULL;
return;
}
//
// Description:
//
// Class Destructor
//
JpegDecoderComponent::~JpegDecoderComponent() {
delete[] data_units;
data_units = NULL;
delete[] upsample_data;
upsample_data = NULL;
}
//
// Description:
//
// This function associates a quantization table with the component.
//
// Parameters:
// table: The quantization table
//
void JpegDecoderComponent::SetQuantizationTable(JpegDecoderQuantizationTable &table) { quantization_table = &table; }
//
// Description:
//
// This function determines the dimensions for the component and allocates
// the storage to hold the component's data.
//
// Parameters:
// decoder: The jpeg decoder this component belongs to.
//
void JpegDecoderComponent::AllocateComponentBuffers(const JpegDecoder &decoder) {
if (data_units == NULL) {
// Determine sampling for the component. This is the amount of
// stretching needed for the component.
v_sampling = decoder.max_vertical_frequency / vertical_frequency;
h_sampling = decoder.max_horizontal_frequency / horizontal_frequency;
// Determine the component's dimensions in a non-interleaved scan.
noninterleaved_rows = (480 + v_sampling * JpegSampleWidth - 1) / (v_sampling * JpegSampleWidth);
noninterleaved_cols = (640 + h_sampling * JpegSampleWidth - 1) / (h_sampling * JpegSampleWidth);
du_rows = decoder.mcu_rows * vertical_frequency;
du_cols = decoder.mcu_cols * horizontal_frequency;
data_units = new JpegDecoderDataUnit[du_rows * du_cols];
}
}
//
// Description:
//
// This function frees the memory allocated by the component
// during the decompression process.
//
void JpegDecoderComponent::FreeComponentBuffers() {
delete[] data_units;
data_units = NULL;
delete[] upsample_data;
upsample_data = NULL;
}
//
// Description:
//
// This function asigned Huffman tables to the component.
//
// Parameters:
// dc: The DC Huffman table
// ac: The AC Huffman table
//
void JpegDecoderComponent::SetHuffmanTables(JpegHuffmanDecoder &dc, JpegHuffmanDecoder &ac) {
dc_table = &dc;
ac_table = &ac;
}
//
// Description:
//
// This function decodes a data unit in a sequential scan.
//
// Parameters:
// decoder: The decoder that owns this component
// mcurow, mcucol: The row and column for this data unit.
//
void JpegDecoderComponent::DecodeSequential(JpegDecoder &decoder, unsigned int mcurow, unsigned int mcucol) {
JpegDecoderCoefficientBlock data;
memset(&data, 0, sizeof(data));
// Decode the DC differce value.
// Section F.2.2.1
unsigned int count; // called T in F.2.2.1
count = dc_table->Decode(decoder);
int bits = decoder.Receive(count);
int diff = Extend(bits, count);
// Create the DC value from the difference and the previous DC value.
int dc = diff + last_dc_value;
last_dc_value = dc;
data[0][0] = (int16)dc;
// Decode the AC coefficients.
// Section F.2.2.2 Figure F.13
for (unsigned int kk = 1; kk < JpegSampleSize; ++kk) {
uint16 rs = (uint16)ac_table->Decode(decoder);
uint16 ssss = (uint16)(rs & 0xF);
uint16 rrrr = (uint16)(rs >> 0x4);
if (ssss == 0) {
// ssss is zero then rrrr should either be 15 or zero according to
// Figure F.1. 0 means that the rest of the coefficients are zero
// while 15 means the next 16 coefficients are zero. We are not checking
// for other values because Figure F.13 shows values other than 15
// as being treated as zero.
if (rrrr != 15)
break;
kk += 15; // Actually 16 since one more gets added by the loop.
} else {
// If ssss is non-zero then rrrr gives the number of zero coefficients
// to skip.
kk += rrrr;
// Receive and extend the additional bits.
// Section F2.2.2 Figure F.14
int bit = decoder.Receive(ssss);
int value = Extend(bit, ssss);
(&data[0][0])[JpegZigZagInputOrderCodes[kk]] = (int16)value;
}
}
data_units[mcurow * du_cols + mcucol].InverseDCT(data, *quantization_table);
}
//
// Description:
//
// This function upsamples the data for the component. Here we take
// the values from the data_units array and copy it to the
// upsample_data. If the horizontal or vertical sampling frequencies
// are less than the maximum for the image then we need to
// stretch the data during the copy.
//
void JpegDecoderComponent::Upsample() {
unsigned int imagesize = du_rows * v_sampling * du_cols * h_sampling * JpegSampleSize;
if (imagesize == 0)
return; // No data for this component yet.
if (upsample_data == NULL)
upsample_data = new uint8[imagesize];
// Simple case where component does not need to be upsampled.
if (v_sampling == 1 && h_sampling == 1) {
unsigned output = 0;
unsigned int startdu = 0;
for (unsigned int durow = 0; durow < du_rows; ++durow) {
for (unsigned int ii = 0; ii < JpegSampleWidth; ++ii) {
unsigned int du = startdu;
for (unsigned int ducol = 0; ducol < du_cols; ++ducol) {
upsample_data[output] = data_units[du].values[ii][0];
++output;
upsample_data[output] = data_units[du].values[ii][1];
++output;
upsample_data[output] = data_units[du].values[ii][2];
++output;
upsample_data[output] = data_units[du].values[ii][3];
++output;
upsample_data[output] = data_units[du].values[ii][4];
++output;
upsample_data[output] = data_units[du].values[ii][5];
++output;
upsample_data[output] = data_units[du].values[ii][6];
++output;
upsample_data[output] = data_units[du].values[ii][7];
++output;
++du;
}
}
startdu += du_cols;
}
} else {
unsigned output = 0;
unsigned int startdu = 0;
for (unsigned int durow = 0; durow < du_rows; ++durow) {
for (unsigned int ii = 0; ii < JpegSampleWidth; ++ii) {
for (unsigned int vv = 0; vv < v_sampling; ++vv) {
unsigned int du = startdu;
for (unsigned int ducol = 0; ducol < du_cols; ++ducol) {
unsigned int jj;
for (jj = 0; jj < h_sampling; ++jj) {
upsample_data[output] = data_units[du].values[ii][0];
++output;
}
for (jj = 0; jj < h_sampling; ++jj) {
upsample_data[output] = data_units[du].values[ii][1];
++output;
}
for (jj = 0; jj < h_sampling; ++jj) {
upsample_data[output] = data_units[du].values[ii][2];
++output;
}
for (jj = 0; jj < h_sampling; ++jj) {
upsample_data[output] = data_units[du].values[ii][3];
++output;
}
for (jj = 0; jj < h_sampling; ++jj) {
upsample_data[output] = data_units[du].values[ii][4];
++output;
}
for (jj = 0; jj < h_sampling; ++jj) {
upsample_data[output] = data_units[du].values[ii][5];
++output;
}
for (jj = 0; jj < h_sampling; ++jj) {
upsample_data[output] = data_units[du].values[ii][6];
++output;
}
for (jj = 0; jj < h_sampling; ++jj) {
upsample_data[output] = data_units[du].values[ii][7];
++output;
}
++du;
}
}
}
startdu += du_cols;
}
}
return;
}
//
// Description:
//
// This static member function converts the upsample_data in three
// components from YCbCr to RGB and writes it to an image.
//
// Parameters:
// c1: The component containing the Y data
// c2: Ditto for Cb
// c3: Ditto for Cr
// image: The output image
//
void JpegDecoderComponent::RGBConvert(JpegDecoderComponent &c1, JpegDecoderComponent &c2, JpegDecoderComponent &c3, uint32 surfaceId) {
uint8 *pDst8 = surface_manager->Lock_surface(surfaceId);
uint32 pitch = surface_manager->Get_pitch(surfaceId);
uint32 bpp = surface_manager->Get_BytesPP(surfaceId);
unsigned int rowstart = 0;
for (unsigned int ii = 480; ii; ii--) {
unsigned int offset = rowstart;
uint8 *outrow = pDst8;
pDst8 += pitch;
for (unsigned int jj = 0; jj < (uint32)(bpp * 640); jj += bpp) {
YCbCr_To_RGB(c1.upsample_data[offset], c2.upsample_data[offset], c3.upsample_data[offset], outrow[jj + 2], outrow[jj + 1], outrow[jj + 0]);
++offset;
}
rowstart += c1.du_cols * c1.h_sampling * JpegSampleWidth;
}
surface_manager->Unlock_surface(surfaceId);
}
} // End of namespace ICB