Newer
Older
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
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();
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,
#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
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
}
#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
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
{
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
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
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
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
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)

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

Karsten Suehring
committed
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
//In case of field coding, compute the interlaced PSNR for both fields
if(isField)
{
bool bothFieldsAreEncoded = false;
int correspondingFieldPOC = pcPic->getPOC();
int currentPicGOPPoc = m_pcCfg->getGOPEntry(iGOPid).m_POC;
if(pcPic->getPOC() == 0)
{
// particular case for POC 0 and 1.
// If they are not encoded first and separately from other pictures, we need to change this
// POC 0 is always encoded first then POC 1 is encoded
bothFieldsAreEncoded = false;
}
else if(pcPic->getPOC() == 1)
{
// if we are at POC 1, POC 0 has been encoded for sure
correspondingFieldPOC = 0;
bothFieldsAreEncoded = true;
}
else
{
if(pcPic->getPOC()%2 == 1)
{
correspondingFieldPOC -= 1; // all odd POC are associated with the preceding even POC (e.g poc 1 is associated to poc 0)
currentPicGOPPoc -= 1;
}
else
{
correspondingFieldPOC += 1; // all even POC are associated with the following odd POC (e.g poc 0 is associated to poc 1)
currentPicGOPPoc += 1;
}
for(int i = 0; i < m_iGopSize; i ++)
{
if(m_pcCfg->getGOPEntry(i).m_POC == currentPicGOPPoc)
{
bothFieldsAreEncoded = m_pcCfg->getGOPEntry(i).m_isEncoded;
break;
}
}
}
if(bothFieldsAreEncoded)
{
//get complementary top field
PicList::iterator iterPic = rcListPic.begin();
while ((*iterPic)->getPOC() != correspondingFieldPOC)
{
iterPic ++;
}
Picture* correspondingFieldPic = *(iterPic);
if ((pcPic->topField && isFieldTopFieldFirst) || (!pcPic->topField && !isFieldTopFieldFirst))

Karsten Suehring
committed
{
xCalculateInterlacedAddPSNR(pcPic, correspondingFieldPic, pcPic->getRecoBuf(),
correspondingFieldPic->getRecoBuf(), snr_conversion, printFrameMSE,
#if MSSIM_UNIFORM_METRICS_LOG
printMSSSIM,
#endif
PSNR_Y, isEncodeLtRef);

Karsten Suehring
committed
}
else
{
xCalculateInterlacedAddPSNR(correspondingFieldPic, pcPic, correspondingFieldPic->getRecoBuf(),
pcPic->getRecoBuf(), snr_conversion, printFrameMSE,
#if MSSIM_UNIFORM_METRICS_LOG
printMSSSIM,
#endif
PSNR_Y, isEncodeLtRef);

Karsten Suehring
committed
}
}
}
}
void EncGOP::xCalculateAddPSNR(Picture *pcPic, PelUnitBuf cPicD, const AccessUnit &accessUnit, double dEncTime,
const InputColourSpaceConversion conversion, const bool printFrameMSE,
#if MSSIM_UNIFORM_METRICS_LOG
const bool printMSSSIM,
#endif
double *PSNR_Y,
bool isEncodeLtRef)

Karsten Suehring
committed
{
const SPS& sps = *pcPic->cs->sps;
const CPelUnitBuf& pic = cPicD;
CHECK(!(conversion == IPCOLOURSPACE_UNCHANGED), "Unspecified error");
// const CPelUnitBuf& org = (conversion != IPCOLOURSPACE_UNCHANGED) ? pcPic->getPicYuvTrueOrg()->getBuf() : pcPic->getPicYuvOrg()->getBuf();
const CPelUnitBuf& org = (sps.getUseLmcs() || m_pcCfg->getGopBasedTemporalFilterEnabled()) ? pcPic->getTrueOrigBuf() : pcPic->getOrigBuf();

Karsten Suehring
committed
#if ENABLE_QPA
const bool useWPSNR = m_pcEncLib->getUseWPSNR();
#endif
double dPSNR[MAX_NUM_COMPONENT];
#if MSSIM_UNIFORM_METRICS_LOG
double msssim[MAX_NUM_COMPONENT] = {0.0,0.0,0.0};
#endif

Karsten Suehring
committed
#if WCG_WPSNR
const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getLmcs() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ);

