www.gusucode.com > 一个可以在局域网进行视频聊天的源代码 > 一个可以在局域网进行视频聊天的源代码/VoIP/encoder/countbit.cpp

    ////////////////////////////////////////////////////////////////////////////
//
//
//    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    : countbit.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
 **************************************************/

 
/**********************************************************************
 *
 *	Name:		CountBitsMB
 *	Description:    counts bits used for MB info
 *	
 *	Input:	        Mode, COD, CBP, Picture and Bits structures
 *	Returns:       
 *	Side effects:
 *
 *	Date: 941129	Author: Karl.Lillevold@nta.no
 *
 ***********************************************************************/

#include "countbit.h"


void CountBitsMB(int Mode, int COD, int CBP, int CBPB, Pict *pic, Bits *bits)
{
  extern EHUFF *vlc_cbpy, *vlc_cbpcm, *vlc_cbpcm_intra;
  int cbpy, cbpcm, length;

  /* COD */
  if (Global::trace) {
    fprintf(Global::tf,"MB-nr: %d",pic->MB);
    if (pic->picture_coding_type == PCT_INTER)
      fprintf(Global::tf,"  COD: %d\n",COD);
  }
  if (pic->picture_coding_type == PCT_INTER) {
    mputv(1,COD);
    bits->COD++;
  }

  if (COD) 
    return;    /* not coded */

  /* CBPCM */
  cbpcm = Mode | ((CBP&3)<<4);


  if (Global::trace) {
    fprintf(Global::tf,"CBPCM (CBP=%d) (cbpcm=%d): ",CBP,cbpcm);
  }
  if (pic->picture_coding_type == PCT_INTRA) {
    length = Encode(cbpcm,vlc_cbpcm_intra);
  } else {
    length = Encode(cbpcm,vlc_cbpcm);
  }
  bits->CBPCM += length;

    
  /* CBPY */
  cbpy = CBP>>2;
  if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) /* Intra */
    cbpy = cbpy^15;
  if (Global::trace) {
    fprintf(Global::tf,"CBPY (CBP=%d) (cbpy=%d): ",CBP,cbpy);
  }
  length = Encode(cbpy, vlc_cbpy);
  bits->CBPY += length;
  

  return;
}


/**********************************************************************
 *
 *	Name:		CountBitsSlice
 *	Description:    couonts bits used for slice (GOB) info
 *	
 *	Input:	        slice no., quantizer
 *
 *	Date: 94????	Author: Karl.Lillevold@nta.no
 *
 ***********************************************************************/

int CountBitsSlice(int slice, int quant)
{
  int bits = 0;


  /* Picture Start Code */
  if (Global::trace)
    fprintf(Global::tf,"GOB sync (GBSC): ");
  mputv(PSC_LENGTH,PSC); /* PSC */
  bits += PSC_LENGTH;

  /* Group Number */
  if (Global::trace)
    fprintf(Global::tf,"GN: ");
  mputv(5,slice);
  bits += 5;

  /* GOB Sub Bitstream Indicator */
  /* if CPM == 1: read 2 bits GSBI */
  /* not supported in this version */

  /* GOB Frame ID */
  if (Global::trace)
    fprintf(Global::tf,"GFID: ");
  mputv(2, 0);  
  /* NB: in error-prone environments this value should change if 
     PTYPE in picture header changes. In this version of the encoder
     PTYPE only changes when PB-frames are used in the following cases:
     (i) after the first intra frame
     (ii) if the distance between two P-frames is very large 
     Therefore I haven't implemented this GFID change */
  /* GFID is not allowed to change unless PTYPE changes */
  bits += 2;

  /* Gquant */
  if (Global::trace)
    fprintf(Global::tf,"GQUANT: ");
  mputv(5,quant);
  bits += 5;

  return bits;
}


/**********************************************************************
 *
 *	Name:		CountBitsCoeff
 *	Description:	counts bits used for coeffs
 *	
 *	Input:		qcoeff, coding mode CBP, bits structure, no. of 
 *                      coeffs
 *			
 *	Returns:	struct with no. of bits used
 *	Side effects:	
 *
 *	Date: 940111	Author:	Karl.Lillevold@nta.no
 *
 ***********************************************************************/

void CountBitsCoeff(int *qcoeff, int Mode, int CBP, Bits *bits, int ncoeffs)

