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


/* 
* H263PEncode.cxx 
* 
* implementation of the CH263Encoder class. 
* 
* 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. 
*/ 
#ifdef _USRDLL 
#define DLL_EXPORT 
#endif 
 
#include  
#include  
 
#include "../include/picture.h" 
#include "../include/image.h" 
#include "../include/stat.h" 
#include "../include/init.h" 
#include "../include/Exceptions.h" 
#include "../include/ratectrl.h" 
#include "../include/H263PEncode.h" 
 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
#ifdef  __cplusplus 
extern "C" { 
#endif 
 
// globals !!!!!!!!!!!!!!!!!! 
putstrm putstrmctrl; 
int SpiralX[6561];			//!< The Spiral for full search 
int SpiralY[6561];	 
		//!< The Spiral for full search 
#ifdef  __cplusplus 
} 
#endif 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CH263Encoder::CH263Encoder() 
{ 
	m_EncOption.m_iPicFormat		= _QCIF; 
	m_EncOption.m_iQuantI			= 5; 
	m_EncOption.m_iQuantP			= 5; 
	m_EncOption.m_iQuantB           = 5; 
	m_EncOption.m_iPRate			= 300; 
	m_EncOption.m_iBFrame			= 2; 
	m_EncOption.m_iFrameRate		= 30; 
	m_EncOption.m_iRefBufSize		= 4; 
	m_EncOption.m_iMVSearchMethod	= FULLSEARCH; 
	m_EncOption.m_iMVSearchWin		= 15; 
	m_EncOption.m_iUseAP			= 0;  
	m_EncOption.m_iUseDF			= 0; 
	m_EncOption.m_iUseRPS			= 0; 
	m_EncOption.m_iUseBFrame		= 0; 
	m_EncOption.m_iUseGob			= 0; 
	m_EncOption.m_iUseVersion2		= 1; 
	m_EncOption.m_iUseBlock         = 0; 
	m_EncOption.m_iUseRC            = 0; 
	m_EncOption.m_pCBContext        = NULL; 
} 
 
CH263Encoder::~CH263Encoder() 
{ 
 
} 
 
