VVC代码阅读(2)compressGOP函数(1)

注意:本次代码运用的是encoder_intra_vtm的设置,所以GOP_size  只有一帧,都是I帧

EncApp::encode()

const InputColourSpaceConversion snrCSC = ( !m_snrInternalColourSpace ) ? m_inputColourSpaceConvert : IPCOLOURSPACE_UNCHANGED;
  bool keepDoing = false;

  // call encoding function for one frame
  if( m_isField )
  {
    keepDoing = m_cEncLib.encode( snrCSC, m_recBufList, m_numEncoded, m_isTopFieldFirst );
  }
  else
  {
    keepDoing = m_cEncLib.encode( snrCSC, m_recBufList, m_numEncoded );//调用编码函数
  }

从EncLib::encode进入compressgop()函数

bool EncLib::encode( const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded )
{
  // compress GOP
  m_cGOPEncoder.compressGOP( m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut,
    false, false, snrCSC, m_printFrameMSE, m_printMSSSIM, false, m_picIdInGOP ); 

 snrCSC:色彩空间转换形式                         m_iPOCLast:图像序列号(POC)的最后一位 

m_iNumPicRcvd:当前GOP已接收到几帧数据

iNumEncoded:已编码数量

rcListPicYuvRecOut的意思在EncLib::encode上面的绿色注释中:

 \retval  rcListPicYuvRecOut  list of reconstruction YUV pictures      重建YUV图片列表

compressGOP()函数 

1.初始设置

// TODO: Split this function up.

  Picture*        pcPic = NULL;
  PicHeader*      picHeader = NULL;
  Slice*      pcSlice;
  OutputBitstream  *pcBitstreamRedirect;  //将码流装入VCL-NALU之前暂存的地方
  pcBitstreamRedirect = new OutputBitstream;
  AccessUnit::iterator  itLocationToPushSliceHeaderNALU; // used to store location where    NALU containing slice header is to be inserted
  Picture* scaledRefPic[MAX_NUM_REF] = {};

 xInitGOP( iPOCLast, iNumPicRcvd, isField, isEncodeLtRef );


isEncodeLtRef:猜测是已编码左侧参考像素的意思
【H.264/AVC视频编解码技术详解】 九、序列参数集Sequence Paramater Set(SPS)解析_取次花丛懒回顾的博客-CSDN博客

【H.264/AVC视频编解码技术详解】十一、H.264的Slice Header解析_取次花丛懒回顾的博客-CSDN博客_avc slice

pcBitstreamRedirect:将码流装入VCL-NALU之前暂存的地方

scaledRefPic:存储着缩放后的参考帧

xInitGOP:设置m_iGopSize,表示当前GOP的大小,除了第一帧是1的情况外是恒定的,即使当前GOP没有读取到足够的帧数

MAX_NUM_REF:图片参考队列可能达到的最大长度,最大为16。(存疑

 m_iNumPicCoded = 0;    //已编码图片数
  SEIMessages leadingSeiMessages;
  SEIMessages nestedSeiMessages;
  SEIMessages duInfoSeiMessages;
  SEIMessages trailingSeiMessages;
  std::deque<DUData> duData;

  EfficientFieldIRAPMapping effFieldIRAPMap;   //随机接入点
  if (m_pcCfg->getEfficientFieldIRAPEnabled())  //与场编码有关,跳过
  {
    effFieldIRAPMap.initialize(isField, m_iGopSize, iPOCLast, iNumPicRcvd, m_iLastIDR, this, m_pcCfg);
  }

  if( isField && picIdInGOP == 0 )
  {
    for( int iGOPid = 0; iGOPid < max(2, m_iGopSize); iGOPid++ )
    {
      m_pcCfg->setEncodedFlag( iGOPid, false );
    }
  }

//重设flag指明图片是否已被编码 reset flag indicating whether pictures have been encoded
  for( int iGOPid = picIdInGOP; iGOPid <= picIdInGOP; iGOPid++ )
  {
    m_pcCfg->setEncodedFlag( iGOPid, false );  //表示当前帧还未编码
    if (m_pcCfg->getEfficientFieldIRAPEnabled())
    {
      iGOPid=effFieldIRAPMap.adjustGOPid(iGOPid);
    }

    //-- For time output for each slice
    auto beforeTime = std::chrono::steady_clock::now();

读H.265/HEVC编码笔记(一)_qq_27901569的博客-CSDN博客

IRAP(Intra Random Access Point)——随机接入点:

为了满足压缩视频流的随机介入需求,如电视频道的切换、视频播放中的快进、拖曳等,一段视频流中通常会间隔地存在一些随机介入点。从IRAP开始,后续视频流(播放顺序在IRAP后的图像)可以独立正确解码,无需参考IRAP前面的视频信息。IRAP后的第一幅解码图像被称为IRAP图像。IRAP图像只包含帧内编码片,不采用帧间预测技术,可以独立解码。

setEncodedFlag():将m_RPLList0、m_RPLList1、m_GOPList中的m_isEncoded设置为false,表示当前帧还未编码。m_GOPList里面存着一个GOP内每个帧的一些信息(例如POC、I/B/P帧等等),这些都是直接从cfg文件中得到的。m_RPLList0和m_RPLList1相对侧重于存储每个帧有关参考帧列表1和0的信息。 

now():记录一下起始时间
iGOPid:猜测为  GOP id,这幅图片的序列号

picIdInGOP:猜测为 这幅图片在GOP中的序列号

初始化以便开始编码

    int iTimeOffset;
    int pocCurr;
    int multipleFactor = m_pcCfg->getUseCompositeRef() ? 2 : 1;  //倍乘因子

    if(iPOCLast == 0) //帧编码或顶场编码case first frame or first top field
    {
      pocCurr=0;
      iTimeOffset = isField ? (1 - multipleFactor) : multipleFactor;
    }
    else if(iPOCLast == 1 && isField) //底场编码case first bottom field, just like the first frame, the poc computation is not right anymore, we set the right value
    {
      pocCurr = 1;
      iTimeOffset = multipleFactor + 1;
    }
    else //帧编码的POC
    {
      pocCurr = iPOCLast - iNumPicRcvd * multipleFactor + m_pcCfg->getGOPEntry(iGOPid).m_POC - ((isField && m_iGopSize>1) ? 1 : 0);
      iTimeOffset = m_pcCfg->getGOPEntry(iGOPid).m_POC;
    }

pocCurr:表示当前编码帧的POC

iTimeOffset:表示当前编码帧是当前GOP播放顺序的第几帧

 int multipleFactor = m_pcCfg->getUseCompositeRef() ? 2 : 1; //Composite Reference综合参考。应该是从配置里看是否运用这种技术.默认为0

编码顺序、frame_num和POC_chinabinlang的博客-CSDN博客

因为此时我设置的只编码一帧,所以iPOCLast = 0.之后可以试试改为编码多帧时的运行结果

if (m_pcCfg->getUseCompositeRef() && isEncodeLtRef)
    {
      pocCurr++;
      iTimeOffset--;
    }
    if (pocCurr / multipleFactor >= m_pcCfg->getFramesToBeEncoded())
    {
      if (m_pcCfg->getEfficientFieldIRAPEnabled())
      {
        iGOPid=effFieldIRAPMap.restoreGOPid(iGOPid);
      }
      continue;
    }

    if( getNalUnitType(pocCurr, m_iLastIDR, isField) == NAL_UNIT_CODED_SLICE_IDR_W_RADL || getNalUnitType(pocCurr, m_iLastIDR, isField) == NAL_UNIT_CODED_SLICE_IDR_N_LP )
    {
      m_iLastIDR = pocCurr;
    }

I 帧和 IDR 帧的区别_chenchong_219的博客-CSDN博客_idr帧

前两个if:跳过。之后再看

m_iLastIDR(getNalUnitType()中有注释):最后一个IDR帧的POC序号

 getNalUnitType():检查配置并为图片返回适当的NAL单元类型

第三个if:如果当前帧的NAL单元类型为IDR,则更新m_iLastIDR为最近一个IDR帧的POC编码顺序

RADL:注意看万帅书P274。朱秀昌书P236

 // start a new access unit: create an entry in the list of output access units
    AccessUnit accessUnit;
    accessUnit.temporalId = m_pcCfg->getGOPEntry( iGOPid ).m_temporalId;
    xGetBuffer( rcListPic, rcListPicYuvRecOut,
                iNumPicRcvd, iTimeOffset, pcPic, pocCurr, isField );
    picHeader = pcPic->cs->picHeader;
    picHeader->setSPSId( pcPic->cs->pps->getSPSId() );
    picHeader->setPPSId( pcPic->cs->pps->getPPSId() );
    picHeader->setSplitConsOverrideFlag(false);
    // initial two flags to be false
    picHeader->setPicInterSliceAllowedFlag(false);
    picHeader->setPicIntraSliceAllowedFlag(false);
#if ER_CHROMA_QP_WCG_PPS
    // th this is a hot fix for the choma qp control
    if( m_pcEncLib->getWCGChromaQPControl().isEnabled() && m_pcEncLib->getSwitchPOC() != -1 )
    {
      static int usePPS = 0; /* TODO: MT */
      if( pocCurr == m_pcEncLib->getSwitchPOC() )
      {
        usePPS = 1;
      }
      const PPS *pPPS = m_pcEncLib->getPPS(usePPS);
      // replace the pps with a more appropriated one
      pcPic->cs->pps = pPPS;
    }
#endif
access unit( H.264英文解释 ) : A set of NAL units always containing a primary coded picture . In addition to the primary coded picture , an access unit may also contain one or more redundant coded pictures or other NAL units not containing slices or slice data partitions of a coded picture . The decoding of an access unit always results in a decoded picture .
基本编码图像(PCP,primary coded picture)
冗余编码图像(CRP,corresponding redundant picture)
access unit (AU H.266英文解释 ): A set of PUs that belong to different layers and contain coded pictures associated with the
same time for output from the DPB .
万帅HEVC的P282页有关于AU的解释。定义为:多个按解码顺序排列的NALU,这些NALU解码正好生成一幅图像。AU可以看成压缩视频比特流的基本单位,压缩视频比特流有多个按顺序排列的AU组成
xGetBuffer():相当于初始化指针pcPic,设置重建帧指针的指向
后面是PictureHeader有关的初始设置
    // create objects based on the picture size
    const int picWidth = pcPic->cs->pps->getPicWidthInLumaSamples();//帧的宽度
    const int picHeight = pcPic->cs->pps->getPicHeightInLumaSamples();//帧的高度
    const int maxCUWidth = pcPic->cs->sps->getMaxCUWidth();//最大CU允许宽度
    const int maxCUHeight = pcPic->cs->sps->getMaxCUHeight();//最大CU允许高度
    const ChromaFormat chromaFormatIDC = pcPic->cs->sps->getChromaFormatIdc(); //色度采样格式
    const int maxTotalCUDepth = floorLog2(maxCUWidth) - pcPic->cs->sps->getLog2MinCodingBlockSize();//最大CU深度

    m_pcSliceEncoder->create( picWidth, picHeight, chromaFormatIDC, maxCUWidth, maxCUHeight, maxTotalCUDepth );

    pcPic->createTempBuffers( pcPic->cs->pps->pcv->maxCUWidth );
    pcPic->cs->createCoeffs((bool)pcPic->cs->sps->getPLTMode());

    //  Slice data initialization
    pcPic->clearSliceBuffer();
    pcPic->allocateNewSlice();
    m_pcSliceEncoder->setSliceSegmentIdx(0);

    m_pcSliceEncoder->initEncSlice(pcPic, iPOCLast, pocCurr, iGOPid, pcSlice, isField, isEncodeLtRef, m_pcEncLib->getLayerId(), getNalUnitType(pocCurr, m_iLastIDR, isField) );

    DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) );
    DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 0 ) ) );

