Newer
Older
{
CHECK(aps != picHeader->getLmcsAPS(), "Wrong LMCS APS pointer in compressGOP");
}
#else
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 JVET_Z0118_GDR // note : insert APS at every GDR picture
if (aps && apsId >= 0)
{
writeAPS |= pcSlice->isInterGDR();
}
#endif
if( writeAPS )
{
#if JVET_R0433
aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400;
#endif
actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
apsMap->clearChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
#if JVET_Z0118_GDR
if (!pcSlice->isInterGDR())
{
CHECK(aps != picHeader->getScalingListAPS(), "Wrong SCALING LIST APS pointer in compressGOP");
}
#else
CHECK( aps != picHeader->getScalingListAPS(), "Wrong SCALING LIST APS pointer in compressGOP" );
}
}
if (pcSlice->getSPS()->getALFEnabledFlag() && (pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y) || pcSlice->getTileGroupCcAlfCbEnabledFlag() || pcSlice->getTileGroupCcAlfCrEnabledFlag()))
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 << NUM_APS_TYPE_LEN) + ALF_APS) = *aps; //allocate and cpy
m_pcALF->setApsIdStart( apsId );
}
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);
}
#if JVET_Z0118_GDR // note : insert APS at every GDR picture
if (aps && apsId >= 0)
{
writeAPS |= (pcSlice->isInterGDR());
}
#endif
#if JVET_R0433
aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400;
#endif
actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS);
#if JVET_Z0118_GDR
if (!pcSlice->isInterGDR())
{
CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getTileGroupCcAlfCbApsId() && apsId != pcSlice->getTileGroupCcAlfCrApsId(), "Wrong APS pointer in compressGOP");
}
#else
CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getTileGroupCcAlfCbApsId() && apsId != pcSlice->getTileGroupCcAlfCrApsId(), "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)
#if JVET_Q0406_CABAC_ZERO
std::size_t sumZeroWords = 0; // sum of cabac_zero_word inserted per sub-picture
std::vector<EncBitstreamParams> subPicStats (pcPic->cs->pps->getNumSubPics());
#endif

Karsten Suehring
committed
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
picHeader->setNoOutputBeforeRecoveryFlag( false );
if (pcSlice->isIRAP())
{
if (pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && pcSlice->getNalUnitType() <= NAL_UNIT_CODED_SLICE_IDR_N_LP)
{
picHeader->setNoOutputBeforeRecoveryFlag( true );
}
//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() )
{
if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA || pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_GDR)
{
#if JVET_S0193_NO_OUTPUT_PRIOR_PIC
pcSlice->setNoOutputOfPriorPicsFlag(true);
#else
}
}
}
// 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();
}
// code DBLK in picture header or slice headers
if( !m_pcCfg->getSliceLevelDblk() )
{
picHeader->setDeblockingFilterOverrideFlag ( pcSlice->getDeblockingFilterOverrideFlag() );
picHeader->setDeblockingFilterDisable ( pcSlice->getDeblockingFilterDisable() );
picHeader->setDeblockingFilterBetaOffsetDiv2 ( pcSlice->getDeblockingFilterBetaOffsetDiv2() );
picHeader->setDeblockingFilterTcOffsetDiv2 ( pcSlice->getDeblockingFilterTcOffsetDiv2() );
picHeader->setDeblockingFilterCbBetaOffsetDiv2( pcSlice->getDeblockingFilterCbBetaOffsetDiv2() );
picHeader->setDeblockingFilterCbTcOffsetDiv2 ( pcSlice->getDeblockingFilterCbTcOffsetDiv2() );
picHeader->setDeblockingFilterCrBetaOffsetDiv2( pcSlice->getDeblockingFilterCrBetaOffsetDiv2() );
picHeader->setDeblockingFilterCrTcOffsetDiv2 ( pcSlice->getDeblockingFilterCrTcOffsetDiv2() );
if (!m_pcCfg->getSliceLevelDeltaQp())
{
picHeader->setQpDelta(pcSlice->getSliceQp() - (pcSlice->getPPS()->getPicInitQPMinus26() + 26));
}
// 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));
#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
// 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) );
#if JVET_AG0157_ALF_CHROMA_FIXED_FILTER
picHeader->setAlfFixedFilterSetIdx(COMPONENT_Y, pcSlice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Y));
picHeader->setAlfFixedFilterSetIdx(COMPONENT_Cb, pcSlice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Cb));
picHeader->setAlfFixedFilterSetIdx(COMPONENT_Cr, pcSlice->getTileGroupAlfFixedFilterSetIdx(COMPONENT_Cr));
#else
picHeader->setAlfFixedFilterSetIdx(pcSlice->getTileGroupAlfFixedFilterSetIdx());
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());
// 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));
}
picHeader->setDisFracMBVD(pcSlice->getPicHeader()->getDisFracMBVD());
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);
}
Jonatan Samuelsson-Allendes
committed
{
pcSlice->setPictureHeaderInSliceHeader(true);
}
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");
}
}
pcSlice->setPicHeader( pcPic->cs->picHeader );
pcSlice->setNalUnitLayerId( m_pcEncLib->getLayerId() );

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 EMBEDDED_APS
m_HLSWriter->codeSliceHeader( m_aps, pcSlice );
#else

