Skip to content
Snippets Groups Projects
EncGOP.cpp 171 KiB
Newer Older
  • Learn to ignore specific revisions
  • {
      if (duInfoSeiMessages.empty() || (pictureTimingSEI == NULL))
      {
        return;
      }
    
      int i=0;
    
      for (SEIMessages::iterator du = duInfoSeiMessages.begin(); du!= duInfoSeiMessages.end(); du++)
      {
        SEIDecodingUnitInfo *duInfoSEI = (SEIDecodingUnitInfo*) (*du);
        duInfoSEI->m_decodingUnitIdx = i;
        duInfoSEI->m_duSptCpbRemovalDelay = pictureTimingSEI->m_duCpbRemovalDelayMinus1[i] + 1;
        duInfoSEI->m_dpbOutputDuDelayPresentFlag = false;
        i++;
      }
    }
    
    static void
    cabac_zero_word_padding(Slice *const pcSlice, Picture *const pcPic, const std::size_t binCountsInNalUnits, const std::size_t numBytesInVclNalUnits, std::ostringstream &nalUnitData, const bool cabacZeroWordPaddingEnabled)
    {
      const SPS &sps=*(pcSlice->getSPS());
      const ChromaFormat format = sps.getChromaFormatIdc();
      const int log2subWidthCxsubHeightC = (::getComponentScaleX(COMPONENT_Cb, format)+::getComponentScaleY(COMPONENT_Cb, format));
      const int minCuWidth  = pcPic->cs->pcv->minCUWidth;
      const int minCuHeight = pcPic->cs->pcv->minCUHeight;
    
    #if JVET_O1164_PS
      const int paddedWidth = ( ( pcSlice->getPPS()->getPicWidthInLumaSamples() + minCuWidth - 1 ) / minCuWidth ) * minCuWidth;
      const int paddedHeight = ( ( pcSlice->getPPS()->getPicHeightInLumaSamples() + minCuHeight - 1 ) / minCuHeight ) * minCuHeight;
    #else
    
      const int paddedWidth = ((sps.getPicWidthInLumaSamples()  + minCuWidth  - 1) / minCuWidth) * minCuWidth;
      const int paddedHeight= ((sps.getPicHeightInLumaSamples() + minCuHeight - 1) / minCuHeight) * minCuHeight;
    
      const int rawBits = paddedWidth * paddedHeight *
                             (sps.getBitDepth(CHANNEL_TYPE_LUMA) + 2*(sps.getBitDepth(CHANNEL_TYPE_CHROMA)>>log2subWidthCxsubHeightC));
      const std::size_t threshold = (32/3)*numBytesInVclNalUnits + (rawBits/32);
      if (binCountsInNalUnits >= threshold)
      {
        // need to add additional cabac zero words (each one accounts for 3 bytes (=00 00 03)) to increase numBytesInVclNalUnits
        const std::size_t targetNumBytesInVclNalUnits = ((binCountsInNalUnits - (rawBits/32))*3+31)/32;
    
        if (targetNumBytesInVclNalUnits>numBytesInVclNalUnits) // It should be!
        {
          const std::size_t numberOfAdditionalBytesNeeded=targetNumBytesInVclNalUnits - numBytesInVclNalUnits;
          const std::size_t numberOfAdditionalCabacZeroWords=(numberOfAdditionalBytesNeeded+2)/3;
          const std::size_t numberOfAdditionalCabacZeroBytes=numberOfAdditionalCabacZeroWords*3;
          if (cabacZeroWordPaddingEnabled)
          {
            std::vector<uint8_t> zeroBytesPadding(numberOfAdditionalCabacZeroBytes, uint8_t(0));
            for(std::size_t i=0; i<numberOfAdditionalCabacZeroWords; i++)
            {
              zeroBytesPadding[i*3+2]=3;  // 00 00 03
            }
            nalUnitData.write(reinterpret_cast<const char*>(&(zeroBytesPadding[0])), numberOfAdditionalCabacZeroBytes);
            msg( NOTICE, "Adding %d bytes of padding\n", uint32_t( numberOfAdditionalCabacZeroWords * 3 ) );
          }
          else
          {
            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
    
    #if JVET_O1164_RPR
      const Picture *refPicL0 = pSlice->getRefPic( REF_PIC_LIST_0, refIdx )->unscaledPic;
      const Picture *refPicL1 = pSlice->getRefPic( REF_PIC_LIST_1, refIdx )->unscaledPic;
    #else
    
      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;
      }
    }
    
    
    #if JVET_O1164_PS
    void EncGOP::xPicInitHashME( Picture *pic, const PPS *pps, PicList &rcListPic )
    #else
    
    void EncGOP::xPicInitHashME(Picture *pic, const SPS *sps, PicList &rcListPic)
    
    {
      if (! m_pcCfg->getUseHashME())
      {
        return;
      }
    
      PicList::iterator iterPic = rcListPic.begin();
      while (iterPic != rcListPic.end())
      {
        Picture* refPic = *(iterPic++);
    
        if (refPic->poc != pic->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;
    
    #if JVET_O1164_PS
              int picWidth = pps->getPicWidthInLumaSamples();
              int picHeight = pps->getPicHeightInLumaSamples();
    #else
    
              int picWidth = sps->getPicWidthInLumaSamples();
              int picHeight = sps->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();
          }
        }
      }
    }
    
    void EncGOP::xPicInitRateControl(int &estimatedBits, int gopId, double &lambda, Picture *pic, Slice *slice)
    {
      if ( !m_pcCfg->getUseRateCtrl() ) // TODO: does this work with multiple slices and slice-segments?
      {
        return;
      }
      int frameLevel = m_pcRateCtrl->getRCSeq()->getGOPID2Level( gopId );
      if ( pic->slices[0]->isIRAP() )
      {
        frameLevel = 0;
      }
      m_pcRateCtrl->initRCPic( frameLevel );
      estimatedBits = m_pcRateCtrl->getRCPic()->getTargetBits();
    
    #if U0132_TARGET_BITS_SATURATION
      if (m_pcRateCtrl->getCpbSaturationEnabled() && frameLevel != 0)
      {
        int estimatedCpbFullness = m_pcRateCtrl->getCpbState() + m_pcRateCtrl->getBufferingRate();
    
        // prevent overflow
        if (estimatedCpbFullness - estimatedBits > (int)(m_pcRateCtrl->getCpbSize()*0.9f))
        {
          estimatedBits = estimatedCpbFullness - (int)(m_pcRateCtrl->getCpbSize()*0.9f);
        }
    
        estimatedCpbFullness -= m_pcRateCtrl->getBufferingRate();
        // prevent underflow
    #if V0078_ADAPTIVE_LOWER_BOUND
        if (estimatedCpbFullness - estimatedBits < m_pcRateCtrl->getRCPic()->getLowerBound())
        {
          estimatedBits = std::max(200, estimatedCpbFullness - m_pcRateCtrl->getRCPic()->getLowerBound());
        }
    #else
        if (estimatedCpbFullness - estimatedBits < (int)(m_pcRateCtrl->getCpbSize()*0.1f))
        {
          estimatedBits = std::max(200, estimatedCpbFullness - (int)(m_pcRateCtrl->getCpbSize()*0.1f));
        }
    #endif
    
        m_pcRateCtrl->getRCPic()->setTargetBits(estimatedBits);
      }
    #endif
    
      int sliceQP = m_pcCfg->getInitialQP();
      if ( ( slice->getPOC() == 0 && m_pcCfg->getInitialQP() > 0 ) || ( frameLevel == 0 && m_pcCfg->getForceIntraQP() ) ) // QP is specified
      {
        int    NumberBFrames = ( m_pcCfg->getGOPSize() - 1 );
        double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(double)NumberBFrames );
        double dQPFactor     = 0.57*dLambda_scale;
        int    SHIFT_QP      = 12;
        int bitdepth_luma_qp_scale = 6 * (slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 8
                                    - DISTORTION_PRECISION_ADJUSTMENT(slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)));
        double qp_temp = (double) sliceQP + bitdepth_luma_qp_scale - SHIFT_QP;
        lambda = dQPFactor*pow( 2.0, qp_temp/3.0 );
      }
      else if ( frameLevel == 0 )   // intra case, but use the model
      {
        m_pcSliceEncoder->calCostSliceI(pic); // TODO: This only analyses the first slice segment - what about the others?
    
        if ( m_pcCfg->getIntraPeriod() != 1 )   // do not refine allocated bits for all intra case
        {
          int bits = m_pcRateCtrl->getRCSeq()->getLeftAverageBits();
          bits = m_pcRateCtrl->getRCPic()->getRefineBitsForIntra( bits );
    
    #if U0132_TARGET_BITS_SATURATION
          if (m_pcRateCtrl->getCpbSaturationEnabled() )
          {
            int estimatedCpbFullness = m_pcRateCtrl->getCpbState() + m_pcRateCtrl->getBufferingRate();
    
            // prevent overflow
            if (estimatedCpbFullness - bits > (int)(m_pcRateCtrl->getCpbSize()*0.9f))
            {
              bits = estimatedCpbFullness - (int)(m_pcRateCtrl->getCpbSize()*0.9f);
            }
    
            estimatedCpbFullness -= m_pcRateCtrl->getBufferingRate();
            // prevent underflow
    #if V0078_ADAPTIVE_LOWER_BOUND
            if (estimatedCpbFullness - bits < m_pcRateCtrl->getRCPic()->getLowerBound())
            {
              bits = estimatedCpbFullness - m_pcRateCtrl->getRCPic()->getLowerBound();
            }
    #else
            if (estimatedCpbFullness - bits < (int)(m_pcRateCtrl->getCpbSize()*0.1f))
            {
              bits = estimatedCpbFullness - (int)(m_pcRateCtrl->getCpbSize()*0.1f);
            }
    #endif
          }
    #endif
    
          if ( bits < 200 )
          {
            bits = 200;
          }
          m_pcRateCtrl->getRCPic()->setTargetBits( bits );
        }
    
        list<EncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();
        m_pcRateCtrl->getRCPic()->getLCUInitTargetBits();
        lambda  = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, slice->isIRAP());
        sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture );
      }
      else    // normal case
      {
        list<EncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();
        lambda  = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, slice->isIRAP());
        sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture );
      }
    
      sliceQP = Clip3( -slice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, sliceQP );
      m_pcRateCtrl->getRCPic()->setPicEstQP( sliceQP );
    
      m_pcSliceEncoder->resetQP( pic, sliceQP, lambda );
    }
    
    void EncGOP::xPicInitLMCS(Picture *pic, Slice *slice)
    {
      if (slice->getSPS()->getUseReshaper())
      {
        const SliceType sliceType = slice->getSliceType();
    
        m_pcReshaper->getReshapeCW()->rspTid = slice->getTLayer() + (slice->isIntra() ? 0 : 1);
        m_pcReshaper->getReshapeCW()->rspSliceQP = slice->getSliceQp();
    
        m_pcReshaper->setSrcReshaped(false);
        m_pcReshaper->setRecReshaped(true);
    
        if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ)
        {
          m_pcReshaper->preAnalyzerHDR(pic, sliceType, m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree());
        }
    #if JVET_O0432_LMCS_ENCODER
        else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR || m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_HLG)
        {
          m_pcReshaper->preAnalyzerLMCS(pic, m_pcCfg->getReshapeSignalType(), sliceType, m_pcCfg->getReshapeCW());
        }
    #else
        else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR)
        {
          m_pcReshaper->preAnalyzerSDR(pic, sliceType, m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree());
        }
    #endif
        else
        {
          THROW("Reshaper for other signal currently not defined!");
        }
    
        if (sliceType == I_SLICE )
        {
          if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ)
          {
            m_pcReshaper->initLUTfromdQPModel();
            m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTableChromaMD(m_pcReshaper->getInvLUT());
          }
    #if JVET_O0432_LMCS_ENCODER
          else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR || m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_HLG)
          {
            if (m_pcReshaper->getReshapeFlag())
            {
              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)
          {
            if (m_pcReshaper->getReshapeFlag())
            {
              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!");
          }
    
          //reshape original signal
          if (m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper())
          {
            pic->getOrigBuf(COMPONENT_Y).rspSignal(m_pcReshaper->getFwdLUT());
            m_pcReshaper->setSrcReshaped(true);
            m_pcReshaper->setRecReshaped(true);
          }
        }
        else
        {
          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);