Newer
Older

Karsten Suehring
committed
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;
}
if (m_pcCfg->getDependentRAPIndicationSEIEnabled() && pcSlice->isDRAP()) c = 'D';

Karsten Suehring
committed
if( g_verbosity >= NOTICE )
{
msg( NOTICE, "POC %4d LId: %2d TId: %1d ( %s, %c-SLICE, QP %d ) %10d bits",
pcSlice->getPOC(),
pcSlice->getPic()->layerId,

Karsten Suehring
committed
pcSlice->getTLayer(),
nalUnitTypeToString(pcSlice->getNalUnitType()),

Karsten Suehring
committed
c,
pcSlice->getSliceQp(),
uibits );
msg( NOTICE, " [Y %6.4lf dB U %6.4lf dB V %6.4lf dB]", dPSNR[COMPONENT_Y], dPSNR[COMPONENT_Cb], dPSNR[COMPONENT_Cr] );
#if EXTENSION_360_VIDEO
m_ext360.printPerPOCInfo(NOTICE);
#endif

Karsten Suehring
committed
if (m_pcEncLib->getPrintHexPsnr())
{
uint64_t xPsnr[MAX_NUM_COMPONENT];
for (int i = 0; i < MAX_NUM_COMPONENT; i++)
{
copy(reinterpret_cast<uint8_t *>(&dPSNR[i]),
reinterpret_cast<uint8_t *>(&dPSNR[i]) + sizeof(dPSNR[i]),
reinterpret_cast<uint8_t *>(&xPsnr[i]));
}
msg(NOTICE, " [xY %16" PRIx64 " xU %16" PRIx64 " xV %16" PRIx64 "]", xPsnr[COMPONENT_Y], xPsnr[COMPONENT_Cb], xPsnr[COMPONENT_Cr]);
#if EXTENSION_360_VIDEO
m_ext360.printPerPOCInfo(NOTICE, true);

Karsten Suehring
committed
#endif
#if MSSIM_UNIFORM_METRICS_LOG
if (printMSSSIM)
{
msg( NOTICE, " [MS-SSIM Y %1.6lf U %1.6lf V %1.6lf]", msssim[COMPONENT_Y], msssim[COMPONENT_Cb], msssim[COMPONENT_Cr] );
}
#endif

Karsten Suehring
committed
if( printFrameMSE )
{
msg( NOTICE, " [Y MSE %6.4lf U MSE %6.4lf V MSE %6.4lf]", MSEyuvframe[COMPONENT_Y], MSEyuvframe[COMPONENT_Cb], MSEyuvframe[COMPONENT_Cr] );
}
#if WCG_WPSNR
if (useLumaWPSNR)
{
msg(NOTICE, " [WY %6.4lf dB WU %6.4lf dB WV %6.4lf dB]", dPSNRWeighted[COMPONENT_Y], dPSNRWeighted[COMPONENT_Cb], dPSNRWeighted[COMPONENT_Cr]);
if (m_pcEncLib->getPrintHexPsnr())
{
uint64_t xPsnrWeighted[MAX_NUM_COMPONENT];
for (int i = 0; i < MAX_NUM_COMPONENT; i++)
{
copy(reinterpret_cast<uint8_t *>(&dPSNRWeighted[i]),
reinterpret_cast<uint8_t *>(&dPSNRWeighted[i]) + sizeof(dPSNRWeighted[i]),
reinterpret_cast<uint8_t *>(&xPsnrWeighted[i]));
}
msg(NOTICE, " [xWY %16" PRIx64 " xWU %16" PRIx64 " xWV %16" PRIx64 "]", xPsnrWeighted[COMPONENT_Y], xPsnrWeighted[COMPONENT_Cb], xPsnrWeighted[COMPONENT_Cr]);
}

Karsten Suehring
committed
}
#endif
#if JVET_O0756_CALCULATE_HDRMETRICS
if(calculateHdrMetrics)
{
for (int i=0; i<1; i++)
{
msg(NOTICE, " [DeltaE%d %6.4lf dB]", (int)m_pcCfg->getWhitePointDeltaE(i), deltaE[i]);
if (m_pcEncLib->getPrintHexPsnr())
{
int64_t xdeltaE[MAX_NUM_COMPONENT];
for (int i = 0; i < 1; i++)
{
copy(reinterpret_cast<uint8_t *>(&deltaE[i]),
reinterpret_cast<uint8_t *>(&deltaE[i]) + sizeof(deltaE[i]),
reinterpret_cast<uint8_t *>(&xdeltaE[i]));
}
msg(NOTICE, " [xDeltaE%d %16" PRIx64 "]", (int)m_pcCfg->getWhitePointDeltaE(i), xdeltaE[0]);
}
}
for (int i=0; i<1; i++)
{
msg(NOTICE, " [PSNRL%d %6.4lf dB]", (int)m_pcCfg->getWhitePointDeltaE(i), psnrL[i]);
if (m_pcEncLib->getPrintHexPsnr())
{
int64_t xpsnrL[MAX_NUM_COMPONENT];
for (int i = 0; i < 1; i++)
{
copy(reinterpret_cast<uint8_t *>(&psnrL[i]),
reinterpret_cast<uint8_t *>(&psnrL[i]) + sizeof(psnrL[i]),
reinterpret_cast<uint8_t *>(&xpsnrL[i]));
}
msg(NOTICE, " [xPSNRL%d %16" PRIx64 "]", (int)m_pcCfg->getWhitePointDeltaE(i), xpsnrL[0]);

Karsten Suehring
committed
#endif
msg( NOTICE, " [ET %5.0f ]", dEncTime );
// msg( SOME, " [WP %d]", pcSlice->getUseWeightedPrediction());
for( int iRefList = 0; iRefList < 2; iRefList++ )
{
msg( NOTICE, " [L%d", iRefList );

Karsten Suehring
committed
for( int iRefIndex = 0; iRefIndex < pcSlice->getNumRefIdx( RefPicList( iRefList ) ); iRefIndex++ )
{
Jani Lainema
committed
const std::pair<int, int>& scaleRatio = pcSlice->getScalingRatio( RefPicList( iRefList ), iRefIndex );
if( pcPic->cs->picHeader->getEnableTMVPFlag() && pcSlice->getColFromL0Flag() == bool(1 - iRefList) && pcSlice->getColRefIdx() == iRefIndex )
if( scaleRatio.first != 1 << SCALE_RATIO_BITS || scaleRatio.second != 1 << SCALE_RATIO_BITS )
{
msg( NOTICE, " %dc(%1.2lfx, %1.2lfx)", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( scaleRatio.first ) / ( 1 << SCALE_RATIO_BITS ), double( scaleRatio.second ) / ( 1 << SCALE_RATIO_BITS ) );
}
else
{
msg( NOTICE, " %dc", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
}
}
else
Jani Lainema
committed
{
if( scaleRatio.first != 1 << SCALE_RATIO_BITS || scaleRatio.second != 1 << SCALE_RATIO_BITS )
{
msg( NOTICE, " %d(%1.2lfx, %1.2lfx)", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( scaleRatio.first ) / ( 1 << SCALE_RATIO_BITS ), double( scaleRatio.second ) / ( 1 << SCALE_RATIO_BITS ) );
}
Jani Lainema
committed
else
{
msg( NOTICE, " %d", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
}
Jani Lainema
committed
}
if( pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) == pcSlice->getPOC() )
{
msg( NOTICE, ".%d", pcSlice->getRefPic( RefPicList( iRefList ), iRefIndex )->layerId );
}

Karsten Suehring
committed
}
msg( NOTICE, "]" );
}
if (m_pcEncLib->isResChangeInClvsEnabled())
#if JVET_W0134_UNIFORM_METRICS_LOG
msg( NOTICE, " [Y2 %6.4lf dB U2 %6.4lf dB V2 %6.4lf dB]", upscaledPSNR[COMPONENT_Y], upscaledPSNR[COMPONENT_Cb], upscaledPSNR[COMPONENT_Cr] );
msg( NOTICE, "\nPSNR2: [Y %6.4lf dB U %6.4lf dB V %6.4lf dB]", upscaledPSNR[COMPONENT_Y], upscaledPSNR[COMPONENT_Cb], upscaledPSNR[COMPONENT_Cr] );

Karsten Suehring
committed
}
else if( g_verbosity >= INFO )
{
std::cout << "\r\t" << pcSlice->getPOC();
std::cout.flush();
}
}
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
#if MSSIM_UNIFORM_METRICS_LOG
double EncGOP::xCalculateMSSSIM(const Pel *org, const int orgStride, const Pel *rec, const int recStride,
const int width, const int height, const uint32_t bitDepth)
{
const int MAX_MSSSIM_SCALE = 5;
const int WEIGHTING_MID_TAP = 5;
const int WEIGHTING_SIZE = WEIGHTING_MID_TAP * 2 + 1;
uint32_t maxScale;
// For low resolution videos determine number of scales
if (width < 22 || height < 22)
{
maxScale = 1;
}
else if (width < 44 || height < 44)
{
maxScale = 2;
}
else if (width < 88 || height < 88)
{
maxScale = 3;
}
else if (width < 176 || height < 176)
{
maxScale = 4;
}
else
{
maxScale = 5;
}
assert(maxScale > 0 && maxScale <= MAX_MSSSIM_SCALE);
// Normalized Gaussian mask design, 11*11, s.d. 1.5
double weights[WEIGHTING_SIZE][WEIGHTING_SIZE];
double coeffSum = 0.0;
for (int y = 0; y < WEIGHTING_SIZE; y++)
{
for (int x = 0; x < WEIGHTING_SIZE; x++)
{
weights[y][x] =
exp(-((y - WEIGHTING_MID_TAP) * (y - WEIGHTING_MID_TAP) + (x - WEIGHTING_MID_TAP) * (x - WEIGHTING_MID_TAP))
/ (WEIGHTING_MID_TAP - 0.5));
coeffSum += weights[y][x];
}
}
for (int y = 0; y < WEIGHTING_SIZE; y++)
{
for (int x = 0; x < WEIGHTING_SIZE; x++)
{
weights[y][x] /= coeffSum;
}
}
// Resolution based weights
const double exponentWeights[MAX_MSSSIM_SCALE][MAX_MSSSIM_SCALE] = { { 1.0, 0, 0, 0, 0 },
{ 0.1356, 0.8644, 0, 0, 0 },
{ 0.0711, 0.4530, 0.4760, 0, 0 },
{ 0.0517, 0.3295, 0.3462, 0.2726, 0 },
{ 0.0448, 0.2856, 0.3001, 0.2363, 0.1333 } };
// Downsampling of data:
std::vector<double> original[MAX_MSSSIM_SCALE];
std::vector<double> recon[MAX_MSSSIM_SCALE];
for (uint32_t scale = 0; scale < maxScale; scale++)
{
const int scaledHeight = height >> scale;
const int scaledWidth = width >> scale;
original[scale].resize(scaledHeight * scaledWidth, double(0));
recon[scale].resize(scaledHeight * scaledWidth, double(0));
}
// Initial [0] arrays to be a copy of the source data (but stored in array "double", not Pel array).
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
original[0][y * width + x] = org[y * orgStride + x];
recon[0][y * width + x] = rec[y * recStride + x];
}
}
// Set up other arrays to be average value of each 2x2 sample.
for (uint32_t scale = 1; scale < maxScale; scale++)
{
const int scaledHeight = height >> scale;
const int scaledWidth = width >> scale;
for (int y = 0; y < scaledHeight; y++)
{
for (int x = 0; x < scaledWidth; x++)
{
original[scale][y * scaledWidth + x] = (original[scale - 1][2 * y * (2 * scaledWidth) + 2 * x]
+ original[scale - 1][2 * y * (2 * scaledWidth) + 2 * x + 1]
+ original[scale - 1][(2 * y + 1) * (2 * scaledWidth) + 2 * x]
+ original[scale - 1][(2 * y + 1) * (2 * scaledWidth) + 2 * x + 1])
/ 4.0;
recon[scale][y * scaledWidth + x] =
(recon[scale - 1][2 * y * (2 * scaledWidth) + 2 * x] + recon[scale - 1][2 * y * (2 * scaledWidth) + 2 * x + 1]
+ recon[scale - 1][(2 * y + 1) * (2 * scaledWidth) + 2 * x]
+ recon[scale - 1][(2 * y + 1) * (2 * scaledWidth) + 2 * x + 1])
/ 4.0;
}
}
}
// Calculate MS-SSIM:
const uint32_t maxValue = (1 << bitDepth) - 1;
const double c1 = (0.01 * maxValue) * (0.01 * maxValue);
const double c2 = (0.03 * maxValue) * (0.03 * maxValue);
double finalMSSSIM = 1.0;
for (uint32_t scale = 0; scale < maxScale; scale++)
{
const int scaledHeight = height >> scale;
const int scaledWidth = width >> scale;
const int blocksPerRow = scaledWidth - WEIGHTING_SIZE + 1;
const int blocksPerColumn = scaledHeight - WEIGHTING_SIZE + 1;
const int totalBlocks = blocksPerRow * blocksPerColumn;
double meanSSIM = 0.0;
for (int blockIndexY = 0; blockIndexY < blocksPerColumn; blockIndexY++)
{
for (int blockIndexX = 0; blockIndexX < blocksPerRow; blockIndexX++)
{
double muOrg = 0.0;
double muRec = 0.0;
double muOrigSqr = 0.0;
double muRecSqr = 0.0;
double muOrigMultRec = 0.0;
for (int y = 0; y < WEIGHTING_SIZE; y++)
{
for (int x = 0; x < WEIGHTING_SIZE; x++)
{
const double gaussianWeight = weights[y][x];
const int sampleOffset = (blockIndexY + y) * scaledWidth + (blockIndexX + x);
const double orgPel = original[scale][sampleOffset];
const double recPel = recon[scale][sampleOffset];
muOrg += orgPel * gaussianWeight;
muRec += recPel * gaussianWeight;
muOrigSqr += orgPel * orgPel * gaussianWeight;
muRecSqr += recPel * recPel * gaussianWeight;
muOrigMultRec += orgPel * recPel * gaussianWeight;
}
}
const double sigmaSqrOrig = muOrigSqr - (muOrg * muOrg);
const double sigmaSqrRec = muRecSqr - (muRec * muRec);
const double sigmaOrigRec = muOrigMultRec - (muOrg * muRec);
double blockSSIMVal = ((2.0 * sigmaOrigRec + c2) / (sigmaSqrOrig + sigmaSqrRec + c2));
if (scale == maxScale - 1)
{
blockSSIMVal *= (2.0 * muOrg * muRec + c1) / (muOrg * muOrg + muRec * muRec + c1);
}
meanSSIM += blockSSIMVal;
}
}
meanSSIM /= totalBlocks;
finalMSSSIM *= pow(meanSSIM, exponentWeights[maxScale - 1][scale]);
}
return finalMSSSIM;
}
#endif
#if JVET_O0756_CALCULATE_HDRMETRICS
void EncGOP::xCalculateHDRMetrics( Picture* pcPic, double deltaE[hdrtoolslib::NB_REF_WHITE], double psnrL[hdrtoolslib::NB_REF_WHITE])
{
copyBuftoFrame(pcPic);
ChromaFormat chFmt = pcPic->chromaFormat;
if (chFmt != CHROMA_444)
{
m_pcConvertFormat->process(m_ppcFrameOrg[1], m_ppcFrameOrg[0]);
m_pcConvertFormat->process(m_ppcFrameRec[1], m_ppcFrameRec[0]);
}
m_pcConvertIQuantize->process(m_ppcFrameOrg[2], m_ppcFrameOrg[1]);
m_pcConvertIQuantize->process(m_ppcFrameRec[2], m_ppcFrameRec[1]);
m_pcColorTransform->process(m_ppcFrameOrg[3], m_ppcFrameOrg[2]);
m_pcColorTransform->process(m_ppcFrameRec[3], m_ppcFrameRec[2]);
m_pcTransferFct->forward(m_ppcFrameOrg[4], m_ppcFrameOrg[3]);
m_pcTransferFct->forward(m_ppcFrameRec[4], m_ppcFrameRec[3]);
// Calculate the Metrics
m_pcDistortionDeltaE->computeMetric(m_ppcFrameOrg[4], m_ppcFrameRec[4]);
*deltaE = m_pcDistortionDeltaE->getDeltaE();
*psnrL = m_pcDistortionDeltaE->getPsnrL();
}
void EncGOP::copyBuftoFrame( Picture* pcPic )
{
int cropOffsetLeft = m_pcCfg->getCropOffsetLeft();
int cropOffsetTop = m_pcCfg->getCropOffsetTop();
int cropOffsetRight = m_pcCfg->getCropOffsetRight();
int cropOffsetBottom = m_pcCfg->getCropOffsetBottom();
int height = pcPic->getOrigBuf(COMPONENT_Y).height - cropOffsetLeft + cropOffsetRight;
int width = pcPic->getOrigBuf(COMPONENT_Y).width - cropOffsetTop + cropOffsetBottom;
ChromaFormat chFmt = pcPic->chromaFormat;
Pel* pOrg = pcPic->getOrigBuf(COMPONENT_Y).buf;
Pel* pRec = pcPic->getRecoBuf(COMPONENT_Y).buf;
uint16_t* yOrg = m_ppcFrameOrg[0]->m_ui16Comp[hdrtoolslib::Y_COMP];
uint16_t* yRec = m_ppcFrameRec[0]->m_ui16Comp[hdrtoolslib::Y_COMP];
uint16_t* uOrg = m_ppcFrameOrg[0]->m_ui16Comp[hdrtoolslib::Cb_COMP];
uint16_t* uRec = m_ppcFrameRec[0]->m_ui16Comp[hdrtoolslib::Cb_COMP];
uint16_t* vOrg = m_ppcFrameOrg[0]->m_ui16Comp[hdrtoolslib::Cr_COMP];
uint16_t* vRec = m_ppcFrameRec[0]->m_ui16Comp[hdrtoolslib::Cr_COMP];
if(chFmt == CHROMA_444){
yOrg = m_ppcFrameOrg[1]->m_ui16Comp[hdrtoolslib::Y_COMP];
yRec = m_ppcFrameRec[1]->m_ui16Comp[hdrtoolslib::Y_COMP];
uOrg = m_ppcFrameOrg[1]->m_ui16Comp[hdrtoolslib::Cb_COMP];
uRec = m_ppcFrameRec[1]->m_ui16Comp[hdrtoolslib::Cb_COMP];
vOrg = m_ppcFrameOrg[1]->m_ui16Comp[hdrtoolslib::Cr_COMP];
vRec = m_ppcFrameRec[1]->m_ui16Comp[hdrtoolslib::Cr_COMP];
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
yOrg[i*width + j] = static_cast<uint16_t>(pOrg[(i + cropOffsetTop) * pcPic->getOrigBuf(COMPONENT_Y).stride + j + cropOffsetLeft]);
yRec[i*width + j] = static_cast<uint16_t>(pRec[(i + cropOffsetTop) * pcPic->getRecoBuf(COMPONENT_Y).stride + j + cropOffsetLeft]);
if (chFmt != CHROMA_444) {
height >>= 1;
width >>= 1;
cropOffsetLeft >>= 1;
cropOffsetTop >>= 1;
}
pOrg = pcPic->getOrigBuf(COMPONENT_Cb).buf;
pRec = pcPic->getRecoBuf(COMPONENT_Cb).buf;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
uOrg[i*width + j] = static_cast<uint16_t>(pOrg[(i + cropOffsetTop) * pcPic->getOrigBuf(COMPONENT_Cb).stride + j + cropOffsetLeft]);
uRec[i*width + j] = static_cast<uint16_t>(pRec[(i + cropOffsetTop) * pcPic->getRecoBuf(COMPONENT_Cb).stride + j + cropOffsetLeft]);
pOrg = pcPic->getOrigBuf(COMPONENT_Cr).buf;
pRec = pcPic->getRecoBuf(COMPONENT_Cr).buf;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
vOrg[i*width + j] = static_cast<uint16_t>(pOrg[(i + cropOffsetTop) * pcPic->getOrigBuf(COMPONENT_Cr).stride + j + cropOffsetLeft]);
vRec[i*width + j] = static_cast<uint16_t>(pRec[(i + cropOffsetTop) * pcPic->getRecoBuf(COMPONENT_Cr).stride + j + cropOffsetLeft]);
}
}
}
#endif

