Skip to content
Snippets Groups Projects
EncGOP.cpp 156 KiB
Newer Older
  • Learn to ignore specific revisions
  •       {
            msg( NOTICE, "Standard would normally require adding %d bytes of padding\n", uint32_t( numberOfAdditionalCabacZeroWords * 3 ) );
          }
        }
      }
    }
    
    class EfficientFieldIRAPMapping
    {
      private:
        int  IRAPGOPid;
        bool IRAPtoReorder;
        bool swapIRAPForward;
    
      public:
        EfficientFieldIRAPMapping() :
          IRAPGOPid(-1),
          IRAPtoReorder(false),
          swapIRAPForward(false)
        { }
    
        void initialize(const bool isField, const int gopSize, const int POCLast, const int numPicRcvd, const int lastIDR, EncGOP *pEncGop, EncCfg *pCfg);
    
        int adjustGOPid(const int gopID);
        int restoreGOPid(const int gopID);
        int GetIRAPGOPid() const { return IRAPGOPid; }
    };
    
    void EfficientFieldIRAPMapping::initialize(const bool isField, const int gopSize, const int POCLast, const int numPicRcvd, const int lastIDR, EncGOP *pEncGop, EncCfg *pCfg )
    {
      if(isField)
      {
        int pocCurr;
        for ( int iGOPid=0; iGOPid < gopSize; iGOPid++ )
        {
          // determine actual POC
          if(POCLast == 0) //case first frame or first top field
          {
            pocCurr=0;
          }
          else if(POCLast == 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;
          }
          else
          {
            pocCurr = POCLast - numPicRcvd + pCfg->getGOPEntry(iGOPid).m_POC - isField;
          }
    
          // check if POC corresponds to IRAP
          NalUnitType tmpUnitType = pEncGop->getNalUnitType(pocCurr, lastIDR, isField);
    
          if (tmpUnitType >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && tmpUnitType <= NAL_UNIT_CODED_SLICE_CRA) // if picture is an IRAP
    
          {
            if(pocCurr%2 == 0 && iGOPid < gopSize-1 && pCfg->getGOPEntry(iGOPid).m_POC == pCfg->getGOPEntry(iGOPid+1).m_POC-1)
            { // if top field and following picture in enc order is associated bottom field
              IRAPGOPid = iGOPid;
              IRAPtoReorder = true;
              swapIRAPForward = true;
              break;
            }
            if(pocCurr%2 != 0 && iGOPid > 0 && pCfg->getGOPEntry(iGOPid).m_POC == pCfg->getGOPEntry(iGOPid-1).m_POC+1)
            {
              // if picture is an IRAP remember to process it first
              IRAPGOPid = iGOPid;
              IRAPtoReorder = true;
              swapIRAPForward = false;
              break;
            }
          }
        }
      }
    }
    
    int EfficientFieldIRAPMapping::adjustGOPid(const int GOPid)
    {
      if(IRAPtoReorder)
      {
        if(swapIRAPForward)
        {
          if(GOPid == IRAPGOPid)
          {
            return IRAPGOPid +1;
          }
          else if(GOPid == IRAPGOPid +1)
          {
            return IRAPGOPid;
          }
        }
        else
        {
          if(GOPid == IRAPGOPid -1)
          {
            return IRAPGOPid;
          }
          else if(GOPid == IRAPGOPid)
          {
            return IRAPGOPid -1;
          }
        }
      }
      return GOPid;
    }
    
    int EfficientFieldIRAPMapping::restoreGOPid(const int GOPid)
    {
      if(IRAPtoReorder)
      {
        if(swapIRAPForward)
        {
          if(GOPid == IRAPGOPid)
          {
            IRAPtoReorder = false;
            return IRAPGOPid +1;
          }
          else if(GOPid == IRAPGOPid +1)
          {
            return GOPid -1;
          }
        }
        else
        {
          if(GOPid == IRAPGOPid)
          {
            return IRAPGOPid -1;
          }
          else if(GOPid == IRAPGOPid -1)
          {
            IRAPtoReorder = false;
            return IRAPGOPid;
          }
        }
      }
      return GOPid;
    }
    
    
    #if X0038_LAMBDA_FROM_QP_CAPABILITY
    static uint32_t calculateCollocatedFromL0Flag(const Slice *pSlice)
    {
      const int refIdx = 0; // Zero always assumed
      const Picture *refPicL0 = pSlice->getRefPic(REF_PIC_LIST_0, refIdx);
      const Picture *refPicL1 = pSlice->getRefPic(REF_PIC_LIST_1, refIdx);
      return refPicL0->slices[0]->getSliceQp() > refPicL1->slices[0]->getSliceQp();
    }
    #else
    static uint32_t calculateCollocatedFromL1Flag(EncCfg *pCfg, const int GOPid, const int gopSize)
    {
      int iCloseLeft=1, iCloseRight=-1;
      for(int i = 0; i<pCfg->getGOPEntry(GOPid).m_numRefPics; i++)
      {
        int iRef = pCfg->getGOPEntry(GOPid).m_referencePics[i];
        if(iRef>0&&(iRef<iCloseRight||iCloseRight==-1))
        {
          iCloseRight=iRef;
        }
        else if(iRef<0&&(iRef>iCloseLeft||iCloseLeft==1))
        {
          iCloseLeft=iRef;
        }
      }
      if(iCloseRight>-1)
      {
        iCloseRight=iCloseRight+pCfg->getGOPEntry(GOPid).m_POC-1;
      }
      if(iCloseLeft<1)
      {
        iCloseLeft=iCloseLeft+pCfg->getGOPEntry(GOPid).m_POC-1;
        while(iCloseLeft<0)
        {
          iCloseLeft+=gopSize;
        }
      }
      int iLeftQP=0, iRightQP=0;
      for(int i=0; i<gopSize; i++)
      {
        if(pCfg->getGOPEntry(i).m_POC==(iCloseLeft%gopSize)+1)
        {
          iLeftQP= pCfg->getGOPEntry(i).m_QPOffset;
        }
        if (pCfg->getGOPEntry(i).m_POC==(iCloseRight%gopSize)+1)
        {
          iRightQP=pCfg->getGOPEntry(i).m_QPOffset;
        }
      }
      if(iCloseRight>-1&&iRightQP<iLeftQP)
      {
        return 0;
      }
      else
      {
        return 1;
      }
    }
    #endif
    
    
    static void
    printHash(const HashType hashType, const std::string &digestStr)
    {
      const char *decodedPictureHashModeName;
      switch (hashType)
      {
        case HASHTYPE_MD5:
          decodedPictureHashModeName = "MD5";
          break;
        case HASHTYPE_CRC:
          decodedPictureHashModeName = "CRC";
          break;
        case HASHTYPE_CHECKSUM:
          decodedPictureHashModeName = "Checksum";
          break;
        default:
          decodedPictureHashModeName = NULL;
          break;
      }
      if (decodedPictureHashModeName != NULL)
      {
        if (digestStr.empty())
        {
          msg( NOTICE, " [%s:%s]", decodedPictureHashModeName, "?");
        }
        else
        {
          msg( NOTICE, " [%s:%s]", decodedPictureHashModeName, digestStr.c_str());
        }
      }
    }
    
    bool isPicEncoded( int targetPoc, int curPoc, int curTLayer, int gopSize, int intraPeriod )
    {
      int  tarGop = targetPoc / gopSize;
      int  curGop = curPoc / gopSize;
    
      if( tarGop + 1 == curGop )
      {
        // part of next GOP only for tl0 pics
        return curTLayer == 0;
      }
    
      int  tarIFr = ( targetPoc / intraPeriod ) * intraPeriod;
      int  curIFr = ( curPoc / intraPeriod ) * intraPeriod;
    
      if( curIFr != tarIFr )
      {
        return false;
      }
    
      int  tarId = targetPoc - tarGop * gopSize;
    
      if( tarGop > curGop )
      {
        return ( tarId == 0 ) ? ( 0 == curTLayer ) : ( 1 >= curTLayer );
      }
    
      if( tarGop + 1 < curGop )
      {
        return false;
      }
    
      int  curId = curPoc - curGop * gopSize;
      int  tarTL = 0;
    
      while( tarId != 0 )
      {
        gopSize /= 2;
        if( tarId >= gopSize )
        {
          tarId -= gopSize;
          if( curId != 0 ) curId -= gopSize;
        }
        else if( curId == gopSize )
        {
          curId = 0;
        }
        tarTL++;
      }
    
      return curTLayer <= tarTL && curId == 0;
    }
    
    void trySkipOrDecodePicture( bool& decPic, bool& encPic, const EncCfg& cfg, Picture* pcPic )
    {
      // check if we should decode a leading bitstream
      if( !cfg.getDecodeBitstream( 0 ).empty() )
      {
        static bool bDecode1stPart = true; /* TODO: MT */
        if( bDecode1stPart )
        {
          if( cfg.getForceDecodeBitstream1() )
          {
            if( ( bDecode1stPart = tryDecodePicture( pcPic, pcPic->getPOC(), cfg.getDecodeBitstream( 0 ), false ) ) )
            {
              decPic = bDecode1stPart;
            }
          }
          else
          {
            // update decode decision
    
    Tobias Hinz's avatar
    Tobias Hinz committed
            bool dbgCTU = cfg.getDebugCTU() != -1 && cfg.getSwitchPOC() == pcPic->getPOC();
    
            if( ( bDecode1stPart = ( cfg.getSwitchPOC() != pcPic->getPOC() ) || dbgCTU ) && ( bDecode1stPart = tryDecodePicture( pcPic, pcPic->getPOC(), cfg.getDecodeBitstream( 0 ), false, cfg.getDebugCTU(), cfg.getSwitchPOC() ) ) )
            {
              if( dbgCTU )
              {
                encPic = true;
                decPic = false;
                bDecode1stPart = false;
    
                return;
              }
              decPic = bDecode1stPart;
              return;
            }
    
            else if( pcPic->getPOC() )
            {
              // reset decoder if used and not required any further
              tryDecodePicture( NULL, 0, std::string( "" ) );
            }
          }
        }
    
        encPic |= cfg.getForceDecodeBitstream1() && !decPic;
        if( cfg.getForceDecodeBitstream1() ) { return; }
      }
    
    
      // check if we should decode a trailing bitstream
      if( ! cfg.getDecodeBitstream(1).empty() )
      {
        const int  iNextKeyPOC    = (1+cfg.getSwitchPOC()  / cfg.getGOPSize())     *cfg.getGOPSize();
        const int  iNextIntraPOC  = (1+(cfg.getSwitchPOC() / cfg.getIntraPeriod()))*cfg.getIntraPeriod();
        const int  iRestartIntraPOC   = iNextIntraPOC + (((iNextKeyPOC == iNextIntraPOC) && cfg.getSwitchDQP() ) ? cfg.getIntraPeriod() : 0);
    
        bool bDecode2ndPart = (pcPic->getPOC() >= iRestartIntraPOC);
        int expectedPoc = pcPic->getPOC();
        Slice slice0;
        if ( cfg.getBs2ModPOCAndType() )
        {
          expectedPoc = pcPic->getPOC() - iRestartIntraPOC;
          slice0.copySliceInfo( pcPic->slices[ 0 ], false );
        }
        if( bDecode2ndPart && (bDecode2ndPart = tryDecodePicture( pcPic, expectedPoc, cfg.getDecodeBitstream(1), true )) )
        {
          decPic = bDecode2ndPart;
          if ( cfg.getBs2ModPOCAndType() )
          {
            for( int i = 0; i < pcPic->slices.size(); i++ )
            {
              pcPic->slices[ i ]->setPOC              ( slice0.getPOC()            );
              if ( pcPic->slices[ i ]->getNalUnitType() != slice0.getNalUnitType()
                  && pcPic->slices[ i ]->getIdrPicFlag()
                  && slice0.getRapPicFlag()
                  && slice0.isIntra() )
              {
                // patch IDR-slice to CRA-Intra-slice
                pcPic->slices[ i ]->setNalUnitType    ( slice0.getNalUnitType()    );
                pcPic->slices[ i ]->setLastIDR        ( slice0.getLastIDR()        );
                pcPic->slices[ i ]->setEnableTMVPFlag ( slice0.getEnableTMVPFlag() );
                if ( slice0.getEnableTMVPFlag() )
                {
                  pcPic->slices[ i ]->setColFromL0Flag( slice0.getColFromL0Flag()  );
                  pcPic->slices[ i ]->setColRefIdx    ( slice0.getColRefIdx()      );
                }
              }
            }
          }
          return;
        }
      }
    
      // leave here if we do not use forward to poc
      if( ! cfg.useFastForwardToPOC() )
      {
        // let's encode
        encPic   = true;
        return;
      }
    
      // this is the forward to poc section
      static bool bHitFastForwardPOC = false; /* TODO: MT */
      if( bHitFastForwardPOC || isPicEncoded( cfg.getFastForwardToPOC(), pcPic->getPOC(), pcPic->layer, cfg.getGOPSize(), cfg.getIntraPeriod() ) )
      {
        bHitFastForwardPOC |= cfg.getFastForwardToPOC() == pcPic->getPOC(); // once we hit the poc we continue encoding
    
        if( bHitFastForwardPOC && cfg.getStopAfterFFtoPOC() && cfg.getFastForwardToPOC() != pcPic->getPOC() )
        {
          return;
        }
    
        //except if FastForwardtoPOC is meant to be a SwitchPOC in thist case drop all preceding pictures
        if( bHitFastForwardPOC && ( cfg.getSwitchPOC() == cfg.getFastForwardToPOC() ) && ( cfg.getFastForwardToPOC() > pcPic->getPOC() ) )
        {
          return;
        }
        // let's encode
        encPic   = true;
      }
    }
    
    // ====================================================================================================================
    // 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
    
    
      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 );
    
        // 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 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);
        }
    
    
    Hendry's avatar
    Hendry committed
        if (pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPL0(), 0, false) != 0 || pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPL1(), 1, false) != 0)
        {
          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);
    
        if (m_pcCfg->getUseHashME())
        {
          PicList::iterator iterPic = rcListPic.begin();
          while (iterPic != rcListPic.end())
          {
            Picture* refPic = *(iterPic++);
    
            if (refPic->poc != pcPic->poc && refPic->referenced)
            {
              if (!refPic->getHashMap()->isInitial())
              {
                if (refPic->getPOC() == 0)
                {
                  Pel* picSrc = refPic->getOrigBuf().get(COMPONENT_Y).buf;
                  int stridePic = refPic->getOrigBuf().get(COMPONENT_Y).stride;
                  int picWidth = pcSlice->getSPS()->getPicWidthInLumaSamples();
                  int picHeight = pcSlice->getSPS()->getPicHeightInLumaSamples();
                  int blockSize = 4;
                  int allNum = 0;
                  int simpleNum = 0;
                  for (int j = 0; j <= picHeight - blockSize; j += blockSize)
                  {
                    for (int i = 0; i <= picWidth - blockSize; i += blockSize)
                    {
                      Pel* curBlock = picSrc + j * stridePic + i;
                      bool isHorSame = true;
                      for (int m = 0; m < blockSize&&isHorSame; m++)
                      {
                        for (int n = 1; n < blockSize&&isHorSame; n++)
                        {
                          if (curBlock[m*stridePic] != curBlock[m*stridePic + n])
                          {
                            isHorSame = false;
                          }
                        }
                      }
                      bool isVerSame = true;
                      for (int m = 1; m < blockSize&&isVerSame; m++)
                      {
                        for (int n = 0; n < blockSize&&isVerSame; n++)
                        {
                          if (curBlock[n] != curBlock[m*stridePic + n])
                          {
                            isVerSame = false;
                          }
                        }
                      }
                      allNum++;
                      if (isHorSame || isVerSame)
                      {
                        simpleNum++;
                      }
                    }
                  }
    
                  if (simpleNum < 0.3*allNum)
                  {
                    m_pcCfg->setUseHashME(false);
                    break;
                  }
                }
                refPic->addPictureToHashMapForInter();
              }
            }
          }
        }
    
          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
        uiColDir = 1-uiColDir;
    #endif
    
        //-------------------------------------------------------------
        pcSlice->setRefPOCList();
    
    
        pcSlice->setList1IdxToList0Idx();
    
        if (m_pcEncLib->getTMVPModeId() == 2)
        {
          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)
        {
          pcSlice->setEnableTMVPFlag(1);
        }
        else
        {
          pcSlice->setEnableTMVPFlag(0);
        }
    
    
        // disable TMVP when current picture is the only ref picture
    
    Yu Han's avatar
    Yu Han committed
        if (pcSlice->isIRAP() && pcSlice->getSPS()->getIBCFlag())
    
        // 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) )