Karsten Suehring
committed
m_HLSWriter->codeSliceHeader( pcSlice );

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

Karsten Suehring
committed
pcSlice->clearSubstreamSizes( );
#if JVET_Q0406_CABAC_ZERO
const int subpicIdx = pcPic->cs->pps->getSubPicIdxFromSubPicId(pcSlice->getSliceSubPicId());
#endif

Karsten Suehring
committed
{
uint32_t numBinsCoded = 0;
m_pcSliceEncoder->encodeSlice(pcPic, &(substreamsOut[0]), numBinsCoded);
binCountsInNalUnits+=numBinsCoded;
#if JVET_Q0406_CABAC_ZERO
subPicStats[subpicIdx].numBinsWritten += numBinsCoded;
#endif

Karsten Suehring
committed
}
{
// 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;
const int numSubstreamsToCode = pcSlice->getNumberOfSubstream() + 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());
#if JVET_Q0406_CABAC_ZERO
subPicStats[subpicIdx].numBytesInVclNalUnits += (std::size_t)(accessUnit.back()->m_nalUnitData.str().size());
#endif

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

Karsten Suehring
committed
{
uint32_t numNalus = 0;

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

Karsten Suehring
committed
} // end iteration over slices
{
// 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);
}

Karsten Suehring
committed
#if JVET_Z0118_GDR
pcPic->setCleanDirty(false);

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();

Karsten Suehring
committed
std::string digestStr;
#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

Karsten Suehring
committed
if (m_pcCfg->getDecodedPictureHashSEIType()!=HASHTYPE_NONE)

Karsten Suehring
committed
{
SEIDecodedPictureHash *decodedPictureHashSei = new SEIDecodedPictureHash();
PelUnitBuf recoBuf = pcPic->cs->getRecoBuf();
m_seiEncoder.initDecodedPictureHashSEI(decodedPictureHashSei, recoBuf, digestStr, pcSlice->getSPS()->getBitDepths());
trailingSeiMessages.push_back(decodedPictureHashSei);
}

Karsten Suehring
committed
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
#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

Karsten Suehring
committed
m_pcCfg->setEncodedFlag(iGOPid, true);
double PSNR_Y;
#if MSSIM_UNIFORM_METRICS_LOG
xCalculateAddPSNRs(isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, encTime, snr_conversion, printFrameMSE, printMSSSIM,&PSNR_Y, isEncodeLtRef );
#else
xCalculateAddPSNRs(isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, encTime, snr_conversion, printFrameMSE, &PSNR_Y, isEncodeLtRef );
xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer());

Karsten Suehring
committed
#if JVET_Z0118_GDR
if (!(m_pcCfg->getGdrNoHash() && pcSlice->getPicHeader()->getInGdrInterval()))
{
printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr);
}
#else

Karsten Suehring
committed
printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr);

Karsten Suehring
committed
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 (m_pcCfg->getScalableNestingSEIEnabled())

Karsten Suehring
committed
{
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
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;
}
}
}

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

Karsten Suehring
committed
#endif

Karsten Suehring
committed
}

Karsten Suehring
committed
xWriteLeadingSEIMessages( leadingSeiMessages, duInfoSeiMessages, accessUnit, pcSlice->getTLayer(), pcSlice->getSPS(), duData );
xWriteDuSEIMessages( duInfoSeiMessages, accessUnit, pcSlice->getTLayer(), duData );

Karsten Suehring
committed
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();
Fabrice URBAN
committed
pcPic->cs->destroyTemporaryCsData();
#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();

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

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
#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

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
#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 );

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
}

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.
#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
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
}
#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

Karsten Suehring
committed
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
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
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
{
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