Skip to content
Snippets Groups Projects
EncGOP.cpp 184 KiB
Newer Older
  • Learn to ignore specific revisions
  •     {
          if (!m_pcReshaper->getReshapeFlag())
          {
            m_pcReshaper->setCTUFlag(false);
          }
          else
            m_pcReshaper->setCTUFlag(true);
    
          m_pcReshaper->getSliceReshaperInfo().setSliceReshapeModelPresentFlag(false);
    
          if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ)
          {
            m_pcEncLib->getRdCost()->restoreReshapeLumaLevelToWeightTable();
          }
    #if JVET_O0432_LMCS_ENCODER
          else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR || m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_HLG)
          {
            int modIP = pic->getPOC() - pic->getPOC() / m_pcCfg->getReshapeCW().rspFpsToIp * m_pcCfg->getReshapeCW().rspFpsToIp;
            if (m_pcReshaper->getReshapeFlag() && m_pcCfg->getReshapeCW().updateCtrl == 2 && modIP == 0)
            {
              m_pcReshaper->getSliceReshaperInfo().setSliceReshapeModelPresentFlag(true);
              m_pcReshaper->constructReshaperLMCS();
              m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTable(m_pcReshaper->getSliceReshaperInfo(), m_pcReshaper->getWeightTable(), m_pcReshaper->getCWeight());
            }
          }
    #else
          else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR)
          {
            int modIP = pic->getPOC() - pic->getPOC() / m_pcCfg->getReshapeCW().rspFpsToIp * m_pcCfg->getReshapeCW().rspFpsToIp;
            if (m_pcReshaper->getReshapeFlag() && m_pcCfg->getReshapeCW().rspIntraPeriod == -1 && modIP == 0)           // for LDB, update reshaping curve every second
            {
              m_pcReshaper->getSliceReshaperInfo().setSliceReshapeModelPresentFlag(true);
              m_pcReshaper->constructReshaperSDR();
              m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTable(m_pcReshaper->getSliceReshaperInfo(), m_pcReshaper->getWeightTable(), m_pcReshaper->getCWeight());
            }
          }
    #endif
          else
          {
            THROW("Reshaper for other signal currently not defined!");
          }
        }
    
        //set all necessary information in LMCS APS and slice
        slice->setLmcsEnabledFlag(m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper());
        slice->setLmcsChromaResidualScaleFlag(m_pcReshaper->getSliceReshaperInfo().getSliceReshapeChromaAdj() == 1);
        if (m_pcReshaper->getSliceReshaperInfo().getSliceReshapeModelPresentFlag())
        {
          int apsId = 0;
          slice->setLmcsAPSId(apsId);
          APS* lmcsAPS = slice->getLmcsAPS();
          if (lmcsAPS == nullptr)
          {
            ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
            lmcsAPS = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
            if (lmcsAPS == NULL)
            {
              lmcsAPS = apsMap->allocatePS((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
              lmcsAPS->setAPSId(apsId);
              lmcsAPS->setAPSType(LMCS_APS);
            }
            slice->setLmcsAPS(lmcsAPS);
          }
          //m_pcReshaper->copySliceReshaperInfo(lmcsAPS->getReshaperAPSInfo(), m_pcReshaper->getSliceReshaperInfo());
          SliceReshapeInfo& tInfo = lmcsAPS->getReshaperAPSInfo();
          SliceReshapeInfo& sInfo = m_pcReshaper->getSliceReshaperInfo();
          tInfo.reshaperModelMaxBinIdx = sInfo.reshaperModelMaxBinIdx;
          tInfo.reshaperModelMinBinIdx = sInfo.reshaperModelMinBinIdx;
          memcpy(tInfo.reshaperModelBinCWDelta, sInfo.reshaperModelBinCWDelta, sizeof(int)*(PIC_CODE_CW_BINS));
          tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW;
          m_pcEncLib->getApsMap()->setChangedFlag((lmcsAPS->getAPSId() << NUM_APS_TYPE_LEN) + LMCS_APS);
        }
    
        if (slice->getLmcsEnabledFlag())
        {
          int apsId = 0;
          slice->setLmcsAPSId(apsId);
        }
      }
      else
      {
        m_pcReshaper->setCTUFlag(false);
      }
    }
    
    
    // ====================================================================================================================
    // Public member functions
    // ====================================================================================================================
    void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
                              std::list<PelUnitBuf*>& rcListPicYuvRecOut,
    
                              bool isField, bool isTff, const InputColourSpaceConversion snr_conversion, const bool printFrameMSE
                            , bool isEncodeLtRef
    )
    
    {
      // TODO: Split this function up.
    
      Picture*        pcPic = NULL;
      Slice*      pcSlice;
      OutputBitstream  *pcBitstreamRedirect;
      pcBitstreamRedirect = new OutputBitstream;
      AccessUnit::iterator  itLocationToPushSliceHeaderNALU; // used to store location where NALU containing slice header is to be inserted
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      Picture* scaledRefPic[MAX_NUM_REF] = {};
    
      xInitGOP(iPOCLast, iNumPicRcvd, isField
             , isEncodeLtRef
      );
    
    
      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);
      }
    
      // reset flag indicating whether pictures have been encoded
      for ( int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ )
      {
        m_pcCfg->setEncodedFlag(iGOPid, false);
      }
    
      for ( int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ )
      {
        if (m_pcCfg->getEfficientFieldIRAPEnabled())
        {
          iGOPid=effFieldIRAPMap.adjustGOPid(iGOPid);
        }
    
        //-- For time output for each slice
        auto beforeTime = std::chrono::steady_clock::now();
    
    #if !X0038_LAMBDA_FROM_QP_CAPABILITY
        uint32_t uiColDir = calculateCollocatedFromL1Flag(m_pcCfg, iGOPid, m_iGopSize);
    #endif
    
        /////////////////////////////////////////////////////////////////////////////////////////////////// Initial to start encoding
        int iTimeOffset;
        int pocCurr;
    
        int multipleFactor = m_pcCfg->getUseCompositeRef() ? 2 : 1;
    
    
        if(iPOCLast == 0) //case first frame or first top field
        {
          pocCurr=0;
    
        }
        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 = 1;
        }
        else
        {
    
          pocCurr = iPOCLast - iNumPicRcvd * multipleFactor + m_pcCfg->getGOPEntry(iGOPid).m_POC - ((isField && m_iGopSize>1) ? 1 : 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;
        }
    
        // start a new access unit: create an entry in the list of output access units
        AccessUnit accessUnit;
        xGetBuffer( rcListPic, rcListPicYuvRecOut,
                    iNumPicRcvd, iTimeOffset, pcPic, pocCurr, isField );
    
    
    #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;
        }
    
    #if JVET_O1164_PS
        // 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();
        const int maxCUHeight = pcPic->cs->sps->getMaxCUHeight();
        const ChromaFormat chromaFormatIDC = pcPic->cs->sps->getChromaFormatIdc();
        const int maxTotalCUDepth = pcPic->cs->sps->getMaxCodingDepth();
    
        m_pcSliceEncoder->create( picWidth, picHeight, chromaFormatIDC, maxCUWidth, maxCUHeight, maxTotalCUDepth );
    #endif
    
    
    #if ENABLE_SPLIT_PARALLELISM && ENABLE_WPP_PARALLELISM
        pcPic->scheduler.init( pcPic->cs->pcv->heightInCtus, pcPic->cs->pcv->widthInCtus, m_pcCfg->getNumWppThreads(), m_pcCfg->getNumWppExtraLines(), m_pcCfg->getNumSplitThreads() );
    #elif ENABLE_SPLIT_PARALLELISM
        pcPic->scheduler.init( pcPic->cs->pcv->heightInCtus, pcPic->cs->pcv->widthInCtus, 1                          , 0                             , m_pcCfg->getNumSplitThreads() );
    #elif ENABLE_WPP_PARALLELISM
        pcPic->scheduler.init( pcPic->cs->pcv->heightInCtus, pcPic->cs->pcv->widthInCtus, m_pcCfg->getNumWppThreads(), m_pcCfg->getNumWppExtraLines(), 1                             );
    #endif
        pcPic->createTempBuffers( pcPic->cs->pps->pcv->maxCUWidth );
        pcPic->cs->createCoeffs();
    
        //  Slice data initialization
        pcPic->clearSliceBuffer();
        pcPic->allocateNewSlice();
        m_pcSliceEncoder->setSliceSegmentIdx(0);
    
    
        m_pcSliceEncoder->initEncSlice(pcPic, iPOCLast, pocCurr, iGOPid, pcSlice, isField
          , isEncodeLtRef
        );
    
    
        DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) );
        DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 0 ) ) );
    
    #if !SHARP_LUMA_DELTA_QP
        //Set Frame/Field coding
        pcPic->fieldPic = isField;
    #endif
    
    
        pcSlice->setLastIDR(m_iLastIDR);
    
        pcSlice->setIndependentSliceIdx(0);
        //set default slice level flag to the same as SPS level flag
        pcSlice->setLFCrossSliceBoundaryFlag(  pcSlice->getPPS()->getLoopFilterAcrossSlicesEnabledFlag()  );
    
        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);
        }
        // Set the nal unit type
        pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField));
    
        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 = pcSlice->getNalUnitType();
            m_associatedIRAPPOC = pocCurr;
          }
          pcSlice->setAssociatedIRAPType(m_associatedIRAPType);
          pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC);
        }
    
        pcSlice->decodingRefreshMarking(m_pocCRA, m_bRefreshPending, rcListPic, m_pcCfg->getEfficientFieldIRAPEnabled());
    
        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);
        }
    
    
    Hendry's avatar
    Hendry committed
        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 ( 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 = pcSlice->getNalUnitType();
            m_associatedIRAPPOC = pocCurr;
          }
          pcSlice->setAssociatedIRAPType(m_associatedIRAPType);
          pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC);
        }
    
    
    #if JVET_N0494_DRAP
        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;
            }
          }
        }
    
        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())) ))
    #else
    
    Hendry's avatar
    Hendry committed
        if (pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPL0(), 0, false) != 0 || pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPL1(), 1, false) != 0)
    
    Hendry's avatar
    Hendry committed
        {
          pcSlice->createExplicitReferencePictureSetFromReference(rcListPic, pcSlice->getRPL0(), pcSlice->getRPL1());
        }
    
        pcSlice->applyReferencePictureListBasedMarking(rcListPic, pcSlice->getRPL0(), pcSlice->getRPL1());
    
          && !(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=iGOPid+1;(ii<m_pcCfg->getGOPSize() && isSTSA==true);ii++)
            {
    
    Hendry's avatar
    Hendry committed
              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 = m_pcCfg->getRPLEntry(0, ii).m_POC + 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 = m_pcCfg->getRPLEntry(1, ii).m_POC + 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;
                  }
                }
              }
    
              pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_STSA);
    
    Hendry's avatar
    Hendry committed
        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);
        }
    
    Hendry's avatar
    Hendry committed
        pcSlice->constructRefPicList(rcListPic);
    
        pcSlice->scaleRefPicList( scaledRefPic, m_pcEncLib->getApss(), pcSlice->getLmcsAPS(), pcSlice->getscalingListAPS(), false );
    
        pcSlice->scaleRefPicList( scaledRefPic, m_pcEncLib->getApss(), pcSlice->getLmcsAPS(), false );
    
    #if JVET_O1164_PS
        xPicInitHashME( pcPic, pcSlice->getPPS(), rcListPic );
    #else
    
        xPicInitHashME(pcPic, pcSlice->getSPS(), rcListPic);
    
          if( !pcSlice->isIRAP() )
    
          {
            int refLayer = pcSlice->getDepth();
            if( refLayer > 9 ) refLayer = 9; // Max layer is 10
    
            if( m_bInitAMaxBT && pcSlice->getPOC() > m_uiPrevISlicePOC )
            {
              ::memset( m_uiBlkSize, 0, sizeof( m_uiBlkSize ) );
              ::memset( m_uiNumBlk,  0, sizeof( m_uiNumBlk ) );
              m_bInitAMaxBT = false;
            }
    
            if( refLayer >= 0 && m_uiNumBlk[refLayer] != 0 )
            {
    
              pcSlice->setSplitConsOverrideFlag(true);
    
              double dBlkSize = sqrt( ( double ) m_uiBlkSize[refLayer] / m_uiNumBlk[refLayer] );
              if( dBlkSize < AMAXBT_TH32 )
              {
                pcSlice->setMaxBTSize( 32 > MAX_BT_SIZE_INTER ? MAX_BT_SIZE_INTER : 32 );
              }
              else if( dBlkSize < AMAXBT_TH64 )
              {
                pcSlice->setMaxBTSize( 64 > MAX_BT_SIZE_INTER ? MAX_BT_SIZE_INTER : 64 );
              }
              else
              {
                pcSlice->setMaxBTSize( 128 > MAX_BT_SIZE_INTER ? MAX_BT_SIZE_INTER : 128 );
              }
    
              m_uiBlkSize[refLayer] = 0;
              m_uiNumBlk [refLayer] = 0;
            }
          }
          else
          {
            if( m_bInitAMaxBT )
            {
              ::memset( m_uiBlkSize, 0, sizeof( m_uiBlkSize ) );
              ::memset( m_uiNumBlk,  0, sizeof( m_uiNumBlk ) );
            }
    
            m_uiPrevISlicePOC = pcSlice->getPOC();
            m_bInitAMaxBT = true;
          }
        }
    
        //  Slice info. refinement
        if ( (pcSlice->getSliceType() == B_SLICE) && (pcSlice->getNumRefIdx(REF_PIC_LIST_1) == 0) )
        {
          pcSlice->setSliceType ( P_SLICE );
        }
        xUpdateRasInit( pcSlice );
    
        if ( pcSlice->getPendingRasInit() )
        {
          // this ensures that independently encoded bitstream chunks can be combined to bit-equal
          pcSlice->setEncCABACTableIdx( pcSlice->getSliceType() );
        }
        else
        {
          pcSlice->setEncCABACTableIdx( m_pcSliceEncoder->getEncCABACTableIdx() );
        }
    
        if (pcSlice->getSliceType() == B_SLICE)
        {
    
    #if X0038_LAMBDA_FROM_QP_CAPABILITY
          const uint32_t uiColFromL0 = calculateCollocatedFromL0Flag(pcSlice);
          pcSlice->setColFromL0Flag(uiColFromL0);
    #else
          pcSlice->setColFromL0Flag(1-uiColDir);
    #endif
    
          bool bLowDelay = true;
          int  iCurrPOC  = pcSlice->getPOC();
          int iRefIdx = 0;
    
          for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0) && bLowDelay; iRefIdx++)
          {
            if ( pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC() > iCurrPOC )
            {
              bLowDelay = false;
            }
          }
          for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1) && bLowDelay; iRefIdx++)
          {
            if ( pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC() > iCurrPOC )
            {
              bLowDelay = false;
            }
          }
    
          pcSlice->setCheckLDC(bLowDelay);
        }
        else
        {
          pcSlice->setCheckLDC(true);
        }
    
    
    #if !X0038_LAMBDA_FROM_QP_CAPABILITY && !JVET_O1164_RPR
    
        uiColDir = 1-uiColDir;
    #endif
    
        //-------------------------------------------------------------
        pcSlice->setRefPOCList();
    
    
        pcSlice->setList1IdxToList0Idx();
    
    #if JVET_O0238_PPS_OR_SLICE
          assert (m_pcEncLib->getPPSTemporalMVPEnabledIdc() == 0);
    #endif
    
          if (iGOPid == 0) // first picture in SOP (i.e. forward B)
          {
            pcSlice->setEnableTMVPFlag(0);
          }
          else
          {
            // Note: pcSlice->getColFromL0Flag() is assumed to be always 0 and getcolRefIdx() is always 0.
            pcSlice->setEnableTMVPFlag(1);
          }
        }
    
        else if (m_pcEncLib->getTMVPModeId() == 1 && m_pcEncLib->getPPSTemporalMVPEnabledIdc() != 1)
    
        // disable TMVP when current picture is the only ref picture
    
    Yu Han's avatar
    Yu Han committed
        if (pcSlice->isIRAP() && pcSlice->getSPS()->getIBCFlag())
    
    #if JVET_O1164_RPR
        if( pcSlice->getSliceType() != I_SLICE && pcSlice->getEnableTMVPFlag() )
        {
          int colRefIdxL0 = -1, colRefIdxL1 = -1;
    
          for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); refIdx++ )
          {
            int refPicWidth = pcSlice->getRefPic( REF_PIC_LIST_0, refIdx )->unscaledPic->cs->pps->getPicWidthInLumaSamples();
            int refPicHeight = pcSlice->getRefPic( REF_PIC_LIST_0, refIdx )->unscaledPic->cs->pps->getPicHeightInLumaSamples();
            int curPicWidth = pcSlice->getPPS()->getPicWidthInLumaSamples();
            int curPicHeight = pcSlice->getPPS()->getPicHeightInLumaSamples();
    
            if( refPicWidth == curPicWidth && refPicHeight == curPicHeight )
            {
              colRefIdxL0 = refIdx;
              break;
            }
          }
    
          if( pcSlice->getSliceType() == B_SLICE )
          {
            for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); refIdx++ )
            {
              int refPicWidth = pcSlice->getRefPic( REF_PIC_LIST_1, refIdx )->unscaledPic->cs->pps->getPicWidthInLumaSamples();
              int refPicHeight = pcSlice->getRefPic( REF_PIC_LIST_1, refIdx )->unscaledPic->cs->pps->getPicHeightInLumaSamples();
              int curPicWidth = pcSlice->getPPS()->getPicWidthInLumaSamples();
              int curPicHeight = pcSlice->getPPS()->getPicHeightInLumaSamples();
    
              if( refPicWidth == curPicWidth && refPicHeight == curPicHeight )
              {
                colRefIdxL1 = refIdx;
                break;
              }
            }
          }
    
          if( colRefIdxL0 >= 0 && colRefIdxL1 >= 0 )
          {
            const Picture *refPicL0 = pcSlice->getRefPic( REF_PIC_LIST_0, colRefIdxL0 );
            if( !refPicL0->slices.size() )
            {
              refPicL0 = refPicL0->unscaledPic;
            }
    
            const Picture *refPicL1 = pcSlice->getRefPic( REF_PIC_LIST_1, colRefIdxL1 );
            if( !refPicL1->slices.size() )
            {
              refPicL1 = refPicL1->unscaledPic;
            }
    
            const uint32_t uiColFromL0 = refPicL0->slices[0]->getSliceQp() > refPicL1->slices[0]->getSliceQp();
            pcSlice->setColFromL0Flag( uiColFromL0 );
            pcSlice->setColRefIdx( uiColFromL0 ? colRefIdxL0 : colRefIdxL1 );
          }
          else if( colRefIdxL0 < 0 && colRefIdxL1 >= 0 )
          {
            pcSlice->setColFromL0Flag( false );
            pcSlice->setColRefIdx( colRefIdxL1 );
          }
          else if( colRefIdxL0 >= 0 && colRefIdxL1 < 0 )
          {
            pcSlice->setColFromL0Flag( true );
            pcSlice->setColRefIdx( colRefIdxL0 );
          }
          else
          {
            pcSlice->setEnableTMVPFlag( 0 );
          }
        }
    #endif
    
    
        // set adaptive search range for non-intra-slices
    
        if (m_pcCfg->getUseASR() && !pcSlice->isIRAP())
    
        {
          m_pcSliceEncoder->setSearchRange(pcSlice);
        }
    
        bool bGPBcheck=false;
        if ( pcSlice->getSliceType() == B_SLICE)
        {
          if ( pcSlice->getNumRefIdx(RefPicList( 0 ) ) == pcSlice->getNumRefIdx(RefPicList( 1 ) ) )
          {
            bGPBcheck=true;
            int i;
            for ( i=0; i < pcSlice->getNumRefIdx(RefPicList( 1 ) ); i++ )
            {
              if ( pcSlice->getRefPOC(RefPicList(1), i) != pcSlice->getRefPOC(RefPicList(0), i) )
              {
                bGPBcheck=false;
                break;
              }
            }
          }
        }
        if(bGPBcheck)
        {
          pcSlice->setMvdL1ZeroFlag(true);
        }
        else
        {
          pcSlice->setMvdL1ZeroFlag(false);
        }
    
    
        if ( pcSlice->getSPS()->getUseSMVD() && pcSlice->getCheckLDC() == false
    
    #if JVET_O0284_CONDITION_SMVD_MVDL1ZEROFLAG
          && pcSlice->getMvdL1ZeroFlag() == false
    #endif
    
        {
          int currPOC = pcSlice->getPOC();
    
          int forwardPOC = currPOC;
    
    Daniel's avatar
    Daniel committed
          int backwardPOC = currPOC;
    
          int ref = 0, refIdx0 = -1, refIdx1 = -1;
    
          // search nearest forward POC in List 0
          for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
          {
            int poc = pcSlice->getRefPic( REF_PIC_LIST_0, ref )->getPOC();
    
            const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_0, ref)->longTerm;
            if ( poc < currPOC && (poc > forwardPOC || refIdx0 == -1) && !isRefLongTerm )
    
            if ( poc < currPOC && (poc > forwardPOC || refIdx0 == -1) )
    
            {
              forwardPOC = poc;
              refIdx0 = ref;
            }
          }
    
          // search nearest backward POC in List 1
          for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
          {
            int poc = pcSlice->getRefPic( REF_PIC_LIST_1, ref )->getPOC();
    
            const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_1, ref)->longTerm;
            if ( poc > currPOC && (poc < backwardPOC || refIdx1 == -1) && !isRefLongTerm )
    
    Daniel's avatar
    Daniel committed
            if ( poc > currPOC && (poc < backwardPOC || refIdx1 == -1) )
    
    Daniel's avatar
    Daniel committed
              backwardPOC = poc;
    
    Daniel's avatar
    Daniel committed
          if ( !(forwardPOC < currPOC && backwardPOC > currPOC) )
    
          {
            forwardPOC = currPOC;
    
    Daniel's avatar
    Daniel committed
            backwardPOC = currPOC;
    
            refIdx0 = -1;
            refIdx1 = -1;
    
            // search nearest backward POC in List 0
            for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
            {
              int poc = pcSlice->getRefPic( REF_PIC_LIST_0, ref )->getPOC();
    
              const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_0, ref)->longTerm;
              if ( poc > currPOC && (poc < backwardPOC || refIdx0 == -1) && !isRefLongTerm )
    
    Daniel's avatar
    Daniel committed
              if ( poc > currPOC && (poc < backwardPOC || refIdx0 == -1) )
    
    Daniel's avatar
    Daniel committed
                backwardPOC = poc;
    
                refIdx0 = ref;
              }
            }
    
            // search nearest forward POC in List 1
            for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
            {
              int poc = pcSlice->getRefPic( REF_PIC_LIST_1, ref )->getPOC();
    
              const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_1, ref)->longTerm;
              if ( poc < currPOC && (poc > forwardPOC || refIdx1 == -1) && !isRefLongTerm )
    
              if ( poc < currPOC && (poc > forwardPOC || refIdx1 == -1) )
    
    Daniel's avatar
    Daniel committed
          if ( forwardPOC < currPOC && backwardPOC > currPOC )
    
          {
            pcSlice->setBiDirPred( true, refIdx0, refIdx1 );
          }
          else
          {
            pcSlice->setBiDirPred( false, -1, -1 );
          }
        }
        else
        {
          pcSlice->setBiDirPred( false, -1, -1 );
        }
    
    
        double lambda            = 0.0;
        int actualHeadBits       = 0;
        int actualTotalBits      = 0;
        int estimatedBits        = 0;
        int tmpBitsBeforeWriting = 0;
    
        xPicInitRateControl(estimatedBits, iGOPid, lambda, pcPic, pcSlice);
    
    
        uint32_t uiNumSliceSegments = 1;
    
        {
          pcSlice->setDefaultClpRng( *pcSlice->getSPS() );
        }
    
        // Allocate some coders, now the number of tiles are known.
        const uint32_t numberOfCtusInFrame = pcPic->cs->pcv->sizeInCtus;
        const int numSubstreamsColumns = (pcSlice->getPPS()->getNumTileColumnsMinus1() + 1);
        const int numSubstreamRows     = pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag() ? pcPic->cs->pcv->heightInCtus : (pcSlice->getPPS()->getNumTileRowsMinus1() + 1);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        const int numSubstreams        = std::max<int> (numSubstreamRows * numSubstreamsColumns, (int) pcPic->brickMap->bricks.size());
    
        std::vector<OutputBitstream> substreamsOut(numSubstreams);
    
    #if ENABLE_QPA
    
        pcPic->m_uEnerHpCtu.resize (numberOfCtusInFrame);
        pcPic->m_iOffsetCtu.resize (numberOfCtusInFrame);
    
    #if ENABLE_QPA_SUB_CTU
        if (pcSlice->getPPS()->getUseDQP() && pcSlice->getPPS()->getCuQpDeltaSubdiv() > 0)
    
    #if MAX_TB_SIZE_SIGNALLING
    
          const unsigned   mtsLog2 = (unsigned)floorLog2(std::min (pcPic->cs->sps->getMaxTbSize(), pcv.maxCUWidth));
    
          const unsigned   mtsLog2 = (unsigned)floorLog2(std::min<uint32_t> (MAX_TB_SIZEY, pcv.maxCUWidth));
    
          pcPic->m_subCtuQP.resize ((pcv.maxCUWidth >> mtsLog2) * (pcv.maxCUHeight >> mtsLog2));
        }
    
        if (pcSlice->getSPS()->getSAOEnabledFlag())
    
        {
          pcPic->resizeSAO( numberOfCtusInFrame, 0 );
          pcPic->resizeSAO( numberOfCtusInFrame, 1 );
        }
    
        // it is used for signalling during CTU mode decision, i.e. before ALF processing
    
        if( pcSlice->getSPS()->getALFEnabledFlag() )
    
        {
          pcPic->resizeAlfCtuEnableFlag( numberOfCtusInFrame );
    
    #if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
          pcPic->resizeAlfCtuAlternative( numberOfCtusInFrame );
    #endif
    
          pcPic->resizeAlfCtbFilterIndex(numberOfCtusInFrame);
    
        }
    
        bool decPic = false;
        bool encPic = false;
        // test if we can skip the picture entirely or decode instead of encoding
        trySkipOrDecodePicture( decPic, encPic, *m_pcCfg, pcPic );
    
        pcPic->cs->slice = pcSlice; // please keep this
    
    #if ENABLE_QPA
        if (pcSlice->getPPS()->getSliceChromaQpFlag() && CS::isDualITree (*pcSlice->getPic()->cs) && !m_pcCfg->getUsePerceptQPA() && (m_pcCfg->getSliceChromaOffsetQpPeriodicity() == 0))
    #else
        if (pcSlice->getPPS()->getSliceChromaQpFlag() && CS::isDualITree (*pcSlice->getPic()->cs))
    #endif
    
        {
          // overwrite chroma qp offset for dual tree
          pcSlice->setSliceChromaQpDelta(COMPONENT_Cb, m_pcCfg->getChromaCbQpOffsetDualTree());
          pcSlice->setSliceChromaQpDelta(COMPONENT_Cr, m_pcCfg->getChromaCrQpOffsetDualTree());
    
    #if JVET_O0376_SPS_JOINTCBCR_FLAG
          if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
    
    Fangdong Chen's avatar
    Fangdong Chen committed
          {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            pcSlice->setSliceChromaQpDelta(JOINT_CbCr, m_pcCfg->getChromaCbCrQpOffsetDualTree());
    
    Fangdong Chen's avatar
    Fangdong Chen committed
          }
    #else
          pcSlice->setSliceChromaQpDelta(JOINT_CbCr, m_pcCfg->getChromaCbCrQpOffsetDualTree());
    #endif
    
          m_pcSliceEncoder->setUpLambda(pcSlice, pcSlice->getLambdas()[0], pcSlice->getSliceQp());
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        }
    
    #if JVET_O0299_APS_SCALINGLIST
        if( pcSlice->getSPS()->getScalingListFlag() && m_pcCfg->getUseScalingListId() == SCALING_LIST_FILE_READ )
        {
          pcSlice->setscalingListPresentFlag( true );
          int apsId = 0;
          pcSlice->setscalingListAPSId( apsId );
    
          ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
          APS*  scalingListAPS = apsMap->getPS( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
          assert( scalingListAPS != NULL );
          pcSlice->setscalingListAPS( scalingListAPS );
        }
    #endif
    
    
        if( encPic )
        // now compress (trial encode) the various slice segments (slices, and dependent slices)
        {
          DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) );
    
    
          uint32_t sliceIdx = 0;
          const BrickMap& tileMap = *(pcPic->brickMap);
    
          for(uint32_t nextCtuTsAddr = 0; nextCtuTsAddr < numberOfCtusInFrame; )
          {
            m_pcSliceEncoder->precompressSlice( pcPic );
            m_pcSliceEncoder->compressSlice   ( pcPic, false, false );
    
            const uint32_t curSliceEnd = pcSlice->getSliceCurEndCtuTsAddr();
    
            pcSlice->setSliceIndex(sliceIdx);
    
            if(curSliceEnd < numberOfCtusInFrame)
            {
              uint32_t independentSliceIdx = pcSlice->getIndependentSliceIdx();
              pcPic->allocateNewSlice();
              m_pcSliceEncoder->setSliceSegmentIdx      (uiNumSliceSegments);
              // prepare for next slice
              pcSlice = pcPic->slices[uiNumSliceSegments];
              CHECK(!(pcSlice->getPPS() != 0), "Unspecified error");
              pcSlice->copySliceInfo(pcPic->slices[uiNumSliceSegments - 1]);
    
              sliceIdx++;
              if (pcSlice->getPPS()->getRectSliceFlag())
              {
                uint32_t startTileIdx = pcSlice->getPPS()->getTopLeftBrickIdx(sliceIdx);
                uint32_t nextCtu = 0;
                uint32_t tmpSliceIdx = 0;
                while (tmpSliceIdx != startTileIdx)
                {
                  nextCtu++;
                  tmpSliceIdx = tileMap.getBrickIdxBsMap(nextCtu);
                }
                pcSlice->setSliceCurStartCtuTsAddr(nextCtu);
              }
              else
              {
                pcSlice->setSliceCurStartCtuTsAddr(curSliceEnd);
              }
    
              pcSlice->setSliceBits(0);
              independentSliceIdx++;
              pcSlice->setIndependentSliceIdx(independentSliceIdx);
              uiNumSliceSegments++;
            }
            nextCtuTsAddr = curSliceEnd;
          }
    
          duData.clear();
    
          CodingStructure& cs = *pcPic->cs;
          pcSlice = pcPic->slices[0];
    
    
    Taoran Lu's avatar
    Taoran Lu committed
          if (pcSlice->getSPS()->getUseReshaper() && m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper())
          {
    
            pcSlice->setLmcsEnabledFlag(true);
            int apsId = 0;
            pcSlice->setLmcsAPSId(apsId);
            for (int s = 0; s < uiNumSliceSegments; s++)
            {
              pcPic->slices[s]->setLmcsEnabledFlag(pcSlice->getLmcsEnabledFlag());
              pcPic->slices[s]->setLmcsChromaResidualScaleFlag((pcSlice->getLmcsChromaResidualScaleFlag()));
              if (pcSlice->getLmcsEnabledFlag())
              {
                //pcPic->slices[s]->setLmcsAPS(pcSlice->getLmcsAPS());
                pcPic->slices[s]->setLmcsAPSId(pcSlice->getLmcsAPSId());
              }
            }
    
    Taoran Lu's avatar
    Taoran Lu committed
              CHECK((m_pcReshaper->getRecReshaped() == false), "Rec picture is not reshaped!");
              pcPic->getRecoBuf(COMPONENT_Y).rspSignal(m_pcReshaper->getInvLUT());
              m_pcReshaper->setRecReshaped(false);
    
              pcPic->getOrigBuf().copyFrom(pcPic->getTrueOrigBuf());
          }
    
    
    #if JVET_O1164_PS
          // create SAO object based on the picture size
          if( pcSlice->getSPS()->getSAOEnabledFlag() )
          {
            const uint32_t widthInCtus = ( picWidth + maxCUWidth - 1 ) / maxCUWidth;
            const uint32_t heightInCtus = ( picHeight + maxCUHeight - 1 ) / maxCUHeight;
            const uint32_t numCtuInFrame = widthInCtus * heightInCtus;
    
            const uint32_t log2SaoOffsetScaleLuma = pcPic->cs->slice->getPPS()->getPpsRangeExtension().getLog2SaoOffsetScale( CHANNEL_TYPE_LUMA );
            const uint32_t log2SaoOffsetScaleChroma = pcPic->cs->slice->getPPS()->getPpsRangeExtension().getLog2SaoOffsetScale( CHANNEL_TYPE_CHROMA );
    
            m_pcSAO->create( picWidth, picHeight, chromaFormatIDC, maxCUWidth, maxCUHeight, maxTotalCUDepth, log2SaoOffsetScaleLuma, log2SaoOffsetScaleChroma );
            m_pcSAO->destroyEncData();
            m_pcSAO->createEncData( m_pcCfg->getSaoCtuBoundary(), numCtuInFrame );
            m_pcSAO->setReshaper( m_pcReshaper );
          }
    
          if( !m_pcEncLib->getLoopFilterDisable() )
          {
            m_pcEncLib->getLoopFilter()->initEncPicYuvBuffer( chromaFormatIDC, picWidth, picHeight );
          }
    #endif
    
    
    #if JVET_O0299_APS_SCALINGLIST
          if( pcSlice->getSPS()->getScalingListFlag() && m_pcCfg->getUseScalingListId() == SCALING_LIST_FILE_READ )
          {
            pcSlice->setscalingListPresentFlag( true );
            int apsId = 0;
            pcSlice->setscalingListAPSId( apsId );
          }
          for( int s = 0; s < uiNumSliceSegments; s++ )
          {