HEVC函数入门(1)——HM编码器的基本结构

来源:互联网 发布:tcp监听端口检测失败 编辑:程序博客网 时间:2024/06/05 18:24

首先说明这篇主要是记录用(意思是里面很多是我自己的理解,我也是刚入门的新手,肯定有许多不正确的地方,还请轻喷),使用的是HM 16.3 VS2015 当然如果有新手不太懂的话也可以看看。
本文主要参照http://blog.csdn.net/shaqoneal/article/details/36398707

int main(int argc, char* argv[]){  TAppEncTop  cTAppEncTop;  // print information  fprintf( stdout, "\n" );  fprintf( stdout, "HM software: Encoder Version [%s] (including RExt)", NV_VERSION );  fprintf( stdout, NVM_ONOS );  fprintf( stdout, NVM_COMPILEDBY );  fprintf( stdout, NVM_BITS );  fprintf( stdout, "\n\n" );  // create application encoder class  cTAppEncTop.create();  // parse configuration  try  {    if(!cTAppEncTop.parseCfg( argc, argv ))    {      cTAppEncTop.destroy();#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST      EnvVar::printEnvVar();#endif      return 1;    }  }  catch (df::program_options_lite::ParseFailure &e)  {    std::cerr << "Error parsing option \""<< e.arg <<"\" with argument \""<< e.val <<"\"." << std::endl;    return 1;  }#if PRINT_MACRO_VALUES  printMacroSettings();#endif#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST  EnvVar::printEnvVarInUse();#endif  // starting time  Double dResult;  clock_t lBefore = clock();  // call encoding function  cTAppEncTop.encode();  // ending time  dResult = (Double)(clock()-lBefore) / CLOCKS_PER_SEC;  printf("\n Total Time: %12.3f sec.\n", dResult);  // destroy application encoder class  cTAppEncTop.destroy();  return 0;}//! \}

这里是主函数,在TAppEncoder中的Source Files中,我们现在不关注TAppEncCfg.cpp,先打开encmain.cpp,可以很清楚地看到,整个main函数非常简洁清晰,主要可以分为几大部分,分别是输入软件信息、创建编码器类的实例、解析配置文件、获取开始时间、编码数据、计算耗费时间和销毁编码器类的实例几大部分。
如上所示,从英文中找到call encoding function也就是这里是实际进行编码的地方,右键查看所有引用,下方TAppEncTop::encode XXX406这个是encode函数所在的地方,其内容为

Void TAppEncTop::encode(){  fstream bitstreamFile(m_pchBitstreamFile, fstream::binary | fstream::out);  if (!bitstreamFile)  {    fprintf(stderr, "\nfailed to open bitstream file `%s' for writing\n", m_pchBitstreamFile);    exit(EXIT_FAILURE);  }  TComPicYuv*       pcPicYuvOrg = new TComPicYuv;  TComPicYuv*       pcPicYuvRec = NULL;  // initialize internal class & member variables  xInitLibCfg();  xCreateLib();  xInitLib(m_isField);  printChromaFormat();  // 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  if( m_isField )  {    pcPicYuvOrg->create( m_iSourceWidth, m_iSourceHeightOrg, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth );  cPicYuvTrueOrg.create(m_iSourceWidth, m_iSourceHeightOrg, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth);  }  else  {    pcPicYuvOrg->create( m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth );  cPicYuvTrueOrg.create(m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth);  }  while ( !bEos )  {    // get buffers    xGetBuffer(pcPicYuvRec);    // read input YUV file    m_cTVideoIOYuvInputFile.read( pcPicYuvOrg, &cPicYuvTrueOrg, ipCSC, m_aiPad, m_InputChromaFormatIDC );    // 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    if ( iNumEncoded > 0 )    {      xWriteOutput(bitstreamFile, iNumEncoded, outputAccessUnits);      outputAccessUnits.clear();    }  }  m_cTEncTop.printSummary(m_isField);  // delete original YUV buffer  pcPicYuvOrg->destroy();  delete pcPicYuvOrg;  pcPicYuvOrg = NULL;  // delete used buffers in encoder class  m_cTEncTop.deletePicBuffer();  cPicYuvTrueOrg.destroy();  // delete buffers & classes  xDeleteBuffer();  xDestroyLib();  printRateSummary();  return;}

这么长看的我都慌了,先参考上面博客链接里面讲的

该函数中首先调用pcPicYuvOrg->create( m_iSourceWidth, m_iSourceHeight, m_uiMaxCUWidth, m_uiMaxCUHeight, m_uiMaxCUDepth )分配YUV数据缓存,然后再while循环中逐帧读取YUV数据、设置当前以编码的帧数、编码当前帧、写出码流,随后做其他清理工作。核心功能实现在m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, m_cListPicYuvRec, outputAccessUnits, iNumEncoded )函数中。在该函数中调用m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, accessUnitsOut)进行编码一个GOP的操作。这个函数奇长无比,用了接近1500行代码,看来实现了很多很多很多的功能。这个碉堡了的函数究竟做了些啥事儿呢?这个函数中大部分内容就是在为了编码当前slice做准备,以及编码完成之后一些辅助操作。实际编码过程的操作由以下函数m_pcSliceEncoder->compressSlice( pcPic )实现。
这又是一个碉堡了的函数,占了将近400行……代码就不贴了,会死人的……简单看下好了。
首先还是各种编码的配置,包括配置熵编码器、初始化CU编码器等。在完成了一长串的设置之后,在compressCU函数中实现对一个CU的编码:

我们直接看核心功能实现,这里博主使用的HM10,和我使用的16.3略有不同,我这里关于这个函数是这个样子的

 // 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 );    }

这里分成两个了,个人理解第一个是对第一帧编码,第二个是对后续帧编码,那么来看看第一个的内容吧
右键查看它的引用,跳转到了一个.h文件里面(这个不是很懂了就),暂时不管那么多,接着跳转,啊啊啊啊不对,不是这么跳转的。我是
这里写图片描述
先全拖住再F12跳转的,所以错了应该这样
这里写图片描述
这样就跳转到了encode里面
找到这个
// compress GOP
m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, accessUnitsOut, false, false, snrCSC, m_printFrameMSE);

再跳转 一步步跳转之后,最后找CU要跳转compressCtu,我一直搜索compressCU找不到来着。今天的内容就到这儿吧

阅读全文
0 0