m_pcSliceEncoder->create():通过片编码器类建立一个片的编码器,分配内存,输入参数

compressGOP中的一些函数解释_青椒鸡汤的博客-CSDN博客

createTempBuffers():创建预测值和残差值的buffer

createCoeffs():创建和TU有关的buffer

clearSliceBuffer():清空slices的buffer

allocateNewSlice():分配一个新的slice

setSliceSegmentIdx():设置m_uiSliceSegmentIdx,表示当前编码slice的Index

initEncSlice():初始化slice.这个函数之后看,可参考HM编码器代码阅读(9)——片编码器的初始化_NB_vol_1的博客-CSDN博客

2.slice的设置

    pcSlice->setLastIDR(m_iLastIDR); 
    pcSlice->setIndependentSliceIdx(0);

    if(pcSlice->getSliceType()==B_SLICE&&m_pcCfg->getGOPEntry(iGOPid).m_sliceType=='P')
    {
      pcSlice->setSliceType(P_SLICE);
    }
    if(pcSlice->getSliceType()==B_SLICE&&m_pcCfg->getGOPEntry(iGOPid).m_sliceType=='I')
    {
      pcSlice->setSliceType(I_SLICE);
    }
    pcSlice->setTLayer(m_pcCfg->getGOPEntry(iGOPid).m_temporalId);