Karsten Suehring
committed
void EncGOP::xCalculateInterlacedAddPSNR( Picture* pcPicOrgFirstField, Picture* pcPicOrgSecondField,
PelUnitBuf cPicRecFirstField, PelUnitBuf cPicRecSecondField,
const InputColourSpaceConversion conversion, const bool printFrameMSE,
#if MSSIM_UNIFORM_METRICS_LOG
const bool printMSSSIM,
#endif
double *PSNR_Y, bool isEncodeLtRef)

Karsten Suehring
committed
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
{
const SPS &sps = *pcPicOrgFirstField->cs->sps;
const ChromaFormat format = sps.getChromaFormatIdc();
double dPSNR[MAX_NUM_COMPONENT];
Picture *apcPicOrgFields[2] = {pcPicOrgFirstField, pcPicOrgSecondField};
PelUnitBuf acPicRecFields[2] = {cPicRecFirstField, cPicRecSecondField};
#if ENABLE_QPA
const bool useWPSNR = m_pcEncLib->getUseWPSNR();
#endif
for(int i=0; i<MAX_NUM_COMPONENT; i++)
{
dPSNR[i]=0.0;
}
PelStorage cscd[2 /* first/second field */];
if (conversion!=IPCOLOURSPACE_UNCHANGED)
{
for(uint32_t fieldNum=0; fieldNum<2; fieldNum++)
{
PelUnitBuf& reconField= (acPicRecFields[fieldNum]);
cscd[fieldNum].create( reconField.chromaFormat, Area( Position(), reconField.Y()) );
VideoIOYuv::ColourSpaceConvert(reconField, cscd[fieldNum], conversion, false);
acPicRecFields[fieldNum]=cscd[fieldNum];
}
}
//===== calculate PSNR =====
double MSEyuvframe[MAX_NUM_COMPONENT] = {0, 0, 0};
#if MSSIM_UNIFORM_METRICS_LOG
double msssim[MAX_NUM_COMPONENT] = {0.0,0.,0.};
#endif

Karsten Suehring
committed
CHECK(!(acPicRecFields[0].chromaFormat==acPicRecFields[1].chromaFormat), "Unspecified error");
const uint32_t numValidComponents = ::getNumberValidComponents( acPicRecFields[0].chromaFormat );
for (int chan = 0; chan < numValidComponents; chan++)
{
const ComponentID ch=ComponentID(chan);
CHECK(!(acPicRecFields[0].get(ch).width==acPicRecFields[1].get(ch).width), "Unspecified error");
CHECK(!(acPicRecFields[0].get(ch).height==acPicRecFields[0].get(ch).height), "Unspecified error");
uint64_t uiSSDtemp=0;
const uint32_t width = acPicRecFields[0].get(ch).width - (m_pcEncLib->getPad(0) >> ::getComponentScaleX(ch, format));
const uint32_t height = acPicRecFields[0].get(ch).height - ((m_pcEncLib->getPad(1) >> 1) >> ::getComponentScaleY(ch, format));
const uint32_t bitDepth = sps.getBitDepth(toChannelType(ch));
#if MSSIM_UNIFORM_METRICS_LOG
double sumOverFieldsMSSSIM = 0;
#endif

Karsten Suehring
committed
for(uint32_t fieldNum=0; fieldNum<2; fieldNum++)
{
CHECK(!(conversion == IPCOLOURSPACE_UNCHANGED), "Unspecified error");
#if ENABLE_QPA
Yang Wang
committed
uiSSDtemp += xFindDistortionPlane( acPicRecFields[fieldNum].get(ch), apcPicOrgFields[fieldNum]->getOrigBuf().get(ch), useWPSNR ? bitDepth : 0, ::getComponentScaleX(ch, format), ::getComponentScaleY(ch, format) );

Karsten Suehring
committed
#else
uiSSDtemp += xFindDistortionPlane( acPicRecFields[fieldNum].get(ch), apcPicOrgFields[fieldNum]->getOrigBuf().get(ch), 0 );
#endif
#if MSSIM_UNIFORM_METRICS_LOG
if (printMSSSIM)
{
CPelBuf o = apcPicOrgFields[fieldNum]->getOrigBuf().get(ch);
CPelBuf p = acPicRecFields[fieldNum].get(ch);
sumOverFieldsMSSSIM +=
xCalculateMSSSIM(o.bufAt(0, 0), o.stride, p.bufAt(0, 0), p.stride, width, height, bitDepth);
}
#endif
}
#if MSSIM_UNIFORM_METRICS_LOG
if (printMSSSIM)
{
msssim[ch] = sumOverFieldsMSSSIM / 2;

Karsten Suehring
committed
}

Karsten Suehring
committed
const uint32_t maxval = 255 << (bitDepth - 8);
const uint32_t size = width * height * 2;
const double fRefValue = (double)maxval * maxval * size;
dPSNR[ch] = uiSSDtemp ? 10.0 * log10(fRefValue / (double)uiSSDtemp) : 999.99;
MSEyuvframe[ch] = (double)uiSSDtemp / size;
}
uint32_t uibits = 0; // the number of bits for the pair is not calculated here - instead the overall total is used elsewhere.
//===== add PSNR =====
m_gcAnalyzeAll_in.addResult(dPSNR, (double) uibits, MSEyuvframe, MSEyuvframe,
#if MSSIM_UNIFORM_METRICS_LOG
msssim,
#endif
isEncodeLtRef);

Karsten Suehring
committed
*PSNR_Y = dPSNR[COMPONENT_Y];
msg( INFO, "\n Interlaced frame %d: [Y %6.4lf dB U %6.4lf dB V %6.4lf dB]", pcPicOrgSecondField->getPOC()/2, dPSNR[COMPONENT_Y], dPSNR[COMPONENT_Cb], dPSNR[COMPONENT_Cr] );

Karsten Suehring
committed
if (printFrameMSE)
{
msg( DETAILS, " [Y MSE %6.4lf U MSE %6.4lf V MSE %6.4lf]", MSEyuvframe[COMPONENT_Y], MSEyuvframe[COMPONENT_Cb], MSEyuvframe[COMPONENT_Cr] );
}
#if MSSIM_UNIFORM_METRICS_LOG
if (printMSSSIM)
{
printf(" [MS-SSIM Y %1.6lf U %1.6lf V %1.6lf]", msssim[COMPONENT_Y], msssim[COMPONENT_Cb], msssim[COMPONENT_Cr] );
}
#endif

Karsten Suehring
committed
for(uint32_t fieldNum=0; fieldNum<2; fieldNum++)
{
cscd[fieldNum].destroy();
}
}
/** Function for deciding the nal_unit_type.
* \param pocCurr POC of the current picture
* \param lastIDR POC of the last IDR picture
* \param isField true to indicate field coding
* \returns the NAL unit type of the picture
* This function checks the configuration and returns the appropriate nal_unit_type for the picture.
*/
NalUnitType EncGOP::getNalUnitType(int pocCurr, int lastIDR, bool isField)
{
#if JVET_Z0118_GDR
if (m_pcCfg->getGdrEnabled() && m_pcCfg->getDecodingRefreshType() == 3 && (pocCurr >= m_pcCfg->getGdrPocStart()))
{
int m = pocCurr - m_pcCfg->getGdrPocStart();
int n = m_pcCfg->getGdrPeriod();
if (m % n == 0)
{
return NAL_UNIT_CODED_SLICE_GDR;
}
}
#endif

Karsten Suehring
committed
if (pocCurr == 0)
{
return NAL_UNIT_CODED_SLICE_IDR_N_LP;

Karsten Suehring
committed
}
if (m_pcCfg->getEfficientFieldIRAPEnabled() && isField && pocCurr == (m_pcCfg->getUseCompositeRef() ? 2: 1))

Karsten Suehring
committed
{
// to avoid the picture becoming an IRAP

Karsten Suehring
committed
}
if (m_pcCfg->getDecodingRefreshType() != 3 && (pocCurr - isField) % (m_pcCfg->getIntraPeriod() * (m_pcCfg->getUseCompositeRef() ? 2 : 1)) == 0)

Karsten Suehring
committed
{
if (m_pcCfg->getDecodingRefreshType() == 1)
{
return NAL_UNIT_CODED_SLICE_CRA;
}
else if (m_pcCfg->getDecodingRefreshType() == 2)
{
return NAL_UNIT_CODED_SLICE_IDR_W_RADL;
}
}
if(m_pocCRA>0)
{
if(pocCurr<m_pocCRA)
{
// All leading pictures are being marked as TFD pictures here since current encoder uses all
// reference pictures while encoding leading pictures. An encoder can ensure that a leading
// picture can be still decodable when random accessing to a CRA/CRANT/BLA/BLANT picture by
// controlling the reference pictures used for encoding that leading picture. Such a leading
// picture need not be marked as a TFD picture.

Karsten Suehring
committed
}
}
if (lastIDR>0)
{
if (pocCurr < lastIDR)
{

Karsten Suehring
committed
}
}
#if JVET_Z0118_GDR
if (m_pcCfg->getGdrEnabled() && pocCurr >= m_pcCfg->getGdrPocStart() && ((pocCurr - m_pcCfg->getGdrPocStart()) % m_pcCfg->getGdrPeriod() == 0))
{
return NAL_UNIT_CODED_SLICE_GDR;
}
else
{
return NAL_UNIT_CODED_SLICE_TRAIL;
}
#else

Karsten Suehring
committed
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
}
void EncGOP::xUpdateRasInit(Slice* slice)
{
slice->setPendingRasInit( false );
if ( slice->getPOC() > m_lastRasPoc )
{
m_lastRasPoc = MAX_INT;
slice->setPendingRasInit( true );
}
if ( slice->isIRAP() )
{
m_lastRasPoc = slice->getPOC();
}
}
double EncGOP::xCalculateRVM()
{
double dRVM = 0;
if( m_pcCfg->getGOPSize() == 1 && m_pcCfg->getIntraPeriod() != 1 && m_pcCfg->getFramesToBeEncoded() > RVM_VCEGAM10_M * 2 )
{
// calculate RVM only for lowdelay configurations
std::vector<double> vRL , vB;
size_t N = m_vRVM_RP.size();
vRL.resize( N );
vB.resize( N );
int i;
double dRavg = 0 , dBavg = 0;
vB[RVM_VCEGAM10_M] = 0;
for( i = RVM_VCEGAM10_M + 1 ; i < N - RVM_VCEGAM10_M + 1 ; i++ )
{
vRL[i] = 0;
for( int j = i - RVM_VCEGAM10_M ; j <= i + RVM_VCEGAM10_M - 1 ; j++ )
{
vRL[i] += m_vRVM_RP[j];
}
vRL[i] /= ( 2 * RVM_VCEGAM10_M );
vB[i] = vB[i-1] + m_vRVM_RP[i] - vRL[i];
dRavg += m_vRVM_RP[i];
dBavg += vB[i];
}
dRavg /= ( N - 2 * RVM_VCEGAM10_M );
dBavg /= ( N - 2 * RVM_VCEGAM10_M );
double dSigamB = 0;
for( i = RVM_VCEGAM10_M + 1 ; i < N - RVM_VCEGAM10_M + 1 ; i++ )
{
double tmp = vB[i] - dBavg;
dSigamB += tmp * tmp;
}
dSigamB = sqrt( dSigamB / ( N - 2 * RVM_VCEGAM10_M ) );
double f = sqrt( 12.0 * ( RVM_VCEGAM10_M - 1 ) / ( RVM_VCEGAM10_M + 1 ) );
dRVM = dSigamB / dRavg * f;
}
return( dRVM );
}
/** Attaches the input bitstream to the stream in the output NAL unit
Updates rNalu to contain concatenated bitstream. rpcBitstreamRedirect is cleared at the end of this function call.
* \param codedSliceData contains the coded slice data (bitstream) to be concatenated to rNalu
* \param rNalu target NAL unit
*/
void EncGOP::xAttachSliceDataToNalUnit (OutputNALUnit& rNalu, OutputBitstream* codedSliceData)
{
// Byte-align
rNalu.m_Bitstream.writeByteAlignment(); // Slice header byte-alignment
// Perform bitstream concatenation
if (codedSliceData->getNumberOfWrittenBits() > 0)
{
rNalu.m_Bitstream.addSubstream(codedSliceData);
}
codedSliceData->clear();
}
void EncGOP::arrangeCompositeReference(Slice* pcSlice, PicList& rcListPic, int pocCurr)
{
Picture* curPic = NULL;
PicList::iterator iterPic = rcListPic.begin();
const PreCalcValues *pcv = pcSlice->getPPS()->pcv;
m_bgPOC = pocCurr + 1;
if (m_picBg->getSpliceFull())
{
return;
}
while (iterPic != rcListPic.end())
{
curPic = *(iterPic++);
if (curPic->getPOC() == pocCurr)
{
break;
}
}
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
{
return;
}
int width = pcv->lumaWidth;
int height = pcv->lumaHeight;
int stride = curPic->getOrigBuf().get(COMPONENT_Y).stride;
int cStride = curPic->getOrigBuf().get(COMPONENT_Cb).stride;
Pel* curLumaAddr = curPic->getOrigBuf().get(COMPONENT_Y).buf;
Pel* curCbAddr = curPic->getOrigBuf().get(COMPONENT_Cb).buf;
Pel* curCrAddr = curPic->getOrigBuf().get(COMPONENT_Cr).buf;
Pel* bgOrgLumaAddr = m_picOrig->getOrigBuf().get(COMPONENT_Y).buf;
Pel* bgOrgCbAddr = m_picOrig->getOrigBuf().get(COMPONENT_Cb).buf;
Pel* bgOrgCrAddr = m_picOrig->getOrigBuf().get(COMPONENT_Cr).buf;
int cuMaxWidth = pcv->maxCUWidth;
int cuMaxHeight = pcv->maxCUHeight;
int maxReplace = (pcv->sizeInCtus) / 2;
maxReplace = maxReplace < 1 ? 1 : maxReplace;
typedef struct tagCostStr
{
double cost;
int ctuIdx;
}CostStr;
CostStr* minCtuCost = new CostStr[maxReplace];
for (int i = 0; i < maxReplace; i++)
{
minCtuCost[i].cost = 1e10;
minCtuCost[i].ctuIdx = -1;
}
int bitIncrementY = pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 8;
int bitIncrementUV = pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 8;
for (int y = 0; y < height; y += cuMaxHeight)
{
for (int x = 0; x < width; x += cuMaxWidth)
{
double lcuDist = 0.0;
double lcuDistCb = 0.0;
double lcuDistCr = 0.0;
int realPixelCnt = 0;
double lcuCost = 1e10;
int largeDist = 0;
for (int tmpy = 0; tmpy < cuMaxHeight; tmpy++)
{
if (y + tmpy >= height)
{
break;
}
for (int tmpx = 0; tmpx < cuMaxWidth; tmpx++)
{
if (x + tmpx >= width)
{
break;
}
realPixelCnt++;
lcuDist += abs(curLumaAddr[(y + tmpy)*stride + x + tmpx] - bgOrgLumaAddr[(y + tmpy)*stride + x + tmpx]);
if (abs(curLumaAddr[(y + tmpy)*stride + x + tmpx] - bgOrgLumaAddr[(y + tmpy)*stride + x + tmpx]) >(20 << bitIncrementY))
{
largeDist++;
}
if (tmpy % 2 == 0 && tmpx % 2 == 0)
{
lcuDistCb += abs(curCbAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2] - bgOrgCbAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2]);
lcuDistCr += abs(curCrAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2] - bgOrgCrAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2]);
}
}
}
//Test the vertical or horizontal edge for background patches candidates
int yInLCU = y / cuMaxHeight;
int xInLCU = x / cuMaxWidth;
int iLCUIdx = yInLCU * pcv->widthInCtus + xInLCU;
if ((largeDist / (double)realPixelCnt < 0.01 &&lcuDist / realPixelCnt < (3.5 * (1 << bitIncrementY)) && lcuDistCb / realPixelCnt < (0.5 * (1 << bitIncrementUV)) && lcuDistCr / realPixelCnt < (0.5 * (1 << bitIncrementUV)) && m_picBg->getSpliceIdx(iLCUIdx) == 0))
{
lcuCost = lcuDist / realPixelCnt + lcuDistCb / realPixelCnt + lcuDistCr / realPixelCnt;
//obtain the maxReplace smallest cost
//1) find the largest cost in the maxReplace candidates
for (int i = 0; i < maxReplace - 1; i++)
{
if (minCtuCost[i].cost > minCtuCost[i + 1].cost)
{
swap(minCtuCost[i].cost, minCtuCost[i + 1].cost);
swap(minCtuCost[i].ctuIdx, minCtuCost[i + 1].ctuIdx);
}
}
// 2) compare the current cost with the largest cost
if (lcuCost < minCtuCost[maxReplace - 1].cost)
{
minCtuCost[maxReplace - 1].cost = lcuCost;
minCtuCost[maxReplace - 1].ctuIdx = iLCUIdx;
}
}
}
}
// modify QP for background CTU
{
for (int i = 0; i < maxReplace; i++)
{
if (minCtuCost[i].ctuIdx != -1)
{
m_picBg->setSpliceIdx(minCtuCost[i].ctuIdx, pocCurr);
}
}
}
delete[]minCtuCost;
}
void EncGOP::updateCompositeReference(Slice* pcSlice, PicList& rcListPic, int pocCurr)
{
Picture* curPic = NULL;
const PreCalcValues *pcv = pcSlice->getPPS()->pcv;
PicList::iterator iterPic = rcListPic.begin();
iterPic = rcListPic.begin();
while (iterPic != rcListPic.end())
{
curPic = *(iterPic++);
if (curPic->getPOC() == pocCurr)
{
break;
}
}
assert(curPic->getPOC() == pocCurr);
int width = pcv->lumaWidth;
int height = pcv->lumaHeight;
int stride = curPic->getRecoBuf().get(COMPONENT_Y).stride;
int cStride = curPic->getRecoBuf().get(COMPONENT_Cb).stride;
Pel* bgLumaAddr = m_picBg->getRecoBuf().get(COMPONENT_Y).buf;
Pel* bgCbAddr = m_picBg->getRecoBuf().get(COMPONENT_Cb).buf;
Pel* bgCrAddr = m_picBg->getRecoBuf().get(COMPONENT_Cr).buf;
Pel* curLumaAddr = curPic->getRecoBuf().get(COMPONENT_Y).buf;
Pel* curCbAddr = curPic->getRecoBuf().get(COMPONENT_Cb).buf;
Pel* curCrAddr = curPic->getRecoBuf().get(COMPONENT_Cr).buf;
int maxCuWidth = pcv->maxCUWidth;
int maxCuHeight = pcv->maxCUHeight;
// Update background reference
if (pcSlice->isIRAP())//(pocCurr == 0)
curPic->extendPicBorder( pcSlice->getPPS() );
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
curPic->setBorderExtension(true);
m_picBg->getRecoBuf().copyFrom(curPic->getRecoBuf());
m_picOrig->getOrigBuf().copyFrom(curPic->getOrigBuf());
}
else
{
//cout << "update B" << pocCurr << endl;
for (int y = 0; y < height; y += maxCuHeight)
{
for (int x = 0; x < width; x += maxCuWidth)
{
if (m_picBg->getSpliceIdx((y / maxCuHeight)*pcv->widthInCtus + x / maxCuWidth) == pocCurr)
{
for (int tmpy = 0; tmpy < maxCuHeight; tmpy++)
{
if (y + tmpy >= height)
{
break;
}
for (int tmpx = 0; tmpx < maxCuWidth; tmpx++)
{
if (x + tmpx >= width)
{
break;
}
bgLumaAddr[(y + tmpy)*stride + x + tmpx] = curLumaAddr[(y + tmpy)*stride + x + tmpx];
if (tmpy % 2 == 0 && tmpx % 2 == 0)
{
bgCbAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2] = curCbAddr[(y + tmpy) / 2 * cStride + (x + tmpx) / 2];