www.pudn.com > henclib263.rar > macroblock.cxx


/* 
* macroblock.cxx 
* 
* implementation for the macroblock level functions. 
* 
* Copyright (c) 2002-2004 Li Chun-lin(li_chunlin@263.net) 
* 
* This program is free software; you can redistribute it and/or 
* modify it under the terms of the GNU General Public License 
* as published by the Free Software Foundation; either version 2 
* of the License, or (at your option) any later version. 
*  
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
* GNU General Public License for more details. 
 
* You should have received a copy of the GNU General Public License 
* along with this program; if not, write to the Free Software 
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
*/ 
#include "../include/macroblock.h" 
#include "../include/block.h" 
#include  
 
 
 
 
#ifdef  __cplusplus 
extern "C" { 
#endif 
 
 
//! find MV for chroma block according to MV(s) of luma block 
void findchromMV(H263VencStatus *encoder, MCParam *MC, int x, int y, int *dx, int *dy, int BACKWARD); 
//! find both forward and backward MV for chroma block in direct prediction mode of B pictures 
void findchromMV_dir(H263VencStatus *encoder, MCParam *MC, int x, int y,  
					 int *dx1, int *dy1, int *dx2, int *dy2); 
 
/*! 
******************************************************************************* 
* 
*   Name:          MB_Encode_P 
*   Description:   Encode one Macroblock in P mode(make diff,dct,Q,IQ,IDct,data-recon) 
*   Input:         position of curr-MB, encoder structure, MV  
*   Output:        qcoeff_p 
*   Side effect:   write reconstructive data to recon_pic in corresponding position 
*   Return:        cbp 
*   Last modified: 2002/12/17 
* 
*******************************************************************************/ 
int MB_Encode_P(H263VencStatus *encoder, int pix_x, int pix_y, MCParam *MC,   
				 short *qcoeff_p) 
{ 
	int i, j; 
	int flag = 32; 
	unsigned char *curr_block; 
	unsigned char *recon_block; 
	unsigned char pred_block[64]; 
	short       diff_block[64]; 
 
	MB_structure curr_mb; 
	MB_structure recon_mb; 
	MotionVector *MV; 
	int dx, dy; 
 
	int           cbp = 0; 
	int           pic_width = encoder->pels; 
	int           rec_width = encoder->mv_outside_frame ? encoder->pels + 32 : encoder->pels; 
	int           lx_ipol = encoder->mv_outside_frame ? pic_width*2+64 : pic_width*2; 
	int           lx_ref_c = encoder->mv_outside_frame ? pic_width/2+16 : pic_width/2; 
	int           QP = encoder->total_Q;     
	unsigned char *prev_ipol = encoder->prev_ipol; 
	Image         *ref_img   = &(encoder->frame_buf[encoder->ref_index]); 
	Image         *curr_img  = &(encoder->frameToEncode); 
	Image         *recon_img = &(encoder->frame_buf[encoder->zero_index]); 
 
 
//! Find MB in the image 
	curr_mb.pLum = curr_img->pLum + pix_y * pic_width + pix_x; 
	curr_mb.pCb  = curr_img->pCb + pix_y * pic_width/4 + pix_x/2; 
	curr_mb.pCr  = curr_img->pCr + pix_y * pic_width/4 + pix_x/2; 
 
	recon_mb.pLum = recon_img->pLum + pix_y * rec_width + pix_x; 
	recon_mb.pCb  = recon_img->pCb + pix_y * rec_width/4 + pix_x/2; 
	recon_mb.pCr  = recon_img->pCr + pix_y * rec_width/4 + pix_x/2;  
//! Encode each block in the MB 
	//!4 lum blocks 
	for (i = 0; i < 16; i+=8) 
	{ 
		for (j = 0; j < 16; j+=8) 
		{ 
			curr_block = curr_mb.pLum + i*pic_width + j; 
			recon_block = recon_mb.pLum + i*rec_width + j; 
 
			if (!encoder->obmc) 
			{ 
				if (encoder->use4mv && (MC->mv_frame[0][pix_y/16+1][pix_x/16+1]->Mode == MODE_INTER4V)) 
				{ 
					MV = MC->mv_frame[(j>>3)+(i>>2)+1][pix_y/16+1][pix_x/16+1]; 
				} 
				else 
				{ 
					MV = MC->mv_frame[0][pix_y/16+1][pix_x/16+1];  
				} 
				pred_lum(pix_x+j, pix_y+i, MV, prev_ipol, lx_ipol, pred_block); 
			} 
			else 
			{ 
				pred_obmc(pix_x, pix_y, MC->mv_frame, pic_width,  
					      prev_ipol, lx_ipol, (j>>3)+(i>>2)+1, pred_block); 
			} 
			make_diff(curr_block, pic_width, pred_block, diff_block); 
 
			fdct(diff_block, diff_block); 
 
			if (Quant_blk_P(diff_block, qcoeff_p, QP))  
 
			{ 
				cbp|=flag; 
			    DeQuant_blk_P(qcoeff_p, diff_block, QP);   
				idct(diff_block, diff_block); 
				recon_pic(recon_block, rec_width, pred_block, diff_block); 
			} 
			else 
			{ 
				block_copy1(recon_block, pred_block, rec_width); 
			} 
			flag = flag >> 1; 
			qcoeff_p+=64; 
		} 
	} 
 
    findchromMV(encoder, MC, pix_x, pix_y, &dx, &dy, 0);  //!< find MV for 2 chrom blocks 
 
    //! Cb block 
	curr_block = curr_mb.pCb; 
	recon_block = recon_mb.pCb; 
	pred_chrom(pix_x/2, pix_y/2, ref_img->pCb, lx_ref_c, dx, dy, pred_block); 
	make_diff(curr_block, pic_width/2, pred_block, diff_block); 
 
	fdct(diff_block, diff_block); 
 
	if (Quant_blk_P(diff_block, qcoeff_p, QP))                
	{ 
 
		cbp|=flag; 
	    DeQuant_blk_P (qcoeff_p, diff_block, QP);   
		idct(diff_block, diff_block); 
		recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
	} 
	else 
	{ 
		block_copy1(recon_block, pred_block, rec_width/2); 
	} 
	flag = flag >> 1; 
	qcoeff_p+=64; 
    //! Cr block 
	curr_block = curr_mb.pCr; 
	recon_block = recon_mb.pCr; 
	pred_chrom(pix_x/2, pix_y/2, ref_img->pCr, lx_ref_c, dx, dy, pred_block); 
	make_diff(curr_block, pic_width/2, pred_block, diff_block); 
 
	fdct(diff_block, diff_block); 
 
	if (Quant_blk_P(diff_block, qcoeff_p, QP))                
	{ 
		cbp|=flag; 
	    DeQuant_blk_P (qcoeff_p, diff_block, QP);       
		idct(diff_block, diff_block); 
		recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
	} 
	else 
	{ 
		block_copy1(recon_block, pred_block, rec_width/2); 
	} 
 
	return cbp; 
 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          MB_Encode_I 
*   Description:   Encode one Macroblock in I mode(dct, Q, IQ, Idct, data-recon) 
*   Input:         position of curr-MB, encoder structure   
*   Output:        qcoeff_p 
*   Side effect:   write reconstructive data to recon_pic in corresponding position 
*   Last modified: 2002/12/5 by zj  
* 
*******************************************************************************/ 
int MB_Encode_I(H263VencStatus *encoder, int pix_x, int pix_y, short *qcoeff_i) 
{ 
	int i, j; 
	int flag = 32; 
	unsigned char *curr_block; 
	unsigned char *recon_block; 
	MB_structure curr_mb; 
	MB_structure recon_mb; 
 
	int   cbp = 0; 
	int   pic_width = encoder->pels; 
	int   rec_width = encoder->mv_outside_frame? encoder->pels+32 : encoder->pels; 
	int   QI = encoder->total_Q; 
	Image *curr_img  = &(encoder->frameToEncode); 
	Image *recon_img = &(encoder->frame_buf[encoder->zero_index]); 
 
	short tmpblk[64]; 
 
	if (encoder->PTYPE == B_IMG) 
	{ 
		curr_img  = &(encoder->BPicture[encoder->B_count]); 
		recon_img = &(encoder->BPicture[0]); 
		rec_width = encoder->pels; 
	} 
//! Find MB in the image 
	curr_mb.pLum = curr_img->pLum + pix_y * pic_width + pix_x; 
	curr_mb.pCb  = curr_img->pCb + pix_y * pic_width/4 + pix_x/2; 
	curr_mb.pCr  = curr_img->pCr + pix_y * pic_width/4 + pix_x/2; 
 
	recon_mb.pLum = recon_img->pLum + pix_y * rec_width + pix_x; 
	recon_mb.pCb  = recon_img->pCb + pix_y * rec_width/4 + pix_x/2; 
	recon_mb.pCr  = recon_img->pCr + pix_y * rec_width/4 + pix_x/2;  
 
//! Encode each block in the MB 
	//! 4 lum blocks 
	for (i = 0; i < 16; i+=8) 
	{ 
		for (j = 0; j < 16; j+=8) 
		{ 
			curr_block = curr_mb.pLum + i*pic_width + j; 
			recon_block = recon_mb.pLum + i*rec_width + j; 
			block_copy2(tmpblk, curr_block, pic_width);   // 2/11/2003 lcl 
			fdct (tmpblk, tmpblk);    // 2/11/2003 lcl 
			if (Quant_blk_I (tmpblk, qcoeff_i, QI))                // 2/12/2003 lcl 
//			if(rsden (curr_block, 0,  pic_width, QI, INTRA, qcoeff_i)) 
			{ 
				cbp|=flag; 
			} 
			DeQuant_blk_I (qcoeff_i, tmpblk, QI);                //  2/12/2003 lcl 
			idct (tmpblk, tmpblk);          // 2/25/2003 lcl 
			block_copy3(recon_block, tmpblk, rec_width); 
			flag = flag >> 1; 
			qcoeff_i+=64; 
		} 
	} 
    //! Cb block 
	curr_block = curr_mb.pCb; 
	recon_block = recon_mb.pCb; 
	block_copy2(tmpblk, curr_block, pic_width/2); 
	fdct (tmpblk, tmpblk);    // 2/12/2003 lcl 
	if (Quant_blk_I (tmpblk, qcoeff_i, QI))                // 2/12/2003 lcl 
	{ 
		cbp|=flag; 
	} 
	DeQuant_blk_I (qcoeff_i, tmpblk, QI);                  // 2/12/2003 lcl 
	idct (tmpblk, tmpblk);           // 2/26/2003 lcl 
	block_copy3(recon_block, tmpblk, rec_width/2); 
	flag = flag >> 1; 
	qcoeff_i+=64; 
    //! Cr block 
	curr_block = curr_mb.pCr; 
	recon_block = recon_mb.pCr; 
	block_copy2(tmpblk, curr_block, pic_width/2); 
	fdct (tmpblk, tmpblk);    // 2/12/2003 lcl 
	if (Quant_blk_I (tmpblk, qcoeff_i, QI))                // 2/12/2003 lcl 
	{ 
		cbp|=flag; 
	} 
	DeQuant_blk_I (qcoeff_i, tmpblk, QI);                  // 2/12/2003 lcl 
	idct (tmpblk, tmpblk);           // 2/25/2003 lcl 
	block_copy3(recon_block, tmpblk, rec_width/2); 
	 
	return cbp;      
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          MB_Encode_B 
*   Description:   Encode one Macroblock in for B frame(make diff,dct,Q,IQ,IDct,data-recon) 
*   Input:         position of curr-MB, encoder structure, MV  
*   Output:        qcoeff_p 
*   Side effect:   write reconstructive data to recon_pic in corresponding position 
*   Return:        cbp 
*   Last modified: 2003/1/8 
* 
*******************************************************************************/ 
int  MB_Encode_B(H263VencStatus *encoder, int pix_x, int pix_y, MCParam *MC,  
				 short *qcoeff_p) 
{ 
	int i, j; 
	int flag = 32; 
	unsigned char *curr_block; 
	unsigned char *recon_block; 
	unsigned char pred_block[64]; 
	short       diff_block[64]; 
	MB_structure curr_mb; 
	MB_structure recon_mb; 
	int trb; 
	int trd; 
	int dxf, dyf, dxb, dyb; 
	MotionVector *MV;                    //!< pointer to MV of last P frame 
 
	int           mb_x = pix_x/16; 
	int           mb_y = pix_y/16; 
	int           pred_mode = MC->mv_frame[0][mb_y+1][mb_x+1]->Mode; 
	int           cbp = 0; 
	int           pic_width = encoder->pels; 
	int           rec_width = encoder->pels; 
	int           lx_ipol = encoder->mv_outside_frame ? pic_width*2+64 : pic_width*2; 
	int           lx_ref_c = encoder->mv_outside_frame ? pic_width/2+16 : pic_width/2; 
	int           QP = encoder->total_Q;   
	 
	unsigned char *prev_ipol = encoder->prev_ipol; 
	unsigned char *next_ipol = encoder->next_ipol; 
	Image         *ref_img   = &(encoder->frame_buf[encoder->ref_index]); 
	Image         *next_img  = &(encoder->frame_buf[encoder->zero_index]); 
	Image         *curr_img  = &(encoder->BPicture[encoder->B_count]); 
	Image         *recon_img = &(encoder->BPicture[0]); 
 
 
	trb = encoder->TRB - encoder->TRP[encoder->ref_index]; 
	if (trb < 0) 
	{ 
		trb += 256; 
	} 
	trd = encoder->TRP[encoder->zero_index] - encoder->TRP[encoder->ref_index]; 
	if (trd < 0) 
	{ 
		trd += 256; 
	} 
 
//! Find MB in the image 
	curr_mb.pLum = curr_img->pLum + pix_y * pic_width + pix_x; 
	curr_mb.pCb  = curr_img->pCb + pix_y * pic_width/4 + pix_x/2; 
	curr_mb.pCr  = curr_img->pCr + pix_y * pic_width/4 + pix_x/2; 
 
	recon_mb.pLum = recon_img->pLum + pix_y * rec_width + pix_x; 
	recon_mb.pCb  = recon_img->pCb + pix_y * rec_width/4 + pix_x/2; 
	recon_mb.pCr  = recon_img->pCr + pix_y * rec_width/4 + pix_x/2;  
 
	/* direct mode */ 
	if (B_DIRECT == pred_mode)  
	{ 
		//! Encode each block in the MB 
		//!4 lum blocks 
		for (i = 0; i < 16; i+=8) 
		{ 
			for (j = 0; j < 16; j+=8) 
			{ 
				curr_block = curr_mb.pLum + i*pic_width + j; 
				recon_block = recon_mb.pLum + i*rec_width + j; 
				 
				MV = MC->mv_lastframe[0][mb_y][mb_x]; 
				if (MV->Mode == MODE_INTER4V || MV->Mode == MODE_INTER4V_Q) 
				{ 
					MV = MC->mv_lastframe[(j>>3)+(i>>2)+1][mb_y][mb_x]; 
				} 
				dxf = (MV->x*2 + MV->x_half) * trb / trd; 
				dyf = (MV->y*2 + MV->y_half) * trb / trd; 
				dxb = (MV->x*2 + MV->x_half) * (trb-trd) / trd; 
				dyb = (MV->y*2 + MV->y_half) * (trb-trd) / trd; 
 
				pred_lum_bid(pix_x+j, pix_y+i, dxf, dyf, dxb, dyb, prev_ipol, next_ipol,  
					lx_ipol, pred_block); 
								 
				make_diff(curr_block, pic_width, pred_block, diff_block); 
				 
				fdct(diff_block, diff_block); 
				 
				if (Quant_blk_P(diff_block, qcoeff_p, QP))  
					 
				{ 
					cbp|=flag; 
					DeQuant_blk_P(qcoeff_p, diff_block, QP);   
					idct(diff_block, diff_block); 
					recon_pic(recon_block, rec_width, pred_block, diff_block); 
				} 
				else 
				{ 
					block_copy1(recon_block, pred_block, rec_width); 
				} 
				flag = flag >> 1; 
				qcoeff_p+=64;			 
			} 
		} 
 
		/* find both forward MV and backward MV for chrom blocks in direct mode */ 
		findchromMV_dir(encoder, MC, pix_x, pix_y, &dxf, &dyf, &dxb, &dyb);  
 
		//! Cb block 
		curr_block = curr_mb.pCb; 
		recon_block = recon_mb.pCb; 
		 
		pred_chrom_bid(pix_x/2, pix_y/2, ref_img->pCb, next_img->pCb, lx_ref_c, dxf, dyf, dxb, dyb, pred_block); 
		 
		make_diff(curr_block, pic_width/2, pred_block, diff_block); 
		 
		fdct(diff_block, diff_block); 
		 
		if (Quant_blk_P(diff_block, qcoeff_p, QP))                
		{ 
			 
			cbp|=flag; 
			DeQuant_blk_P (qcoeff_p, diff_block, QP);   
			idct(diff_block, diff_block); 
			recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
		} 
		else 
		{ 
			block_copy1(recon_block, pred_block, rec_width/2); 
		} 
		flag = flag >> 1; 
		qcoeff_p+=64; 
		 
		//! Cr block 
		curr_block = curr_mb.pCr; 
		recon_block = recon_mb.pCr; 
		 
		pred_chrom_bid(pix_x/2, pix_y/2, ref_img->pCr, next_img->pCr, lx_ref_c, dxf, dyf, dxb, dyb, pred_block); 
		 
		make_diff(curr_block, pic_width/2, pred_block, diff_block); 
		 
		fdct(diff_block, diff_block); 
		 
		if (Quant_blk_P(diff_block, qcoeff_p, QP))                
		{ 
			cbp|=flag; 
			DeQuant_blk_P (qcoeff_p, diff_block, QP);       
			idct(diff_block, diff_block); 
			recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
		} 
		else 
		{ 
			block_copy1(recon_block, pred_block, rec_width/2); 
		} 
		 
	} 
	/* forward mode */ 
	else if (B_FORWARD == pred_mode) 
	{ 
		//! Encode each block in the MB 
		//!4 lum blocks 
		for (i = 0; i < 16; i+=8) 
		{ 
			for (j = 0; j < 16; j+=8) 
			{ 
				curr_block = curr_mb.pLum + i*pic_width + j; 
				recon_block = recon_mb.pLum + i*rec_width + j; 
 
				MV = MC->mv_frame[0][mb_y+1][mb_x+1]; 
				 
				pred_lum(pix_x+j, pix_y+i, MV, prev_ipol, lx_ipol, pred_block); 
				make_diff(curr_block, pic_width, pred_block, diff_block); 
				 
				fdct( diff_block, diff_block); 
				 
				if (Quant_blk_P(diff_block, qcoeff_p, QP))  
					 
				{ 
					cbp|=flag; 
					DeQuant_blk_P(qcoeff_p, diff_block, QP);   
					idct(diff_block, diff_block); 
					recon_pic(recon_block, rec_width, pred_block, diff_block); 
				} 
				else 
				{ 
					block_copy1(recon_block, pred_block, rec_width); 
				} 
				flag = flag >> 1; 
				qcoeff_p+=64;			 
			} 
		} 
		/* only find forward MV for chrom blocks in forward mode */ 
        findchromMV(encoder, MC, pix_x, pix_y, &dxf, &dyf, 0); 
 
		//! Cb block 
		curr_block = curr_mb.pCb; 
		recon_block = recon_mb.pCb; 
		 
		pred_chrom(pix_x/2, pix_y/2, ref_img->pCb, lx_ref_c, dxf, dyf, pred_block); 
		 
		make_diff(curr_block, pic_width/2, pred_block, diff_block); 
		 
		fdct(diff_block, diff_block); 
		 
		if (Quant_blk_P(diff_block, qcoeff_p, QP))                
		{ 
			 
			cbp|=flag; 
			DeQuant_blk_P (qcoeff_p, diff_block, QP);   
			idct(diff_block, diff_block); 
			recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
		} 
		else 
		{ 
			block_copy1(recon_block, pred_block, rec_width/2); 
		} 
		flag = flag >> 1; 
		qcoeff_p+=64; 
		 
		//! Cr block 
		curr_block = curr_mb.pCr; 
		recon_block = recon_mb.pCr; 
		 
		pred_chrom(pix_x/2, pix_y/2, ref_img->pCr, lx_ref_c, dxf, dyf, pred_block); 
		 
		make_diff(curr_block, pic_width/2, pred_block, diff_block); 
		 
		fdct(diff_block, diff_block); 
		 
		if (Quant_blk_P(diff_block, qcoeff_p, QP))                
		{ 
			cbp|=flag; 
			DeQuant_blk_P (qcoeff_p, diff_block, QP);       
			idct(diff_block, diff_block); 
			recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
		} 
		else 
		{ 
			block_copy1(recon_block, pred_block, rec_width/2); 
		} 
	} 
	/* backward mode */ 
	else if (B_BACKWARD == pred_mode) 
	{ 
		//! Encode each block in the MB 
		//!4 lum blocks 
		for (i = 0; i < 16; i+=8) 
		{ 
			for (j = 0; j < 16; j+=8) 
			{ 
				curr_block = curr_mb.pLum + i*pic_width + j; 
				recon_block = recon_mb.pLum + i*rec_width + j; 
 
				MV = MC->mv_frame[5][mb_y+1][mb_x+1]; 
				 
				pred_lum(pix_x+j, pix_y+i, MV, next_ipol, lx_ipol, pred_block); 
				make_diff(curr_block, pic_width, pred_block, diff_block); 
				 
				fdct(diff_block, diff_block); 
				 
				if (Quant_blk_P(diff_block, qcoeff_p, QP))  
					 
				{ 
					cbp|=flag; 
					DeQuant_blk_P(qcoeff_p, diff_block, QP);   
					idct(diff_block, diff_block); 
					recon_pic(recon_block, rec_width, pred_block, diff_block); 
				} 
				else 
				{ 
					block_copy1(recon_block, pred_block, rec_width); 
				} 
				flag = flag >> 1; 
				qcoeff_p+=64;			 
			} 
		} 
		/* only find backward MV for chrom blocks in backward mode */ 
        findchromMV(encoder, MC, pix_x, pix_y, &dxb, &dyb, 1);		 
		 
		//! Cb block 
		curr_block = curr_mb.pCb; 
		recon_block = recon_mb.pCb; 
		 
		pred_chrom(pix_x/2, pix_y/2, next_img->pCb, lx_ref_c, dxb, dyb, pred_block); 
		 
		make_diff(curr_block, pic_width/2, pred_block, diff_block); 
		 
		fdct(diff_block, diff_block); 
		 
		if (Quant_blk_P(diff_block, qcoeff_p, QP))                
		{ 
			 
			cbp|=flag; 
			DeQuant_blk_P (qcoeff_p, diff_block, QP);   
			idct(diff_block, diff_block); 
			recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
		} 
		else 
		{ 
			block_copy1(recon_block, pred_block, rec_width/2); 
		} 
		flag = flag >> 1; 
		qcoeff_p+=64; 
		 
		//! Cr block 
		curr_block = curr_mb.pCr; 
		recon_block = recon_mb.pCr; 
	 
		pred_chrom(pix_x/2, pix_y/2, next_img->pCr, lx_ref_c, dxb, dyb, pred_block); 
		 
		make_diff(curr_block, pic_width/2, pred_block, diff_block); 
		 
		fdct(diff_block, diff_block); 
		 
		if (Quant_blk_P(diff_block, qcoeff_p, QP))                
		{ 
			cbp|=flag; 
			DeQuant_blk_P (qcoeff_p, diff_block, QP);       
			idct(diff_block, diff_block); 
			recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
		} 
		else 
		{ 
			block_copy1(recon_block, pred_block, rec_width/2); 
		} 
	} 
	/* bi-direction mode */ 
	else if (B_BIDIRECTIONAL == pred_mode) 
	{ 
		//! Encode each block in the MB 
		//!4 lum blocks 
		for (i = 0; i < 16; i+=8) 
		{ 
			for (j = 0; j < 16; j+=8) 
			{ 
				curr_block = curr_mb.pLum + i*pic_width + j; 
				recon_block = recon_mb.pLum + i*rec_width + j; 
 
				dxf = MC->mv_frame[0][mb_y+1][mb_x+1]->x*2 + MC->mv_frame[0][mb_y+1][mb_x+1]->x_half; 
				dyf = MC->mv_frame[0][mb_y+1][mb_x+1]->y*2 + MC->mv_frame[0][mb_y+1][mb_x+1]->y_half; 
				dxb = MC->mv_frame[5][mb_y+1][mb_x+1]->x*2 + MC->mv_frame[5][mb_y+1][mb_x+1]->x_half; 
				dyb = MC->mv_frame[5][mb_y+1][mb_x+1]->y*2 + MC->mv_frame[5][mb_y+1][mb_x+1]->y_half; 
 
				pred_lum_bid(pix_x+j, pix_y+i, dxf, dyf, dxb, dyb, prev_ipol, next_ipol, lx_ipol, pred_block); 
				make_diff(curr_block, pic_width, pred_block, diff_block); 
				 
				fdct(diff_block, diff_block); 
				 
				if (Quant_blk_P(diff_block, qcoeff_p, QP))  
					 
				{ 
					cbp|=flag; 
					DeQuant_blk_P(qcoeff_p, diff_block, QP);   
					idct(diff_block, diff_block); 
					recon_pic(recon_block, rec_width, pred_block, diff_block); 
				} 
				else 
				{ 
					block_copy1(recon_block, pred_block, rec_width); 
				} 
				flag = flag >> 1; 
				qcoeff_p+=64;			 
			} 
		} 
		/* find forward MV and backward MV for chrom blocks respectivly in bi-direction mode */   
        findchromMV(encoder, MC, pix_x, pix_y, &dxf, &dyf, 0); 
		findchromMV(encoder, MC, pix_x, pix_y, &dxb, &dyb, 1); 
		 
		//! Cb block 
		curr_block = curr_mb.pCb; 
		recon_block = recon_mb.pCb; 
		 
		pred_chrom_bid(pix_x/2, pix_y/2, ref_img->pCb, next_img->pCb, lx_ref_c, dxf, dyf, 
			           dxb, dyb, pred_block); 
		 
		make_diff(curr_block, pic_width/2, pred_block, diff_block); 
		 
		fdct(diff_block, diff_block); 
		 
		if (Quant_blk_P(diff_block, qcoeff_p, QP))                
		{ 
			 
			cbp|=flag; 
			DeQuant_blk_P (qcoeff_p, diff_block, QP);   
			idct(diff_block, diff_block); 
			recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
		} 
		else 
		{ 
			block_copy1(recon_block, pred_block, rec_width/2); 
		} 
		flag = flag >> 1; 
		qcoeff_p+=64; 
		 
		//! Cr block 
		curr_block = curr_mb.pCr; 
		recon_block = recon_mb.pCr; 
		 
        pred_chrom_bid(pix_x/2, pix_y/2, ref_img->pCr, next_img->pCr, lx_ref_c, dxf, dyf, 
			           dxb, dyb, pred_block); 
		 
		make_diff(curr_block, pic_width/2, pred_block, diff_block); 
		 
		fdct(diff_block, diff_block); 
		 
		if (Quant_blk_P(diff_block, qcoeff_p, QP))                
		{ 
			cbp|=flag; 
			DeQuant_blk_P (qcoeff_p, diff_block, QP);       
			idct(diff_block, diff_block); 
			recon_pic(recon_block, rec_width/2, pred_block, diff_block); 
		} 
		else 
		{ 
			block_copy1(recon_block, pred_block, rec_width/2); 
		} 
	} 
	else 
	{ 
		return -1; 
	} 
 
	return cbp; 
} 
 
/*! 
  findbiSAD 
  calculate the sum of the absolute difference between one MB and its bi-direction  
  predicted value 
*/ 
int  findbiSAD(unsigned char *prev, unsigned char *next, unsigned char *curr,  
			   int lx_ipol,  int lx_curr, int blocksize) 
{ 
	int i, j; 
	unsigned char *p0 = curr; 
	unsigned char *p1 = prev; 
	unsigned char *p2 = next; 
	int sad = 0; 
 
	for (j = 0; j < blocksize; j++) 
	{ 
		for (i = 0; i < blocksize; i++) 
		{ 
			sad += absm(p0[i] - (p1[i<<1]+p2[i<<1])/2); 
		} 
		p0 += lx_curr; 
		p1 += lx_ipol<<1; 
		p2 += lx_ipol<<1; 
	} 
 
	return sad; 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          findchromMV 
*   Description:    
*   Input:          
*   Output:         
*   Last modified: 2002/12/21 
* 
*******************************************************************************/ 
void findchromMV(H263VencStatus *encoder, MCParam *MC, int x, int y, int *dx, int *dy, int BACKWARD) 
{ 
	int r = y/16+1; 
	int c = x/16+1; 
	int vec = BACKWARD ? 5 : 0; 
    int roundtab[] = {0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2}; 
	int sum; 
	 
	if (((MC->mv_frame[0][r][c]->Mode == MODE_INTER4V)||(MC->mv_frame[0][r][c]->Mode == MODE_INTER4V_Q)) 
		&& encoder->use4mv && (encoder->PTYPE != B_IMG)) 
	{ 
		 
		sum = MC->mv_frame[1][r][c]->x*2+MC->mv_frame[1][r][c]->x_half+ 
			MC->mv_frame[2][r][c]->x*2+MC->mv_frame[2][r][c]->x_half+ 
			MC->mv_frame[3][r][c]->x*2+MC->mv_frame[3][r][c]->x_half+ 
			MC->mv_frame[4][r][c]->x*2+MC->mv_frame[4][r][c]->x_half; 
		*dx = sign(sum)*(roundtab[absm(sum)%16] + (absm(sum)/16)*2); 
		sum = MC->mv_frame[1][r][c]->y*2+MC->mv_frame[1][r][c]->y_half+ 
			MC->mv_frame[2][r][c]->y*2+MC->mv_frame[2][r][c]->y_half+ 
			MC->mv_frame[3][r][c]->y*2+MC->mv_frame[3][r][c]->y_half+ 
			MC->mv_frame[4][r][c]->y*2+MC->mv_frame[4][r][c]->y_half; 
		*dy = sign(sum)*(roundtab[absm(sum)%16] + (absm(sum)/16)*2); 
	} 
	else 
	{ 
		*dx = 2*MC->mv_frame[vec][r][c]->x + MC->mv_frame[vec][r][c]->x_half; 
		*dy = 2*MC->mv_frame[vec][r][c]->y + MC->mv_frame[vec][r][c]->y_half; 
		*dx = ( *dx % 4 == 0 ? *dx >> 1 : (*dx>>1)|1 ); 
		*dy = ( *dy % 4 == 0 ? *dy >> 1 : (*dy>>1)|1 ); 
	} 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          findchromMV_dir 
*   Description:    
*   Input:          
*   Output:         
*   Last modified: 2003/1/9 
* 
*******************************************************************************/ 
void findchromMV_dir(H263VencStatus *encoder, MCParam *MC, int x, int y,  
					 int *dx1, int *dy1, int *dx2, int *dy2) 
{ 
	int r = y/16; 
	int c = x/16; 
	int trb; 
	int trd; 
	int dxf, dyf, dxb, dyb; 
    int roundtab[] = {0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2}; 
	int sum1, sum2, sum3, sum4; 
	int i; 
 
	trb = encoder->TRB - encoder->TRP[encoder->ref_index]; 
	if (trb < 0) 
	{ 
		trb += 256; 
	} 
	trd = encoder->TRP[encoder->zero_index] - encoder->TRP[encoder->ref_index]; 
	if (trd < 0) 
	{ 
		trd += 256; 
	}	 
	if (((MC->mv_lastframe[0][r][c]->Mode == MODE_INTER4V)||(MC->mv_lastframe[0][r][c]->Mode == MODE_INTER4V_Q)) 
		&& encoder->use4mv ) 
	{	 
		sum1 = sum2 = sum3 = sum4 = 0; 
		for (i = 1; i < 5; i++) 
		{ 
			dxf = (MC->mv_lastframe[i][r][c]->x*2 + MC->mv_lastframe[i][r][c]->x_half) * trb / trd; 
			dyf = (MC->mv_lastframe[i][r][c]->y*2 + MC->mv_lastframe[i][r][c]->y_half) * trb / trd; 
			dxb = (MC->mv_lastframe[i][r][c]->x*2 + MC->mv_lastframe[i][r][c]->x_half) * (trb - trd) / trd; 
			dyb = (MC->mv_lastframe[i][r][c]->y*2 + MC->mv_lastframe[i][r][c]->y_half) * (trb - trd) / trd; 
			sum1 += dxf; 
			sum2 += dyf; 
			sum3 += dxb; 
			sum4 += dyb; 
		} 
		*dx1 = sign(sum1)*(roundtab[absm(sum1)%16] + (absm(sum1)/16)*2); 
		*dy1 = sign(sum2)*(roundtab[absm(sum2)%16] + (absm(sum2)/16)*2); 
		*dx2 = sign(sum3)*(roundtab[absm(sum3)%16] + (absm(sum3)/16)*2); 
		*dy2 = sign(sum4)*(roundtab[absm(sum4)%16] + (absm(sum4)/16)*2); 
	} 
	else 
	{ 
		dxf = (MC->mv_lastframe[0][r][c]->x*2 + MC->mv_lastframe[0][r][c]->x_half) * trb / trd; 
		dyf = (MC->mv_lastframe[0][r][c]->y*2 + MC->mv_lastframe[0][r][c]->y_half) * trb / trd; 
		dxb = (MC->mv_lastframe[0][r][c]->x*2 + MC->mv_lastframe[0][r][c]->x_half) * (trb - trd) / trd; 
		dyb = (MC->mv_lastframe[0][r][c]->y*2 + MC->mv_lastframe[0][r][c]->y_half) * (trb - trd) / trd; 
 
		*dx1 = (dxf % 4 == 0 ? dxf >> 1 : (dxf>>1)|1); 
		*dy1 = (dyf % 4 == 0 ? dyf >> 1 : (dyf>>1)|1); 
		*dx2 = (dxb % 4 == 0 ? dxb >> 1 : (dxb>>1)|1); 
		*dy2 = (dyb % 4 == 0 ? dyb >> 1 : (dyb>>1)|1); 
	} 
} 
 
#ifdef  __cplusplus 
} 
#endif