Newer
Older

Karsten Suehring
committed
}
#if JVET_Q0795_CCALF
DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 1 ) ) );
#endif
if (m_pcCfg->getUseCompositeRef() && getPrepareLTRef())
{
updateCompositeReference(pcSlice, rcListPic, pocCurr);
}

Karsten Suehring
committed
}
else // skip enc picture
{
pcSlice->setSliceQpBase( pcSlice->getSliceQp() );

Christian Helmrich
committed
#if ENABLE_QPA
if (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP())
{
const double picLambda = pcSlice->getLambdas()[0];
for (uint32_t ctuRsAddr = 0; ctuRsAddr < numberOfCtusInFrame; ctuRsAddr++)
{
pcPic->m_uEnerHpCtu[ctuRsAddr] = picLambda; // initialize to slice lambda (just for safety)
}
}
#endif
if( pcSlice->getSPS()->getSAOEnabledFlag() )

Karsten Suehring
committed
{
m_pcSAO->disabledRate( *pcPic->cs, pcPic->getSAO(1), m_pcCfg->getSaoEncodingRate(), m_pcCfg->getSaoEncodingRateChroma());
}
}
pcSlice->freeScaledRefPicList( scaledRefPic );

Karsten Suehring
committed
if( m_pcCfg->getUseAMaxBT() )
{
for( const CodingUnit *cu : pcPic->cs->cus )
{

Karsten Suehring
committed
{
m_uiBlkSize[pcSlice->getDepth()] += cu->Y().area();
m_uiNumBlk [pcSlice->getDepth()]++;
}
}
}
if( encPic || decPic )
{
pcSlice = pcPic->slices[0];
/////////////////////////////////////////////////////////////////////////////////////////////////// File writing
// write various parameter sets
bool writePS = m_bSeqFirst || (m_pcCfg->getReWriteParamSets() && (pcSlice->isIRAP()));
if (writePS)
{
m_pcEncLib->setParamSetChanged(pcSlice->getSPS()->getSPSId(), pcSlice->getPPS()->getPPSId());
}
int layerIdx = m_pcEncLib->getVPS() == nullptr ? 0 : m_pcEncLib->getVPS()->getGeneralLayerIdx( m_pcEncLib->getLayerId() );
// it is assumed that layerIdx equal to 0 is always present
#if ENABLING_MULTI_SPS
actualTotalBits += xWriteParameterSets(accessUnit, pcSlice, writePS, layerIdx);
#else
actualTotalBits += xWriteParameterSets(accessUnit, pcSlice, writePS && !layerIdx);
#endif

Karsten Suehring
committed
{
// create prefix SEI messages at the beginning of the sequence
CHECK(!(leadingSeiMessages.empty()), "Unspecified error");
xCreateIRAPLeadingSEIMessages(leadingSeiMessages, pcSlice->getSPS(), pcSlice->getPPS());
m_bSeqFirst = false;
}
// it is assumed that layerIdx equal to 0 is always present
if( m_pcCfg->getAccessUnitDelimiter() && !layerIdx )

Karsten Suehring
committed
{
xWriteAccessUnitDelimiter(accessUnit, pcSlice);
}
//send LMCS APS when LMCSModel is updated. It can be updated even current slice does not enable reshaper.
//For example, in RA, update is on intra slice, but intra slice may not use reshaper
if (pcSlice->getSPS()->getUseLmcs())
{
//only 1 LMCS data for 1 picture
ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
APS* aps = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
bool writeAPS = aps && apsMap->getChangedFlag((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
if (writeAPS)
{
actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + LMCS_APS);
CHECK(aps != picHeader->getLmcsAPS(), "Wrong LMCS APS pointer in compressGOP");
// only 1 SCALING LIST data for 1 picture
if( pcSlice->getSPS()->getScalingListFlag() && ( m_pcCfg->getUseScalingListId() == SCALING_LIST_FILE_READ ) )
{
ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
APS* aps = apsMap->getPS( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
bool writeAPS = aps && apsMap->getChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
if( writeAPS )
{
actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
apsMap->clearChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
CHECK( aps != picHeader->getScalingListAPS(), "Wrong SCALING LIST APS pointer in compressGOP" );
}
}
#if JVET_Q0795_CCALF
if (pcSlice->getSPS()->getALFEnabledFlag() && (pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y) || pcSlice->getTileGroupCcAlfCbEnabledFlag() || pcSlice->getTileGroupCcAlfCrEnabledFlag()))
#else
if (pcSlice->getSPS()->getALFEnabledFlag() && pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
for (int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++)
{
ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
APS* aps = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + ALF_APS);
bool writeAPS = aps && apsMap->getChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS);
if (!aps && pcSlice->getAlfAPSs() && pcSlice->getAlfAPSs()[apsId])
{
writeAPS = true;
aps = pcSlice->getAlfAPSs()[apsId]; // use asp from slice header
*apsMap->allocatePS(apsId) = *aps; //allocate and cpy
m_pcALF->setApsIdStart( apsId );
}
#if JVET_Q0795_CCALF
else if (pcSlice->getTileGroupCcAlfCbEnabledFlag() && !aps && apsId == pcSlice->getTileGroupCcAlfCbApsId())
{
writeAPS = true;
aps = apsMap->getPS((pcSlice->getTileGroupCcAlfCbApsId() << NUM_APS_TYPE_LEN) + ALF_APS);
}
else if (pcSlice->getTileGroupCcAlfCrEnabledFlag() && !aps && apsId == pcSlice->getTileGroupCcAlfCrApsId())
{
writeAPS = true;
aps = apsMap->getPS((pcSlice->getTileGroupCcAlfCrApsId() << NUM_APS_TYPE_LEN) + ALF_APS);
}
#endif
actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS);
#if JVET_Q0795_CCALF
CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getTileGroupCcAlfCbApsId() && apsId != pcSlice->getTileGroupCcAlfCrApsId(), "Wrong APS pointer in compressGOP");
#else
CHECK(aps != pcSlice->getAlfAPSs()[apsId], "Wrong APS pointer in compressGOP");
}
}
}