Karsten Suehring
committed
double dPSNRWeighted[MAX_NUM_COMPONENT];
double MSEyuvframeWeighted[MAX_NUM_COMPONENT];
#endif
double upscaledPSNR[MAX_NUM_COMPONENT];

Karsten Suehring
committed
for(int i=0; i<MAX_NUM_COMPONENT; i++)
{
dPSNR[i]=0.0;
#if WCG_WPSNR
dPSNRWeighted[i]=0.0;
MSEyuvframeWeighted[i] = 0.0;
#endif
upscaledPSNR[i] = 0.0;

Karsten Suehring
committed
}
#if JVET_O0756_CALCULATE_HDRMETRICS
double deltaE[hdrtoolslib::NB_REF_WHITE];
double psnrL[hdrtoolslib::NB_REF_WHITE];
for (int i=0; i<hdrtoolslib::NB_REF_WHITE; i++)
{
deltaE[i] = 0.0;
psnrL[i] = 0.0;

Karsten Suehring
committed
PelStorage interm;
if (conversion != IPCOLOURSPACE_UNCHANGED)
{
interm.create(pic.chromaFormat, Area(Position(), pic.Y()));
VideoIOYuv::ColourSpaceConvert(pic, interm, conversion, false);
}
const CPelUnitBuf& picC = (conversion == IPCOLOURSPACE_UNCHANGED) ? pic : interm;
//===== calculate PSNR =====
double MSEyuvframe[MAX_NUM_COMPONENT] = {0, 0, 0};
const ChromaFormat formatD = pic.chromaFormat;
const ChromaFormat format = sps.getChromaFormatIdc();
const bool bPicIsField = pcPic->fieldPic;
const Slice* pcSlice = pcPic->slices[0];
PelStorage upscaledRec;
if (m_pcEncLib->isResChangeInClvsEnabled())
const CPelBuf& upscaledOrg = ( sps.getUseLmcs() || m_pcCfg->getGopBasedTemporalFilterEnabled() ) ? pcPic->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).get( COMPONENT_Y ) : pcPic->M_BUFS( 0, PIC_ORIGINAL_INPUT ).get( COMPONENT_Y );
upscaledRec.create( pic.chromaFormat, Area( Position(), upscaledOrg ) );
int xScale, yScale;
// it is assumed that full resolution picture PPS has ppsId 0
const PPS* pps = m_pcEncLib->getPPS(0);
CU::getRprScaling( &sps, pps, pcPic, xScale, yScale );
std::pair<int, int> scalingRatio = std::pair<int, int>( xScale, yScale );
Picture::rescalePicture( scalingRatio, picC, pcPic->getScalingWindow(), upscaledRec, pps->getScalingWindow(), format, sps.getBitDepths(), false, false, sps.getHorCollocatedChromaFlag(), sps.getVerCollocatedChromaFlag() );
}