bool CH263Encoder::GetOption(Enc_Option &option) 
{ 
	option = m_EncOption; 
 
	return true; 
} 
/*! 
********************************************************* 
*    Open encoder: Set picture format, picture size,  
*    allocate memory needed, and open stream file. 
*    initilize encoder parameters, including global parameters  
*    and parameters in frame level. 
*    get source frame pointer  
*********************************************************/ 
bool CH263Encoder::EncOpen(Enc_Option &option) 
{ 
#ifdef _DEBUG 
	fdebug = fopen("debug.txt", "w"); 
	frecon = fopen("recon.yuv", "wb"); 
	frecon_B = fopen("b.yuv", "wb"); 
#endif 
 
//	option = m_EncOption;             //!< use default encode option 
 
	// allocate memory 
	m_pEncStatus = (H263VencStatus *) malloc(sizeof(H263VencStatus)); 
	m_pMCStatus  = (MCParam *) malloc(sizeof(MCParam)); 
	m_pStream = &putstrmctrl; 
	//Source Format 
	switch(option.m_iPicFormat) 
	{ 
	case _SUBQCIF: 
		{ 
			m_pEncStatus->pels = 128; 
			m_pEncStatus->lines = 96; 
			m_pEncStatus->gobsync = 1; 
			break; 
		} 
	case _QCIF: 
		{ 
			m_pEncStatus->pels = 176; 
			m_pEncStatus->lines = 144; 
			m_pEncStatus->gobsync = 1; 
			break; 
		} 
	case _CIF: 
		{ 
			m_pEncStatus->pels = 352; 
			m_pEncStatus->lines = 288; 
			m_pEncStatus->gobsync = 1; 
			break; 
		} 
	case _4CIF: 
		{ 
			m_pEncStatus->pels = 704; 
			m_pEncStatus->lines = 576; 
			m_pEncStatus->gobsync = 2; 
			break; 
		} 
	case _16CIF: 
		{ 
			m_pEncStatus->pels = 1408; 
			m_pEncStatus->lines = 1152; 
			m_pEncStatus->gobsync = 4; 
			break; 
		} 
	default: 
		{ 
			printf (E_OPENENC_FORMAT); 
			return false; 
		} 
	} 
	// set parameters for m_pStream 
	m_pStream->buff_size = option.m_iUseBlock ? option.m_iUseBlock : (m_pEncStatus->lines * m_pEncStatus->pels); 
	m_pStream->WriteData = option.m_EncoderCallBack; 
	m_pStream->context   = option.m_pCBContext; 
 
	m_pEncStatus->sourceFormat = option.m_iPicFormat; 
	m_pEncStatus->version2 = option.m_iUseVersion2;   //!< h.263 or h.263+ 
 
	// choose annex 
    m_pEncStatus->annex.Advanced_Prediction = option.m_iUseAP; 
	if (m_pEncStatus->version2) 
	{ 
		m_pEncStatus->annex.Temporal_Scalability = option.m_iUseBFrame; 
		m_pEncStatus->annex.Deblocking_Filter = option.m_iUseDF; 
		m_pEncStatus->annex.RPS = option.m_iUseRPS; 
	} 
	else 
	{ 
		m_pEncStatus->annex.Temporal_Scalability = 0; 
		m_pEncStatus->annex.Deblocking_Filter = 0; 
		m_pEncStatus->annex.RPS = 0; 
	} 
 
	m_pEncStatus->mv_outside_frame = m_pEncStatus->annex.Advanced_Prediction || m_pEncStatus->annex.Deblocking_Filter || m_pEncStatus->annex.Temporal_Scalability; 
    m_pEncStatus->use4mv = m_pEncStatus->annex.Advanced_Prediction || m_pEncStatus->annex.Deblocking_Filter; 
    m_pEncStatus->obmc = m_pEncStatus->annex.Advanced_Prediction; 
	m_pEncStatus->filter = m_pEncStatus->annex.Deblocking_Filter; 
	m_pEncStatus->B_frame = m_pEncStatus->annex.Temporal_Scalability ? option.m_iBFrame : 0; 
    m_pEncStatus->buf_cycle = (m_pEncStatus->annex.RPS && option.m_iRefBufSize>2) ? option.m_iRefBufSize : 2; 
     
	alloc_mem(m_pEncStatus, m_pMCStatus, m_pStream); 
 
	 
	/////////////////////////////////////// 
	// set global parameters of encoder 
    if (!init_para(m_pEncStatus, option.m_iPRate, option.m_iQuantP, option.m_iQuantI, option.m_iQuantB, option.m_iUseGob, option.m_iFrameRate, option.m_iUseRC)) 
	{ 
		EncClose(); 
		return false; 
	} 
	//initialize frame level parameters 
    if (!init_control(m_pEncStatus)) 
	{ 
		EncClose(); 
		return false; 
	} 
	//initialize mc parameters 
    if (!init_MCPara(m_pMCStatus, option.m_iMVSearchWin, option.m_iMVSearchMethod)) 
	{ 
		EncClose(); 
		return false; 
	}   
	//initialize coded table and quant table 
	if (!init_table(m_pEncStatus)) 
	{ 
		EncClose(); 
		return false; 
	} 
 
	return false; 
} 
 