Karsten Suehring
committed
// reset presence of BP SEI indication
m_bufferingPeriodSEIPresentInAU = false;
// create prefix SEI associated with a picture
xCreatePerPictureSEIMessages(iGOPid, leadingSeiMessages, nestedSeiMessages, pcSlice);
// pcSlice is currently slice 0.
std::size_t binCountsInNalUnits = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10)
std::size_t numBytesInVclNalUnits = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10)
for(uint32_t sliceSegmentIdxCount = 0; sliceSegmentIdxCount < pcPic->cs->pps->getNumSlicesInPic(); sliceSegmentIdxCount++ )

Karsten Suehring
committed
{
pcSlice = pcPic->slices[sliceSegmentIdxCount];
if(sliceSegmentIdxCount > 0 && pcSlice->getSliceType()!= I_SLICE)
{
pcSlice->checkColRefIdx(sliceSegmentIdxCount, pcPic);
}
m_pcSliceEncoder->setSliceSegmentIdx(sliceSegmentIdxCount);
pcSlice->setRPL0(pcPic->slices[0]->getRPL0());
pcSlice->setRPL1(pcPic->slices[0]->getRPL1());
pcSlice->setRPL0idx(pcPic->slices[0]->getRPL0idx());
pcSlice->setRPL1idx(pcPic->slices[0]->getRPL1idx());

Karsten Suehring
committed
#if SPS_ID_CHECK
picHeader->setNoOutputBeforeRecoveryFlag( false );
#else
if (pcSlice->isIRAP())
{
if (pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && pcSlice->getNalUnitType() <= NAL_UNIT_CODED_SLICE_IDR_N_LP)
{
#if SPS_ID_CHECK
picHeader->setNoOutputBeforeRecoveryFlag( true );
#else
}
//the inference for NoOutputPriorPicsFlag
// KJS: This cannot happen at the encoder
#if SPS_ID_CHECK
if( !m_bFirst && ( pcSlice->isIRAP() || pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_GDR ) && picHeader->getNoOutputBeforeRecoveryFlag() )
#else
if (!m_bFirst && (pcSlice->isIRAP() || pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_GDR) && pcSlice->getNoIncorrectPicOutputFlag())
{
if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA || pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_GDR)
{
picHeader->setNoOutputOfPriorPicsFlag(true);
}
}
}
// code picture header before first slice
if(sliceSegmentIdxCount == 0)
{
// 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();
}
else {
picHeader->setPicRplPresentFlag(false);
}
// code DBLK in picture header or slice headers
if( !m_pcCfg->getSliceLevelDblk() )
{
#if !JVET_Q0819_PH_CHANGES
picHeader->setDeblockingFilterOverridePresentFlag(true);
#endif
picHeader->setDeblockingFilterOverrideFlag ( pcSlice->getDeblockingFilterOverrideFlag() );
picHeader->setDeblockingFilterDisable ( pcSlice->getDeblockingFilterDisable() );
picHeader->setDeblockingFilterBetaOffsetDiv2 ( pcSlice->getDeblockingFilterBetaOffsetDiv2() );
picHeader->setDeblockingFilterTcOffsetDiv2 ( pcSlice->getDeblockingFilterTcOffsetDiv2() );
#if JVET_Q0121_DEBLOCKING_CONTROL_PARAMETERS
picHeader->setDeblockingFilterCbBetaOffsetDiv2( pcSlice->getDeblockingFilterCbBetaOffsetDiv2() );
picHeader->setDeblockingFilterCbTcOffsetDiv2 ( pcSlice->getDeblockingFilterCbTcOffsetDiv2() );
picHeader->setDeblockingFilterCrBetaOffsetDiv2( pcSlice->getDeblockingFilterCrBetaOffsetDiv2() );
picHeader->setDeblockingFilterCrTcOffsetDiv2 ( pcSlice->getDeblockingFilterCrTcOffsetDiv2() );
#endif
picHeader->setDeblockingFilterOverridePresentFlag( false );
}
#endif
#if JVET_Q0819_PH_CHANGES
if (!m_pcCfg->getSliceLevelDeltaQp())
{
picHeader->setQpDelta(pcSlice->getSliceQp() - (pcSlice->getPPS()->getPicInitQPMinus26() + 26));
}
#endif
// code SAO parameters in picture header or slice headers
if( !m_pcCfg->getSliceLevelSao() )
{
#if !JVET_Q0819_PH_CHANGES
picHeader->setSaoEnabledPresentFlag(true);
#endif
picHeader->setSaoEnabledFlag(CHANNEL_TYPE_LUMA, pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_LUMA ));
picHeader->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, pcSlice->getSaoEnabledFlag(CHANNEL_TYPE_CHROMA));
}
picHeader->setSaoEnabledPresentFlag( false );
}
// code ALF parameters in picture header or slice headers
if( !m_pcCfg->getSliceLevelAlf() )
{
#if !JVET_Q0819_PH_CHANGES
picHeader->setAlfEnabledPresentFlag(true);
#endif
picHeader->setAlfEnabledFlag(COMPONENT_Y, pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y ) );
picHeader->setAlfEnabledFlag(COMPONENT_Cb, pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) );
picHeader->setAlfEnabledFlag(COMPONENT_Cr, pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cr) );
picHeader->setNumAlfAps(pcSlice->getTileGroupNumAps());
picHeader->setAlfAPSs(pcSlice->getTileGroupApsIdLuma());
picHeader->setAlfApsIdChroma(pcSlice->getTileGroupApsIdChroma());
#if JVET_Q0795_CCALF
picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, pcSlice->getTileGroupCcAlfCbEnabledFlag());
picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, pcSlice->getTileGroupCcAlfCrEnabledFlag());
picHeader->setCcAlfCbApsId(pcSlice->getTileGroupCcAlfCbApsId());
picHeader->setCcAlfCrApsId(pcSlice->getTileGroupCcAlfCrApsId());
#endif
picHeader->setAlfEnabledPresentFlag( false );
}
#endif
#if JVET_Q0819_PH_CHANGES
// 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));
}
#endif
pcPic->cs->picHeader->setPic(pcPic);
pcPic->cs->picHeader->setValid();
#if JVET_Q0775_PH_IN_SH
if (pcPic->cs->pps->getNumSlicesInPic() > 1 || !m_pcCfg->getEnablePictureHeaderInSliceHeader())
pcSlice->setPictureHeaderInSliceHeader(false);
actualTotalBits += xWritePicHeader(accessUnit, pcPic->cs->picHeader);
}
Jonatan Samuelsson-Allendes
committed
{
pcSlice->setPictureHeaderInSliceHeader(true);
}
#else
actualTotalBits += xWritePicHeader(accessUnit, pcPic->cs->picHeader);
#endif
}
pcSlice->setPicHeader( pcPic->cs->picHeader );