#if GDR_ENABLED
    if (m_pcCfg->getGdrEnabled() && pocCurr >= m_pcCfg->getGdrPocStart() && ((pocCurr - m_pcCfg->getGdrPocStart()) % m_pcCfg->getGdrPeriod() == 0))
    {
      pcSlice->setSliceType(B_SLICE);
    }

    // note : first picture is GDR(I_SLICE)
    if (m_pcCfg->getGdrEnabled() && pocCurr == 0)
    {
      pcSlice->setSliceType(I_SLICE);
    }
#endif

    // Set the nal unit type
    pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField));
    // set two flags according to slice type presented in the picture
    if (pcSlice->getSliceType() != I_SLICE)
    {
      picHeader->setPicInterSliceAllowedFlag(true);
    }
    if (pcSlice->getSliceType() == I_SLICE)
    {
      picHeader->setPicIntraSliceAllowedFlag(true);
    }
    picHeader->setGdrOrIrapPicFlag(picHeader->getGdrPicFlag() || pcSlice->isIRAP());

setLastIDR():设置m_iLastIDR,表示这个slice所在帧之前最近的一个IDR帧的POC序号

setIndependentSliceIdx():设置m_independentSliceIdx,表示独立slice的index。万帅书68页

iGOPid(POC offset for hierarchical structure)代表一个GOP中的第几帧图。

