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


/* 
* vlc.cxx 
* 
* implementation for VLC(Variable Length Coding) funtions. 
* 
* 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  
#include  
#include "../include/vlc.h" 
#include "../include/bitstream.h" 
 
#ifdef  __cplusplus 
extern "C" { 
#endif 
 
 
//! find predictive MV 
void FindPMV(MotionVector *MV[6][MBR+1][MBC+2], int x, int y, int *pmv0, int *pmv1, int block, int newgob, int half_pel); 
//! find predictive MV for B picture 
void FindPMV_B(MotionVector *MV[6][MBR+1][MBC+2], int x, int y,  
             int *pmv0, int *pmv1, int newgob, int half_pel,int BACKWARD); 
 
//! the sturcture of VLC table 
typedef struct 
{ 
	unsigned int cdwd;  //!< codeword get from h.263draft 
	unsigned int len;   //!< length of codeword 
 
}vlcstr; 
//VLC CODEWORD TABLE 
 
//generating index : MB type == 3, index = 0 | cbpc; 
//                   MB type == 4, index = 1 | cbpc; 
//                   last stuffing's index = 0x08; 
//! MCPBC table for I frame 
static vlcstr mcbpctabI[9] = 
{ 
	{1, 1}, {1, 3}, {2, 3}, {3, 3}, {1, 4},  
	{1, 6}, {2, 6}, {3, 6}, {1, 9} 
}; 
 
//generating index : mmmcc: MB type(3 bits) CBPC (2 bit) 
//                   last stuffing's index =20 
//! MCPBC table for P frame  
static vlcstr mcbpctabP[21] = 
{ 
	{1, 1}, {3, 4}, {2, 4}, {5, 6}, 
	{3, 3}, {7, 7}, {6, 7}, {5, 9}, 
	{2, 3}, {5, 7}, {4, 7}, {5, 8}, 
	{3, 5}, {4, 8}, {3, 8}, {3, 7}, 
	{4, 6}, {4, 9}, {3, 9}, {2, 9}, 
	{1, 9} 
}; 
 
//! MBTYPE table for B picture 
static vlcstr mbtypetab[14] = 
{ 
	{3, 2}, {1, 4}, 
	{4, 3}, {5, 3}, {6, 5}, 
	{2, 3}, {3, 3}, {7, 5}, 
	{4, 5}, {5, 5}, {1, 5}, 
	{1, 6}, {1, 7}, 
	{1, 9} 
}; 
 
//! CBPC table(only for B picture) 
static vlcstr cbpctab[4] = 
{ 
	{0, 1}, {2, 2}, {7, 3}, {6, 3} 
}; 
//generating index : INTRA index = CBPY 
//                   INTER index = CBPY XOR 0x0f  ,not last four bits of cbpy 
//! CBPY table 
static vlcstr cbpytab[16] = 
{ 
	{3, 4}, {5, 5}, {4, 5}, {9, 4}, 
	{3, 5}, {7, 4}, {2, 6}, {11, 4}, 
	{2, 5}, {3, 6}, {5, 4}, {10, 4}, 
	{4, 4}, {8, 4}, {6, 4}, {3, 2} 
}; 
 
//MV table, the length is 1 less than that in the table 11 except vector difference = 0 
/* Motion vectors */ 
//! MV table 
static vlcstr mvtab[33] = 
{ 
	{1,1}, {1,2}, {1,3}, {1,4}, {3,6}, {5,7}, {4,7}, {3,7}, 
	{11,9}, {10,9}, {9,9}, {17,10}, {16,10}, {15,10}, {14,10}, {13,10}, 
	{12,10}, {11,10}, {10,10}, {9,10}, {8,10}, {7,10}, {6,10}, {5,10}, 
	{4,10}, {7,11}, {6,11}, {5,11}, {4,11}, {3,11}, {2,11}, {3,12}, 
	{2,12} 
}; 
 
//! COEFF table0 
/*! first part of coeffs for last = 0. Indexed by [run][level-1] */ 
static vlcstr coeff_tab0[2][12] = 
{ 
  /* run = 0 */ 
  { 
    {0x02, 2}, {0x0f, 4}, {0x15, 6}, {0x17, 7}, 
    {0x1f, 8}, {0x25, 9}, {0x24, 9}, {0x21,10}, 
    {0x20,10}, {0x07,11}, {0x06,11}, {0x20,11} 
  }, 
  /* run = 1 */ 
  { 
    {0x06, 3}, {0x14, 6}, {0x1e, 8}, {0x0f,10}, 
    {0x21,11}, {0x50,12}, {0x00, 0}, {0x00, 0}, 
    {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  } 
}; 
 
//! COEFF table1 
/*! rest of coeffs for last = 0. indexing by [run-2][level-1] */ 
static vlcstr coeff_tab1[25][4] = 
{ 
  /* run = 2 */ 
  { 
    {0x0e, 4}, {0x1d, 8}, {0x0e,10}, {0x51,12} 
  }, 
  /* run = 3 */ 
  { 
    {0x0d, 5}, {0x23, 9}, {0x0d,10}, {0x00, 0} 
  }, 
  /* run = 4-26 */ 
  { 
    {0x0c, 5}, {0x22, 9}, {0x52,12}, {0x00, 0} 
  }, 
  { 
    {0x0b, 5}, {0x0c,10}, {0x53,12}, {0x00, 0} 
  }, 
  { 
    {0x13, 6}, {0x0b,10}, {0x54,12}, {0x00, 0} 
  }, 
  { 
    {0x12, 6}, {0x0a,10}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x11, 6}, {0x09,10}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x10, 6}, {0x08,10}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x16, 7}, {0x55,12}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x15, 7}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x14, 7}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x1c, 8}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x1b, 8}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x21, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x20, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x1f, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x1e, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x1d, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x1c, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x1b, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x1a, 9}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x22,11}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x23,11}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x56,12}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  }, 
  { 
    {0x57,12}, {0x00, 0}, {0x00, 0}, {0x00, 0} 
  } 
}; 
 