Karsten Suehring
committed
for ( uint32_t ui = 0 ; ui < numSubstreams; ui++ )
{
substreamsOut[ui].clear();
}
/* start slice NALunit */
OutputNALUnit nalu( pcSlice->getNalUnitType(), m_pcEncLib->getLayerId(), pcSlice->getTLayer() );

Karsten Suehring
committed
m_HLSWriter->setBitstream( &nalu.m_Bitstream );
tmpBitsBeforeWriting = m_HLSWriter->getNumberOfWrittenBits();
#if JVET_Q0795_CCALF
pcSlice->m_ccAlfFilterParam = m_pcALF->getCcAlfFilterParam();
pcSlice->m_ccAlfFilterControl[0] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cb);
pcSlice->m_ccAlfFilterControl[1] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cr);
#endif

Karsten Suehring
committed
m_HLSWriter->codeSliceHeader( pcSlice );
actualHeadBits += ( m_HLSWriter->getNumberOfWrittenBits() - tmpBitsBeforeWriting );
pcSlice->setFinalized(true);
#if JVET_Q0151_Q0205_ENTRYPOINTS
pcSlice->resetNumberOfSubstream( );
pcSlice->setNumSubstream( pcSlice->getSPS(), pcSlice->getPPS() );
#endif

Karsten Suehring
committed
pcSlice->clearSubstreamSizes( );
{
uint32_t numBinsCoded = 0;
m_pcSliceEncoder->encodeSlice(pcPic, &(substreamsOut[0]), numBinsCoded);
binCountsInNalUnits+=numBinsCoded;
}
{
// 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;
#if JVET_Q0151_Q0205_ENTRYPOINTS
const int numSubstreamsToCode = pcSlice->getNumberOfSubstream() + 1;
#else

Karsten Suehring
committed
const int numSubstreamsToCode = pcSlice->getNumberOfSubstreamSizes()+1;

Karsten Suehring
committed
for ( uint32_t ui = 0 ; ui < numSubstreamsToCode; ui++ )
{
pcOut->addSubstream(&(substreamsOut[ui]));

Karsten Suehring
committed
}
}
// 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());
bNALUAlignedWrittenToList = true;
if (!bNALUAlignedWrittenToList)
{
nalu.m_Bitstream.writeAlignZero();
accessUnit.push_back(new NALUnitEBSP(nalu));
}
if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) &&
( ( pcSlice->getSPS()->getHrdParameters()->getNalHrdParametersPresentFlag() )
|| ( pcSlice->getSPS()->getHrdParameters()->getVclHrdParametersPresentFlag() ) ) &&
( pcSlice->getSPS()->getHrdParameters()->getGeneralDecodingUnitHrdParamsPresentFlag() ) )