/*! 
********************************************************* 
*    Encode one frame 
*********************************************************/ 
int  CH263Encoder::EncOneFrame(unsigned char *pCapture, unsigned int &nTimeStamp) 
{ 
	int size = 0; 
	int type; 
 
	/* get addresses of source buffer and stream buffer */ 
	GetSourceFrame(m_pEncStatus, pCapture); 
 
	/* encode one frame */ 
	if (INTRA == m_pEncStatus->PTYPE)                   //encode an I-frame 
	{ 
		type = INTRA; 
		init_bitstrm(type, nTimeStamp);              //! initialize stream buffer 
		if (!m_pEncStatus->target_bitrate) 
		{ 
			m_pEncStatus->total_Q = m_pEncStatus->QI;    //! fixed Quant value 
		} 
		m_pEncStatus->totalBits = EncIfrm(m_pEncStatus); 
		m_pEncStatus->framebits[m_pEncStatus->pic_nbr%m_pEncStatus->framerate] = m_pEncStatus->totalBits; 
		m_pEncStatus->TRP[m_pEncStatus->zero_index] = m_pEncStatus->TR; 
		m_pEncStatus->frame_skip = ratectrl(m_pEncStatus->target_bitrate, m_pEncStatus->framerate, m_pEncStatus->framebits, &m_pEncStatus->total_Q); 
		size = m_pEncStatus->totalBits/8; 
#ifdef  _DEBUG 
		computeSNRY(m_pEncStatus);   //! compute PSNR for lum 
		computeSNRCB(m_pEncStatus);  //! compute PSNR for cb  
		computeSNRCR(m_pEncStatus);  //! compute PSNR for cr  
		WriteRec(m_pEncStatus, frecon); 
		printf("frame %d coded, type: INTRA, bits: %d, TR: %d\n", m_pEncStatus->pic_nbr, m_pEncStatus->totalBits, m_pEncStatus->TR); 
#endif 
	} 
	else if (INTER == m_pEncStatus->PTYPE)              //encode a P-frame 
	{ 
		type = INTER; 
		init_bitstrm(type, nTimeStamp);              //! initialize stream buffer 
		if (!m_pEncStatus->target_bitrate) 
		{ 
			m_pEncStatus->total_Q = m_pEncStatus->QP;    //! fixed Quant value 
		} 
		m_pEncStatus->totalBits = EncPfrm(m_pEncStatus, m_pMCStatus);	 
		m_pEncStatus->framebits[m_pEncStatus->pic_nbr%m_pEncStatus->framerate] = m_pEncStatus->totalBits; 
		m_pEncStatus->TRP[m_pEncStatus->zero_index] = m_pEncStatus->TR; 
		size = m_pEncStatus->totalBits/8; 
		m_pEncStatus->frame_skip = ratectrl(m_pEncStatus->target_bitrate, m_pEncStatus->framerate, m_pEncStatus->framebits, &m_pEncStatus->total_Q); 
#ifdef  _DEBUG 
		computeSNRY(m_pEncStatus);   //! compute PSNR for lum 
		computeSNRCB(m_pEncStatus);  //! compute PSNR for cb  
		computeSNRCR(m_pEncStatus);  //! compute PSNR for cr 
		WriteRec(m_pEncStatus, frecon);	 
		printf("frame %d coded, type: INTER refer: %d bits: %d, TR: %d\n",  
			   m_pEncStatus->pic_nbr, m_pEncStatus->ref_pic, m_pEncStatus->totalBits, m_pEncStatus->TR); 
#endif 
 
 
	} 
	else if (B_IMG == m_pEncStatus->PTYPE) 
	{ 
        unsigned int tmp = m_pEncStatus->nTime[m_pEncStatus->B_count]; 
		int          pic_size = m_pEncStatus->pels * m_pEncStatus->lines * 3 / 2; 
 
		type = B_IMG; 
		init_bitstrm(type, tmp);              //! initialize stream buffer 
		if (!m_pEncStatus->target_bitrate) 
		{ 
			m_pEncStatus->total_Q = m_pEncStatus->QB;    //! fixed Quant value 
		} 
		m_pEncStatus->totalBits = EncBfrm(m_pEncStatus, m_pMCStatus); 
		m_pEncStatus->framebits[m_pEncStatus->pic_nbr%m_pEncStatus->framerate] = m_pEncStatus->totalBits; 
		m_pEncStatus->frame_skip = ratectrl(m_pEncStatus->target_bitrate, m_pEncStatus->framerate, m_pEncStatus->framebits, &m_pEncStatus->total_Q); 
#ifdef  _DEBUG 
		computeSNRY(m_pEncStatus); 
		computeSNRCB(m_pEncStatus); 
		computeSNRCR(m_pEncStatus); 
		fwrite(m_pEncStatus->BPicture[0].pLum, m_pEncStatus->lines*m_pEncStatus->pels*3/2, 1, frecon_B); 
		printf("frame %d coded, type: B_IMG, bits: %d, TR: %d\n", m_pEncStatus->pic_nbr, m_pEncStatus->totalBits, m_pEncStatus->TRB); 
#endif 
		//! save the captured frame and related infomation for encoding next B picture 
		memcpy(m_pEncStatus->BPicture[m_pEncStatus->B_count].pLum, m_pEncStatus->frameToEncode.pLum, pic_size); 
		m_pEncStatus->TR4BPicture[m_pEncStatus->B_count] = m_pEncStatus->TR; //< save time reference of the captured frame 
		m_pEncStatus->nTime[m_pEncStatus->B_count] = nTimeStamp; //< save time stamp of the captured frame 
		nTimeStamp = tmp; //! modify time stamp 
		size = m_pEncStatus->totalBits/8;		 
	} 
	else if (STORE == m_pEncStatus->PTYPE) 
	{ 
		int pic_size = m_pEncStatus->pels * m_pEncStatus->lines * 3 / 2; 
 
		memcpy(m_pEncStatus->BPicture[m_pEncStatus->B_count].pLum, m_pEncStatus->frameToEncode.pLum, pic_size); 
		m_pEncStatus->TR4BPicture[m_pEncStatus->B_count] = m_pEncStatus->TR; //< save time reference of the captured frame 
		m_pEncStatus->nTime[m_pEncStatus->B_count] = nTimeStamp; //< save time stamp of the captured frame 
		m_pEncStatus->totalBits = 0; 
		m_pEncStatus->framebits[m_pEncStatus->pic_nbr%m_pEncStatus->framerate] = m_pEncStatus->totalBits; 
		type = STORE; 
		nTimeStamp = 0; 
		size = 0;		 
 
#ifdef  _DEBUG 
		printf("frame %d stored.\n", m_pEncStatus->pic_nbr); 
#endif 
	} 
	else 
	{ 
		m_pEncStatus->totalBits = 0; 
		m_pEncStatus->framebits[m_pEncStatus->pic_nbr%m_pEncStatus->framerate] = m_pEncStatus->totalBits; 
		type = SKIP; 
		nTimeStamp = 0; 
		size = 0; 
#ifdef _DEBUG 
		printf("frame %d skiped.\n", m_pEncStatus->pic_nbr); 
#endif 
	} 
 
    /* regulation and control for next frame */ 
 
	if (!m_pEncStatus->frame_skip) 
	{ 
		if (m_pEncStatus->B_count < m_pEncStatus->B_frame) 
		{ 
			m_pEncStatus->B_count++; 
			m_pEncStatus->PTYPE = B_IMG; 
			m_pEncStatus->TRB = m_pEncStatus->TR4BPicture[m_pEncStatus->B_count]; 
			if (m_pEncStatus->pcount == 0) 
			{ 
				m_pEncStatus->PTYPE = STORE; 
			} 
			 
		} 
		else 
		{ 
			m_pEncStatus->B_count = 0; 
			if (m_pEncStatus->pcount < m_pEncStatus->p_rate) 
			{ 
				m_pEncStatus->pcount++; 
				m_pEncStatus->PTYPE = INTER; 
			} 
			else 
			{ 
				m_pEncStatus->pcount = 0; 
				m_pEncStatus->PTYPE = INTRA; 
	 
			} 
		} 
	} 
	else 
	{ 
		m_pEncStatus->PTYPE = SKIP; 
		m_pEncStatus->frame_skip--; 
	} 
 
 
	m_pEncStatus->gfid = m_pEncStatus->PTYPE; 
	m_pEncStatus->ref_pic = (m_pEncStatus->pcountbuf_cycle) ? m_pEncStatus->pcount : m_pEncStatus->buf_cycle-1; 
	m_pEncStatus->zero_index = m_pEncStatus->pcount % m_pEncStatus->buf_cycle; 
	m_pEncStatus->ref_index  = (m_pEncStatus->pcount - m_pEncStatus->ref_pic) % m_pEncStatus->buf_cycle; 
	m_pEncStatus->pic_nbr++; 
	m_pEncStatus->TR = (m_pEncStatus->TR + 1)%256; 
 
	if (!(m_pEncStatus->pic_nbr%m_pEncStatus->framerate)) 
	{ 
		for (int i = 0; i < m_pEncStatus->framerate; i++) 
			m_pEncStatus->framebits[i] = -1; 
	} 
 
	return size; 
} 
 
/*! 
********************************************************* 
*    Close encoder, set free memory 
*********************************************************/ 
void CH263Encoder::EncClose() 
{ 
	close_encoder(m_pEncStatus, m_pMCStatus, m_pStream); 
	free(m_pEncStatus); 
	free(m_pMCStatus); 
 
//	fclose(m_pStream->bitstrmfptr);  //!< close stream 
#ifdef _DEBUG 
	fclose(frecon_B); 
	fclose(frecon); 
	fclose(fdebug); 
#endif 
}