//! COEFF table2 
/*! first coeffs of last = 1. indexing by [run][level-1] */ 
static vlcstr coeff_tab2[2][3] = 
{ 
  /* run = 0 */ 
  { 
    {0x07, 4}, {0x19, 9}, {0x05,11} 
  }, 
  /* run = 1 */ 
  { 
    {0x0f, 6}, {0x04,11}, {0x00, 0} 
  } 
}; 
 
//! COEFF table3 
/*! rest of coeffs for last = 1. indexing by [run-2] */ 
static vlcstr coeff_tab3[40] = 
{ 
  {0x0e, 6}, {0x0d, 6}, {0x0c, 6}, 
  {0x13, 7}, {0x12, 7}, {0x11, 7}, {0x10, 7}, 
  {0x1a, 8}, {0x19, 8}, {0x18, 8}, {0x17, 8}, 
  {0x16, 8}, {0x15, 8}, {0x14, 8}, {0x13, 8}, 
  {0x18, 9}, {0x17, 9}, {0x16, 9}, {0x15, 9},     
  {0x14, 9}, {0x13, 9}, {0x12, 9}, {0x11, 9},     
  {0x07,10}, {0x06,10}, {0x05,10}, {0x04,10},     
  {0x24,11}, {0x25,11}, {0x26,11}, {0x27,11},     
  {0x58,12}, {0x59,12}, {0x5a,12}, {0x5b,12},     
  {0x5c,12}, {0x5d,12}, {0x5e,12}, {0x5f,12}, 
  {0x00, 0}                
}; 
 
/* Local funtions */ 
int vlcmcbpcI (int CBP, int mode); 
int vlcmcbpcP(int CBP, int mode); 
int vlccbpy (int CBP, int mode); 
int vlcmv (int dmv); 
int CodeCoeff(int intra, short *qcoeff, int block, int ncoeffs); 
int put_coeff (int run, int level, int last); 
 
