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->pcount buf_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 }