Skip to content
Snippets Groups Projects
EncGOP.cpp 261 KiB
Newer Older
  • Learn to ignore specific revisions
  • Brian Heng's avatar
    Brian Heng committed
              //the inference for NoOutputPriorPicsFlag
              // KJS: This cannot happen at the encoder
    
              if( !m_bFirst && ( pcSlice->isIRAP() || pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_GDR ) && picHeader->getNoOutputBeforeRecoveryFlag() )
    
    Brian Heng's avatar
    Brian Heng committed
              {
                if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA || pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_GDR)
                {
    
    bdchoi's avatar
    bdchoi committed
    #if JVET_S0193_NO_OUTPUT_PRIOR_PIC
                  pcSlice->setNoOutputOfPriorPicsFlag(true);
    #else
    
    Brian Heng's avatar
    Brian Heng committed
                  picHeader->setNoOutputOfPriorPicsFlag(true);
    
    bdchoi's avatar
    bdchoi committed
    #endif
    
    Brian Heng's avatar
    Brian Heng committed
                }
              }
            }
    
            // code picture header before first slice
    
            if(sliceSegmentIdxCount == 0)
    
    Brian Heng's avatar
    Brian Heng committed
            {
              // code RPL in picture header or slice headers
              if( !m_pcCfg->getSliceLevelRpl() && (!pcSlice->getIdrPicFlag() || pcSlice->getSPS()->getIDRRefParamListPresent()) )
              {
                picHeader->setRPL0idx(pcSlice->getRPL0idx());
                picHeader->setRPL1idx(pcSlice->getRPL1idx());
                picHeader->setRPL0(pcSlice->getRPL0());
                picHeader->setRPL1(pcSlice->getRPL1());
                *picHeader->getLocalRPL0() = *pcSlice->getLocalRPL0();
                *picHeader->getLocalRPL1() = *pcSlice->getLocalRPL1();
              }
    
    Brian Heng's avatar
    Brian Heng committed
              // code DBLK in picture header or slice headers
              if( !m_pcCfg->getSliceLevelDblk() )
              {
                picHeader->setDeblockingFilterOverrideFlag   ( pcSlice->getDeblockingFilterOverrideFlag()   );
    
                picHeader->setDeblockingFilterDisable        ( pcSlice->getDeblockingFilterDisable()        );
                picHeader->setDeblockingFilterBetaOffsetDiv2 ( pcSlice->getDeblockingFilterBetaOffsetDiv2() );
    
    Brian Heng's avatar
    Brian Heng committed
                picHeader->setDeblockingFilterTcOffsetDiv2   ( pcSlice->getDeblockingFilterTcOffsetDiv2()   );
    
                picHeader->setDeblockingFilterCbBetaOffsetDiv2( pcSlice->getDeblockingFilterCbBetaOffsetDiv2() );
                picHeader->setDeblockingFilterCbTcOffsetDiv2  ( pcSlice->getDeblockingFilterCbTcOffsetDiv2() );
                picHeader->setDeblockingFilterCrBetaOffsetDiv2( pcSlice->getDeblockingFilterCrBetaOffsetDiv2() );
                picHeader->setDeblockingFilterCrTcOffsetDiv2  ( pcSlice->getDeblockingFilterCrTcOffsetDiv2() );
    
    Hendry's avatar
    Hendry committed
    
              if (!m_pcCfg->getSliceLevelDeltaQp())
              {
                picHeader->setQpDelta(pcSlice->getSliceQp() - (pcSlice->getPPS()->getPicInitQPMinus26() + 26));
              }
    
    
    Brian Heng's avatar
    Brian Heng committed
              // code SAO parameters in picture header or slice headers
              if( !m_pcCfg->getSliceLevelSao() )
              {
                picHeader->setSaoEnabledFlag(CHANNEL_TYPE_LUMA,   pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_LUMA  ));
                picHeader->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_CHROMA));
    
    Xiaoyu Xiu's avatar
    Xiaoyu Xiu committed
    #if JVET_W0066_CCSAO
                picHeader->setCcSaoEnabledFlag(COMPONENT_Y,  pcSlice->getCcSaoEnabledFlag(COMPONENT_Y));
                picHeader->setCcSaoEnabledFlag(COMPONENT_Cb, pcSlice->getCcSaoEnabledFlag(COMPONENT_Cb));
                picHeader->setCcSaoEnabledFlag(COMPONENT_Cr, pcSlice->getCcSaoEnabledFlag(COMPONENT_Cr));
    #endif
    
    Brian Heng's avatar
    Brian Heng committed
              // code ALF parameters in picture header or slice headers
              if( !m_pcCfg->getSliceLevelAlf() )
              {
                picHeader->setAlfEnabledFlag(COMPONENT_Y,  pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y ) );
                picHeader->setAlfEnabledFlag(COMPONENT_Cb, pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) );
    
                picHeader->setAlfEnabledFlag(COMPONENT_Cr, pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cr) );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if ALF_IMPROVEMENT
                picHeader->setAlfFixedFilterSetIdx(pcSlice->getTileGroupAlfFixedFilterSetIdx());
    #endif
    
    Brian Heng's avatar
    Brian Heng committed
                picHeader->setNumAlfAps(pcSlice->getTileGroupNumAps());
                picHeader->setAlfAPSs(pcSlice->getTileGroupApsIdLuma());
                picHeader->setAlfApsIdChroma(pcSlice->getTileGroupApsIdChroma());
    
                picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, pcSlice->getTileGroupCcAlfCbEnabledFlag());
                picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, pcSlice->getTileGroupCcAlfCrEnabledFlag());
                picHeader->setCcAlfCbApsId(pcSlice->getTileGroupCcAlfCbApsId());
                picHeader->setCcAlfCrApsId(pcSlice->getTileGroupCcAlfCrApsId());
    
    Hendry's avatar
    Hendry committed
    
              // code WP parameters in picture header or slice headers
              if (!m_pcCfg->getSliceLevelWp())
              {
                picHeader->setWpScaling(pcSlice->getWpScalingAll());
                picHeader->setNumL0Weights(pcSlice->getNumRefIdx(REF_PIC_LIST_0));
                picHeader->setNumL0Weights(pcSlice->getNumRefIdx(REF_PIC_LIST_1));
              }
    
    Brian Heng's avatar
    Brian Heng committed
    
              pcPic->cs->picHeader->setPic(pcPic);
              pcPic->cs->picHeader->setValid();
    
              if (pcPic->cs->pps->getNumSlicesInPic() > 1 || !m_pcCfg->getEnablePictureHeaderInSliceHeader())
    
                pcSlice->setPictureHeaderInSliceHeader(false);
    
                actualTotalBits += xWritePicHeader(accessUnit, pcPic->cs->picHeader);
              }
    
    bdchoi's avatar
    bdchoi committed
              if (pcSlice->getSPS()->getProfileTierLevel()->getConstraintInfo()->getPicHeaderInSliceHeaderConstraintFlag())
              {
                CHECK(pcSlice->getPictureHeaderInSliceHeader() == false, "PH shall be present in SH, when pic_header_in_slice_header_constraint_flag is equal to 1");
              }
    
    Brian Heng's avatar
    Brian Heng committed
            }
            pcSlice->setPicHeader( pcPic->cs->picHeader );
    
            pcSlice->setNalUnitLayerId( m_pcEncLib->getLayerId() );
    
            for ( uint32_t ui = 0 ; ui < numSubstreams; ui++ )
            {
              substreamsOut[ui].clear();
            }
    
            /* start slice NALunit */
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            OutputNALUnit nalu( pcSlice->getNalUnitType(), m_pcEncLib->getLayerId(), pcSlice->getTLayer() );
    
            m_HLSWriter->setBitstream( &nalu.m_Bitstream );
    
    
            tmpBitsBeforeWriting = m_HLSWriter->getNumberOfWrittenBits();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            pcSlice->m_ccAlfFilterParam      = m_pcALF->getCcAlfFilterParam();
            pcSlice->m_ccAlfFilterControl[0] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cb);
            pcSlice->m_ccAlfFilterControl[1] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cr);
    
    #if EMBEDDED_APS
            m_HLSWriter->codeSliceHeader( m_aps, pcSlice );
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
            actualHeadBits += ( m_HLSWriter->getNumberOfWrittenBits() - tmpBitsBeforeWriting );
    
            pcSlice->setFinalized(true);
    
    
    Hendry's avatar
    Hendry committed
            pcSlice->resetNumberOfSubstream( );
            pcSlice->setNumSubstream( pcSlice->getSPS(), pcSlice->getPPS() );
    
    #if JVET_Q0406_CABAC_ZERO
            const int subpicIdx = pcPic->cs->pps->getSubPicIdxFromSubPicId(pcSlice->getSliceSubPicId());
    #endif
    
            {
              uint32_t numBinsCoded = 0;
              m_pcSliceEncoder->encodeSlice(pcPic, &(substreamsOut[0]), numBinsCoded);
              binCountsInNalUnits+=numBinsCoded;
    
    #if JVET_Q0406_CABAC_ZERO
              subPicStats[subpicIdx].numBinsWritten += numBinsCoded;
    #endif
    
            }
            {
              // Construct the final bitstream by concatenating substreams.
              // The final bitstream is either nalu.m_Bitstream or pcBitstreamRedirect;
              // Complete the slice header info.
              m_HLSWriter->setBitstream( &nalu.m_Bitstream );
              m_HLSWriter->codeTilesWPPEntryPoint( pcSlice );
    
              // Append substreams...
              OutputBitstream *pcOut = pcBitstreamRedirect;
    
    Hendry's avatar
    Hendry committed
              const int numSubstreamsToCode = pcSlice->getNumberOfSubstream() + 1;
    
    
              for ( uint32_t ui = 0 ; ui < numSubstreamsToCode; ui++ )
              {
    
                pcOut->addSubstream(&(substreamsOut[ui]));
    
              }
            }
    
            // If current NALU is the first NALU of slice (containing slice header) and more NALUs exist (due to multiple dependent slices) then buffer it.
            // If current NALU is the last NALU of slice and a NALU was buffered, then (a) Write current NALU (b) Update an write buffered NALU at approproate location in NALU list.
            bool bNALUAlignedWrittenToList    = false; // used to ensure current NALU is not written more than once to the NALU list.
            xAttachSliceDataToNalUnit(nalu, pcBitstreamRedirect);
            accessUnit.push_back(new NALUnitEBSP(nalu));
            actualTotalBits += uint32_t(accessUnit.back()->m_nalUnitData.str().size()) * 8;
            numBytesInVclNalUnits += (std::size_t)(accessUnit.back()->m_nalUnitData.str().size());
    
    #if JVET_Q0406_CABAC_ZERO
            subPicStats[subpicIdx].numBytesInVclNalUnits += (std::size_t)(accessUnit.back()->m_nalUnitData.str().size());
    #endif
    
            bNALUAlignedWrittenToList = true;
    
            if (!bNALUAlignedWrittenToList)
            {
              nalu.m_Bitstream.writeAlignZero();
              accessUnit.push_back(new NALUnitEBSP(nalu));
            }
    
    
            if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) &&
    
            ((pcSlice->getSPS()->getGeneralHrdParameters()->getGeneralNalHrdParametersPresentFlag())
              || (pcSlice->getSPS()->getGeneralHrdParameters()->getGeneralVclHrdParametersPresentFlag())) &&
              (pcSlice->getSPS()->getGeneralHrdParameters()->getGeneralDecodingUnitHrdParamsPresentFlag()))
    
              uint32_t numRBSPBytes = 0;
              for (AccessUnit::const_iterator it = accessUnit.begin(); it != accessUnit.end(); it++)
              {
                numRBSPBytes += uint32_t((*it)->m_nalUnitData.str().size());
                numNalus ++;
              }
              duData.push_back(DUData());
              duData.back().accumBitsDU = ( numRBSPBytes << 3 );
              duData.back().accumNalsDU = numNalus;
            }
    
    #if JVET_Q0406_CABAC_ZERO
            if (pcSlice->isLastSliceInSubpic())
            {
              // Check picture level encoding constraints/requirements
              ProfileLevelTierFeatures profileLevelTierFeatures;
              profileLevelTierFeatures.extractPTLInformation(*(pcSlice->getSPS()));
              sumZeroWords += cabac_zero_word_padding(pcSlice, pcPic, subPicStats[subpicIdx].numBinsWritten, subPicStats[subpicIdx].numBytesInVclNalUnits, 0,
                                                      accessUnit.back()->m_nalUnitData, m_pcCfg->getCabacZeroWordPaddingEnabled(), profileLevelTierFeatures);
            }
    #endif
    
          {
            // Check picture level encoding constraints/requirements
            ProfileLevelTierFeatures profileLevelTierFeatures;
            profileLevelTierFeatures.extractPTLInformation(*(pcSlice->getSPS()));
            validateMinCrRequirements(profileLevelTierFeatures, numBytesInVclNalUnits, pcPic, m_pcCfg);
            // cabac_zero_words processing
    
    #if JVET_Q0406_CABAC_ZERO
            cabac_zero_word_padding(pcSlice, pcPic, binCountsInNalUnits, numBytesInVclNalUnits, sumZeroWords, accessUnit.back()->m_nalUnitData, m_pcCfg->getCabacZeroWordPaddingEnabled(), profileLevelTierFeatures);
    #else
    
            cabac_zero_word_padding(pcSlice, pcPic, binCountsInNalUnits, numBytesInVclNalUnits, accessUnit.back()->m_nalUnitData, m_pcCfg->getCabacZeroWordPaddingEnabled(), profileLevelTierFeatures);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
          pcPic->setCleanDirty(false);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
          pcPic->copyCleanCurPicture();      
    
          //-- For time output for each slice
          auto elapsed = std::chrono::steady_clock::now() - beforeTime;
          auto encTime = std::chrono::duration_cast<std::chrono::seconds>( elapsed ).count();
    
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    
    #if JVET_Z0118_GDR
          // note : generate hash sei only for non-gdr pictures
          bool genHash = !(m_pcCfg->getGdrNoHash() && pcSlice->getPicHeader()->getInGdrInterval());
          if (m_pcCfg->getDecodedPictureHashSEIType() != HASHTYPE_NONE && genHash)
    #else
    
          if (m_pcCfg->getDecodedPictureHashSEIType()!=HASHTYPE_NONE)
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
          {
            SEIDecodedPictureHash *decodedPictureHashSei = new SEIDecodedPictureHash();
            PelUnitBuf recoBuf = pcPic->cs->getRecoBuf();
            m_seiEncoder.initDecodedPictureHashSEI(decodedPictureHashSei, recoBuf, digestStr, pcSlice->getSPS()->getBitDepths());
            trailingSeiMessages.push_back(decodedPictureHashSei);
          }
    
    #if JVET_R0294_SUBPIC_HASH
          // create per-subpicture decoded picture hash SEI messages, if more than one subpicture is enabled
          const PPS* pps = pcPic->cs->pps;
          const int numSubpics = pps->getNumSubPics();
          std::string subPicDigest;
          if (numSubpics > 1 && m_pcCfg->getSubpicDecodedPictureHashType() != HASHTYPE_NONE )
          {
            for (int subPicIdx = 0; subPicIdx < numSubpics; subPicIdx++)
            {
              const SubPic& subpic = pps->getSubPic(subPicIdx);
              const UnitArea area = UnitArea(pcSlice->getSPS()->getChromaFormatIdc(), Area(subpic.getSubPicLeft(), subpic.getSubPicTop(), subpic.getSubPicWidthInLumaSample(), subpic.getSubPicHeightInLumaSample()));
              PelUnitBuf recoBuf = pcPic->cs->getRecoBuf(area);
              SEIDecodedPictureHash *decodedPictureHashSEI = new SEIDecodedPictureHash();
              m_seiEncoder.initDecodedPictureHashSEI(decodedPictureHashSEI, recoBuf, subPicDigest, pcSlice->getSPS()->getBitDepths());
              SEIMessages nestedSEI;
              nestedSEI.push_back(decodedPictureHashSEI);
              const std::vector<uint16_t> subPicIds = { (uint16_t)subpic.getSubPicID() };
              std::vector<int> targetOLS;
              std::vector<int> targetLayers = {pcPic->layerId};
              xCreateScalableNestingSEI(trailingSeiMessages, nestedSEI, targetOLS, targetLayers, subPicIds);
            }
          }
    #endif
    
    #if MSSIM_UNIFORM_METRICS_LOG
          xCalculateAddPSNRs(isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, encTime, snr_conversion, printFrameMSE, printMSSSIM,&PSNR_Y, isEncodeLtRef );
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          xCalculateAddPSNRs(isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, encTime, snr_conversion, printFrameMSE, &PSNR_Y, isEncodeLtRef );
    
          xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer());
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
          if (!(m_pcCfg->getGdrNoHash() && pcSlice->getPicHeader()->getInGdrInterval()))
          {
              printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr);
          }
    #else
    
          printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr);
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
    
          if ( m_pcCfg->getUseRateCtrl() )
          {
            double avgQP     = m_pcRateCtrl->getRCPic()->calAverageQP();
            double avgLambda = m_pcRateCtrl->getRCPic()->calAverageLambda();
            if ( avgLambda < 0.0 )
            {
              avgLambda = lambda;
            }
    
    
            m_pcRateCtrl->getRCPic()->updateAfterPicture( actualHeadBits, actualTotalBits, avgQP, avgLambda, pcSlice->isIRAP());
    
            m_pcRateCtrl->getRCPic()->addToPictureLsit( m_pcRateCtrl->getPicList() );
    
            m_pcRateCtrl->getRCSeq()->updateAfterPic( actualTotalBits );
    
            if ( !pcSlice->isIRAP() )
    
            {
              m_pcRateCtrl->getRCGOP()->updateAfterPicture( actualTotalBits );
            }
            else    // for intra picture, the estimated bits are used to update the current status in the GOP
            {
              m_pcRateCtrl->getRCGOP()->updateAfterPicture( estimatedBits );
            }
      #if U0132_TARGET_BITS_SATURATION
            if (m_pcRateCtrl->getCpbSaturationEnabled())
            {
              m_pcRateCtrl->updateCpbState(actualTotalBits);
              msg( NOTICE, " [CPB %6d bits]", m_pcRateCtrl->getCpbState() );
            }
      #endif
          }
    
          xCreateFrameFieldInfoSEI( leadingSeiMessages, pcSlice, isField );
    
          xCreatePictureTimingSEI( m_pcCfg->getEfficientFieldIRAPEnabled() ? effFieldIRAPMap.GetIRAPGOPid() : 0, leadingSeiMessages, nestedSeiMessages, duInfoSeiMessages, pcSlice, isField, duData );
    
    
          if (m_pcCfg->getScalableNestingSEIEnabled())
    
            const SPS* sps = pcSlice->getSPS();
            const PPS* pps = pcSlice->getPPS();
    
            std::vector<uint16_t> subpicIDs;
            if (sps->getSubPicInfoPresentFlag())
            {
              if(sps->getSubPicIdMappingExplicitlySignalledFlag())
              {
                if(sps->getSubPicIdMappingInSpsFlag())
                {
                  subpicIDs = sps->getSubPicIds();
                }
                else
                {
                  subpicIDs = pps->getSubPicIds();
                }
              }
              else
              {
                const int numSubPics = sps->getNumSubPics();
                subpicIDs.resize(numSubPics);
                for (int i = 0 ; i < numSubPics; i++)
                {
                  subpicIDs[i] = (uint16_t) i;
                }
              }
            }
    
    #if JVET_R0294_SUBPIC_HASH
            // Note (KJS): Using targetOLS = 0, 1 is as random as encapsulating the same SEIs in scalable nesting.
            //             This can just be seen as example regarding how to write scalable nesting, not what to write.
            std::vector<int> targetOLS = {0, 1};
            std::vector<int> targetLayers;
            xCreateScalableNestingSEI(leadingSeiMessages, nestedSeiMessages, targetOLS, targetLayers, subpicIDs);
    #else
    
            xCreateScalableNestingSEI(leadingSeiMessages, nestedSeiMessages, subpicIDs);
    
          xWriteLeadingSEIMessages( leadingSeiMessages, duInfoSeiMessages, accessUnit, pcSlice->getTLayer(), pcSlice->getSPS(), duData );
    
          xWriteDuSEIMessages( duInfoSeiMessages, accessUnit, pcSlice->getTLayer(), duData );
    
    
          m_AUWriterIf->outputAU( accessUnit );
    
          msg( NOTICE, "\n" );
          fflush( stdout );
        }
    
    
        DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 0 ) ) );
    
        pcPic->reconstructed = true;
        m_bFirst = false;
        m_iNumPicCoded++;
    
        if (!(m_pcCfg->getUseCompositeRef() && isEncodeLtRef))
    
        {
          for( int i = pcSlice->getTLayer() ; i < pcSlice->getSPS()->getMaxTLayers() ; i ++ )
          {
            m_totalCoded[i]++;
          }
        }
    
        /* 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();
    
    #if JVET_AA0096_MC_BOUNDARY_PADDING
        m_pcFrameMcPadPrediction->init(m_pcEncLib->getRdCost(), pcSlice->getSPS()->getChromaFormatIdc(),
                                       pcSlice->getSPS()->getMaxCUHeight(), NULL, pcPic->getPicWidthInLumaSamples());
        m_pcFrameMcPadPrediction->mcFramePad(pcPic, *(pcPic->slices[0]));
    
        m_pcFrameMcPadPrediction->destroy();
    
      CHECK( m_iNumPicCoded > 1, "Unspecified error" );
    
    void EncGOP::printOutSummary(uint32_t uiNumAllPicCoded, bool isField, const bool printMSEBasedSNR,
    
                                 const bool printSequenceMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                                 const bool printMSSSIM,
    #endif
                                 const bool printHexPsnr, const bool printRprPSNR, const BitDepths &bitDepths
    
    #if JVET_W0134_UNIFORM_METRICS_LOG
                                 ,
                                 int layerId
    #endif
    )
    
    {
    #if ENABLE_QPA
      const bool    useWPSNR = m_pcEncLib->getUseWPSNR();
    #endif
    #if WCG_WPSNR
    
      const bool    useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getLmcs() && 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
    
    
    #if JVET_W0134_UNIFORM_METRICS_LOG
      std::string header, metrics;
      std::string id = "a";
      if (layerId == 0)
      {
        id += ' ';
      }
      else
      {
        id += std::to_string(layerId);
      }
    
      m_gcAnalyzeAll.printOut(header, metrics, id, chFmt, printMSEBasedSNR, printSequenceMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                              printMSSSIM,
    #endif
                              printHexPsnr, printRprPSNR, bitDepths, useWPSNR
    
    #if JVET_O0756_CALCULATE_HDRMETRICS
                              ,
                              calculateHdrMetrics
    #endif
      );
      if (g_verbosity >= INFO)
      {
        std::cout << header << '\n' << metrics << std::endl;
      }
    #else
    
      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
    #if JVET_O0756_CALCULATE_HDRMETRICS
                              , calculateHdrMetrics
    #endif
                              );
    
    #endif
    #if JVET_W0134_UNIFORM_METRICS_LOG
      id = "i";
      if (layerId == 0)
      {
        id += ' ';
      }
      else
      {
        id += std::to_string(layerId);
      }
    
      m_gcAnalyzeI.printOut(header, metrics, id, chFmt, printMSEBasedSNR, printSequenceMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                            printMSSSIM,
    #endif
                            printHexPsnr, printRprPSNR, bitDepths);
    
      if (g_verbosity >= DETAILS)
      {
        std::cout << "\n\nI Slices--------------------------------------------------------\n"
                  << header << '\n'
                  << metrics << std::endl;
      }
      id = "p";
      if (layerId == 0)
      {
        id += ' ';
      }
      else
      {
        id += std::to_string(layerId);
      }
    
      m_gcAnalyzeP.printOut(header, metrics, id, chFmt, printMSEBasedSNR, printSequenceMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                            printMSSSIM,
    #endif
                            printHexPsnr, printRprPSNR, bitDepths);
    
      if (g_verbosity >= DETAILS)
      {
        std::cout << "\n\nP Slices--------------------------------------------------------\n"
                  << header << '\n'
                  << metrics << std::endl;
      }
      id = "b";
      if (layerId == 0)
      {
        id += ' ';
      }
      else
      {
        id += std::to_string(layerId);
      }
    
      m_gcAnalyzeB.printOut(header, metrics, id, chFmt, printMSEBasedSNR, printSequenceMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                            printMSSSIM,
    #endif
                            printHexPsnr, printRprPSNR, bitDepths);
    
      if (g_verbosity >= DETAILS)
      {
        std::cout << "\n\nB Slices--------------------------------------------------------\n"
                  << header << '\n'
                  << metrics << std::endl;
      }
    
    #if WCG_WPSNR
      if (useLumaWPSNR)
      {
        id = "w";
        if (layerId == 0)
        {
          id += ' ';
        }
        else
        {
          id += std::to_string(layerId);
        }
    
        m_gcAnalyzeWPSNR.printOut(header, metrics, id, chFmt, printMSEBasedSNR, printSequenceMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                                  printMSSSIM,
    #endif
                                  printHexPsnr, printRprPSNR, bitDepths, useLumaWPSNR);
    
        if (g_verbosity >= DETAILS)
        {
          std::cout << "\nWPSNR SUMMARY --------------------------------------------------------\n"
                    << header << '\n'
                    << metrics << std::endl;
        }
      }
    #endif
    #else
    
      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 );
    
    #if WCG_WPSNR
      if (useLumaWPSNR)
      {
        msg(DETAILS, "\nWPSNR SUMMARY --------------------------------------------------------\n");
    
        m_gcAnalyzeWPSNR.printOut( 'w', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths, useLumaWPSNR );
    
    #endif
      if (!m_pcCfg->getSummaryOutFilename().empty())
      {
    
        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.
    
    #if JVET_W0134_UNIFORM_METRICS_LOG
        id = "a";
        if (layerId == 0)
        {
          id += ' ';
        }
        else
        {
          id += std::to_string(layerId);
        }
    
        m_gcAnalyzeAll_in.printOut(header, metrics, id, chFmt, printMSEBasedSNR, printSequenceMSE,
    #if MSSIM_UNIFORM_METRICS_LOG
                                   printMSSSIM,
    #endif
    
                                   printHexPsnr, printRprPSNR, bitDepths, useWPSNR);
    
        if (g_verbosity >= DETAILS)
        {
          std::cout << "\n\nSUMMARY INTERLACED ---------------------------------------------\n"
                    << header << '\n'
                    << metrics << std::endl;
        }
    #else
    
    Haiwei Sun's avatar
    Haiwei Sun committed
        msg( INFO,"\n\nSUMMARY INTERLACED ---------------------------------------------\n" );
    
        m_gcAnalyzeAll_in.printOut( 'a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, 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;
    
    #if JVET_AB0171_ASYMMETRIC_DB_FOR_GDR
      if (m_pcCfg->getAsymmetricILF() && (pcPic->cs->picHeader->getInGdrInterval() || pcPic->cs->picHeader->getIsGdrRecoveryPocPic()))
      {
        m_pcLoopFilter->setAsymmetricDB(true);
      }
      else
      {
        m_pcLoopFilter->setAsymmetricDB(false);
      } 
    #endif
    
    
      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);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        if( rpcPic->getPOC() == pocCurr && rpcPic->layerId == m_pcEncLib->getLayerId() )
    
        {
          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 chromaShiftHor /*= 0*/, const uint32_t chromaShiftVer /*= 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 >> chromaShiftVer, 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 << chromaShiftHor) * (H << chromaShiftVer))) * 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,
    
      const bool    useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getLmcs() && 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,
    #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;
        }