查看SliceType  枚举函数可知

enum SliceType
{
  B_SLICE               = 0,
  P_SLICE               = 1,
  I_SLICE               = 2,
  NUMBER_OF_SLICE_TYPES = 3
};

这里可以用cout << pcSlice->getSliceType() << endl;直接验证得出这个片的IPB类型

 两个if语句:应该是当前片的类型为B_slice但 从cfg配置中根据当前帧的序号读取到当前slice的类型为I或P时,对slice类型的设置方法。以配置为准

setTLayer():设置所在的时域层,不清楚的可以看万老师书P275

    // Set the nal unit type
    pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField));
    // set two flags according to slice type presented in the picture
    if (pcSlice->getSliceType() != I_SLICE)
    {
      picHeader->setPicInterSliceAllowedFlag(true);
    }
    if (pcSlice->getSliceType() == I_SLICE)
    {
      picHeader->setPicIntraSliceAllowedFlag(true);
    }
    picHeader->setGdrOrIrapPicFlag(picHeader->getGdrPicFlag() || pcSlice->isIRAP());

    if (m_pcCfg->getEfficientFieldIRAPEnabled())
    {
      if ( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL
        || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP
        || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA)  // IRAP picture
      {
        m_associatedIRAPType[pcPic->layerId] = pcSlice->getNalUnitType();//IRAP帧所在时域层标记NAL单元类型
        m_associatedIRAPPOC[pcPic->layerId] = pocCurr;//IRAP帧所在时域层标记当前帧的POC序号
        if (m_pcEncLib->getEdrapIndicationSEIEnabled())
        {
          m_latestEDRAPPOC = MAX_INT;
          pcPic->setEdrapRapId(0);
        }
      }
      pcSlice->setAssociatedIRAPType(m_associatedIRAPType[pcPic->layerId]);//设置IRAP帧对应时域层的NALU类型
      pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC[pcPic->layerId]);//设置IRAP帧对应时域层的POC序号
    }

