Skip to content
Snippets Groups Projects
EncGOP.cpp 265 KiB
Newer Older
  • Learn to ignore specific revisions
  •   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,
    #if MSSIM_UNIFORM_METRICS_LOG
                                    const bool printMSSSIM,
    #endif
                                    double *PSNR_Y, bool isEncodeLtRef)
    
      xCalculateAddPSNR(pcPic, pcPic->getRecoBuf(), accessUnit, (double) dEncTime, snr_conversion, printFrameMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                        printMSSSIM,
    #endif
                        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,
    #if MSSIM_UNIFORM_METRICS_LOG
                                        printMSSSIM,
    #endif
                                        PSNR_Y, isEncodeLtRef);
    
            xCalculateInterlacedAddPSNR(correspondingFieldPic, pcPic, correspondingFieldPic->getRecoBuf(),
                                        pcPic->getRecoBuf(), snr_conversion, printFrameMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                                        printMSSSIM,
    #endif
                                        PSNR_Y, isEncodeLtRef);
    
    void EncGOP::xCalculateAddPSNR(Picture *pcPic, PelUnitBuf cPicD, const AccessUnit &accessUnit, double dEncTime,
                                   const InputColourSpaceConversion conversion, const bool printFrameMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                                   const bool printMSSSIM,
    #endif
                                   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();
    
      const CPelUnitBuf& org = (sps.getUseLmcs() || m_pcCfg->getGopBasedTemporalFilterEnabled()) ? pcPic->getTrueOrigBuf() : pcPic->getOrigBuf();
    
    #if ENABLE_QPA
      const bool    useWPSNR = m_pcEncLib->getUseWPSNR();
    #endif
      double  dPSNR[MAX_NUM_COMPONENT];
    
    #if MSSIM_UNIFORM_METRICS_LOG
      double msssim[MAX_NUM_COMPONENT] = {0.0,0.0,0.0};
    #endif
    
      const bool    useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getLmcs() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ);
    
      double  dPSNRWeighted[MAX_NUM_COMPONENT];
      double  MSEyuvframeWeighted[MAX_NUM_COMPONENT];
    
    #endif
      double  upscaledPSNR[MAX_NUM_COMPONENT];
    
      double  upscaledMsssim[MAX_NUM_COMPONENT];
    
      for(int i=0; i<MAX_NUM_COMPONENT; i++)
      {
        dPSNR[i]=0.0;
    #if WCG_WPSNR
        dPSNRWeighted[i]=0.0;
        MSEyuvframeWeighted[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 (m_pcEncLib->isResChangeInClvsEnabled())
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        const CPelBuf& upscaledOrg = ( sps.getUseLmcs() || m_pcCfg->getGopBasedTemporalFilterEnabled() ) ? pcPic->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).get( COMPONENT_Y ) : pcPic->M_BUFS( 0, PIC_ORIGINAL_INPUT ).get( COMPONENT_Y );
    
        upscaledRec.create( pic.chromaFormat, Area( Position(), upscaledOrg ) );
    
    
        int xScale, yScale;
        // it is assumed that full resolution picture PPS has ppsId 0
        const PPS* pps = m_pcEncLib->getPPS(0);
        CU::getRprScaling( &sps, pps, pcPic, xScale, yScale );
        std::pair<int, int> scalingRatio = std::pair<int, int>( xScale, yScale );
    
    
    #if JVET_AB0082
        bool rescaleForDisplay = true;
        Picture::rescalePicture(scalingRatio, picC, pcPic->getScalingWindow(), upscaledRec, pps->getScalingWindow(), format, sps.getBitDepths(), false, false, sps.getHorCollocatedChromaFlag(), sps.getVerCollocatedChromaFlag(), rescaleForDisplay, m_pcCfg->getUpscaleFilerForDisplay());
    #else
    
        Picture::rescalePicture( scalingRatio, picC, pcPic->getScalingWindow(), upscaledRec, pps->getScalingWindow(), format, sps.getBitDepths(), false, false, sps.getHorCollocatedChromaFlag(), sps.getVerCollocatedChromaFlag() );
    
      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");
    
    
    #if JVET_AA0146_WRAP_AROUND_FIX
        int padX = m_pcEncLib->getSourcePadding( 0 );
        int padY = m_pcEncLib->getSourcePadding( 1 );
    #else
    
        int padX = m_pcEncLib->getPad( 0 );
        int padY = m_pcEncLib->getPad( 1 );
    
    
        // when RPR is enabled, picture padding is picture specific due to possible different picture resoluitons, however only full resolution padding is stored in EncLib
        // get per picture padding from the conformance window, in this case if conformance window is set not equal to the padding then PSNR results may be inaccurate
    
        if (m_pcEncLib->isResChangeInClvsEnabled())
    
        {
          Window& conf = pcPic->getConformanceWindow();
          padX = conf.getWindowRightOffset() * SPS::getWinUnitX( format );
          padY = conf.getWindowBottomOffset() * SPS::getWinUnitY( format );
        }
    
        const uint32_t width = p.width - ( padX >> ::getComponentScaleX( compID, format ) );
        const uint32_t height = p.height - ( padY >> ( !!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), ::getComponentScaleY(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 MSSIM_UNIFORM_METRICS_LOG
        if (printMSSSIM)
        {
          msssim[comp] = xCalculateMSSSIM(o.bufAt(0, 0), o.stride, p.bufAt(0, 0), p.stride, width, height, bitDepth);
        }
    #endif
    
        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 (m_pcEncLib->isResChangeInClvsEnabled())
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          const CPelBuf& upscaledOrg = ( sps.getUseLmcs() || m_pcCfg->getGopBasedTemporalFilterEnabled() ) ? pcPic->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).get( compID ) : pcPic->M_BUFS( 0, PIC_ORIGINAL_INPUT ).get( compID );
    
    #if JVET_AA0146_WRAP_AROUND_FIX
          const uint32_t upscaledWidth = upscaledOrg.width - ( m_pcEncLib->getSourcePadding( 0 ) >> ::getComponentScaleX( compID, format ) );
          const uint32_t upscaledHeight = upscaledOrg.height - ( m_pcEncLib->getSourcePadding( 1 ) >> ( !!bPicIsField + ::getComponentScaleY( compID, format ) ) );
    #else
    
          const uint32_t upscaledWidth = upscaledOrg.width - ( m_pcEncLib->getPad( 0 ) >> ::getComponentScaleX( compID, format ) );
          const uint32_t upscaledHeight = upscaledOrg.height - ( m_pcEncLib->getPad( 1 ) >> ( !!bPicIsField + ::getComponentScaleY( compID, format ) ) );
    
    
          // create new buffers with correct dimensions
          const CPelBuf upscaledRecPB( upscaledRec.get( compID ).bufAt( 0, 0 ), upscaledRec.get( compID ).stride, upscaledWidth, upscaledHeight );
          const CPelBuf upscaledOrgPB( upscaledOrg.bufAt( 0, 0 ), upscaledOrg.stride, upscaledWidth, upscaledHeight );
    
    #if ENABLE_QPA
          const uint64_t upscaledSSD = xFindDistortionPlane( upscaledRecPB, upscaledOrgPB, useWPSNR ? bitDepth : 0, ::getComponentScaleX( compID, format ) );
    #else
          const uint64_t scaledSSD = xFindDistortionPlane( upsacledRecPB, upsacledOrgPB, 0 );
    #endif
    
          upscaledPSNR[comp] = upscaledSSD ? 10.0 * log10( (double)maxval * maxval * upscaledWidth * upscaledHeight / (double)upscaledSSD ) : 999.99;
    
          upscaledMsssim[comp] = xCalculateMSSSIM (upscaledOrgPB.bufAt(0, 0), upscaledOrgPB.stride, upscaledRecPB.bufAt(0, 0), upscaledRecPB.stride, upscaledWidth, upscaledHeight, bitDepth);
    
      }
    
    #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;
    
          if (it == accessUnit.begin() || (*it)->m_nalUnitType == NAL_UNIT_VPS || (*it)->m_nalUnitType == NAL_UNIT_DCI || (*it)->m_nalUnitType == NAL_UNIT_SPS || (*it)->m_nalUnitType == NAL_UNIT_PPS || (*it)->m_nalUnitType == NAL_UNIT_PREFIX_APS || (*it)->m_nalUnitType == NAL_UNIT_SUFFIX_APS)
    
          {
            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, upscaledPSNR,
    #if MSSIM_UNIFORM_METRICS_LOG
                               msssim,
    
    #endif
                               isEncodeLtRef);
    
    #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, upscaledPSNR,
    #if MSSIM_UNIFORM_METRICS_LOG
                               msssim,
    
    #endif
                               isEncodeLtRef);
    
        *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, upscaledPSNR,
    #if MSSIM_UNIFORM_METRICS_LOG
                               msssim,
    
    #endif
                               isEncodeLtRef);
    
        *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, upscaledPSNR,
    #if MSSIM_UNIFORM_METRICS_LOG
                               msssim,
    
    #endif
                               isEncodeLtRef);
    
        *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);
    
        m_gcAnalyzeWPSNR.addResult(dPSNRWeighted, (double) uibits, MSEyuvframeWeighted, upscaledPSNR,
    #if MSSIM_UNIFORM_METRICS_LOG
                                   msssim,
    
    #endif
                                   isEncodeLtRef);
    
      }
    #endif
    
      char c = (pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B');
      if (! pcPic->referenced)
      {
        c += 32;
      }
    
      if (m_pcCfg->getDependentRAPIndicationSEIEnabled() && pcSlice->isDRAP()) c = 'D';
    
        msg( NOTICE, "POC %4d LId: %2d TId: %1d ( %s, %c-SLICE, QP %d ) %10d bits",
    
    Vadim Seregin's avatar
    Vadim Seregin committed
             pcSlice->getPOC(),
             pcSlice->getPic()->layerId,
    
             nalUnitTypeToString(pcSlice->getNalUnitType()),
    
             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 MSSIM_UNIFORM_METRICS_LOG
        if (printMSSSIM)
        {
          msg( NOTICE, " [MS-SSIM Y %1.6lf    U %1.6lf    V %1.6lf]", msssim[COMPONENT_Y], msssim[COMPONENT_Cb], msssim[COMPONENT_Cr] );
        }
    #endif
    
        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++ )
          {
    
            const std::pair<int, int>& scaleRatio = pcSlice->getScalingRatio( RefPicList( iRefList ), iRefIndex );
    
    Brian Heng's avatar
    Brian Heng committed
            if( pcPic->cs->picHeader->getEnableTMVPFlag() && pcSlice->getColFromL0Flag() == bool(1 - iRefList) && pcSlice->getColRefIdx() == iRefIndex )
    
              if( scaleRatio.first != 1 << SCALE_RATIO_BITS || scaleRatio.second != 1 << SCALE_RATIO_BITS )
              {
                msg( NOTICE, " %dc(%1.2lfx, %1.2lfx)", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( scaleRatio.first ) / ( 1 << SCALE_RATIO_BITS ), double( scaleRatio.second ) / ( 1 << SCALE_RATIO_BITS ) );
              }
    
              {
                msg( NOTICE, " %dc", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
              }
    
              if( scaleRatio.first != 1 << SCALE_RATIO_BITS || scaleRatio.second != 1 << SCALE_RATIO_BITS )
              {
                msg( NOTICE, " %d(%1.2lfx, %1.2lfx)", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( scaleRatio.first ) / ( 1 << SCALE_RATIO_BITS ), double( scaleRatio.second ) / ( 1 << SCALE_RATIO_BITS ) );
              }
    
              {
                msg( NOTICE, " %d", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
              }
    
    
            if( pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) == pcSlice->getPOC() )
            {
              msg( NOTICE, ".%d", pcSlice->getRefPic( RefPicList( iRefList ), iRefIndex )->layerId );
            }
    
        if (m_pcEncLib->isResChangeInClvsEnabled())
    
    #if JVET_W0134_UNIFORM_METRICS_LOG
    
          msg( NOTICE, " [Y2 %6.4lf dB  U2 %6.4lf dB  V2 %6.4lf dB]", upscaledPSNR[COMPONENT_Y], upscaledPSNR[COMPONENT_Cb], upscaledPSNR[COMPONENT_Cr] );
    
          msg( NOTICE, " MS-SSIM2: [Y %6.4lf  U %6.4lf  V %6.4lf ]", upscaledMsssim[COMPONENT_Y], upscaledMsssim[COMPONENT_Cb], upscaledMsssim[COMPONENT_Cr] );
    
          msg( NOTICE, "\nPSNR2: [Y %6.4lf dB    U %6.4lf dB    V %6.4lf dB]", upscaledPSNR[COMPONENT_Y], upscaledPSNR[COMPONENT_Cb], upscaledPSNR[COMPONENT_Cr] );
    
          msg( NOTICE, "\nMS-SSIM2: [Y %6.4lf  U %6.4lf  V %6.4lf ]", upscaledMsssim[COMPONENT_Y], upscaledMsssim[COMPONENT_Cb], upscaledMsssim[COMPONENT_Cr] );
    
      }
      else if( g_verbosity >= INFO )
      {
        std::cout << "\r\t" << pcSlice->getPOC();
        std::cout.flush();
      }
    }
    
    #if MSSIM_UNIFORM_METRICS_LOG
    double EncGOP::xCalculateMSSSIM(const Pel *org, const int orgStride, const Pel *rec, const int recStride,
                                    const int width, const int height, const uint32_t bitDepth)
    {
      const int MAX_MSSSIM_SCALE  = 5;
      const int WEIGHTING_MID_TAP = 5;
      const int WEIGHTING_SIZE    = WEIGHTING_MID_TAP * 2 + 1;
    
      uint32_t maxScale;
    
      // For low resolution videos determine number of scales
      if (width < 22 || height < 22)
      {
        maxScale = 1;
      }
      else if (width < 44 || height < 44)
      {
        maxScale = 2;
      }
      else if (width < 88 || height < 88)
      {
        maxScale = 3;
      }
      else if (width < 176 || height < 176)
      {
        maxScale = 4;
      }
      else
      {
        maxScale = 5;
      }
    
      assert(maxScale > 0 && maxScale <= MAX_MSSSIM_SCALE);
    
      // Normalized Gaussian mask design, 11*11, s.d. 1.5
      double weights[WEIGHTING_SIZE][WEIGHTING_SIZE];
      double coeffSum = 0.0;
      for (int y = 0; y < WEIGHTING_SIZE; y++)
      {
        for (int x = 0; x < WEIGHTING_SIZE; x++)
        {
          weights[y][x] =
            exp(-((y - WEIGHTING_MID_TAP) * (y - WEIGHTING_MID_TAP) + (x - WEIGHTING_MID_TAP) * (x - WEIGHTING_MID_TAP))
                / (WEIGHTING_MID_TAP - 0.5));
          coeffSum += weights[y][x];
        }
      }
    
      for (int y = 0; y < WEIGHTING_SIZE; y++)
      {
        for (int x = 0; x < WEIGHTING_SIZE; x++)
        {
          weights[y][x] /= coeffSum;
        }
      }
    
      // Resolution based weights
      const double exponentWeights[MAX_MSSSIM_SCALE][MAX_MSSSIM_SCALE] = { { 1.0, 0, 0, 0, 0 },
                                                                           { 0.1356, 0.8644, 0, 0, 0 },
                                                                           { 0.0711, 0.4530, 0.4760, 0, 0 },
                                                                           { 0.0517, 0.3295, 0.3462, 0.2726, 0 },
                                                                           { 0.0448, 0.2856, 0.3001, 0.2363, 0.1333 } };
    
      // Downsampling of data:
      std::vector<double> original[MAX_MSSSIM_SCALE];
      std::vector<double> recon[MAX_MSSSIM_SCALE];
    
      for (uint32_t scale = 0; scale < maxScale; scale++)
      {
        const int scaledHeight = height >> scale;
        const int scaledWidth  = width >> scale;
        original[scale].resize(scaledHeight * scaledWidth, double(0));
        recon[scale].resize(scaledHeight * scaledWidth, double(0));
      }
    
      // Initial [0] arrays to be a copy of the source data (but stored in array "double", not Pel array).
      for (int y = 0; y < height; y++)
      {
        for (int x = 0; x < width; x++)
        {
          original[0][y * width + x] = org[y * orgStride + x];
          recon[0][y * width + x]    = rec[y * recStride + x];
        }
      }
    
      // Set up other arrays to be average value of each 2x2 sample.
      for (uint32_t scale = 1; scale < maxScale; scale++)
      {
        const int scaledHeight = height >> scale;
        const int scaledWidth  = width >> scale;
        for (int y = 0; y < scaledHeight; y++)
        {
          for (int x = 0; x < scaledWidth; x++)
          {
            original[scale][y * scaledWidth + x] = (original[scale - 1][2 * y * (2 * scaledWidth) + 2 * x]
                                                    + original[scale - 1][2 * y * (2 * scaledWidth) + 2 * x + 1]
                                                    + original[scale - 1][(2 * y + 1) * (2 * scaledWidth) + 2 * x]
                                                    + original[scale - 1][(2 * y + 1) * (2 * scaledWidth) + 2 * x + 1])
                                                   / 4.0;
            recon[scale][y * scaledWidth + x] =
              (recon[scale - 1][2 * y * (2 * scaledWidth) + 2 * x] + recon[scale - 1][2 * y * (2 * scaledWidth) + 2 * x + 1]
               + recon[scale - 1][(2 * y + 1) * (2 * scaledWidth) + 2 * x]
               + recon[scale - 1][(2 * y + 1) * (2 * scaledWidth) + 2 * x + 1])
              / 4.0;
          }
        }
      }
    
      // Calculate MS-SSIM:
      const uint32_t maxValue = (1 << bitDepth) - 1;
      const double   c1       = (0.01 * maxValue) * (0.01 * maxValue);
      const double   c2       = (0.03 * maxValue) * (0.03 * maxValue);
    
      double finalMSSSIM = 1.0;
    
      for (uint32_t scale = 0; scale < maxScale; scale++)
      {
        const int scaledHeight    = height >> scale;
        const int scaledWidth     = width >> scale;
        const int blocksPerRow    = scaledWidth - WEIGHTING_SIZE + 1;
        const int blocksPerColumn = scaledHeight - WEIGHTING_SIZE + 1;
        const int totalBlocks     = blocksPerRow * blocksPerColumn;
    
        double meanSSIM = 0.0;
    
        for (int blockIndexY = 0; blockIndexY < blocksPerColumn; blockIndexY++)
        {
          for (int blockIndexX = 0; blockIndexX < blocksPerRow; blockIndexX++)
          {
            double muOrg         = 0.0;
            double muRec         = 0.0;
            double muOrigSqr     = 0.0;
            double muRecSqr      = 0.0;
            double muOrigMultRec = 0.0;
    
            for (int y = 0; y < WEIGHTING_SIZE; y++)
            {
              for (int x = 0; x < WEIGHTING_SIZE; x++)
              {
                const double gaussianWeight = weights[y][x];
                const int    sampleOffset   = (blockIndexY + y) * scaledWidth + (blockIndexX + x);
                const double orgPel         = original[scale][sampleOffset];
                const double recPel         = recon[scale][sampleOffset];
    
                muOrg += orgPel * gaussianWeight;
                muRec += recPel * gaussianWeight;
                muOrigSqr += orgPel * orgPel * gaussianWeight;
                muRecSqr += recPel * recPel * gaussianWeight;
                muOrigMultRec += orgPel * recPel * gaussianWeight;
              }
            }
    
            const double sigmaSqrOrig = muOrigSqr - (muOrg * muOrg);
            const double sigmaSqrRec  = muRecSqr - (muRec * muRec);
            const double sigmaOrigRec = muOrigMultRec - (muOrg * muRec);
    
            double blockSSIMVal = ((2.0 * sigmaOrigRec + c2) / (sigmaSqrOrig + sigmaSqrRec + c2));
            if (scale == maxScale - 1)
            {
              blockSSIMVal *= (2.0 * muOrg * muRec + c1) / (muOrg * muOrg + muRec * muRec + c1);
            }
    
            meanSSIM += blockSSIMVal;
          }
        }
    
        meanSSIM /= totalBlocks;
    
        finalMSSSIM *= pow(meanSSIM, exponentWeights[maxScale - 1][scale]);
      }
    
      return finalMSSSIM;
    }
    #endif
    
    #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->getTrueOrigBuf( COMPONENT_Y ).height - cropOffsetLeft + cropOffsetRight;
      int width = pcPic->getTrueOrigBuf( COMPONENT_Y ).width - cropOffsetTop + cropOffsetBottom;
    
      ChromaFormat chFmt =  pcPic->chromaFormat;
    
      Pel *pOrg = pcPic->getTrueOrigBuf( 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->getTrueOrigBuf( COMPONENT_Y ).stride + j + cropOffsetLeft]);
    
          yRec[i*width + j] = static_cast<uint16_t>(pRec[(i + cropOffsetTop) * pcPic->getRecoBuf(COMPONENT_Y).stride + j + cropOffsetLeft]);
    
        cropOffsetLeft >>= 1;
        cropOffsetTop >>= 1;
      }
    
      pOrg = pcPic->getTrueOrigBuf( COMPONENT_Cb ).buf;
    
      pRec = pcPic->getRecoBuf(COMPONENT_Cb).buf;
    
      for (int i = 0; i < height; i++)
      {
        for (int j = 0; j < width; j++)
        {
          uOrg[i * width + j] = static_cast< uint16_t >(pOrg[(i + cropOffsetTop) * pcPic->getTrueOrigBuf( COMPONENT_Cb ).stride + j + cropOffsetLeft]);
    
          uRec[i*width + j] = static_cast<uint16_t>(pRec[(i + cropOffsetTop) * pcPic->getRecoBuf(COMPONENT_Cb).stride + j + cropOffsetLeft]);
    
      pOrg = pcPic->getTrueOrigBuf( COMPONENT_Cr ).buf;
    
      pRec = pcPic->getRecoBuf(COMPONENT_Cr).buf;
    
      for (int i = 0; i < height; i++)
      {
        for (int j = 0; j < width; j++)
        {
          vOrg[i * width + j] = static_cast< uint16_t >(pOrg[(i + cropOffsetTop) * pcPic->getTrueOrigBuf( COMPONENT_Cr ).stride + j + cropOffsetLeft]);
    
          vRec[i*width + j] = static_cast<uint16_t>(pRec[(i + cropOffsetTop) * pcPic->getRecoBuf(COMPONENT_Cr).stride + j + cropOffsetLeft]);
    
    void EncGOP::xCalculateInterlacedAddPSNR( Picture* pcPicOrgFirstField, Picture* pcPicOrgSecondField,
                                              PelUnitBuf cPicRecFirstField, PelUnitBuf cPicRecSecondField,
    
                                             const InputColourSpaceConversion conversion, const bool printFrameMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                                             const bool printMSSSIM,
    #endif
                                             double *PSNR_Y, bool isEncodeLtRef)
    
    {
      const SPS &sps = *pcPicOrgFirstField->cs->sps;
      const ChromaFormat format = sps.getChromaFormatIdc();
      double  dPSNR[MAX_NUM_COMPONENT];
      Picture    *apcPicOrgFields[2] = {pcPicOrgFirstField, pcPicOrgSecondField};
      PelUnitBuf acPicRecFields[2]   = {cPicRecFirstField, cPicRecSecondField};
    #if ENABLE_QPA
      const bool    useWPSNR = m_pcEncLib->getUseWPSNR();
    #endif
      for(int i=0; i<MAX_NUM_COMPONENT; i++)
      {
        dPSNR[i]=0.0;
      }
    
      PelStorage cscd[2 /* first/second field */];
      if (conversion!=IPCOLOURSPACE_UNCHANGED)
      {
        for(uint32_t fieldNum=0; fieldNum<2; fieldNum++)
        {
          PelUnitBuf& reconField= (acPicRecFields[fieldNum]);
          cscd[fieldNum].create( reconField.chromaFormat, Area( Position(), reconField.Y()) );
          VideoIOYuv::ColourSpaceConvert(reconField, cscd[fieldNum], conversion, false);
          acPicRecFields[fieldNum]=cscd[fieldNum];
        }
      }
    
      //===== calculate PSNR =====
      double MSEyuvframe[MAX_NUM_COMPONENT] = {0, 0, 0};
    
    #if MSSIM_UNIFORM_METRICS_LOG
      double msssim[MAX_NUM_COMPONENT] = {0.0,0.,0.};
    #endif
    
    
      CHECK(!(acPicRecFields[0].chromaFormat==acPicRecFields[1].chromaFormat), "Unspecified error");
      const uint32_t numValidComponents = ::getNumberValidComponents( acPicRecFields[0].chromaFormat );
    
      for (int chan = 0; chan < numValidComponents; chan++)
      {
        const ComponentID ch=ComponentID(chan);
        CHECK(!(acPicRecFields[0].get(ch).width==acPicRecFields[1].get(ch).width), "Unspecified error");
        CHECK(!(acPicRecFields[0].get(ch).height==acPicRecFields[0].get(ch).height), "Unspecified error");
    
        uint64_t uiSSDtemp=0;
    
    #if JVET_AA0146_WRAP_AROUND_FIX
        const uint32_t width    = acPicRecFields[0].get(ch).width - (m_pcEncLib->getSourcePadding(0) >> ::getComponentScaleX(ch, format));
        const uint32_t height   = acPicRecFields[0].get(ch).height - ((m_pcEncLib->getSourcePadding(1) >> 1) >> ::getComponentScaleY(ch, format));
    #else
    
        const uint32_t width    = acPicRecFields[0].get(ch).width - (m_pcEncLib->getPad(0) >> ::getComponentScaleX(ch, format));
        const uint32_t height   = acPicRecFields[0].get(ch).height - ((m_pcEncLib->getPad(1) >> 1) >> ::getComponentScaleY(ch, format));
    
        const uint32_t bitDepth = sps.getBitDepth(toChannelType(ch));
    
    
    #if MSSIM_UNIFORM_METRICS_LOG
        double sumOverFieldsMSSSIM = 0;
    #endif
    
        for(uint32_t fieldNum=0; fieldNum<2; fieldNum++)
        {
          CHECK(!(conversion == IPCOLOURSPACE_UNCHANGED), "Unspecified error");
    #if ENABLE_QPA
    
          uiSSDtemp += xFindDistortionPlane( acPicRecFields[fieldNum].get(ch), apcPicOrgFields[fieldNum]->getOrigBuf().get(ch), useWPSNR ? bitDepth : 0, ::getComponentScaleX(ch, format), ::getComponentScaleY(ch, format) );
    
    #else
          uiSSDtemp += xFindDistortionPlane( acPicRecFields[fieldNum].get(ch), apcPicOrgFields[fieldNum]->getOrigBuf().get(ch), 0 );
    #endif
    
    #if MSSIM_UNIFORM_METRICS_LOG
          if (printMSSSIM)
          {
            CPelBuf o = apcPicOrgFields[fieldNum]->getOrigBuf().get(ch);
            CPelBuf p = acPicRecFields[fieldNum].get(ch);
            sumOverFieldsMSSSIM +=
              xCalculateMSSSIM(o.bufAt(0, 0), o.stride, p.bufAt(0, 0), p.stride, width, height, bitDepth);
        }
    #endif
        }
    #if MSSIM_UNIFORM_METRICS_LOG
        if (printMSSSIM)
        {
          msssim[ch] = sumOverFieldsMSSSIM / 2;
    
        const uint32_t maxval = 255 << (bitDepth - 8);
        const uint32_t size   = width * height * 2;
        const double fRefValue = (double)maxval * maxval * size;
        dPSNR[ch]         = uiSSDtemp ? 10.0 * log10(fRefValue / (double)uiSSDtemp) : 999.99;
        MSEyuvframe[ch]   = (double)uiSSDtemp / size;
      }
    
      uint32_t uibits = 0; // the number of bits for the pair is not calculated here - instead the overall total is used elsewhere.
    
      //===== add PSNR =====
    
      m_gcAnalyzeAll_in.addResult(dPSNR, (double) uibits, MSEyuvframe, MSEyuvframe,
    #if MSSIM_UNIFORM_METRICS_LOG
                                  msssim,
    
    #endif
                                  isEncodeLtRef);
    
      msg( INFO, "\n                                      Interlaced frame %d: [Y %6.4lf dB    U %6.4lf dB    V %6.4lf dB]", pcPicOrgSecondField->getPOC()/2, dPSNR[COMPONENT_Y], dPSNR[COMPONENT_Cb], dPSNR[COMPONENT_Cr] );
    
      if (printFrameMSE)
      {
        msg( DETAILS, " [Y MSE %6.4lf  U MSE %6.4lf  V MSE %6.4lf]", MSEyuvframe[COMPONENT_Y], MSEyuvframe[COMPONENT_Cb], MSEyuvframe[COMPONENT_Cr] );
      }
    
    #if MSSIM_UNIFORM_METRICS_LOG
      if (printMSSSIM)
      {
        printf(" [MS-SSIM Y %1.6lf    U %1.6lf    V %1.6lf]", msssim[COMPONENT_Y], msssim[COMPONENT_Cb], msssim[COMPONENT_Cr] );
      }
    #endif
    
      for(uint32_t fieldNum=0; fieldNum<2; fieldNum++)
      {
        cscd[fieldNum].destroy();
      }
    }
    
    /** Function for deciding the nal_unit_type.
     * \param pocCurr POC of the current picture
     * \param lastIDR  POC of the last IDR picture
     * \param isField  true to indicate field coding
     * \returns the NAL unit type of the picture
     * This function checks the configuration and returns the appropriate nal_unit_type for the picture.
     */
    NalUnitType EncGOP::getNalUnitType(int pocCurr, int lastIDR, bool isField)
    {
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
      if (m_pcCfg->getGdrEnabled() && m_pcCfg->getDecodingRefreshType() == 3 && (pocCurr >= m_pcCfg->getGdrPocStart()))
      {
        int m = pocCurr - m_pcCfg->getGdrPocStart();
        int n = m_pcCfg->getGdrPeriod();