A simple video codec.
/*
encode.cpp
Contains functions to encode one frame and save bit stream in a file.
See 'http://www.webkinesia.com/games/vcompress8.php'
*/
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "rgb_ybr.h"
#include "dct_video.h"
#include "runhuf.h"
#include <set>
//save a DCT block in an array
void save_dct_block ( int *Y, short *dctc )
{
for ( int i = 0; i < 64; ++i )
dctc[i] = ( short ) Y[i]; //convert to short ( 2 bytes );
}
//make DCT coeffs for one macroblock.
void get_dctcoefs( YCbCr_MACRO *ycbcr_macro, short dctcoefs[][64] )
{
short block, i, j, k, *py;
int X[64], Y[64]; //for DCT transform
short bn = 0;
//save DCT coefs in array dctcoefs[] for four 8x8 Y sample blocks
for ( block = 0; block < 4; block++ ) {
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
k = 0;
for ( i = 0; i < 8; i++ ) { //one sample-block
if ( i > 0 ) py += 16; //advance py by 16 ( length of one row )
for ( j = 0; j < 8; j++ ) {
X[k++] = (int) *( py + j );
}
}
dct ( X, Y ); //perform DCT for the sample block
save_dct_block (Y, dctcoefs[bn++]); //save DCT coefs for Y block
}
//save one 8x8 Cb block
k = 0;
for ( i = 0; i < 8; ++i ) {
for ( j = 0; j < 8; ++j ) {
X[k] = (int) ycbcr_macro->Cb[k];
k++;
}
}
dct ( X, Y ); //perform DCT for the sample block
save_dct_block ( Y, dctcoefs[bn++] ); //save DCT coefs for Cb block in dctcoefs[]
//save one 8x8 Cr block
k = 0;
for ( i = 0; i < 8; ++i ) {
for ( j = 0; j < 8; ++j ) {
X[k] = (int) ycbcr_macro->Cr[k];
k++;
}
}
dct ( X, Y ); //perform DCT for the sample block
save_dct_block ( Y, dctcoefs[bn] ); //save DCT coefs for Cr block in dctcoefs[]
}
/*
Encode one image frame pointed by image using Huffman table htable.
Bit stream outputs are saved in a file pointed by outputs.
iwidth, iheight are width and height of image.
*/
void encode_one_frame ( char *image, short iwidth, short iheight, bitFileIO *outputs, set <RunHuff> &htable )
{
short row, col, i, j, r;
YCbCr_MACRO ycbcr_macro; //macroblock for YCbCr samples
short dctcoefs[8][64]; //DCT coefficients for 8 sample blocks
RGB macro16x16[256]; //16x16 pixel macroblock; assume 24-bit for each RGB pixel
short *Y, Yr[64], bn;
run3D runs[64];
RGB *p; //pointer to an RGB pixel
for ( row = 0; row < iheight; row += 16 ) { //scan all rows of image
for ( col = 0; col < iwidth; col += 16 ) { //scan all columns of image
p = ( RGB *) image + ( row * iwidth + col ); //points to beginning of macroblock
r = 0; //note pointer arithmetic
for ( i = 0; i < 16; ++i ) {
for ( j = 0; j < 16; ++j ) {
macro16x16[r++] = (RGB) *p++;
}
p += ( iwidth - 16 ); //points to next row within macroblock ( pointer arithmetic )
}
macroblock2ycbcr ( macro16x16, &ycbcr_macro ); //convert from RGB to YCbCr
get_dctcoefs( &ycbcr_macro, dctcoefs ); //get 6 dct coefs blocks from 1 YCbCr macroblock
for ( bn = 0; bn < 6; ++bn ) {
Y = dctcoefs[bn];
quantize_block ( Y ); //quantize one dct sample block
reorder ( Y, Yr ); //reorder the quantized sample block
run_block ( Yr, runs ); //encode reordered DCT coefs using 3D run-level code
/*
Encode the 3D runs with precalculated Huffman codes using the provided
Huffman table htable. Save the encoded bit stream in file pointed by
outputs.
*/
huff_encode ( htable, runs, outputs ); //encode and save
} //for bn
} //for col
} //for row
}