Karsten Suehring
committed
for (int comp = 0; comp < ::getNumberValidComponents(formatD); comp++)
{
const ComponentID compID = ComponentID(comp);
const CPelBuf& p = picC.get(compID);
const CPelBuf& o = org.get(compID);
CHECK(!( p.width == o.width), "Unspecified error");
CHECK(!( p.height == o.height), "Unspecified error");
int padX = m_pcEncLib->getPad( 0 );
int padY = m_pcEncLib->getPad( 1 );
// when RPR is enabled, picture padding is picture specific due to possible different picture resoluitons, however only full resolution padding is stored in EncLib
// get per picture padding from the conformance window, in this case if conformance window is set not equal to the padding then PSNR results may be inaccurate
if (m_pcEncLib->isResChangeInClvsEnabled())
{
Window& conf = pcPic->getConformanceWindow();
padX = conf.getWindowRightOffset() * SPS::getWinUnitX( format );
padY = conf.getWindowBottomOffset() * SPS::getWinUnitY( format );
}
const uint32_t width = p.width - ( padX >> ::getComponentScaleX( compID, format ) );
const uint32_t height = p.height - ( padY >> ( !!bPicIsField + ::getComponentScaleY( compID, format ) ) );

Karsten Suehring
committed
// create new buffers with correct dimensions
const CPelBuf recPB(p.bufAt(0, 0), p.stride, width, height);
const CPelBuf orgPB(o.bufAt(0, 0), o.stride, width, height);
const uint32_t bitDepth = sps.getBitDepth(toChannelType(compID));
#if ENABLE_QPA
Yang Wang
committed
const uint64_t uiSSDtemp = xFindDistortionPlane(recPB, orgPB, useWPSNR ? bitDepth : 0, ::getComponentScaleX(compID, format), ::getComponentScaleY(compID, format));

Karsten Suehring
committed
#else
const uint64_t uiSSDtemp = xFindDistortionPlane(recPB, orgPB, 0);
#endif

Christian Helmrich
committed
const uint32_t maxval = 255 << (bitDepth - 8);

Karsten Suehring
committed
const uint32_t size = width * height;
const double fRefValue = (double)maxval * maxval * size;
dPSNR[comp] = uiSSDtemp ? 10.0 * log10(fRefValue / (double)uiSSDtemp) : 999.99;
MSEyuvframe[comp] = (double)uiSSDtemp / size;
#if MSSIM_UNIFORM_METRICS_LOG
if (printMSSSIM)
{
msssim[comp] = xCalculateMSSSIM(o.bufAt(0, 0), o.stride, p.bufAt(0, 0), p.stride, width, height, bitDepth);
}
#endif

Karsten Suehring
committed
#if WCG_WPSNR
const double uiSSDtempWeighted = xFindDistortionPlaneWPSNR(recPB, orgPB, 0, org.get(COMPONENT_Y), compID, format);

Karsten Suehring
committed
if (useLumaWPSNR)
{
dPSNRWeighted[comp] = uiSSDtempWeighted ? 10.0 * log10(fRefValue / (double)uiSSDtempWeighted) : 999.99;
MSEyuvframeWeighted[comp] = (double)uiSSDtempWeighted / size;
}
#endif
if (m_pcEncLib->isResChangeInClvsEnabled())
const CPelBuf& upscaledOrg = ( sps.getUseLmcs() || m_pcCfg->getGopBasedTemporalFilterEnabled() ) ? pcPic->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).get( compID ) : pcPic->M_BUFS( 0, PIC_ORIGINAL_INPUT ).get( compID );
const uint32_t upscaledWidth = upscaledOrg.width - ( m_pcEncLib->getPad( 0 ) >> ::getComponentScaleX( compID, format ) );
const uint32_t upscaledHeight = upscaledOrg.height - ( m_pcEncLib->getPad( 1 ) >> ( !!bPicIsField + ::getComponentScaleY( compID, format ) ) );
// create new buffers with correct dimensions
const CPelBuf upscaledRecPB( upscaledRec.get( compID ).bufAt( 0, 0 ), upscaledRec.get( compID ).stride, upscaledWidth, upscaledHeight );
const CPelBuf upscaledOrgPB( upscaledOrg.bufAt( 0, 0 ), upscaledOrg.stride, upscaledWidth, upscaledHeight );
#if ENABLE_QPA
const uint64_t upscaledSSD = xFindDistortionPlane( upscaledRecPB, upscaledOrgPB, useWPSNR ? bitDepth : 0, ::getComponentScaleX( compID, format ) );
#else
const uint64_t scaledSSD = xFindDistortionPlane( upsacledRecPB, upsacledOrgPB, 0 );
#endif
upscaledPSNR[comp] = upscaledSSD ? 10.0 * log10( (double)maxval * maxval * upscaledWidth * upscaledHeight / (double)upscaledSSD ) : 999.99;

Karsten Suehring
committed
}
#if EXTENSION_360_VIDEO
m_ext360.calculatePSNRs(pcPic);
#endif
#if JVET_O0756_CALCULATE_HDRMETRICS
const bool calculateHdrMetrics = m_pcEncLib->getCalcluateHdrMetrics();
if (calculateHdrMetrics)
{
auto beforeTime = std::chrono::steady_clock::now();
xCalculateHDRMetrics(pcPic, deltaE, psnrL);
auto elapsed = std::chrono::steady_clock::now() - beforeTime;
m_metricTime += elapsed;
}
#endif