Karsten Suehring
committed
{
uint32_t numNalus = 0;
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;
}
} // end iteration over slices
#if JVET_Q0436_CABAC_ZERO_WORD || JVET_P0188_MINCR
{
// Check picture level encoding constraints/requirements
ProfileLevelTierFeatures profileLevelTierFeatures;
profileLevelTierFeatures.extractPTLInformation(*(pcSlice->getSPS()));
#endif
#if JVET_P0188_MINCR
validateMinCrRequirements(profileLevelTierFeatures, numBytesInVclNalUnits, pcPic, m_pcCfg);
#endif
#if JVET_Q0436_CABAC_ZERO_WORD
// cabac_zero_words processing
cabac_zero_word_padding(pcSlice, pcPic, binCountsInNalUnits, numBytesInVclNalUnits, accessUnit.back()->m_nalUnitData, m_pcCfg->getCabacZeroWordPaddingEnabled(), profileLevelTierFeatures);
#else

Karsten Suehring
committed
// cabac_zero_words processing
cabac_zero_word_padding(pcSlice, pcPic, binCountsInNalUnits, numBytesInVclNalUnits, accessUnit.back()->m_nalUnitData, m_pcCfg->getCabacZeroWordPaddingEnabled());
#endif
#if JVET_Q0436_CABAC_ZERO_WORD || JVET_P0188_MINCR
}
#endif

