diff --git a/cfg/sei_vui/greenMetadataSEI.cfg b/cfg/sei_vui/greenMetadataSEI.cfg new file mode 100644 index 0000000000000000000000000000000000000000..6fac97f3c189bbf025e4661acb5595728cd1dfb6 --- /dev/null +++ b/cfg/sei_vui/greenMetadataSEI.cfg @@ -0,0 +1,9 @@ +SEIGreenMetadataType: 0 # 0: Complexity metrics for decoder power reduction; 1: Quality metrics for quality recovery after low-power encoding +SEIGreenMetadataPeriodType : 0 # Beta version of the Green-MPEG encoder: Correct functionality of the remaining flags is not tested. +SEIGreenMetadataPeriodTypePictures: 0 +SEIGreenMetadataPeriodTypeSeconds: 0 +SEIGreenMetadataGranularityType: 0 +SEIGreenMetadataExtendedRepresentation: 1 + +SEIXSDMetricNumber: 1 +SEIXSDMetricTypePSNR: 1 diff --git a/doc/software-manual.tex b/doc/software-manual.tex index b2adaae64627e7d28d90e1ab782dcb699577b01d..e8850da1e53d243e2a576a772cfe0c01fd1b574e 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -4288,24 +4288,70 @@ Specifies the rotation and mirroring to be applied to the picture. -\begin{OptionTableNoShorthand}{Green Metadata SEI message encoder parameters}{tab:sei-green-metadata} -\Option{SEIGreenMetadataType} & -\Default{0} & +\Default{-1} & Specifies the type of metadata that is present in the SEI message. \par \begin{tabular}{cp{0.35\textwidth}} - 0 & Reserved \\ - 1 & Metadata enabling quality recovery after low-power encoding is present \\ + -1 & Disabled \\ + 0 & Metadata for decoder complexity metrics \\ + 1 & Metadata enabling quality recovery after low-power encoding\\ \end{tabular} \\ -\Option{SEIXSDMetricType} & +\Option{SEIGreenMetadataPeriodType} & \Default{0} & -Indicates the type of the objective quality metric. +Indicates the period type of metadata. \par \begin{tabular}{cp{0.35\textwidth}} - 0 & PSNR is used as objective quality metric \\ + 0 & Metadata are applicable to a single picture \\ + 1 & Metadata are applicable to all pictures in decoding order, up to (but not including) the picture containing the next I slice (not implemented) \\ + 2 & Metadata are applicable to all pictures over a specified time interval in seconds \\ + 3 & Metadata are applicable over a specified number of pictures counted in decoding order \\ \end{tabular} \\ +\Option{SEIGreenMetadataPeriodTypeSeconds} & +\Default{1} & +Indicates the number of seconds over which metadata should be valid (if SEIGreenMetadataPeriodType == 2) +\\ +\Option{SEIGreenMetadataPeriodTypePictures} & +\Default{1} & +Indicates the number of pictures, counted in decoding order, over which metadata should be valid (if SEIGreenMetadataPeriodType == 3) +\\ +\Option{SEIGreenMetadataExtendedRepresentation} & +\Default{0} & +Enables or disables the signaling of extended complexity metrics (if SEIGreenMetadataType == 0) +\\ +\Option{GMFA} & +\Default{false} & +Enables or disables the output of a file containing analysis statistics for green metadata generation (if SEIGreenMetadataType == 0) +\\ +\Option{GMFAFile} & +\Default{} & +File name for GMFA output file. +\\ +\Option{GMFAFramewise} & +\Default{false} & +Enables or disables frame-wise output of the statistics. If disabled, statistics are calculated for the complete bit stream. +\\ +\Option{SEIXSDMetricNumber} & +\Default{1} & +Number of quality metrics to be signaled (if SEIGreenMetadataType == 1) +\\ +\Option{SEIXSDMetricTypePSNR} & +\Default{false} & +Enables or disables sending of PSNR metric. +\\ +\Option{SEIXSDMetricTypeSSIM} & +\Default{false} & +Enables or disables sending of SSIM metric. +\\ +\Option{SEIXSDMetricTypeWPSNR} & +\Default{false} & +Enables or disables sending of wPSNR metric. +\\ +\Option{SEIXSDMetricTypeWSPSNR} & +\Default{false} & +Enables or disables sending of WS-PSNR metric. +\\ \end{OptionTableNoShorthand} @@ -6244,6 +6290,38 @@ DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, \end{description} +\section{Coding tool statistics extension for green metadata} +\label{sec:green-meta-sei} + +The encoder and the decoder include an extension that generates coding tool statistic. In the encoder, the extension calculates green metadata for encoding green SEI messages, in particular complexity metrics for decoder power reduction. The decoder extension can be used for cross-checking the correct functionality of the encoding extension. + +The output of the analyzer can be enabled with the option 'GMFA' (Green Metadata Feature Analyzer). The output file name is specified with the flag 'GMFAFile'. +Furthermore, it is possible to generate a framewise analysis with the option 'GMFAFramewise'. The output file is generated in a Matlab-readable way. Here is an example for both the encoder and the decoder: + +\begin{minted}{bash} +bin/EncoderAppStatic -b bitstream.vvc --GMFA 1 --GMFAFramewise=1 --GMFAFile="bitstream.m" [encoder options] + +bin/DecoderAppStatic -b bitstream.vvc --GMFA 1 --GMFAFramewise=1 --GMFAFile="bitstream.m" [decoder options] +\end{minted} + +The output file contains arrays with statistics on the use of coding tools on block-size level. As an example, the number of intra-coded blocks is returned as: + +\begin{minted}{bash} +n.intraBlocks = [... +0 0 0 0 0 0 0 0 ;... +0 0 0 16412 2142 54 0 0 ;... +0 0 41654 41906 9780 665 27 0 ;... +0 0 23494 22855 8641 906 26 0 ;... +0 0 4670 4797 4030 1215 60 0 ;... +0 0 433 507 881 1104 84 0 ;... +0 0 38 48 43 122 131 0 ;... +0 0 0 0 0 0 0 0 ]; +\end{minted} + +The horizontal position indicates the logarithm to the basis 2 block width (1, 2, 4, .., 128) and the vertical position the block height, accordingly. In this example, the bit stream contains $16{,}412$ intra-coded blocks of size $8\times 2$. + +More information can be found in JVET-P0085 and \url{10.1109/ICIP40778.2020.9190840}. + diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index 4ee2de1b7c20810deb096e6c83d28f1c4398e9de..9ed20447a0ba672564f75f3930d706ae36ac5c31 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -89,7 +89,18 @@ uint32_t DecApp::decode() { int poc; PicList *pcListPic = nullptr; - + +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct featureCounter; + FeatureCounterStruct featureCounterOld; + ifstream bitstreamSize(m_bitstreamFileName.c_str(), ifstream::in | ifstream::binary); + std::streampos fsize = 0; + fsize = bitstreamSize.tellg(); + bitstreamSize.seekg( 0, std::ios::end ); + featureCounter.bytes = (int) bitstreamSize.tellg() - (int) fsize; + bitstreamSize.close(); +#endif + ifstream bitstreamFile(m_bitstreamFileName.c_str(), ifstream::in | ifstream::binary); if (!bitstreamFile) { @@ -176,6 +187,11 @@ uint32_t DecApp::decode() m_cDecLib.setHTidExternalSetFlag(m_mTidExternalSet); m_cDecLib.setTOlsIdxExternalFlag(m_tOlsIdxTidExternalSet); +#ifdef GREEN_METADATA_SEI_ENABLED + m_cDecLib.setFeatureAnalysisFramewise( m_GMFAFramewise); + m_cDecLib.setGMFAFile(m_GMFAFile); +#endif + bool gdrRecoveryPeriod[MAX_NUM_LAYER_IDS] = { false }; bool prevPicSkipped = true; int lastNaluLayerId = -1; @@ -782,6 +798,14 @@ uint32_t DecApp::decode() m_cDecLib.resetAccessUnitApsNals(); m_cDecLib.resetAccessUnitPicInfo(); } +#ifdef GREEN_METADATA_SEI_ENABLED + if (m_GMFA && m_GMFAFramewise && bNewPicture) + { + FeatureCounterStruct featureCounterUpdated = m_cDecLib.getFeatureCounter(); + writeGMFAOutput(featureCounterUpdated, featureCounterOld, m_GMFAFile,false); + featureCounterOld = m_cDecLib.getFeatureCounter(); + } +#endif } if (!m_annotatedRegionsSEIFileName.empty()) { @@ -790,7 +814,24 @@ uint32_t DecApp::decode() // May need to check again one more time as in case one the bitstream has only one picture, the first check may miss it setOutputPicturePresentInStream(); CHECK(!outputPicturePresentInBitstream, "It is required that there shall be at least one picture with PictureOutputFlag equal to 1 in the bitstream") - + +#ifdef GREEN_METADATA_SEI_ENABLED + if (m_GMFA && m_GMFAFramewise) //Last frame + { + FeatureCounterStruct featureCounterUpdated = m_cDecLib.getFeatureCounter(); + writeGMFAOutput(featureCounterUpdated, featureCounterOld, m_GMFAFile, false); + featureCounterOld = m_cDecLib.getFeatureCounter(); + } + + if (m_GMFA) + { + // Summary + FeatureCounterStruct featureCounterFinal = m_cDecLib.getFeatureCounter(); + FeatureCounterStruct dummy; + writeGMFAOutput(featureCounterFinal, dummy, m_GMFAFile, true); + } +#endif + xFlushOutput( pcListPic ); #if JVET_Z0120_SII_SEI_PROCESSING @@ -1568,4 +1609,6 @@ bool DecApp::xIsNaluWithinTargetOutputLayerIdSet( const InputNALUnit* nalu ) con != m_targetOutputLayerIdSet.end(); } + + //! \} diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h index bf87a7e1a5c7fbf61aac6b5d2f627a8dea5c158a..d427cd39b2a4bd97ef84985ce7f3678121586e08 100644 --- a/source/App/DecoderApp/DecApp.h +++ b/source/App/DecoderApp/DecApp.h @@ -122,7 +122,6 @@ private: void writeLineToOutputLog(Picture * pcPic); void xOutputAnnotatedRegions(PicList* pcListPic); - }; //! \} diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index 321826beca7cb0119f0f52e9919ebb3cd0f327d1..e5f1a7ccb7651d332bf1f319f5afc1f1093e37c5 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -123,6 +123,11 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) "\t1: enable bit statistic\n" "\t2: enable tool statistic\n" "\t3: enable bit and tool statistic\n") +#endif +#ifdef GREEN_METADATA_SEI_ENABLED + ("GMFA", m_GMFA, false, "Write output file for the Green-Metadata analyzer for decoder complexity metrics (JVET-P0085)\n") + ("GMFAFile", m_GMFAFile, string(""), "File for the Green Metadata Bit Stream Feature Analyzer output (JVET-P0085)\n") + ("GMFAFramewise", m_GMFAFramewise, false, "Output of frame-wise Green Metadata Bit Stream Feature Analyzer files\n") #endif ("MCTSCheck", m_mctsCheck, false, "If enabled, the decoder checks for violations of mc_exact_sample_value_match_flag in Temporal MCTS ") ("targetSubPicIdx", m_targetSubPicIdx, 0, "Specify which subpicture shall be written to output, using subpic index, 0: disabled, subpicIdx=m_targetSubPicIdx-1 \n" ) diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index db503e96d637d31a1a9464997e02a448537c5aa9..4721ba11bb0d010748aedbafd5ea8e5d943073a2 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -90,7 +90,11 @@ protected: std::string m_cacheCfgFile; ///< Config file of cache model int m_statMode; ///< Config statistic mode (0 - bit stat, 1 - tool stat, 3 - both) bool m_mctsCheck; - +#ifdef GREEN_METADATA_SEI_ENABLED + bool m_GMFA; + std::string m_GMFAFile; + bool m_GMFAFramewise; +#endif int m_upscaledOutput; ////< Output upscaled (2), decoded but in full resolution buffer (1) or decoded cropped (0, default) picture for RPR. #if JVET_AB0081 int m_upscaleFilterForDisplay; diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index cf7f5b3c07bba6dadfd1ac65707dac8e353a8433..005392c1c8a44d3e0ee65348426e1504e43f6f2e 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -906,6 +906,22 @@ void EncApp::xInitLibCfg( int layerIdx ) m_cEncLib.setDoSEITransformType ( m_doSEITransformType); m_cEncLib.setParameterSetsInclusionIndicationSEIEnabled (m_parameterSetsInclusionIndicationSEIEnabled); m_cEncLib.setSelfContainedClvsFlag (m_selfContainedClvsFlag); +#ifdef GREEN_METADATA_SEI_ENABLED + m_cEncLib.setGMFAFile(m_GMFAFile); + m_cEncLib.setSEIGreenMetadataInfoSEIEnable ( m_greenMetadataType ); + m_cEncLib.setSEIGreenMetadataExtendedRepresentation ( m_greenMetadataExtendedRepresentation); + m_cEncLib.setSEIGreenMetadataGranularityType ( m_greenMetadataGranularityType); + m_cEncLib.setSEIGreenMetadataType ( m_greenMetadataType ); + m_cEncLib.setSEIGreenMetadataPeriodType ( m_greenMetadataPeriodType ); + m_cEncLib.setSEIGreenMetadataPeriodNumPictures (m_greenMetadataPeriodNumPictures); + m_cEncLib.setSEIGreenMetadataPeriodNumSeconds (m_greenMetadataPeriodNumSeconds); + //Metrics for quality recovery after low-power encoding + m_cEncLib.setSEIXSDNumberMetrics (m_xsdNumberMetrics); + m_cEncLib.setSEIXSDMetricTypePSNR (m_xsdMetricTypePSNR); + m_cEncLib.setSEIXSDMetricTypeSSIM (m_xsdMetricTypeSSIM); + m_cEncLib.setSEIXSDMetricTypeWPSNR (m_xsdMetricTypeWPSNR); + m_cEncLib.setSEIXSDMetricTypeWSPSNR (m_xsdMetricTypeWSPSNR); +#endif m_cEncLib.setErpSEIEnabled ( m_erpSEIEnabled ); m_cEncLib.setErpSEICancelFlag ( m_erpSEICancelFlag ); m_cEncLib.setErpSEIPersistenceFlag ( m_erpSEIPersistenceFlag ); @@ -1875,4 +1891,23 @@ void EncApp::printChromaFormat() } } +#ifdef GREEN_METADATA_SEI_ENABLED +void EncApp::featureToFile(std::ofstream& featureFile,int feature[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1], std::string featureName) +{ + featureFile << "\tn." << featureName << " = [...\n\t"; + for (size_t i = 0; i < MAX_CU_DEPTH+1; i++) + { + for (size_t j = 0; j < MAX_CU_DEPTH+1; j++) + { + featureFile << " " << feature[j][i] << " "; + } + if (i != MAX_CU_DEPTH) + { + featureFile << ";... \n\t"; + } + } + featureFile << "]; \n "; +} +#endif + //! \} diff --git a/source/App/EncoderApp/EncApp.h b/source/App/EncoderApp/EncApp.h index 60e776665103a731964cc5be5c3a739549e38c43..7c4138c60d8aff97c6eb14a243bc21c62330c2ce 100644 --- a/source/App/EncoderApp/EncApp.h +++ b/source/App/EncoderApp/EncApp.h @@ -110,6 +110,9 @@ private: PelStorage* m_filteredOrgPicForFG; EncTemporalFilter m_temporalFilterForFG; bool m_flush; +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter; +#endif public: EncApp(std::fstream &bitStream, EncLibCommon *encLibCommon); @@ -134,6 +137,11 @@ public: int getALFAPSIDShift() { return m_cEncLib.getALFAPSIDShift(); } void forceMaxNumALFAPS(int n) { m_cEncLib.setMaxNumALFAPS(n); } void forceALFAPSIDShift(int n) { m_cEncLib.setALFAPSIDShift(n); } +#ifdef GREEN_METADATA_SEI_ENABLED + uint32_t getTotalNumberOfBytes() {return m_totalBytes;} + FeatureCounterStruct getFeatureCounter(){return m_cEncLib.getFeatureCounter();} + void featureToFile(std::ofstream& featureFile,int feature[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1], std::string featureName); +#endif };// END CLASS DEFINITION EncApp //! \} diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index c9b41b55cb0c576d83dff023f0007c6aaa91232d..da97b78e23310cc71be984e492c37e9dde0a9a1f 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -825,7 +825,21 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ( "CropOffsetBottom", m_cropOffsetBottom, 0, "Crop Offset Bottom position") ( "CalculateHdrMetrics", m_calculateHdrMetrics, false, "Enable HDR metric calculation") #endif - +#ifdef GREEN_METADATA_SEI_ENABLED + ("SEIGreenMetadataType", m_greenMetadataType, -1, "Value for the green_metadata_type specifies the type of metadata that is present in the SEI message. -1: Green metadata disabled (default); 0: Decoder complexity metrics; 1: quality recovery after low-power encoding") + ("SEIGreenMetadataGranularityType", m_greenMetadataGranularityType, -1, "Specifies the type of granularity for which the metadata are applicable. Only implemented for picture granularity. ") + ("SEIGreenMetadataPeriodType", m_greenMetadataPeriodType, 0, "Value for the Period Type incidacting over which amount of time the metadata have been calculated") + ("SEIGreenMetadataPeriodTypeSeconds", m_greenMetadataPeriodNumSeconds, 1, "indicates the number of seconds over which the metadata are applicable when SEIGreenMetadataPeriodType is 2.") + ("SEIGreenMetadataPeriodTypePictures", m_greenMetadataPeriodNumPictures, 1, "specifies the number of pictures, counted in decoding order, over which the metadata are applicable when SEIGreenMetadataPeriodType is 3.") + ("SEIXSDMetricNumber", m_xsdNumberMetrics, 1, "Number of quality metrics.") + ("SEIXSDMetricTypePSNR", m_xsdMetricTypePSNR, false, "Set to 'true' if PSNR shall be signalled. ") + ("SEIXSDMetricTypeSSIM", m_xsdMetricTypeSSIM, false, "Set to 'true' if SSIM shall be signalled. ") + ("SEIXSDMetricTypeWPSNR", m_xsdMetricTypeWPSNR, false, "Set to 'true' if WPSNR shall be signalled. ") + ("SEIXSDMetricTypeWSPSNR", m_xsdMetricTypeWSPSNR, false, "Set to 'true' if WSSPSNR shall be signalled. ") + ("SEIGreenMetadataExtendedRepresentation", m_greenMetadataExtendedRepresentation, 0, "Specifies whether reduced or extended set of complexity metrics is signelled. ") + ("GMFA", m_GMFA, false, "Write output file for the Green-Metadata analyzer for decoder complexity metrics (JVET-P0085)\n") + ("GMFAFile", m_GMFAFile, string(""), "File for the Green Metadata Bit Stream Feature Analyzer output (JVET-P0085)\n") +#endif //Field coding parameters ("FieldCoding", m_isField, false, "Signals if it's a field based coding") ("TopFieldFirst, Tff", m_isTopFieldFirst, false, "In case of field based coding, signals whether if it's a top field first or not") @@ -5159,6 +5173,17 @@ bool EncAppCfg::xHasNonZeroTemporalID () return false; } +#ifdef GREEN_METADATA_SEI_ENABLED +bool EncAppCfg::getGMFAUsage() { + return m_GMFA; +} + +std::string EncAppCfg::getGMFAFile (){ + return m_GMFAFile; +} + +#endif + bool EncAppCfg::xHasLeadingPicture () { for (unsigned int i = 0; i < m_iGOPSize; i++) diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index cf5ea5dcbdf3ddb32cd756ffc02737f7a752ce41..9a43eba2816cca8a81c42ef760f5b7d9e6d41b4a 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -858,7 +858,27 @@ protected: int m_SII_BlendingRatio; void setBlendingRatioSII(int value) { m_SII_BlendingRatio = value; } #endif - +#ifdef GREEN_METADATA_SEI_ENABLED +public: + std::string getGMFAFile (); + bool getGMFAUsage(); +protected: + std::string m_GMFAFile; + bool m_GMFA; + + int m_greenMetadataType; + int m_greenMetadataExtendedRepresentation; + int m_greenMetadataGranularityType; + int m_greenMetadataPeriodType; + int m_greenMetadataPeriodNumSeconds; + int m_greenMetadataPeriodNumPictures; + + int m_xsdNumberMetrics; + bool m_xsdMetricTypePSNR; + bool m_xsdMetricTypeSSIM; + bool m_xsdMetricTypeWPSNR; + bool m_xsdMetricTypeWSPSNR; +#endif std::string m_summaryOutFilename; ///< filename to use for producing summary output file. std::string m_summaryPicFilenameBase; ///< Base filename to use for producing summary picture output files. The actual filenames used will have I.txt, P.txt and B.txt appended. uint32_t m_summaryVerboseness; ///< Specifies the level of the verboseness of the text output. diff --git a/source/App/EncoderApp/encmain.cpp b/source/App/EncoderApp/encmain.cpp index 79a8738ff7ee44012a2da81ceff3af376d8d5b61..a73088a543c488999ce802d08f1e3299797f4e87 100644 --- a/source/App/EncoderApp/encmain.cpp +++ b/source/App/EncoderApp/encmain.cpp @@ -336,7 +336,15 @@ int main(int argc, char* argv[]) #else auto encTime = std::chrono::duration_cast<std::chrono::milliseconds>( endTime - startTime).count(); #endif - +#ifdef GREEN_METADATA_SEI_ENABLED + for( auto & encApp : pcEncApp ) + { + FeatureCounterStruct featureCounterFinal = encApp->getFeatureCounter(); + featureCounterFinal.bytes = encApp->getTotalNumberOfBytes(); + FeatureCounterStruct dummy; + writeGMFAOutput(featureCounterFinal, dummy, encApp->getGMFAFile(),true); + } +#endif for( auto & encApp : pcEncApp ) { encApp->destroyLib(); diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp index 0276e88886eb3682ac26b1b710e5b45b76366f7c..d7d5b4534ee790ad2190393e3a705bc1bd5ffa5c 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp @@ -376,7 +376,9 @@ void AdaptiveLoopFilter::applyCcAlfFilter(CodingStructure &cs, ComponentID compI const Area blkDst(xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY); m_filterCcAlf(dstBuf, buf, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight, m_alfVBLumaPos); - +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.ccalf++; +#endif xStart = xEnd; } @@ -392,6 +394,9 @@ void AdaptiveLoopFilter::applyCcAlfFilter(CodingStructure &cs, ComponentID compI m_filterCcAlf(dstBuf, recYuvExt, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight, m_alfVBLumaPos); +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.ccalf++; +#endif } } ctuIdx++; @@ -515,6 +520,10 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) coeff = m_fixedFilterSetCoeffDec[filterSetIndex]; clip = m_clipDefault; } +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfLumaType7+= (width * height / 16) ; + cs.m_featureCounter.alfLumaPels += (width * height); +#endif m_filter7x7Blk(m_classifier, recYuv, buf, blkDst, blkSrc, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs , m_alfVBLumaCTUHeight , m_alfVBLumaPos @@ -535,6 +544,10 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) m_filter5x5Blk(m_classifier, recYuv, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs , m_alfVBChmaCTUHeight , m_alfVBChmaPos ); +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfChromaType5+= ((width >> chromaScaleX) * (height >> chromaScaleY) / 16) ; + cs.m_featureCounter.alfChromaPels += ((width >> chromaScaleX) * (height >> chromaScaleY)) ; +#endif } if (cu->slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1]) { @@ -546,7 +559,10 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) Area blkDst(xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY); const int16_t *filterCoeff = m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1][filterIdx - 1]; - +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfLumaType7+= (width * height / 16) ; + cs.m_featureCounter.alfLumaPels += (width * height); +#endif m_filterCcAlf(recYuv.get(compID), buf, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight, m_alfVBLumaPos); } @@ -579,6 +595,10 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) coeff = m_fixedFilterSetCoeffDec[filterSetIndex]; clip = m_clipDefault; } +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfLumaType7+= (width * height / 16) ; + cs.m_featureCounter.alfLumaPels += (width * height); +#endif m_filter7x7Blk(m_classifier, recYuv, tmpYuv, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, m_alfVBLumaCTUHeight, m_alfVBLumaPos); } @@ -593,6 +613,10 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) { Area blk(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY); uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx]; +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfChromaType5+= ((width >> chromaScaleX) * (height >> chromaScaleY) / 16) ; + cs.m_featureCounter.alfChromaPels += ((width >> chromaScaleX) * (height >> chromaScaleY)) ; +#endif m_filter5x5Blk(m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_alfVBChmaCTUHeight, m_alfVBChmaPos); @@ -607,7 +631,9 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) Area blkSrc(xPos, yPos, width, height); const int16_t *filterCoeff = m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1][filterIdx - 1]; - +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.ccalf++; +#endif m_filterCcAlf(recYuv.get(compID), tmpYuv, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight, m_alfVBLumaPos); } diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index ef5c606417054a38760655d800050ffdf3e0920e..d3f7823d9a4c5d028b7b6397ad420bb7028199ec 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -208,7 +208,10 @@ public: Distortion interHad; TreeType treeType; //because partitioner can not go deep to tu and cu coding (e.g., addCU()), need another variable for indicating treeType ModeType modeType; - +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter; +#endif + void initStructData (const int &QP = MAX_INT, const bool &skipMotBuf = false); void initSubStructure( CodingStructure& cs, const ChannelType chType, const UnitArea &subArea, const bool &isTuEnc); diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 5c284b9693b5b183b32fe6d68c67af6be55e04e2..7fa2f78b50ebb0dfa8c085595c74c086b54f4eaa 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -43,6 +43,10 @@ #include <iomanip> #include <limits> +#ifdef GREEN_METADATA_SEI_ENABLED +#include <fstream> +#endif + #if _MSC_VER > 1000 // disable "signed and unsigned mismatch" @@ -644,6 +648,189 @@ T* aligned_malloc(size_t len, size_t alignement) { # define ALWAYS_INLINE #endif +#ifdef GREEN_METADATA_SEI_ENABLED +struct FeatureCounterStruct// Bit Stream Feature Analyzer structure containing all specific features +{ + int width = -1; + int height = -1; + int bytes = -1; + int baseQP[64] = { 0 }; + int isYUV400 = -1; + int isYUV420 = -1; + int isYUV422 = -1; + int isYUV444 = -1; + int is8bit = -1; + int is10bit = -1; + int is12bit = -1; + int iSlices = 0; + int bSlices = 0; + int pSlices = 0; + + int intraBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaPlaBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaDcBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaHvdBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaHvBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaAngBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaPlaBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaDcBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaHvdBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaHvBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaAngBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaCrossCompBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraPDPCBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaPDPCBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaPDPCBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraMIPBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaMIPBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaMIPBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraSubPartitionsHorizontal[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaSubPartitionsHorizontal[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaSubPartitionsHorizontal[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraSubPartitionsVertical[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraLumaSubPartitionsVertical[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int intraChromaSubPartitionsVertical[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int IBCBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int IBCLumaBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int IBCChromaBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + // Inter-Features + int interBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int interLumaBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int interChromaBlockSizes[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int interInterBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int interLumaInterBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int interChromaInterBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int interSkipBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int interLumaSkipBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int interChromaSkipBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int interMergeBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int interLumaMergeBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int interChromaMergeBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int affine[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int affineLuma[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int affineChroma[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int affineMerge[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int affineLumaMerge[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int affineChromaMerge[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int affineInter[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int affineLumaInter[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int affineChromaInter[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int affineSkip[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int affineLumaSkip[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int affineChromaSkip[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int geo[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int geoLuma[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int geoChroma[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int64_t biPredPel = 0; + int64_t uniPredPel = 0; + int64_t fracPelHor = 0; + int64_t fracPelVer = 0; + int64_t fracPelBoth = 0; + int64_t copyCUPel = 0; + int64_t affineFracPelHor = 0; + int64_t affineFracPelVer = 0; + int64_t affineFracPelBoth = 0; + int64_t affineCopyCUPel = 0; + int dmvrBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int bdofBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + // Transform + int transformBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int transformLumaBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int transformChromaBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int transformSkipBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int transformLumaSkipBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + int transformChromaSkipBlocks[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1] = { { 0 } }; + + int64_t transformLFNST4 = 0; + int64_t transformLFNST8 = 0; + //Coefficent + int64_t nrOfCoeff = 0; + int64_t coeffG1 = 0; + double valueOfCoeff = 0; + //In-Loop Filter + int64_t boundaryStrength[3] = { 0 }; + int64_t boundaryStrengthPel[3] = { 0 }; + int64_t saoLumaBO = 0; + int64_t saoLumaEO = 0; + int64_t saoChromaBO = 0; + int64_t saoChromaEO = 0; + int64_t saoLumaPels = 0; + int64_t saoChromaPels = 0; + int64_t alfLumaType7 = 0; + int64_t alfChromaType5 = 0; + int64_t alfLumaPels = 0; + int64_t alfChromaPels = 0; + int64_t ccalf = 0; + + void resetBoundaryStrengths() + { + for (int i = 0; i < 3; i++) + { + boundaryStrength[i] = 0; + boundaryStrengthPel[i] = 0; + } + } + + void addBoundaryStrengths(const FeatureCounterStruct &c) + { + for (int i = 0; i < 3; i++) + { + boundaryStrength[i] += c.boundaryStrength[i]; + boundaryStrengthPel[i] += c.boundaryStrengthPel[i]; + } + } + + void resetSAO() + { + saoLumaBO = 0; + saoLumaEO = 0; + saoChromaBO = 0; + saoChromaEO = 0; + saoLumaPels = 0; + saoChromaPels = 0; + } + + void addSAO(const FeatureCounterStruct &c) + { + saoLumaBO += c.saoLumaBO; + saoLumaEO += c.saoLumaEO; + saoChromaBO += c.saoChromaBO; + saoChromaEO += c.saoChromaEO; + saoLumaPels += c.saoLumaPels; + saoChromaPels += c.saoChromaPels; + } + + void resetALF() + { + alfLumaType7 = 0; + alfChromaType5 = 0; + alfLumaPels = 0; + alfChromaPels = 0; + ccalf = 0; + } + + void addALF(const FeatureCounterStruct &c) + { + alfLumaType7 += c.alfLumaType7; + alfChromaType5 += c.alfChromaType5; + alfLumaPels += c.alfLumaPels; + alfChromaPels += c.alfChromaPels; + ccalf += c.ccalf; + } +}; +#endif + + #if ENABLE_SIMD_OPT #ifdef TARGET_SIMD_X86 typedef enum{ diff --git a/source/Lib/CommonLib/DeblockingFilter.cpp b/source/Lib/CommonLib/DeblockingFilter.cpp index eb08dc7897d5c8916bbd92b21172595e5d8773ee..d56c273944f95a7c7ed6545acbeafe5298e2341c 100644 --- a/source/Lib/CommonLib/DeblockingFilter.cpp +++ b/source/Lib/CommonLib/DeblockingFilter.cpp @@ -155,6 +155,9 @@ void DeblockingFilter::deblockingFilterPic(CodingStructure &cs) } } #endif +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct tempFeatureCounter; +#endif for( int y = 0; y < pcv.heightInCtus; y++ ) { @@ -172,7 +175,13 @@ void DeblockingFilter::deblockingFilterPic(CodingStructure &cs) // CU-based deblocking for (auto &currCU: cs.traverseCUs(CS::getArea(cs, ctuArea, CHANNEL_TYPE_LUMA), CHANNEL_TYPE_LUMA)) { +#ifdef GREEN_METADATA_SEI_ENABLED + currCU.m_featureCounter.resetBoundaryStrengths(); +#endif xDeblockCU( currCU, EDGE_VER ); +#ifdef GREEN_METADATA_SEI_ENABLED + tempFeatureCounter.addBoundaryStrengths(currCU.m_featureCounter); +#endif } if( CS::isDualITree( cs ) ) @@ -182,7 +191,13 @@ void DeblockingFilter::deblockingFilterPic(CodingStructure &cs) for (auto &currCU: cs.traverseCUs(CS::getArea(cs, ctuArea, CHANNEL_TYPE_CHROMA), CHANNEL_TYPE_CHROMA)) { +#ifdef GREEN_METADATA_SEI_ENABLED + currCU.m_featureCounter.resetBoundaryStrengths(); +#endif xDeblockCU( currCU, EDGE_VER ); +#ifdef GREEN_METADATA_SEI_ENABLED + tempFeatureCounter.addBoundaryStrengths(currCU.m_featureCounter); +#endif } } } @@ -205,7 +220,13 @@ void DeblockingFilter::deblockingFilterPic(CodingStructure &cs) // CU-based deblocking for (auto &currCU: cs.traverseCUs(CS::getArea(cs, ctuArea, CHANNEL_TYPE_LUMA), CHANNEL_TYPE_LUMA)) { +#ifdef GREEN_METADATA_SEI_ENABLED + currCU.m_featureCounter.resetBoundaryStrengths(); +#endif xDeblockCU( currCU, EDGE_HOR ); +#ifdef GREEN_METADATA_SEI_ENABLED + tempFeatureCounter.addBoundaryStrengths(currCU.m_featureCounter); +#endif } if( CS::isDualITree( cs ) ) @@ -215,12 +236,21 @@ void DeblockingFilter::deblockingFilterPic(CodingStructure &cs) for (auto &currCU: cs.traverseCUs(CS::getArea(cs, ctuArea, CHANNEL_TYPE_CHROMA), CHANNEL_TYPE_CHROMA)) { +#ifdef GREEN_METADATA_SEI_ENABLED + currCU.m_featureCounter.resetBoundaryStrengths(); +#endif xDeblockCU( currCU, EDGE_HOR ); +#ifdef GREEN_METADATA_SEI_ENABLED + tempFeatureCounter.addBoundaryStrengths(currCU.m_featureCounter); +#endif } } } } +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.addBoundaryStrengths(tempFeatureCounter); +#endif DTRACE_PIC_COMP(D_REC_CB_LUMA_LF, cs, cs.getRecoBuf(), COMPONENT_Y); DTRACE_PIC_COMP(D_REC_CB_CHROMA_LF, cs, cs.getRecoBuf(), COMPONENT_Cb); DTRACE_PIC_COMP(D_REC_CB_CHROMA_LF, cs, cs.getRecoBuf(), COMPONENT_Cr); @@ -393,10 +423,23 @@ void DeblockingFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir if(cu.treeType != TREE_C) { es |= xGetBoundaryStrengthSingle(cu, edgeDir, localPos, CHANNEL_TYPE_LUMA); +#ifdef GREEN_METADATA_SEI_ENABLED + const int bsY = es.getBoundaryStrength(COMPONENT_Y); + cu.m_featureCounter.boundaryStrength[bsY]++; + cu.m_featureCounter.boundaryStrengthPel[bsY] += pelsInPart; +#endif } if(cu.treeType != TREE_L && cu.chromaFormat != CHROMA_400 && cu.blocks[COMPONENT_Cb].valid()) { es |= xGetBoundaryStrengthSingle(cu, edgeDir, localPos, CHANNEL_TYPE_CHROMA); +#ifdef GREEN_METADATA_SEI_ENABLED + const int bsCb = es.getBoundaryStrength(COMPONENT_Cb); + const int bsCr = es.getBoundaryStrength(COMPONENT_Cr); + cu.m_featureCounter.boundaryStrength[bsCb]++; + cu.m_featureCounter.boundaryStrength[bsCr]++; + cu.m_featureCounter.boundaryStrengthPel[bsCb] += pelsInPart; + cu.m_featureCounter.boundaryStrengthPel[bsCr] += pelsInPart; +#endif } m_edgeStrengths[edgeDir][rasterIdx] = es; } diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 8d5bf6c5b28208c82c557154be477a0cddd06223..3e903c4252d80ba1432811c8b921843b7fa41629 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -200,7 +200,9 @@ private: Window m_scalingWindow; int m_decodingOrderNumber; NalUnitType m_pictureType; - +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter; +#endif public: bool m_isSubPicBorderSaved; @@ -215,7 +217,11 @@ public: void saveSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight); void extendSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight); void restoreSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight); - +#ifdef GREEN_METADATA_SEI_ENABLED + void setFeatureCounter (FeatureCounterStruct b ) { m_featureCounter = b;} + FeatureCounterStruct getFeatureCounter (){return m_featureCounter;} +#endif + bool getSubPicSaved() { return m_isSubPicBorderSaved; } void setSubPicSaved(bool bVal) { m_isSubPicBorderSaved = bVal; } bool m_extendedBorder; diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h index e9ce8cfbfde9081d52cedb7d35f56f4ccc3e656d..6a1632c800a42da8fbb7523c8de5893128fdf71b 100644 --- a/source/Lib/CommonLib/SEI.h +++ b/source/Lib/CommonLib/SEI.h @@ -746,7 +746,10 @@ public: int m_greenMetadataType =-1; // Metrics for quality recovery after low-power encoding int m_xsdSubpicNumberMinus1 = -1; //xsd_metric_number_minus1 plus 1 indicates the number of objective quality metrics contained in the SEI message. - +#ifdef GREEN_METADATA_SEI_ENABLED + int m_xsdSubPicIdc; +#endif + int m_xsdMetricValuePSNR; int m_xsdMetricValueSSIM; int m_xsdMetricValueWPSNR; diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp index fa661de22f21753ddb008856a048288e06ee3b59..724e2cbe403dca1009a078488fed546371a89822 100644 --- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp +++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp @@ -597,7 +597,34 @@ void SampleAdaptiveOffset::offsetCTU(const UnitArea &area, const CPelUnitBuf &sr { verVirBndryPosComp[i] = (verVirBndryPos[i] >> ::getComponentScaleX(compID, area.chromaFormat)) - compArea.x; } - +#ifdef GREEN_METADATA_SEI_ENABLED + if (ctbOffset.typeIdc.newType == SAOModeNewTypes::START_BO) + { + if (compID == COMPONENT_Y) + { + cs.m_featureCounter.saoLumaBO++; + cs.m_featureCounter.saoLumaPels += area.lumaSize().width * area.lumaSize().height; + } + else + { + cs.m_featureCounter.saoChromaBO++; + cs.m_featureCounter.saoChromaPels += area.chromaSize().width * area.chromaSize().height; + } + } + else if (ctbOffset.typeIdc.newType == SAOModeNewTypes::EO_0 || ctbOffset.typeIdc.newType == SAOModeNewTypes::EO_135 || ctbOffset.typeIdc.newType == SAOModeNewTypes::EO_45 ||ctbOffset.typeIdc.newType == SAOModeNewTypes::EO_90 ) + { + if (compID == COMPONENT_Y) + { + cs.m_featureCounter.saoLumaEO++; + cs.m_featureCounter.saoLumaPels += area.lumaSize().width * area.lumaSize().height; + } + else + { + cs.m_featureCounter.saoChromaEO++; + cs.m_featureCounter.saoChromaPels += area.chromaSize().width * area.chromaSize().height; + } + } +#endif offsetBlock(cs.sps->getBitDepth(toChannelType(compID)), cs.slice->clpRng(compID), ctbOffset.typeIdc.newType, ctbOffset.offset, srcBlk, resBlk, srcStride, resStride, compArea.width, compArea.height, isLeftAvail, isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail, isAboveRightAvail, isBelowLeftAvail, diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 524f6ad993b36fd1d81146e60dde93e4f8f28adc..9c94d193950415517bebe6575558a096e0b351af 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -2810,6 +2810,9 @@ private: int m_tsrcIndex{ 0 }; unsigned m_riceBit[8]; int m_cntRightBottom; +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter; +#endif public: Slice(); @@ -2963,7 +2966,10 @@ public: return (m_eSliceType == B_SLICE && m_eNalUnitType == NAL_UNIT_CODED_SLICE_GDR); } #endif - +#ifdef GREEN_METADATA_SEI_ENABLED + void setFeatureCounter (FeatureCounterStruct b ) {m_featureCounter = b;} + FeatureCounterStruct getFeatureCounter (){return m_featureCounter;} +#endif bool getEnableDRAPSEI () const { return m_enableDRAPSEI; } void setEnableDRAPSEI ( bool b ) { m_enableDRAPSEI = b; } bool getUseLTforDRAP () const { return m_useLTforDRAP; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 9294545005a34c8ab954712b68b9a9115c7f8d71..4274ecc618724cb907ff6eff29dbd437f09b6cdc 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,7 @@ #include <cstring> #include <assert.h> #include <cassert> +#include "CommonDef.h" // clang-format off @@ -61,6 +62,7 @@ //########### place macros to be removed in next cycle below this line ############### #define JVET_AB0047_MOVE_GATED_SYNTAX_OF_NNPFC_URIS_AFTER_NNPFC_MODEIDC 1 +#define JVET_AB0072 1 //Green-MPEG SEI Messaging (JVET-AB0072) //########### place macros to be be kept below this line ############### @@ -136,6 +138,10 @@ typedef std::pair<int, int> TrCost; #define KEEP_PRED_AND_RESI_SIGNALS 0 +#if JVET_AB0072 +#define GREEN_METADATA_SEI_ENABLED 0 //JVET-AB0072: Analyser for the Green Metadata SEI +#endif + // ==================================================================================================================== // Debugging // ==================================================================================================================== @@ -864,6 +870,7 @@ enum NalUnitType NAL_UNIT_INVALID }; + #if SHARP_LUMA_DELTA_QP enum LumaLevelToDQPMode { @@ -1364,6 +1371,8 @@ struct XUCache TUCache tuCache; }; + + //! \} #endif diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 4be76be95be35a151269a9a7694adac18258ec76..b4896fbaa7e56c0ebb995e7db71119ac1d3d4ceb 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -334,7 +334,10 @@ struct CodingUnit : public UnitArea uint8_t reusePLTSize[MAX_NUM_CHANNEL_TYPE]; uint8_t curPLTSize[MAX_NUM_CHANNEL_TYPE]; Pel curPLT[MAX_NUM_COMPONENT][MAXPLTSIZE]; - +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter; +#endif + CodingUnit() : chType( CH_L ) { } CodingUnit(const UnitArea &unit); CodingUnit(const ChromaFormat _chromaFormat, const Area &area); diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index f7ffd81dbe930cde1be1700683cde2ae67cf3ff2..d5fcad2659081de097189394b2478eb07a563f72 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -46,6 +46,9 @@ #include <utility> #include <algorithm> +#ifdef GREEN_METADATA_SEI_ENABLED +#include <fstream> +#endif // CS tools bool CS::isDualITree( const CodingStructure &cs ) @@ -4841,3 +4844,1087 @@ bool allowLfnstWithMip(const Size& block) } return false; } + + +#ifdef GREEN_METADATA_SEI_ENABLED +void writeGMFAOutput(FeatureCounterStruct& featureCounterUpdated, FeatureCounterStruct& featureCounterOld, std::string GMFAFile,bool lastFrame ) +{ + std::string fileName = std::string(""); + std::string matlabFile = std::string(""); + if (GMFAFile.length() == 0) + { + return; + } + fileName = GMFAFile; + size_t strStart = 0; + size_t strEnd = 0; + + int64_t codedFrames = featureCounterUpdated.iSlices + featureCounterUpdated.bSlices + featureCounterUpdated.pSlices; + strEnd = fileName.rfind('.'); + strEnd = strEnd == fileName.length() ? 0 : strEnd; + + if (!lastFrame) + { + fileName = fileName.substr(0, strEnd) + "_" + std::to_string(codedFrames) + fileName.substr(strEnd, fileName.length()); + } + + strStart = fileName.find_last_of("/\\"); + strStart = strStart == fileName.length() ? 0 : strStart+1; + + matlabFile = fileName.substr(strStart, strEnd-strStart); + std::ofstream featureFile(fileName); + + featureFile << "function [n]="; + featureFile << matlabFile.c_str(); + featureFile << "() \n"; + //General features + featureFile << "\tn.EO = 1;\n"; + featureFile << "\tn.ISlice = " << featureCounterUpdated.iSlices-featureCounterOld.iSlices << ";\n"; + featureFile << "\tn.PSlice = " << featureCounterUpdated.pSlices-featureCounterOld.pSlices << ";\n"; + featureFile << "\tn.BSlice = " << featureCounterUpdated.bSlices-featureCounterOld.bSlices << ";\n"; + + featureFile << "\tn.width = " << featureCounterUpdated.width << " ; \n"; + featureFile << "\tn.height = " << featureCounterUpdated.height << " ; \n"; + featureFile << "\tn.baseQP = [...\n\t"; + for (int iter = 0; iter < 64; iter++) + { + featureFile << " " << featureCounterUpdated.baseQP[iter]-featureCounterOld.baseQP[iter] << " "; + if (iter % 8 == 7 && iter != 63) + { + featureFile << " ...\n\t"; + } + } + featureFile << "]; \n "; + + featureFile << "\tn.bytes = " << featureCounterUpdated.bytes << " ; \n"; + featureFile << "\tn.is8bit = " << featureCounterUpdated.is8bit << " ; \n"; + featureFile << "\tn.is10bit = " << featureCounterUpdated.is10bit << " ; \n"; + featureFile << "\tn.is12bit = " << featureCounterUpdated.is12bit << " ; \n"; + featureFile << "\tn.isYUV400 = " << featureCounterUpdated.isYUV400 << " ; \n"; + featureFile << "\tn.isYUV420 = " << featureCounterUpdated.isYUV420 << " ; \n"; + featureFile << "\tn.isYUV422 = " << featureCounterUpdated.isYUV422 << " ; \n"; + featureFile << "\tn.isYUV444 = " << featureCounterUpdated.isYUV444 << " ; \n"; + //Intra Feature + featureToFile(featureFile, featureCounterUpdated.intraBlockSizes, "intraBlocks",true,featureCounterOld.intraBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraLumaPlaBlockSizes, "intraPlaLuma",true,featureCounterOld.intraLumaPlaBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraLumaDcBlockSizes, "intraDCLuma",true,featureCounterOld.intraLumaDcBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraLumaHvdBlockSizes, "intraHVDLuma",true,featureCounterOld.intraLumaHvdBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraLumaHvBlockSizes, "intraHVLuma",true,featureCounterOld.intraLumaHvBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraLumaAngBlockSizes, "intraAngLuma",true,featureCounterOld.intraLumaAngBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraChromaPlaBlockSizes, "intraPlaChroma",true,featureCounterOld.intraChromaPlaBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraChromaDcBlockSizes, "intraDCChroma",true,featureCounterOld.intraChromaDcBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraChromaHvdBlockSizes, "intraHVDChroma",true,featureCounterOld.intraChromaHvdBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraChromaHvBlockSizes, "intraHVChroma",true,featureCounterOld.intraChromaHvBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraChromaAngBlockSizes, "intraAngChroma",true,featureCounterOld.intraChromaAngBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraChromaCrossCompBlockSizes, "intraCrossComp",true,featureCounterOld.intraChromaCrossCompBlockSizes); + + featureToFile(featureFile, featureCounterUpdated.intraPDPCBlockSizes, "intraPDPC",true,featureCounterOld.intraPDPCBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraLumaPDPCBlockSizes, "intraLumaPDPC",true,featureCounterOld.intraLumaPDPCBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraChromaPDPCBlockSizes, "intraChromaPDPC",true,featureCounterOld.intraChromaPDPCBlockSizes); + + featureToFile(featureFile, featureCounterUpdated.intraMIPBlockSizes, "intraMIP",true,featureCounterOld.intraMIPBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraLumaMIPBlockSizes, "intraLumaMIP",true,featureCounterOld.intraLumaMIPBlockSizes); + featureToFile(featureFile, featureCounterUpdated.intraChromaMIPBlockSizes, "intraChromaMIP",true,featureCounterOld.intraChromaMIPBlockSizes); + + featureToFile(featureFile, featureCounterUpdated.IBCBlockSizes, "intraIBC",true,featureCounterOld.IBCBlockSizes); + featureToFile(featureFile, featureCounterUpdated.IBCLumaBlockSizes, "intraLumaIBC",true,featureCounterOld.IBCLumaBlockSizes); + featureToFile(featureFile, featureCounterUpdated.IBCChromaBlockSizes, "intraChromaIBC",true,featureCounterOld.IBCChromaBlockSizes); + + featureToFile(featureFile, featureCounterUpdated.intraSubPartitionsHorizontal, "intraSubPartitionsHorizontal",true,featureCounterOld.intraSubPartitionsHorizontal); + featureToFile(featureFile, featureCounterUpdated.intraLumaSubPartitionsHorizontal, "intraLumaSubPartitionsHorizontal",true,featureCounterOld.intraLumaSubPartitionsHorizontal); + featureToFile(featureFile, featureCounterUpdated.intraChromaSubPartitionsHorizontal,"intraChromaSubPartitionsHorizontal",true,featureCounterOld.intraChromaSubPartitionsHorizontal); + + featureToFile(featureFile, featureCounterUpdated.intraSubPartitionsVertical, "intraSubPartitionsVertical",true,featureCounterOld.intraSubPartitionsVertical); + featureToFile(featureFile, featureCounterUpdated.intraLumaSubPartitionsVertical, "intraLumaSubPartitionsVertical",true,featureCounterOld.intraLumaSubPartitionsVertical); + featureToFile(featureFile, featureCounterUpdated.intraChromaSubPartitionsVertical, "intraChromaSubPartitionsVertical",true,featureCounterOld.intraChromaSubPartitionsVertical); + + //Inter + featureToFile(featureFile, featureCounterUpdated.interBlockSizes, "interBlocks",true,featureCounterOld.interBlockSizes); + featureToFile(featureFile, featureCounterUpdated.interLumaBlockSizes, "interLumaBlocks",true,featureCounterOld.interLumaBlockSizes); + featureToFile(featureFile, featureCounterUpdated.interChromaBlockSizes, "interChromaBlocks",true,featureCounterOld.interChromaBlockSizes); + + featureToFile(featureFile, featureCounterUpdated.interInterBlocks, "interInter",true,featureCounterOld.interInterBlocks); + featureToFile(featureFile, featureCounterUpdated.interLumaInterBlocks, "interLumaInter",true,featureCounterOld.interLumaInterBlocks); + featureToFile(featureFile, featureCounterUpdated.interChromaInterBlocks, "interChromaInter",true,featureCounterOld.interChromaInterBlocks); + + featureToFile(featureFile, featureCounterUpdated.interMergeBlocks, "interMerge",true,featureCounterOld.interMergeBlocks); + featureToFile(featureFile, featureCounterUpdated.interLumaMergeBlocks, "interLumaMerge",true,featureCounterOld.interLumaMergeBlocks); + featureToFile(featureFile, featureCounterUpdated.interChromaMergeBlocks, "interChromaMerge",true,featureCounterOld.interChromaMergeBlocks); + + featureToFile(featureFile, featureCounterUpdated.interSkipBlocks, "interSkip",true,featureCounterOld.interSkipBlocks); + featureToFile(featureFile, featureCounterUpdated.interLumaSkipBlocks, "interLumaSkip",true,featureCounterOld.interLumaSkipBlocks); + featureToFile(featureFile, featureCounterUpdated.interChromaSkipBlocks, "interChromaSkip",true,featureCounterOld.interChromaSkipBlocks); + + featureToFile(featureFile, featureCounterUpdated.affine, "interAffine",true,featureCounterOld.affine); + featureToFile(featureFile, featureCounterUpdated.affineLuma, "interLumaAffine",true,featureCounterOld.affineLuma); + featureToFile(featureFile, featureCounterUpdated.affineChroma, "interChromaAffine",true,featureCounterOld.affineChroma); + + featureToFile(featureFile, featureCounterUpdated.affineInter, "interAffineInter",true,featureCounterOld.affineInter); + featureToFile(featureFile, featureCounterUpdated.affineLumaInter, "interLumaAffineInter",true,featureCounterOld.affineLumaInter); + featureToFile(featureFile, featureCounterUpdated.affineChromaInter, "interChromaAffineInter",true,featureCounterOld.affineChromaInter); + + featureToFile(featureFile, featureCounterUpdated.affineMerge, "interAffineMerge",true,featureCounterOld.affineMerge); + featureToFile(featureFile, featureCounterUpdated.affineLumaMerge, "interLumaAffineMerge",true,featureCounterOld.affineLumaMerge); + featureToFile(featureFile, featureCounterUpdated.affineChromaMerge, "interChromaAffineMerge",true,featureCounterOld.affineChromaMerge); + + featureToFile(featureFile, featureCounterUpdated.affineSkip, "interAffineSkip",true,featureCounterOld.affineSkip); + featureToFile(featureFile, featureCounterUpdated.affineLumaSkip, "interLumaAffineSkip",true,featureCounterOld.affineLumaSkip); + featureToFile(featureFile, featureCounterUpdated.affineChromaSkip, "interChromaAffineSkip",true,featureCounterOld.affineChromaSkip); + + featureToFile(featureFile, featureCounterUpdated.geo, "geo",true,featureCounterOld.geo); + featureToFile(featureFile, featureCounterUpdated.geoLuma, "geoLuma",true,featureCounterOld.geoLuma); + featureToFile(featureFile, featureCounterUpdated.geoChroma, "geoChroma",true,featureCounterOld.geoChroma); + + featureToFile(featureFile, featureCounterUpdated.dmvrBlocks, "dmvrBlocks",true,featureCounterOld.dmvrBlocks); + featureToFile(featureFile, featureCounterUpdated.bdofBlocks, "bdofBlocks",true,featureCounterOld.bdofBlocks); + + featureFile << "\tn.uniPredPel = " << featureCounterUpdated.uniPredPel-featureCounterOld.uniPredPel << " ; \n"; + featureFile << "\tn.biPredPel = " << featureCounterUpdated.biPredPel-featureCounterOld.biPredPel << " ; \n"; + featureFile << "\tn.fracPelHor = " << featureCounterUpdated.fracPelHor-featureCounterOld.fracPelHor << " ; \n"; + featureFile << "\tn.fracPelVer = " << featureCounterUpdated.fracPelVer-featureCounterOld.fracPelVer << " ; \n"; + featureFile << "\tn.fracPelBoth = " << featureCounterUpdated.fracPelBoth-featureCounterOld.fracPelBoth << " ; \n"; + featureFile << "\tn.copyCUPel = " << featureCounterUpdated.copyCUPel-featureCounterOld.copyCUPel << " ; \n"; + + featureFile << "\tn.affineFracPelHor = " << featureCounterUpdated.affineFracPelHor-featureCounterOld.affineFracPelHor << " ; \n"; + featureFile << "\tn.affineFracPelVer = " << featureCounterUpdated.affineFracPelVer-featureCounterOld.affineFracPelVer << " ; \n"; + featureFile << "\tn.affineFracPelBoth = " << featureCounterUpdated.affineFracPelBoth-featureCounterOld.affineFracPelBoth << " ; \n"; + featureFile << "\tn.affineCopyCUPel = " << featureCounterUpdated.affineCopyCUPel-featureCounterOld.affineCopyCUPel << " ; \n"; + + //Transform + featureToFile(featureFile, featureCounterUpdated.transformBlocks, "transform",true,featureCounterOld.transformBlocks); + featureToFile(featureFile, featureCounterUpdated.transformLumaBlocks, "transformLuma",true,featureCounterOld.transformLumaBlocks); + featureToFile(featureFile, featureCounterUpdated.transformChromaBlocks, "transformChroma",true,featureCounterOld.transformChromaBlocks); + + featureToFile(featureFile, featureCounterUpdated.transformSkipBlocks, "transformSkip",true,featureCounterOld.transformSkipBlocks); + featureToFile(featureFile, featureCounterUpdated.transformLumaSkipBlocks, "transformLumaSkip",true,featureCounterOld.transformLumaSkipBlocks); + featureToFile(featureFile, featureCounterUpdated.transformChromaSkipBlocks, "transformChromaSkip",true,featureCounterOld.transformChromaSkipBlocks); + + featureFile << "\tn.transformLFNST4 = " << featureCounterUpdated.transformLFNST4-featureCounterOld.transformLFNST4 << " ; \n"; + featureFile << "\tn.transformLFNST8 = " << featureCounterUpdated.transformLFNST8-featureCounterOld.transformLFNST8 << " ; \n"; + + featureFile << "\tn.nrOfCoeff = " << featureCounterUpdated.nrOfCoeff-featureCounterOld.nrOfCoeff << " ; \n"; + featureFile << "\tn.coeffG1 = " << featureCounterUpdated.coeffG1-featureCounterOld.coeffG1 << " ; \n"; + featureFile << "\tn.valueOfCoeff = " << featureCounterUpdated.valueOfCoeff-featureCounterOld.valueOfCoeff << " ; \n"; + //In-Loop + featureFile << "\tn.BS0 = " << featureCounterUpdated.boundaryStrength[0]-featureCounterOld.boundaryStrength[0] << " ; \n"; + featureFile << "\tn.BS1 = " << featureCounterUpdated.boundaryStrength[1]-featureCounterOld.boundaryStrength[1] << " ; \n"; + featureFile << "\tn.BS2 = " << featureCounterUpdated.boundaryStrength[2]-featureCounterOld.boundaryStrength[2] << " ; \n"; + featureFile << "\tn.BSPel0 = " << featureCounterUpdated.boundaryStrengthPel[0]-featureCounterOld.boundaryStrengthPel[0] << " ; \n"; + featureFile << "\tn.BSPel1 = " << featureCounterUpdated.boundaryStrengthPel[1]-featureCounterOld.boundaryStrengthPel[1] << " ; \n"; + featureFile << "\tn.BSPel2 = " << featureCounterUpdated.boundaryStrengthPel[2]-featureCounterOld.boundaryStrengthPel[2] << " ; \n"; + featureFile << "\tn.saoLumaBO = " << featureCounterUpdated.saoLumaBO-featureCounterOld.saoLumaBO << " ; \n"; + featureFile << "\tn.saoLumaEO = " << featureCounterUpdated.saoLumaEO-featureCounterOld.saoLumaEO << " ; \n"; + featureFile << "\tn.saoChromaBO = " << featureCounterUpdated.saoChromaBO-featureCounterOld.saoChromaBO << " ; \n"; + featureFile << "\tn.saoChromaEO = " << featureCounterUpdated.saoChromaEO-featureCounterOld.saoChromaEO << " ; \n"; + featureFile << "\tn.saoLumaPels = " << featureCounterUpdated.saoLumaPels << " ; \n"; + featureFile << "\tn.saoChromaPels = " << featureCounterUpdated.saoChromaPels << " ; \n"; + featureFile << "\tn.alfLumaType7 = " << featureCounterUpdated.alfLumaType7-featureCounterOld.alfLumaType7 << " ; \n"; + featureFile << "\tn.alfChromaType5 = " << featureCounterUpdated.alfChromaType5-featureCounterOld.alfChromaType5 << " ; \n"; + featureFile << "\tn.alfLumaPels = " << featureCounterUpdated.alfLumaPels << " ; \n"; + featureFile << "\tn.alfChromaPels = " << featureCounterUpdated.alfChromaPels << " ; \n"; + featureFile << "\tn.ccalf = " << featureCounterUpdated.ccalf-featureCounterOld.ccalf << " ; \n"; + featureFile << "end\n"; + featureFile.close(); +} + +void featureToFile(std::ofstream& featureFile,int featureCounterReference[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1], std::string featureName,bool calcDifference,int featureCounter[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1]) +{ + featureFile << "\tn." << featureName << " = [...\n\t"; + for (size_t i = 0; i < MAX_CU_DEPTH+1; i++) + { + for (size_t j = 0; j < MAX_CU_DEPTH+1; j++) + { + if (calcDifference) + { + featureFile << " " << featureCounterReference[j][i] - featureCounter[j][i] << " "; + } + else + { + featureFile << " " << featureCounterReference[j][i] << " "; + } + } + if (i != MAX_CU_DEPTH) + { + featureFile << ";... \n\t"; + } + } + featureFile << "]; \n "; +} + +void countFeatures(FeatureCounterStruct& featureCounter, CodingStructure& cs, const UnitArea& ctuArea) +{ + SizeType cuWidthIdx = MAX_UINT; + SizeType cuHeightIdx = MAX_UINT; + + for (auto &currCU: cs.traverseCUs(ctuArea, CHANNEL_TYPE_LUMA)) + { + cuWidthIdx = floorLog2(currCU.lwidth()); + cuHeightIdx = floorLog2(currCU.lheight()); + if ((cuWidthIdx <= MAX_CU_DEPTH+1) && (cuHeightIdx <= MAX_CU_DEPTH+1)) + { + if (currCU.predMode == MODE_INTRA) // Intra-Mode + { + for (auto &currPU: CU::traversePUs(currCU)) + { + SizeType puWidthIdx = floorLog2(currPU.Y().width); + SizeType puHeightIdx = floorLog2(currPU.Y().height); + if ((puWidthIdx <= MAX_CU_DEPTH+1) && (puHeightIdx <= MAX_CU_DEPTH+1)) + { + featureCounter.intraBlockSizes[puWidthIdx][puHeightIdx]++; + SizeType lumaPredDir = currPU.intraDir[CHANNEL_TYPE_LUMA]; + if (currCU.mipFlag) + { + featureCounter.intraMIPBlockSizes[puWidthIdx][puHeightIdx]++; + featureCounter.intraLumaMIPBlockSizes[puWidthIdx][puHeightIdx]++; + } + else + { + if (lumaPredDir == PLANAR_IDX) + { + featureCounter.intraLumaPlaBlockSizes[puWidthIdx][puHeightIdx]++; + } + else if (lumaPredDir == DC_IDX) + { + featureCounter.intraLumaDcBlockSizes[puWidthIdx][puHeightIdx]++; + } + else if (lumaPredDir == HOR_IDX || lumaPredDir == VER_IDX || lumaPredDir == DIA_IDX) + { + featureCounter.intraLumaHvdBlockSizes[puWidthIdx][puHeightIdx]++; + } + else + { + featureCounter.intraLumaAngBlockSizes[puWidthIdx][puHeightIdx]++; + } + } + bool tempPDPC = + (currPU.Y().width >= MIN_TB_SIZEY && currPU.Y().height >= MIN_TB_SIZEY) && isLuma(COMPONENT_Y) + ? currPU.multiRefIdx + : false; + if (tempPDPC) + { + featureCounter.intraPDPCBlockSizes[puWidthIdx][puHeightIdx]++; + featureCounter.intraLumaPDPCBlockSizes[puWidthIdx][puHeightIdx]++; + } + } + } + + if (currCU.ispMode > NOT_INTRA_SUBPARTITIONS) + { + if (currCU.ispMode == VER_INTRA_SUBPARTITIONS) + { + featureCounter.intraSubPartitionsVertical[cuWidthIdx][cuHeightIdx]++; + featureCounter.intraLumaSubPartitionsVertical[cuWidthIdx][cuHeightIdx]++; + } + if (currCU.ispMode == HOR_INTRA_SUBPARTITIONS) + { + featureCounter.intraSubPartitionsHorizontal[cuWidthIdx][cuHeightIdx]++; + featureCounter.intraLumaSubPartitionsHorizontal[cuWidthIdx][cuHeightIdx]++; + } + } + } + else if (currCU.predMode == MODE_IBC) // IBC-Mode + { + featureCounter.IBCBlockSizes[cuWidthIdx][cuHeightIdx]++; + featureCounter.IBCLumaBlockSizes[cuWidthIdx][cuHeightIdx]++; + } + else if (currCU.predMode == MODE_INTER) // Inter-Mode + { + featureCounter.interBlockSizes[cuWidthIdx][cuHeightIdx]++; + featureCounter.interLumaBlockSizes[cuWidthIdx][cuHeightIdx]++; + featureCounter.interBlockSizes[cuWidthIdx-1][cuHeightIdx-1] += 2; + featureCounter.interChromaBlockSizes[cuWidthIdx-1][cuHeightIdx-1] += 2; + if (currCU.skip) + { + featureCounter.interSkipBlocks[cuWidthIdx][cuHeightIdx]++; + featureCounter.interLumaSkipBlocks[cuWidthIdx][cuHeightIdx]++; + featureCounter.interSkipBlocks[cuWidthIdx-1][cuHeightIdx-1] += 2; + featureCounter.interChromaSkipBlocks[cuWidthIdx-1][cuHeightIdx-1] += 2; + if (currCU.affine) + { + featureCounter.affine[cuWidthIdx][cuHeightIdx]++; + featureCounter.affineLuma[cuWidthIdx][cuHeightIdx]++; + featureCounter.affineSkip[cuWidthIdx][cuHeightIdx]++; + featureCounter.affineLumaSkip[cuWidthIdx][cuHeightIdx]++; + featureCounter.affine[cuWidthIdx-1][cuHeightIdx-1] += 2; + featureCounter.affineChroma[cuWidthIdx-1][cuHeightIdx-1] += 2; + featureCounter.affineSkip[cuWidthIdx-1][cuHeightIdx-1] += 2; + featureCounter.affineChromaSkip[cuWidthIdx-1][cuHeightIdx-1] += 2; + } + } + else + { + for (auto &currPU: CU::traversePUs(currCU)) + { + SizeType puWidthIdx = floorLog2(currPU.lwidth()); + SizeType puHeightIdx = floorLog2(currPU.lheight()); + if ((puWidthIdx <= MAX_CU_DEPTH+1) && (puHeightIdx <= MAX_CU_DEPTH+1)) + { + if (currPU.mergeFlag) + { + featureCounter.interMergeBlocks[puWidthIdx][puHeightIdx]++; + featureCounter.interLumaMergeBlocks[puWidthIdx][puHeightIdx]++; + featureCounter.interMergeBlocks[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.interChromaMergeBlocks[puWidthIdx-1][puHeightIdx-1] += 2; + if (currCU.affine) + { + featureCounter.affine[puWidthIdx][puHeightIdx]++; + featureCounter.affineLuma[puWidthIdx][puHeightIdx]++; + featureCounter.affineMerge[puWidthIdx][puHeightIdx]++; + featureCounter.affineLumaMerge[puWidthIdx][puHeightIdx]++; + featureCounter.affine[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.affineChroma[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.affineMerge[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.affineChromaMerge[puWidthIdx-1][puHeightIdx-1] += 2; + } + } + else // InterInter + { + featureCounter.interInterBlocks[puWidthIdx][puHeightIdx]++; + featureCounter.interLumaInterBlocks[puWidthIdx][puHeightIdx]++; + featureCounter.interInterBlocks[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.interChromaInterBlocks[puWidthIdx-1][puHeightIdx-1] += 2; + if (currCU.affine) + { + featureCounter.affine[puWidthIdx][puHeightIdx]++; + featureCounter.affineLuma[puWidthIdx][puHeightIdx]++; + featureCounter.affineInter[puWidthIdx][puHeightIdx]++; + featureCounter.affineLumaInter[puWidthIdx][puHeightIdx]++; + featureCounter.affine[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.affineChroma[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.affineInter[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.affineChromaInter[puWidthIdx-1][puHeightIdx-1] += 2; + } + } + if (currPU.cu->geoFlag) + { + featureCounter.geo[puWidthIdx][puHeightIdx]++; + featureCounter.geoLuma[puWidthIdx][puHeightIdx]++; + featureCounter.geo[puWidthIdx-1][puHeightIdx-1] += 2; + featureCounter.geoChroma[puWidthIdx-1][puHeightIdx-1] += 2; + } + } + } + } + + + + for (auto &currPU: CU::traversePUs(currCU)) // Check whether BDOF or DMVR are used in the current PU + { + bool m_DMVRapplied = false; + bool m_BDOFapplied = false; + + PredictionUnit &pu = currPU; + SizeType puWidthIdx = floorLog2(currPU.lwidth()); + SizeType puHeightIdx = floorLog2(currPU.lheight()); + if ((puWidthIdx <= MAX_CU_DEPTH + 1) && (puHeightIdx <= MAX_CU_DEPTH + 1)) + { + const PPS &pps = *pu.cs->pps; + const Slice &localSlice = *pu.cs->slice; + CHECK(!pu.cu->affine && pu.refIdx[0] >= 0 && pu.refIdx[1] >= 0 && (pu.lwidth() + pu.lheight() == 12), + "invalid 4x8/8x4 bi-predicted blocks"); + + int refIdx0 = pu.refIdx[REF_PIC_LIST_0]; + int refIdx1 = pu.refIdx[REF_PIC_LIST_1]; + + const WPScalingParam *wp0 = pu.cs->slice->getWpScaling(REF_PIC_LIST_0, refIdx0); + const WPScalingParam *wp1 = pu.cs->slice->getWpScaling(REF_PIC_LIST_1, refIdx1); + + bool bioApplied = false; + if (pu.cs->sps->getBDOFEnabledFlag() && (!pu.cs->picHeader->getBdofDisabledFlag())) + { + if (pu.cu->affine) + { + bioApplied = false; + } + else + { + const bool biocheck0 = !((WPScalingParam::isWeighted(wp0) || WPScalingParam::isWeighted(wp1)) + && localSlice.getSliceType() == B_SLICE); + const bool biocheck1 = !(pps.getUseWP() && localSlice.getSliceType() == P_SLICE); + if (biocheck0 && biocheck1 && PU::isSimpleSymmetricBiPred(pu) && (pu.Y().height >= 8) + && (pu.Y().width >= 8) && ((pu.Y().height * pu.Y().width) >= 128)) + { + bioApplied = true; + } + } + + if (bioApplied && pu.ciipFlag) + { + bioApplied = false; + } + + if (bioApplied && pu.cu->smvdMode) + { + bioApplied = false; + } + + if (pu.cu->cs->sps->getUseBcw() && bioApplied && pu.cu->bcwIdx != BCW_DEFAULT) + { + bioApplied = false; + } + } + if (pu.mmvdEncOptMode == 2 && pu.mmvdMergeFlag) + { + bioApplied = false; + } + bool dmvrApplied = false; + dmvrApplied = PU::checkDMVRCondition(pu); + + bool refIsScaled = + (refIdx0 < 0 ? false : pu.cu->slice->getRefPic(REF_PIC_LIST_0, refIdx0)->isRefScaled(pu.cs->pps)) + || (refIdx1 < 0 ? false : pu.cu->slice->getRefPic(REF_PIC_LIST_1, refIdx1)->isRefScaled(pu.cs->pps)); + dmvrApplied = dmvrApplied && !refIsScaled; + bioApplied = bioApplied && !refIsScaled; + + for (uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++) + { + if (pu.refIdx[refList] < 0) + { + continue; + } + + RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0); + + CHECK(CU::isIBC(*pu.cu) && eRefPicList != REF_PIC_LIST_0, "Invalid interdir for ibc mode"); + CHECK(CU::isIBC(*pu.cu) && pu.refIdx[refList] != MAX_NUM_REF, "Invalid reference index for ibc mode"); + CHECK((CU::isInter(*pu.cu) && pu.refIdx[refList] >= localSlice.getNumRefIdx(eRefPicList)), + "Invalid reference index"); + } + + m_BDOFapplied = bioApplied; + + if (!pu.cu->geoFlag && (!dmvrApplied) && (!bioApplied) && pps.getWPBiPred() + && localSlice.getSliceType() == B_SLICE && pu.cu->bcwIdx == BCW_DEFAULT) + { + m_DMVRapplied = false; + } + else if (!pu.cu->geoFlag && pps.getUseWP() && localSlice.getSliceType() == P_SLICE) + { + m_DMVRapplied = false; + } + else + { + m_DMVRapplied = dmvrApplied; + } + + if (m_DMVRapplied) + { + featureCounter.dmvrBlocks[puWidthIdx][puHeightIdx]++; + } + + if (m_BDOFapplied) + { + featureCounter.bdofBlocks[puWidthIdx][puHeightIdx]++; + } + } + } + } + + if (currCU.predMode == MODE_INTER) + { + const int nShift = MV_FRACTIONAL_BITS_DIFF; + const int nOffset = 1 << (nShift - 1); + + for (auto &currPU: CU::traversePUs(currCU)) + { + int numberOfPels = currPU.lwidth() * currPU.lheight(); + if (!currPU.cu->affine && !currPU.cu->geoFlag) + { + if (currPU.interDir != MODE_TYPE_INTRA /* PRED_L1 */) + { + Mv mv = currPU.mv[REF_PIC_LIST_0]; + Mv mvd = currPU.mvd[REF_PIC_LIST_0]; + mv.hor = mv.hor >= 0 ? (mv.hor + nOffset) >> nShift : -((-mv.hor + nOffset) >> nShift); + mv.ver = mv.ver >= 0 ? (mv.ver + nOffset) >> nShift : -((-mv.ver + nOffset) >> nShift); + mvd.hor = mvd.hor >= 0 ? (mvd.hor + nOffset) >> nShift : -((-mvd.hor + nOffset) >> nShift); + mvd.ver = mvd.ver >= 0 ? (mvd.ver + nOffset) >> nShift : -((-mvd.ver + nOffset) >> nShift); + + if (currPU.interDir == 3) + { + featureCounter.biPredPel += numberOfPels; + } + else + { + featureCounter.uniPredPel += numberOfPels; + } + + if (mv.hor == 0 && mv.ver == 0) + { + featureCounter.copyCUPel += numberOfPels; + } + if (mv.hor != 0 && mv.ver == 0) + { + featureCounter.fracPelHor += numberOfPels; + } + if (mv.hor == 0 && mv.ver != 0) + { + featureCounter.fracPelVer += numberOfPels; + } + if (mv.hor != 0 && mv.ver != 0) + { + featureCounter.fracPelBoth += numberOfPels; + } + } + if (currPU.interDir != 1 /* PRED_L1 */) + { + Mv mv = currPU.mv[REF_PIC_LIST_1]; + Mv mvd = currPU.mvd[REF_PIC_LIST_1]; + mv.hor = mv.hor >= 0 ? (mv.hor + nOffset) >> nShift : -((-mv.hor + nOffset) >> nShift); + mv.ver = mv.ver >= 0 ? (mv.ver + nOffset) >> nShift : -((-mv.ver + nOffset) >> nShift); + mvd.hor = mvd.hor >= 0 ? (mvd.hor + nOffset) >> nShift : -((-mvd.hor + nOffset) >> nShift); + mvd.ver = mvd.ver >= 0 ? (mvd.ver + nOffset) >> nShift : -((-mvd.ver + nOffset) >> nShift); + + if (currPU.interDir != 3) + { + featureCounter.uniPredPel += numberOfPels; + } + + if (mv.hor == 0 && mv.ver == 0) + { + featureCounter.copyCUPel += numberOfPels; + } + if (mv.hor != 0 && mv.ver == 0) + { + featureCounter.fracPelHor += numberOfPels; + } + if (mv.hor == 0 && mv.ver != 0) + { + featureCounter.fracPelVer += numberOfPels; + } + if (mv.hor != 0 && mv.ver != 0) + { + featureCounter.fracPelBoth += numberOfPels; + } + } + } + else if (currPU.cu->affine) + { + if (currPU.interDir != 2 /* PRED_L1 */) + { + Mv mv[3]; + const CMotionBuf &mb = currPU.getMotionBuf(); + mv[0] = mb.at(0, 0).mv[REF_PIC_LIST_0]; + mv[1] = mb.at(mb.width - 1, 0).mv[REF_PIC_LIST_0]; + mv[2] = mb.at(0, mb.height - 1).mv[REF_PIC_LIST_0]; + mv[0].hor = mv[0].hor >= 0 ? (mv[0].hor + nOffset) >> nShift : -((-mv[0].hor + nOffset) >> nShift); + mv[0].ver = mv[0].ver >= 0 ? (mv[0].ver + nOffset) >> nShift : -((-mv[0].ver + nOffset) >> nShift); + mv[1].hor = mv[1].hor >= 0 ? (mv[1].hor + nOffset) >> nShift : -((-mv[1].hor + nOffset) >> nShift); + mv[1].ver = mv[1].ver >= 0 ? (mv[1].ver + nOffset) >> nShift : -((-mv[1].ver + nOffset) >> nShift); + mv[2].hor = mv[2].hor >= 0 ? (mv[2].hor + nOffset) >> nShift : -((-mv[2].hor + nOffset) >> nShift); + mv[2].ver = mv[2].ver >= 0 ? (mv[2].ver + nOffset) >> nShift : -((-mv[2].ver + nOffset) >> nShift); + + if (currPU.interDir == 3) + { + featureCounter.biPredPel += numberOfPels; + } + else + { + featureCounter.uniPredPel += numberOfPels; + } + + for (int iter = 0; iter < 3; iter++) + { + if (mv[iter].hor == 0 && mv[iter].ver == 0) + { + featureCounter.affineCopyCUPel += numberOfPels; + } + if (mv[iter].hor != 0 && mv[iter].ver == 0) + { + featureCounter.affineFracPelHor += numberOfPels; + } + if (mv[iter].hor == 0 && mv[iter].ver != 0) + { + featureCounter.affineFracPelVer += numberOfPels; + } + if (mv[iter].hor != 0 && mv[iter].ver != 0) + { + featureCounter.affineFracPelBoth += numberOfPels; + } + } + } + if (currPU.interDir != 1 /* PRED_L1 */) + { + Mv mv[3]; + const CMotionBuf &mb = currPU.getMotionBuf(); + mv[0] = mb.at(0, 0).mv[REF_PIC_LIST_1]; + mv[1] = mb.at(mb.width - 1, 0).mv[REF_PIC_LIST_1]; + mv[2] = mb.at(0, mb.height - 1).mv[REF_PIC_LIST_1]; + + mv[0].hor = mv[0].hor >= 0 ? (mv[0].hor + nOffset) >> nShift : -((-mv[0].hor + nOffset) >> nShift); + mv[0].ver = mv[0].ver >= 0 ? (mv[0].ver + nOffset) >> nShift : -((-mv[0].ver + nOffset) >> nShift); + mv[1].hor = mv[1].hor >= 0 ? (mv[1].hor + nOffset) >> nShift : -((-mv[1].hor + nOffset) >> nShift); + mv[1].ver = mv[1].ver >= 0 ? (mv[1].ver + nOffset) >> nShift : -((-mv[1].ver + nOffset) >> nShift); + mv[2].hor = mv[2].hor >= 0 ? (mv[2].hor + nOffset) >> nShift : -((-mv[2].hor + nOffset) >> nShift); + mv[2].ver = mv[2].ver >= 0 ? (mv[2].ver + nOffset) >> nShift : -((-mv[2].ver + nOffset) >> nShift); + + if (currPU.interDir != 3) + { + featureCounter.uniPredPel += numberOfPels; + } + + for (int iter = 0; iter < 3; iter++) + { + if (mv[iter].hor == 0 && mv[iter].ver == 0) + { + featureCounter.affineCopyCUPel += numberOfPels; + } + if (mv[iter].hor != 0 && mv[iter].ver == 0) + { + featureCounter.affineFracPelHor += numberOfPels; + } + if (mv[iter].hor == 0 && mv[iter].ver != 0) + { + featureCounter.affineFracPelVer += numberOfPels; + } + if (mv[iter].hor != 0 && mv[iter].ver != 0) + { + featureCounter.affineFracPelBoth += numberOfPels; + } + } + } + } + } + } + + for (auto &currTU: CU::traverseTUs(currCU)) + { + bool m_notOnCounterGridWidth = false; + bool m_notOnCounterGridHeight = false; + SizeType currTUWIdx = MAX_UINT; + SizeType currTUHIdx = MAX_UINT; + currTUWIdx = floorLog2(currTU.Y().width); + currTUHIdx = floorLog2(currTU.Y().height); + if ((currTUWIdx <= MAX_CU_DEPTH + 1) && (currTUHIdx <= MAX_CU_DEPTH + 1)) + { + if (currTU.Y().width != int(pow(2, currTUWIdx))) + { + m_notOnCounterGridWidth = true; + } + + if (currTU.Y().height != int(pow(2, currTUHIdx))) + { + m_notOnCounterGridHeight = true; + } + + if (currTU.cu->skip) + { + featureCounter.transformSkipBlocks[currTUWIdx][currTUHIdx]++; + featureCounter.transformLumaSkipBlocks[currTUWIdx][currTUHIdx]++; + if (m_notOnCounterGridHeight || m_notOnCounterGridWidth) + { + if (m_notOnCounterGridHeight) + { + featureCounter.transformSkipBlocks[currTUWIdx][currTUHIdx - 1]++; + featureCounter.transformLumaSkipBlocks[currTUWIdx][currTUHIdx - 1]++; + } + + if (m_notOnCounterGridWidth) + { + featureCounter.transformSkipBlocks[currTUWIdx - 1][currTUHIdx]++; + featureCounter.transformLumaSkipBlocks[currTUWIdx - 1][currTUHIdx]++; + } + } + } + else + { + featureCounter.transformBlocks[currTUWIdx][currTUHIdx]++; + featureCounter.transformLumaBlocks[currTUWIdx][currTUHIdx]++; + if (m_notOnCounterGridHeight || m_notOnCounterGridWidth) + { + if (m_notOnCounterGridHeight) + { + featureCounter.transformBlocks[currTUWIdx][currTUHIdx - 1]++; + featureCounter.transformLumaBlocks[currTUWIdx][currTUHIdx - 1]++; + } + + if (m_notOnCounterGridWidth) + { + featureCounter.transformBlocks[currTUWIdx - 1][currTUHIdx]++; + featureCounter.transformLumaBlocks[currTUWIdx - 1][currTUHIdx]++; + } + } + } + + if (currTU.cu->lfnstIdx && currTU.mtsIdx[COMPONENT_Y] != MTS_SKIP + && (currTU.cu->isSepTree() ? true : isLuma(COMPONENT_Y))) + { + bool significantCoeff = false; + for (int bufferScan = 0; bufferScan < currTU.lwidth() * currTU.lheight() && !significantCoeff; bufferScan++) + { + if (currTU.getCoeffs(ComponentID(0)).buf[bufferScan] != 0) + { + significantCoeff = true; + } + } + + if (significantCoeff) + { + if (currTU.Y().width >= 8 && currTU.Y().height >= 8) + { + featureCounter.transformLFNST8++; + } + else + { + featureCounter.transformLFNST4++; + } + } + } + + int maxNumberOfCoeffs = 0; + + maxNumberOfCoeffs = currTU.Y().width * currTU.Y().height; + if (currTU.cbf[COMPONENT_Y] == 0) + { + maxNumberOfCoeffs = 0; + } + + for (int i = 0; i < maxNumberOfCoeffs; i++) + { + int counterCoeff = currTU.getCoeffs(COMPONENT_Y).buf[i]; + if (counterCoeff != 0) + { + featureCounter.nrOfCoeff++; + + if (counterCoeff < 0) + { + counterCoeff *= -1; + } + + if (counterCoeff > 1) + { + featureCounter.coeffG1++; + } + + counterCoeff--; // taking account of the fact that n_coeffg1 has already been counted + double ldVal = counterCoeff < 2 ? 0.0 + : floorLog2(counterCoeff) + + (2 * counterCoeff >= (3 << floorLog2(counterCoeff)) ? 0.585 : 0.0); + featureCounter.valueOfCoeff += ldVal; + } + } + } + } + } + } + + for (auto &currCU: cs.traverseCUs(ctuArea, CHANNEL_TYPE_CHROMA)) + { + SizeType cuCbWidthIdx = floorLog2(currCU.Cb().width); + SizeType cuCbHeightIdx = floorLog2(currCU.Cb().height); + SizeType cuCrWidthIdx = floorLog2(currCU.Cr().width); + SizeType cuCrHeightIdx = floorLog2(currCU.Cr().height); + + if ((cuCbWidthIdx <= MAX_CU_DEPTH+1) && (cuCbHeightIdx <= MAX_CU_DEPTH+1) && (cuCrWidthIdx <= MAX_CU_DEPTH+1) && (cuCrHeightIdx <= MAX_CU_DEPTH+1)) + { + if (currCU.predMode == MODE_INTRA) // Intra-Mode + { + for (auto &currPU: CU::traversePUs(currCU)) + { + SizeType chromaWidthIdx = floorLog2(currPU.Cb().width); + SizeType chromaHeightIdx = floorLog2(currPU.Cb().height); + if ((chromaWidthIdx <= MAX_CU_DEPTH+1) && (chromaHeightIdx <= MAX_CU_DEPTH+1)) + { + featureCounter.intraBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + SizeType chromaPredDir = currPU.intraDir[CHANNEL_TYPE_CHROMA]; + // Intra Prediction Direction + if (currCU.mipFlag) + { + featureCounter.intraMIPBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + featureCounter.intraChromaMIPBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + else + { + if (chromaPredDir == PLANAR_IDX) + { + featureCounter.intraChromaPlaBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + else if (chromaPredDir == DC_IDX) + { + featureCounter.intraChromaDcBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + else if (chromaPredDir == HOR_IDX || chromaPredDir == VER_IDX || chromaPredDir == DIA_IDX) + { + featureCounter.intraChromaHvdBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + else if (chromaPredDir < LM_CHROMA_IDX) + { + featureCounter.intraChromaAngBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + + if (PU::isLMCMode(chromaPredDir)) + { + featureCounter.intraChromaCrossCompBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + } + + bool tempPDPC = + (currPU.Cb().width >= MIN_TB_SIZEY && currPU.Cb().height >= MIN_TB_SIZEY) && isLuma(COMPONENT_Cb) + ? currPU.multiRefIdx + : false; + if (tempPDPC) + { + featureCounter.intraPDPCBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + featureCounter.intraChromaPDPCBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + } + } + + if (currCU.ispMode > NOT_INTRA_SUBPARTITIONS) + { + if (currCU.ispMode == VER_INTRA_SUBPARTITIONS) + { + featureCounter.intraSubPartitionsVertical[cuCbWidthIdx][cuCbHeightIdx]++; + featureCounter.intraChromaSubPartitionsVertical[cuCbWidthIdx][cuCbHeightIdx]++; + } + if (currCU.ispMode == HOR_INTRA_SUBPARTITIONS) + { + featureCounter.intraSubPartitionsHorizontal[cuCbWidthIdx][cuCbHeightIdx]++; + featureCounter.intraChromaSubPartitionsHorizontal[cuCbWidthIdx][cuCbHeightIdx]++; + } + } + } + + if (currCU.predMode == MODE_INTRA) // Intra-Mode + { + for (auto &currPU: CU::traversePUs(currCU)) + { + SizeType chromaWidthIdx = floorLog2(currPU.Cr().width); + SizeType chromaHeightIdx = floorLog2(currPU.Cr().height); + featureCounter.intraBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + SizeType chromaPredDir = currPU.intraDir[CHANNEL_TYPE_CHROMA]; + if ((chromaWidthIdx <= MAX_CU_DEPTH + 1) && (chromaHeightIdx <= MAX_CU_DEPTH + 1)) + { + if (currCU.mipFlag) + { + featureCounter.intraMIPBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + featureCounter.intraChromaMIPBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + else + { + if (chromaPredDir == PLANAR_IDX) + { + featureCounter.intraChromaPlaBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + else if (chromaPredDir == DC_IDX) + { + featureCounter.intraChromaDcBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + else if (chromaPredDir == HOR_IDX || chromaPredDir == VER_IDX || chromaPredDir == DIA_IDX) + { + featureCounter.intraChromaHvdBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + else if (chromaPredDir < NUM_CHROMA_MODE) + { + featureCounter.intraChromaAngBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + + if (PU::isLMCMode(chromaPredDir)) + { + featureCounter.intraChromaCrossCompBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + } + bool tempPDPC = + (currPU.Cr().width >= MIN_TB_SIZEY && currPU.Cr().height >= MIN_TB_SIZEY) && isLuma(COMPONENT_Cr) + ? currPU.multiRefIdx + : false; + if (tempPDPC) + { + featureCounter.intraPDPCBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + featureCounter.intraChromaPDPCBlockSizes[chromaWidthIdx][chromaHeightIdx]++; + } + } + } + + if (currCU.ispMode > NOT_INTRA_SUBPARTITIONS) + { + if (currCU.ispMode == VER_INTRA_SUBPARTITIONS) + { + featureCounter.intraSubPartitionsVertical[cuCrWidthIdx][cuCrHeightIdx]++; + featureCounter.intraChromaSubPartitionsVertical[cuCrWidthIdx][cuCrHeightIdx]++; + } + if (currCU.ispMode == HOR_INTRA_SUBPARTITIONS) + { + featureCounter.intraSubPartitionsHorizontal[cuCrWidthIdx][cuCrHeightIdx]++; + featureCounter.intraSubPartitionsHorizontal[cuCrWidthIdx][cuCrHeightIdx]++; + } + } + } + + + for (auto &currTU: CU::traverseTUs(currCU)) + { + for (int m_compID = 1; m_compID < getNumberValidComponents(currTU.chromaFormat); m_compID++) + { + bool m_notOnCounterGridWidth = false; + bool m_notOnCounterGridHeight = false; + SizeType currTUWIdx = MAX_UINT; + SizeType currTUHIdx = MAX_UINT; + if ((currTUWIdx <= MAX_CU_DEPTH+1) && (currTUHIdx <= MAX_CU_DEPTH+1)) + { + if (m_compID == COMPONENT_Cb) + { + currTUWIdx = floorLog2(currTU.Cb().width); + currTUHIdx = floorLog2(currTU.Cb().height); + if (currTU.Cb().width != int(pow(2, currTUWIdx))) + { + m_notOnCounterGridWidth = true; + } + + if (currTU.Cb().height != int(pow(2, currTUHIdx))) + { + m_notOnCounterGridHeight = true; + } + } + else + { + currTUWIdx = floorLog2(currTU.Cr().width); + currTUHIdx = floorLog2(currTU.Cr().height); + if (currTU.Cr().width != int(pow(2, currTUWIdx))) + { + m_notOnCounterGridWidth = true; + } + + if (currTU.Cr().height != int(pow(2, currTUHIdx))) + { + m_notOnCounterGridHeight = true; + } + } + + if (currTU.cu->skip) + { + featureCounter.transformSkipBlocks[currTUWIdx][currTUHIdx]++; + featureCounter.transformChromaSkipBlocks[currTUWIdx][currTUHIdx]++; + if (m_notOnCounterGridHeight || m_notOnCounterGridWidth) + { + if (m_notOnCounterGridHeight) + { + featureCounter.transformSkipBlocks[currTUWIdx][currTUHIdx - 1]++; + featureCounter.transformChromaSkipBlocks[currTUWIdx][currTUHIdx - 1]++; + } + + if (m_notOnCounterGridWidth) + { + featureCounter.transformSkipBlocks[currTUWIdx - 1][currTUHIdx]++; + featureCounter.transformChromaSkipBlocks[currTUWIdx - 1][currTUHIdx]++; + } + } + } + else + { + featureCounter.transformBlocks[currTUWIdx][currTUHIdx]++; + featureCounter.transformChromaBlocks[currTUWIdx][currTUHIdx]++; + if (m_notOnCounterGridHeight || m_notOnCounterGridWidth) + { + if (m_notOnCounterGridHeight) + { + featureCounter.transformBlocks[currTUWIdx][currTUHIdx - 1]++; + featureCounter.transformChromaBlocks[currTUWIdx][currTUHIdx - 1]++; + } + + if (m_notOnCounterGridWidth) + { + featureCounter.transformBlocks[currTUWIdx - 1][currTUHIdx]++; + featureCounter.transformChromaBlocks[currTUWIdx - 1][currTUHIdx]++; + } + } + } + + if (currTU.cu->lfnstIdx && currTU.mtsIdx[m_compID] != MTS_SKIP + && (currTU.cu->isSepTree() ? true : isLuma(COMPONENT_Cr))) + { + bool significantCoeff = false; + if (m_compID == COMPONENT_Cb) + { + for (int bufferScan = 0; + bufferScan < currTU.Cb().width * currTU.Cb().height && significantCoeff == false; bufferScan++) + { + if (currTU.getCoeffs(ComponentID(m_compID)).buf[bufferScan] != 0) + { + significantCoeff = true; + } + } + } + else + { + for (int bufferScan = 0; + bufferScan < currTU.Cr().width * currTU.Cr().height && significantCoeff == false; bufferScan++) + { + if (currTU.getCoeffs(ComponentID(m_compID)).buf[bufferScan] != 0) + { + significantCoeff = true; + } + } + } + + if (significantCoeff) + { + if (currTU.Cb().width >= 8 && currTU.Cb().height >= 8) + { + featureCounter.transformLFNST8++; + } + else + { + featureCounter.transformLFNST4++; + } + } + } + + int maxNumberOfCoeffs = 0; + if (m_compID == COMPONENT_Y) + { + maxNumberOfCoeffs = currTU.Y().width * currTU.Y().height; + if (currTU.cbf[COMPONENT_Y] == 0) + { + maxNumberOfCoeffs = 0; + } + } + else if (m_compID == COMPONENT_Cb) + { + maxNumberOfCoeffs = currTU.Cb().width * currTU.Cb().height; + if (currTU.cbf[COMPONENT_Cb] == 0) + { + maxNumberOfCoeffs = 0; + } + } + else + { + maxNumberOfCoeffs = currTU.Cr().width * currTU.Cr().height; + if (currTU.cbf[COMPONENT_Cr] == 0) + { + maxNumberOfCoeffs = 0; + } + } + + for (int i = 0; i < maxNumberOfCoeffs; i++) + { + int counterCoeff = currTU.getCoeffs((ComponentID) m_compID).buf[i]; + + if (counterCoeff != 0) + { + featureCounter.nrOfCoeff++; + + if (counterCoeff < 0) // abs val + { + counterCoeff *= -1; + } + + if (counterCoeff > 1) + { + featureCounter.coeffG1++; + } + + counterCoeff--; // taking account of the fact that n_coeffg1 has already been counted + double ldVal = + counterCoeff < 2 + ? 0.0 + : floorLog2(counterCoeff) + (2 * counterCoeff >= (3 << floorLog2(counterCoeff)) ? 0.585 : 0.0); + featureCounter.valueOfCoeff += ldVal; + } + } + } + } + } + } + } +} +#endif diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 2b34156aa11e39361fb889238967615ae3f0e17f..6bb72a5d4caa8bd34bc0dae20a913a3e7b4348ac 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -231,7 +231,11 @@ uint32_t getCtuAddr (const Position& pos, const PreCalcValues &pcv); int getNumModesMip (const Size& block); int getMipSizeId (const Size& block); bool allowLfnstWithMip(const Size& block); - +#ifdef GREEN_METADATA_SEI_ENABLED +void writeGMFAOutput(FeatureCounterStruct& featureCounter, FeatureCounterStruct& featureCounterReference, std::string GMFAFile, bool lastFrame); +void featureToFile(std::ofstream& featureFile,int featureCounterReference[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1], std::string featureName,bool calcDifference=false,int featureCounter[MAX_CU_DEPTH+1][MAX_CU_DEPTH+1]=NULL); +void countFeatures (FeatureCounterStruct& featureCounterStruct, CodingStructure& cs, const UnitArea& ctuArea); +#endif template<typename T, size_t N> uint32_t updateCandList(T mode, double uiCost, static_vector<T, N> &candModeList, static_vector<double, N> &candCostList, size_t uiFastCandNum = N, int *iserttPos = nullptr) diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 25ccc032f08f4889e1f0f4338a40570d764e0055..8a29bcde60561cba8c083e59a92700cf3e611594 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -686,6 +686,10 @@ void DecLib::executeLoopFilters() m_cReshaper.setRecReshaped(false); m_cSAO.setReshaper(&m_cReshaper); } +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct initValues; + cs.m_featureCounter = initValues; +#endif // deblocking filter m_deblockingFilter.deblockingFilterPic( cs ); CS::setRefinedMotionField(cs); @@ -703,6 +707,11 @@ void DecLib::executeLoopFilters() m_cALF.ALFProcess(cs); } +#ifdef GREEN_METADATA_SEI_ENABLED + m_featureCounter.addSAO(cs.m_featureCounter); + m_featureCounter.addALF(cs.m_featureCounter); + m_featureCounter.addBoundaryStrengths(cs.m_featureCounter); +#endif for (int i = 0; i < cs.pps->getNumSubPics() && m_targetSubPicIdx; i++) { // keep target subpic samples untouched, for other subpics mask their output sample value to 0 @@ -781,7 +790,11 @@ void DecLib::finishPicture(int &poc, PicList *&rpcListPic, MsgLevel msgl, bool a Slice* pcSlice = m_pcPic->cs->slice; m_prevPicPOC = pcSlice->getPOC(); - +#ifdef GREEN_METADATA_SEI_ENABLED + m_featureCounter.height = m_pcPic->Y().height; + m_featureCounter.width = m_pcPic->Y().width; +#endif + char c = (pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B'); if (!m_pcPic->referenced) { @@ -3421,9 +3434,15 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl } } #endif // GDR_LEAK_TEST +#ifdef GREEN_METADATA_SEI_ENABLED + pcSlice->setFeatureCounter(this->m_featureCounter); +#endif // Decode a picture m_cSliceDecoder.decompressSlice( pcSlice, &( nalu.getBitstream() ), ( m_pcPic->poc == getDebugPOC() ? getDebugCTU() : -1 ) ); - +#ifdef GREEN_METADATA_SEI_ENABLED + this->m_featureCounter = pcSlice->getFeatureCounter(); +#endif + m_bFirstSliceInPicture = false; m_uiSliceSegmentIdx++; diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index c198ab0bdb33dce84701f291bed4334fd9ba3b17..948b62240a0c512b0d3b1c22fccc3800e161a389 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -321,12 +321,22 @@ public: const OPI* getOPI() { return m_opi; } bool getMixedNaluTypesInPicFlag(); +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter; + bool m_GMFAFramewise; + std::string m_GMFAFile; + void setFeatureCounter (FeatureCounterStruct b ) {m_featureCounter = b;} + FeatureCounterStruct getFeatureCounter (){return m_featureCounter;} + void setGMFAFile(std::string b){m_GMFAFile = b;} + void setFeatureAnalysisFramewise(bool b){m_GMFAFramewise = b;} +#endif #if JVET_Z0120_SII_SEI_PROCESSING bool getShutterFilterFlag() const { return m_ShutterFilterEnable; } void setShutterFilterFlag(bool value) { m_ShutterFilterEnable = value; } #endif + protected: void xUpdateRasInit(Slice* slice); diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index 753f6dcdabbcbd8b2d3cf2fd6fe485bf25ebc0aa..498413832c4d2ea23c6dc069567e24ce78c302a0 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -232,7 +232,12 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb cabacReader.coding_tree_unit( cs, ctuArea, pic->m_prevQP, ctuRsAddr ); m_pcCuDecoder->decompressCtu( cs, ctuArea ); - +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct featureCounter = slice->getFeatureCounter(); + countFeatures( featureCounter, cs,ctuArea); + slice->setFeatureCounter(featureCounter); +#endif + if( ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled ) { m_entropyCodingSyncContextState = cabacReader.getCtx(); @@ -285,7 +290,40 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb } } } - + +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct featureCounter = slice->getFeatureCounter(); + featureCounter.baseQP[slice->getSliceQpBase()] ++; + if (featureCounter.isYUV400 == -1) + { + featureCounter.isYUV400 = sps->getChromaFormatIdc() == CHROMA_400 ? 1 : 0; + featureCounter.isYUV420 = sps->getChromaFormatIdc() == CHROMA_420 ? 1 : 0; + featureCounter.isYUV422 = sps->getChromaFormatIdc() == CHROMA_422 ? 1 : 0; + featureCounter.isYUV444 = sps->getChromaFormatIdc() == CHROMA_444 ? 1 : 0; + } + + if (featureCounter.is8bit == -1) + { + featureCounter.is8bit = (sps->getBitDepth(CHANNEL_TYPE_LUMA) == 8) ? 1 : 0; + featureCounter.is10bit = (sps->getBitDepth(CHANNEL_TYPE_LUMA) == 10) ? 1 : 0; + featureCounter.is12bit = (sps->getBitDepth(CHANNEL_TYPE_LUMA) == 12) ? 1 : 0; + } + + if (slice->getSliceType() == B_SLICE) + { + featureCounter.bSlices++; + } + else if (slice->getSliceType() == P_SLICE) + { + featureCounter.pSlices++; + } + else + { + featureCounter.iSlices++; + } + slice->setFeatureCounter(featureCounter); +#endif + // deallocate all created substreams, including internal buffers. for( auto substr: ppcSubstreams ) { diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp index 43289b8b154b1f108fdc25e86c2d5de4d263dffb..8257f3b56faf31e43f4326b77e13751b5f9c7009 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp @@ -3235,6 +3235,10 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB coeff = m_fixedFilterSetCoeffDec[filterSetIndex]; clip = m_clipDefault; } +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfLumaType7+= (width * height / 16) ; + cs.m_featureCounter.alfLumaPels += (width * height); +#endif m_filter7x7Blk(m_classifier, recBuf, buf, blkDst, blkSrc, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, m_alfVBLumaCTUHeight, m_alfVBLumaPos); } @@ -3252,6 +3256,10 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB m_filter5x5Blk(m_classifier, recBuf, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_alfVBChmaCTUHeight, m_alfVBChmaPos); +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfChromaType5+= ((width >> chromaScaleX) * (height >> chromaScaleY) / 16); + cs.m_featureCounter.alfChromaPels += ((width >> chromaScaleX) * (height >> chromaScaleY)) ; +#endif } } @@ -3282,6 +3290,10 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB } m_filter7x7Blk(m_classifier, recBuf, recExtBuf, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, m_alfVBLumaCTUHeight, m_alfVBLumaPos); +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfLumaType7+= (width * height / 16) ; + cs.m_featureCounter.alfLumaPels += (width * height); +#endif } for (int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++) @@ -3296,6 +3308,10 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB m_filter5x5Blk(m_classifier, recBuf, recExtBuf, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_alfVBChmaCTUHeight, m_alfVBChmaPos); +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.alfChromaType5+= ((width >> chromaScaleX) * (height >> chromaScaleY) / 16) ; + cs.m_featureCounter.alfChromaPels += ((width >> chromaScaleX) * (height >> chromaScaleY)) ; +#endif } } } diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 391b65ec16ac702d920873e11a8623aecd86776a..8c38a9772f70675d8c23870f3911bf2ede64260a 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -564,6 +564,23 @@ protected: bool m_doSEIPersistenceFlag; int m_doSEITransformType; bool m_parameterSetsInclusionIndicationSEIEnabled; +#ifdef GREEN_METADATA_SEI_ENABLED + bool m_greenMetadataInfoSEIEnabled; + int m_greenMetadataType; + int m_greenMetadataGranularityType; + int m_greenMetadataExtendedRepresentation; + int m_greenMetadataPeriodType; + int m_greenMetadataPeriodNumSeconds; + int m_greenMetadataPeriodNumPictures; + //Metrics for quality recovery after low-power encoding + int m_xsdNumberMetrics; + bool m_xsdMetricTypePSNR; + bool m_xsdMetricTypeSSIM; + bool m_xsdMetricTypeVMAF; + bool m_xsdMetricTypeWPSNR; + bool m_xsdMetricTypeWSPSNR; + bool m_xsdMetricTypeEstimatedEnergy; +#endif bool m_selfContainedClvsFlag; bool m_bpDeltasGOPStructure; bool m_decodingUnitInfoSEIEnabled; @@ -1925,6 +1942,32 @@ public: int getDOSEITransformType() const { return m_doSEITransformType; } void setParameterSetsInclusionIndicationSEIEnabled(bool b) { m_parameterSetsInclusionIndicationSEIEnabled = b; } bool getParameterSetsInclusionIndicationSEIEnabled() const { return m_parameterSetsInclusionIndicationSEIEnabled; } +#ifdef GREEN_METADATA_SEI_ENABLED + void setSEIGreenMetadataInfoSEIEnable(int b) { (b >= 0) ? m_greenMetadataInfoSEIEnabled = 1 : m_greenMetadataInfoSEIEnabled =0;} + bool getSEIGreenMetadataInfoSEIEnable() { return m_greenMetadataInfoSEIEnabled;} + void setSEIGreenMetadataType(int b) { m_greenMetadataType = b;} + int getSEIGreenMetadataType() { return m_greenMetadataType;} + int getSEIGreenMetadataGranularityType() { return m_greenMetadataGranularityType;} + void setSEIGreenMetadataGranularityType(int b) { m_greenMetadataGranularityType = b;} + int getSEIGreenMetadataExtendedRepresentation() { return m_greenMetadataExtendedRepresentation;} + void setSEIGreenMetadataExtendedRepresentation(int b) { m_greenMetadataExtendedRepresentation = b;} + void setSEIGreenMetadataPeriodType(int b) { m_greenMetadataPeriodType = b;} + int getSEIGreenMetadataPeriodType() { return m_greenMetadataPeriodType;} + void setSEIGreenMetadataPeriodNumSeconds(int b) {m_greenMetadataPeriodNumSeconds = b;} + int getSEIGreenMetadataPeriodNumSeconds() {return m_greenMetadataPeriodNumSeconds;} + void setSEIGreenMetadataPeriodNumPictures(int b) {m_greenMetadataPeriodNumPictures = b;} + int getSEIGreenMetadataPeriodNumPictures() {return m_greenMetadataPeriodNumPictures;} + void setSEIXSDNumberMetrics(int b) { m_xsdNumberMetrics = b;} + int getSEIXSDNumberMetrics() { return m_xsdNumberMetrics;} + void setSEIXSDMetricTypePSNR(bool b) { m_xsdMetricTypePSNR = b;} + bool getSEIXSDMetricTypePSNR() { return m_xsdMetricTypePSNR;} + void setSEIXSDMetricTypeSSIM(bool b) { m_xsdMetricTypeSSIM = b;} + bool getSEIXSDMetricTypeSSIM() { return m_xsdMetricTypeSSIM;} + void setSEIXSDMetricTypeWPSNR(bool b) { m_xsdMetricTypeWPSNR = b;} + bool getSEIXSDMetricTypeWPSNR() { return m_xsdMetricTypeWPSNR;} + void setSEIXSDMetricTypeWSPSNR(bool b) { m_xsdMetricTypeWSPSNR = b;} + bool getSEIXSDMetricTypeWSPSNR() { return m_xsdMetricTypeWSPSNR;} +#endif void setSelfContainedClvsFlag(bool b) { m_selfContainedClvsFlag = b; } int getSelfContainedClvsFlag() { return m_selfContainedClvsFlag; } void setBpDeltasGOPStructure(bool b) { m_bpDeltasGOPStructure = b; } diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 13012b02678c30122e63e916179ae0998b673fca..546d2bc5568bbea978a445356b27538bbcff2476 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -223,7 +223,6 @@ void EncGOP::init ( EncLib* pcEncLib ) ::memset(m_lastBPSEI, 0, sizeof(m_lastBPSEI)); ::memset(m_totalCoded, 0, sizeof(m_totalCoded)); m_HRD = pcEncLib->getHRD(); - m_AUWriterIf = pcEncLib->getAUWriterIf(); if (m_pcCfg->getFilmGrainAnalysisEnabled()) @@ -3342,7 +3341,18 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l computeSignalling(pcPic, pcSlice); } m_pcSliceEncoder->precompressSlice( pcPic ); - m_pcSliceEncoder->compressSlice ( pcPic, false, false ); +#ifdef GREEN_METADATA_SEI_ENABLED + pcPic->setFeatureCounter(m_featureCounter); + if(m_pcEncLib->getGMFAFramewise()) + { + FeatureCounterStruct m_featureCounterFrameReference; + m_featureCounterFrameReference = m_featureCounter; + } +#endif + m_pcSliceEncoder->compressSlice ( pcPic, false, false); +#ifdef GREEN_METADATA_SEI_ENABLED + m_featureCounter = pcPic->getFeatureCounter(); +#endif if(sliceIdx < pcPic->cs->pps->getNumSlicesInPic() - 1) { @@ -3359,7 +3369,47 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l uiNumSliceSegments++; } } - +#ifdef GREEN_METADATA_SEI_ENABLED + m_featureCounter.baseQP[pcPic->getLossyQPValue()] ++; + if (m_featureCounter.isYUV420 == -1) + { + m_featureCounter.isYUV400 = pcSlice->getSPS()->getChromaFormatIdc() == CHROMA_400 ? 1 : 0; + m_featureCounter.isYUV420 = pcSlice->getSPS()->getChromaFormatIdc() == CHROMA_420 ? 1 : 0; + m_featureCounter.isYUV422 = pcSlice->getSPS()->getChromaFormatIdc() == CHROMA_422 ? 1 : 0; + m_featureCounter.isYUV444 = pcSlice->getSPS()->getChromaFormatIdc() == CHROMA_444 ? 1 : 0; + } + + if (m_featureCounter.is8bit == -1) + { + m_featureCounter.is8bit = (pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) == 8) ? 1 : 0; + m_featureCounter.is10bit = (pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) == 10) ? 1 : 0; + m_featureCounter.is12bit = (pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) == 12) ? 1 : 0; + } + + + if (pcSlice->getSliceType() == B_SLICE) + { + m_featureCounter.bSlices++; + } + else if (pcSlice->getSliceType()== P_SLICE) + { + m_featureCounter.pSlices++; + } + else + { + m_featureCounter.iSlices++; + } + + if (m_featureCounter.width == -1) + { + m_featureCounter.width = pcPic->getPicWidthInLumaSamples(); + } + + if (m_featureCounter.height == -1) + { + m_featureCounter.height = pcPic->getPicHeightInLumaSamples(); + } +#endif duData.clear(); CodingStructure& cs = *pcPic->cs; @@ -3455,12 +3505,21 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l } } } +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.resetBoundaryStrengths(); +#endif m_pcLoopFilter->deblockingFilterPic( cs ); +#ifdef GREEN_METADATA_SEI_ENABLED + m_featureCounter.addBoundaryStrengths(cs.m_featureCounter); +#endif CS::setRefinedMotionField(cs); if( pcSlice->getSPS()->getSAOEnabledFlag() ) { +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.resetSAO(); +#endif bool sliceEnabled[MAX_NUM_COMPONENT]; m_pcSAO->initCABACEstimator( m_pcEncLib->getCABACEncoder(), m_pcEncLib->getCtxCache(), pcSlice ); m_pcSAO->SAOProcess( cs, sliceEnabled, pcSlice->getLambdas(), @@ -3483,6 +3542,9 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, sliceEnabled[COMPONENT_Cb]); } } +#ifdef GREEN_METADATA_SEI_ENABLED + m_featureCounter.addSAO(cs.m_featureCounter); +#endif } if( pcSlice->getSPS()->getALFEnabledFlag() ) @@ -3495,13 +3557,18 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l pcPic->slices[s]->setAlfEnabledFlag(COMPONENT_Y, false); } m_pcALF->initCABACEstimator(m_pcEncLib->getCABACEncoder(), m_pcEncLib->getCtxCache(), pcSlice, m_pcEncLib->getApsMap()); +#ifdef GREEN_METADATA_SEI_ENABLED + cs.m_featureCounter.resetALF(); +#endif m_pcALF->ALFProcess(cs, pcSlice->getLambdas() #if ENABLE_QPA , (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP() ? m_pcEncLib->getRdCost()->getChromaWeight() : 0.0) #endif , pcPic, uiNumSliceSegments ); - +#ifdef GREEN_METADATA_SEI_ENABLED + m_featureCounter.addALF(cs.m_featureCounter); +#endif //assign ALF slice header for (int s = 0; s < uiNumSliceSegments; s++) { @@ -4113,7 +4180,79 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l double PSNR_Y; xCalculateAddPSNRs(isField, isTff, gopId, pcPic, accessUnit, rcListPic, encTime, snr_conversion, printFrameMSE, printMSSSIM, &PSNR_Y, isEncodeLtRef); - +#ifdef GREEN_METADATA_SEI_ENABLED + this->setFeatureCounter(m_featureCounter); + m_SEIGreenQualityMetrics.psnr = PSNR_Y; + if (m_pcCfg->getSEIGreenMetadataInfoSEIEnable()) + { + SEIGreenMetadataInfo* seiGreenMetadataInfo = new SEIGreenMetadataInfo; + seiGreenMetadataInfo->m_greenMetadataType = m_pcCfg->getSEIGreenMetadataType(); + seiGreenMetadataInfo->m_numPictures = m_pcCfg->getSEIGreenMetadataPeriodNumPictures(); + seiGreenMetadataInfo->m_periodType = m_pcCfg->getSEIGreenMetadataPeriodType(); + seiGreenMetadataInfo->m_numSeconds = m_pcCfg->getSEIGreenMetadataPeriodNumSeconds(); + seiGreenMetadataInfo->m_greenMetadataGranularityType = m_pcCfg->getSEIGreenMetadataGranularityType(); + seiGreenMetadataInfo->m_greenMetadataExtendedRepresentation = m_pcCfg->getSEIGreenMetadataExtendedRepresentation(); + int64_t codedFrames = m_featureCounter.iSlices + m_featureCounter.bSlices + m_featureCounter.pSlices; + int numberFrames = seiGreenMetadataInfo->m_numSeconds * m_pcCfg->getFrameRate(); + + if (seiGreenMetadataInfo->m_greenMetadataType == 0) + { + switch (m_pcCfg->getSEIGreenMetadataPeriodType()) // Period type + { + case 0: //0x00 complexity metrics are applicable to a single picture + seiGreenMetadataInfo->m_numPictures = m_pcCfg->getSEIGreenMetadataPeriodNumPictures(); + xCalculateGreenComplexityMetrics(m_featureCounter, m_featureCounterReference, seiGreenMetadataInfo); + m_seiEncoder.initSEIGreenMetadataInfo(seiGreenMetadataInfo, m_featureCounter, m_SEIGreenQualityMetrics,m_SEIGreenComplexityMetrics); + leadingSeiMessages.push_back(seiGreenMetadataInfo); + m_featureCounterReference = m_featureCounter; + break; + case 1: //0x01 complexity metrics are applicable to all pictures in decoding order, up to (but not including) the picture containing the next I slice + if (codedFrames == m_pcCfg->getFramesToBeEncoded() || codedFrames == 1) + { + xCalculateGreenComplexityMetrics(m_featureCounter, m_featureCounterReference, seiGreenMetadataInfo); + m_seiEncoder.initSEIGreenMetadataInfo(seiGreenMetadataInfo, m_featureCounter, m_SEIGreenQualityMetrics,m_SEIGreenComplexityMetrics); + leadingSeiMessages.push_back(seiGreenMetadataInfo); + m_featureCounterReference = m_featureCounter; + } + break; + case 2: //0x02 complexity metrics are applicable over a specified time interval in seconds + seiGreenMetadataInfo->m_numSeconds = m_pcCfg->getSEIGreenMetadataPeriodNumSeconds(); + if( ((codedFrames% numberFrames) == 0) || (codedFrames == m_pcCfg->getFramesToBeEncoded())) + { + seiGreenMetadataInfo->m_numSeconds = int(floor(double(codedFrames)/double(m_pcCfg->getFrameRate()))); + xCalculateGreenComplexityMetrics(m_featureCounter, m_featureCounterReference, seiGreenMetadataInfo); + m_seiEncoder.initSEIGreenMetadataInfo(seiGreenMetadataInfo, m_featureCounter, m_SEIGreenQualityMetrics,m_SEIGreenComplexityMetrics); + leadingSeiMessages.push_back(seiGreenMetadataInfo); + m_featureCounterReference = m_featureCounter; + } + break; + case 3: //0x03 complexity metrics are applicable over a specified number of pictures counted in decoding order + seiGreenMetadataInfo->m_numPictures = m_pcCfg->getSEIGreenMetadataPeriodNumPictures(); + if( ((codedFrames%(seiGreenMetadataInfo->m_numPictures)) == 0) || (codedFrames == m_pcCfg->getFramesToBeEncoded())) + { + xCalculateGreenComplexityMetrics(m_featureCounter, m_featureCounterReference, seiGreenMetadataInfo); + m_seiEncoder.initSEIGreenMetadataInfo(seiGreenMetadataInfo, m_featureCounter, m_SEIGreenQualityMetrics,m_SEIGreenComplexityMetrics); + leadingSeiMessages.push_back(seiGreenMetadataInfo); + m_featureCounterReference = m_featureCounter; + } + break; + case 4: //0x04 complexity metrics are applicable to a single picture with slice or tile granularity + case 5: //0x05 complexity metrics are applicable to a single picture with subpicture granularity + case 6: //0x06 complexity metrics are applicable to all pictures in decoding order, up to (but not including) the picture containing the next I slice with subpicture granularity + case 7: //0x07 complexity metrics are applicable over a specified time interval in seconds with subpicture granularity + case 8: //0x08 complexity metrics are applicable over a specified number of pictures counted in decoding order with subpicture granularity + default: //0x05-0xFF reserved + break; + } + } + else if (seiGreenMetadataInfo->m_greenMetadataType == 1) // Quality metric signaling + { + m_seiEncoder.initSEIGreenMetadataInfo(seiGreenMetadataInfo, m_featureCounter, m_SEIGreenQualityMetrics, m_SEIGreenComplexityMetrics); + leadingSeiMessages.push_back(seiGreenMetadataInfo); + } + } +#endif + xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer()); #if GDR_ENABLED @@ -5161,7 +5300,148 @@ void EncGOP::xCalculateAddPSNR(Picture* pcPic, PelUnitBuf cPicD, const AccessUni std::cout << "\r\t" << pcSlice->getPOC(); std::cout.flush(); } +#ifdef GREEN_METADATA_SEI_ENABLED + m_SEIGreenQualityMetrics.ssim = msssim[0]; + m_SEIGreenQualityMetrics.wpsnr = dPSNR[0]; +#endif +} + +#ifdef GREEN_METADATA_SEI_ENABLED +void EncGOP::xCalculateGreenComplexityMetrics( FeatureCounterStruct featureCounter, FeatureCounterStruct featureCounterReference, SEIGreenMetadataInfo* seiGreenMetadataInfo) +{ + double chromaFormatMultiplier = 0; + + if (featureCounter.isYUV400 == 1) + { + chromaFormatMultiplier = 1; + } + else if (featureCounter.isYUV420) + { + chromaFormatMultiplier = 1.5; + } + else if (featureCounter.isYUV422) + { + chromaFormatMultiplier = 2; + } + else if (featureCounter.isYUV444) + { + chromaFormatMultiplier = 3; + } + + // Initialize + int64_t totalNum4BlocksPic = 0; + int64_t totalNum4BlocksInPeriod = 0; + int64_t maxNumDeblockingInstances = 0; + + double numNonZeroBlocks = 0; + double numNonZero4_8_16_Blocks = 0; + double numNonZero32_64_128_Blocks = 0; + double numNonZero256_512_1024_Blocks = 0; + double numNonZero2048_4096_Blocks = 0; + double numIntraPredictedBlocks = 0; + double numBiAndGpmPredictedBlocks = 0; + double numBDOFPredictedBlocks = 0; + double numDeblockingInstances = 0; + double numSaoFilteredBlocks = 0; + double numAlfFilteredBlocks = 0; + // Calculate difference + FeatureCounterStruct featureCounterDifference; + + featureCounterDifference.iSlices = featureCounter.iSlices - featureCounterReference.iSlices; + featureCounterDifference.bSlices = featureCounter.bSlices - featureCounterReference.bSlices; + featureCounterDifference.pSlices = featureCounter.pSlices - featureCounterReference.pSlices; + featureCounterDifference.nrOfCoeff = featureCounter.nrOfCoeff - featureCounterReference.nrOfCoeff; + featureCounterDifference.biPredPel = featureCounter.biPredPel - featureCounterReference.biPredPel; + featureCounterDifference.boundaryStrength[0] = featureCounter.boundaryStrength[0] - featureCounterReference.boundaryStrength[0]; + featureCounterDifference.boundaryStrength[1] = featureCounter.boundaryStrength[1] - featureCounterReference.boundaryStrength[1]; + featureCounterDifference.boundaryStrength[2] = featureCounter.boundaryStrength[2] - featureCounterReference.boundaryStrength[2]; + featureCounterDifference.saoLumaEO = featureCounter.saoLumaEO - featureCounterReference.saoLumaEO; + featureCounterDifference.saoLumaBO = featureCounter.saoLumaBO - featureCounterReference.saoLumaBO; + featureCounterDifference.saoChromaEO = featureCounter.saoChromaEO - featureCounterReference.saoChromaEO; + featureCounterDifference.saoChromaBO = featureCounter.saoChromaBO - featureCounterReference.saoChromaBO; + featureCounterDifference.saoLumaPels = featureCounter.saoLumaPels - featureCounterReference.saoLumaPels; + featureCounterDifference.saoChromaPels = featureCounter.saoChromaPels - featureCounterReference.saoChromaPels; + featureCounterDifference.alfLumaType7 = featureCounter.alfLumaType7 - featureCounterReference.alfLumaType7; + featureCounterDifference.alfChromaType5 = featureCounter.alfChromaType5 - featureCounterReference.alfChromaType5; + featureCounterDifference.alfLumaPels = featureCounter.alfLumaPels - featureCounterReference.alfLumaPels; + featureCounterDifference.alfChromaPels = featureCounter.alfChromaPels - featureCounterReference.alfChromaPels; + + + for (int i = 0; i < MAX_CU_DEPTH+1; i++) + { + for (int j = 0; j < MAX_CU_DEPTH+1; j++) + { + featureCounterDifference.transformBlocks[i][j] = featureCounter.transformBlocks[i][j] - featureCounterReference.transformBlocks[i][j]; + featureCounterDifference.intraBlockSizes[i][j] = featureCounter.intraBlockSizes[i][j] - featureCounterReference.intraBlockSizes[i][j]; + featureCounterDifference.geo[i][j] = featureCounter.geo[i][j] - featureCounterReference.geo[i][j]; + featureCounterDifference.bdofBlocks[i][j] = featureCounter.bdofBlocks[i][j] - featureCounterReference.bdofBlocks[i][j]; + } + } + + + //Calculate complexity metrics + totalNum4BlocksPic = int(chromaFormatMultiplier * featureCounter.width * featureCounter.height / 4); + totalNum4BlocksInPeriod = int((featureCounterDifference.iSlices + featureCounterDifference.pSlices + featureCounterDifference.bSlices) * totalNum4BlocksPic); + maxNumDeblockingInstances = int(chromaFormatMultiplier * totalNum4BlocksInPeriod - 2 * (featureCounter.width + featureCounter.height) * 2); + + for (int i = 0; i < MAX_CU_DEPTH+1; i++) + { + for(int j = 0; j < MAX_CU_DEPTH+1; j++) + { + double numberOfPels = pow(2,i) * pow(2,j); + numNonZeroBlocks += double(featureCounterDifference.transformBlocks[i][j] * numberOfPels / 4); + numIntraPredictedBlocks += double(featureCounterDifference.intraBlockSizes[i][j] * numberOfPels / 4); + + if (numberOfPels == 4 || numberOfPels == 8 || numberOfPels == 16) + { + numNonZero4_8_16_Blocks += double(featureCounterDifference.transformBlocks[i][j] * numberOfPels / 4); + } + + if (numberOfPels == 32 || numberOfPels == 64 || numberOfPels == 128) + { + numNonZero32_64_128_Blocks += double(featureCounterDifference.transformBlocks[i][j] * numberOfPels / 4); + } + + if (numberOfPels == 256 || numberOfPels == 512 || numberOfPels == 1024) + { + numNonZero256_512_1024_Blocks += double(featureCounterDifference.transformBlocks[i][j] * numberOfPels / 4); + } + + if (numberOfPels == 2048 || numberOfPels == 4096 ) + { + numNonZero2048_4096_Blocks += double(featureCounterDifference.transformBlocks[i][j] * numberOfPels / 4); + } + numBDOFPredictedBlocks += double(featureCounterDifference.bdofBlocks[i][j] * numberOfPels / 4); + numBiAndGpmPredictedBlocks += double(featureCounterDifference.geo[i][j] * numberOfPels / 4); + } + } + + numBiAndGpmPredictedBlocks += double(featureCounterDifference.biPredPel/4); + numDeblockingInstances = double(featureCounterDifference.boundaryStrength[0] + featureCounterDifference.boundaryStrength[1] + featureCounterDifference.boundaryStrength[2]); + numSaoFilteredBlocks = double(featureCounterDifference.saoLumaPels + featureCounterDifference.saoChromaPels)/4; + numAlfFilteredBlocks = double(featureCounterDifference.alfLumaPels + featureCounterDifference.alfChromaPels)/4; + + seiGreenMetadataInfo->m_greenComplexityMetrics.portionNonZeroBlocksArea = int(floor( 255.0 * numNonZeroBlocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionNonZero_4_8_16BlocksArea = int(floor(255.0 * numNonZero4_8_16_Blocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionNonZero_32_64_128BlocksArea = int(floor( 255.0 * numNonZero32_64_128_Blocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionNonZero_256_512_1024BlocksArea = int(floor( 255.0 * numNonZero256_512_1024_Blocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionNonZero_2048_4096BlocksArea = int(floor( 255.0 * numNonZero2048_4096_Blocks / totalNum4BlocksInPeriod)); + if (numNonZeroBlocks != 0) + { + seiGreenMetadataInfo->m_greenComplexityMetrics.portionNonZeroTransformCoefficientsArea = + int(floor(255.0 * featureCounterDifference.nrOfCoeff / (4 *numNonZeroBlocks))); + } + + seiGreenMetadataInfo->m_greenComplexityMetrics.portionIntraPredictedBlocksArea = int(floor( 255.0 * numIntraPredictedBlocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionBiAndGpmPredictedBlocksArea = int(floor( 255.0 * numBiAndGpmPredictedBlocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionBdofBlocksArea = int(floor( 255.0 * numBDOFPredictedBlocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionDeblockingInstances = int(floor( 255.0 * numDeblockingInstances / maxNumDeblockingInstances)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionSaoInstances = int(floor( 255.0 * numSaoFilteredBlocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_greenComplexityMetrics.portionAlfInstances = int(floor( 255.0 * numAlfFilteredBlocks / totalNum4BlocksInPeriod)); + seiGreenMetadataInfo->m_numPictures = int(featureCounterDifference.iSlices + featureCounterDifference.bSlices +featureCounterDifference.pSlices); + seiGreenMetadataInfo->m_numSeconds = int(floor(double(seiGreenMetadataInfo->m_numPictures) / double(m_pcCfg->getFrameRate()))); } +#endif 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) { @@ -6697,4 +6977,5 @@ void EncGOP::xCreateExplicitReferencePictureSetFromReference( Slice* slice, PicL } } + //! \} diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h index 5d3cff2b6ac0ba5514d138bbb9a5d1ed464262e7..1fe29a27738a07d99c1d5a660cd1d4acf9f1d2ba 100644 --- a/source/Lib/EncoderLib/EncGOP.h +++ b/source/Lib/EncoderLib/EncGOP.h @@ -220,6 +220,13 @@ private: std::chrono::duration<long long, std::ratio<1, 1000000000>> m_metricTime; #endif +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter; + FeatureCounterStruct m_featureCounterReference; + SEIQualityMetrics m_SEIGreenQualityMetrics; + SEIComplexityMetrics m_SEIGreenComplexityMetrics; +#endif + public: EncGOP(); virtual ~EncGOP(); @@ -253,6 +260,10 @@ public: void setLastLTRefPoc(int iLastLTRefPoc) { m_lastLTRefPoc = iLastLTRefPoc; } int getLastLTRefPoc() const { return m_lastLTRefPoc; } +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct getFeatureCounter(){return m_featureCounter;} + void setFeatureCounter(FeatureCounterStruct b){m_featureCounter=b;} +#endif #if GDR_ENABLED void setLastGdrIntervalPoc(int p) { m_lastGdrIntervalPoc = p; } int getLastGdrIntervalPoc() const { return m_lastGdrIntervalPoc; } @@ -358,6 +369,9 @@ protected: void xCreateExplicitReferencePictureSetFromReference( Slice* slice, PicList& rcListPic, const ReferencePictureList *rpl0, const ReferencePictureList *rpl1 ); bool xCheckMaxTidILRefPics(int layerIdx, Picture* refPic, bool currentPicIsIRAP); void computeSignalling(Picture* pcPic, Slice* pcSlice) const; +#ifdef GREEN_METADATA_SEI_ENABLED + void xCalculateGreenComplexityMetrics(FeatureCounterStruct featureCounter, FeatureCounterStruct featureCounterReference, SEIGreenMetadataInfo* seiGreenMetadataInfo); +#endif };// END CLASS DEFINITION EncGOP //! \} diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index edcf9cdd344527dcfc29a7d487f3e13a2f9240a7..63fc838688e08017e0b1594781769808c804b8c9 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -676,6 +676,9 @@ bool EncLib::encodePrep(bool flush, PelStorage *pcPicYuvOrg, PelStorage *cPicYuv #if JVET_O0756_CALCULATE_HDRMETRICS m_metricTime = m_cGOPEncoder.getMetricTime(); +#endif +#ifdef GREEN_METADATA_SEI_ENABLED + this->setFeatureCounter(m_cGOPEncoder.getFeatureCounter()); #endif m_cGOPEncoder.setEncodedLTRef( true ); if( m_RCEnableRateControl ) diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index 415b449e7df0a9d317b28e4320622e1f75a9f87d..b43b4c338e4dd36fd6096025a7090baa8ef5db9a 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -129,7 +129,11 @@ private: int* m_layerDecPicBuffering; RPLList m_rplLists[2]; - +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter; + bool m_GMFAFramewise; + std::string m_GMFAFile; +#endif public: SPS* getSPS( int spsId ) { return m_spsMap.getPS( spsId ); }; APS** getApss() { return m_apss; } @@ -189,7 +193,13 @@ public: CtxCache* getCtxCache () { return &m_CtxCache; } RateCtrl* getRateCtrl () { return &m_cRateCtrl; } - +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct getFeatureCounter(){return m_featureCounter;} + void setFeatureCounter(FeatureCounterStruct b){m_featureCounter=b;} + bool getGMFAFramewise() {return m_GMFAFramewise;} + void setGMFAFile(std::string b){m_GMFAFile = b;} +#endif + void selectReferencePictureList(Slice* slice, int POCCurr, int GOPid, int ltPoc); void setParamSetChanged(int spsId, int ppsId); diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 559e35fe9141824c6ff18d368cad554ccade8bdc..051edc93f4f1d0e68bf5757bd13adb391bbffa2c 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -1872,6 +1872,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons if (pCfg->getSwitchPOC() != pcPic->poc || ctuRsAddr >= pCfg->getDebugCTU()) { m_pcCuEncoder->compressCtu(cs, ctuArea, ctuRsAddr, prevQP, currQP); +#ifdef GREEN_METADATA_SEI_ENABLED + FeatureCounterStruct m_featureCounter = pcPic->getFeatureCounter(); + countFeatures(m_featureCounter, cs,ctuArea); + pcPic->setFeatureCounter(m_featureCounter); +#endif } #if K0149_BLOCK_STATISTICS getAndStoreBlockStatistics(cs, ctuArea); diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp index 70e427c69204164c5d4afdce9056184c1325d7aa..7fa48a729d19e849ddcaeebb41eb410786185dee 100644 --- a/source/Lib/EncoderLib/SEIEncoder.cpp +++ b/source/Lib/EncoderLib/SEIEncoder.cpp @@ -232,6 +232,54 @@ void SEIEncoder::initSEIErp(SEIEquirectangularProjection* seiEquirectangularProj } } +#ifdef GREEN_METADATA_SEI_ENABLED +void SEIEncoder::initSEIGreenMetadataInfo(SEIGreenMetadataInfo* seiGreenMetadataInfo, FeatureCounterStruct featureCounter, SEIQualityMetrics metrics,SEIComplexityMetrics greenMetadata) +{ + assert (m_isInitialized); + assert (seiGreenMetadataInfo!=NULL); + + if (m_pcCfg->getSEIGreenMetadataType() == 1) //Metadata for quality recovery after low-power encoding + { + seiGreenMetadataInfo->m_greenMetadataType = m_pcCfg->getSEIGreenMetadataType(); + seiGreenMetadataInfo->m_xsdSubpicNumberMinus1 = m_pcCfg->getSEIXSDNumberMetrics()-1; + seiGreenMetadataInfo->m_xsdSubPicIdc = 1; //Only 1 Picture is supported + // Maximum valid value for 16-bit integer: 65535 + (m_pcCfg->getSEIXSDMetricTypePSNR()) ? seiGreenMetadataInfo->m_xsdMetricValuePSNR = min(int(metrics.psnr*100),65535) : seiGreenMetadataInfo->m_xsdMetricValuePSNR = 0; + (m_pcCfg->getSEIXSDMetricTypeSSIM()) ? seiGreenMetadataInfo->m_xsdMetricValueSSIM = min(int(metrics.ssim*100),65535) : seiGreenMetadataInfo->m_xsdMetricValueSSIM = 0; + (m_pcCfg->getSEIXSDMetricTypeWPSNR()) ? seiGreenMetadataInfo->m_xsdMetricValueWPSNR = min(int(metrics.wpsnr*100),65535) : seiGreenMetadataInfo->m_xsdMetricValueWPSNR = 0; + (m_pcCfg->getSEIXSDMetricTypeWSPSNR()) ? seiGreenMetadataInfo->m_xsdMetricValueWSPSNR = min(int(metrics.wspsnr*100),65535) : seiGreenMetadataInfo->m_xsdMetricValueWSPSNR = 0; + + seiGreenMetadataInfo->m_xsdMetricTypePSNR = m_pcCfg->getSEIXSDMetricTypePSNR(); + seiGreenMetadataInfo->m_xsdMetricTypeSSIM = m_pcCfg->getSEIXSDMetricTypeSSIM(); + seiGreenMetadataInfo->m_xsdMetricTypeWPSNR = m_pcCfg->getSEIXSDMetricTypeWPSNR(); + seiGreenMetadataInfo->m_xsdMetricTypeWSPSNR = m_pcCfg->getSEIXSDMetricTypeWSPSNR(); + } + else if(m_pcCfg->getSEIGreenMetadataType() == 0) // Metadata for decoder-complexity metrics + { + seiGreenMetadataInfo->m_greenMetadataType = m_pcCfg->getSEIGreenMetadataType(); + seiGreenMetadataInfo->m_greenMetadataGranularityType = m_pcCfg->getSEIGreenMetadataGranularityType(); + seiGreenMetadataInfo->m_greenMetadataExtendedRepresentation = m_pcCfg->getSEIGreenMetadataExtendedRepresentation(); + switch (m_pcCfg->getSEIGreenMetadataPeriodType()) // Period type + { + case 0: // 0x00 complexity metrics are applicable to a single picture + seiGreenMetadataInfo->m_numPictures = m_pcCfg->getSEIGreenMetadataPeriodNumPictures(); + break; + case 1: // 0x01 complexity metrics are applicable to all pictures in decoding order, up to (but not including) the picture containing the next I slice + // + break; + case 2: // 0x02 complexity metrics are applicable over a specified time interval in seconds + seiGreenMetadataInfo->m_numPictures = m_pcCfg->getSEIGreenMetadataPeriodNumPictures(); + break; + case 3: // 0x03 complexity metrics are applicable over a specified number of pictures counted in decoding order + seiGreenMetadataInfo->m_numSeconds = m_pcCfg->getSEIGreenMetadataPeriodNumSeconds(); + break; + default: // 0x05-0xFF reserved + break; // + } + } +} +#endif + void SEIEncoder::initSEISphereRotation(SEISphereRotation* seiSphereRotation) { CHECK(!(m_isInitialized), "seiSphereRotation already initialized"); diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h index 135badf23388f2992976b09bc77d6aba145b3085..286a14004bdb5b96dde8e9c1d8ff5a070e8c48ee 100644 --- a/source/Lib/EncoderLib/SEIEncoder.h +++ b/source/Lib/EncoderLib/SEIEncoder.h @@ -93,6 +93,9 @@ public: void initSEINeuralNetworkPostFilterCharacteristics(SEINeuralNetworkPostFilterCharacteristics *sei, int filterIdx); void initSEINeuralNetworkPostFilterActivation(SEINeuralNetworkPostFilterActivation *sei); void initSEIProcessingOrderInfo(SEIProcessingOrderInfo *sei); +#ifdef GREEN_METADATA_SEI_ENABLED + void initSEIGreenMetadataInfo(SEIGreenMetadataInfo *sei, FeatureCounterStruct featureCounter, SEIQualityMetrics metrics, SEIComplexityMetrics greenMetadata); +#endif private: EncCfg* m_pcCfg; EncLib* m_pcEncLib; diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp index 0c899d49809cf7e38f098c1837907246381151ea..9a9376179508163f22c32aa5e4baa63493aa84c6 100644 --- a/source/Lib/EncoderLib/SEIwrite.cpp +++ b/source/Lib/EncoderLib/SEIwrite.cpp @@ -83,6 +83,11 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI& sei, HRD &h case SEI::FRAME_PACKING: xWriteSEIFramePacking(*static_cast<const SEIFramePacking*>(&sei)); break; +#ifdef GREEN_METADATA_SEI_ENABLED + case SEI::GREEN_METADATA: + xWriteSEIGreenMetadataInfo(*static_cast<const SEIGreenMetadataInfo*>(&sei)); + break; +#endif case SEI::DISPLAY_ORIENTATION: xWriteSEIDisplayOrientation(*static_cast<const SEIDisplayOrientation*>(&sei)); break; @@ -1420,6 +1425,118 @@ void SEIWriter::xWriteSEIConstrainedRaslIndication(const SEIConstrainedRaslIndic // intentionally empty } +#ifdef GREEN_METADATA_SEI_ENABLED +void SEIWriter::xWriteSEIGreenMetadataInfo(const SEIGreenMetadataInfo& sei) +{ + WRITE_CODE(sei.m_greenMetadataType, 8, "green_metadata_type"); + switch (sei.m_greenMetadataType) + { + case 0: + WRITE_CODE(sei.m_periodType,4, "period_type"); + WRITE_CODE(sei.m_greenMetadataGranularityType,3, "granularity_type"); + WRITE_CODE(sei.m_greenMetadataExtendedRepresentation,1, "extended_representation_flag"); + + if (sei.m_periodType == 2) + { + WRITE_CODE(sei.m_numSeconds, 16, "num_seconds"); + } + else if (sei.m_periodType == 3) + { + WRITE_CODE(sei.m_numPictures, 16, "num_pictures"); + } + + if (sei.m_greenMetadataGranularityType == 0) + { + WRITE_CODE(sei.m_greenComplexityMetrics.portionNonZeroBlocksArea, 8, "portion_non_zero_blocks_area"); + WRITE_CODE(sei.m_greenComplexityMetrics.portionNonZeroTransformCoefficientsArea, 8, "portion_non_zero_transform_coefficients_area"); + WRITE_CODE(sei.m_greenComplexityMetrics.portionIntraPredictedBlocksArea, 8, "portion_intra_predicted_blocks_area"); + WRITE_CODE(sei.m_greenComplexityMetrics.portionDeblockingInstances, 8, "portion_deblocking_instances"); + WRITE_CODE(sei.m_greenComplexityMetrics.portionAlfInstances, 8, "portion_alf_instances"); + + if(sei.m_greenMetadataExtendedRepresentation == 1) + { + if(sei.m_greenComplexityMetrics.portionNonZeroBlocksArea != 0) + { + WRITE_CODE(sei.m_greenComplexityMetrics.portionNonZero_4_8_16BlocksArea, 8, "portion_non_zero_4_8_16_blocks_area"); + WRITE_CODE(sei.m_greenComplexityMetrics.portionNonZero_32_64_128BlocksArea, 8, "portion_non_zero_32_64_128_blocks_area"); + WRITE_CODE(sei.m_greenComplexityMetrics.portionNonZero_256_512_1024BlocksArea, 8, "portion_non_zero_256_512_1024_blocks_area"); + WRITE_CODE(sei.m_greenComplexityMetrics.portionNonZero_2048_4096BlocksArea, 8, "portion_non_zero_2048_4096_blocks_area"); + } + + + if(sei.m_greenComplexityMetrics.portionIntraPredictedBlocksArea < 255) + { + WRITE_CODE(sei.m_greenComplexityMetrics.portionBiAndGpmPredictedBlocksArea, 8,"portion_bi_and_gpm_predicted_blocks_area"); + WRITE_CODE(sei.m_greenComplexityMetrics.portionBdofBlocksArea, 8,"portion_bdof_blocks_area"); + } + + WRITE_CODE(sei.m_greenComplexityMetrics.portionSaoInstances, 8, "portion_sao_instances"); + } + } + + break; + case 1: + int xsdSubpicNumberMinus1 = 0; + WRITE_CODE(xsdSubpicNumberMinus1, 16, "xsd_subpic_number_minus1"); + for (int i = 0; i <= xsdSubpicNumberMinus1; i++) + { + int xsdMetricNumberMinus1 = -1; + WRITE_CODE(sei.m_xsdSubPicIdc, 16, "xsd_subpic_idc[i]"); + std::vector <int> xsdMetricArray; + if (sei.m_xsdMetricTypePSNR) + { + xsdMetricNumberMinus1++; + xsdMetricArray.push_back(0); + } + if (sei.m_xsdMetricTypeSSIM) + { + xsdMetricNumberMinus1++; + xsdMetricArray.push_back(1); + } + + if (sei.m_xsdMetricTypeWPSNR) + { + xsdMetricNumberMinus1++; + xsdMetricArray.push_back(2); + } + + if (sei.m_xsdMetricTypeWSPSNR) + { + xsdMetricNumberMinus1++; + xsdMetricArray.push_back(3); + } + + WRITE_CODE(xsdMetricNumberMinus1, 8, "xsd_metric_number_minus1[i]"); + for (int j = 0; j <= xsdMetricNumberMinus1; j++) + { + if (xsdMetricArray[j] == 0) + { + WRITE_CODE(0, 8, "xsd_metric_type"); + WRITE_CODE(sei.m_xsdMetricValuePSNR, 16, "xsd_metric_type[i][j]"); + } + else if (xsdMetricArray[j] == 1) + { + WRITE_CODE(1, 8, "xsd_metric_type"); + WRITE_CODE(sei.m_xsdMetricValueSSIM, 16, "xsd_metric_type[i][j]"); + } + else if (xsdMetricArray[j] == 2) + { + WRITE_CODE(3, 8, "xsd_metric_type"); + WRITE_CODE(sei.m_xsdMetricValueWPSNR, 16, "xsd_metric_type[i][j]"); + } + else if (xsdMetricArray[j] == 3) + { + WRITE_CODE(4, 8, "xsd_metric_type"); + WRITE_CODE(sei.m_xsdMetricValueWSPSNR, 16, "xsd_metric_type[i][j]"); + } + } + } + break; + } +} +#endif + + void SEIWriter::xWriteSEINeuralNetworkPostFilterCharacteristics(const SEINeuralNetworkPostFilterCharacteristics &sei) { WRITE_UVLC(sei.m_id, "nnpfc_id"); diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h index 8d3ec33cdf30a0f2af137da2b3043442869104bf..88ec2dfa298815b84f09cbf41d8b032f5170e9c6 100644 --- a/source/Lib/EncoderLib/SEIwrite.h +++ b/source/Lib/EncoderLib/SEIwrite.h @@ -97,6 +97,9 @@ protected: void xWriteNNPFCComplexityElement(const SEINeuralNetworkPostFilterCharacteristics& sei); void xWriteSEINeuralNetworkPostFilterActivation(const SEINeuralNetworkPostFilterActivation &sei); void xWriteSEIProcessingOrder(const SEIProcessingOrderInfo &sei); +#ifdef GREEN_METADATA_SEI_ENABLED + void xWriteSEIGreenMetadataInfo (const SEIGreenMetadataInfo &sei); +#endif protected: HRD m_nestingHrd; };