1. 程式人生 > >HEVC程式碼學習2:TAppEncTop::encode函式

HEVC程式碼學習2:TAppEncTop::encode函式

之前對TAppEncoder的main函式進行了學習,其中最重要的呼叫函式即是TAppEncTop::encode,將所有的編碼過程全部封裝在其中,下面將對其進行具體學習。

TAppEncTop::encode主要做的是編碼前的準備工作,進行編碼器引數、視訊檔案、以及各類引數等的初始化,為原始YUV分配空間,然後呼叫TEncTop::encode進行編碼,編碼完成後列印統計資訊。

主要過程如下:


其中呼叫了三個重要函式進行初始化:

xInitLibCfg()——初始化編碼器的引數,包括VPS,Profile、Level、Framerate以及編碼影象的寬度和高度,待編碼的幀數,編碼結構,層,環路區塊濾波器等等資訊。這些引數其實都是TEncTop類下TEnCfg類的成員,這裡就是直接把TAppEncCfg類的成員值複製過來設定TEncCfg類的成員值。

xCreateLib()——初始化視訊原始檔以及編碼重建後的二進位制視訊檔案和程式連線,初始化GOP、Slice、CU的部分物件函式。

XInitLib(m_isField)——初始化SPS、PPS,GOP、Slice、CU的部分物件函式,變換和量化類,編碼器搜尋類函式。

然後呼叫了TEncTop::encode對視訊幀進行編碼,將在之後進行學習。

Void TAppEncTop::encode()
{
  fstream bitstreamFile(m_pchBitstreamFile, fstream::binary | fstream::out); //以二進位制輸出方式開啟位元流檔案
  if (!bitstreamFile) //判斷位元流檔案是否存在,若bitstreamFile為空則輸出錯誤提示並退出程式
  {
    fprintf(stderr, "\nfailed to open bitstream file `%s' for writing\n", m_pchBitstreamFile);
    exit(EXIT_FAILURE);
  }

  TComPicYuv*       pcPicYuvOrg = new TComPicYuv; //定義YUV類
  TComPicYuv*       pcPicYuvRec = NULL;

  // initialize internal class & member variables 初始化內部類和成員變數
  xInitLibCfg(); //初始化編碼器的引數
  xCreateLib(); //建立視訊原始檔以及編碼重建後的二進位制視訊檔案和程式的連線,初始化GOP、Slice、CU的部分物件函式
  xInitLib(m_isField); //初始化SPS、PPS,GOP、Slice、CU的部分物件函式,變換和量化類,編碼器搜尋類函式

  printChromaFormat(); //列印輸入和輸出的YUV格式

  // main encoder loop 初始化編碼器中的部分變數
  Int   iNumEncoded = 0; //記錄已編碼幀數
  Bool  bEos = false; //控制編碼是否結束

  const InputColourSpaceConversion ipCSC  =  m_inputColourSpaceConvert;
  const InputColourSpaceConversion snrCSC = (!m_snrInternalColourSpace) ? m_inputColourSpaceConvert : IPCOLOURSPACE_UNCHANGED;

  list<AccessUnit> outputAccessUnits; ///< list of access units to write out.  is populated by the encoding process

  TComPicYuv cPicYuvTrueOrg;

  // allocate original YUV buffer 為原始YUV緩衝區分配記憶體空間
  if( m_isField )
  {
    pcPicYuvOrg->create  ( m_iSourceWidth, m_iSourceHeightOrg, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxTotalCUDepth, true );
    cPicYuvTrueOrg.create(m_iSourceWidth, m_iSourceHeightOrg, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxTotalCUDepth, true);
  }
  else
  {
    pcPicYuvOrg->create  ( m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxTotalCUDepth, true );
    cPicYuvTrueOrg.create(m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxTotalCUDepth, true );
  }

  while ( !bEos ) //由bEos控制,對視訊幀進行編碼
  {
    // get buffers 設定緩衝區
    xGetBuffer(pcPicYuvRec);

    // read input YUV file 讀入輸入的YUV檔案
    m_cTVideoIOYuvInputFile.read( pcPicYuvOrg, &cPicYuvTrueOrg, ipCSC, m_aiPad, m_InputChromaFormatIDC, m_bClipInputVideoToRec709Range );

    // increase number of received frames 接收到幀數自加
    m_iFrameRcvd++;

    bEos = (m_isField && (m_iFrameRcvd == (m_framesToBeEncoded >> 1) )) || ( !m_isField && (m_iFrameRcvd == m_framesToBeEncoded) );

    Bool flush = 0;
    // if end of file (which is only detected on a read failure) flush the encoder of any queued pictures 檔案讀取完成重新整理編碼器中的影象佇列
    if (m_cTVideoIOYuvInputFile.isEof())
    {
      flush = true;
      bEos = true;
      m_iFrameRcvd--;
      m_cTEncTop.setFramesToBeEncoded(m_iFrameRcvd);
    }

    // call encoding function for one frame 呼叫編碼器函式對單幀進行編碼
    if ( m_isField )
    {
      m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, flush ? 0 : &cPicYuvTrueOrg, snrCSC, m_cListPicYuvRec, outputAccessUnits, iNumEncoded, m_isTopFieldFirst );
    }
    else
    {
      m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, flush ? 0 : &cPicYuvTrueOrg, snrCSC, m_cListPicYuvRec, outputAccessUnits, iNumEncoded );
    }

    // write bistream to file if necessary 當iNumEncoded>0時<span style="font-family: Arial, Helvetica, sans-serif;">寫入位元流檔案</span>
    if ( iNumEncoded > 0 )
    {
      xWriteOutput(bitstreamFile, iNumEncoded, outputAccessUnits);
      outputAccessUnits.clear();
    }
  }

  m_cTEncTop.printSummary(m_isField); //列印編碼結果統計資訊

  // delete original YUV buffer 刪除原始YUV緩衝區
  pcPicYuvOrg->destroy();
  delete pcPicYuvOrg;
  pcPicYuvOrg = NULL;

  // delete used buffers in encoder class 刪除編碼器類使用的緩衝區
  m_cTEncTop.deletePicBuffer();
  cPicYuvTrueOrg.destroy();

  // delete buffers & classes 刪除緩衝區和類
  xDeleteBuffer();
  xDestroyLib();

  printRateSummary(); //列印總位元率資訊

  return;
}