HEVC程式碼學習2:TAppEncTop::encode函式
阿新 • • 發佈:2019-02-18
之前對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; }