Karsten Suehring
committed
//-- 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();
std::string digestStr;
if (m_pcCfg->getDecodedPictureHashSEIType()!=HASHTYPE_NONE)
{
SEIDecodedPictureHash *decodedPictureHashSei = new SEIDecodedPictureHash();
PelUnitBuf recoBuf = pcPic->cs->getRecoBuf();
m_seiEncoder.initDecodedPictureHashSEI(decodedPictureHashSei, recoBuf, digestStr, pcSlice->getSPS()->getBitDepths());
trailingSeiMessages.push_back(decodedPictureHashSei);
}
m_pcCfg->setEncodedFlag(iGOPid, true);
double PSNR_Y;
xCalculateAddPSNRs(isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, encTime, snr_conversion, printFrameMSE, &PSNR_Y, isEncodeLtRef );

Karsten Suehring
committed

Karsten Suehring
committed
xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer(), pcSlice->getSPS());
printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr);
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());

Karsten Suehring
committed
m_pcRateCtrl->getRCPic()->addToPictureLsit( m_pcRateCtrl->getPicList() );
m_pcRateCtrl->getRCSeq()->updateAfterPic( actualTotalBits );

Karsten Suehring
committed
{
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 );

Karsten Suehring
committed
xCreatePictureTimingSEI( m_pcCfg->getEfficientFieldIRAPEnabled() ? effFieldIRAPMap.GetIRAPGOPid() : 0, leadingSeiMessages, nestedSeiMessages, duInfoSeiMessages, pcSlice, isField, duData );
#if JVET_P0190_SCALABLE_NESTING_SEI
if (m_pcCfg->getScalableNestingSEIEnabled())

Karsten Suehring
committed
{
xCreateScalableNestingSEI(leadingSeiMessages, nestedSeiMessages);

Karsten Suehring
committed
}
#endif

Karsten Suehring
committed
xWriteLeadingSEIMessages( leadingSeiMessages, duInfoSeiMessages, accessUnit, pcSlice->getTLayer(), pcSlice->getSPS(), duData );
xWriteDuSEIMessages( duInfoSeiMessages, accessUnit, pcSlice->getTLayer(), pcSlice->getSPS(), 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]++;
}
}

