Skip to content
Snippets Groups Projects
EncGOP.cpp 176 KiB
Newer Older
  • Learn to ignore specific revisions
  • #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++ )
          {
            pcPic->slices[ s ]->setscalingListPresentFlag( pcSlice->getscalingListPresentFlag() );
            if( pcSlice->getscalingListPresentFlag() )
            {
              pcPic->slices[ s ]->setscalingListAPSId( pcSlice->getscalingListAPSId() );
            }
          }
    #endif
    
    
          // SAO parameter estimation using non-deblocked pixels for CTU bottom and right boundary areas
    
          if( pcSlice->getSPS()->getSAOEnabledFlag() && m_pcCfg->getSaoCtuBoundary() )
    
          {
            m_pcSAO->getPreDBFStatistics( cs );
          }
    
          //-- Loop filter
          if ( m_pcCfg->getDeblockingFilterMetric() )
          {
      #if W0038_DB_OPT
            if ( m_pcCfg->getDeblockingFilterMetric()==2 )
            {
              applyDeblockingFilterParameterSelection(pcPic, uiNumSliceSegments, iGOPid);
            }
            else
            {
      #endif
              applyDeblockingFilterMetric(pcPic, uiNumSliceSegments);
      #if W0038_DB_OPT
            }
      #endif
          }
    
          m_pcLoopFilter->loopFilterPic( cs );
    
    
          CS::setRefinedMotionField(cs);
    
          DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 1 ) ) );
    
    
          if( pcSlice->getSPS()->getSAOEnabledFlag() )
    
          {
            bool sliceEnabled[MAX_NUM_COMPONENT];
            m_pcSAO->initCABACEstimator( m_pcEncLib->getCABACEncoder(), m_pcEncLib->getCtxCache(), pcSlice );
    
    
            m_pcSAO->SAOProcess( cs, sliceEnabled, pcSlice->getLambdas(),
    #if ENABLE_QPA
                                 (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP() ? m_pcEncLib->getRdCost (PARL_PARAM0 (0))->getChromaWeight() : 0.0),
    #endif
                                 m_pcCfg->getTestSAODisableAtPictureLevel(), m_pcCfg->getSaoEncodingRate(), m_pcCfg->getSaoEncodingRateChroma(), m_pcCfg->getSaoCtuBoundary(), m_pcCfg->getSaoGreedyMergeEnc() );
    
            //assign SAO slice header
            for(int s=0; s< uiNumSliceSegments; s++)
            {
              pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_LUMA, sliceEnabled[COMPONENT_Y]);
              CHECK(!(sliceEnabled[COMPONENT_Cb] == sliceEnabled[COMPONENT_Cr]), "Unspecified error");
              pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, sliceEnabled[COMPONENT_Cb]);
            }
          }
    
    
          if( pcSlice->getSPS()->getALFEnabledFlag() )
    
    #if JVET_O1164_PS
            m_pcALF->destroy();
            m_pcALF->create( m_pcCfg, picWidth, picHeight, chromaFormatIDC, maxCUWidth, maxCUHeight, maxTotalCUDepth, m_pcCfg->getBitDepth(), m_pcCfg->getInputBitDepth() );
    #endif
    
    
            for (int s = 0; s < uiNumSliceSegments; s++)
            {
              pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Y, false);
            }
            m_pcALF->initCABACEstimator(m_pcEncLib->getCABACEncoder(), m_pcEncLib->getCtxCache(), pcSlice, m_pcEncLib->getApsMap());
            m_pcALF->ALFProcess(cs, pcSlice->getLambdas()
    #if ENABLE_QPA
              , (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP() ? m_pcEncLib->getRdCost(PARL_PARAM0(0))->getChromaWeight() : 0.0)
    #endif
            );
    
            //assign ALF slice header
            for (int s = 0; s < uiNumSliceSegments; s++)
            {
              pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Y, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y));
              pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb));
              pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr));
              if (pcPic->slices[s]->getTileGroupAlfEnabledFlag(COMPONENT_Y))
              {
                pcPic->slices[s]->setTileGroupNumAps(cs.slice->getTileGroupNumAps());
    
                pcPic->slices[s]->setAlfAPSs(cs.slice->getTileGroupApsIdLuma());
    
              pcPic->slices[s]->setAlfAPSs(cs.slice->getAlfAPSs());
              pcPic->slices[s]->setTileGroupApsIdChroma(cs.slice->getTileGroupApsIdChroma());
    
          if (m_pcCfg->getUseCompositeRef() && getPrepareLTRef())
    
          {
            updateCompositeReference(pcSlice, rcListPic, pocCurr);
          }
    
        }
        else // skip enc picture
        {
          pcSlice->setSliceQpBase( pcSlice->getSliceQp() );
    
    
    #if ENABLE_QPA
          if (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP())
          {
            const double picLambda = pcSlice->getLambdas()[0];
    
            for (uint32_t ctuRsAddr = 0; ctuRsAddr < numberOfCtusInFrame; ctuRsAddr++)
            {
              pcPic->m_uEnerHpCtu[ctuRsAddr] = picLambda;  // initialize to slice lambda (just for safety)
            }
          }
    #endif
    
          if( pcSlice->getSPS()->getSAOEnabledFlag() )
    
          {
            m_pcSAO->disabledRate( *pcPic->cs, pcPic->getSAO(1), m_pcCfg->getSaoEncodingRate(), m_pcCfg->getSaoEncodingRateChroma());
          }
        }
    
    
    #if JVET_O1164_RPR
        pcSlice->freeScaledRefPicList( scaledRefPic );
    #endif
    
    
        if( m_pcCfg->getUseAMaxBT() )
        {
          for( const CodingUnit *cu : pcPic->cs->cus )
          {
    
            if( !pcSlice->isIRAP() )
    
            {
              m_uiBlkSize[pcSlice->getDepth()] += cu->Y().area();
              m_uiNumBlk [pcSlice->getDepth()]++;
            }
          }
        }
    
        if( encPic || decPic )
        {
          pcSlice = pcPic->slices[0];
    
          /////////////////////////////////////////////////////////////////////////////////////////////////// File writing
    
          // write various parameter sets
    
          bool writePS = m_bSeqFirst || (m_pcCfg->getReWriteParamSets() && (pcSlice->isIRAP()));
          if (writePS)
          {
            m_pcEncLib->setParamSetChanged(pcSlice->getSPS()->getSPSId(), pcSlice->getPPS()->getPPSId());
          }
          actualTotalBits += xWriteParameterSets(accessUnit, pcSlice, writePS);
    
          {
            // create prefix SEI messages at the beginning of the sequence
            CHECK(!(leadingSeiMessages.empty()), "Unspecified error");
            xCreateIRAPLeadingSEIMessages(leadingSeiMessages, pcSlice->getSPS(), pcSlice->getPPS());
    
            m_bSeqFirst = false;
          }
          if (m_pcCfg->getAccessUnitDelimiter())
          {
            xWriteAccessUnitDelimiter(accessUnit, pcSlice);
          }
    
    
          //send LMCS APS when LMCSModel is updated. It can be updated even current slice does not enable reshaper.
          //For example, in RA, update is on intra slice, but intra slice may not use reshaper
          if (pcSlice->getSPS()->getUseReshaper())
          {
            //only 1 LMCS data for 1 picture
            int apsId = pcSlice->getLmcsAPSId();
            ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
            APS* aps = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
            bool writeAPS = aps && apsMap->getChangedFlag((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
            if (writeAPS)
            {
              actualTotalBits += xWriteAPS(accessUnit, aps);
              apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
              CHECK(aps != pcSlice->getLmcsAPS(), "Wrong LMCS APS pointer in compressGOP");
            }
          }
    
    
    #if JVET_O0299_APS_SCALINGLIST
          // only 1 SCALING LIST data for 1 picture    
          if( pcSlice->getSPS()->getScalingListFlag() && ( m_pcCfg->getUseScalingListId() == SCALING_LIST_FILE_READ ) )
          {
            int apsId = pcSlice->getscalingListAPSId();
            ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
            APS* aps = apsMap->getPS( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
            bool writeAPS = aps && apsMap->getChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
            if( writeAPS )
            {
              actualTotalBits += xWriteAPS( accessUnit, aps );
              apsMap->clearChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
              CHECK( aps != pcSlice->getscalingListAPS(), "Wrong SCALING LIST APS pointer in compressGOP" );
            }
          }
    #endif
    
    
          if (pcSlice->getSPS()->getALFEnabledFlag() && pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
          {
    
    #if JVET_O_MAX_NUM_ALF_APS_8
            for (int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++)
    #else