setNalUnitType():设置NALU的类型

前两个if:判断是否是I_SLICE,然后设置pictureheader的m_picIntraSliceAllowedFlag标志位,设为true

Gdr(gradual decoding refresh picture )逐步解码刷新帧。GDR(Gradual Decoder Refresh)帧_KeepSimpleKeepHungry的博客-CSDN博客_gdr编码

isIRAP():return一个getNalUnitType()的值,限定在7~9,即IDR_W_RADL,IDR_N_LP,CRA这三个模式。RADL帧的解释在万帅书p273和p280,还有VVC正式标准的87页

setGdrOrIrapPicFlag(): 判断并设置Gdr或Irap帧的标志位

getEfficientFieldIRAPEnabled():允许以特定的、可能更有效的顺序编码场。

时域层:根据万帅书p275页,每幅图像都有一个标识所属时域层的时域层标识号,低层图像(时域层标识号小)不适用比其时域层高的图像作参考。也就是说,低层图像解码不依赖比其时域层高的图像。IRAP图像的时域层标识号为0,既属于第0个时域层。

 m_associatedIRAPType[pcPic->layerId]和_associatedIRAPPOC[pcPic->layerId]:为对应时域层的IRAP帧赋给相应的NALU类型,POC序号

getEdrapIndicationSEIEnabled():这个函数暂时不知道

    pcSlice->decodingRefreshMarking(m_pocCRA, m_bRefreshPending, rcListPic, m_pcCfg->getEfficientFieldIRAPEnabled());//重置某些帧的referenced和m_hashMap,更新m_pocCRA。m_pocCRA表示编码顺序之前最近CRA帧的POC
    if (m_pcCfg->getUseCompositeRef() && isEncodeLtRef)
    {
      setUseLTRef(true);
      setPrepareLTRef(false);
      setNewestBgPOC(pocCurr);
      setLastLTRefPoc(pocCurr);
    }
    else if (m_pcCfg->getUseCompositeRef() && getLastLTRefPoc() >= 0 && getEncodedLTRef()==false && !getPicBg()->getSpliceFull() && (pocCurr - getLastLTRefPoc()) > (m_pcCfg->getFrameRate() * 2))
    {
      setUseLTRef(false);
      setPrepareLTRef(false);
      setEncodedLTRef(true);
      setNewestBgPOC(-1);
      setLastLTRefPoc(-1);
    }

    if (m_pcCfg->getUseCompositeRef() && m_picBg->getSpliceFull() && getUseLTRef())
    {
      m_pcEncLib->selectReferencePictureList(pcSlice, pocCurr, iGOPid, m_bgPOC);
    }
    else
    {
      m_pcEncLib->selectReferencePictureList(pcSlice, pocCurr, iGOPid, -1);
    }
    if (!m_pcCfg->getEfficientFieldIRAPEnabled())
    {
      if ( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL
        || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP
        || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA)  // IRAP picture
      {
        m_associatedIRAPType[pcPic->layerId] = pcSlice->getNalUnitType();
        m_associatedIRAPPOC[pcPic->layerId] = pocCurr;
        if (m_pcEncLib->getEdrapIndicationSEIEnabled())
        {
          m_latestEDRAPPOC = MAX_INT;
          pcPic->setEdrapRapId(0);
        }
      }
      pcSlice->setAssociatedIRAPType(m_associatedIRAPType[pcPic->layerId]);
      pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC[pcPic->layerId]);
    }

    pcSlice->setEnableDRAPSEI(m_pcEncLib->getDependentRAPIndicationSEIEnabled());
    if (m_pcEncLib->getDependentRAPIndicationSEIEnabled())
    {
      // Only mark the picture as DRAP if all of the following applies:
      //  1) DRAP indication SEI messages are enabled
      //  2) The current picture is not an intra picture
      //  3) The current picture is in the DRAP period
      //  4) The current picture is a trailing picture
      pcSlice->setDRAP(m_pcEncLib->getDependentRAPIndicationSEIEnabled() && m_pcEncLib->getDrapPeriod() > 0 && !pcSlice->isIntra() &&
              pocCurr % m_pcEncLib->getDrapPeriod() == 0 && pocCurr > pcSlice->getAssociatedIRAPPOC());

      if (pcSlice->isDRAP())
      {
        int pocCycle = 1 << (pcSlice->getSPS()->getBitsForPOC());
        int deltaPOC = pocCurr > pcSlice->getAssociatedIRAPPOC() ? pocCurr - pcSlice->getAssociatedIRAPPOC() : pocCurr - ( pcSlice->getAssociatedIRAPPOC() & (pocCycle -1) );
        CHECK(deltaPOC > (pocCycle >> 1), "Use a greater value for POC wraparound to enable a POC distance between IRAP and DRAP of " << deltaPOC << ".");
        m_latestDRAPPOC = pocCurr;
        pcSlice->setTLayer(0); // Force DRAP picture to have temporal layer 0
      }
      pcSlice->setLatestDRAPPOC(m_latestDRAPPOC);
      pcSlice->setUseLTforDRAP(false); // When set, sets the associated IRAP as long-term in RPL0 at slice level, unless the associated IRAP is already included in RPL0 or RPL1 defined in SPS

      PicList::iterator iterPic = rcListPic.begin();
      Picture *rpcPic;
      while (iterPic != rcListPic.end())
      {
        rpcPic = *(iterPic++);
        if ( pcSlice->isDRAP() && rpcPic->getPOC() != pocCurr )
        {
          rpcPic->precedingDRAP = true;
        }
        else if ( !pcSlice->isDRAP() && rpcPic->getPOC() == pocCurr )
        {
          rpcPic->precedingDRAP = false;
        }
      }
    }

    pcSlice->setEnableEdrapSEI(m_pcEncLib->getEdrapIndicationSEIEnabled());
    if (m_pcEncLib->getEdrapIndicationSEIEnabled())
    {
      // Only mark the picture as Extended DRAP if all of the following applies:
      //  1) Extended DRAP indication SEI messages are enabled
      //  2) The current picture is not an intra picture
      //  3) The current picture is in the EDRAP period
      //  4) The current picture is a trailing picture
      if (m_pcEncLib->getEdrapIndicationSEIEnabled() && m_pcEncLib->getEdrapPeriod() > 0 && !pcSlice->isIntra() &&
          pocCurr % m_pcEncLib->getEdrapPeriod() == 0 && pocCurr > pcSlice->getAssociatedIRAPPOC())
      {
        pcSlice->setEdrapRapId(pocCurr / m_pcEncLib->getEdrapPeriod());
        pcSlice->getPic()->setEdrapRapId(pocCurr / m_pcEncLib->getEdrapPeriod());
      }

      if (pcSlice->getEdrapRapId() > 0)
      {
        m_latestEDRAPPOC = pocCurr;
        m_latestEdrapLeadingPicDecodableFlag = false;
        pcSlice->setTLayer(0); // Force Extended DRAP picture to have temporal layer 0
        msg( NOTICE, "Force the temporal sublayer identifier of the EDRAP picture equal to 0.\n");
      }
      pcSlice->setLatestEDRAPPOC(m_latestEDRAPPOC);
      pcSlice->setLatestEdrapLeadingPicDecodableFlag(m_latestEdrapLeadingPicDecodableFlag);
      pcSlice->setUseLTforEdrap(false); // When set, sets the associated IRAP/EDRAP as long-term in RPL0 at slice level, unless the associated IRAP/EDRAP is already included in RPL0 or RPL1 defined in SPS

      PicList::iterator iterPic = rcListPic.begin();
      Picture *rpcPic;
      while (iterPic != rcListPic.end())
      {
        rpcPic = *(iterPic++);
        if ( pcSlice->getEdrapRapId() > 0 && rpcPic->getPOC() != pocCurr && rpcPic->getPOC() >= pcSlice->getAssociatedIRAPPOC() )
        {
          if (rpcPic->getEdrapRapId() >= 0 && rpcPic->getPOC() % m_pcEncLib->getEdrapPeriod() == 0)
          {
            bool bRefExist = false;
            for (int i = 0; i < pcSlice->getEdrapNumRefRapPics(); i++)
            {
              if (pcSlice->getEdrapRefRapId(i) == rpcPic->getEdrapRapId())
                bRefExist = true;
            }
            if (!bRefExist)
            {
              pcSlice->addEdrapRefRapIds(rpcPic->getPOC() / m_pcEncLib->getEdrapPeriod());
              pcSlice->setEdrapNumRefRapPics(pcSlice->getEdrapNumRefRapPics() + 1);
            }
          }
        }
      }
    }

    if (pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPL0(), 0, false) != 0 || pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPL1(), 1, false) != 0 ||
        (m_pcEncLib->getDependentRAPIndicationSEIEnabled() && !pcSlice->isIRAP() && ( pcSlice->isDRAP() || !pcSlice->isPOCInRefPicList(pcSlice->getRPL0(), pcSlice->getAssociatedIRAPPOC())) ) ||
        (m_pcEncLib->getEdrapIndicationSEIEnabled() && !pcSlice->isIRAP() && ( pcSlice->getEdrapRapId() > 0 || !pcSlice->isPOCInRefPicList(pcSlice->getRPL0(), pcSlice->getAssociatedIRAPPOC()) ) )
      || ((m_pcEncLib->getAvoidIntraInDepLayer() || !pcSlice->isIRAP()) && pcSlice->getPic()->cs->vps && m_pcEncLib->getNumRefLayers(pcSlice->getPic()->cs->vps->getGeneralLayerIdx(m_pcEncLib->getLayerId())))
      )
    {
      xCreateExplicitReferencePictureSetFromReference( pcSlice, rcListPic, pcSlice->getRPL0(), pcSlice->getRPL1() );
    }

    pcSlice->applyReferencePictureListBasedMarking( rcListPic, pcSlice->getRPL0(), pcSlice->getRPL1(), pcSlice->getPic()->layerId, *(pcSlice->getPPS()));

    if(pcSlice->getTLayer() > 0
      && !(pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL     // Check if not a leading picture
        || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL)
        )
    {
      if (pcSlice->isStepwiseTemporalLayerSwitchingPointCandidate(rcListPic))
      {
        bool isSTSA=true;

        for(int ii=0;(ii<m_pcCfg->getGOPSize() && isSTSA==true);ii++)
        {
          int lTid = m_pcCfg->getRPLEntry(0, ii).m_temporalId;

          if (lTid == pcSlice->getTLayer())
          {
            const ReferencePictureList* rpl0 = pcSlice->getSPS()->getRPLList0()->getReferencePictureList(ii);
            for (int jj = 0; jj < pcSlice->getRPL0()->getNumberOfActivePictures(); jj++)
            {
              int tPoc = pcSlice->getPOC() + rpl0->getRefPicIdentifier(jj);
              int kk = 0;
              for (kk = 0; kk<m_pcCfg->getGOPSize(); kk++)
              {
                if (m_pcCfg->getRPLEntry(0, kk).m_POC == tPoc)
                {
                  break;
                }
              }
              int tTid = m_pcCfg->getRPLEntry(0, kk).m_temporalId;
              if (tTid >= pcSlice->getTLayer())
              {
                isSTSA = false;
                break;
              }
            }
            const ReferencePictureList* rpl1 = pcSlice->getSPS()->getRPLList1()->getReferencePictureList(ii);
            for (int jj = 0; jj < pcSlice->getRPL1()->getNumberOfActivePictures(); jj++)
            {
              int tPoc = pcSlice->getPOC() + rpl1->getRefPicIdentifier(jj);
              int kk = 0;
              for (kk = 0; kk<m_pcCfg->getGOPSize(); kk++)
              {
                if (m_pcCfg->getRPLEntry(1, kk).m_POC == tPoc)
                {
                  break;
                }
              }
              int tTid = m_pcCfg->getRPLEntry(1, kk).m_temporalId;
              if (tTid >= pcSlice->getTLayer())
              {
                isSTSA = false;
                break;
              }
            }
          }
        }
        if(isSTSA==true)
        {
          pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_STSA);
        }
      }
    }

    if (m_pcCfg->getUseCompositeRef() && getUseLTRef() && (pocCurr > getLastLTRefPoc()))
    {
      pcSlice->setNumRefIdx(REF_PIC_LIST_0, (pcSlice->isIntra()) ? 0 : min(m_pcCfg->getRPLEntry(0, iGOPid).m_numRefPicsActive + 1, pcSlice->getRPL0()->getNumberOfActivePictures()));
      pcSlice->setNumRefIdx(REF_PIC_LIST_1, (!pcSlice->isInterB()) ? 0 : min(m_pcCfg->getRPLEntry(1, iGOPid).m_numRefPicsActive + 1, pcSlice->getRPL1()->getNumberOfActivePictures()));
    }
    else
    {
      pcSlice->setNumRefIdx(REF_PIC_LIST_0, (pcSlice->isIntra()) ? 0 : pcSlice->getRPL0()->getNumberOfActivePictures());
      pcSlice->setNumRefIdx(REF_PIC_LIST_1, (!pcSlice->isInterB()) ? 0 : pcSlice->getRPL1()->getNumberOfActivePictures());
    }
    if (m_pcCfg->getUseCompositeRef() && getPrepareLTRef())
    {
      arrangeCompositeReference(pcSlice, rcListPic, pocCurr);
    }
    //  Set reference list
    pcSlice->constructRefPicList(rcListPic);