{
  
  int i;

  if (Mode == MODE_INTRA) {
    for (i = 0; i < 4; i++) {
      bits->Y += CodeCoeff(Mode, qcoeff,i,ncoeffs);
    }
    for (i = 4; i < 6; i++) {
      bits->C += CodeCoeff(Mode, qcoeff,i,ncoeffs);
    }
  }
  else {
    for (i = 0; i < 4; 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->Y += CodeCoeff(Mode, qcoeff, i, ncoeffs);
      }
    }
    for (i = 4; 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->C += CodeCoeff(Mode, qcoeff, i, ncoeffs);
      }
    }
  }
  return;
}
  
int CodeCoeff(int Mode, int *qcoeff, int block, int ncoeffs)
{
  int j, bits;
  int prev_run, run, prev_level, level, first;
  int prev_ind, ind, prev_s, s, length;

  extern EHUFF *vlc_3d;

  run = bits = 0;
  first = 1;
  prev_run = prev_level = prev_ind = level = s = prev_s = ind = 0;
  
  for (j = block*ncoeffs; j< (block + 1)*ncoeffs; j++) {
    /* Do this block's DC-coefficient first */
    if (!(j%ncoeffs) && (Mode == MODE_INTRA)) {
      /* DC coeff */
      if (Global::trace) {
	fprintf(Global::tf,"DC: ");
      }
      if (qcoeff[block*ncoeffs] != 128)
	mputv(8,qcoeff[block*ncoeffs]);
      else
	mputv(8,255);
      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;
	}
	ind = level | run<<4;
	ind = ind | 0<<12; /* Not last coeff */

	if (!first) {
	  /* Encode the previous ind */
	  if (prev_level  < 13 && prev_run < 64) {
	    length = Encode(prev_ind,vlc_3d);

	  } else
	    length = 0;
	  if (length == 0) {  /* Escape coding */
	    if (Global::trace) {
	      fprintf(Global::tf,"Escape coding:\n");
	    }
	    if (prev_s == 1) {prev_level = (prev_level^0xff)+1;}
	    Encode(ESCAPE,vlc_3d);
	    mputv(1,0);
	    mputv(6,prev_run);
	    mputv(8,prev_level);
	    bits += 22;
	  }
	  else {
	    mputv(1,prev_s);
	    bits += length + 1;
	  }
	}
	prev_run = run; prev_s = s;
	prev_level = level; prev_ind = ind;

	run = first = 0;
      }
    }
  }
  /* Encode the last coeff */
  if (!first) {
    if (Global::trace) {
      fprintf(Global::tf,"Last coeff: ");
    }
    prev_ind = prev_ind | 1<<12;   /* last coeff */
    if (prev_level  < 13 && prev_run < 64) { 
      length = Encode(prev_ind,vlc_3d);
    } else
      length = 0;
    if (length == 0) {  /* Escape coding */
      if (Global::trace) {
	fprintf(Global::tf,"Escape coding:\n");
      }
      if (prev_s == 1) {prev_level = (prev_level^0xff)+1;}
      Encode(ESCAPE,vlc_3d);
      mputv(1,1);
      mputv(6,prev_run);
      mputv(8,prev_level);
      bits += 22;
    }
    else {
      mputv(1,prev_s);
      bits += length + 1;
    }
  }
  return bits;
}

 
/**********************************************************************
 *
 *	Name:		FindCBP
 *	Description:	Finds the CBP for a macroblock
 *	
 *	Input:		qcoeff and mode
 *			
 *	Returns:	CBP
 *	Side effects:	
 *
 *	Date: 940829	Author:	Karl.Lillevold@nta.no
 *
 ***********************************************************************/


int FindCBP(int *qcoeff, int Mode, int ncoeffs)
{
  
  int i,j;
  int CBP = 0;

				/* IF INTRABLOCK then intra =1 else 0 */
  int intra = (Mode == MODE_INTRA);

  /* Set CBP for this Macroblock */
  for (i = 0; i < 6; i++) {
				
    /* First time i = 0: j = 0 ..64-1  set bit 5 if coeff != 0
       Sec. time  i = 1; j = 64..128-1 set bit 4 if coeff != 0
       */
    /* OPTIMIZE: I think for i can be removed 
       and only values i=0 must be proessed */
    for (j = i*ncoeffs + intra; j < (i+1)*ncoeffs; j++) {
      if (qcoeff[j]) {
	if (i == 0) {CBP |= 32;}
	else if (i == 1) {CBP |= 16;}
	else if (i == 2) {CBP |= 8;}
	else if (i == 3) {CBP |= 4;}
	else if (i == 4) {CBP |= 2;}
	else if (i == 5) {CBP |= 1;}
	else {
	  fprintf(stderr,"Error in CBP assignment\n");
	  exit(-1);
	}
	break;
      }
    }
  }

  return CBP;
}


