coder.cpp
上传用户:panstart
上传日期:2022-04-12
资源大小:199k
文件大小:31k
- ////////////////////////////////////////////////////////////////////////////
- //
- //
- // Project : VideoNet version 1.1.
- // Description : Peer to Peer Video Conferencing over the LAN.
- // Author : Nagareshwar Y Talekar ( nsry2002@yahoo.co.in)
- // Date : 15-6-2004.
- //
- // I have converted origional fast h.263 encoder library from C to C++
- // so that it can be integrated into any windows application easily.
- // I have removed some of unnecessary codes/files from the
- // fast h263 library.Also moved definitions and declarations
- // in their proper .h and .cpp files.
- //
- // File description :
- // Name : coder.cpp
- //
- //
- /////////////////////////////////////////////////////////////////////////////
- /*************************************************
* libr263: fast H.263 encoder library
*
* Copyright (C) 1996, Roalt Aalmoes, Twente University
* SPA multimedia group
*
* Based on Telenor TMN 1.6 encoder (Copyright (C) 1995, Telenor R&D)
* created by Karl Lillevold
*
* Author encoder: Roalt Aalmoes, <aalmoes@huygens.nl>
*
* Date: 31-07-96
**************************************************/
/* Modyfied by Roalt Aalmoes with better algorithms and performance
- * objectives
*
* Warning: Although I tried to remove all advanced options code,
- * there might still be some artifacts in the code. Please do not
- * blame me for not removing all of it.
- * Removing all advanced and alternating quantization code was done
- * for performance reasons. I'm sorry these options are not
- * implemented here, but see the tmn1.7 code for a slow functioning
- * advanced H.263 compression algorithm.
- *****************************************************************/
/* Notes for clear code: */
- /* var. j is used for row indexing of MB in frame */
- /* var. i is used for column indexing of MB in frame */
- /* pic is declared global */
- /* MV is changed: it is now a real array of MV instead of array of pointers
- to MV. Its range is also equal to MVs encoded, without border MVs
- Advantages: No more mallocs and frees in the code, disadvantages: ?? */
- /* PictImage structure is replaced by int pointer. Drawback: not flexible for
- other format. */
- #include"coder.h"
- #include "countbit.h"
- #include "pred.h"
- #include "quant.h"
- #include "mot_est.h"
- #include "dct.h"
/**********************************************************************
*
- * Name: Clip
- * Description: clips recontructed data 0-255
- *
- * Input: pointer to recon. data structure
- * Side effects: data structure clipped
- *
- * Date: 960715 Author: Roalt Aalmoes
- *
- ***********************************************************************/
//__inline__ void Clip(MB_Structure *data)
void Clip(MB_Structure *data)
- {
int n;
int *mb_ptr = (int *) data;
for (n = 0; n < 256 + 64 + 64; n++) {
*mb_ptr = mmin(255,mmax(0,*mb_ptr));
mb_ptr++;
}
}
/* Encodes one frame intra using params */
void CodeIntraH263(CParam *params, Bits *bits)
{
unsigned int *new_recon;
MB_Structure *data = (MB_Structure *)malloc(sizeof(MB_Structure));
int *qcoeff;
int Mode = MODE_INTRA;
int CBP;
int i,j;
new_recon = params->recon;
ZeroBits(bits);
Global::pic->QUANT = params->Q_intra;
Global::pic->picture_coding_type = PCT_INTRA;
bits->header += CountBitsPicture(Global::pic);
for ( j = 0; j < Global::mbr; j++) {
/* insert sync in *every* slice if use_gobsync is chosen */
if (Global::pic->use_gobsync && j != 0)
bits->header += CountBitsSlice(j,params->Q_intra);
for ( i = 0; i < Global::mbc; i++) {
Global::pic->MB = i + j * Global::mbc;
bits->no_intra++;
FillLumBlock(i*MB_SIZE, j*MB_SIZE, params->data, data);
FillChromBlock(i*MB_SIZE, j*MB_SIZE, params->data, data);
qcoeff = MB_EncodeAndFindCBP(data, params->Q_intra, Mode, &CBP);
/* Do standard VLC encoding */
/* COD = 0 ,Every block is coded as Intra frame */
CountBitsMB(Mode,0,CBP,0,Global::pic,bits);
- CountBitsCoeff(qcoeff, Mode, CBP,bits,64);
-
- MB_Decode(qcoeff, data, params->Q_intra, Mode);
- Clip(data);
- ReconImage(i,j,data,new_recon);
- free(qcoeff);
}
}
Global::pic->QP_mean = params->Q_intra;
- params->recon = new_recon;
- AddBitsPicture(bits);
- free(data);
return;
}
/**********************************************************************
*
* Name: MB_Encode
- * Description: DCT and quantization of Macroblocks
- *
- * Input: MB data struct, mquant (1-31, 0 = no quant),
- * MB info struct
- * Returns: Pointer to quantized coefficients
- * Side effects:
- *
- * Date: 930128 Author: Robert.Danielsen@nta.no
- *
**********************************************************************/
/* If you compare original quant with FindCBP, you see they both act
on the same range of coefficients in the cases INTRA (1..63) or
INTER (0..63) */
int *MB_EncodeAndFindCBP(MB_Structure *mb_orig, int QP, int I, int *CBP)
{
int i, j, k, l, row, col;
int fblock[64];
int coeff[384];
int *coeff_ind;
int *qcoeff;
int *qcoeff_ind;
int CBP_Mask = 32;
*CBP = 0; /* CBP gives bit pattern of lowest 6 bits
that specify which coordinates are not
zero. Bits 6 (32) to 2 (4) repr. four
8x8 Y parts of macroblock, while bits
1 (2) and 0 (1) repr. resp. the U and
V component */
if ((qcoeff=(int *)malloc(sizeof(int)*384)) == 0) {
- fprintf(stderr,"mb_encode(): Couldn't allocate qcoeff.n");
- exit(0);
- }
coeff_ind = coeff;
qcoeff_ind = qcoeff;
for (k=0;k<16;k+=8) {
for (l=0;l<16;l+=8) {
for (i=k,row=0;row<64;i++,row+=8) {
#if LONGISDOUBLEINT
for (j=l,col=0;col<8;j += 2,col +=2 ) {
*(long *) (fblock+row+col) = * (long *) &(mb_orig->lum[i][j]);
}
#else
for (j=l,col=0;col<8;j++ , col++ ) {
*(int *) (fblock+row+col) = * (int *) &(mb_orig->lum[i][j]);
}
#endif
}
Dct(fblock,coeff_ind);
*CBP |= QuantAndFindCBP(coeff_ind,qcoeff_ind,QP,I,CBP_Mask);
coeff_ind += 64;
qcoeff_ind += 64;
CBP_Mask = CBP_Mask>>1;
} /* end l */
} /* End k */
for (i=0;i<8;i++) {
#ifdef LONGISDOUBLEINT
for (j=0;j<8;j += 2) {
*(long *) (fblock+i*8+j) = *(long *) &(mb_orig->Cb[i][j]);
}
#else
for (j=0;j<8;j++) {
*(int *) (fblock+i*8+j) = *(int *) &(mb_orig->Cb[i][j]);
}
#endif
}
Dct(fblock,coeff_ind);
- *CBP |= QuantAndFindCBP(coeff_ind,qcoeff_ind,QP,I,CBP_Mask /* i == 4 */);
- coeff_ind += 64;
- qcoeff_ind += 64;
- CBP_Mask = CBP_Mask>>1;
for (i=0;i<8;i++) {
#ifdef LONGISDOUBLEINT
for (j=0;j<8;j += 2) {
* (long *) (fblock+i*8+j) = *(long *) &(mb_orig->Cr[i][j]);
}
#else
for (j=0;j<8;j ++) {
* (int *) (fblock+i*8+j) = *(int *) &(mb_orig->Cr[i][j]);
}
#endif
}
Dct(fblock,coeff_ind);
*CBP |= QuantAndFindCBP(coeff_ind,qcoeff_ind,QP,I, CBP_Mask /* i == 5 */);
return qcoeff;
}
/**********************************************************************
*
* Name: MB_Decode
* Description: Reconstruction of quantized DCT-coded Macroblocks
*
- * Input: Quantized coefficients, MB data
- * QP (1-31, 0 = no quant), MB info block
- * Returns: int (just 0)
- * Side effects:
*
* Date: 930128 Author: Robert.Danielsen@nta.no
*
**********************************************************************/
int MB_Decode(int *qcoeff, MB_Structure *mb_recon, int QP, int I)
{
int i, j, k, l, row, col;
int *iblock;
int *qcoeff_ind;
int *rcoeff, *rcoeff_ind;
if ((iblock = (int *)malloc(sizeof(int)*64)) == NULL) {
fprintf(stderr,"MB_Coder: Could not allocate space for iblockn");
exit(-1);
}
if ((rcoeff = (int *)malloc(sizeof(int)*384)) == NULL) {
fprintf(stderr,"MB_Coder: Could not allocate space for rcoeffn");
exit(-1);
}
/* For control purposes */
/* Zero data */
for (i = 0; i < 16; i++)
#ifdef LONGISDOUBLEINT
for (j = 0; j < 8; j+=2)
*(long *) &(mb_recon->lum[i][j]) = 0L;
#else
for (j = 0; j < 8; j++)
*(int *) &(mb_recon->lum[i][j]) = 0;
#endif
for (i = 0; i < 8; i++)
#ifdef LONGISDOUBLEINT
for (j = 0; j < 8; j += 2) {
*(long *) &(mb_recon->Cb[i][j]) = 0L;
*(long *) &(mb_recon->Cr[i][j]) = 0L;
}
#else
for (j = 0; j < 8; j ++) {
*(int *) &(mb_recon->Cb[i][j]) = 0;
*(int *) &(mb_recon->Cr[i][j]) = 0;
}
#endif
qcoeff_ind = qcoeff;
rcoeff_ind = rcoeff;
for (k=0;k<16;k+=8) {
for (l=0;l<16;l+=8) {
Dequant(qcoeff_ind,rcoeff_ind,QP,I);
#ifdef STANDARDIDCT
idctref(rcoeff_ind,iblock);
#else
idct(rcoeff_ind,iblock);
#endif
qcoeff_ind += 64;
rcoeff_ind += 64;
for (i=k,row=0;row<64;i++,row+=8) {
#ifdef LONGISDOUBLEINT
for (j=l,col=0;col<8;j += 2,col += 2) {
*(long *) &(mb_recon->lum[i][j]) = * (long *) (iblock+row+col);
}
#else
for (j=l,col=0;col<8; j++, col++) {
*(int *) &(mb_recon->lum[i][j]) = * (int *) (iblock+row+col);
}
#endif
}
}
}
Dequant(qcoeff_ind,rcoeff_ind,QP,I);
#ifdef STANDARDIDCT
idctref(rcoeff_ind,iblock);
#else
idct(rcoeff_ind,iblock);
#endif
qcoeff_ind += 64;
rcoeff_ind += 64;
for (i=0;i<8;i++) {
#ifdef LONGISDOUBLEINT
for (j=0;j<8;j +=2 ) {
*(long *) &(mb_recon->Cb[i][j]) = *(long *) (iblock+i*8+j);
}
#else
for (j=0;j<8;j++ ) {
*(int *) &(mb_recon->Cb[i][j]) = *(int *) (iblock+i*8+j);
}
#endif
}
Dequant(qcoeff_ind,rcoeff_ind,QP,I);
#ifdef STANDARDIDCT
idctref(rcoeff_ind,iblock);
#else
idct(rcoeff_ind,iblock);
#endif
for (i=0;i<8;i++) {
#ifdef LONGISDOUBLEINT
for (j=0;j<8;j += 2) {
*(long *) &(mb_recon->Cr[i][j]) = *(long *) (iblock+i*8+j);
}
#else
for (j=0;j<8;j++) {
*(int *) &(mb_recon->Cr[i][j]) = *(int *) (iblock+i*8+j);
}
#endif
}
free(iblock);
free(rcoeff);
return 0;
}
/**********************************************************************
*
* Name: FillLumBlock
* Description: Fills the luminance of one block of lines*pels
*
* Input: Position, pointer to qcif, array to fill
* Returns:
* Side effects: fills array
*
* Date: 930129 Author: Karl.Lillevold@nta.no
*
***********************************************************************/
void FillLumBlock( int x, int y, unsigned int *image, MB_Structure *data)
{
int n, m;
/* OPTIMIZE HERE */
/* m -> int conversion is done here, so no long optimiz. possible */
for (n = 0; n < MB_SIZE; n++)
for (m = 0; m < MB_SIZE; m++)
data->lum[n][m] =
(int) (*(image + x+m + (y+n)*Global::pels));
return;
}
/**********************************************************************
*
* Name: FillChromBlock
- * Description: Fills the chrominance of one block of qcif
- *
- * Input: Position, pointer to qcif, array to fill
- * Returns:
- * Side effects: fills array
- * 128 subtracted from each
- *
- * Date: 930129 Author: Karl.Lillevold@nta.no
*
***********************************************************************/
void FillChromBlock(int x_curr, int y_curr, unsigned int *image,
MB_Structure *data)
{
int n;
register int m;
int x, y;
x = x_curr>>1;
y = y_curr>>1;
for (n = 0; n < (MB_SIZE>>1); n++)
for (m = 0; m < (MB_SIZE>>1); m++) {
data->Cr[n][m] =
(int) (*(image + Global::vskip + x+m + (y+n)*Global::cpels));
data->Cb[n][m] =
(int) (*(image + Global::uskip + x+m + (y+n)*Global::cpels));
}
return;
}
/**********************************************************************
*
* Name: ZeroMBlock
* Description: Fills one MB with Zeros
*
* Input: MB_Structure to zero out
* Returns:
* Side effects:
*
* Date: 940829 Author: Karl.Lillevold@nta.no
*
***********************************************************************/
void ZeroMBlock(MB_Structure *data)
{
int n;
register int m;
/* ALPHA optimization */
#ifdef LONGISDOUBLEINT
for (n = 0; n < MB_SIZE; n++)
for (m = 0; m < MB_SIZE; m +=2 )
*(long *) &(data->lum[n][m]) = 0L;
for (n = 0; n < (MB_SIZE>>1); n++)
for (m = 0; m < (MB_SIZE>>1); m +=2 ) {
*(long *) &(data->Cr[n][m]) = 0L;
*(long *) &(data->Cb[n][m]) = 0L;
}
#else
for (n = 0; n < MB_SIZE; n++)
for (m = 0; m < MB_SIZE; m++ )
*(int *) &(data->lum[n][m]) = 0;
for (n = 0; n < (MB_SIZE>>1); n++)
for (m = 0; m < (MB_SIZE>>1); m++ ) {
*(int *) &(data->Cr[n][m]) = 0;
*(int *) &(data->Cb[n][m]) = 0;
}
#endif
return;
}
/**********************************************************************
*
* Name: ReconImage
* Description: Puts together reconstructed image
*
* Input: position of curr block, reconstructed
- * macroblock, pointer to recontructed image
* Returns:
* Side effects:
*
* Date: 930123 Author: Karl.Lillevold@nta.no
*
***********************************************************************/
void ReconImage (int i, int j, MB_Structure *data, unsigned int *recon)
{
int n;
int x_curr, y_curr;
int *lum_ptr, *Cb_ptr, *Cr_ptr;
unsigned int *recon_ptr, *recon_Cb_ptr, *recon_Cr_ptr;
x_curr = i * MB_SIZE;
y_curr = j * MB_SIZE;
lum_ptr = &(data->lum[0][0]);
recon_ptr = recon + x_curr + y_curr*Global::pels;
/* Fill in luminance data */
for (n = 0; n < MB_SIZE; n++) {
#ifdef LONGISDOUBLEINT
* (long *) recon_ptr = * (long *) lum_ptr;
recon_ptr += 2; lum_ptr += 2;
* (long *) recon_ptr = * (long *) lum_ptr;
recon_ptr += 2; lum_ptr += 2;
* (long *) recon_ptr = * (long *) lum_ptr;
recon_ptr += 2; lum_ptr += 2;
* (long *) recon_ptr = * (long *) lum_ptr;
recon_ptr += 2; lum_ptr += 2;
* (long *) recon_ptr = * (long *) lum_ptr;
recon_ptr += 2; lum_ptr += 2;
* (long *) recon_ptr = * (long *) lum_ptr;
recon_ptr += 2; lum_ptr += 2;
* (long *) recon_ptr = * (long *) lum_ptr;
recon_ptr += 2; lum_ptr += 2;
* (long *) recon_ptr = * (long *) lum_ptr;
recon_ptr += Global::pels - 14; lum_ptr += 2;
/* Was: for every m = 0..15 :
*(recon->lum + x_curr+m + (y_curr+n)*Global::pels) = *(lum_ptr++);
*/
#else
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr++; lum_ptr++;
* (int *) recon_ptr = * (int *) lum_ptr;
recon_ptr += Global::pels - 15; lum_ptr++;
#endif
}
recon_Cb_ptr = recon+Global::uskip+ (x_curr>>1) + (y_curr>>1)*Global::cpels;
recon_Cr_ptr = recon+Global::vskip+ (x_curr>>1) + (y_curr>>1)*Global::cpels;
Cb_ptr = &(data->Cb[0][0]);
Cr_ptr = &(data->Cr[0][0]);
/* Fill in chrominance data */
for (n = 0; n < MB_SIZE>>1; n++) {
#ifdef LONGISDOUBLEINT
* (long *) recon_Cb_ptr = * (long *) Cb_ptr;
recon_Cb_ptr += 2; Cb_ptr += 2;
* (long *) recon_Cr_ptr = * (long *) Cr_ptr;
recon_Cr_ptr += 2; Cr_ptr += 2;
* (long *) recon_Cb_ptr = * (long *) Cb_ptr;
recon_Cb_ptr += 2; Cb_ptr += 2;
* (long *) recon_Cr_ptr = * (long *) Cr_ptr;
recon_Cr_ptr += 2; Cr_ptr += 2;
* (long *) recon_Cb_ptr = * (long *) Cb_ptr;
recon_Cb_ptr += 2; Cb_ptr += 2;
* (long *) recon_Cr_ptr = * (long *) Cr_ptr;
recon_Cr_ptr += 2; Cr_ptr += 2;
* (long *) recon_Cb_ptr = * (long *) Cb_ptr;
recon_Cb_ptr += Global::cpels - 6; Cb_ptr += 2;
* (long *) recon_Cr_ptr = * (long *) Cr_ptr;
recon_Cr_ptr += Global::cpels - 6; Cr_ptr += 2;
#else
* (int *) recon_Cb_ptr = * (int *) Cb_ptr;
recon_Cb_ptr++; Cb_ptr++;
* (int *) recon_Cr_ptr = * (int *) Cr_ptr;
recon_Cr_ptr++; Cr_ptr++;
* (int *) recon_Cb_ptr = * (int *) Cb_ptr;
recon_Cb_ptr++; Cb_ptr++;
* (int *) recon_Cr_ptr = * (int *) Cr_ptr;
recon_Cr_ptr++; Cr_ptr++;
* (int *) recon_Cb_ptr = * (int *) Cb_ptr;
recon_Cb_ptr++; Cb_ptr++;
* (int *) recon_Cr_ptr = * (int *) Cr_ptr;
recon_Cr_ptr++; Cr_ptr++;
* (int *) recon_Cb_ptr = * (int *) Cb_ptr;
recon_Cb_ptr++; Cb_ptr++;
* (int *) recon_Cr_ptr = * (int *) Cr_ptr;
recon_Cr_ptr++; Cr_ptr++;
* (int *) recon_Cb_ptr = * (int *) Cb_ptr;
recon_Cb_ptr++; Cb_ptr++;
* (int *) recon_Cr_ptr = * (int *) Cr_ptr;
recon_Cr_ptr++; Cr_ptr++;
* (int *) recon_Cb_ptr = * (int *) Cb_ptr;
recon_Cb_ptr++; Cb_ptr++;
* (int *) recon_Cr_ptr = * (int *) Cr_ptr;
recon_Cr_ptr++; Cr_ptr++;
* (int *) recon_Cb_ptr = * (int *) Cb_ptr;
recon_Cb_ptr++; Cb_ptr++;
* (int *) recon_Cr_ptr = * (int *) Cr_ptr;
recon_Cr_ptr++; Cr_ptr++;
* (int *) recon_Cb_ptr = * (int *) Cb_ptr;
* (int *) recon_Cr_ptr = * (int *) Cr_ptr;
recon_Cb_ptr += Global::cpels - 7; Cb_ptr ++;
recon_Cr_ptr += Global::cpels - 7; Cr_ptr ++;
#endif
}
/* WAS:
for (m = 0; m < MB_SIZE>>1; m++) {
*(recon->Cr + (x_curr>>1)+m + ((y_curr>>1)+n)*Global::cpels) = data->Cr[n][m];
*(recon->Cb + (x_curr>>1)+m + ((y_curr>>1)+n)*Global::cpels) = data->Cb[n][m];
}
*/
return;
}
/**********************************************************************
*
* Name: ReconCopyImage
* Description: Copies previous recon_image to current recon image
*
* Input: position of curr block, reconstructed
* macroblock, pointer to recontructed image
* Returns:
* Side effects:
*
* Date: 960423 Author: Roalt Aalmoes
*
***********************************************************************/
void ReconCopyImage (int i, int j, unsigned int *recon, unsigned int *prev_recon)
{
int n;
int x_curr, y_curr;
unsigned int *lum_now, *lum_prev, *cb_now, *cr_now, *cb_prev, *cr_prev;
x_curr = i * MB_SIZE;
y_curr = j * MB_SIZE;
lum_now = recon + x_curr + y_curr*Global::pels;
lum_prev = prev_recon + x_curr + y_curr*Global::pels;
/* Fill in luminance data */
for (n = 0; n < 16; n++) {
#ifdef LONGISDOUBLEINT
*(long *)(lum_now) = *(long *)(lum_prev);
*(long *)(lum_now + 2) = *(long *)(lum_prev + 2);
*(long *)(lum_now + 4) = *(long *)(lum_prev + 4);
*(long *)(lum_now + 6) = *(long *)(lum_prev + 6);
*(long *)(lum_now + 8) = *(long *)(lum_prev + 8);
*(long *)(lum_now + 10) = *(long *)(lum_prev + 10);
*(long *)(lum_now + 12) = *(long *)(lum_prev + 12);
*(long *)(lum_now + 14) = *(long *)(lum_prev + 14);
#else
*(int *)(lum_now) = *(int *)(lum_prev);
*(int *)(lum_now + 1) = *(int *)(lum_prev + 1);
*(int *)(lum_now + 2) = *(int *)(lum_prev + 2);
*(int *)(lum_now + 3) = *(int *)(lum_prev + 3);
*(int *)(lum_now + 4) = *(int *)(lum_prev + 4);
*(int *)(lum_now + 5) = *(int *)(lum_prev + 5);
*(int *)(lum_now + 6) = *(int *)(lum_prev + 6);
*(int *)(lum_now + 7) = *(int *)(lum_prev + 7);
*(int *)(lum_now + 8) = *(int *)(lum_prev + 8);
*(int *)(lum_now + 9) = *(int *)(lum_prev + 9);
*(int *)(lum_now + 10) = *(int *)(lum_prev + 10);
*(int *)(lum_now + 11) = *(int *)(lum_prev + 11);
*(int *)(lum_now + 12) = *(int *)(lum_prev + 12);
*(int *)(lum_now + 13) = *(int *)(lum_prev + 13);
*(int *)(lum_now + 14) = *(int *)(lum_prev + 14);
*(int *)(lum_now + 15) = *(int *)(lum_prev + 15);
#endif
lum_now += Global::pels;
lum_prev += Global::pels;
}
cb_now = recon+Global::uskip + (x_curr>>1) + (y_curr>>1)*Global::cpels;
- cr_now = recon+Global::vskip + (x_curr>>1) + (y_curr>>1)*Global::cpels;
- cb_prev = prev_recon+Global::uskip+ (x_curr>>1) + (y_curr>>1)*Global::cpels;
- cr_prev = prev_recon+Global::vskip + (x_curr>>1) + (y_curr>>1)*Global::cpels;
- /* Fill in chrominance data */
for (n = 0; n < (MB_SIZE>>1); n++) {
#ifdef LONGISDOUBLEINT
*(long *)(cb_now) = *(long *)(cb_prev);
*(long *)(cb_now + 2) = *(long *)(cb_prev + 2);
*(long *)(cb_now + 4) = *(long *)(cb_prev + 4);
*(long *)(cb_now + 6) = *(long *)(cb_prev + 6);
cb_now += Global::cpels;
cb_prev += Global::cpels;
*(long *)(cr_now) = *(long *)(cr_prev);
*(long *)(cr_now + 2) = *(long *)(cr_prev + 2);
*(long *)(cr_now + 4) = *(long *)(cr_prev + 4);
*(long *)(cr_now + 6) = *(long *)(cr_prev + 6);
cr_now += Global::cpels;
cr_prev += Global::cpels;
#else
*(int *)(cb_now) = *(int *)(cb_prev);
*(int *)(cb_now + 1) = *(int *)(cb_prev + 1);
*(int *)(cb_now + 2) = *(int *)(cb_prev + 2);
*(int *)(cb_now + 3) = *(int *)(cb_prev + 3);
*(int *)(cb_now + 4) = *(int *)(cb_prev + 4);
*(int *)(cb_now + 5) = *(int *)(cb_prev + 5);
*(int *)(cb_now + 6) = *(int *)(cb_prev + 6);
*(int *)(cb_now + 7) = *(int *)(cb_prev + 7);
cb_now += Global::cpels;
cb_prev += Global::cpels;
*(int *)(cr_now) = *(int *)(cr_prev);
*(int *)(cr_now + 1) = *(int *)(cr_prev + 1);
*(int *)(cr_now + 2) = *(int *)(cr_prev + 2);
*(int *)(cr_now + 3) = *(int *)(cr_prev + 3);
*(int *)(cr_now + 4) = *(int *)(cr_prev + 4);
*(int *)(cr_now + 5) = *(int *)(cr_prev + 5);
*(int *)(cr_now + 6) = *(int *)(cr_prev + 6);
*(int *)(cr_now + 7) = *(int *)(cr_prev + 7);
cr_now += Global::cpels;
cr_prev += Global::cpels;
#endif
}
return;
}
/**********************************************************************
*
* Name: InterpolateImage
* Description: Interpolates a complete image for easier half
* pel prediction
*
- * Input: pointer to image structure
- * Returns: pointer to interpolated image
- * Side effects: allocates memory to interpolated image
- *
* Date: 950207 Author: Karl.Lillevold@nta.no
* 960207 Author: Roalt aalmoes
***********************************************************************/
void InterpolateImage(unsigned int *image, unsigned int *ipol_image,
int width, int height)
{
/* If anyone has better ideas to optimize this code, be my guest!
note: assembly or some advanced bitshifts routine might do the trick...*/
register unsigned int *ii, *oo,
*ii_new,
*ii_new_line2,
*oo_prev,
*oo_prev_line2;
register int i,j;
register unsigned int pix1,pix2,pix3,pix4;
ii = ipol_image;
oo = image;
oo_prev = image;
oo_prev_line2 = image + width;
ii_new = ipol_image;
ii_new_line2 = ipol_image + (width<<1);
/* main image */
for (j = 0; j < height-1; j++) {
/* get Pix1 and Pix3, because they are
not known the first time */
pix1 = *oo_prev;
pix3 = *oo_prev_line2;
for (i = 0; i < width-1; i++) {
/* Pix1 Pix2
Pix3 Pix4 */
/* Pix2 and Pix4 are used here for first time */
pix2 = *(oo_prev + 1);
pix4 = *(oo_prev_line2 + 1);
*(ii_new) = pix1; /* X.
..*/
*(ii_new + 1) = (pix1 + pix2 + 1)>>1; /* *X
.. */
*ii_new_line2 = (pix1 + pix3 + 1)>>1; /* *.
X. */
*(ii_new_line2 + 1) = (pix1 + pix2 + pix3 + pix4 + 2)>>2;
oo_prev++; oo_prev_line2++; ii_new += 2; ii_new_line2 += 2;
pix1 = pix2;
pix3 = pix4; /* Pix1 Pix2=Pix1' Pix2' */
/* Pix3 Pix4=Pix3' Pix4' */
}
/* One but last column */
*(ii_new++) = pix1;
*(ii_new++) = pix3;
/* Last column -On the Edge - */
*(ii_new_line2++) = (pix1 + pix3 + 1 ) >>1;
*(ii_new_line2++) = (pix1 + pix3 + 1 ) >>1;
ii_new += (width<<1); /* ii_new now on old position ii_new_line2,so
one interpolated screen line must be added*/
ii_new_line2 += (width<<1); /* In fact, ii_new_line here has same value
as ii_new */
oo_prev += 1; /* Remember, loop is done one time less! */
oo_prev_line2 += 1;
}
/* last lines */
pix1 = *oo_prev;
for (i = 0; i < width-1; i++) {
pix2 = *(oo_prev + 1);
*ii_new = *ii_new_line2 = pix1;
*(ii_new + 1) = *(ii_new_line2 + 1) = (pix1 + pix2 + 1)>>1;
ii_new += 2;
ii_new_line2 += 2;
oo_prev += 1;
pix1 = pix2; /* Pix1 Pix2=Pix1' Pix2' */
}
/* bottom right corner Global::pels */
*(ii_new) = pix1;
*(ii_new + 1) = pix1;
*(ii_new_line2) = pix1;
*(ii_new_line2+1) = pix1;
return;
}
/**********************************************************************
*
* Name: FullMotionEstimatePicture
* Description: Finds integer and half pel motion estimation
*
* Input: current image, previous image, interpolated
* reconstructed previous image, seek_dist,
* motion vector array
* Returns:
* Side effects: allocates memory for MV structure
*
* Date: 960418 Author: Roatlt
*
***********************************************************************/
void FullMotionEstimatePicture(unsigned int *curr, unsigned int *prev,
unsigned int *prev_ipol, int seek_dist,
MotionVector *MV_ptr,
int advanced_method,
int *EncodeThisBlock)
{
int i,j;
MotionVector *current_MV;
for(j = 0; j < Global::mbr; j++) {
for(i = 0; i < Global::mbc; i++) {
current_MV = MV_ptr + j*Global::mbc + i;
if(advanced_method && !*(EncodeThisBlock + j*Global::mbc + i) ) {
current_MV->x = current_MV->y = current_MV->x_half =
current_MV->y_half = 0;
current_MV->Mode = MODE_SKIP;
} else { /* EncodeThisBlock */
FullMotionEstimation(curr, prev_ipol, seek_dist, current_MV,
i*MB_SIZE, j*MB_SIZE);
current_MV->Mode = ChooseMode(curr,i*MB_SIZE,j*MB_SIZE,
current_MV->min_error);
if(current_MV->Mode == MODE_INTRA)
ZeroVec(current_MV);
}
}
}
}
void CodeInterH263(CParam *params, Bits *bits)
{
MotionVector *MV;
MotionVector ZERO = {0,0,0,0,0};
MB_Structure *recon_data_P;
MB_Structure *diff;
int *qcoeff_P;
unsigned int *new_recon=NULL;
unsigned int *prev_recon;
int Mode;
int CBP, CBPB=0;
int newgob;
int i,j;
Global::search_p_frames = params->search_method;
MV =(struct motionvector*) malloc(sizeof(MotionVector)*Global::mbc*Global::mbr);
new_recon =(unsigned int*) malloc(Global::sizeof_frame);
prev_recon = params->recon;
/* buffer control vars */
ZeroBits(bits);
/* Interpolate luminance from reconstr. picture */
InterpolateImage(prev_recon,params->interpolated_lum,Global::pels,Global::lines);
FullMotionEstimatePicture( params->data,
prev_recon,
params->interpolated_lum,
params->half_pixel_searchwindow,MV,
params->advanced_method, params->EncodeThisBlock);
/* Calculate MV for each MB */
/* ENCODE TO H.263 STREAM */
for ( j = 0; j < Global::mbr; j++) {
newgob = 0;
if (j == 0) {
Global::pic->QUANT = params->Q_inter;
Global::pic->picture_coding_type = PCT_INTER;
bits->header += CountBitsPicture(Global::pic);
}
else if (Global::pic->use_gobsync && j%Global::pic->use_gobsync == 0) {
bits->header += CountBitsSlice(j,params->Q_inter); /* insert gob sync */
newgob = 1;
}
for ( i = 0; i < Global::mbc; i++) {
/* This means: For every macroblock (i,j) do ... */
/* We have 4 different situations:
- 1) !EncodeThisBlock: this means that the
- macroblock in not encoded
- 2) EncodeThisBlock: This means that the MB is
encoded by using the predicted motion vector.
3) EncodeThisBlock: However, the approx of the
motion vector was so bad, that INTRA coding is more
appropiate here ...
4) EncodeThisBlock: The approx is so good that
the coefficients are all zero (after quant.) and are not
send.
*/
/* This means: For every macroblock (i,j) do ... */
Global::pic->DQUANT = 0;
Mode = MV[j*Global::mbc + i].Mode;
/* Determine position of MB */
Global::pic->MB = i + j * Global::mbc;
if(Mode == MODE_SKIP) {
/* SITUATION 1 */
Mode = MODE_INTRA; /* This might be done "better" in the future*/
MV[j*Global::mbc + i].Mode = Mode;
ZeroVec(&(MV[j*Global::mbc + i]));
CBP = CBPB = 0;
/* Now send code for "skip this MB" */
CountBitsMB(Mode,1,CBP,CBPB,Global::pic,bits);
ReconCopyImage(i,j,new_recon,prev_recon);
} else { /* Encode this block */
if (Mode == MODE_INTER) {
/* SITUATION 2 */
/* Predict P-MB */
diff = Predict_P(params->data,
- prev_recon,
- params->interpolated_lum,i*MB_SIZE,
- j*MB_SIZE,MV);
} else {
/* SITUATION 3 */
/* Create MB_Structure diff that contains coefficients that must be
sent to the other end */
diff = (MB_Structure *)malloc(sizeof(MB_Structure));
FillLumBlock(i*MB_SIZE, j*MB_SIZE, params->data, diff);
/* Copy curr->lum to diff for macroblock (i,j) */
FillChromBlock(i*MB_SIZE, j*MB_SIZE, params->data, diff);
/* Equiv. for curr->Cb and curr->Cr */
}
/* P or INTRA Macroblock */
/* diff -> DCT -> QUANTIZED -> qcoeff_P */
qcoeff_P = MB_EncodeAndFindCBP(diff, params->Q_inter, Mode,&CBP);
/* CBP = FindCBP(qcoeff_P, Mode, 64); -> Not required anymore */
/* All encoded, now calculate decoded image
for comparison in next frame */
/* Do DECODING */
if (CBP == 0 && (Mode == MODE_INTER) ) {
/* SITUATION 4 */
ZeroMBlock(diff);
} else {
/* qcoeff_P -> Dequantized -> IDCT -> diff */
MB_Decode(qcoeff_P, diff, params->Q_inter, Mode);
}
recon_data_P = MB_Recon_P(prev_recon,
params->interpolated_lum,diff,
i*MB_SIZE,j*MB_SIZE,MV);
Clip(recon_data_P);
free(diff);
/* Do bitstream encoding */
if((CBP==0) && (EqualVec(&(MV[j*Global::mbc+i]),&ZERO)) &&
(Mode == MODE_INTER) ) {
/* Skipped MB : both CBP and CBPB are zero, 16x16 vector is zero,
PB delta vector is zero and Mode = MODE_INTER */
/* Now send code for "skip this MB" */
CountBitsMB(Mode,1,CBP,CBPB,Global::pic,bits);
} else {
/* Normal MB */
/* VLC */
CountBitsMB(Mode,0,CBP,CBPB,Global::pic,bits);
if (Mode == MODE_INTER) {
bits->no_inter++;
CountBitsVectors(MV, bits, i, j, Mode, newgob, Global::pic);
- } else {
- /* MODE_INTRA */
bits->no_intra++;
}
/* Only encode coefficient if they are nonzero or Mode is INTRA*/
-
- if (CBP || Mode == MODE_INTRA)
- CountBitsCoeff(qcoeff_P, Mode, CBP, bits, 64);
} /* End skip/not skip macroblock encoding */
ReconImage(i,j,recon_data_P,new_recon);
free(recon_data_P);
free(qcoeff_P);
} /* End advanced */
} /* End for i */
} /* End for j */
Global::pic->QP_mean = params->Q_inter;
free(prev_recon);
params->recon = new_recon;
AddBitsPicture(bits);
free(MV);
return;
}