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


/* 
* picureB.cxx 
* 
* implementation for frame(B frame) level funcitons . 
* 
* 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/picture.h" 
#include "../include/macroblock.h" 
#include "../include/vlc.h" 
#include "../include/mot_est.h" 
#include "../include/bitstream.h" 
#include  
 
 
#ifdef  __cplusplus 
extern "C" { 
#endif 
 
 
/* Local functions */ 
int  findbiSAD(unsigned char *prev, unsigned char *next, unsigned char *curr,  
			   int lx_ipol,  int lx_curr, int blocksize); 
int  findIntraSAD(unsigned char *curr, int lx_curr); 
 
//! Choose  prediction mode for B frame  
void chooseBmode(H263VencStatus *encoder,MCParam *MC); 
//! Set MB type for B frame 
int  setBtype(int a, int b, int c); 
 
/*! 
******************************************************************************* 
* 
*   Name:          EncBfrm 
*   Description:   Encode one B Picture 
*   Input:           
*   Output:         
*   Last modified: 2003/1/8 by lcl 
* 
*******************************************************************************/ 
int EncBfrm(H263VencStatus *encoder, MCParam *MC) 
{ 
	int     total_bits = 0; 
	int     pix_x, pix_y; 
	int     mb_x, mb_y; 
	int     lines = encoder->lines; 
	int     pels = encoder->pels; 
	int     newgob; 
	int     cod; 
	int     cbp; 
	short qcoeff[384]; 
	int     dquant = 0; 
	int     mb_mode; 
	int     mb_type; 
	int     gob_nbr = 0; 
	int     gob_quant = encoder->total_Q; 
	int  	TRP = encoder->TR - encoder->ref_pic*(encoder->frame_skip+1); 
 
	interpolate_lum(encoder); 
	/* Search for forward MV */ 
	grabVec(encoder, MC, 0); 
	/* Search for backward MV */ 
	grabVec(encoder, MC, 1); 
 
	chooseBmode(encoder, MC); 
 
    total_bits += EncPicHdrPlus(encoder); 
 
	for (pix_y = 0, mb_y = 0; pix_y < lines; pix_y += 16, mb_y++) 
	{ 
		newgob = 0; 
		if(encoder->gobsync && pix_y && mb_y%(encoder->gobsync) == 0) 
		{ 
			gob_nbr++; 
			total_bits += EncGOBHdr(gob_nbr, encoder->gfid, gob_quant, encoder->TRB, TRP); 
			newgob = 1; 
		} 
		for (pix_x = 0, mb_x = 0; pix_x < pels; pix_x += 16, mb_x++) 
		{ 
			mb_mode = (MC->mv_frame[0][mb_y+1][mb_x+1])->Mode; //!< set mode of current mb 
			cod = 0; 
			if (B_INTRA == mb_mode) 
			{  
				cbp = MB_Encode_I(encoder, pix_x, pix_y, qcoeff); 
				mb_type = setBtype(mb_mode, cbp, dquant); 
				total_bits += EncMBHdr_B(mb_type, cbp, dquant);         //!<   write MCBPC, CBPY, DQUANT 
				total_bits += EncCoeff(1, cbp, qcoeff, 64);          //!<   write coefficients 
				 
			} 
			else 
			{ 
				cbp = MB_Encode_B(encoder, pix_x, pix_y, MC, qcoeff); 
				mb_type = setBtype(mb_mode, cbp, dquant); 
				total_bits += EncMBHdr_B(mb_type, cbp, dquant);            //!<  write COD, MCBPC, CBPY, DQUANT 
                total_bits += EncMVD_B(MC, mb_x, mb_y, mb_mode, newgob);   //!<  write MVD  
				total_bits += EncCoeff(0, cbp, qcoeff, 64);        //!<  write coefficients    
	 		} 
		} 
	} 
 
	total_bits += alignbits(); 
	clear_buff(); 
 
	return total_bits; 
} 
/*! 
******************************************************************************* 
* 
*   Name:          chooseBmode 
*   Description:   choose prediction mode for a B frame 
*   Input:           
*   Output:         
*   Last modified: 2003/1/8 by lcl 
* 
*******************************************************************************/ 
void chooseBmode(H263VencStatus *encoder, MCParam *MC) 
{ 
	int i, j; 
	int block; 
	int pix_x, pix_y; 
	int lx_curr = encoder->pels; 
	int lx_ipol = encoder->mv_outside_frame ? encoder->pels * 2 + 64 : encoder->pels * 2; 
	int lines = encoder->lines/16; 
	int pels  = encoder->pels/16; 
	int sadfwd; 
	int sadbwd; 
	int saddir; 
	int sadbid; 
	int sadmin; 
	int sadintra; 
	int trb; 
	int trd; 
	int dx, dy, dxf, dyf, dxb, dyb; 
	unsigned char *curr; 
	unsigned char *prev; 
	unsigned char *next; 
 
	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; 
	} 
	for (j = 0, pix_y = 0; j < lines; j++, pix_y+=16) 
	{ 
		for ( i = 0, pix_x = 0; i < pels; i++, pix_x+=16) 
		{ 
			sadfwd = MC->mv_frame[0][j+1][i+1]->min_sad; 
			sadbwd = MC->mv_frame[5][j+1][i+1]->min_sad; 
			/* compute saddir */ 
			if (MC->mv_lastframe[0][j][i]->Mode == MODE_INTER4V ||  
				MC->mv_lastframe[0][j][i]->Mode == MODE_INTER4V_Q) 
			{ 
				saddir = 0; 
				for (block = 0; block < 4; block++) 
				{ 
					dx = (MC->mv_lastframe[block+1][j][i]->x*2+MC->mv_lastframe[block+1][j][i]->x_half); 
					dy = (MC->mv_lastframe[block+1][j][i]->y*2+MC->mv_lastframe[block+1][j][i]->y_half); 
					dxf = trb * dx / trd; 
					dyf = trb * dy / trd; 
					dxb = (trb - trd) * dx / trd; 
					dyb = (trb - trd) * dy / trd; 
					curr = encoder->BPicture[encoder->B_count].pLum +pix_y*lx_curr + pix_x; 
					prev = encoder->prev_ipol + (dyf+2*pix_y+((block&2)<<3))*lx_ipol + dxf+2*pix_x+((block&1)<<4); 
					next = encoder->next_ipol + (dyb+2*pix_y+((block&2)<<3))*lx_ipol + dxb+2*pix_x+((block&1)<<4); 
					saddir += findbiSAD(prev, next, curr, lx_ipol, lx_curr, 8); 
				} 
			} 
			else 
			{ 
				dx = (MC->mv_lastframe[0][j][i]->x*2+MC->mv_lastframe[0][j][i]->x_half); 
				dy = (MC->mv_lastframe[0][j][i]->y*2+MC->mv_lastframe[0][j][i]->y_half); 
				dxf = trb * dx / trd; 
				dyf = trb * dy / trd; 
				dxb = (trb - trd) * dx / trd; 
				dyb = (trb - trd) * dy / trd; 
				curr = encoder->BPicture[encoder->B_count].pLum +pix_y*lx_curr + pix_x; 
				prev = encoder->prev_ipol + (dyf+2*pix_y)*lx_ipol + dxf+2*pix_x; 
				next = encoder->next_ipol + (dyb+2*pix_y)*lx_ipol + dxb+2*pix_x; 
				saddir = findbiSAD(prev, next, curr, lx_ipol, lx_curr, 16); 
			} 
			/* compute sadbid */ 
			dxf = MC->mv_frame[0][j+1][i+1]->x*2 + MC->mv_frame[0][j+1][i+1]->x_half; 
			dyf = MC->mv_frame[0][j+1][i+1]->y*2 + MC->mv_frame[0][j+1][i+1]->y_half; 
			dxb = MC->mv_frame[5][j+1][i+1]->x*2 + MC->mv_frame[5][j+1][i+1]->x_half; 
			dyb = MC->mv_frame[5][j+1][i+1]->y*2 + MC->mv_frame[5][j+1][i+1]->y_half; 
			curr = encoder->BPicture[encoder->B_count].pLum + pix_y*lx_curr + pix_x; 
			prev = encoder->prev_ipol + (dyf+2*pix_y)*lx_ipol + dxf+2*pix_x; 
			next = encoder->next_ipol + (dyb+2*pix_y)*lx_ipol + dxb+2*pix_x; 
			sadbid = findbiSAD(prev, next, curr, lx_ipol, lx_curr, 16); 
			/* compute sadintra */ 
			curr = encoder->BPicture[encoder->B_count].pLum + pix_y*lx_curr + pix_x; 
			sadintra = findIntraSAD(curr, lx_curr); 
 
			/* mode decision */ 
			if ((saddir < sadfwd) && (saddir < sadbwd) && (saddir < sadbid)) 
			{ 
				MC->mv_frame[0][j+1][i+1]->Mode = B_DIRECT; 
				sadmin = saddir; 
				zeroVec(MC->mv_frame[0][j+1][i+1]); 
				zeroVec(MC->mv_frame[5][j+1][i+1]); 
			} 
			else if((sadfwd < saddir) && (sadfwd < sadbwd) && (sadfwd mv_frame[0][j+1][i+1]->Mode = B_FORWARD; 
				sadmin = sadfwd; 
				zeroVec(MC->mv_frame[5][j+1][i+1]); 
			} 
			else if((sadbwd < saddir) && (sadbwd < sadfwd) && (sadbwd mv_frame[0][j+1][i+1]->Mode = B_BACKWARD; 
				sadmin = sadbwd; 
				zeroVec(MC->mv_frame[0][j+1][i+1]); 
			} 
			else 
			{ 
				MC->mv_frame[0][j+1][i+1]->Mode = B_BIDIRECTIONAL; 
				sadmin = sadbid; 
			} 
			 
			if (sadintra < sadmin - 500) 
			{ 
				MC->mv_frame[0][j+1][i+1]->Mode = B_INTRA; 
				zeroVec(MC->mv_frame[0][j+1][i+1]); 
				zeroVec(MC->mv_frame[5][j+1][i+1]); 
			} 
#ifdef PRINTMODE 
			printf("%d  ", MC->mv_frame[0][j+1][i+1]->Mode); 
#endif 
		} 
#ifdef PRINTMODE 
		printf("\n"); 
#endif 
	} 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          setBtype 
*   Description:   set MB type for B frames 
*   Input:           
*   Output:         
*   Last modified: 2003/1/8 by lcl 
* 
*******************************************************************************/ 
int  setBtype(int a, int b, int c) 
{ 
	int type = a * 3; 
 
	if (b != 0) 
	{ 
		type = c ? type+2 : type+1; 
	} 
	// intra and intra+q 
	if ((13 == type) || (14 == type)) 
	{ 
		type--; 
	} 
 
	return type - 1; 
} 
 
 
/*! 
   findIntraSAD  
   calculate the sum of the absolute difference between each pixel of one MB and its  
   mean value 
*/ 
int  findIntraSAD(unsigned char *curr, int lx_curr) 
{ 
	int i, j; 
	int MB_mean = 0; 
	int A = 0; 
	int y_off = 0; 
	 
	for (j = 0; j < 16; j++) 
	{ 
		for (i = 0; i < 16; i++) 
		{ 
			MB_mean += *(curr + i + y_off); 
		} 
		y_off += lx_curr; 
	} 
	MB_mean /= 256; 
 
	y_off = 0; 
	for (j = 0; j < 16; j++) 
	{ 
		for (i = 0; i < 16; i++) 
		{ 
			A += absm (*(curr + i + y_off) - MB_mean); 
		} 
		y_off += lx_curr; 
	} 
 
	return A; 
} 
 
 
#ifdef  __cplusplus 
} 
#endif