decodingRefreshMarking():重置某些帧的referenced和m_hashMap,更新m_pocCRA。m_pocCRA表示编码顺序之前最近CRA帧的POC.当遇到IDR/CRA/CRANT/BLA/BLANT时,标记参考图片.具体函数之后再看

第一个if语句:getUseCompositeRef():复合参考列表?PicBg:不知道什么意思。跳过

第二个if语句:selectReferencePictureList():设置slice的RPL0和RPL1.

第三个if语句getEfficientFieldIRAPEnabled()在前面已经设置过了,所以跳过。

2349行~~2437行与图片标记为DRAP和EDRAP有关,暂时不考虑

setEnableDRAPSEI():DRAP(Dependent Random Access Point),设置m_enableDRAPSEI

checkThatAllRefPicsAreAvailable():检查图像参考列表是否存在。4个参数:rcListPic( m_cListPic):动态图片列表。pRPL:参考图像列表。rplIdx:参考图像列表序号。printErrors:错误输出

if语句中还有几个判断函数和DARP,EDRAP,layer有关,暂时不看,以后再说

xCreateExplicitReferencePictureSetFromReference():用来解决参考帧无效的情况。没仔细看

applyReferencePictureListBasedMarking():根据图像参考列表来申请图像标记 。(1)检查是否应该保留为参考图片(2)如果图片未在参考图像列表中,标记为unused picture(3)标记long~term 图片

接下来的if语句(if(pcSlice->getTLayer() > 0......):检查当前编码帧是不是STSA

if (m_pcCfg->getUseCompositeRef() && getUseLTRef() && (pocCurr > getLastLTRefPoc())):

推测因为我使用的是encoder_intra_vtm的设置,都是I帧,所以不需要参考帧。所以getUseLTRef() ,推测意思是左边的参考帧都为0.这一段在改变设置后可重新验证一次

setNumRefIdx():设置m_aiNumRefIdx,表示参考帧的数量。I帧都是0,P帧RPL1的参考帧数量为0。

constructRefPicList():构建参考帧列表

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值