void CountBitsVectors(MotionVector *MV_ptr, Bits *bits, 
		      int x, int y, int Mode, int newgob, Pict *pic)
{
  int y_vec, x_vec;
  extern EHUFF *vlc_mv;
  int pmv0, pmv1;
  int start,stop,block;
  MotionVector *MV_xy;

  start = 0; stop = 0;
  MV_xy = MV_ptr + y*Global::mbc + x;

  for (block = start; block <= stop;  block++) {

    FindPMV(MV_ptr,x,y,&pmv0,&pmv1, block, newgob, 1);

    x_vec = (2*(*MV_xy).x + (*MV_xy).x_half) - pmv0;
    y_vec = (2*(*MV_xy).y + (*MV_xy).y_half) - pmv1;

    if (!Global::long_vectors) {
      if (x_vec < -32) x_vec += 64;
      else if (x_vec > 31) x_vec -= 64;

      if (y_vec < -32) y_vec += 64;
      else if (y_vec > 31) y_vec -= 64;
    }
    else {
      if (pmv0 < -31 && x_vec < -63) x_vec += 64;
      else if (pmv0 > 32 && x_vec > 63) x_vec -= 64;

      if (pmv1 < -31 && y_vec < -63) y_vec += 64;
      else if (pmv1 > 32 && y_vec > 63) y_vec -= 64;
    }
    
    if (x_vec < 0) x_vec += 64;
    if (y_vec < 0) y_vec += 64;

    if (Global::trace) {
      fprintf(Global::tf,"Vectors:\n");
    }
    bits->vec += Encode(x_vec,vlc_mv);
    bits->vec += Encode(y_vec,vlc_mv);

    if (Global::trace) {
      if (x_vec > 31) x_vec -= 64;
      if (y_vec > 31) y_vec -= 64;
      fprintf(Global::tf,"(x,y) = (%d,%d) - ",
	      (2*(*MV_xy).x + (*MV_xy).x_half),
	      (2*(*MV_xy).y + (*MV_xy).y_half));
      fprintf(Global::tf,"(Px,Py) = (%d,%d)\n", pmv0,pmv1);
      fprintf(Global::tf,"(x_diff,y_diff) = (%d,%d)\n",x_vec,y_vec);
    }
  }

  return;
}

void FindPMV(MotionVector *MV_ptr, 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;
 
  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;

  if (half_pel) {

    p1 = (x > 0) ? 
      2*((*(MV_ptr + yin1*Global::mbc + xin1)).x) + (*(MV_ptr+ yin1*Global::mbc + xin1)).x_half : 0;
    p2 = (y > 0) ? 
      2*((*(MV_ptr + yin2*Global::mbc + xin2)).x) + (*(MV_ptr + yin2*Global::mbc + xin2)).x_half : 2*NO_VEC;
    if((y > 0) && (x < Global::mbc - 1))
      p3 = 2*((*(MV_ptr+yin3*Global::mbc + xin3)).x) + ((*(MV_ptr + yin3*Global::mbc + xin3)).x_half);
    else if(x == Global::mbc - 1)
      p3 = 0;
    else			/* y == 0 && x != Global::mbc - 1 */
      p3 = 2*NO_VEC;
    }
  else {
    p1 =  (x > 0) ? 
      (2*((*(MV_ptr + yin1*Global::mbc + xin1)).x)) : 0;
    p2 =  (y > 0) ? 
      (2*((*(MV_ptr + yin2*Global::mbc + xin2)).x)) : 2*NO_VEC;
    if((y > 0) && (x < Global::mbc - 1))
      p3 = 2*((*(MV_ptr + yin3*Global::mbc + xin3)).x);
    else if(x == Global::mbc - 1)
      p3 = 0;
    else			/* y == 0 && x != Global::mbc - 1 */
      p3 = 2*NO_VEC;
  }

  if (newgob && (block == 0 || block == 1 || block == 2))
    p2 = 2*NO_VEC;

  if (p2 == 2*NO_VEC) { p2 = p3 = p1; }

  *pmv0 = p1+p2+p3 - mmax(p1,mmax(p2,p3)) - mmin(p1,mmin(p2,p3));
  if (half_pel) {
    p1 =  (x > 0) ? 
      (2*((*(MV_ptr + yin1*Global::mbc + xin1)).y)) + ((*(MV_ptr + yin1*Global::mbc + xin1)).y_half) : 0;
    p2 =  (y > 0) ? 
      2*((*(MV_ptr + yin2*Global::mbc + xin2)).y) + ((*(MV_ptr + yin2*Global::mbc + xin2)).y_half) : 2*NO_VEC;

    if((y > 0) && (x < Global::mbc - 1))
      p3 = 2*((*(MV_ptr + yin3*Global::mbc + xin3)).y) + ((*(MV_ptr + Global::mbc*yin3 + xin3)).y_half);
    else if(x == Global::mbc - 1)
      p3 = 0;
    else			/* y == 0 && x != Global::mbc - 1 */
      p3 = 2*NO_VEC;
 
  }
  else {
    p1 = (x > 0) ?
      (2*((*(MV_ptr + yin1*Global::mbc + xin1)).y)) : 0;
    p2 =  (y > 0) ?
      (2*((*(MV_ptr + yin2*Global::mbc + xin2)).y)) : 2*NO_VEC;
    if((y > 0) && (x < Global::mbc - 1))
      p3 = 2*((*(MV_ptr + yin3*Global::mbc + xin3)).y);
    else if(x == Global::mbc - 1)
      p3 = 0;
    else			/* y == 0 && x != Global::mbc - 1 */
      p3 = 2*NO_VEC;
  }    

 
  if (newgob && (block == 0 || block == 1 || block == 2))
    p2 = 2*NO_VEC;

  if (p2 == 2*NO_VEC) { p2 = p3 = p1; }

  *pmv1 = p1+p2+p3 - mmax(p1,mmax(p2,p3)) - mmin(p1,mmin(p2,p3));
  
  return;
}

