Skip to content
Snippets Groups Projects
EncGOP.cpp 166 KiB
Newer Older
  • Learn to ignore specific revisions
  •     /* logging: insert a newline at end of picture period */
    
        if (m_pcCfg->getEfficientFieldIRAPEnabled())
        {
          iGOPid=effFieldIRAPMap.restoreGOPid(iGOPid);
        }
    
        pcPic->destroyTempBuffers();
        pcPic->cs->destroyCoeffs();
        pcPic->cs->releaseIntermediateData();
      } // iGOPid-loop
    
      delete pcBitstreamRedirect;
    
      CHECK(!( (m_iNumPicCoded == iNumPicRcvd) ), "Unspecified error");
    
    }
    
    
    #if RPR_CTC_PRINT
    void EncGOP::printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printHexPsnr, const bool printRprPSNR, const BitDepths &bitDepths )
    #else
    
    void EncGOP::printOutSummary(uint32_t uiNumAllPicCoded, bool isField, const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printHexPsnr, const BitDepths &bitDepths)
    
    {
    #if ENABLE_QPA
      const bool    useWPSNR = m_pcEncLib->getUseWPSNR();
    #endif
    #if WCG_WPSNR
    
    Taoran Lu's avatar
    Taoran Lu committed
      const bool    useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ);
    
    #endif
    
      if( m_pcCfg->getDecodeBitstream(0).empty() && m_pcCfg->getDecodeBitstream(1).empty() && !m_pcCfg->useFastForwardToPOC() )
      {
        CHECK( !( uiNumAllPicCoded == m_gcAnalyzeAll.getNumPic() ), "Unspecified error" );
      }
    
      //--CFG_KDY
      const int rateMultiplier=(isField?2:1);
      m_gcAnalyzeAll.setFrmRate( m_pcCfg->getFrameRate()*rateMultiplier / (double)m_pcCfg->getTemporalSubsampleRatio());
      m_gcAnalyzeI.setFrmRate( m_pcCfg->getFrameRate()*rateMultiplier / (double)m_pcCfg->getTemporalSubsampleRatio());
      m_gcAnalyzeP.setFrmRate( m_pcCfg->getFrameRate()*rateMultiplier / (double)m_pcCfg->getTemporalSubsampleRatio());
      m_gcAnalyzeB.setFrmRate( m_pcCfg->getFrameRate()*rateMultiplier / (double)m_pcCfg->getTemporalSubsampleRatio());
    #if WCG_WPSNR
      if (useLumaWPSNR)
      {
        m_gcAnalyzeWPSNR.setFrmRate(m_pcCfg->getFrameRate()*rateMultiplier / (double)m_pcCfg->getTemporalSubsampleRatio());
      }
    #endif
    
      const ChromaFormat chFmt = m_pcCfg->getChromaFormatIdc();
    
      //-- all
      msg( INFO, "\n" );
      msg( DETAILS,"\nSUMMARY --------------------------------------------------------\n" );
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
      const bool calculateHdrMetrics = m_pcEncLib->getCalcluateHdrMetrics();
    #endif
    
      m_gcAnalyzeAll.printOut( 'a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths, useWPSNR
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
                              , calculateHdrMetrics
    #endif
                              );
    
      m_gcAnalyzeAll.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths, useWPSNR
    #if JVET_O0756_CALCULATE_HDRMETRICS
                              , calculateHdrMetrics
    #endif
                              );  
    
      m_gcAnalyzeAll.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths
    #if JVET_O0756_CALCULATE_HDRMETRICS
                              , calculateHdrMetrics
    #endif
                              );
    
    #if RPR_CTC_PRINT
      msg( DETAILS, "\n\nI Slices--------------------------------------------------------\n" );
      m_gcAnalyzeI.printOut( 'i', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths );
    
      msg( DETAILS, "\n\nP Slices--------------------------------------------------------\n" );
      m_gcAnalyzeP.printOut( 'p', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths );
    
      msg( DETAILS, "\n\nB Slices--------------------------------------------------------\n" );
      m_gcAnalyzeB.printOut( 'b', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths );
    #else
    
      msg( DETAILS,"\n\nI Slices--------------------------------------------------------\n" );
    
      m_gcAnalyzeI.printOut('i', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths);
    
    
      msg( DETAILS,"\n\nP Slices--------------------------------------------------------\n" );
    
      m_gcAnalyzeP.printOut('p', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths);
    
    
      msg( DETAILS,"\n\nB Slices--------------------------------------------------------\n" );
    
      m_gcAnalyzeB.printOut('b', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths);
    
    #if WCG_WPSNR
      if (useLumaWPSNR)
      {
        msg(DETAILS, "\nWPSNR SUMMARY --------------------------------------------------------\n");
    
    #if RPR_CTC_PRINT
        m_gcAnalyzeWPSNR.printOut( 'w', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths, useLumaWPSNR );
    #else
    
        m_gcAnalyzeWPSNR.printOut('w', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths, useLumaWPSNR);
    
        m_gcAnalyzeAll.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename());
    
        m_gcAnalyzeI.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryPicFilenameBase()+"I.txt");
        m_gcAnalyzeP.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryPicFilenameBase()+"P.txt");
        m_gcAnalyzeB.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryPicFilenameBase()+"B.txt");
    
      }
    
    #if WCG_WPSNR
      if (!m_pcCfg->getSummaryOutFilename().empty() && useLumaWPSNR)
      {
    
        m_gcAnalyzeWPSNR.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename());
    
      }
    #endif
      if(isField)
      {
        //-- interlaced summary
        m_gcAnalyzeAll_in.setFrmRate( m_pcCfg->getFrameRate() / (double)m_pcCfg->getTemporalSubsampleRatio());
        m_gcAnalyzeAll_in.setBits(m_gcAnalyzeAll.getBits());
        // prior to the above statement, the interlace analyser does not contain the correct total number of bits.
    
        msg( DETAILS,"\n\nSUMMARY INTERLACED ---------------------------------------------\n" );
    #if ENABLE_QPA
    
    #if RPR_CTC_PRINT
        m_gcAnalyzeAll_in.printOut( 'a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths, useWPSNR );
    #else
    
        m_gcAnalyzeAll_in.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths, useWPSNR);
    
        m_gcAnalyzeAll_in.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths);
    
    #endif
        if (!m_pcCfg->getSummaryOutFilename().empty())
        {
    
          m_gcAnalyzeAll_in.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename());
    
            m_gcAnalyzeWPSNR.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename());
    
          }
    #endif
        }
      }
    
      msg( DETAILS,"\nRVM: %.3lf\n", xCalculateRVM() );
    }
    
    #if W0038_DB_OPT
    uint64_t EncGOP::preLoopFilterPicAndCalcDist( Picture* pcPic )
    {
      CodingStructure& cs = *pcPic->cs;
      m_pcLoopFilter->loopFilterPic( cs );
    
      const CPelUnitBuf picOrg = pcPic->getRecoBuf();
      const CPelUnitBuf picRec = cs.getRecoBuf();
    
      uint64_t uiDist = 0;
      for( uint32_t comp = 0; comp < (uint32_t)picRec.bufs.size(); comp++)
      {
        const ComponentID compID = ComponentID(comp);
        const uint32_t rshift = 2 * DISTORTION_PRECISION_ADJUSTMENT(cs.sps->getBitDepth(toChannelType(compID)));
    #if ENABLE_QPA
        CHECK( rshift >= 8, "shifts greater than 7 are not supported." );
    #endif
        uiDist += xFindDistortionPlane( picOrg.get(compID), picRec.get(compID), rshift );
      }
      return uiDist;
    }
    #endif
    
    // ====================================================================================================================
    // Protected member functions
    // ====================================================================================================================
    
    void EncGOP::xInitGOP( int iPOCLast, int iNumPicRcvd, bool isField
      , bool isEncodeLtRef
    )
    
    {
      CHECK(!( iNumPicRcvd > 0 ), "Unspecified error");
      //  Exception for the first frames
    
      if ((isField && (iPOCLast == 0 || iPOCLast == 1)) || (!isField && (iPOCLast == 0)) || isEncodeLtRef)
    
      {
        m_iGopSize    = 1;
      }
      else
      {
        m_iGopSize    = m_pcCfg->getGOPSize();
      }
      CHECK(!(m_iGopSize > 0), "Unspecified error");
    
      return;
    }
    
    
    void EncGOP::xGetBuffer( PicList&                  rcListPic,
                             std::list<PelUnitBuf*>&   rcListPicYuvRecOut,
                             int                       iNumPicRcvd,
                             int                       iTimeOffset,
                             Picture*&                 rpcPic,
                             int                       pocCurr,
                             bool                      isField )
    {
      int i;
      //  Rec. output
      std::list<PelUnitBuf*>::iterator     iterPicYuvRec = rcListPicYuvRecOut.end();
    
      if (isField && pocCurr > 1 && m_iGopSize!=1)
      {
        iTimeOffset--;
      }
    
    
      int multipleFactor = m_pcCfg->getUseCompositeRef() ? 2 : 1;
      for (i = 0; i < (iNumPicRcvd * multipleFactor - iTimeOffset + 1); i += multipleFactor)
    
      {
        iterPicYuvRec--;
      }
    
      //  Current pic.
      PicList::iterator        iterPic       = rcListPic.begin();
      while (iterPic != rcListPic.end())
      {
        rpcPic = *(iterPic);
        if (rpcPic->getPOC() == pocCurr)
        {
          break;
        }
        iterPic++;
      }
    
      CHECK(!(rpcPic != NULL), "Unspecified error");
      CHECK(!(rpcPic->getPOC() == pocCurr), "Unspecified error");
    
      (**iterPicYuvRec) = rpcPic->getRecoBuf();
      return;
    }
    
    #if ENABLE_QPA
    
    #ifndef BETA
    
      #define BETA 0.5 // value between 0.0 and 1; use 0.0 to obtain traditional PSNR
    
    static inline double calcWeightedSquaredError(const CPelBuf& org,        const CPelBuf& rec,
                                                  double &sumAct,            const uint32_t bitDepth,
                                                  const uint32_t imageWidth, const uint32_t imageHeight,
                                                  const uint32_t offsetX,    const uint32_t offsetY,
                                                  int blockWidth,            int blockHeight)
    
    {
      const int    O = org.stride;
      const int    R = rec.stride;
      const Pel   *o = org.bufAt(offsetX, offsetY);
      const Pel   *r = rec.bufAt(offsetX, offsetY);
      const int yAct = offsetY > 0 ? 0 : 1;
      const int xAct = offsetX > 0 ? 0 : 1;
    
      if (offsetY + (uint32_t)blockHeight > imageHeight) blockHeight = imageHeight - offsetY;
      if (offsetX + (uint32_t)blockWidth  > imageWidth ) blockWidth  = imageWidth  - offsetX;
    
      const int hAct = offsetY + (uint32_t)blockHeight < imageHeight ? blockHeight : blockHeight - 1;
      const int wAct = offsetX + (uint32_t)blockWidth  < imageWidth  ? blockWidth  : blockWidth  - 1;
    
      uint64_t ssErr = 0; // sum of squared diffs
      uint64_t saAct = 0; // sum of abs. activity
    
      double msAct;
      int x, y;
    
      // calculate image differences and activity
      for (y = 0; y < blockHeight; y++)  // error
      {
        for (x = 0; x < blockWidth; x++)
        {
    
          const     int64_t iDiff = (int64_t)o[y*O + x] - (int64_t)r[y*R + x];
    
          ssErr += uint64_t(iDiff * iDiff);
        }
      }
      if (wAct <= xAct || hAct <= yAct) return (double)ssErr;
    
      for (y = yAct; y < hAct; y++)   // activity
      {
        for (x = xAct; x < wAct; x++)
        {
    
          const int f = 12 * (int)o[y*O + x] - 2 * ((int)o[y*O + x-1] + (int)o[y*O + x+1] + (int)o[(y-1)*O + x] + (int)o[(y+1)*O + x])
                           - (int)o[(y-1)*O + x-1] - (int)o[(y-1)*O + x+1] - (int)o[(y+1)*O + x-1] - (int)o[(y+1)*O + x+1];
          saAct += abs(f);
    
        }
      }
    
      // calculate weight (mean squared activity)
      msAct = (double)saAct / (double(wAct - xAct) * double(hAct - yAct));
    
    
      // lower limit, accounts for high-pass gain
      if (msAct < double(1 << (bitDepth - 4))) msAct = double(1 << (bitDepth - 4));
    
    
      msAct *= msAct; // because ssErr is squared
    
      sumAct += msAct; // includes high-pass gain
    
      // calculate activity weighted error square
      return (double)ssErr * pow(msAct, -1.0 * BETA);
    }
    #endif // ENABLE_QPA
    
    uint64_t EncGOP::xFindDistortionPlane(const CPelBuf& pic0, const CPelBuf& pic1, const uint32_t rshift
    #if ENABLE_QPA
    
                                        , const uint32_t chromaShift /*= 0*/
    
    {
      uint64_t uiTotalDiff;
      const  Pel*  pSrc0 = pic0.bufAt(0, 0);
      const  Pel*  pSrc1 = pic1.bufAt(0, 0);
    
      CHECK(pic0.width  != pic1.width , "Unspecified error");
      CHECK(pic0.height != pic1.height, "Unspecified error");
    
      if( rshift > 0 )
      {
    #if ENABLE_QPA
        const   uint32_t  BD = rshift;      // image bit-depth
        if (BD >= 8)
        {
          const uint32_t   W = pic0.width;  // image width
          const uint32_t   H = pic0.height; // image height
    
          const double     R = double(W * H) / (1920.0 * 1080.0);
    
          const uint32_t   B = Clip3<uint32_t>(0, 128 >> chromaShift, 4 * uint32_t(16.0 * sqrt(R) + 0.5)); // WPSNR block size in integer multiple of 4 (for SIMD, = 64 at full-HD)
    
          uint32_t x, y;
    
          if (B < 4) // image is too small to use WPSNR, resort to traditional PSNR
          {
            uiTotalDiff = 0;
            for (y = 0; y < H; y++)
            {
              for (x = 0; x < W; x++)
              {
    
                const           int64_t iDiff = (int64_t)pSrc0[x] - (int64_t)pSrc1[x];
    
                uiTotalDiff += uint64_t(iDiff * iDiff);
              }
              pSrc0 += pic0.stride;
              pSrc1 += pic1.stride;
            }
            return uiTotalDiff;
          }
    
          double wmse = 0.0, sumAct = 0.0; // compute activity normalized SNR value
    
              wmse += calcWeightedSquaredError(pic1,   pic0,
                                               sumAct, BD,
                                               W,      H,
                                               x,      y,
                                               B,      B);
    
          sumAct = 16.0 * sqrt ((3840.0 * 2160.0) / double((W << chromaShift) * (H << chromaShift))) * double(1 << BD);
    
          return (wmse <= 0.0) ? 0 : uint64_t(wmse * pow(sumAct, BETA) + 0.5);
        }
    #endif // ENABLE_QPA
        uiTotalDiff = 0;
        for (int y = 0; y < pic0.height; y++)
        {
          for (int x = 0; x < pic0.width; x++)
          {
            Intermediate_Int iTemp = pSrc0[x] - pSrc1[x];
            uiTotalDiff += uint64_t((iTemp * iTemp) >> rshift);
          }
          pSrc0 += pic0.stride;
          pSrc1 += pic1.stride;
        }
      }
      else
      {
        uiTotalDiff = 0;
        for (int y = 0; y < pic0.height; y++)
        {
          for (int x = 0; x < pic0.width; x++)
          {
            Intermediate_Int iTemp = pSrc0[x] - pSrc1[x];
            uiTotalDiff += uint64_t(iTemp * iTemp);
          }
          pSrc0 += pic0.stride;
          pSrc1 += pic1.stride;
        }
      }
    
      return uiTotalDiff;
    }
    #if WCG_WPSNR
    
    double EncGOP::xFindDistortionPlaneWPSNR(const CPelBuf& pic0, const CPelBuf& pic1, const uint32_t rshift, const CPelBuf& picLuma0,
    
    Taoran Lu's avatar
    Taoran Lu committed
      const bool    useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ);
    
      if (!useLumaWPSNR)
      {
        return 0;
      }
    
      double uiTotalDiffWPSNR;
      const  Pel*  pSrc0 = pic0.bufAt(0, 0);
      const  Pel*  pSrc1 = pic1.bufAt(0, 0);
      const  Pel*  pSrcLuma = picLuma0.bufAt(0, 0);
      CHECK(pic0.width  != pic1.width , "Unspecified error");
      CHECK(pic0.height != pic1.height, "Unspecified error");
    
      if( rshift > 0 )
      {
        uiTotalDiffWPSNR = 0;
        for (int y = 0; y < pic0.height; y++)
        {
          for (int x = 0; x < pic0.width; x++)
          {
            Intermediate_Int iTemp = pSrc0[x] - pSrc1[x];
            double dW = m_pcEncLib->getRdCost()->getWPSNRLumaLevelWeight(pSrcLuma[(x << getComponentScaleX(compID, chfmt))]);
            uiTotalDiffWPSNR += ((dW * (double)iTemp * (double)iTemp)) * (double)(1 >> rshift);
          }
          pSrc0 += pic0.stride;
          pSrc1 += pic1.stride;
          pSrcLuma += picLuma0.stride << getComponentScaleY(compID, chfmt);
        }
      }
      else
      {
        uiTotalDiffWPSNR = 0;
        for (int y = 0; y < pic0.height; y++)
        {
          for (int x = 0; x < pic0.width; x++)
          {
            Intermediate_Int iTemp = pSrc0[x] - pSrc1[x];
            double dW = m_pcEncLib->getRdCost()->getWPSNRLumaLevelWeight(pSrcLuma[x << getComponentScaleX(compID, chfmt)]);
            uiTotalDiffWPSNR += dW * (double)iTemp * (double)iTemp;
          }
          pSrc0 += pic0.stride;
          pSrc1 += pic1.stride;
          pSrcLuma += picLuma0.stride << getComponentScaleY(compID, chfmt);
        }
      }
    
      return uiTotalDiffWPSNR;
    }
    #endif
    
    
    void EncGOP::xCalculateAddPSNRs( const bool isField, const bool isFieldTopFieldFirst, const int iGOPid, Picture* pcPic, const AccessUnit&accessUnit, PicList &rcListPic, const int64_t dEncTime, const InputColourSpaceConversion snr_conversion, const bool printFrameMSE, double* PSNR_Y
                                   , bool isEncodeLtRef
    )
    
      xCalculateAddPSNR(pcPic, pcPic->getRecoBuf(), accessUnit, (double)dEncTime, snr_conversion, printFrameMSE, PSNR_Y
                      , isEncodeLtRef
      );
    
    
      //In case of field coding, compute the interlaced PSNR for both fields
      if(isField)
      {
        bool bothFieldsAreEncoded = false;
        int correspondingFieldPOC = pcPic->getPOC();
        int currentPicGOPPoc = m_pcCfg->getGOPEntry(iGOPid).m_POC;
        if(pcPic->getPOC() == 0)
        {
          // particular case for POC 0 and 1.
          // If they are not encoded first and separately from other pictures, we need to change this
          // POC 0 is always encoded first then POC 1 is encoded
          bothFieldsAreEncoded = false;
        }
        else if(pcPic->getPOC() == 1)
        {
          // if we are at POC 1, POC 0 has been encoded for sure
          correspondingFieldPOC = 0;
          bothFieldsAreEncoded = true;
        }
        else
        {
          if(pcPic->getPOC()%2 == 1)
          {
            correspondingFieldPOC -= 1; // all odd POC are associated with the preceding even POC (e.g poc 1 is associated to poc 0)
            currentPicGOPPoc      -= 1;
          }
          else
          {
            correspondingFieldPOC += 1; // all even POC are associated with the following odd POC (e.g poc 0 is associated to poc 1)
            currentPicGOPPoc      += 1;
          }
          for(int i = 0; i < m_iGopSize; i ++)
          {
            if(m_pcCfg->getGOPEntry(i).m_POC == currentPicGOPPoc)
            {
              bothFieldsAreEncoded = m_pcCfg->getGOPEntry(i).m_isEncoded;
              break;
            }
          }
        }
    
        if(bothFieldsAreEncoded)
        {
          //get complementary top field
          PicList::iterator   iterPic = rcListPic.begin();
          while ((*iterPic)->getPOC() != correspondingFieldPOC)
          {
            iterPic ++;
          }
          Picture* correspondingFieldPic = *(iterPic);
    
    
          if ((pcPic->topField && isFieldTopFieldFirst) || (!pcPic->topField && !isFieldTopFieldFirst))
    
            xCalculateInterlacedAddPSNR(pcPic, correspondingFieldPic, pcPic->getRecoBuf(), correspondingFieldPic->getRecoBuf(), snr_conversion, printFrameMSE, PSNR_Y
              , isEncodeLtRef
            );
    
            xCalculateInterlacedAddPSNR(correspondingFieldPic, pcPic, correspondingFieldPic->getRecoBuf(), pcPic->getRecoBuf(), snr_conversion, printFrameMSE, PSNR_Y
              , isEncodeLtRef
            );
    
    void EncGOP::xCalculateAddPSNR(Picture* pcPic, PelUnitBuf cPicD, const AccessUnit& accessUnit, double dEncTime, const InputColourSpaceConversion conversion, const bool printFrameMSE, double* PSNR_Y
                                  , bool isEncodeLtRef
    )
    
    {
      const SPS&         sps = *pcPic->cs->sps;
      const CPelUnitBuf& pic = cPicD;
      CHECK(!(conversion == IPCOLOURSPACE_UNCHANGED), "Unspecified error");
    //  const CPelUnitBuf& org = (conversion != IPCOLOURSPACE_UNCHANGED) ? pcPic->getPicYuvTrueOrg()->getBuf() : pcPic->getPicYuvOrg()->getBuf();
    
    Taoran Lu's avatar
    Taoran Lu committed
      const CPelUnitBuf& org = sps.getUseReshaper() ? pcPic->getTrueOrigBuf() : pcPic->getOrigBuf();
    
    #if ENABLE_QPA
      const bool    useWPSNR = m_pcEncLib->getUseWPSNR();
    #endif
      double  dPSNR[MAX_NUM_COMPONENT];
    #if WCG_WPSNR
    
    Taoran Lu's avatar
    Taoran Lu committed
      const bool    useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ);
    
      double  dPSNRWeighted[MAX_NUM_COMPONENT];
      double  MSEyuvframeWeighted[MAX_NUM_COMPONENT];
    
    #endif
    #if RPR_CTC_PRINT
      double  upscaledPSNR[MAX_NUM_COMPONENT];
    
    #endif
      for(int i=0; i<MAX_NUM_COMPONENT; i++)
      {
        dPSNR[i]=0.0;
    #if WCG_WPSNR
        dPSNRWeighted[i]=0.0;
        MSEyuvframeWeighted[i] = 0.0;
    
    #endif
    #if RPR_CTC_PRINT
        upscaledPSNR[i] = 0.0;
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
      double deltaE[hdrtoolslib::NB_REF_WHITE];
      double psnrL[hdrtoolslib::NB_REF_WHITE];
      for (int i=0; i<hdrtoolslib::NB_REF_WHITE; i++)
      {
        deltaE[i] = 0.0;
        psnrL[i] = 0.0;
    
      PelStorage interm;
    
      if (conversion != IPCOLOURSPACE_UNCHANGED)
      {
        interm.create(pic.chromaFormat, Area(Position(), pic.Y()));
        VideoIOYuv::ColourSpaceConvert(pic, interm, conversion, false);
      }
    
      const CPelUnitBuf& picC = (conversion == IPCOLOURSPACE_UNCHANGED) ? pic : interm;
    
      //===== calculate PSNR =====
      double MSEyuvframe[MAX_NUM_COMPONENT] = {0, 0, 0};
      const ChromaFormat formatD = pic.chromaFormat;
      const ChromaFormat format  = sps.getChromaFormatIdc();
    
      const bool bPicIsField     = pcPic->fieldPic;
      const Slice*  pcSlice      = pcPic->slices[0];
    
    
    #if RPR_CTC_PRINT
      PelStorage upscaledRec;
    
      if( m_pcEncLib->isRPREnabled() )
      {
        const CPelBuf& upscaledOrg = sps.getUseReshaper() ? pcPic->m_bufs[PIC_TRUE_ORIGINAL_INPUT].get( COMPONENT_Y ) : pcPic->m_bufs[PIC_ORIGINAL_INPUT].get( COMPONENT_Y );
        upscaledRec.create( pic.chromaFormat, Area( Position(), upscaledOrg ) );
    
    #if RPR_CONF_WINDOW
    
        // the input source picture has a conformance window derived at encoder
        Window& conformanceWindow = m_pcEncLib->getConformanceWindow();
    
        Picture::rescalePicture( picC, pcPic->cs->pps->getConformanceWindow(), upscaledRec, conformanceWindow, format, sps.getBitDepths(), false );
    #else
        Picture::rescalePicture(picC, upscaledRec, format, sps.getBitDepths(), false);
    #endif
    
      for (int comp = 0; comp < ::getNumberValidComponents(formatD); comp++)
      {
        const ComponentID compID = ComponentID(comp);
        const CPelBuf&    p = picC.get(compID);
        const CPelBuf&    o = org.get(compID);
    
        CHECK(!( p.width  == o.width), "Unspecified error");
        CHECK(!( p.height == o.height), "Unspecified error");
    
        const uint32_t   width  = p.width  - (m_pcEncLib->getPad(0) >> ::getComponentScaleX(compID, format));
        const uint32_t   height = p.height - (m_pcEncLib->getPad(1) >> (!!bPicIsField+::getComponentScaleY(compID,format)));
    
        // create new buffers with correct dimensions
        const CPelBuf recPB(p.bufAt(0, 0), p.stride, width, height);
        const CPelBuf orgPB(o.bufAt(0, 0), o.stride, width, height);
        const uint32_t    bitDepth = sps.getBitDepth(toChannelType(compID));
    #if ENABLE_QPA
        const uint64_t uiSSDtemp = xFindDistortionPlane(recPB, orgPB, useWPSNR ? bitDepth : 0, ::getComponentScaleX(compID, format));
    #else
        const uint64_t uiSSDtemp = xFindDistortionPlane(recPB, orgPB, 0);
    #endif
    
        const uint32_t size   = width * height;
        const double fRefValue = (double)maxval * maxval * size;
        dPSNR[comp]       = uiSSDtemp ? 10.0 * log10(fRefValue / (double)uiSSDtemp) : 999.99;
        MSEyuvframe[comp] = (double)uiSSDtemp / size;
    #if WCG_WPSNR
    
        const double uiSSDtempWeighted = xFindDistortionPlaneWPSNR(recPB, orgPB, 0, org.get(COMPONENT_Y), compID, format);
    
        if (useLumaWPSNR)
        {
          dPSNRWeighted[comp] = uiSSDtempWeighted ? 10.0 * log10(fRefValue / (double)uiSSDtempWeighted) : 999.99;
          MSEyuvframeWeighted[comp] = (double)uiSSDtempWeighted / size;
        }
    #endif
    
    
    #if RPR_CTC_PRINT
        if( m_pcEncLib->isRPREnabled() )
        {
          const CPelBuf& upscaledOrg = sps.getUseReshaper() ? pcPic->m_bufs[PIC_TRUE_ORIGINAL_INPUT].get( compID ) : pcPic->m_bufs[PIC_ORIGINAL_INPUT].get( compID );
    
    #if ENABLE_QPA
          const uint64_t upscaledSSD = xFindDistortionPlane( upscaledRec.get( compID ), upscaledOrg, useWPSNR ? bitDepth : 0, ::getComponentScaleX( compID, format ) );
    #else
          const uint64_t scaledSSD = xFindDistortionPlane( upscaledRec.get( compID ), upscaledOrg, 0 );
    #endif
    
          upscaledPSNR[comp] = upscaledSSD ? 10.0 * log10( (double)maxval * maxval * upscaledOrg.width * upscaledOrg.height / (double)upscaledSSD ) : 999.99;
        }
    #endif
    
      }
    
    #if EXTENSION_360_VIDEO
      m_ext360.calculatePSNRs(pcPic);
    #endif
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
      const bool calculateHdrMetrics = m_pcEncLib->getCalcluateHdrMetrics();
    
      {
        auto beforeTime = std::chrono::steady_clock::now();
    
        xCalculateHDRMetrics(pcPic, deltaE, psnrL);
    
        auto elapsed = std::chrono::steady_clock::now() - beforeTime;
        m_metricTime += elapsed;
      }
    #endif
    
      /* calculate the size of the access unit, excluding:
       *  - any AnnexB contributions (start_code_prefix, zero_byte, etc.,)
       *  - SEI NAL units
       */
      uint32_t numRBSPBytes = 0;
      for (AccessUnit::const_iterator it = accessUnit.begin(); it != accessUnit.end(); it++)
      {
        uint32_t numRBSPBytes_nal = uint32_t((*it)->m_nalUnitData.str().size());
        if (m_pcCfg->getSummaryVerboseness() > 0)
        {
          msg( NOTICE, "*** %6s numBytesInNALunit: %u\n", nalUnitTypeToString((*it)->m_nalUnitType), numRBSPBytes_nal);
        }
        if( ( *it )->m_nalUnitType != NAL_UNIT_PREFIX_SEI && ( *it )->m_nalUnitType != NAL_UNIT_SUFFIX_SEI )
        {
          numRBSPBytes += numRBSPBytes_nal;
    
    Lidong Xu's avatar
    Lidong Xu committed
          if (it == accessUnit.begin() || (*it)->m_nalUnitType == NAL_UNIT_VPS || (*it)->m_nalUnitType == NAL_UNIT_DPS || (*it)->m_nalUnitType == NAL_UNIT_SPS || (*it)->m_nalUnitType == NAL_UNIT_PPS)
    
          {
            numRBSPBytes += 4;
          }
          else
          {
            numRBSPBytes += 3;
          }
        }
      }
    
      uint32_t uibits = numRBSPBytes * 8;
      m_vRVM_RP.push_back( uibits );
    
      //===== add PSNR =====
    
      m_gcAnalyzeAll.addResult(dPSNR, (double)uibits, MSEyuvframe
    
    #if EXTENSION_360_VIDEO
      m_ext360.addResult(m_gcAnalyzeAll);
    #endif
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
      if (calculateHdrMetrics)
      {
        m_gcAnalyzeAll.addHDRMetricsResult(deltaE, psnrL);
    
        m_gcAnalyzeI.addResult(dPSNR, (double)uibits, MSEyuvframe
    
        *PSNR_Y = dPSNR[COMPONENT_Y];
    #if EXTENSION_360_VIDEO
        m_ext360.addResult(m_gcAnalyzeI);
    #endif
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
        if (calculateHdrMetrics)
        {
          m_gcAnalyzeI.addHDRMetricsResult(deltaE, psnrL);
    
        m_gcAnalyzeP.addResult(dPSNR, (double)uibits, MSEyuvframe
    
        *PSNR_Y = dPSNR[COMPONENT_Y];
    #if EXTENSION_360_VIDEO
        m_ext360.addResult(m_gcAnalyzeP);
    #endif
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
        if (calculateHdrMetrics)
        {
          m_gcAnalyzeP.addHDRMetricsResult(deltaE, psnrL);
    
        m_gcAnalyzeB.addResult(dPSNR, (double)uibits, MSEyuvframe
    
        *PSNR_Y = dPSNR[COMPONENT_Y];
    #if EXTENSION_360_VIDEO
        m_ext360.addResult(m_gcAnalyzeB);
    #endif
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
        if (calculateHdrMetrics)
        {
          m_gcAnalyzeB.addHDRMetricsResult(deltaE, psnrL);
    
    #if RPR_CTC_PRINT
        m_gcAnalyzeWPSNR.addResult( dPSNRWeighted, (double)uibits, MSEyuvframeWeighted, upscaledPSNR, isEncodeLtRef );
    #else
    
        m_gcAnalyzeWPSNR.addResult(dPSNRWeighted, (double)uibits, MSEyuvframeWeighted, isEncodeLtRef);
    
      }
    #endif
    
      char c = (pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B');
      if (! pcPic->referenced)
      {
        c += 32;
      }
    
      if( g_verbosity >= NOTICE )
      {
        msg( NOTICE, "POC %4d TId: %1d ( %c-SLICE, QP %d ) %10d bits",
    
             pcSlice->getPOC(),
    
             pcSlice->getTLayer(),
             c,
             pcSlice->getSliceQp(),
             uibits );
    
        msg( NOTICE, " [Y %6.4lf dB    U %6.4lf dB    V %6.4lf dB]", dPSNR[COMPONENT_Y], dPSNR[COMPONENT_Cb], dPSNR[COMPONENT_Cr] );
    
    
    #if EXTENSION_360_VIDEO
        m_ext360.printPerPOCInfo(NOTICE);
    #endif
    
    
        if (m_pcEncLib->getPrintHexPsnr())
        {
          uint64_t xPsnr[MAX_NUM_COMPONENT];
          for (int i = 0; i < MAX_NUM_COMPONENT; i++)
          {
            copy(reinterpret_cast<uint8_t *>(&dPSNR[i]),
                 reinterpret_cast<uint8_t *>(&dPSNR[i]) + sizeof(dPSNR[i]),
                 reinterpret_cast<uint8_t *>(&xPsnr[i]));
          }
          msg(NOTICE, " [xY %16" PRIx64 " xU %16" PRIx64 " xV %16" PRIx64 "]", xPsnr[COMPONENT_Y], xPsnr[COMPONENT_Cb], xPsnr[COMPONENT_Cr]);
    
    #if EXTENSION_360_VIDEO
    
          m_ext360.printPerPOCInfo(NOTICE, true);
    
    
        if( printFrameMSE )
        {
          msg( NOTICE, " [Y MSE %6.4lf  U MSE %6.4lf  V MSE %6.4lf]", MSEyuvframe[COMPONENT_Y], MSEyuvframe[COMPONENT_Cb], MSEyuvframe[COMPONENT_Cr] );
        }
    #if WCG_WPSNR
        if (useLumaWPSNR)
        {
          msg(NOTICE, " [WY %6.4lf dB    WU %6.4lf dB    WV %6.4lf dB]", dPSNRWeighted[COMPONENT_Y], dPSNRWeighted[COMPONENT_Cb], dPSNRWeighted[COMPONENT_Cr]);
    
    
          if (m_pcEncLib->getPrintHexPsnr())
          {
            uint64_t xPsnrWeighted[MAX_NUM_COMPONENT];
            for (int i = 0; i < MAX_NUM_COMPONENT; i++)
            {
              copy(reinterpret_cast<uint8_t *>(&dPSNRWeighted[i]),
                   reinterpret_cast<uint8_t *>(&dPSNRWeighted[i]) + sizeof(dPSNRWeighted[i]),
                   reinterpret_cast<uint8_t *>(&xPsnrWeighted[i]));
            }
            msg(NOTICE, " [xWY %16" PRIx64 " xWU %16" PRIx64 " xWV %16" PRIx64 "]", xPsnrWeighted[COMPONENT_Y], xPsnrWeighted[COMPONENT_Cb], xPsnrWeighted[COMPONENT_Cr]);
          }
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
    
        if(calculateHdrMetrics)
        {
          for (int i=0; i<1; i++)
          {
            msg(NOTICE, " [DeltaE%d %6.4lf dB]", (int)m_pcCfg->getWhitePointDeltaE(i), deltaE[i]);
    
            if (m_pcEncLib->getPrintHexPsnr())
            {
              int64_t xdeltaE[MAX_NUM_COMPONENT];
              for (int i = 0; i < 1; i++)
              {
                copy(reinterpret_cast<uint8_t *>(&deltaE[i]),
                     reinterpret_cast<uint8_t *>(&deltaE[i]) + sizeof(deltaE[i]),
                     reinterpret_cast<uint8_t *>(&xdeltaE[i]));
              }
              msg(NOTICE, " [xDeltaE%d %16" PRIx64 "]", (int)m_pcCfg->getWhitePointDeltaE(i), xdeltaE[0]);
            }
    
          }
          for (int i=0; i<1; i++)
          {
            msg(NOTICE, " [PSNRL%d %6.4lf dB]", (int)m_pcCfg->getWhitePointDeltaE(i), psnrL[i]);
    
            
            if (m_pcEncLib->getPrintHexPsnr())
            {
              int64_t xpsnrL[MAX_NUM_COMPONENT];
              for (int i = 0; i < 1; i++)
              {
                copy(reinterpret_cast<uint8_t *>(&psnrL[i]),
                     reinterpret_cast<uint8_t *>(&psnrL[i]) + sizeof(psnrL[i]),
                     reinterpret_cast<uint8_t *>(&xpsnrL[i]));
              }
              msg(NOTICE, " [xPSNRL%d %16" PRIx64 "]", (int)m_pcCfg->getWhitePointDeltaE(i), xpsnrL[0]);
              
            }
    
    #endif
        msg( NOTICE, " [ET %5.0f ]", dEncTime );
    
        // msg( SOME, " [WP %d]", pcSlice->getUseWeightedPrediction());
    
        for( int iRefList = 0; iRefList < 2; iRefList++ )
        {
          msg( NOTICE, " [L%d ", iRefList );
          for( int iRefIndex = 0; iRefIndex < pcSlice->getNumRefIdx( RefPicList( iRefList ) ); iRefIndex++ )
          {
    
    #if RPR_CTC_PRINT
            if( m_pcEncLib->isRPREnabled() )
            {
              const Picture* refPic = pcSlice->getRefPic( RefPicList( iRefList ), iRefIndex );
    
              int xScale, yScale;
              CU::getRprScaling( pcSlice->getSPS(), pcSlice->getPPS(), refPic->unscaledPic->cs->pps, xScale, yScale );
    
              if( pcSlice->getEnableTMVPFlag() && pcSlice->getColFromL0Flag() == bool( 1 - iRefList ) && pcSlice->getColRefIdx() == iRefIndex )
              {
                msg( NOTICE, "%dc(%1.2lfx, %1.2lfx) ", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( xScale ) / ( 1 << 14 ), double( yScale ) / ( 1 << 14 ) );
              }
              else
              {
                msg( NOTICE, "%d(%1.2lfx, %1.2lfx) ", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( xScale ) / ( 1 << 14 ), double( yScale ) / ( 1 << 14 ) );
              }
            }
            else
    #endif
    
            msg( NOTICE, "%d ", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
    
    #if RPR_CTC_PRINT
        if( m_pcEncLib->isRPREnabled() )
        {
          msg( NOTICE, "\nPSNR2: [Y %6.4lf dB    U %6.4lf dB    V %6.4lf dB]", upscaledPSNR[COMPONENT_Y], upscaledPSNR[COMPONENT_Cb], upscaledPSNR[COMPONENT_Cr] );
        }
    #endif
    
      }
      else if( g_verbosity >= INFO )
      {
        std::cout << "\r\t" << pcSlice->getPOC();
        std::cout.flush();
      }
    }
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
    
    void EncGOP::xCalculateHDRMetrics( Picture* pcPic, double deltaE[hdrtoolslib::NB_REF_WHITE], double psnrL[hdrtoolslib::NB_REF_WHITE])
    
      ChromaFormat chFmt =  pcPic->chromaFormat;
    
        m_pcConvertFormat->process(m_ppcFrameOrg[1], m_ppcFrameOrg[0]);
        m_pcConvertFormat->process(m_ppcFrameRec[1], m_ppcFrameRec[0]);
      }
    
      m_pcConvertIQuantize->process(m_ppcFrameOrg[2], m_ppcFrameOrg[1]);
      m_pcConvertIQuantize->process(m_ppcFrameRec[2], m_ppcFrameRec[1]);
    
      m_pcColorTransform->process(m_ppcFrameOrg[3], m_ppcFrameOrg[2]);
      m_pcColorTransform->process(m_ppcFrameRec[3], m_ppcFrameRec[2]);
    
      m_pcTransferFct->forward(m_ppcFrameOrg[4], m_ppcFrameOrg[3]);
      m_pcTransferFct->forward(m_ppcFrameRec[4], m_ppcFrameRec[3]);
    
      // Calculate the Metrics
      m_pcDistortionDeltaE->computeMetric(m_ppcFrameOrg[4], m_ppcFrameRec[4]);
    
      *deltaE = m_pcDistortionDeltaE->getDeltaE();
      *psnrL  = m_pcDistortionDeltaE->getPsnrL();
    
    }
    
    void EncGOP::copyBuftoFrame( Picture* pcPic )
    {
      int cropOffsetLeft   = m_pcCfg->getCropOffsetLeft();
      int cropOffsetTop    = m_pcCfg->getCropOffsetTop();
      int cropOffsetRight  = m_pcCfg->getCropOffsetRight();
      int cropOffsetBottom = m_pcCfg->getCropOffsetBottom();
    
      int height = pcPic->getOrigBuf(COMPONENT_Y).height - cropOffsetLeft + cropOffsetRight;
      int width = pcPic->getOrigBuf(COMPONENT_Y).width - cropOffsetTop + cropOffsetBottom;
    
      ChromaFormat chFmt =  pcPic->chromaFormat;
    
      Pel* pOrg = pcPic->getOrigBuf(COMPONENT_Y).buf;
      Pel* pRec = pcPic->getRecoBuf(COMPONENT_Y).buf;
    
      uint16_t* yOrg = m_ppcFrameOrg[0]->m_ui16Comp[hdrtoolslib::Y_COMP];
      uint16_t* yRec = m_ppcFrameRec[0]->m_ui16Comp[hdrtoolslib::Y_COMP];
      uint16_t* uOrg = m_ppcFrameOrg[0]->m_ui16Comp[hdrtoolslib::Cb_COMP];
      uint16_t* uRec = m_ppcFrameRec[0]->m_ui16Comp[hdrtoolslib::Cb_COMP];
      uint16_t* vOrg = m_ppcFrameOrg[0]->m_ui16Comp[hdrtoolslib::Cr_COMP];
      uint16_t* vRec = m_ppcFrameRec[0]->m_ui16Comp[hdrtoolslib::Cr_COMP];
    
      if(chFmt == CHROMA_444){
        yOrg = m_ppcFrameOrg[1]->m_ui16Comp[hdrtoolslib::Y_COMP];
        yRec = m_ppcFrameRec[1]->m_ui16Comp[hdrtoolslib::Y_COMP];
        uOrg = m_ppcFrameOrg[1]->m_ui16Comp[hdrtoolslib::Cb_COMP];
        uRec = m_ppcFrameRec[1]->m_ui16Comp[hdrtoolslib::Cb_COMP];
        vOrg = m_ppcFrameOrg[1]->m_ui16Comp[hdrtoolslib::Cr_COMP];
        vRec = m_ppcFrameRec[1]->m_ui16Comp[hdrtoolslib::Cr_COMP];
      }
    
      for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
          yOrg[i*width + j] = static_cast<uint16_t>(pOrg[(i + cropOffsetTop) * pcPic->getOrigBuf(COMPONENT_Y).stride + j + cropOffsetLeft]);
          yRec[i*width + j] = static_cast<uint16_t>(pRec[(i + cropOffsetTop) * pcPic->getRecoBuf(COMPONENT_Y).stride + j + cropOffsetLeft]);