/*! 
******************************************************************************* 
* 
*   Name:          EncPicHdr  
*   Description:   Encode picture header and send bits to stream  
*   Input:         Encoder status structure  
*   Output:        
*   Return:        The number of bits  
*   Side effect:   Write bits to global stream structure putstrmctrl  
*   Last modified: 2002/12/5 
* 
*******************************************************************************/ 
int EncPicHdr(H263VencStatus *encoder) 
{ 
	int bits = 0; 
	int QUANT = encoder->total_Q; 
 
	/*! PSC(Picture Start Code) */ 
	putbits(1, 17); 
	bits += 17; 
	putbits(0, 5); 
	bits += 5; 
 
	/*! TR(Temporal Reference) */ 
	putbits(encoder->TR, 8); 
	bits += 8; 
 
	/*! PTYPE(Type Information) */ 
	putbits(1, 1);  //!< always '1', in order to avoid code emulation 
	putbits(0, 1);  //!< always '0', for distinction with H.261 
	putbits(0, 1);  //!< spilt screen indicator, set off currently 
	putbits(0, 1);  //!< document camera indicator, set off currently 
	putbits(0, 1);  //!< freeze picture release, set off currently 
	putbits(encoder->sourceFormat, 3); 
	putbits(encoder->PTYPE, 1); 
	putbits(0, 1);  //!< optional unrestricted motion vector mode, set off currently 
	putbits(0, 1);  //!< optional syntax-based arithmetic coding mode, set off currently 
	putbits(encoder->annex.Advanced_Prediction ? 1 : 0, 1);   
	putbits(0, 1);  //!< optional pb-frame mode, set off currently 
	bits += 13; 
 
	/*! PQUANT(Quantizer Information) */ 
	putbits(QUANT, 5); 
	bits += 5; 
 
	/*! CPM(Continuous Presence Multipoint) */ 
	putbits(0, 1); 
	bits ++; 
 
	/*! PEI(Extra Insertion Information) */ 
	putbits(0, 1); 
	bits ++; 
 
	return bits; 
 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          EncPicHdrPlus  
*   Description:   Encode picture header and send bits to stream(for h263+)  
*   Input:         Encoder status structure  
*   Output:        
*   Return:        The number of bits  
*   Side effect:   Write bits to global stream structure putstrmctrl  
*   Last modified: 2002/12/27 
* 
*******************************************************************************/ 
int EncPicHdrPlus(H263VencStatus *encoder) 
{ 
	int bits = 0; 
	int UFEP = 1; 
	int QUANT = encoder->total_Q; 
 
	/*! PSC(Picture Start Code) */ 
	putbits(1, 17); 
	bits += 17; 
	putbits(0, 5); 
	bits += 5; 
 
	/*! TR(Temporal Reference) */ 
	if (B_IMG == encoder->PTYPE) 
	{ 
		putbits(encoder->TRB, 8); 
	} 
	else 
	{ 
		putbits(encoder->TR, 8); 
	} 
	bits += 8; 
 
	/*! PTYPE(Type Information) */ 
	putbits(1, 1);  //!< always '1', in order to avoid code emulation 
	putbits(0, 1);  //!< always '0', for distinction with H.261 
	putbits(0, 1);  //!< spilt screen indicator, set off currently 
	putbits(0, 1);  //!< document camera indicator, set off currently 
	putbits(0, 1);  //!< freeze picture release, set off currently 
	putbits(7, 3);  //!< indicating PLUSPTYPE will be added 
	bits += 8; 
 
	/*! PLUSPTYPE */ 
	putbits(UFEP, 3); //!< update full extended PTYPE when UFEP is set to zero 
	bits += 3; 
	if (UFEP) 
	{ 
		putbits(encoder->sourceFormat, 3);  
		putbits(0, 1);    //!< optional custum PCF, set off currently 
		putbits(0, 1);    //!< optional unrestricted motion vector mode, set off currently 
		putbits(0, 1);    //!< optional syntax-based arithmetic coding mode, set off currently 
		putbits(encoder->annex.Advanced_Prediction ? 1 : 0, 1); 
		putbits(0, 1);    //!< optional advanced INTRA coding mode, set off currently 
		putbits(encoder->annex.Deblocking_Filter ? 1 : 0, 1);    
		putbits(0, 1);    //!< optional slice structure mode, set off currently 
		putbits(encoder->annex.RPS ? 1 : 0, 1);     
		putbits(0, 1);    //!< optional independent segment decoding mode, set off currently 
		putbits(0, 1);    //!< optional alternative INTER VLC mode, set off currently 
		putbits(0, 1);    //!< optional modified quantization mode, set off currently 
		putbits(1, 1);    //!< equal to "1" to prevent start code emulation 
		putbits(0, 1);    //!< reserved 
		putbits(0, 1);    //!< reserved 
		putbits(0, 1);    //!< reserved 
		bits += 18; 
	} 
	putbits(encoder->PTYPE, 3); 
	putbits(0, 1);     //!< optional reference picture resampling mode, set off currently 
	putbits(0, 1);     //!< optional reduced-resolution update mode, set off currently 
	putbits(0, 1);     //!< rounding type, equal to "0" currently 
	putbits(0, 1);     //!< reserved 
	putbits(0, 1);     //!< reserved 
	putbits(1, 1);     //!< equal to "1" to prevent start code emulation 
	bits += 9; 
 
	/*! CPM(Continuous Presence Multipoint) */ 
	putbits(0, 1); 
	bits++; 
 
	/*! PLUSPTYPE related information 
	It would be added according to successive changes of encoder in future */ 
	//! B picture related information 
	if (encoder->PTYPE == B_IMG) 
	{ 
		putbits(1, 4);      //!< Enhanced Layer Number. equal to '0001' now 
		bits += 4; 
		if (UFEP) 
		{ 
			putbits(1, 4);  //!< Reference Layer Number. equal to '0001' now 
			bits += 4; 
		} 
	} 
	if (encoder->annex.RPS) 
	{ 
		int trp = encoder->TRP[encoder->ref_index]; 
		 
		if (trp < 0) 
		{ 
			trp += 256; 
		} 
		if (UFEP) 
		{ 
			putbits(4, 3);  //! Reference Picture Selection Mode Flags. equal to '100' now 
			bits += 3; 
		} 
		if (encoder->PTYPE == INTRA) 
		{ 
			putbits(0, 1);  //! Temporal reference for prediction indication 
			bits++; 
		} 
		else 
		{ 
			putbits(1, 1);  //! Temporal reference for prediction indication.  
			bits++; 
			putbits(trp, 10);  //! Temporal Reference for Prediction. 
			bits += 10; 
		} 
		putbits(1, 2);  //! Back-Channel message indication. 
		bits += 2; 
	} 
 
	/*! PQUANT(Quantizer Information) */ 
	putbits(QUANT, 5); 
	bits += 5; 
 
	/*! PEI(Extra Insertion Information) */ 
	putbits(0, 1); 
	bits ++; 
 
	return bits; 
 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:           
*   Description:    
*   Input:          
*   Output:         
*   Last modified:  
* 
*******************************************************************************/ 
int EncGOBHdr(int gob_nbr, int gob_fid, int gob_quant, int gob_tr, int gob_trp) 
{ 
	int bits = 0; 
	int rps_flag = 0; 
	 
	bits += alignbits();        //< GSTUF 
	putbits(1, 17);             //< GBSC 
	bits += 17; 
	putbits(gob_nbr, 5);        //< GN   
	bits += 5; 
	putbits(gob_fid, 2);        //< GFID 
	bits +=2; 
	putbits(gob_quant, 5);      //< GQUANT 
	bits += 5; 
 
	if(rps_flag) 
	{ 
		putbits(1, 1);             //< TRI 
		bits++; 
		putbits(gob_tr, 8);        //< TR 
		bits += 8; 
		if (gob_trp) 
		{ 
			putbits(1, 1);         //< TRPI 
			bits++; 
			putbits(gob_trp, 8);   //< TRP 
			bits += 8; 
		} 
		else 
		{ 
			putbits(0, 1);         //< TRPI 
			bits++; 
		} 
		putbits(0, 1);             //< BCI 
		bits++; 
	} 
 
	return bits; 
} 
/*! 
******************************************************************************* 
* 
*   Name:          EncMBHdr 
*   Description:   Encode MB header and send bits to stream 
*   Input:         Picture type, MB mode, cod, cbp and dquant 
*   Output:         
*   Return:        The number of bits  
*   Side effect:   Write bits to global stream structure putstrmctrl  
*   Last modified: 2002/12/5 
* 
*******************************************************************************/ 
int EncMBHdr(int p_type, int mode, int cod, int cbp, int dquant) 
{ 
	int bits = 0; 
     
	/* COD(Coded macroblock indication) */ 
	if (p_type == INTER) 
	{ 
		putbits(cod, 1); 
		bits++; 
	} 
	if (cod) 
	{ 
		return bits; 
	} 
 
	/* MCBPC(Macroblock type & Code block pattern for chrominance) */ 
	if (p_type == INTRA) 
	{ 
		bits += vlcmcbpcI(cbp, mode); 
	} 
    else  
	{ 
		bits += vlcmcbpcP(cbp, mode); 
	} 
	 
	/* CBPY(Coded block pattern for luminance) */ 
    bits += vlccbpy(cbp, mode); 
 
	/* DQUANT(Quantizer Information) */ 
	if (mode == MODE_INTRA_Q || mode ==MODE_INTER_Q) 
	{ 
		switch(dquant) 
		{ 
		case -1: 
			putbits(0, 2); 
			break; 
		case -2: 
			putbits(1, 2); 
			break; 
		case  1: 
			putbits(2, 2); 
			break; 
		case  2: 
			putbits(3, 2); 
			break; 
		default: 
			printf("error dquant!"); 
			exit(-1); 
		} 
		bits += 2; 
	} 
	return bits; 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          EncMBHdr_B 
*   Description:   Encode MB header for B picture and send bits to stream 
*   Input:         mb_type, cbp and dequant 
*   Output:         
*   Return:        The number of bits  
*   Side effect:   Write bits to global stream structure putstrmctrl  
*   Last modified: 2002/1/13 
* 
*******************************************************************************/ 
int EncMBHdr_B(int mb_type, int cbp, int dquant) 
{ 
	int bits = 0; 
	int cbpc = cbp&3; 
	int cbpy = (cbp&60)>>2; 
 
	if ((mb_type != 11) && (mb_type != 12)) 
	{ 
		cbpy = cbpy ^ 15;           //!< intra 
	} 
 
	/* COD(coded macroblock indication */ 
	if (-1 == mb_type) 
	{ 
		putbits(1, 1); 
		return 1; 
	} 
	else 
	{ 
		putbits(0, 1); 
	} 
	bits++; 
 
	/* MBTYPE */ 
	putbits(mbtypetab[mb_type].cdwd, mbtypetab[mb_type].len); 
	bits += mbtypetab[mb_type].len; 
 
	/* CBPC, CBPY and DQUANT */ 
	if ((mb_type == 2) || (mb_type == 5) || (mb_type == 8)) 
	{ 
		return bits; 
	} 
	else 
	{ 
		putbits(cbpctab[cbpc].cdwd, cbpctab[cbpc].len); 
		bits += cbpctab[cbpc].len; 
		putbits(cbpytab[cbpy].cdwd, cbpytab[cbpy].len); 
		bits += cbpytab[cbpy].len; 
		if ((mb_type == 0) || (mb_type == 3) || (mb_type == 6) || (mb_type == 9) || (mb_type == 11)) 
		{ 
			return bits; 
		} 
		else 
		{ 
			switch(dquant) 
			{ 
			case -1: 
				putbits(0, 2); 
				break; 
			case -2: 
				putbits(1, 2); 
				break; 
			case  1: 
				putbits(2, 2); 
				break; 
			case  2: 
				putbits(3, 2); 
				break; 
			default: 
				printf("error dquant!"); 
				exit(-1); 
			} 
			bits += 2; 
		} 
	} 
	return bits; 
}  
 
/*! 
******************************************************************************* 
* 
*   Name:          EncMVD 
*   Description:   Encode MV data and send bits to stream 
*   Input:         MCParam structure, the position and mode of current MB, gob identification  
*   Output:         
*   Return:        The number of bits  
*   Side effect:   Write bits to global stream structure putstrmctrl  
*   Last modified: 2002/12/5 
* 
*******************************************************************************/ 
int EncMVD(MCParam *MC, int x, int y, int mode, int newgob) 
{ 
	int bits = 0; 
	int dmvx; 
	int dmvy; 
	int block; 
	 
	if ((mode == MODE_INTER4V) || (mode == MODE_INTER4V_Q)) 
	{ 
		for (block = 1; block < 5; block++) 
		{ 
			FindPMV(MC->mv_frame, x+1, y+1, &dmvx, &dmvy, block, newgob, 1); 
			dmvx = (MC->mv_frame[block][y+1][x+1])->x*2 + (MC->mv_frame[block][y+1][x+1])->x_half - dmvx; 
			dmvy = (MC->mv_frame[block][y+1][x+1])->y*2 + (MC->mv_frame[block][y+1][x+1])->y_half - dmvy; 
			bits += vlcmv(dmvx); 
			bits += vlcmv(dmvy); 
		} 
	} 
	else 
	{ 
		FindPMV(MC->mv_frame, x+1, y+1, &dmvx, &dmvy, 0, newgob, 1); 
		dmvx = (MC->mv_frame[0][y+1][x+1])->x*2 + (MC->mv_frame[0][y+1][x+1])->x_half - dmvx; 
		dmvy = (MC->mv_frame[0][y+1][x+1])->y*2 + (MC->mv_frame[0][y+1][x+1])->y_half - dmvy; 
		bits += vlcmv(dmvx); 
		bits += vlcmv(dmvy); 
	} 
 
	return bits; 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          EncMVD_B 
*   Description:   Encode MV data for B picture and send bits to stream 
*   Input:         MCParam structure, the position and mode of current MB, gob identification  
*   Output:         
*   Return:        The number of bits  
*   Side effect:   Write bits to global stream structure putstrmctrl  
*   Last modified: 2002/1/13 
* 
*******************************************************************************/ 
int EncMVD_B(MCParam *MC, int x, int y, int mode, int newgob) 
{ 
	int bits = 0; 
	int dmvx, dmvy; 
 
	if (B_DIRECT == mode) 
	{ 
		return 0; 
	} 
	if ((B_FORWARD == mode) || (B_BIDIRECTIONAL == mode)) 
	{ 
		FindPMV_B(MC->mv_frame, x+1, y+1, &dmvx, &dmvy, newgob, 1, 0); 
		dmvx = (MC->mv_frame[0][y+1][x+1])->x*2 + (MC->mv_frame[0][y+1][x+1])->x_half - dmvx; 
		dmvy = (MC->mv_frame[0][y+1][x+1])->y*2 + (MC->mv_frame[0][y+1][x+1])->y_half - dmvy; 
		bits += vlcmv(dmvx); 
		bits += vlcmv(dmvy); 
	} 
	if ((B_BACKWARD == mode) || (B_BIDIRECTIONAL == mode)) 
	{ 
		FindPMV_B(MC->mv_frame, x+1, y+1, &dmvx, &dmvy, newgob, 1, 1); 
		dmvx = (MC->mv_frame[5][y+1][x+1])->x*2 + (MC->mv_frame[5][y+1][x+1])->x_half - dmvx; 
		dmvy = (MC->mv_frame[5][y+1][x+1])->y*2 + (MC->mv_frame[5][y+1][x+1])->y_half - dmvy; 
		bits += vlcmv(dmvx); 
		bits += vlcmv(dmvy); 
	} 
	 
	return bits; 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          EncCoeff 
*   Description:   Encode transform coefficients and send bits to stream 
*   Input:         MB mode, cbp value, address of transform coefficients,  
*                  number of coefficients to be coded 
*   Output:         
*   Return:        The number of bits  
*   Side effect:   Write bits to global stream structure putstrmctrl  
*   Last modified: 2002/12/5 
* 
*******************************************************************************/ 
int EncCoeff(int intra, int CBP, short *qcoeff, int ncoeffs) 
{ 
	int bits = 0; 
    int i; 
	 
    if (intra)  
	{ 
		for (i = 0; i < 6; i++)  
		{ 
			bits += CodeCoeff(intra, qcoeff, i, ncoeffs); 
		} 
	} 
	else  
	{ 
		for (i = 0; i < 6; i++)  
		{ 
			if ((i==0 && CBP&32) ||  
				(i==1 && CBP&16) || 
				(i==2 && CBP&8) ||  
				(i==3 && CBP&4) || 
				(i==4 && CBP&2) || 
				(i==5 && CBP&1))  
			{ 
				bits += CodeCoeff(intra, qcoeff, i, ncoeffs); 
			} 
		} 
	} 
	return bits; 
} 
 
//Name    : vlcmcbpcI; 
//Input   : CBP & mode of a MB, CBP & mode; 
//Output  : number of bits put into bitstream; 
//Discription : this function is for INTRA MB 
//              usage: vlcstr * cbpcI = vlcmcbpcI (CBP, mode); 
int vlcmcbpcI (int CBP, int mode) 
{ 
	int CBPC = CBP & 3; 
	int index = (mode == MODE_INTRA) ?  CBPC : (CBPC & 4); 
	if ((index <8) && (index >= 0)) 
	{ 
		putbits (mcbpctabI[index].cdwd, mcbpctabI[index].len); 
		return mcbpctabI[index].len; 
	} 
	else                  //!< ??should be considered carefully later 
	{ 
		putbits (mcbpctabI[8].cdwd, mcbpctabI[8].len); 
		return mcbpctabI[8].len; 
	} 
} 
 
//Name    : vlcmcbpcP; 
//Input   : CBP & mode of a MB, CBP & mode; 
//Output  : number of bits put into bitstream; 
//Discription : this function is for INTER MB 
//              usage: vlcstr * cbpcI = vlcmcbpcI (CBP, mode); 
int vlcmcbpcP(int CBP, int mode) 
{ 
	int CBPC = CBP & 3; 
	int index = CBPC | (mode << 2); 
	if ((index < 20) && (index >= 0)) 
	{ 
		putbits (mcbpctabP[index].cdwd, mcbpctabP[index].len); 
		return mcbpctabP[index].len; 
	} 
	else                 //!<  ??should be considered carefully later 
	{ 
		putbits (mcbpctabP[20].cdwd, mcbpctabP[20].len); 
		return mcbpctabP[20].len; 
	} 
} 
 
//Name    : vlccbpy; 
//Input   : CBP & mode of a MB, CBP & mode; 
//Output  : a vlcstr type pointer, pointing to the position in cbpytab, which is determined 
//          by CBPY & mode; 
//Discription :  
//              usage: vlcstr * cbpcI = vlcmcbpcI (CBP, mode); 
int vlccbpy (int CBP, int mode) 
{ 
	int CBPY = CBP >> 2; 
	int index = (mode == MODE_INTRA)||(mode == MODE_INTRA_Q) ? CBPY : CBPY ^ 15; 
 
	putbits (cbpytab [index].cdwd, cbpytab[index].len); 
	return cbpytab[index].len; 
} 
 
//Name    : vlcmv; 
//Input   : difference of mv and pmv 
//Output  : number of bits of vlc-encoded mv 
//Discription : put vlc-codeword of mv into bitstream. for mv should return two parameter 
//              vlcstr, and sign, this function will put bits into bitstream to avoid return 
//              so many parameters; 
int vlcmv (int dmv) 
{ 
	int index,sign = 0; 
	if(dmv) 
	{ 
		if (dmv >= 0) 
		{ 
			if (dmv < 32) 
				index = dmv; 
			else if (dmv <= 63) 
			{ 
				index = 64 - dmv; 
				sign = 1; 
			} 
			else 
			{ 
				printf ("ERROR HAPPENED IN VLC-ENCODE OF MV! MV>63.\n"); 
				exit (0); 
			} 
		} 
		else 
		{ 
			if (dmv >= -32) 
			{ 
				index = -dmv; 
				sign = 1; 
			} 
			else if (dmv >= -63) 
				index = 64 + dmv; 
			else 
			{ 
				printf ("ERROR HAPPENED IN VLC-ENCODE OF MV! MV<-63.\n"); 
				exit (0); 
			} 
		} 
		/* 
		if (dmv >= 0 && dmv <= 32) 
		index = dmv; 
		else if (dmv < 0 && dmv >= -32) 
		{ 
		index = -dmv; 
		sign = 1; 
		} 
		else if (dmv < -32 && dmv >= -63) 
		index = 64 + dmv; 
		else if (dmv > 32 && dmv <= 63) 
		{ 
		index = 64 - dmv; 
		sign = 1; 
		} 
		else 
		{ 
		printf ("ERROR HAPPENED WHEN VLCMV.\n"); 
		exit (0); 
		} 
		*/ 
		putbits (mvtab[index].cdwd, mvtab[index].len); 
		putbits (sign, 1); 
		return mvtab[index].len + 1; 
	} 
	else 
	{ 
		putbits (1,1); 
		return 1; 
		 
	} 
	 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:           
*   Description:    
*   Input:          
*   Output:         
*   Last modified:  
* 
*******************************************************************************/ 
int CodeCoeff(int intra, short *qcoeff, int block, int ncoeffs) 
{ 
    int j, bits; 
    int prev_run, run, prev_level, level, first; 
    int prev_s, s, length; 
	 
    run = bits = 0; 
    first = 1; 
    prev_run = prev_level = level = s = prev_s = 0; 
	 
	for (j = block*ncoeffs; j< (block + 1)*ncoeffs; j++) 
	{ 
		/* Do this block's DC-coefficient first */ 
		if (!(j%ncoeffs) && intra) 
		{ 
			/* DC coeff */ 
			 
			if (qcoeff[block*ncoeffs] != 128) 
				putbits(qcoeff[block*ncoeffs], 8); 
			else 
				putbits(255, 8); 
			bits += 8; 
		} 
		else { 
			/* AC coeff */ 
			s = 0; 
			/* Increment run if coeff is zero */ 
			if ((level = qcoeff[j]) == 0)  
			{ 
				run++; 
			} 
			else  
			{ 
				/* code run & level and count bits */ 
				if (level < 0)  
				{ 
					s = 1; 
					level = -level; 
				} 
				if (!first)  
				{ 
					/* Encode the previous coefficient */ 
					if (prev_level  < 13 && prev_run < 64) 
						length = put_coeff (prev_run, prev_level, 0);   
					else 
						length = 0; 
					if (length == 0) 
					{  /* Escape coding */ 
						if (prev_s == 1) 
						{ 
							prev_level = (prev_level^0xff)+1; 
						} 
						putbits(3, 7);	/* Escape code */ 
						putbits(0, 1); 
						putbits(prev_run, 6); 
						putbits(prev_level, 8); 
						bits += 22; 
					} 
					else 
					{ 
						putbits(prev_s, 1); 
						bits += length + 1; 
					} 
				} 
				prev_run = run; prev_s = s; 
				prev_level = level;  
				run = first = 0; 
			} 
		} 
	} 
	/* Encode the last coeff */ 
	if (!first)  
	{ 
 
		if (prev_level  < 13 && prev_run < 64)  
			length = put_coeff (prev_run, prev_level, 1);    
		else 
			length = 0; 
		if (length == 0)  
		{  /* Escape coding */ 
			if (prev_s == 1)  
			{ 
				prev_level = (prev_level^0xff)+1; 
			} 
			putbits (3, 7);	/* Escape code */ 
			putbits(1, 1); 
			putbits(prev_run, 6); 
			putbits(prev_level, 8); 
			bits += 22; 
		} 
		else { 
			putbits(prev_s, 1); 
			bits += length + 1; 
		} 
	} 
	return bits; 
} 
/*! 
******************************************************************************* 
* 
*   Name:           
*   Description:    
*   Input:          
*   Output:         
*   Last modified:  
* 
*******************************************************************************/ 
int put_coeff (int run, int level, int last) 
{ 
	int length = 0; 
	 
	assert (last >= 0 && last < 2); 
	assert (run >= 0 && run < 64); 
	assert (level > 0 && level < 128); 
	 
	if (last == 0)  
	{ 
		if (run < 2 && level < 13 )  
		{ 
			putbits (coeff_tab0[run][level-1].cdwd, coeff_tab0[run][level-1].len);			 
			length = coeff_tab0[run][level-1].len; 
		} 
		else if (run > 1 && run < 27 && level < 5)  
		{ 
			putbits (coeff_tab1[run-2][level-1].cdwd, coeff_tab1[run-2][level-1].len); 
			length = coeff_tab1[run-2][level-1].len; 
		} 
	} 
	else if (last == 1)  
	{ 
		if (run < 2 && level < 4)  
		{ 
			putbits (coeff_tab2[run][level-1].cdwd, coeff_tab2[run][level-1].len); 
			length = coeff_tab2[run][level-1].len; 
		} 
		else if (run > 1 && run < 42 && level == 1)  
		{ 
			putbits (coeff_tab3[run-2].cdwd, coeff_tab3[run-2].len);			 
			length = coeff_tab3[run-2].len; 
		} 
	} 
	return length; 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          FindPMV 
*   Description:   find predictor for mv of current block 
*   Input:         Array of motion vectors, positon of current block 
*   Output:        x value and y value of predictor 
*   Last modified: 2002/11/23 by lcl 
* 
*******************************************************************************/ 
void FindPMV(MotionVector *MV[6][MBR+1][MBC+2], int x, int y,  
             int *pmv0, int *pmv1, int block, int newgob, int half_pel) 
{ 
	int p1,p2,p3; 
	int xin1,xin2,xin3; 
	int yin1,yin2,yin3; 
	int vec1,vec2,vec3; 
	int l8,o8,or8; 
	 
	 
	l8 = o8 = or8 = 0; 
	if ((MV[0][y][x-1]->Mode == MODE_INTER4V) || (MV[0][y][x-1]->Mode == MODE_INTER4V_Q)) 
	{ 
		l8 = 1; 
	} 
	 
	if ((MV[0][y-1][x]->Mode == MODE_INTER4V) || (MV[0][y-1][x]->Mode == MODE_INTER4V_Q)) 
	{ 
		o8 = 1; 
	} 
	 
	if ((MV[0][y-1][x+1]->Mode == MODE_INTER4V || MV[0][y-1][x+1]->Mode == MODE_INTER4V_Q)) 
	{ 
		or8 = 1; 
	} 
	 
	 
	switch (block)  
	{ 
	case 0:  
		vec1 = (l8 ? 2 : 0) ; yin1 = y  ; xin1 = x-1; 
		vec2 = (o8 ? 3 : 0) ; yin2 = y-1; xin2 = x; 
		vec3 = (or8? 3 : 0) ; yin3 = y-1; xin3 = x+1; 
		break; 
	case 1: 
		vec1 = (l8 ? 2 : 0) ; yin1 = y  ; xin1 = x-1; 
		vec2 = (o8 ? 3 : 0) ; yin2 = y-1; xin2 = x; 
		vec3 = (or8? 3 : 0) ; yin3 = y-1; xin3 = x+1; 
		break; 
	case 2: 
		vec1 = 1            ; yin1 = y  ; xin1 = x; 
		vec2 = (o8 ? 4 : 0) ; yin2 = y-1; xin2 = x; 
		vec3 = (or8? 3 : 0) ; yin3 = y-1; xin3 = x+1; 
		break; 
	case 3: 
		vec1 = (l8 ? 4 : 0) ; yin1 = y  ; xin1 = x-1; 
		vec2 = 1            ; yin2 = y  ; xin2 = x; 
		vec3 = 2            ; yin3 = y  ; xin3 = x; 
		break; 
	case 4: 
		vec1 = 3            ; yin1 = y  ; xin1 = x; 
		vec2 = 1            ; yin2 = y  ; xin2 = x; 
		vec3 = 2            ; yin3 = y  ; xin3 = x; 
		break; 
	default: 
		fprintf(stderr,"Illegal block number in FindPMV (countbit.c)\n"); 
		exit(-1); 
		break; 
	} 
	if (half_pel) 
	{ 
		p1 = 2*MV[vec1][yin1][xin1]->x + MV[vec1][yin1][xin1]->x_half; 
		p2 = 2*MV[vec2][yin2][xin2]->x + MV[vec2][yin2][xin2]->x_half; 
		p3 = 2*MV[vec3][yin3][xin3]->x + MV[vec3][yin3][xin3]->x_half; 
	} 
	else  
	{ 
		p1 = 2*MV[vec1][yin1][xin1]->x; 
		p2 = 2*MV[vec2][yin2][xin2]->x; 
		p3 = 2*MV[vec3][yin3][xin3]->x; 
	} 
	if (newgob && (block == 0 || block == 1 || block == 2)) 
	{ 
		p2 = 2 * NO_VEC;   //!< MV above can not be accessed  
	} 
	if (p2 == 2*NO_VEC) 
	{ 
		p2 = p3 = p1;      //!< When MV above can not be accessed, use left MV instead  
	} 
	 
	*pmv0 = p1+p2+p3 - mmax(p1,mmax(p2,p3)) - mmin(p1,mmin(p2,p3)); 
     
	if (half_pel)  
	{ 
		p1 = 2*MV[vec1][yin1][xin1]->y + MV[vec1][yin1][xin1]->y_half; 
		p2 = 2*MV[vec2][yin2][xin2]->y + MV[vec2][yin2][xin2]->y_half; 
		p3 = 2*MV[vec3][yin3][xin3]->y + MV[vec3][yin3][xin3]->y_half; 
	} 
	else  
	{ 
		p1 = 2*MV[vec1][yin1][xin1]->y; 
		p2 = 2*MV[vec2][yin2][xin2]->y; 
		p3 = 2*MV[vec3][yin3][xin3]->y; 
	}     
	if (newgob && (block == 0 || block == 1 || block == 2)) 
	{ 
		p2 = 2 * NO_VEC;   //!< MV above can not be accessed  
	} 
	if (p2 == 2*NO_VEC) 
	{ 
		p2 = p3 = p1;      //!< When MV above can not be accessed, use left MV instead  
	} 
	 
	*pmv1 = p1+p2+p3 - mmax(p1,mmax(p2,p3)) - mmin(p1,mmin(p2,p3)); 
	 
} 
/*! 
******************************************************************************* 
* 
*   Name:          FindPMV_B 
*   Description:   find predictor for mv of current block for B picture 
*   Input:         Array of motion vectors, positon of current block 
*   Output:        x value and y value of predictor 
*   Last modified: 2003/1/13 by lcl 
* 
*******************************************************************************/ 
void FindPMV_B(MotionVector *MV[6][MBR+1][MBC+2], int x, int y,  
             int *pmv0, int *pmv1, int newgob, int half_pel, int BACKWARD) 
{ 
	int vec = BACKWARD ? 5 : 0; 
	int yin1 = y;  
	int xin1 = x-1; 
	int yin2 = y-1;  
	int xin2 = x; 
	int yin3 = y-1;  
	int xin3 = x+1; 
	int p1, p2, p3; 
 
	 
	if (half_pel) 
	{ 
		p1 = 2*MV[vec][yin1][xin1]->x + MV[vec][yin1][xin1]->x_half; 
		p2 = 2*MV[vec][yin2][xin2]->x + MV[vec][yin2][xin2]->x_half; 
		p3 = 2*MV[vec][yin3][xin3]->x + MV[vec][yin3][xin3]->x_half; 
	} 
	else  
	{ 
		p1 = 2*MV[vec][yin1][xin1]->x; 
		p2 = 2*MV[vec][yin2][xin2]->x; 
		p3 = 2*MV[vec][yin3][xin3]->x; 
	} 
	if (newgob) 
	{ 
		p2 = 2 * NO_VEC;   //!< MV above can not be accessed  
	} 
	if (p2 == 2*NO_VEC) 
	{ 
		p2 = p3 = p1;      //!< When MV above can not be accessed, use left MV instead  
	} 
	 
	*pmv0 = p1+p2+p3 - mmax(p1,mmax(p2,p3)) - mmin(p1,mmin(p2,p3)); 
    
	if (half_pel)  
	{ 
		p1 = 2*MV[vec][yin1][xin1]->y + MV[vec][yin1][xin1]->y_half; 
		p2 = 2*MV[vec][yin2][xin2]->y + MV[vec][yin2][xin2]->y_half; 
		p3 = 2*MV[vec][yin3][xin3]->y + MV[vec][yin3][xin3]->y_half; 
	} 
	else  
	{ 
		p1 = 2*MV[vec][yin1][xin1]->y; 
		p2 = 2*MV[vec][yin2][xin2]->y; 
		p3 = 2*MV[vec][yin3][xin3]->y; 
	}     
	if (newgob) 
	{ 
		p2 = 2 * NO_VEC;   //!< MV above can not be accessed  
	} 
	if (p2 == 2*NO_VEC) 
	{ 
		p2 = p3 = p1;      //!< When MV above can not be accessed, use left MV instead  
	} 
	 
	*pmv1 = p1+p2+p3 - mmax(p1,mmax(p2,p3)) - mmin(p1,mmin(p2,p3)); 
} 
 
#ifdef  __cplusplus 
} 
#endif