There is certainly a problem with the aptina header generation code. The function DefineQuantizationTableMarker() produces incorrect results. I don’t know exactly why this is, but it clearly does. Replace the function from the developer’s guide with the following:
// Calculate and write the quantisation tables
// qscale is the customised scaling factor - see MT9D131 developer guide page 78
int DefineQuantizationTableMarker (unsigned char *pbuf, int qscale, int format)
{
int i, length, temp;
unsigned char newtbl[64]; // temporary array to store scaled zigzagged quant entries
if (format == FORMAT_MONOCHROME) // monochrome
length = 67;
else
length = 132;
*pbuf++ = 0xFF; // define quantization table marker
*pbuf++ = 0xDB;
*pbuf++ = length>>8; // length field
*pbuf++ = length&0xFF;
*pbuf++ = 0; // quantization table precision | identifier
// calculate scaled zigzagged luminance quantisation table entries
for (i=0; i<64; i++) {
temp = (JPEG_StdQuantTblY[i] * qscale + 16) / 32;
// limit the values to the valid range
if (temp <= 0)
temp = 1;
if (temp > 255)
temp = 255;
newtbl[zigzag[i]] = (unsigned char) temp;
}
// write the resulting luminance quant table to the output buffer
for (i=0; i<64; i++)
*pbuf++ = newtbl[i];
// if format is monochrome we're finished, otherwise continue on, to do chrominance quant table
if (format == FORMAT_MONOCHROME)
return length+2;
*pbuf++ = 1; // quantization table precision | identifier for chrominance
// calculate scaled zigzagged chrominance quantisation table entries
for (i=0; i<64; i++) {
temp = (JPEG_StdQuantTblC[i] * qscale + 16) / 32;
// limit the values to the valid range
if (temp <= 0)
temp = 1;
if (temp > 255)
temp = 255;
newtbl[zigzag[i]] = (unsigned char) temp;
}
// write the resulting chrominance quant table to the output buffer
for (i=0; i<64; i++)
*pbuf++ = newtbl[i];
return (length+2);
}
To go along with the code you need the following 3 lookup tables:
unsigned char JPEG_StdQuantTblY[64] =
{
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
unsigned char JPEG_StdQuantTblC[64] =
{
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
// this table is used for regular-position to zigzagged-position lookup
static unsigned char zigzag[64] =
{
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,22,33,38,46,51,55,60,
21,34,37,47,50,56,59,61,
35,36,48,49,57,58,62,63
};
The inspiration for this code came from a user named Cristi Cuturicu at the website http://www.wotsit.org who posted some jpeg encoder / decoder code. I don’t really know exactly where the aptina code is “broken”, and I’m not too motivated to find out.
Using this revised function produces a far cleaner image. Take a look at the attached jpeg.
It’s not perfect yet, but it’s a big step forward.