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