diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 998d64f0a17889e20b0b36127faa42e3894bc5ab..290a176074cca73c710d6e4bf1155933c7066fcd 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -53,6 +53,7 @@ // clang-format off //########### place macros to be removed in next cycle below this line ############### +#define JVET_W0134_UNIFORM_METRICS_LOG 1 // change metrics output for easy parsing //########### place macros to be be kept below this line ############### #define GDR_ENABLED 1 diff --git a/source/Lib/EncoderLib/Analyze.h b/source/Lib/EncoderLib/Analyze.h index 1518c26fe91936a3e9b8c275378abd4f7c7c90b8..9ef8471aa19ec935f786530ffed79a4c57d9bac0 100644 --- a/source/Lib/EncoderLib/Analyze.h +++ b/source/Lib/EncoderLib/Analyze.h @@ -99,8 +99,8 @@ public: m_uiNumPic++; } -#if ENABLE_QPA - double getWPSNR (const ComponentID compID) const { return m_dPSNRSum[compID] / (double)m_uiNumPic; } +#if ENABLE_QPA || JVET_W0134_UNIFORM_METRICS_LOG + double getWPSNR(const ComponentID compID) const { return m_dPSNRSum[compID] / (double)m_uiNumPic; } #endif double getPsnr(ComponentID compID) const { return m_dPSNRSum[compID]; } double getMsssim(ComponentID compID) const { return m_msssim[compID]; } @@ -189,8 +189,156 @@ public: PSNRyuv = (MSEyuv == 0) ? 999.99 : 10.0 * log10((maxval * maxval) / MSEyuv); } -#if ENABLE_QPA || WCG_WPSNR - void printOut( char cDelim, const ChromaFormat chFmt, const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printMSSSIM, +#if JVET_W0134_UNIFORM_METRICS_LOG + void printOut(std::string &header, std::string &metrics, const std::string &delim, ChromaFormat chFmt, + bool printMSEBasedSNR, bool printSequenceMSE, bool printMSSSIM, + bool printHexPsnr, bool printRprPSNR, const BitDepths &bitDepths, + bool useWPSNR = false, bool printHdrMetrics = false) + { + + std::ostringstream headeross,metricoss; + // no generic lambda in C++11... + auto addFieldD=[&](const std::string &header,const char *fmt,double x, bool withchroma=true) { + if (!withchroma) return; + char buffer[512]; + headeross<<header; + snprintf(buffer,512,fmt,x); + metricoss<<buffer; + }; + auto addFieldL=[&](const std::string &header,const char *fmt,uint64_t x, bool withchroma=true) { + if (!withchroma) return; + char buffer[512]; + headeross<<header; + snprintf(buffer,512,fmt,x); + metricoss<<buffer; + }; + auto addFieldS=[&](const std::string &header,const char *fmt,const char *s) { + char buffer[512]; + headeross<<header; + snprintf(buffer,512,fmt,s); + metricoss<<buffer; + }; + + auto hexValue=[](double x) { + uint64_t ui; + copy(reinterpret_cast<uint8_t *>(&x), + reinterpret_cast<uint8_t *>(&x) + sizeof(x), + reinterpret_cast<uint8_t *>(&ui)); + return ui; + }; + // + double fps = m_dFrmRate; //--CFG_KDY + double scale = fps / 1000 / (double)m_uiNumPic; + + double mseBasedSNR[MAX_NUM_COMPONENT]; + if (printMSEBasedSNR||printRprPSNR) + { + for (uint32_t componentIndex = 0; componentIndex < MAX_NUM_COMPONENT; componentIndex++) + { + const ComponentID compID = ComponentID(componentIndex); + if (getNumPic() == 0) mseBasedSNR[compID] = 0 * scale; // this is the same calculation that will be evaluated for any other statistic when there are no frames (it should result in NaN). We use it here so all the output is consistent. + else + { + const uint32_t maxval = /*useWPSNR ? (1 << bitDepths.recon[toChannelType(compID)]) - 1 :*/ 255 << (bitDepths.recon[toChannelType(compID)] - 8); + const double MSE = m_MSEyuvframe[compID]; + mseBasedSNR[compID] = (MSE == 0) ? 999.99 : 10.0 * log10((maxval * maxval) / (MSE / (double)getNumPic())); + } + } + } + + + + addFieldL("\tTotal Frames","\t%-8d ",getNumPic()); + addFieldS(" | ", " %s ",delim.c_str()); + addFieldD("Bitrate ", "%-12.4lf ",getBits() * scale); + + const bool withchroma=(chFmt != CHROMA_400); + double psnrYUV = MAX_DOUBLE; + double mseYUV = MAX_DOUBLE; + if (withchroma) calculateCombinedValues(chFmt, psnrYUV, mseYUV, bitDepths); + + if (useWPSNR) + { + addFieldD("Y-WPSNR ", "%-8.4lf ", getWPSNR(COMPONENT_Y)); + addFieldD("U-WPSNR ", "%-8.4lf ", getWPSNR(COMPONENT_Cb), withchroma); + addFieldD("V-WPSNR ", "%-8.4lf ", getWPSNR(COMPONENT_Cr), withchroma); + addFieldD("YUV-WPSNR ", "%-8.4lf ", psnrYUV, withchroma); + } + else + { + addFieldD("Y-PSNR ", "%-8.4lf ", getPsnr(COMPONENT_Y) / (double) getNumPic()); + addFieldD("U-PSNR ", "%-8.4lf ", getPsnr(COMPONENT_Cb) / (double) getNumPic(), withchroma); + addFieldD("V-PSNR ", "%-8.4lf ", getPsnr(COMPONENT_Cr) / (double) getNumPic(), withchroma); + addFieldD("YUV-PSNR ", "%-8.4lf ", psnrYUV, withchroma); + } +#if JVET_O0756_CALCULATE_HDRMETRICS + if (printHdrMetrics && withchroma) + { + addFieldD("DeltaE ", "%-8.4lf ", getDeltaE() / (double) getNumPic()); + addFieldD("PSNRL ", "%-8.4lf ", getPsnrL() / (double) getNumPic()); + } +#endif +#if EXTENSION_360_VIDEO + m_ext360.printInfos(headeross,metricoss,getNumPic()); +#endif + if (printHexPsnr) + { + if (useWPSNR) { + addFieldL("xY-WPSNR ", "%-16" PRIx64 " ", hexValue(getWPSNR(COMPONENT_Y) )); + addFieldL("xU-WPSNR ", "%-16" PRIx64 " ", hexValue(getWPSNR(COMPONENT_Cb)), withchroma); + addFieldL("xV-WPSNR ", "%-16" PRIx64 " ", hexValue(getWPSNR(COMPONENT_Cr)), withchroma); + + } else { + addFieldL("xY-PSNR ", "%-16" PRIx64 " ", hexValue(getPsnr(COMPONENT_Y) / (double) getNumPic())); + addFieldL("xU-PSNR ", "%-16" PRIx64 " ", hexValue(getPsnr(COMPONENT_Cb) / (double) getNumPic()), withchroma); + addFieldL("xV-PSNR ", "%-16" PRIx64 " ", hexValue(getPsnr(COMPONENT_Cr) / (double) getNumPic()), withchroma); + } + } +#if JVET_O0756_CALCULATE_HDRMETRICS + if (printHdrMetrics && printHexPsnr && withchroma) + { + addFieldL("xDeltaE ", "%-16" PRIx64 " ", hexValue(getDeltaE() / (double) getNumPic())); + addFieldL("xPSNRL ", "%-16" PRIx64 " " , hexValue(getPsnrL() / (double) getNumPic())); + } +#endif + if (printMSSSIM) + { + addFieldD("Y-MS-SSIM ", "%-9.7lf ", getMsssim(COMPONENT_Y) / (double) getNumPic()); + addFieldD("U-MS-SSIM ", "%-9.7lf ", getMsssim(COMPONENT_Cb) / (double) getNumPic(), withchroma); + addFieldD("V-MS-SSIM ", "%-9.7lf ", getMsssim(COMPONENT_Cr) / (double) getNumPic(), withchroma); + } + if (printSequenceMSE) + { + addFieldD("Y-MSE ", "%-10.4lf ", m_MSEyuvframe[COMPONENT_Y] / (double) getNumPic()); + addFieldD("U-MSE ", "%-10.4lf ", m_MSEyuvframe[COMPONENT_Cb] / (double) getNumPic(), withchroma); + addFieldD("V-MSE ", "%-10.4lf ", m_MSEyuvframe[COMPONENT_Cr] / (double) getNumPic(), withchroma); + addFieldD("YUV-MSE ", "%-10.4lf ",mseYUV, withchroma); + } + + if (printMSEBasedSNR&&!printRprPSNR) { + addFieldD("MSE-Y-PSNR ", "%-8.4lf ", mseBasedSNR[COMPONENT_Y]); + addFieldD("MSE-U-PSNR ", "%-8.4lf ", mseBasedSNR[COMPONENT_Cb], withchroma); + addFieldD("MSE-V-PSNR ", "%-8.4lf ", mseBasedSNR[COMPONENT_Cr], withchroma); + addFieldD("MSE-YUV-PSNR ", "%-8.4lf ", psnrYUV, withchroma); + } + if (printRprPSNR) { + addFieldD("Y-PSNR1 ", "%-8.4lf ", mseBasedSNR[COMPONENT_Y]); + addFieldD("U-PSNR1 ", "%-8.4lf ", mseBasedSNR[COMPONENT_Cb], withchroma); + addFieldD("V-PSNR1 ", "%-8.4lf ", mseBasedSNR[COMPONENT_Cr], withchroma); + addFieldD("Y-PSNR2 ", "%-8.4lf ", m_upscaledPSNR[COMPONENT_Y]/ (double)getNumPic()); + addFieldD("U-PSNR2 ", "%-8.4lf ", m_upscaledPSNR[COMPONENT_Cb]/ (double)getNumPic(), withchroma); + addFieldD("V-PSNR2 ", "%-8.4lf ", m_upscaledPSNR[COMPONENT_Cr]/ (double)getNumPic(), withchroma); + } + header=headeross.str(); + metrics=metricoss.str(); + } + +#endif + +#if !JVET_W0134_UNIFORM_METRICS_LOG +#if (ENABLE_QPA || WCG_WPSNR) + void printOut( + char cDelim, const ChromaFormat chFmt, const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printMSSSIM, const bool printHexPsnr, const bool printRprPSNR, const BitDepths &bitDepths, const bool useWPSNR = false #if JVET_O0756_CALCULATE_HDRMETRICS , const bool printHdrMetrics = false @@ -635,7 +783,7 @@ public: break; } } - +#endif void printSummary(const ChromaFormat chFmt, const bool printSequenceMSE, const bool printHexPsnr, const BitDepths &bitDepths, const std::string &sFilename) { diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index c9c1e274eac79950e354ecc901d58bbb939eb8a3..f550cec1dd8f1d673d47daf274b928a160a40d73 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -3971,7 +3971,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, void EncGOP::printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printMSSSIM, const bool printHexPsnr, const bool printRprPSNR, - const BitDepths &bitDepths ) + const BitDepths &bitDepths +#if JVET_W0134_UNIFORM_METRICS_LOG + , int layerId +#endif + ) { #if ENABLE_QPA const bool useWPSNR = m_pcEncLib->getUseWPSNR(); @@ -4006,6 +4010,20 @@ void EncGOP::printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const boo #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, printMSSSIM, printHexPsnr, printRprPSNR, bitDepths, useWPSNR +#if JVET_O0756_CALCULATE_HDRMETRICS + , calculateHdrMetrics +#endif + ); + if( g_verbosity >= INFO ) std::cout<<header<<'\n'<<metrics<<std::endl; +#else #if ENABLE_QPA m_gcAnalyzeAll.printOut( 'a', chFmt, printMSEBasedSNR, printSequenceMSE, printMSSSIM, printHexPsnr, printRprPSNR, bitDepths, useWPSNR @@ -4020,10 +4038,42 @@ void EncGOP::printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const boo #endif ); #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, printMSSSIM, 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, printMSSSIM, 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, printMSSSIM, 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, printMSSSIM, 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, printMSSSIM, printHexPsnr, printRprPSNR, bitDepths ); - msg( DETAILS, "\n\nP Slices--------------------------------------------------------\n" ); m_gcAnalyzeP.printOut( 'p', chFmt, printMSEBasedSNR, printSequenceMSE, printMSSSIM, printHexPsnr, printRprPSNR, bitDepths ); @@ -4040,6 +4090,9 @@ void EncGOP::printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const boo printHexPsnr, printRprPSNR, bitDepths, useLumaWPSNR ); } #endif +#endif + + if (!m_pcCfg->getSummaryOutFilename().empty()) { m_gcAnalyzeAll.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, m_pcCfg->getSummaryOutFilename()); @@ -4064,7 +4117,13 @@ void EncGOP::printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const boo 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, printMSSSIM, 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" ); #if ENABLE_QPA m_gcAnalyzeAll_in.printOut( 'a', chFmt, printMSEBasedSNR, printSequenceMSE, printMSSSIM, @@ -4072,6 +4131,7 @@ void EncGOP::printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const boo #else m_gcAnalyzeAll_in.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE, printMSSSIM, printHexPsnr, bitDepths); +#endif #endif if (!m_pcCfg->getSummaryOutFilename().empty()) { @@ -4893,7 +4953,11 @@ void EncGOP::xCalculateAddPSNR(Picture* pcPic, PelUnitBuf cPicD, const AccessUni } 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] ); +#else msg( NOTICE, "\nPSNR2: [Y %6.4lf dB U %6.4lf dB V %6.4lf dB]", upscaledPSNR[COMPONENT_Y], upscaledPSNR[COMPONENT_Cb], upscaledPSNR[COMPONENT_Cr] ); +#endif } } else if( g_verbosity >= INFO ) diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h index e136731164efbbd06370852ca30785ce99cc6024..a89aed5d814f0316f4e96b5ae9456f8b9f4aa321 100644 --- a/source/Lib/EncoderLib/EncGOP.h +++ b/source/Lib/EncoderLib/EncGOP.h @@ -250,7 +250,11 @@ public: int getPreQP() const { return m_preQP[0]; } void printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const bool printMSEBasedSNR, const bool printSequenceMSE, - const bool printMSSSIM, const bool printHexPsnr, const bool printRprPSNR, const BitDepths &bitDepths ); + const bool printMSSSIM, const bool printHexPsnr, const bool printRprPSNR, const BitDepths &bitDepths +#if JVET_W0134_UNIFORM_METRICS_LOG + , int layerId +#endif + ); #if W0038_DB_OPT uint64_t preLoopFilterPicAndCalcDist( Picture* pcPic ); #endif diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index ec0616fca4cbcd246668b066021a5c05a01121c0..94e383d171ee5716a741f8920b0e732df6ed9ca2 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -234,7 +234,11 @@ public: void printSummary(bool isField) { m_cGOPEncoder.printOutSummary(m_uiNumAllPicCoded, isField, m_printMSEBasedSequencePSNR, - m_printSequenceMSE, m_printMSSSIM, m_printHexPsnr, m_resChangeInClvsEnabled, m_spsMap.getFirstPS()->getBitDepths()); } + m_printSequenceMSE, m_printMSSSIM, m_printHexPsnr, m_resChangeInClvsEnabled, m_spsMap.getFirstPS()->getBitDepths() +#if JVET_W0134_UNIFORM_METRICS_LOG + , m_layerId +#endif + ); } int getLayerId() const { return m_layerId; } VPS* getVPS() { return m_vps; }