I have finally reached a point in my development my current pet project of making a lossless video codec where i need to start thinking of optimizations.
Currently i amd working on the ‘key frame’ image compressor and have made a stable build which does compress reasonably well, however it is not as fast as i would like as i will eventually need it to be able to uncompress the image at 30 images per second.
I would like to hear some peoples opinons on how to go about optimizing my code.
according to JProfiler, 70% of the time is spend in my ‘encode’ method, which is to be expected. So optimizing this code would speed up the compression significantly.
Here is the encode method:
// encodes a given pixel (w,h)
public void encode(int w,int h,int k,int width,byte[][] frame, boolean verbose,boolean[][] ODCodes,boolean [][] IDCodes,boolean[][] huffCodes, OutputStream fos) throws IOException
{
int Rdiff=0;
int Gdiff=0;
int Bdiff=0;
int RGdiff;
int RBdiff;
int red;
int bitMask=0x01;
int innerBitCount;
int j=h*width+w;
{
if (k>-1)
{
Rdiff=256+((frame[j][0] & 0xFF)-(frame[k][0] & 0xFF));
Gdiff=256+((frame[j][1] & 0xFF)-(frame[k][1] & 0xFF));
Bdiff=256+((frame[j][2] & 0xFF)-(frame[k][2] & 0xFF));
}
innerBitCount=0;
// Determine the number of bits compressing via the InnerDifferences will give.
innerBitCount+=huffCodes[((int)(frame[j][0]) & 0xff)].length+1;
RGdiff= 256+((frame[j][1] & 0xFF)-(frame[j][0] & 0xFF));
if (IDCodes[RGdiff].length>0 && IDCodes[RGdiff].length<huffCodes[(frame[j][1] & 0xFF)].length)
{
innerBitCount+=IDCodes[RGdiff].length+1;
}
else
{
innerBitCount+=huffCodes[((int)(frame[j][1]) & 0xff)].length+1;
}
RBdiff= 256+((frame[j][2] & 0xFF)-(frame[j][0] & 0xFF));
if (IDCodes[RBdiff].length>0 && IDCodes[RBdiff].length<huffCodes[(frame[j][2] & 0xFF)].length)
{
innerBitCount+=IDCodes[RGdiff].length+1;
}
else
{
innerBitCount+=huffCodes[((int)(frame[j][2]) & 0xff)].length+1;
}
// if the pixel we are comparing the current pixel to is in range and all the RGB components of the current pixel are in
// the Outer Differences and coding using the OuterDifferences yields better compression than via the InnerDifferences write the OD codes.
if (k>-1 && ODCodes[Rdiff].length>0 && ODCodes[Gdiff].length>0 && ODCodes[Bdiff].length>0 && (innerBitCount>ODCodes[Rdiff].length+ODCodes[Gdiff].length+ODCodes[Bdiff].length+1))
{
value=value<<1 | bitMask; count++;
addToBuffer(fos);
for (int i=0;i<ODCodes[Rdiff].length;i++)
{
value=value<<1; count++;
if (ODCodes[Rdiff][i]) value=value| bitMask;
addToBuffer(fos);
}
for (int i=0;i<ODCodes[Gdiff].length;i++)
{
value=value<<1; count++;
if (ODCodes[Gdiff][i]) value=value| bitMask;
addToBuffer(fos);
}
for (int i=0;i<ODCodes[Bdiff].length;i++)
{
value=value<<1; count++;
if (ODCodes[Bdiff][i]) value=value| bitMask;
addToBuffer(fos);
}
}
else
{
// set Red component to its huffman code
red=((int)(frame[j][0]) & 0xff);
value=value<<1;
count++;
addToBuffer(fos);
for (int i=0;i<huffCodes[red].length;i++)
{
value=value<<1; count++;
if (huffCodes[red][i]) value=value| bitMask;
addToBuffer(fos);
}
// if the Red-Green Difference is in the Inner Differences add the ID huff code else add the Green component huffman code
// unless the Green component huffman code is less than the difference code in which case the Green component huffman code is written.
RGdiff= 256+((frame[j][1] & 0xFF)-(frame[j][0] & 0xFF));
if (IDCodes[RGdiff].length>0 && IDCodes[RGdiff].length<huffCodes[(frame[j][1] & 0xFF)].length)
{
value=value<<1 | bitMask; count++;
addToBuffer(fos);
for (int i=0;i<IDCodes[RGdiff].length;i++)
{
value=value<<1; count++;
if (IDCodes[RGdiff][i]) value=value| bitMask;
addToBuffer(fos);
}
}
else
{
value=value<<1; count++;
addToBuffer(fos);
for (int i=0;i<huffCodes[(frame[j][1] & 0xFF)].length;i++)
{
value=value<<1; count++;
if (huffCodes[(frame[j][1] & 0xFF)][i]) value=value| bitMask;
addToBuffer(fos);
}
}
// if the Red-Blue Difference is in the Inner Differences add the ID huff code else add the Blue component huffman code
// unless the Blue component huffman code is less than the difference code in which case the Blue component huffman code is written.
RBdiff= 256+((frame[j][2] & 0xFF)-(frame[j][0] & 0xFF));
if (IDCodes[RBdiff].length >0 && IDCodes[RBdiff].length<huffCodes[(frame[j][2] & 0xFF)].length)
{
value=value<<1 | bitMask; count++;
addToBuffer(fos);
for (int i=0;i<IDCodes[RBdiff].length;i++)
{
value=value<<1; count++;
if (IDCodes[RBdiff][i]) value=value| bitMask;
addToBuffer(fos);
}
}
else
{
value=value<<1; count++;
addToBuffer(fos);
for (int i=0;i<huffCodes[(frame[j][2] & 0xFF)].length;i++)
{
value=value<<1; count++;
if (huffCodes[(frame[j][2] & 0xFF)][i]) value=value| bitMask;
addToBuffer(fos);
}
}
}
}
}
similarily, in the decompressor, the decode method takes most of the time and i would like to optimize it:
// decodes a given pixel at (w,h)
public void decode(int w,int h,int k,Read read,byte[][] frame) throws IOException
{
boolean bit=bit=read.read();
int count=h*width+w;
///// re-assemble pixel using Outer Differences /////
if (bit)
{
// Red component
frame[count][0]=(byte) (-256+traverseTree(ODroot,read) + frame[k][0]);
// Green component
frame[count][1]=(byte) (-256+traverseTree(ODroot,read) + frame[k][1]);
// Blue Component
frame[count][2]=(byte) (-256+traverseTree(ODroot,read) + frame[k][2]);
}
else
{
///// re-assemble using Inner Differences /////
// Red component - from huffman code
frame[count][0]=traverseTree(root,read);
//int red=((int)(frame[count][0]) & 0xff);
bit=read.read();
// Green component - from Inner Differences else from huffman code
if (bit)
{
frame[count][1]=(byte) ((traverseTree(IDroot,read) & 0xFF) + frame[count][0]);
}
else
{
frame[count][1]=traverseTree(root,read);
//red=((int)(frame[count][1]) & 0xff);
}
bit=read.read();
// Blue component - from Inner Differences else from huffman code
if (bit)
{
frame[count][2]=(byte) ((traverseTree(IDroot,read) & 0xFF) + frame[count][0]);
}
else
{
frame[count][2]=traverseTree(root,read);
//red=((int)(frame[count][2]) & 0xff);
}
}
}
The current byte code of the compressor/decomressor can be found at: www.geocities.com/budgetanime/avid4.zip.txt (Note: you will have to remove the .txt extension once downloaded)