Karsten Suehring
committed
/* calculate the size of the access unit, excluding:
* - any AnnexB contributions (start_code_prefix, zero_byte, etc.,)
* - SEI NAL units
*/
uint32_t numRBSPBytes = 0;
for (AccessUnit::const_iterator it = accessUnit.begin(); it != accessUnit.end(); it++)
{
uint32_t numRBSPBytes_nal = uint32_t((*it)->m_nalUnitData.str().size());
if (m_pcCfg->getSummaryVerboseness() > 0)
{
msg( NOTICE, "*** %6s numBytesInNALunit: %u\n", nalUnitTypeToString((*it)->m_nalUnitType), numRBSPBytes_nal);
}
if( ( *it )->m_nalUnitType != NAL_UNIT_PREFIX_SEI && ( *it )->m_nalUnitType != NAL_UNIT_SUFFIX_SEI )
{
numRBSPBytes += numRBSPBytes_nal;
if (it == accessUnit.begin() || (*it)->m_nalUnitType == NAL_UNIT_VPS || (*it)->m_nalUnitType == NAL_UNIT_DCI || (*it)->m_nalUnitType == NAL_UNIT_SPS || (*it)->m_nalUnitType == NAL_UNIT_PPS || (*it)->m_nalUnitType == NAL_UNIT_PREFIX_APS || (*it)->m_nalUnitType == NAL_UNIT_SUFFIX_APS)

Karsten Suehring
committed
{
numRBSPBytes += 4;
}
else
{
numRBSPBytes += 3;
}
}
}
uint32_t uibits = numRBSPBytes * 8;
m_vRVM_RP.push_back( uibits );
//===== add PSNR =====
m_gcAnalyzeAll.addResult(dPSNR, (double) uibits, MSEyuvframe, upscaledPSNR,
#if MSSIM_UNIFORM_METRICS_LOG
msssim,
#endif
isEncodeLtRef);

Karsten Suehring
committed
#if EXTENSION_360_VIDEO
m_ext360.addResult(m_gcAnalyzeAll);
#endif
#if JVET_O0756_CALCULATE_HDRMETRICS
if (calculateHdrMetrics)
{
m_gcAnalyzeAll.addHDRMetricsResult(deltaE, psnrL);

Karsten Suehring
committed
#endif
if (pcSlice->isIntra())
{
m_gcAnalyzeI.addResult(dPSNR, (double) uibits, MSEyuvframe, upscaledPSNR,
#if MSSIM_UNIFORM_METRICS_LOG
msssim,
#endif
isEncodeLtRef);

Karsten Suehring
committed
*PSNR_Y = dPSNR[COMPONENT_Y];
#if EXTENSION_360_VIDEO
m_ext360.addResult(m_gcAnalyzeI);
#endif
#if JVET_O0756_CALCULATE_HDRMETRICS
if (calculateHdrMetrics)
{
m_gcAnalyzeI.addHDRMetricsResult(deltaE, psnrL);

Karsten Suehring
committed
#endif
}
if (pcSlice->isInterP())
{
m_gcAnalyzeP.addResult(dPSNR, (double) uibits, MSEyuvframe, upscaledPSNR,
#if MSSIM_UNIFORM_METRICS_LOG
msssim,
#endif
isEncodeLtRef);

Karsten Suehring
committed
*PSNR_Y = dPSNR[COMPONENT_Y];
#if EXTENSION_360_VIDEO
m_ext360.addResult(m_gcAnalyzeP);
#endif
#if JVET_O0756_CALCULATE_HDRMETRICS
if (calculateHdrMetrics)
{
m_gcAnalyzeP.addHDRMetricsResult(deltaE, psnrL);

Karsten Suehring
committed
#endif
}
if (pcSlice->isInterB())
{
m_gcAnalyzeB.addResult(dPSNR, (double) uibits, MSEyuvframe, upscaledPSNR,
#if MSSIM_UNIFORM_METRICS_LOG
msssim,
#endif
isEncodeLtRef);

Karsten Suehring
committed
*PSNR_Y = dPSNR[COMPONENT_Y];
#if EXTENSION_360_VIDEO
m_ext360.addResult(m_gcAnalyzeB);
#endif
#if JVET_O0756_CALCULATE_HDRMETRICS
if (calculateHdrMetrics)
{
m_gcAnalyzeB.addHDRMetricsResult(deltaE, psnrL);

Karsten Suehring
committed
#endif
}
#if WCG_WPSNR
if (useLumaWPSNR)
{
m_gcAnalyzeWPSNR.addResult(dPSNRWeighted, (double) uibits, MSEyuvframeWeighted, upscaledPSNR,
#if MSSIM_UNIFORM_METRICS_LOG
msssim,
#endif
isEncodeLtRef);

Karsten Suehring
committed
}
#endif
char c = (pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B');
if (! pcPic->referenced)
{
c += 32;
}