A simple video codec.
/*
decode.cpp
Contains functions to decode a bit stream to RGB data.
See 'http://www.webkinesia.com/games/vcompress8.php'
*/
#include "common.h"
#include "fbitios.h"
#include "runhuf.h"
#include "dct_video.h"
#include "rgb_ybr.h"
/*
Read bit stream from inputs, Huffman-decode the input stream to obtain a
sample block, then run-level decode it to get an 8x8 sample block, reverse-
reorder and inverse-quantize it to get the desired DCT block.
Output: 8x8 DCT sample block in Yi[].
*/
int get_dct_block ( bitFileIO *inputs, int Yi[] )
{
short Yr[64], Y[64];
run3D runs[64];
static Dtables decode_tables; //tables used in decoding process
static set <RunHuff> htable;
static short first = 1;
if ( first ) {
build_htable ( htable );
build_huff_tree ( htable, decode_tables );
first = 0;
}
if ( huff_decode( inputs, decode_tables, runs ) > 0 ) {
run_decode ( runs, Yr );
reverse_reorder ( Yr, Y );
inverse_quantize_block ( Y );
for ( int i = 0; i < 64; ++i )
Yi[i] = (int) Y[i];
return 1;
} else
return -1;
}
/*
Get DCT data from get_dct_block(); convert DCT coefficients to YCbcr and put the
four 8x8 Y sample blocks, one 8x8 Cb sample block and one 8x8 Cr sample block into a
struct of YCbCr_MACRO.
Return: number of bytes read from file and put in YCbCr_MACRO struct.
*/
int get_ybrblocks( bitFileIO *inputs, YCbCr_MACRO *ycbcr_macro )
{
short r, row, col, i, j, k, n, block, *py;
short c;
int Y[64], X[64]; //for IDCT
n = 0;
//read data from file, perform IDCT and put them in four 8x8 Y sample blocks
for ( block = 0; block < 4; block++ ) {
if ( !get_dct_block ( inputs, Y ) ) //read in one DCT block
return 0;
idct ( Y, X ); //perform IDCT, output in X
k = 0;
if ( block < 2 )
py = ( short * ) &ycbcr_macro->Y + 8*block; //points to beginning of block
else
py = (short *)&ycbcr_macro->Y + 128 + 8*(block-2); //points to beginning of block
for ( i = 0; i < 8; i++ ) { //one sample-block
if ( i > 0 ) py += 16; //advance py by 16 ( length of one row of macroblock )
for ( j = 0; j < 8; j++ ) {
*(py+j) = X[k++]; //put sample value in macroblock
n++;
} //for j
} //for i
} //for block
if ( !get_dct_block ( inputs, Y ) ) //read in one DCT block
return 0;
idct (Y, X ); //perform IDCT, output in X
k = 0;
for ( i = 0; i < 8; ++i ) {
for ( j = 0; j < 8; ++j ) {
ycbcr_macro->Cb[k] = X[k]; //put Cb sample value in macro block
k++;
n++;
}
}
//now do that for 8x8 Cr block
if ( !get_dct_block ( inputs, Y ) ) //read in one DCT block
return 0;
idct (Y, X ); //perform IDCT, output in X
k = 0;
for ( i = 0; i < 8; ++i ) {
for ( j = 0; j < 8; ++j ) {
ycbcr_macro->Cr[k] = X[k]; //put Cr sample value in macro block
k++;
n++;
}
}
return n; //number of bytes read
}
/*
Convert a YCbCr frame to RGB frame.
*/
int decode_ybrFrame ( bitFileIO *inputs, char *image, short width, short height )
{
short r, row, col, i, j, k, block, *py;
int n, numBytes = 0;
RGB *p, macro16x16[256];
YCbCr_MACRO ycbcr_macro;
for ( row = 0; row < height; row += 16 ) {
for ( col = 0; col < width; col += 16 ) {
n = get_ybrblocks( inputs, &ycbcr_macro );
if ( n <= 0 ) return n;
ycbcr2macroblock( &ycbcr_macro, macro16x16 ); //converts to RGB
p = ( RGB *) image + ( row * width + col ); //points to beginning of macroblock
r = 0;
for ( i = 0; i < 16; ++i ) {
for ( j = 0; j < 16; ++j ) {
*p++ = macro16x16[r++];
}
p += ( width - 16 ); //points to next row within macroblock
}
numBytes += 768; // 768 = 16x16x3
} //for col
} //for row
return numBytes;
}