Karsten Suehring
committed
/* 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 > 1, "Unspecified error" );

Karsten Suehring
committed
}
void EncGOP::printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printHexPsnr, const bool printRprPSNR, const BitDepths &bitDepths )

Karsten Suehring
committed
{
#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);

Karsten Suehring
committed
#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

Karsten Suehring
committed
const ChromaFormat chFmt = m_pcCfg->getChromaFormatIdc();
//-- all
msg( INFO, "\n" );
msg( DETAILS,"\nSUMMARY --------------------------------------------------------\n" );
Dominik Mehlem
committed
#if JVET_O0756_CALCULATE_HDRMETRICS
const bool calculateHdrMetrics = m_pcEncLib->getCalcluateHdrMetrics();
#endif

Karsten Suehring
committed
#if ENABLE_QPA
Vadim Seregin
committed
m_gcAnalyzeAll.printOut( 'a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths, useWPSNR
Dominik Mehlem
committed
#if JVET_O0756_CALCULATE_HDRMETRICS
, calculateHdrMetrics
#endif
);

Karsten Suehring
committed
#else
Dominik Mehlem
committed
m_gcAnalyzeAll.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths
#if JVET_O0756_CALCULATE_HDRMETRICS
, calculateHdrMetrics
#endif
);

Karsten Suehring
committed
#endif
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 );

Karsten Suehring
committed
#if WCG_WPSNR
if (useLumaWPSNR)
{
msg(DETAILS, "\nWPSNR SUMMARY --------------------------------------------------------\n");
m_gcAnalyzeWPSNR.printOut( 'w', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths, useLumaWPSNR );

Karsten Suehring
committed
}
#endif
if (!m_pcCfg->getSummaryOutFilename().empty())
{
m_gcAnalyzeAll.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename());

Karsten Suehring
committed
}
if (!m_pcCfg->getSummaryPicFilenameBase().empty())
{
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");

Karsten Suehring
committed
}
#if WCG_WPSNR
if (!m_pcCfg->getSummaryOutFilename().empty() && useLumaWPSNR)
{
m_gcAnalyzeWPSNR.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename());

Karsten Suehring
committed
}
#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( INFO,"\n\nSUMMARY INTERLACED ---------------------------------------------\n" );

Karsten Suehring
committed
#if ENABLE_QPA
m_gcAnalyzeAll_in.printOut( 'a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, printRprPSNR, bitDepths, useWPSNR );

Karsten Suehring
committed
#else
m_gcAnalyzeAll_in.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths);

Karsten Suehring
committed
#endif
if (!m_pcCfg->getSummaryOutFilename().empty())
{
m_gcAnalyzeAll_in.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename());

Karsten Suehring
committed
#if WCG_WPSNR
if (useLumaWPSNR)
{
m_gcAnalyzeWPSNR.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename());

Karsten Suehring
committed
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
}
#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
)

Karsten Suehring
committed
{
CHECK(!( iNumPicRcvd > 0 ), "Unspecified error");
// Exception for the first frames
if ((isField && (iPOCLast == 0 || iPOCLast == 1)) || (!isField && (iPOCLast == 0)) || isEncodeLtRef)

Karsten Suehring
committed
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
{
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)

Karsten Suehring
committed
{
iterPicYuvRec--;
}
// Current pic.
PicList::iterator iterPic = rcListPic.begin();
while (iterPic != rcListPic.end())
{
rpcPic = *(iterPic);
if( rpcPic->getPOC() == pocCurr && rpcPic->layerId == m_pcEncLib->getLayerId() )

Karsten Suehring
committed
{
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

Karsten Suehring
committed
#endif
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)

Karsten Suehring
committed
{
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

Karsten Suehring
committed
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];

Karsten Suehring
committed
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);

Karsten Suehring
committed
}
}
// 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));

Karsten Suehring
committed
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
Yang Wang
committed
, const uint32_t chromaShiftHor /*= 0*/, const uint32_t chromaShiftVer /*= 0*/

Karsten Suehring
committed
#endif

Karsten Suehring
committed
{
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);
Yang Wang
committed
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)

Karsten Suehring
committed
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];

Karsten Suehring
committed
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

Christian Helmrich
committed

Karsten Suehring
committed
for (y = 0; y < H; y += B)
{
for (x = 0; x < W; x += B)
{
wmse += calcWeightedSquaredError(pic1, pic0,
sumAct, BD,
W, H,
x, y,
B, B);

Karsten Suehring
committed
}
}
// integer weighted distortion
Yang Wang
committed
sumAct = 16.0 * sqrt ((3840.0 * 2160.0) / double((W << chromaShiftHor) * (H << chromaShiftVer))) * double(1 << BD);

Karsten Suehring
committed
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
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,

Karsten Suehring
committed
ComponentID compID, const ChromaFormat chfmt )
{
const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getLmcs() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ);

Karsten Suehring
committed
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
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
)

Karsten Suehring
committed
{
xCalculateAddPSNR(pcPic, pcPic->getRecoBuf(), accessUnit, (double)dEncTime, snr_conversion, printFrameMSE, PSNR_Y
, isEncodeLtRef
);

Karsten Suehring
committed
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
//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)