void ZeroBits(Bits *bits)
{
#ifndef MINIMAL_REPORT
  bits->Y = 0;
  bits->C = 0;
  bits->vec = 0;
  bits->CBPY = 0;
  bits->CBPCM = 0;
  bits->MODB = 0;
  bits->CBPB = 0;
  bits->COD = 0;
  bits->DQUANT = 0;
  bits->header = 0;
  bits->total = 0;
  bits->no_inter = 0;
  bits->no_inter4v = 0;
  bits->no_intra = 0;
#endif
  return;
}

void ZeroRes(Results *res)
{
#ifndef MINIMAL_REPORT
  res->SNR_l = 0;
  res->SNR_Cr = 0;
  res->SNR_Cb = 0;
  res->QP_mean = 0;
#endif
}

void AddBits(Bits *total, Bits *bits)
{
#ifndef MINIMAL_REPORT
  total->Y += bits->Y;
  total->C += bits->C;
  total->vec += bits->vec;
  total->CBPY += bits->CBPY;
  total->CBPCM += bits->CBPCM;
  total->MODB += bits->MODB;
  total->CBPB += bits->CBPB;
  total->COD += bits->COD;
  total->DQUANT += bits->DQUANT;
  total->header += bits->header;
  total->total += bits->total;
  total->no_inter += bits->no_inter;
  total->no_inter4v += bits->no_inter4v;
  total->no_intra += bits->no_intra;
#endif
  return;
}
void AddRes(Results *total, Results *res, Pict *pic)
{
#ifndef MINIMAL_REPORT
  total->SNR_l += res->SNR_l;
  total->SNR_Cr += res->SNR_Cr;
  total->SNR_Cb += res->SNR_Cb;
  total->QP_mean += pic->QP_mean;
#endif
  return;
}

void AddBitsPicture(Bits *bits)
{
#ifndef MINIMAL_REPORT
  bits->total = 
    bits->Y + 
    bits->C + 
    bits->vec +  
    bits->CBPY + 
    bits->CBPCM + 
    bits->MODB +
    bits->CBPB +
    bits->COD + 
    bits->DQUANT +
    bits->header ;
#endif
} 
void ZeroVec(MotionVector *MV)
{
  MV->x = 0;
  MV->y = 0;
  MV->x_half = 0;
  MV->y_half = 0;
  return;
}
void MarkVec(MotionVector *MV)
{
  MV->x = NO_VEC;
  MV->y = NO_VEC;
  MV->x_half = 0;
  MV->y_half = 0;
  return;
}

void CopyVec(MotionVector *MV2, MotionVector *MV1)
{
  MV2->x = MV1->x;
  MV2->x_half = MV1->x_half;
  MV2->y = MV1->y;
  MV2->y_half = MV1->y_half;
  return;
}

