VideoCodec/Modules/Transform/DCT.cpp
#include "DCT.h"
// For reference DCT:
#define DCT_PI 3.14159265358979323846
#define DCT_RECIPROCAL_SQRT_2 0.70710678118654752438
namespace VideoCodec
{
DCT::DCT() : Module(DCT_MODULE_ID)
{
this->isInitialized = false;
}
DCT::~DCT()
{
if (this->isInitialized)
{
delete[] this->dctCosineProductLookupTable;
delete[] this->idctCosineProductLookupTable;
}
}
ConfigurationStatus DCT::Configure(ConfigurationElement* configuration)
{
return MODULE_CONFIGURATION_OK;
}
void DCT::ExecuteIDCT(PictureInfo* picture)
{
if (!this->isInitialized)
this->initialize();
int blockRows = picture->GetBlockRows();
int blockColumns = picture->GetBlockColumns();
if (picture->GetPixelLayout() != PIXEL_LAYOUT_MB_FOUR_TWO_ZERO)
Logger::LogMessage("Warning: The reference IDCT requires a 4:2:0 MB pixel layout.");
SignedShort* transformedBlocks = picture->GetSignedShortData();
UnsignedByte* result = new UnsignedByte[8 * 8 * 6 * (blockRows * blockColumns)];
for (int y = 0; y < blockRows; y++)
for (int x = 0; x < blockColumns; x++)
{
for (int block = 0; block < 6; block++)
{
//this->debugOutputMB(transformedBlocks + 8 * 8 * 6 * (x + (y * blockColumns)), "Source blocks\n");
this->referenceIDCT(transformedBlocks + 8 * 8 * 6 * (x + y * blockColumns) + (block << 6), result + 8 * 8 * 6 * (x + y * blockColumns) + (block << 6));
/*char* debugLabel = new char[255];
sprintf(debugLabel, "IDCTed block at (%d, %d)\n", x, y);
this->debugOutputMB(result + 8 * 8 * 6 * (x + (y * blockColumns)), debugLabel);
delete debugLabel;*/
}
}
// Store the result of the IDCT.
picture->SetUnsignedByteData(result, blockRows * blockColumns * 6 * 64);
}
void DCT::ExecuteDCT(PictureInfo* picture)
{
if (!this->isInitialized)
this->initialize();
int blockRows = picture->GetBlockRows();
int blockColumns = picture->GetBlockColumns();
if (picture->GetPixelLayout() != PIXEL_LAYOUT_MB_FOUR_TWO_ZERO)
Logger::LogMessage("Warning: The reference DCT requires a 4:2:0 MB pixel layout.");
// Get the block data.
UnsignedByte* mbData = picture->GetUnsignedByteData();
SignedShort* result = new SignedShort[8 * 8 * 6 * (blockRows * blockColumns)];
for (int index = 0; index < blockRows * blockColumns * 6 * 64; index += 64)
this->referenceDCT(mbData + index, result + index);
// Store the result in the picture.
picture->SetSignedShortData(result, blockRows * blockColumns * 6 * 64);
}
void DCT::initialize()
{
Logger::LogMessage("Initializing simple DCT/IDCT");
this->dctCosineProductLookupTable = new double[1 << 12];
this->idctCosineProductLookupTable = new double[1 << 12];
this->reciprocalRootTwo = 1.0 / sqrt(2.0);
for (int index = 0, v = 0; v < 8; v++)
{
for (int u = 0; u < 8; u++)
{
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++, index++)
{
this->dctCosineProductLookupTable[index] =
cos(((2.0 * (double)x + 1.0) * (double)u * DCT_PI) / 16.0) *
cos(((2.0 * (double)y + 1.0) * (double)v * DCT_PI) / 16.0);
}
}
}
}
for (int index = 0, y = 0; y < 8; y++)
for (int x = 0; x < 8; x++)
for (int v = 0; v < 8; v++)
for (int u = 0; u < 8; u++, index++)
this->idctCosineProductLookupTable[index] =
cos(((2.0 * (double)x + 1.0) * (double)u * DCT_PI) / 16.0) *
cos(((2.0 * (double)y + 1.0) * (double)v * DCT_PI) / 16.0) *
(v == 0 ? this->reciprocalRootTwo : 1.0) *
(u == 0 ? this->reciprocalRootTwo : 1.0);
this->isInitialized = true;
Logger::LogMessage("Initialization complete.");
}
void DCT::debugOutputMB(short int* mb, const char* label)
{
Logger::BeginIncrementalLogMessage(label);
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
Logger::IncrementalLogMessage((int)mb[y * 8 + x]);
Logger::IncrementalLogMessage(" ");
}
Logger::IncrementalLogMessage("\n");
}
Logger::EndIncrementalLogMessage(label);
}
void DCT::debugOutputMB(unsigned char* mb, const char* label)
{
Logger::BeginIncrementalLogMessage(label);
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
Logger::IncrementalLogMessage((int)mb[y * 8 + x]);
Logger::IncrementalLogMessage(" ");
}
Logger::IncrementalLogMessage("\n");
}
Logger::EndIncrementalLogMessage(label);
}
// Slow reference IDCT.
void DCT::referenceIDCT(SignedShort* data, UnsignedByte* result)
{
double temp;
int index = 0;
for (int outerIndex = 0; outerIndex < 64; outerIndex++)
{
temp = 0;
for (int i = 0; i < 64; i++, index++)
temp += (double)data[i] * this->idctCosineProductLookupTable[index];
temp *= 0.25;
short int value = lrintf(temp);
result[outerIndex] = (value < 0 ? 0 : value > 255 ? 255 : value);
}
}
// Slow reference DCT.
void DCT::referenceDCT(unsigned char* data, short int* result)
{
double temp;
int index = 0;
for (int outerIndex = 0; outerIndex < 64; outerIndex++)
{
temp = 0.0;
for (int i = 0; i < 64; i++, index++)
{
temp += ((double)data[i] * this->dctCosineProductLookupTable[index]);
}
temp *= 0.25 *
(outerIndex < 8 ? this->reciprocalRootTwo : 1.0) *
((outerIndex % 8) == 0 ? this->reciprocalRootTwo : 1.0);
result[outerIndex] = lrintf(temp);
}
}
}