int EqualVec(MotionVector *MV2, MotionVector *MV1)
{
  if (MV1->x != MV2->x)
    return 0;
  if (MV1->y != MV2->y)
    return 0;
  if (MV1->x_half != MV2->x_half)
    return 0;
  if (MV1->y_half != MV2->y_half)
    return 0;
  return 1;
}

/**********************************************************************
 *
 *	Name:		CountBitsPicture(Pict *pic)
 *	Description:    counts the number of bits needed for picture
 *                      header
 *	
 *	Input:	        pointer to picture structure
 *	Returns:        number of bits
 *	Side effects:
 *
 *	Date: 941128	Author:Karl.Lillevold@nta.no
 *
 ***********************************************************************/

int CountBitsPicture(Pict *pic)
{
  int bits = 0;

 
  /* Picture start code */
  if (Global::trace) {
    fprintf(Global::tf,"picture_start_code: ");
  }
  mputv(PSC_LENGTH,PSC);
  bits += PSC_LENGTH;

  /* Group number */
  if (Global::trace) {
    fprintf(Global::tf,"Group number in picture header: ");
  }
  mputv(5,0); 
  bits += 5;
  
  /* Time reference */
  if (Global::trace) {
    fprintf(Global::tf,"Time reference: ");
  }
  mputv(8,pic->TR);
  bits += 8;

 /* bit 1 */
  if (Global::trace) {
    fprintf(Global::tf,"spare: ");
  }
  pic->spare = 1; /* always 1 to avoid start code emulation */
  mputv(1,pic->spare);
  bits += 1;

  /* bit 2 */
  if (Global::trace) {
    fprintf(Global::tf,"always zero for distinction with H.261\n");
  }
  mputv(1,0);
  bits += 1;
  
  /* bit 3 */
  if (Global::trace) {
    fprintf(Global::tf,"split_screen_indicator: ");
  }
  mputv(1,0);     /* no support for split-screen in this software */
  bits += 1;

  /* bit 4 */
  if (Global::trace) {
    fprintf(Global::tf,"document_camera_indicator: ");
  }
  mputv(1,0);
  bits += 1;

  /* bit 5 */
  if (Global::trace) {
    fprintf(Global::tf,"freeze_picture_release: ");
  }
  mputv(1,0);
  bits += 1;

  /* bit 6-8 */
  if (Global::trace) {
    fprintf(Global::tf,"source_format: ");
  }
  mputv(3,pic->source_format);
  bits += 3;

  /* bit 9 */
  if (Global::trace) {
    fprintf(Global::tf,"picture_coding_type: ");
  }
  mputv(1,pic->picture_coding_type);
  bits += 1;

  /* bit 10 */
  if (Global::trace) {
    fprintf(Global::tf,"Global::mv_outside_frame: ");
  }
  mputv(1,pic->unrestricted_mv_mode);  /* Unrestricted Motion Vector mode */
  bits += 1;

  /* bit 11 */
  if (Global::trace) {
    fprintf(Global::tf,"sac_coding: ");
  }
  mputv(1,0); /* Syntax-based Arithmetic Coding mode not used*/
  bits += 1;

  /* bit 12 */
  if (Global::trace) {
    fprintf(Global::tf,"adv_pred_mode: ");
  }
  mputv(1,Global::advanced); /* Advanced Prediction mode */
  bits += 1;

  /* bit 13 */
  if (Global::trace) {
    fprintf(Global::tf,"PB-coded: "); /* PB-frames mode */
  }
  mputv(1,pic->PB);
  bits += 1;


  /* QUANT */
  if (Global::trace) {
    fprintf(Global::tf,"QUANT: ");
  }
  mputv(5,pic->QUANT);
  bits += 5;

  /* Continuous Presence Multipoint (CPM) */
  mputv(1,0); /* CPM is not supported in this software */
  bits += 1;

  /* Picture Sub Bitstream Indicator (PSBI) */
  /* if CPM == 1: 2 bits PSBI */
  /* not supported */


  /* PEI (extra information) */
  if (Global::trace) {
    fprintf(Global::tf,"PEI: ");
  }
  /* "Encoders shall not insert PSPARE until specified by the ITU" */
  mputv(1,0); 
  bits += 1;

  /* PSPARE */
  /* if PEI == 1: 8 bits PSPARE + another PEI bit */
  /* not supported */

  return bits;
}