diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index d82d17e8e..945a1d718 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -559,7 +559,44 @@ uint32_t DecApp::decode() } } } - +#if JVET_AG0328 + if (!m_SEIFGRFileName.empty() && !m_videoIOYuvSEIFGRFile[nalu.m_nuhLayerId].isOpen()) + { + std::string SEIFGRFileName = m_SEIFGRFileName; + if (m_SEIFGRFileName.compare("/dev/null") && m_cDecLib.getVPS() != nullptr && m_cDecLib.getVPS()->getMaxLayers() > 1 && xIsNaluWithinTargetOutputLayerIdSet(&nalu)) + { + size_t pos = SEIFGRFileName.find_last_of('.'); + std::string layerString = std::string(".layer") + std::to_string(nalu.m_nuhLayerId); + if (pos != std::string::npos) + { + SEIFGRFileName.insert(pos, layerString); + } + else + { + SEIFGRFileName.append(layerString); + } + } + if ((m_cDecLib.getVPS() != nullptr && (m_cDecLib.getVPS()->getMaxLayers() == 1 || xIsNaluWithinTargetOutputLayerIdSet(&nalu))) || m_cDecLib.getVPS() == nullptr) + { + m_videoIOYuvSEIFGRFile[nalu.m_nuhLayerId].open(SEIFGRFileName, true, layerOutputBitDepth,layerOutputBitDepth, bitDepths); // write mode + } + } + // update file bitdepth shift if recon bitdepth changed between sequences + if (!m_SEIFGRFileName.empty()) + { + for (const auto channelType: { ChannelType::LUMA, ChannelType::CHROMA }) + { + int reconBitdepth = (*iterPicLayer)->m_bitDepths[( ChannelType) channelType]; + int fileBitdepth = m_videoIOYuvSEIFGRFile[nalu.m_nuhLayerId].getFileBitdepth(channelType); + int bitdepthShift = m_videoIOYuvSEIFGRFile[nalu.m_nuhLayerId].getBitdepthShift(channelType); + if (fileBitdepth + bitdepthShift != reconBitdepth) + { + m_videoIOYuvSEIFGRFile[nalu.m_nuhLayerId].setBitdepthShift(channelType, reconBitdepth - fileBitdepth); + } + } + } +#endif + if (!m_SEICTIFileName.empty() && !m_cVideoIOYuvSEICTIFile[nalu.m_nuhLayerId].isOpen()) { std::string SEICTIFileName = m_SEICTIFileName; @@ -953,6 +990,15 @@ void DecApp::xDestroyDecLib() recFile.second.close(); } } +#if JVET_AG0328 + if (!m_SEIFGRFileName.empty()) + { + for (auto &recFile: m_videoIOYuvSEIFGRFile) + { + recFile.second.close(); + } + } +#endif if (!m_SEICTIFileName.empty()) { for (auto& recFile : m_cVideoIOYuvSEICTIFile) @@ -1161,6 +1207,32 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId ) } } +#if JVET_AG0328 + // Perform region based FGS on decoded frame and write to output FGR file + if (!m_SEIFGRFileName.empty()) + { + const Window& conf = pcPic->getConformanceWindow(); + const SPS* sps = pcPic->cs->sps; + ChromaFormat chromaFormatIdc = sps->getChromaFormatIdc(); + if (m_upscaledOutput) + { + m_videoIOYuvSEIFGRFile[pcPic->layerId].writeUpscaledPicture( + *sps, *pcPic->cs->pps, pcPic->getDisplayBufFGR(), m_outputColourSpaceConvert, m_packedYUVMode, + m_upscaledOutput, ChromaFormat::UNDEFINED, m_clipOutputVideoToRec709Range, m_upscaleFilterForDisplay); + } + else + { + m_videoIOYuvSEIFGRFile[pcPic->layerId].write( + pcPic->getRecoBuf().get(COMPONENT_Y).width, pcPic->getRecoBuf().get(COMPONENT_Y).height, + pcPic->getDisplayBufFGR(), m_outputColourSpaceConvert, m_packedYUVMode, + conf.getWindowLeftOffset() * SPS::getWinUnitX(chromaFormatIdc), + conf.getWindowRightOffset() * SPS::getWinUnitX(chromaFormatIdc), + conf.getWindowTopOffset() * SPS::getWinUnitY(chromaFormatIdc), + conf.getWindowBottomOffset() * SPS::getWinUnitY(chromaFormatIdc), ChromaFormat::UNDEFINED, + m_clipOutputVideoToRec709Range); + } + } +#endif if (!m_shutterIntervalPostFileName.empty() && getShutterFilterFlag()) { @@ -1375,7 +1447,33 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId ) m_clipOutputVideoToRec709Range); } } - +#if JVET_AG0328 + // Perform region based FGS on decoded frame and write to output FGR file + if (!m_SEIFGRFileName.empty()) + { + const Window& conf = pcPic->getConformanceWindow(); + const SPS* sps = pcPic->cs->sps; + ChromaFormat chromaFormatIdc = sps->getChromaFormatIdc(); + if (m_upscaledOutput) + { + m_videoIOYuvSEIFGRFile[pcPic->layerId].writeUpscaledPicture( + *sps, *pcPic->cs->pps, pcPic->getDisplayBufFGR(), m_outputColourSpaceConvert, m_packedYUVMode, + m_upscaledOutput, ChromaFormat::UNDEFINED, m_clipOutputVideoToRec709Range, m_upscaleFilterForDisplay); + } + else + { + m_videoIOYuvSEIFGRFile[pcPic->layerId].write( + pcPic->getRecoBuf().get(COMPONENT_Y).width, pcPic->getRecoBuf().get(COMPONENT_Y).height, + pcPic->getDisplayBufFGR(), m_outputColourSpaceConvert, m_packedYUVMode, + conf.getWindowLeftOffset() * SPS::getWinUnitX(chromaFormatIdc), + conf.getWindowRightOffset() * SPS::getWinUnitX(chromaFormatIdc), + conf.getWindowTopOffset() * SPS::getWinUnitY(chromaFormatIdc), + conf.getWindowBottomOffset() * SPS::getWinUnitY(chromaFormatIdc), ChromaFormat::UNDEFINED, + m_clipOutputVideoToRec709Range); + } + } +#endif + if (!m_shutterIntervalPostFileName.empty() && getShutterFilterFlag()) { int blendingRatio = getBlendingRatio(); diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h index c92890252..e25adf395 100644 --- a/source/App/DecoderApp/DecApp.h +++ b/source/App/DecoderApp/DecApp.h @@ -62,6 +62,9 @@ private: DecLib m_cDecLib; ///< decoder class std::unordered_map m_cVideoIOYuvReconFile; ///< reconstruction YUV class std::unordered_map m_videoIOYuvSEIFGSFile; ///< reconstruction YUV with FGS class +#if JVET_AG0328 + std::unordered_map m_videoIOYuvSEIFGRFile; ///< reconstruction YUV with FGR class +#endif std::unordered_map m_cVideoIOYuvSEICTIFile; ///< reconstruction YUV with CTI class bool m_ShutterFilterEnable; ///< enable Post-processing with Shutter Interval SEI diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index eaf90dd50..ba79c4142 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -98,6 +98,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) ("SEIColourRemappingInfoFilename", m_colourRemapSEIFileName, std::string(""), "Colour Remapping YUV output file name. If empty, no remapping is applied (ignore SEI message)\n") ("SEICTIFilename", m_SEICTIFileName, std::string(""), "CTI YUV output file name. If empty, no Colour Transform is applied (ignore SEI message)\n") ("SEIFGSFilename", m_SEIFGSFileName, std::string(""), "FGS YUV output file name. If empty, no film grain is applied (ignore SEI message)\n") +#if JVET_AG0328 + ("SEIFGRFilename", m_SEIFGRFileName, std::string(""), "FGR YUV output file name. If empty, no film grain region is applied (ignore SEI message)\n") +#endif ("SEIAnnotatedRegionsInfoFilename", m_annotatedRegionsSEIFileName, std::string(""), "Annotated regions output file name. If empty, no object information will be saved (ignore SEI message)\n") ("OutputDecodedSEIMessagesFilename", m_outputDecodedSEIMessagesFilename, std::string(""), "When non empty, output decoded SEI messages to the indicated file. If file is '-', then output to stdout\n") #if JVET_S0257_DUMP_360SEI_MESSAGE @@ -267,6 +270,9 @@ DecAppCfg::DecAppCfg() , m_colourRemapSEIFileName() , m_SEICTIFileName() , m_SEIFGSFileName() +#if JVET_AG0328 +, m_SEIFGRFileName() +#endif , m_annotatedRegionsSEIFileName() , m_targetDecLayerIdSet() , m_outputDecodedSEIMessagesFilename() diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index cd38e1515..7fdbf1230 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -77,6 +77,9 @@ protected: std::string m_colourRemapSEIFileName; ///< output Colour Remapping file name std::string m_SEICTIFileName; ///< output Recon with CTI file name std::string m_SEIFGSFileName; ///< output file name for reconstructed sequence with film grain +#if JVET_AG0328 + std::string m_SEIFGRFileName; ///< output file name for reconstructed sequence with film grain regions +#endif std::string m_annotatedRegionsSEIFileName; ///< annotated regions file name std::vector m_targetDecLayerIdSet; ///< set of LayerIds to be included in the sub-bitstream extraction process. std::string m_outputDecodedSEIMessagesFilename; ///< filename to output decoded SEI messages to. If '-', then use stdout. If empty, do not output details. diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 064736a83..1f018a0a6 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -1089,6 +1089,49 @@ void EncApp::xInitLibCfg( int layerIdx ) } } } +#if JVET_AG0328 + // film grain regions charcteristics + m_cEncLib.setFilmGrainRegionsCharactersticsSEIEnabled (m_fgrSEIEnabled); + m_cEncLib.setFilmGrainRegionsCharactersticsSEICancelFlag (m_fgrSEICancelFlag); + m_cEncLib.setFilmGrainRegionsCharactersticsSEIPersistenceFlag (m_fgrSEIPersistenceFlag); + m_cEncLib.setFilmGrainRegionsCharactersticsSEIModelID ((uint8_t)m_fgrSEIModelID); + m_cEncLib.setFilmGrainRegionsCharactersticsSEISepColourDescPresent (m_fgrSEISepColourDescPresentFlag); + m_cEncLib.setFilmGrainRegionsCharactersticsSEIBlendingModeID ((uint8_t)m_fgrSEIBlendingModeID); + m_cEncLib.setFilmGrainRegionsCharactersticsSEILog2ScaleFactor ((uint8_t)m_fgrSEILog2ScaleFactor); + m_cEncLib.setFilmGrainRegionsAnalysisEnabled (m_fgrSEIAnalysisEnabled); + m_cEncLib.setFilmGrainRegionsExternalMask (m_fgrSEIExternalMask); + m_cEncLib.setFilmGrainRegionsExternalDenoised (m_fgrSEIExternalDenoised); + m_cEncLib.setFilmGrainRegionsTemporalFilterPastRefs (m_fgrSEITemporalFilterPastRefs); + m_cEncLib.setFilmGrainRegionsTemporalFilterFutureRefs (m_fgrSEITemporalFilterFutureRefs); + m_cEncLib.setFilmGrainRegionsTemporalFilterStrengths (m_fgrSEITemporalFilterStrengths); + for (int i = 0; i < MAX_NUM_COMPONENT; i++) + { + m_cEncLib.setFGRSEICompModelPresent (m_fgrSEICompModelPresent[i], i); + if (m_fgrSEICompModelPresent[i]) + { + m_cEncLib.setFGRSEINumIntensityIntervalMinus1 ((uint8_t)m_fgrSEINumIntensityIntervalMinus1[i], i); + m_cEncLib.setFGRSEINumModelValuesMinus1 ((uint8_t)m_fgrSEINumModelValuesMinus1[i], i); + for (int j = 0; j <= m_fgrSEINumIntensityIntervalMinus1[i]; j++) + { + m_cEncLib.setFGRSEIIntensityIntervalLowerBound ((uint8_t)m_fgrSEIIntensityIntervalLowerBound[i][j], i, j); + m_cEncLib.setFGRSEIIntensityIntervalUpperBound ((uint8_t)m_fgrSEIIntensityIntervalUpperBound[i][j], i, j); + for (int k = 0; k <= m_fgrSEINumModelValuesMinus1[i]; k++) + { + m_cEncLib.setFGRSEICompModelValue (m_fgrSEICompModelValue[i][j][k], i, j, k); + } + } + } + } + m_cEncLib.setFilmGrainRegionInformationPresentFlag (m_fgrSEI_region_information_present_flag); + m_cEncLib.setFilmGrainRegionBasedAdaptationFlag (m_fgrSEI_region_based_adaptation_flag); + m_cEncLib.setFilmGrainAlphaChannelAdaptationFlag (m_fgrSEI_alpha_channel_adaptation_flag); + m_cEncLib.setFilmGrainNumActiveRegionsMinus1 (m_fgrSEINumActiveRegionsMinus1); + + if(m_fgrSEI_region_based_adaptation_flag) + { + m_cEncLib.setFilmGrainRegionCharacteristics(m_fgrSEIregionCharacteristics,m_fgrSEINumActiveRegionsMinus1); + } +#endif // content light level m_cEncLib.setCLLSEIEnabled (m_cllSEIEnabled); m_cEncLib.setCLLSEIMaxContentLightLevel ((uint16_t)m_cllSEIMaxContentLevel); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index e7040d294..b195d9787 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -152,7 +152,56 @@ std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry) //in return in; } +#if JVET_AG0328 +template +static void readValueFromFile(T &returnedValue, /// value returned + bool &failed, /// used and updated + std::istream &is, /// stream to read token from + const char *pToken) /// token string +{ + returnedValue=T(); + if (failed) + { + return; + } + int c; + // Ignore any whitespace + while ((c=is.get())!=EOF && isspace(c)); + // test for comment mark + while (c=='#') + { + // Ignore to the end of the line + while ((c=is.get())!=EOF && (c!=10 && c!=13)); + // Ignore any white space at the start of the next line + while ((c=is.get())!=EOF && isspace(c)); + } + // test first character of token + failed=(c!=pToken[0]); + // test remaining characters of token + int pos; + for(pos=1;!failed && pToken[pos]!=0 && is.get()==pToken[pos]; pos++); + failed|=(pToken[pos]!=0); + // Ignore any whitespace before the ':' + while (!failed && (c=is.get())!=EOF && isspace(c)); + failed|=(c!=':'); + // Now read the value associated with the token: + if (!failed) + { + is >> returnedValue; + failed=!is.good(); + if (!failed) + { + c=is.get(); + failed=(c!=EOF && !isspace(c)); + } + } + if (failed) + { + std::cerr << "Unable to read Value '" << pToken << "'\n"; + } +} +#endif bool confirmPara(bool bflag, const char* message); @@ -727,6 +776,31 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) SMultiValueInput cfg_FgcSEICompModelValueComp0 (0, 65535, 0, 256 * 6); SMultiValueInput cfg_FgcSEICompModelValueComp1 (0, 65535, 0, 256 * 6); SMultiValueInput cfg_FgcSEICompModelValueComp2 (0, 65535, 0, 256 * 6); +#if JVET_AG0328 + //film grain regions SEI + SMultiValueInput cfg_FgrSEIIntensityIntervalLowerBoundComp0 (0, 255, 0, 256); + SMultiValueInput cfg_FgrSEIIntensityIntervalLowerBoundComp1 (0, 255, 0, 256); + SMultiValueInput cfg_FgrSEIIntensityIntervalLowerBoundComp2 (0, 255, 0, 256); + SMultiValueInput cfg_FgrSEIIntensityIntervalUpperBoundComp0 (0, 255, 0, 256); + SMultiValueInput cfg_FgrSEIIntensityIntervalUpperBoundComp1 (0, 255, 0, 256); + SMultiValueInput cfg_FgrSEIIntensityIntervalUpperBoundComp2 (0, 255, 0, 256); + SMultiValueInput cfg_FgrSEICompModelValueComp0 (0, 65535, 0, 256 * 6); + SMultiValueInput cfg_FgrSEICompModelValueComp1 (0, 65535, 0, 256 * 6); + SMultiValueInput cfg_FgrSEICompModelValueComp2 (0, 65535, 0, 256 * 6); + + SMultiValueInput cfg_fgr_region_top(0, 65535, 0, 256 * 6); + SMultiValueInput cfg_fgr_region_left(0, 65535, 0, 256 * 6); + SMultiValueInput cfg_fgr_region_width(0, 65535, 0, 256 * 6); + SMultiValueInput cfg_fgr_region_height(0, 65535, 0, 256 * 6); + SMultiValueInput cfg_fgr_region_fg_enable(0, 1, 0, 256); + SMultiValueInput cfg_fgr_region_interval_min_comp0(0, 255, 0, 256); + SMultiValueInput cfg_fgr_region_interval_min_comp1(0, 255, 0, 256); + SMultiValueInput cfg_fgr_region_interval_min_comp2(0, 255, 0, 256); + SMultiValueInput cfg_fgr_region_interval_max_comp0(0, 255, 0, 256); + SMultiValueInput cfg_fgr_region_interval_max_comp1(0, 255, 0, 256); + SMultiValueInput cfg_fgr_region_interval_max_comp2(0, 255, 0, 256); +#endif + SMultiValueInput cfg_siiSEIInputNumUnitsInSI(0, std::numeric_limits::max(), 0, 7); SMultiValueInput cfg_poSEIWrappingFlag(false, true, 0, 256); SMultiValueInput cfg_poSEIImportanceFlag(false, true, 0, 256); @@ -1504,6 +1578,57 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("SEIFGCCompModelValuesComp0", cfg_FgcSEICompModelValueComp0, cfg_FgcSEICompModelValueComp0, "Specifies the component model values on colour component 0.") ("SEIFGCCompModelValuesComp1", cfg_FgcSEICompModelValueComp1, cfg_FgcSEICompModelValueComp1, "Specifies the component model values on colour component 1.") ("SEIFGCCompModelValuesComp2", cfg_FgcSEICompModelValueComp2, cfg_FgcSEICompModelValueComp2, "Specifies the component model values on colour component 2.") +#if JVET_AG0328 + // film grain region characteristics SEI + ("SEIFGREnabled", m_fgrSEIEnabled, false, "Control generation of the film grain regions characteristics SEI message") + ("SEIFGRCancelFlag", m_fgrSEICancelFlag, true, "Specifies the persistence of any previous film grain regions characteristics SEI message in output order.") + ("SEIFGRPersistenceFlag", m_fgrSEIPersistenceFlag, false, "Specifies the persistence of the film grain regions characteristics SEI message for the current layer.") + ("SEIFGRModelID", m_fgrSEIModelID, 0u, "Specifies the film grain simulation model. 0: frequency filtering; 1: auto-regression.") + ("SEIFGRSepColourDescPresentFlag", m_fgrSEISepColourDescPresentFlag, false, "Specifies the presence of a distinct colour space description for the film grain characteristics specified in the SEI message.") + ("SEIFGRBlendingModeID", m_fgrSEIBlendingModeID, 0u, "Specifies the blending mode used to blend the simulated film grain with the decoded images. 0: additive; 1: multiplicative.") + ("SEIFGRLog2ScaleFactor", m_fgrSEILog2ScaleFactor, 0u, "Specifies a scale factor used in the film grain characterization equations.") + ("SEIFGRCompModelPresentComp0", m_fgrSEICompModelPresent[0], false, "Specifies the presence of film grain modelling on colour component 0.") + ("SEIFGRCompModelPresentComp1", m_fgrSEICompModelPresent[1], false, "Specifies the presence of film grain modelling on colour component 1.") + ("SEIFGRCompModelPresentComp2", m_fgrSEICompModelPresent[2], false, "Specifies the presence of film grain modelling on colour component 2.") + ("SEIFGRAnalysisEnabled", m_fgrSEIAnalysisEnabled, false, "Control adaptive film grain parameter estimation - film grain analysis") + ("SEIFGRExternalMask", m_fgrSEIExternalMask, std::string( "" ), "Read external file with mask for film grain analysis. If empty string, use internally calculated mask.") + ("SEIFGRExternalDenoised", m_fgrSEIExternalDenoised, std::string( "" ), "Read external file with denoised sequence for film grain analysis. If empty string, use MCTF for denoising.") + ("SEIFGRTemporalFilterPastRefs", m_fgrSEITemporalFilterPastRefs, TF_DEFAULT_REFS, "Number of past references for temporal prefilter") + ("SEIFGRTemporalFilterFutureRefs", m_fgrSEITemporalFilterFutureRefs, TF_DEFAULT_REFS, "Number of future references for temporal prefilter") + ("SEIFGRTemporalFilterStrengthFrame*", m_fgrSEITemporalFilterStrengths, std::map(), "Strength for every * frame in FGC-specific temporal filter, where * is an integer.") + ("SEIFGRPerPictureSEI", m_fgrSEIPerPictureSEI, false, "Film Grain Regions SEI is added for each picture as speciffied in RDD5 to ensure bit accurate synthesis in tricky mode") + ("SEIFGRNumIntensityIntervalMinus1Comp0", m_fgrSEINumIntensityIntervalMinus1[0], 0u, "Specifies the number of intensity intervals minus1 on colour component 0.") + ("SEIFGRNumIntensityIntervalMinus1Comp1", m_fgrSEINumIntensityIntervalMinus1[1], 0u, "Specifies the number of intensity intervals minus1 on colour component 1.") + ("SEIFGRNumIntensityIntervalMinus1Comp2", m_fgrSEINumIntensityIntervalMinus1[2], 0u, "Specifies the number of intensity intervals minus1 on colour component 2.") + ("SEIFGRNumModelValuesMinus1Comp0", m_fgrSEINumModelValuesMinus1[0], 0u, "Specifies the number of component model values minus1 on colour component 0.") + ("SEIFGRNumModelValuesMinus1Comp1", m_fgrSEINumModelValuesMinus1[1], 0u, "Specifies the number of component model values minus1 on colour component 1.") + ("SEIFGRNumModelValuesMinus1Comp2", m_fgrSEINumModelValuesMinus1[2], 0u, "Specifies the number of component model values minus1 on colour component 2.") + ("SEIFGRIntensityIntervalLowerBoundComp0", cfg_FgrSEIIntensityIntervalLowerBoundComp0, cfg_FgrSEIIntensityIntervalLowerBoundComp0, "Specifies the lower bound for the intensity intervals on colour component 0.") + ("SEIFGRIntensityIntervalLowerBoundComp1", cfg_FgrSEIIntensityIntervalLowerBoundComp1, cfg_FgrSEIIntensityIntervalLowerBoundComp1, "Specifies the lower bound for the intensity intervals on colour component 1.") + ("SEIFGRIntensityIntervalLowerBoundComp2", cfg_FgrSEIIntensityIntervalLowerBoundComp2, cfg_FgrSEIIntensityIntervalLowerBoundComp2, "Specifies the lower bound for the intensity intervals on colour component 2.") + ("SEIFGRIntensityIntervalUpperBoundComp0", cfg_FgrSEIIntensityIntervalUpperBoundComp0, cfg_FgrSEIIntensityIntervalUpperBoundComp0, "Specifies the upper bound for the intensity intervals on colour component 0.") + ("SEIFGRIntensityIntervalUpperBoundComp1", cfg_FgrSEIIntensityIntervalUpperBoundComp1, cfg_FgrSEIIntensityIntervalUpperBoundComp1, "Specifies the upper bound for the intensity intervals on colour component 1.") + ("SEIFGRIntensityIntervalUpperBoundComp2", cfg_FgrSEIIntensityIntervalUpperBoundComp2, cfg_FgrSEIIntensityIntervalUpperBoundComp2, "Specifies the upper bound for the intensity intervals on colour component 2.") + ("SEIFGRCompModelValuesComp0", cfg_FgrSEICompModelValueComp0, cfg_FgrSEICompModelValueComp0, "Specifies the component model values on colour component 0.") + ("SEIFGRCompModelValuesComp1", cfg_FgrSEICompModelValueComp1, cfg_FgrSEICompModelValueComp1, "Specifies the component model values on colour component 1.") + ("SEIFGRCompModelValuesComp2", cfg_FgrSEICompModelValueComp2, cfg_FgrSEICompModelValueComp2, "Specifies the component model values on colour component 2.") + ("SEIFGRSpatialAdaptation", m_fgrSEI_region_information_present_flag, false, "Specifies if spatial adaptation if enabled or not.") + ("SEIFGRegionBasedAdaptation", m_fgrSEI_region_based_adaptation_flag, false, "Spatial adaptation based on rectangle regions.") + ("SEIFGAlphaChannelBasedAdaptation", m_fgrSEI_alpha_channel_adaptation_flag, false, "Spatial adaptation based on alpha Mask.") + ("SEIFGRegionsNumberMinus1", m_fgrSEINumActiveRegionsMinus1, 0u, "Number of active regions with adaptive parameters.") + + ("SEIFGRegionTop", cfg_fgr_region_top, cfg_fgr_region_top, "Specifies the Top coordinate of the regions.") + ("SEIFGRegionLeft", cfg_fgr_region_left, cfg_fgr_region_left, "Specifies the Left coordinate of the regions.") + ("SEIFGRegionWidth", cfg_fgr_region_width, cfg_fgr_region_left, "Specifies the width coordinate of the regions.") + ("SEIFGRegionHeight", cfg_fgr_region_height, cfg_fgr_region_height, "Specifies the height coordinate of the regions.") + ("SEIFGRFilmGrainEnabled", cfg_fgr_region_fg_enable, cfg_fgr_region_fg_enable, "Enable/disable Film grain for the regions.") + ("SEIFGRegionIntervalMinComp0", cfg_fgr_region_interval_min_comp0, cfg_fgr_region_interval_min_comp0, "Specifies the min interval for Comp0 for the regions.") + ("SEIFGRegionIntervalMinComp1", cfg_fgr_region_interval_min_comp1, cfg_fgr_region_interval_min_comp1, "Specifies the min interval for Comp1 for the regions.") + ("SEIFGRegionIntervalMinComp2", cfg_fgr_region_interval_min_comp2, cfg_fgr_region_interval_min_comp2, "Specifies the min interval for Comp2 for the regions.") + ("SEIFGRegionIntervalMaxComp0", cfg_fgr_region_interval_max_comp0, cfg_fgr_region_interval_max_comp0, "Specifies the max interval for Comp0 for the regions.") + ("SEIFGRegionIntervalMaxComp1", cfg_fgr_region_interval_max_comp1, cfg_fgr_region_interval_max_comp1, "Specifies the max interval for Comp1 for the regions.") + ("SEIFGRegionIntervalMaxComp2", cfg_fgr_region_interval_max_comp2, cfg_fgr_region_interval_max_comp2, "Specifies the max interval for Comp2 for the regions.") +#endif // content light level SEI ("SEICLLEnabled", m_cllSEIEnabled, false, "Control generation of the content light level SEI message") ("SEICLLMaxContentLightLevel", m_cllSEIMaxContentLevel, 0u, "When not equal to 0, specifies an upper bound on the maximum light level among all individual samples in a 4:4:4 representation " @@ -3232,6 +3357,121 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } m_fgcSEILog2ScaleFactor = m_fgcSEILog2ScaleFactor ? m_fgcSEILog2ScaleFactor : 2; } + +#if JVET_AG0328 + // set sei film grain regions parameters. + CHECK(!m_fgrSEIEnabled && m_fgrSEIAnalysisEnabled, "FGR SEI must be enabled in order to perform film grain regions analysis!"); + if (m_fgrSEIEnabled) + { + if (m_iQP < 17 && m_fgrSEIAnalysisEnabled == true) + { // TODO: JVET_Z0047_FG_IMPROVEMENT: check this; the constraint may have gone + msg(WARNING, "*************************************************************************\n"); + msg(WARNING, "* WARNING: Film Grain Estimation is disabled for Qp<17! FGR SEI will use default parameters for film grain! *\n"); + msg(WARNING, "*************************************************************************\n"); + m_fgrSEIAnalysisEnabled = false; + } + if (m_intraPeriod < 1) + { // low delay configuration + msg(WARNING, "*************************************************************************\n"); + msg(WARNING, "* WARNING: For low delay configuration, FGR SEI is inserted for first frame only!*\n"); + msg(WARNING, "*************************************************************************\n"); + m_fgrSEIPerPictureSEI = false; + m_fgrSEIPersistenceFlag = true; + } + else if (m_intraPeriod == 1) + { // all intra configuration + msg(WARNING, "*************************************************************************\n"); + msg(WARNING, "* WARNING: For Intra Period = 1, FGR SEI is inserted per frame!*\n"); + msg(WARNING, "*************************************************************************\n"); + m_fgrSEIPerPictureSEI = true; + m_fgrSEIPersistenceFlag = false; + } + if (!m_fgrSEIPerPictureSEI && !m_fgrSEIPersistenceFlag) { + msg(WARNING, "*************************************************************************\n"); + msg(WARNING, "* WARNING: SEIPerPictureSEI is set to 0, SEIPersistenceFlag needs to be set to 1! *\n"); + msg(WARNING, "*************************************************************************\n"); + m_fgrSEIPersistenceFlag = true; + } + else if (m_fgrSEIPerPictureSEI && m_fgrSEIPersistenceFlag) { + msg(WARNING, "*************************************************************************\n"); + msg(WARNING, "* WARNING: SEIPerPictureSEI is set to 1, SEIPersistenceFlag needs to be set to 0! *\n"); + msg(WARNING, "*************************************************************************\n"); + m_fgrSEIPersistenceFlag = false; + } + if (m_fgrSEIAnalysisEnabled && m_fgrSEITemporalFilterStrengths.empty()) + { + // By default: in random-acces = filter RAPs, in all-intra = filter every frame, otherwise = filter every 2s + int filteredFrame = m_intraPeriod < 1 ? 2 * m_frameRate.getIntValRound() : m_intraPeriod; + m_fgrSEITemporalFilterStrengths[filteredFrame] = 1.5; + } + uint32_t numModelCtr; + if (m_fgrSEICompModelPresent[0]) + { + numModelCtr = 0; + for (uint8_t i = 0; i <= m_fgrSEINumIntensityIntervalMinus1[0]; i++) + { + m_fgrSEIIntensityIntervalLowerBound[0][i] = uint32_t((cfg_FgrSEIIntensityIntervalLowerBoundComp0.values.size() > i) ? cfg_FgrSEIIntensityIntervalLowerBoundComp0.values[i] : 10); + m_fgrSEIIntensityIntervalUpperBound[0][i] = uint32_t((cfg_FgrSEIIntensityIntervalUpperBoundComp0.values.size() > i) ? cfg_FgrSEIIntensityIntervalUpperBoundComp0.values[i] : 250); + for (uint8_t j = 0; j <= m_fgrSEINumModelValuesMinus1[0]; j++) + { + m_fgrSEICompModelValue[0][i][j] = uint32_t((cfg_FgrSEICompModelValueComp0.values.size() > numModelCtr) ? cfg_FgrSEICompModelValueComp0.values[numModelCtr] : 24); + numModelCtr++; + } + } + } + if (m_fgrSEICompModelPresent[1]) + { + numModelCtr = 0; + for (uint8_t i = 0; i <= m_fgrSEINumIntensityIntervalMinus1[1]; i++) + { + m_fgrSEIIntensityIntervalLowerBound[1][i] = uint32_t((cfg_FgrSEIIntensityIntervalLowerBoundComp1.values.size() > i) ? cfg_FgrSEIIntensityIntervalLowerBoundComp1.values[i] : 60); + m_fgrSEIIntensityIntervalUpperBound[1][i] = uint32_t((cfg_FgrSEIIntensityIntervalUpperBoundComp1.values.size() > i) ? cfg_FgrSEIIntensityIntervalUpperBoundComp1.values[i] : 200); + + for (uint8_t j = 0; j <= m_fgrSEINumModelValuesMinus1[1]; j++) + { + m_fgrSEICompModelValue[1][i][j] = uint32_t((cfg_FgrSEICompModelValueComp1.values.size() > numModelCtr) ? cfg_FgrSEICompModelValueComp1.values[numModelCtr] : 16); + numModelCtr++; + } + } + } + if (m_fgrSEICompModelPresent[2]) + { + numModelCtr = 0; + for (uint8_t i = 0; i <= m_fgrSEINumIntensityIntervalMinus1[2]; i++) + { + m_fgrSEIIntensityIntervalLowerBound[2][i] = uint32_t((cfg_FgrSEIIntensityIntervalLowerBoundComp2.values.size() > i) ? cfg_FgrSEIIntensityIntervalLowerBoundComp2.values[i] : 60); + m_fgrSEIIntensityIntervalUpperBound[2][i] = uint32_t((cfg_FgrSEIIntensityIntervalUpperBoundComp2.values.size() > i) ? cfg_FgrSEIIntensityIntervalUpperBoundComp2.values[i] : 250); + + for (uint8_t j = 0; j <= m_fgrSEINumModelValuesMinus1[2]; j++) + { + m_fgrSEICompModelValue[2][i][j] = uint32_t((cfg_FgrSEICompModelValueComp2.values.size() > numModelCtr) ? cfg_FgrSEICompModelValueComp2.values[numModelCtr] : 12); + numModelCtr++; + } + } + } + m_fgrSEILog2ScaleFactor = m_fgrSEILog2ScaleFactor ? m_fgrSEILog2ScaleFactor : 2; + + if (m_fgrSEI_region_based_adaptation_flag) + { + m_fgrSEIregionCharacteristics.resize(m_fgrSEINumActiveRegionsMinus1 + 1); + for (int regionIdx = 0; regionIdx <= m_fgrSEINumActiveRegionsMinus1; regionIdx++) + { + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_region_top = cfg_fgr_region_top.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_region_left = cfg_fgr_region_left.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_region_width = cfg_fgr_region_width.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_region_height = cfg_fgr_region_height.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_film_grain_enabled_flag = cfg_fgr_region_fg_enable.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_regionIntervals[0].m_fgr_region_interval_min = cfg_fgr_region_interval_min_comp0.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_regionIntervals[1].m_fgr_region_interval_min = cfg_fgr_region_interval_min_comp1.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_regionIntervals[2].m_fgr_region_interval_min = cfg_fgr_region_interval_min_comp2.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_regionIntervals[0].m_fgr_region_interval_max = cfg_fgr_region_interval_max_comp0.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_regionIntervals[1].m_fgr_region_interval_max = cfg_fgr_region_interval_max_comp1.values[regionIdx]; + m_fgrSEIregionCharacteristics[regionIdx].m_fgr_regionIntervals[2].m_fgr_region_interval_max = cfg_fgr_region_interval_max_comp2.values[regionIdx]; + } + } + } + +#endif if (m_ctiSEIEnabled) { CHECK(!m_ctiSEICrossComponentFlag && m_ctiSEICrossComponentInferred, "CTI CrossComponentFlag is 0, but CTI CrossComponentInferred is 1 (must be 0 for CrossComponentFlag 0)"); @@ -5651,7 +5891,9 @@ void EncAppCfg::xPrintParameter() msg(VERBOSE, "SEI CTI:%d ", m_ctiSEIEnabled); msg(VERBOSE, "BIM:%d ", m_bimEnabled); msg(VERBOSE, "SEI FGC:%d ", m_fgcSEIEnabled); - +#if JVET_AG0328 + msg(VERBOSE, "SEI FGR:%d ", m_fgrSEIEnabled); +#endif msg(VERBOSE, "SEI processing Order:%d ", m_poSEIEnabled); #if EXTENSION_360_VIDEO diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index a9bcd15b3..04bac1d43 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -563,6 +563,34 @@ protected: uint32_t m_fgcSEIIntensityIntervalLowerBound [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES]; uint32_t m_fgcSEIIntensityIntervalUpperBound [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES]; uint32_t m_fgcSEICompModelValue [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES][MAX_NUM_MODEL_VALUES]; +#if JVET_AG0328 + // film grain regions characterstics sei + bool m_fgrSEIEnabled; + bool m_fgrSEICancelFlag; + bool m_fgrSEIPersistenceFlag; + uint32_t m_fgrSEIModelID; + bool m_fgrSEISepColourDescPresentFlag; + uint32_t m_fgrSEIBlendingModeID; + uint32_t m_fgrSEILog2ScaleFactor; + bool m_fgrSEICompModelPresent[MAX_NUM_COMPONENT]; + bool m_fgrSEIAnalysisEnabled; + std::string m_fgrSEIExternalMask; + std::string m_fgrSEIExternalDenoised; + int m_fgrSEITemporalFilterPastRefs; + int m_fgrSEITemporalFilterFutureRefs; + std::map m_fgrSEITemporalFilterStrengths; + bool m_fgrSEIPerPictureSEI; + uint32_t m_fgrSEINumModelValuesMinus1 [MAX_NUM_COMPONENT]; + uint32_t m_fgrSEINumIntensityIntervalMinus1 [MAX_NUM_COMPONENT]; + uint32_t m_fgrSEIIntensityIntervalLowerBound [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES]; + uint32_t m_fgrSEIIntensityIntervalUpperBound [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES]; + uint32_t m_fgrSEICompModelValue [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES][MAX_NUM_MODEL_VALUES]; + bool m_fgrSEI_region_information_present_flag; + bool m_fgrSEI_region_based_adaptation_flag; + bool m_fgrSEI_alpha_channel_adaptation_flag; + uint32_t m_fgrSEINumActiveRegionsMinus1; + std::vector m_fgrSEIregionCharacteristics; +#endif // content light level SEI bool m_cllSEIEnabled; uint32_t m_cllSEIMaxContentLevel; diff --git a/source/App/utils/BitrateTargeting/encodeCommand.sh b/source/App/utils/BitrateTargeting/encodeCommand.sh old mode 100755 new mode 100644 diff --git a/source/App/utils/BitrateTargeting/targetBitrates.sh b/source/App/utils/BitrateTargeting/targetBitrates.sh old mode 100755 new mode 100644 diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index 48cd7befb..c1cea36f4 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -76,6 +76,10 @@ Picture::Picture() m_isMctfFiltered = false; m_grainCharacteristic = nullptr; m_grainBuf = nullptr; +#if JVET_AG0328 + m_grainRegionsCharacteristic = nullptr; + m_grainRegionsBuf = nullptr; +#endif } void Picture::create(const bool useWrapAround, const ChromaFormat& _chromaFormat, const Size& size, @@ -1455,6 +1459,67 @@ PelUnitBuf Picture::getDisplayBufFG(bool wrap) } } +#if JVET_AG0328 +void Picture::createGrainRegionsSynthesizer(bool firstPictureInSequence, SEIFilmGrainRegionsSynthesizer *grainRegionsCharacteristics, PelStorage *grainRegionsBuf, int width, int height, ChromaFormat fmt, int bitDepth) +{ + m_grainRegionsCharacteristic = grainRegionsCharacteristics; + m_grainRegionsBuf = grainRegionsBuf; + + // Padding to make wd and ht multiple of max fgs window size(64) + int paddedWdFGS = ((width - 1) | 0x3F) + 1 - width; + int paddedHtFGS = ((height - 1) | 0x3F) + 1 - height; + m_padValue = (paddedWdFGS > paddedHtFGS) ? paddedWdFGS : paddedHtFGS; + + if (firstPictureInSequence) + { + // Create and initialize the Film Grain Synthesizer + m_grainRegionsCharacteristic->create(width, height, fmt, bitDepth, 1); + + // Frame level PelStorage buffer created to blend Film Grain Noise into it + m_grainRegionsBuf->create(chromaFormat, Area(0, 0, width, height), 0, m_padValue, 0, false); + + m_grainRegionsCharacteristic->fgrInit(); + } +} + +PelUnitBuf Picture::getDisplayBufFGR(bool wrap) +{ + SEI::PayloadType payloadType; + std::list::iterator message; + for (message = SEIs.begin(); message != SEIs.end(); ++message) + { + payloadType = (*message)->payloadType(); + if (payloadType == SEI::PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS) + { + m_grainRegionsCharacteristic->m_errorCode = -1; + *m_grainRegionsCharacteristic->m_fgrParameters = *static_cast(*message); + /* Validation of Film grain region characteristic parameters for the constrains of SMPTE-RDD5*/ + m_grainRegionsCharacteristic->m_errorCode = m_grainRegionsCharacteristic->grainValidateParams(); + break; + } + } + + if (FGS_SUCCESS == m_grainRegionsCharacteristic->m_errorCode) + { + m_grainRegionsBuf->copyFrom(getRecoBuf()); + m_grainRegionsBuf->extendBorderPel(m_padValue); // Padding to make wd and ht multiple of max fgs window size(64) + + m_grainRegionsCharacteristic->m_poc = getPOC(); + m_grainRegionsCharacteristic->grainSynthesizeAndBlend(m_grainRegionsBuf, slices[0]->getIdrPicFlag()); + + return *m_grainRegionsBuf; + } + else + { + if (payloadType == SEI::PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS) + { + msg(WARNING, "Film Grain Region synthesis is not performed. Error code: 0x%x \n", m_grainCharacteristic->m_errorCode); + } + return M_BUFS(scheduler.getSplitPicId(), wrap ? PIC_RECON_WRAP : PIC_RECONSTRUCTION); + } +} +#endif + void Picture::createColourTransfProcessor(bool firstPictureInSequence, SEIColourTransformApply* ctiCharacteristics, PelStorage* ctiBuf, int width, int height, ChromaFormat fmt, int bitDepth) { m_colourTranfParams = ctiCharacteristics; diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 224e96293..8f3fe73e2 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -85,7 +85,13 @@ struct Picture : public UnitArea PelStorage* m_grainBuf; void createGrainSynthesizer(bool firstPictureInSequence, SEIFilmGrainSynthesizer* grainCharacteristics, PelStorage* grainBuf, int width, int height, ChromaFormat fmt, int bitDepth); PelUnitBuf getDisplayBufFG (bool wrap = false); - +#if JVET_AG0328 + // Film Grain Regions Synthesizer + SEIFilmGrainRegionsSynthesizer* m_grainRegionsCharacteristic; + PelStorage* m_grainRegionsBuf; + void createGrainRegionsSynthesizer(bool firstPictureInSequence, SEIFilmGrainRegionsSynthesizer* grainRegionsCharacteristics, PelStorage* grainRegionsBuf, int width, int height, ChromaFormat fmt, int bitDepth); + PelUnitBuf getDisplayBufFGR (bool wrap = false); +#endif SEIColourTransformApply* m_colourTranfParams; PelStorage* m_invColourTransfBuf; void createColourTransfProcessor(bool firstPictureInSequence, SEIColourTransformApply* ctiCharacteristics, PelStorage* ctiBuf, int width, int height, ChromaFormat fmt, int bitDepth); diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp index 4a46ac283..acaa59840 100644 --- a/source/Lib/CommonLib/SEI.cpp +++ b/source/Lib/CommonLib/SEI.cpp @@ -446,6 +446,9 @@ static const std::map payloadTypeStrings = { { SEI::PayloadType::USER_DATA_REGISTERED_ITU_T_T35, "User data registered" }, { SEI::PayloadType::USER_DATA_UNREGISTERED, "User data unregistered" }, { SEI::PayloadType::FILM_GRAIN_CHARACTERISTICS, "Film grain characteristics" }, +#if JVET_AG0328 + { SEI::PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS, "Film grain region characteristics" }, +#endif { SEI::PayloadType::FRAME_PACKING, "Frame packing arrangement" }, { SEI::PayloadType::DISPLAY_ORIENTATION, "Display orientation" }, { SEI::PayloadType::GREEN_METADATA, "Green metadata" }, @@ -882,6 +885,54 @@ SEIFilmGrainCharacteristics::SEIFilmGrainCharacteristics(const SEIFilmGrainChara m_filmGrainCharacteristicsPersistenceFlag = sei.m_filmGrainCharacteristicsPersistenceFlag; } +#if JVET_AG0328 +SEIFilmGrainRegionsCharacteristics::SEIFilmGrainRegionsCharacteristics(const SEIFilmGrainRegionsCharacteristics& sei) +{ + m_filmGrainRegionsCharacteristicsCancelFlag = sei.m_filmGrainRegionsCharacteristicsCancelFlag; + m_filmGrainRegionsModelId = sei.m_filmGrainRegionsModelId; + m_fgr_separateColourDescriptionPresentFlag = sei.m_fgr_separateColourDescriptionPresentFlag; + m_filmGrainRegionsBitDepthLumaMinus8 = sei.m_filmGrainRegionsBitDepthLumaMinus8; + m_filmGrainRegionsBitDepthChromaMinus8 = sei.m_filmGrainRegionsBitDepthChromaMinus8; + m_filmGrainRegionsFullRangeFlag = sei.m_filmGrainRegionsFullRangeFlag; + m_filmGrainRegionsColourPrimaries = sei.m_filmGrainRegionsColourPrimaries; + m_filmGrainRegionsTransferCharacteristics = sei.m_filmGrainRegionsTransferCharacteristics; + m_filmGrainRegionsMatrixCoeffs = sei.m_filmGrainRegionsMatrixCoeffs; + m_fgr_blendingModeId = sei.m_fgr_blendingModeId; + m_fgr_log2ScaleFactor = sei.m_fgr_log2ScaleFactor; + for (int i = 0; i < MAX_NUM_COMPONENT; i++) + { + m_fgr_compModel[i].presentFlag = sei.m_fgr_compModel[i].presentFlag; + m_fgr_compModel[i].numModelValues = sei.m_fgr_compModel[i].numModelValues; + m_fgr_compModel[i].numIntensityIntervals = sei.m_fgr_compModel[i].numIntensityIntervals; + m_fgr_compModel[i].intensityValues = sei.m_fgr_compModel[i].intensityValues; + } + m_filmGrainRegionsCharacteristicsPersistenceFlag = sei.m_filmGrainRegionsCharacteristicsPersistenceFlag; + + // region-based specific parameters + m_fgr_region_information_present_flag = sei.m_fgr_region_information_present_flag; + m_fgr_region_based_adaptation_flag = sei.m_fgr_region_based_adaptation_flag; + m_fgr_active_regions_number = sei.m_fgr_active_regions_number; + if(m_fgr_region_based_adaptation_flag) + { + fgr_active_regions.resize(m_fgr_active_regions_number); + for (int regionId = 0 ; regionId < m_fgr_active_regions_number ; regionId++) + { + fgr_active_regions[regionId].m_fgr_region_top = sei.fgr_active_regions[regionId].m_fgr_region_top; + fgr_active_regions[regionId].m_fgr_region_left = sei.fgr_active_regions[regionId].m_fgr_region_left; + fgr_active_regions[regionId].m_fgr_region_width = sei.fgr_active_regions[regionId].m_fgr_region_width; + fgr_active_regions[regionId].m_fgr_region_height = sei.fgr_active_regions[regionId].m_fgr_region_height; + fgr_active_regions[regionId].m_film_grain_enabled_flag = sei.fgr_active_regions[regionId].m_film_grain_enabled_flag; + for (int i = 0; i < MAX_NUM_COMPONENT; i++) + { + fgr_active_regions[regionId].m_fgr_regionIntervals[i].m_fgr_region_interval_min = sei.fgr_active_regions[regionId].m_fgr_regionIntervals[i].m_fgr_region_interval_min; + fgr_active_regions[regionId].m_fgr_regionIntervals[i].m_fgr_region_interval_max = sei.fgr_active_regions[regionId].m_fgr_regionIntervals[i].m_fgr_region_interval_max; + } + } + } + m_fgr_alpha_channel_adaptation_flag = sei.m_fgr_alpha_channel_adaptation_flag; +} +#endif + SEIContentLightLevelInfo::SEIContentLightLevelInfo(const SEIContentLightLevelInfo& sei) { m_maxContentLightLevel = sei.m_maxContentLightLevel; diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h index 3396d9b53..7d26d8d95 100644 --- a/source/Lib/CommonLib/SEI.h +++ b/source/Lib/CommonLib/SEI.h @@ -102,6 +102,9 @@ public: SEI_PROCESSING_ORDER = 213, #if JVET_AF0310_PO_NESTING SEI_PROCESSING_ORDER_NESTING = 214, +#endif +#if JVET_AG0328 + FILM_GRAIN_REGIONS_CHARACTERISTICS = 215, //arbitrary paylaod type number, to be decided by JVET #endif }; @@ -188,6 +191,9 @@ public: switch (payloadType) { case SEI::PayloadType::FILM_GRAIN_CHARACTERISTICS: +#if JVET_AG0328 + case SEI::PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS: +#endif case SEI::PayloadType::POST_FILTER_HINT: case SEI::PayloadType::CONTENT_LIGHT_LEVEL_INFO: case SEI::PayloadType::NEURAL_NETWORK_POST_FILTER_CHARACTERISTICS: @@ -999,6 +1005,75 @@ public: bool m_filmGrainCharacteristicsPersistenceFlag; }; +#if JVET_AG0328 +class SEIFilmGrainRegionsCharacteristics : public SEI +{ +public: + PayloadType payloadType() const { return PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS; } + + SEIFilmGrainRegionsCharacteristics() {} + SEIFilmGrainRegionsCharacteristics(const SEIFilmGrainRegionsCharacteristics& sei); + virtual ~SEIFilmGrainRegionsCharacteristics() {} + + bool m_filmGrainRegionsCharacteristicsCancelFlag; + uint8_t m_filmGrainRegionsModelId; + bool m_fgr_separateColourDescriptionPresentFlag; + uint8_t m_filmGrainRegionsBitDepthLumaMinus8; + uint8_t m_filmGrainRegionsBitDepthChromaMinus8; + bool m_filmGrainRegionsFullRangeFlag; + uint8_t m_filmGrainRegionsColourPrimaries; + uint8_t m_filmGrainRegionsTransferCharacteristics; + uint8_t m_filmGrainRegionsMatrixCoeffs; + uint8_t m_fgr_blendingModeId; + uint8_t m_fgr_log2ScaleFactor; + + struct CompModelIntensityValues + { + uint8_t intensityIntervalLowerBound; + uint8_t intensityIntervalUpperBound; + std::vector compModelValue; + }; + + struct CompModel + { + bool presentFlag; + uint8_t numModelValues; + uint8_t numIntensityIntervals; + std::vector intensityValues; + }; + + CompModel m_fgr_compModel[MAX_NUM_COMPONENT]; + + // Region-based specific parameters + bool m_fgr_region_information_present_flag; + bool m_fgr_region_based_adaptation_flag; + uint8_t m_fgr_active_regions_number; + + struct RegionIntervals + { + uint16_t m_fgr_region_interval_min; + uint16_t m_fgr_region_interval_max; + }; + + struct RegionCharacteristics + { + uint16_t m_fgr_region_top; + uint16_t m_fgr_region_left; + uint16_t m_fgr_region_width; + uint16_t m_fgr_region_height; + bool m_film_grain_enabled_flag; + RegionIntervals m_fgr_regionIntervals[MAX_NUM_COMPONENT]; + }; + + std::vector fgr_active_regions; + + // option 2 alpha mask + bool m_fgr_alpha_channel_adaptation_flag; + + bool m_filmGrainRegionsCharacteristicsPersistenceFlag; +}; +#endif + class SEIContentLightLevelInfo : public SEI { public: diff --git a/source/Lib/CommonLib/SEIFilmGrainSynthesizer.cpp b/source/Lib/CommonLib/SEIFilmGrainSynthesizer.cpp index a68ac0d3b..6b41dd510 100644 --- a/source/Lib/CommonLib/SEIFilmGrainSynthesizer.cpp +++ b/source/Lib/CommonLib/SEIFilmGrainSynthesizer.cpp @@ -1261,3 +1261,1337 @@ uint32_t SEIFilmGrainSynthesizer::fgsSimulationBlending_32x32(fgsProcessArgs *in return FGS_SUCCESS; } +#if JVET_AG0328 +SEIFilmGrainRegionsSynthesizer::SEIFilmGrainRegionsSynthesizer() + : m_width(0) + , m_height(0) + , m_chromaFormat(ChromaFormat::UNDEFINED) + , m_bitDepth(0) + , m_idrPicId(0) + , m_grainSynt(nullptr) + , m_fgsBlkSize(8) + , m_poc(0) + , m_errorCode(0) + , m_fgrParameters(nullptr) +{ + +} + +void SEIFilmGrainRegionsSynthesizer::create(uint32_t width, uint32_t height, ChromaFormat fmt, uint8_t bitDepth, uint32_t idrPicId) +{ + m_width = width; + m_height = height; + m_chromaFormat = fmt; + m_bitDepth = bitDepth; + m_idrPicId = idrPicId; + m_fgsBlkSize = 8; + m_errorCode = 0; + int extended_height = ((height >> 5) + ((height & 0x1F) ? 1 : 0)) << 5; + + if (!m_grainSynt) + m_grainSynt = new GrainSynthesisStruct; + if (!m_fgrParameters) + m_fgrParameters = new SEIFilmGrainRegionsCharacteristics; + // test allocation map of FGS enabled map + m_fgrArgs.fgr_grain_enabled_map.resize(width * extended_height); + // test allocation map of intervals min/max map + for (int i = 0 ; i < MAX_NUM_COMPONENT; i++) + { + m_fgrArgs.fgr_regionIntervals_min_map[i].resize(width * extended_height); + m_fgrArgs.fgr_regionIntervals_max_map[i].resize(width * extended_height); + } +} + +SEIFilmGrainRegionsSynthesizer::~SEIFilmGrainRegionsSynthesizer() +{ + destroy(); +} + +void SEIFilmGrainRegionsSynthesizer::fgrInit() +{ + deriveFGSBlkSize(); + dataBaseGen(); +} + +void SEIFilmGrainRegionsSynthesizer::destroy() +{ + if (m_fgrParameters) + delete m_fgrParameters; + if (m_grainSynt) + delete m_grainSynt; +} + +void SEIFilmGrainRegionsSynthesizer::grainSynthesizeAndBlend(PelStorage* pGrainBuf, bool isIdrPic) +{ + uint8_t compCtr; /* number of color components */ + uint8_t color_offset[MAX_NUM_COMPONENT]; + uint32_t widthComp[MAX_NUM_COMPONENT], heightComp[MAX_NUM_COMPONENT]; + ptrdiff_t strideComp[MAX_NUM_COMPONENT]; + uint32_t * offsetsArr[MAX_NUM_COMPONENT]; + Pel * decComp[MAX_NUM_COMPONENT]; + uint32_t pseudoRandValEc; + uint32_t picOffset; + + /* from SMPTE RDD5 */ + color_offset[0] = COLOUR_OFFSET_LUMA; + color_offset[1] = COLOUR_OFFSET_CR; + color_offset[2] = COLOUR_OFFSET_CB; + + if (0 != m_fgrParameters->m_filmGrainRegionsCharacteristicsCancelFlag) + { + return; + } + + const int numComp = getNumberValidComponents(m_chromaFormat); + + widthComp[0] = m_width; + heightComp[0] = m_height; + + if (ChromaFormat::_420 == m_chromaFormat) + { + widthComp[1] = (m_width >> 1); + widthComp[2] = (m_width >> 1); + heightComp[1] = (m_height >> 1); + heightComp[2] = (m_height >> 1); + } + else if (ChromaFormat::_422 == m_chromaFormat) + { + widthComp[1] = (m_width >> 1); + widthComp[2] = (m_width >> 1); + heightComp[1] = m_height; + heightComp[2] = m_height; + } + + /*Allocate memory for offsets assuming 16x16 block size, + 32x32 will need lesser than this*/ + uint32_t maxNumBlocks = ((m_width >> 4) + 1) * ((m_height >> 4) + 1); + + for (compCtr = 0; compCtr < numComp; compCtr++) + { + offsetsArr[compCtr] = new uint32_t[maxNumBlocks]; + } + + decComp[0] = pGrainBuf->bufs[0].buf; + decComp[1] = pGrainBuf->bufs[1].buf; + decComp[2] = pGrainBuf->bufs[2].buf; + + /* component strides */ + strideComp[0] = pGrainBuf->bufs[0].stride; + strideComp[1] = 0; + strideComp[2] = 0; + + if (isChromaEnabled(m_chromaFormat)) + { + strideComp[1] = pGrainBuf->bufs[1].stride; + strideComp[2] = pGrainBuf->bufs[2].stride; + } + + int32_t numBlks_x[MAX_NUM_COMPONENT]; + int32_t numBlks_y[MAX_NUM_COMPONENT]; + + picOffset = m_poc; + for (compCtr = 0; compCtr < numComp; compCtr++) + { + if (BLK_32 == m_fgsBlkSize) + { + numBlks_x[compCtr] = (widthComp[compCtr] >> 5) + ((widthComp[compCtr] & 0x1F) ? 1 : 0); + numBlks_y[compCtr] = (heightComp[compCtr] >> 5) + ((heightComp[compCtr] & 0x1F) ? 1 : 0); + } + else + { + numBlks_x[compCtr] = (widthComp[compCtr] >> 4) + ((widthComp[compCtr] & 0xF) ? 1 : 0); + numBlks_y[compCtr] = (heightComp[compCtr] >> 4) + ((heightComp[compCtr] & 0xF) ? 1 : 0); + } + } + for (compCtr = 0; compCtr < numComp; compCtr++) + { + if (1 == m_fgrParameters->m_fgr_compModel[compCtr].presentFlag) + { + uint32_t *tmp = offsetsArr[compCtr]; + int i, j; + + /* Seed initialization for current picture*/ + pseudoRandValEc = seedLUT[((picOffset + color_offset[compCtr]) & 0xFF)]; + + for (i = 0; i < numBlks_y[compCtr]; i++) + { + for (j = 0; j < numBlks_x[compCtr]; j++) + { + *tmp = pseudoRandValEc; + pseudoRandValEc = prng(pseudoRandValEc); + tmp++; + } + } + } + } + + m_fgrArgs.numComp = numComp; + for (compCtr = 0; compCtr < numComp; compCtr++) + { + if (1 == m_fgrParameters->m_fgr_compModel[compCtr].presentFlag) + { + m_fgrArgs.decComp[compCtr] = decComp[compCtr]; + m_fgrArgs.widthComp[compCtr] = widthComp[compCtr]; + m_fgrArgs.strideComp[compCtr] = strideComp[compCtr]; + m_fgrArgs.fgsOffsets[compCtr] = offsetsArr[compCtr]; + + if (BLK_32 == m_fgsBlkSize) + { + m_fgrArgs.heightComp[compCtr] = numBlks_y[compCtr] * BLK_32; + } + else + { + m_fgrArgs.heightComp[compCtr] = numBlks_y[compCtr] * BLK_16; + } + } + } + m_fgrArgs.pFgrParameters = m_fgrParameters; + m_fgrArgs.blkSize = m_fgsBlkSize; + m_fgrArgs.bitDepth = m_bitDepth; + m_fgrArgs.pGrainSynt = m_grainSynt; + + int extended_height = ((m_height >> 5) + ((m_height & 0x1F) ? 1 : 0)) << 5; + + //region based maps setting + if (m_fgrParameters->m_fgr_region_based_adaptation_flag) + { + // -------FILM GRAIN ENABLED FLAG-------- + for (int j = 0; j < extended_height; j++) + { + for (int i = 0; i < m_width; i++) + { + m_fgrArgs.fgr_grain_enabled_map[j*m_width+i] = true; + for (int k = 0 ; k < m_fgrParameters->m_fgr_active_regions_number; k++) + { + if ((i >= m_fgrParameters->fgr_active_regions[k].m_fgr_region_left) && + (i < m_fgrParameters->fgr_active_regions[k].m_fgr_region_left+m_fgrParameters->fgr_active_regions[k].m_fgr_region_width) && + (j >= m_fgrParameters->fgr_active_regions[k].m_fgr_region_top) && + (j < m_fgrParameters->fgr_active_regions[k].m_fgr_region_top+m_fgrParameters->fgr_active_regions[k].m_fgr_region_height)) + { + m_fgrArgs.fgr_grain_enabled_map[j * m_width + i] = m_fgrParameters->fgr_active_regions[k].m_film_grain_enabled_flag; + } + } + } + } + + + // -------FILM GRAIN MIN/MAX INTERVALS -------- + for (int i = 0; i < m_width; i++) + { + for (int j = 0; j < extended_height; j++) + { + for (compCtr = 0; compCtr < numComp; compCtr++) + { + m_fgrArgs.fgr_regionIntervals_min_map[compCtr][j * m_width + i] = 0; + m_fgrArgs.fgr_regionIntervals_max_map[compCtr][j * m_width + i] = (int)m_fgrArgs.pFgrParameters->m_fgr_compModel[compCtr].intensityValues.size() - 1; + + for (int k = 0 ; k < m_fgrParameters->m_fgr_active_regions_number; k++) + { + if ((i >= m_fgrParameters->fgr_active_regions[k].m_fgr_region_left) && + (i < m_fgrParameters->fgr_active_regions[k].m_fgr_region_left+ m_fgrParameters->fgr_active_regions[k].m_fgr_region_width) && + (j >= m_fgrParameters->fgr_active_regions[k].m_fgr_region_top) && + (j < m_fgrParameters->fgr_active_regions[k].m_fgr_region_top+m_fgrParameters->fgr_active_regions[k].m_fgr_region_height)) + { + m_fgrArgs.fgr_regionIntervals_min_map[compCtr][j*m_width+i] = m_fgrParameters->fgr_active_regions[k].m_fgr_regionIntervals[compCtr].m_fgr_region_interval_min; + m_fgrArgs.fgr_regionIntervals_max_map[compCtr][j*m_width+i] = m_fgrParameters->fgr_active_regions[k].m_fgr_regionIntervals[compCtr].m_fgr_region_interval_max; + } + } + } + } + } + if (ChromaFormat::_420 == m_chromaFormat) + { + heightComp[1] = extended_height / 2; + heightComp[2] = extended_height / 2; + for (int i = 0 ; i < widthComp[2] ; i++) + { + for (int j = 0; j < heightComp[2]; j++) + { + for (compCtr = 1; compCtr < numComp; compCtr++) + { + m_fgrArgs.fgr_regionIntervals_min_map[compCtr][j*widthComp[2]+i] = m_fgrArgs.fgr_regionIntervals_min_map[compCtr][j*2*widthComp[2]*2+i*2]; + m_fgrArgs.fgr_regionIntervals_max_map[compCtr][j*widthComp[2]+i] = m_fgrArgs.fgr_regionIntervals_max_map[compCtr][j*2*widthComp[2]*2+i*2]; + } + } + } + } + else if (ChromaFormat::_422 == m_chromaFormat) + { + widthComp[1] = (m_width >> 1); + widthComp[2] = (m_width >> 1); + heightComp[1] = m_height; + heightComp[2] = m_height; + heightComp[1] = extended_height; + heightComp[2] = extended_height; + for (int i = 0 ; i < widthComp[2] ; i++) + { + for (int j = 0 ; j < heightComp[2] ; j++) + { + for (compCtr = 1; compCtr < numComp; compCtr++) + { + m_fgrArgs.fgr_regionIntervals_min_map[compCtr][j*widthComp[2]+i] = m_fgrArgs.fgr_regionIntervals_min_map[compCtr][j*widthComp[2]+i*2]; + m_fgrArgs.fgr_regionIntervals_max_map[compCtr][j*widthComp[2]+i] = m_fgrArgs.fgr_regionIntervals_max_map[compCtr][j*widthComp[2]+i*2]; + } + } + } + } + } + + fgrProcess(m_fgrArgs); + + for (compCtr = 0; compCtr < numComp; compCtr++) + { + delete offsetsArr[compCtr]; + } + return; +} + +/* Function validates film grain parameters and returns 0 for valid parameters of SMPTE-RDD5 else 1*/ +/* Also down converts the chroma model values for 4:2:0 and 4:2:2 chroma_formats */ +uint8_t SEIFilmGrainRegionsSynthesizer::grainValidateParams() +{ + uint8_t compCtr, intensityCtr, multiGrainCheck[MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES] = { { 0 } }; + uint16_t multiGrainCtr; + uint8_t limitCompModelVal1[10] = { 0 }, limitCompModelVal2[10] = { 0 }; + uint8_t num_comp_model_pairs = 0, limitCompModelCtr, compPairMatch; + + memset(m_grainSynt->intensityInterval, INTENSITY_INTERVAL_MATCH_FAIL, sizeof(m_grainSynt->intensityInterval)); + + if ((m_width < MIN_WIDTH) || (m_width > MAX_WIDTH) || (m_width % 4)) + { + return FGS_INVALID_WIDTH; /* Width not supported */ + } + if ((m_height < MIN_HEIGHT) || (m_height > MAX_HEIGHT) || (m_height % 4)) + { + return FGS_INVALID_HEIGHT; /* Height not supported */ + } + if (m_chromaFormat == ChromaFormat::UNDEFINED) + { + return FGS_INVALID_CHROMA_FORMAT; /* Chroma format not supported */ + } + const int numComp = getNumberValidComponents(m_chromaFormat); + + if ((m_bitDepth < MIN_BIT_DEPTH) || (m_bitDepth > MAX_BIT_DEPTH)) + { + return FGS_INVALID_BIT_DEPTH; /* Bit depth not supported */ + } + + if ((0 != m_fgrParameters->m_filmGrainRegionsCharacteristicsCancelFlag) && + (1 != m_fgrParameters->m_filmGrainRegionsCharacteristicsCancelFlag)) + { + return FGS_INVALID_FGC_CANCEL_FLAG; /* Film grain synthesis disabled */ + } + + if (FILM_GRAIN_MODEL_ID_VALUE != m_fgrParameters->m_filmGrainRegionsModelId) + { + return FGS_INVALID_GRAIN_MODEL_ID; /* Not supported */ + } + + if (0 != m_fgrParameters->m_fgr_separateColourDescriptionPresentFlag) + { + return FGS_INVALID_SEP_COL_DES_FLAG; /* Not supported */ + } + + if (BLENDING_MODE_VALUE != m_fgrParameters->m_fgr_blendingModeId) + { + return FGS_INVALID_BLEND_MODE; /* Not supported */ + } + + if (m_fgrParameters->m_fgr_compModel[0].presentFlag || m_fgrParameters->m_fgr_compModel[1].presentFlag || m_fgrParameters->m_fgr_compModel[2].presentFlag) { + if ((m_fgrParameters->m_fgr_log2ScaleFactor < MIN_LOG2SCALE_VALUE) || + (m_fgrParameters->m_fgr_log2ScaleFactor > MAX_LOG2SCALE_VALUE)) + { + return FGS_INVALID_LOG2_SCALE_FACTOR; /* Not supported */ + } + } + + /* validation of component model present flag */ + for (compCtr = 0; compCtr < numComp; compCtr++) + { + if ((m_fgrParameters->m_fgr_compModel[compCtr].presentFlag != true) && + (m_fgrParameters->m_fgr_compModel[compCtr].presentFlag != false)) + { + return FGS_INVALID_COMP_MODEL_PRESENT_FLAG; /* Not supported */ + } + + if (m_fgrParameters->m_fgr_compModel[compCtr].presentFlag && + (m_fgrParameters->m_fgr_compModel[compCtr].numModelValues > MAX_ALLOWED_MODEL_VALUES)) + { + return FGS_INVALID_NUM_MODEL_VALUES; /* Not supported */ + } + } + + /* validation of intensity intervals and */ + for (compCtr = 0; compCtr < numComp; compCtr++) + { + if (m_fgrParameters->m_fgr_compModel[compCtr].presentFlag) + { + for (intensityCtr = 0; intensityCtr < m_fgrParameters->m_fgr_compModel[compCtr].intensityValues.size(); intensityCtr++) + { + if (m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].intensityIntervalLowerBound > + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].intensityIntervalUpperBound) + { + return FGS_INVALID_INTENSITY_BOUNDARY_VALUES; /* Not supported */ + } + + for (multiGrainCtr = m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].intensityIntervalLowerBound; + multiGrainCtr <= m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].intensityIntervalUpperBound; multiGrainCtr++) + { + m_grainSynt->intensityInterval[compCtr][multiGrainCtr] = intensityCtr; + if (multiGrainCheck[compCtr][multiGrainCtr]) /* Non over lap */ + { + return FGS_INVALID_INTENSITY_BOUNDARY_VALUES; /* Not supported */ + } + else + { + multiGrainCheck[compCtr][multiGrainCtr] = 1; + } + } + + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue.resize(MAX_NUM_MODEL_VALUES); + /* default initialization for cut off frequencies */ + if (1 == m_fgrParameters->m_fgr_compModel[compCtr].numModelValues) + { + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] = DEFAULT_HORZ_CUT_OFF_FREQUENCY; + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] = m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1]; + } + else if (2 == m_fgrParameters->m_fgr_compModel[compCtr].numModelValues) + { + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] = m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1]; + } + + /* Error check on model component value */ + if (m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[0] > (MAX_STANDARD_DEVIATION << (m_bitDepth - BIT_DEPTH_8))) + { + return FGS_INVALID_STANDARD_DEVIATION; /* Not supported */ + } + else if ((m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] < MIN_CUT_OFF_FREQUENCY) || + (m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] > MAX_CUT_OFF_FREQUENCY)) + { + return FGS_INVALID_CUT_OFF_FREQUENCIES; /* Not supported */ + } + else if ((m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] < MIN_CUT_OFF_FREQUENCY) || + (m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] > MAX_CUT_OFF_FREQUENCY)) + { + return FGS_INVALID_CUT_OFF_FREQUENCIES; /* Not supported */ + } + + /* conversion of component model values for 4:2:0 and 4:4:4 */ + if (ChromaFormat::_444 != m_chromaFormat && (compCtr > 0)) + { + if (ChromaFormat::_420 == m_chromaFormat) /* 4:2:0 */ + { + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[0] >>= 1; + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] = + CLIP3(MIN_CUT_OFF_FREQUENCY, MAX_CUT_OFF_FREQUENCY, + (m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] << 1)); + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] = + CLIP3(MIN_CUT_OFF_FREQUENCY, MAX_CUT_OFF_FREQUENCY, + (m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] << 1)); + + } + else if (ChromaFormat::_422 == m_chromaFormat) /* 4:2:2 */ + { + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[0] = + (m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[0] * SCALE_DOWN_422) >> Q_FORMAT_SCALING; + + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] = + CLIP3(MIN_CUT_OFF_FREQUENCY, MAX_CUT_OFF_FREQUENCY, + (m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] << 1)); + } + } + + compPairMatch = 0; + for (limitCompModelCtr = 0; limitCompModelCtr <= num_comp_model_pairs; limitCompModelCtr++) + { + if ((limitCompModelVal1[limitCompModelCtr] == + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1]) && + (limitCompModelVal2[limitCompModelCtr] == + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2])) + { + compPairMatch = 1; + } + } + + if (0 == compPairMatch) + { + num_comp_model_pairs++; + /* max allowed pairs are 10 as per SMPTE -RDD5*/ + if (num_comp_model_pairs > MAX_ALLOWED_COMP_MODEL_PAIRS) + { + return FGS_INVALID_NUM_CUT_OFF_FREQ_PAIRS; /* Not supported */ + } + limitCompModelVal1[num_comp_model_pairs - 1] = + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1]; + limitCompModelVal2[num_comp_model_pairs - 1] = + m_fgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2]; + } + } + } + } + return FGS_SUCCESS; /* Success */ +} + + + + +void SEIFilmGrainRegionsSynthesizer::deriveFGSBlkSize() +{ + uint32_t picSizeInLumaSamples = m_height * m_width; + if (picSizeInLumaSamples <= (1920 * 1080)) + { + m_fgsBlkSize = BLK_8; + } + else if (picSizeInLumaSamples <= (3840 * 2160)) + { + m_fgsBlkSize = BLK_16; + } + else + { + m_fgsBlkSize = BLK_32; + } +} +void SEIFilmGrainRegionsSynthesizer::dataBaseGen() +{ + uint32_t pseudoRandValEhv; + uint8_t h, v; /* Horizaontal and vertical cut off frequencies (+2)*/ + uint32_t ScaleCutOffFh, ScaleCutOffFv, l, r, i, j, k; + int32_t B[DATA_BASE_SIZE][DATA_BASE_SIZE], IDCT[DATA_BASE_SIZE][DATA_BASE_SIZE]; + int32_t Grain[DATA_BASE_SIZE][DATA_BASE_SIZE]; + + const TMatrixCoeff* Tmp = g_trCoreDCT2P64[TRANSFORM_FORWARD][0]; + const int transform_scale = 9; // upscaling of original transform as specified in VVC (for 64x64 block) + const int add_1st = 1 << (transform_scale - 1); + + TMatrixCoeff T[DATA_BASE_SIZE][DATA_BASE_SIZE]; // Original + TMatrixCoeff TT[DATA_BASE_SIZE][DATA_BASE_SIZE]; // Transpose + for (int x = 0; x < DATA_BASE_SIZE; x++) + { + for (int y = 0; y < DATA_BASE_SIZE; y++) + { + T[x][y] = Tmp[x * 64 + y]; /* Matrix Original */ + TT[y][x] = Tmp[x * 64 + y]; /* Matrix Transpose */ + } + } + + for (h = 0; h < NUM_CUT_OFF_FREQ; h++) + { + for (v = 0; v < NUM_CUT_OFF_FREQ; v++) + { + memset(&B, 0, DATA_BASE_SIZE*DATA_BASE_SIZE * sizeof(int32_t)); + memset(&IDCT, 0, DATA_BASE_SIZE*DATA_BASE_SIZE * sizeof(int32_t)); + memset(&Grain, 0, DATA_BASE_SIZE*DATA_BASE_SIZE * sizeof(int32_t)); + ScaleCutOffFh = ((h + 3) << 2) - 1; + ScaleCutOffFv = ((v + 3) << 2) - 1; + + /* ehv : seed to be used for the psudo random generator for a given h and v */ + pseudoRandValEhv = seedLUT[h + v * 13]; + + for (l = 0, r = 0; l <= ScaleCutOffFv; l++) + { + for (k = 0; k <= ScaleCutOffFh; k += 4) + { + B[k][l] = gaussianLUT[pseudoRandValEhv % 2048]; + B[k + 1][l] = gaussianLUT[(pseudoRandValEhv + 1) % 2048]; + B[k + 2][l] = gaussianLUT[(pseudoRandValEhv + 2) % 2048]; + B[k + 3][l] = gaussianLUT[(pseudoRandValEhv + 3) % 2048]; + r++; + pseudoRandValEhv = prng(pseudoRandValEhv); + } + } + B[0][0] = 0; + + for (i = 0; i < DATA_BASE_SIZE; i++) + { + for (j = 0; j < DATA_BASE_SIZE; j++) + { + for (k = 0; k < DATA_BASE_SIZE; k++) + { + IDCT[i][j] += TT[i][k] * B[k][j]; + } + IDCT[i][j] += add_1st; + IDCT[i][j] = IDCT[i][j] >> transform_scale; + } + } + + for (i = 0; i < DATA_BASE_SIZE; i++) + { + for (j = 0; j < DATA_BASE_SIZE; j++) + { + for (k = 0; k < DATA_BASE_SIZE; k++) + { + Grain[i][j] += IDCT[i][k] * T[k][j]; + } + Grain[i][j] += add_1st; + Grain[i][j] = Grain[i][j] >> transform_scale; + m_grainSynt->dataBase[h][v][j][i] = CLIP3(-127, 127, Grain[i][j]); + } + } + + /* De-blocking at horizontal block edges */ + for (l = 0; l < DATA_BASE_SIZE; l += m_fgsBlkSize) + { + for (k = 0; k < DATA_BASE_SIZE; k++) + { + m_grainSynt->dataBase[h][v][l][k] = ((m_grainSynt->dataBase[h][v][l][k]) * deblockFactor[v]) >> 7; + m_grainSynt->dataBase[h][v][l + m_fgsBlkSize - 1][k] = ((m_grainSynt->dataBase[h][v][l + m_fgsBlkSize - 1][k]) * deblockFactor[v]) >> 7; + } + } + } + } + return; +} + +uint32_t SEIFilmGrainRegionsSynthesizer::prng(uint32_t x_r) +{ + uint32_t addVal; + addVal = (1 + ((x_r & (POS_2)) > 0) + ((x_r & (POS_30)) > 0)) % 2; + x_r = (x_r << 1) + addVal; + return x_r; +} + +uint32_t SEIFilmGrainRegionsSynthesizer::fgrProcess(fgrProcessArgs &inArgs) +{ + uint32_t errorCode; + uint8_t blkSize = inArgs.blkSize; + if (blkSize == 8) + errorCode = fgrSimulationBlending_8x8(&inArgs); + else if (blkSize == 16) + errorCode = fgrSimulationBlending_16x16(&inArgs); + else if (blkSize == 32) + errorCode = fgrSimulationBlending_32x32(&inArgs); + else + errorCode = FGS_FAIL; + + return errorCode; +} + +void SEIFilmGrainRegionsSynthesizer::deblockGrainStripe(Pel *grainStripe, uint32_t widthComp, uint32_t heightComp, + uint32_t strideComp, uint32_t blkSize) +{ + int32_t left1, left0, right0, right1; + uint32_t pos, vertCtr; + + uint32_t widthCropped = (widthComp - blkSize); + + for (vertCtr = 0; vertCtr < heightComp; vertCtr++) + { + for (pos = 0; pos < widthCropped; pos += blkSize) + { + left1 = *(grainStripe + blkSize - 2); + left0 = *(grainStripe + blkSize - 1); + right0 = *(grainStripe + blkSize + 0); + right1 = *(grainStripe + blkSize + 1); + *(grainStripe + blkSize + 0) = (left0 + (right0 << 1) + right1) >> 2; + *(grainStripe + blkSize - 1) = (left1 + (left0 << 1) + right0) >> 2; + grainStripe += blkSize; + } + grainStripe = grainStripe + (strideComp - pos); + } + return; +} + +void SEIFilmGrainRegionsSynthesizer::blendStripe(Pel *decSampleHbdOffsetY, Pel *grainStripe, uint32_t widthComp, + ptrdiff_t strideSrc, ptrdiff_t strideGrain, uint32_t blockHeight, + uint8_t bitDepth, uint32_t offset_in_map,std::vector fgr_grain_enabled_map, uint32_t CompFactor) +{ + uint32_t k, l; + uint16_t maxRange; + maxRange = (1 << bitDepth) - 1; + + int32_t grainSample; + uint16_t decodeSampleHbd; + uint8_t bitDepthShift = (bitDepth - BIT_DEPTH_8); + ptrdiff_t bufInc = (strideSrc - widthComp); + ptrdiff_t grainBufInc = (strideGrain - widthComp); + if (CompFactor==1) + { + for (l = 0; l < blockHeight; l++) // y direction + { + for (k = 0; k < widthComp; k++) // x direction + { + decodeSampleHbd = *decSampleHbdOffsetY; + grainSample = *grainStripe; + grainSample <<= bitDepthShift; + grainSample = CLIP3(0, maxRange, grainSample + decodeSampleHbd); + if (fgr_grain_enabled_map[(offset_in_map + l*widthComp + k)]) + *decSampleHbdOffsetY = (Pel)grainSample; + //else + // *decSampleHbdOffsetY = (Pel)0; /debud mask + decSampleHbdOffsetY++; + grainStripe++; + } + decSampleHbdOffsetY += bufInc; + grainStripe += grainBufInc; + } + + } + else + { + for (l = 0; l < blockHeight; l++) // y direction + { + for (k = 0; k < widthComp; k++) // x direction + { + decodeSampleHbd = *decSampleHbdOffsetY; + grainSample = *grainStripe; + grainSample <<= bitDepthShift; + grainSample = CLIP3(0, maxRange, grainSample + decodeSampleHbd); + if (fgr_grain_enabled_map[(offset_in_map + ((l*CompFactor)*(widthComp*CompFactor) + k*CompFactor))]) + *decSampleHbdOffsetY = (Pel)grainSample; + // else + // *decSampleHbdOffsetY = (Pel)0; //debug mask + decSampleHbdOffsetY++; + grainStripe++; + } + decSampleHbdOffsetY += bufInc; + grainStripe += grainBufInc; + } + } + return; +} + +void SEIFilmGrainRegionsSynthesizer::blendStripe_32x32(Pel *decSampleHbdOffsetY, Pel *grainStripe, uint32_t widthComp, + ptrdiff_t strideSrc, ptrdiff_t strideGrain, uint32_t blockHeight, + uint8_t bitDepth, uint32_t offset_in_map,std::vector fgr_grain_enabled_map, uint32_t CompFactor) +{ + uint32_t k, l; + uint16_t maxRange; + maxRange = (1 << bitDepth) - 1; + + int32_t grainSample; + uint16_t decodeSampleHbd; + uint8_t bitDepthShift = (bitDepth - BIT_DEPTH_8); + ptrdiff_t bufInc = (strideSrc - widthComp); + ptrdiff_t grainBufInc = (strideGrain - widthComp); + + if (CompFactor==1) + { + for (l = 0; l < blockHeight; l++) /* y direction */ + { + for (k = 0; k < widthComp; k++) /* x direction */ + { + decodeSampleHbd = *decSampleHbdOffsetY; + grainSample = *grainStripe; + grainSample <<= bitDepthShift; + grainSample = CLIP3(0, maxRange, grainSample + decodeSampleHbd); + if (fgr_grain_enabled_map[(offset_in_map + l*widthComp + k)]) + *decSampleHbdOffsetY = (Pel)grainSample; + // else + // *decSampleHbdOffsetY = (Pel)0; + decSampleHbdOffsetY++; + grainStripe++; + } + decSampleHbdOffsetY += bufInc; + grainStripe += grainBufInc; + } + + } + else + { + for (l = 0; l < blockHeight; l++) /* y direction */ + { + for (k = 0; k < widthComp; k++) /* x direction */ + { + decodeSampleHbd = *decSampleHbdOffsetY; + grainSample = *grainStripe; + grainSample <<= bitDepthShift; + grainSample = CLIP3(0, maxRange, grainSample + decodeSampleHbd); + if (fgr_grain_enabled_map[(offset_in_map*CompFactor*CompFactor + (l*widthComp*CompFactor + k)*CompFactor)]) + *decSampleHbdOffsetY = (Pel)grainSample; + //else + // *decSampleHbdOffsetY = (Pel)0; + decSampleHbdOffsetY++; + grainStripe++; + } + decSampleHbdOffsetY += bufInc; + grainStripe += grainBufInc; + } + } return; +} + +Pel SEIFilmGrainRegionsSynthesizer::blockAverage_8x8(Pel *decSampleBlk8, ptrdiff_t widthComp, uint16_t *pNumSamples, + uint8_t ySize, uint8_t xSize, uint8_t bitDepth) +{ + uint32_t blockAvg = 0; + uint8_t k; + uint8_t l; + + for (k = 0; k < ySize; k++) + { + for (l = 0; l < xSize; l++) + { + blockAvg += *decSampleBlk8; + decSampleBlk8++; + } + decSampleBlk8 += widthComp - xSize; + } + + blockAvg = blockAvg >> (BLK_8_shift + (bitDepth - BIT_DEPTH_8)); + *pNumSamples = BLK_AREA_8x8; + + return blockAvg; +} + +uint32_t SEIFilmGrainRegionsSynthesizer::blockAverage_16x16(Pel *decSampleBlk8, ptrdiff_t widthComp, uint16_t *pNumSamples, + uint8_t ySize, uint8_t xSize, uint8_t bitDepth) +{ + uint32_t blockAvg = 0; + uint8_t k; + uint8_t l; + for (k = 0; k < ySize; k++) + { + for (l = 0; l < xSize; l++) + { + blockAvg += *decSampleBlk8; + decSampleBlk8++; + } + decSampleBlk8 += widthComp - xSize; + } + + // blockAvg = blockAvg >> (BLK_16_shift + (bitDepth - BIT_DEPTH_8)); + // If BLK_16 is not used or changed BLK_AREA_16x16 has to be changed + *pNumSamples = BLK_AREA_16x16; + return blockAvg; +} + +uint32_t SEIFilmGrainRegionsSynthesizer::blockAverage_32x32(Pel *decSampleBlk32, ptrdiff_t strideComp, uint8_t bitDepth) +{ + uint32_t blockAvg = 0; + uint8_t k; + uint8_t l; + ptrdiff_t bufInc = strideComp - BLK_32; + for (k = 0; k < BLK_32; k++) + { + for (l = 0; l < BLK_32; l++) + { + blockAvg += *decSampleBlk32++; + } + decSampleBlk32 += bufInc; + } + blockAvg = blockAvg >> (BLK_32_shift + (bitDepth - BIT_DEPTH_8)); + return blockAvg; +} + +void SEIFilmGrainRegionsSynthesizer::simulateGrainBlk8x8(Pel *grainStripe, uint32_t grainStripeOffsetBlk8, + GrainSynthesisStruct *grain_synt, uint32_t width, + uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset, + uint32_t lOffset, uint8_t h, uint8_t v, uint32_t xSize) +{ + uint32_t l; + int8_t * database_h_v = &grain_synt->dataBase[h][v][lOffset][kOffset]; + grainStripe += grainStripeOffsetBlk8; + uint32_t k; + for (l = 0; l < BLK_8; l++) /* y direction */ + { + for (k = 0; k < xSize; k++) /* x direction */ + { + *grainStripe = ((scaleFactor * (*database_h_v)) >> (log2ScaleFactor + GRAIN_SCALE)); + grainStripe++; + database_h_v++; + } + grainStripe += width - xSize; + database_h_v += DATA_BASE_SIZE - xSize; + } + return; +} + +void SEIFilmGrainRegionsSynthesizer::simulateGrainBlk16x16(Pel *grainStripe, uint32_t grainStripeOffsetBlk8, + GrainSynthesisStruct *grain_synt, uint32_t width, + uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset, + uint32_t lOffset, uint8_t h, uint8_t v, uint32_t xSize) +{ + uint32_t l; + int8_t * database_h_v = &grain_synt->dataBase[h][v][lOffset][kOffset]; + grainStripe += grainStripeOffsetBlk8; + uint32_t k; + for (l = 0; l < BLK_16; l++) /* y direction */ + { + for (k = 0; k < xSize; k++) /* x direction */ + { + *grainStripe = (int16_t)(((int32_t)scaleFactor * (*database_h_v)) >> (log2ScaleFactor + GRAIN_SCALE)); + grainStripe++; + database_h_v++; + } + grainStripe += width - xSize; + database_h_v += DATA_BASE_SIZE - xSize; + } + return; +} + +void SEIFilmGrainRegionsSynthesizer::simulateGrainBlk32x32(Pel *grainStripe, uint32_t grainStripeOffsetBlk32, + GrainSynthesisStruct *grain_synt, uint32_t width, + uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset, + uint32_t lOffset, uint8_t h, uint8_t v) +{ + uint32_t l; + int8_t * database_h_v = &grain_synt->dataBase[h][v][lOffset][kOffset]; + grainStripe += grainStripeOffsetBlk32; + uint32_t k; + uint8_t shiftVal = log2ScaleFactor + GRAIN_SCALE; + uint32_t grainbufInc = width - BLK_32; + + for (l = 0; l < BLK_32; l++) /* y direction */ + { + for (k = 0; k < BLK_32; k++) /* x direction */ + { + *grainStripe = ((scaleFactor * (*database_h_v)) >> shiftVal); + grainStripe++; + database_h_v++; + } + grainStripe += grainbufInc; + database_h_v += DATA_BASE_SIZE - BLK_32; + } + return; +} + +uint32_t SEIFilmGrainRegionsSynthesizer::fgrSimulationBlending_8x8(fgrProcessArgs *inArgs) +{ + uint8_t numComp, compCtr, blkId; /* number of color components */ + uint8_t log2ScaleFactor, h, v; + uint8_t bitDepth; /*grain bit depth and decoded bit depth are assumed to be same */ + uint32_t widthComp[MAX_NUM_COMPONENT], heightComp[MAX_NUM_COMPONENT]; + ptrdiff_t strideComp[MAX_NUM_COMPONENT]; + Pel * decSampleHbdBlk16, *decSampleHbdBlk8, *decSampleHbdOffsetY; + Pel * decHbdComp[MAX_NUM_COMPONENT]; + uint16_t numSamples; + int16_t scaleFactor; + uint32_t kOffset, lOffset, grainStripeOffset, grainStripeOffsetBlk8; + ptrdiff_t offsetBlk8x8; + uint32_t kOffset_const, lOffset_const; + int16_t scaleFactor_const; + Pel * grainStripe; /* worth a row of 16x16 : Max size : 16xw;*/ + int32_t yOffset8x8, xOffset8x8; + uint32_t x, y; + uint32_t blockAvg, intensityInt; /* ec : seed to be used for the psudo random generator for a given color component */ + uint32_t grainStripeWidth; + uint32_t wdPadded; + + bitDepth = inArgs->bitDepth; + numComp = inArgs->numComp; + log2ScaleFactor = inArgs->pFgrParameters->m_fgr_log2ScaleFactor; + + for (compCtr = 0; compCtr < numComp; compCtr++) + { + decHbdComp[compCtr] = inArgs->decComp[compCtr]; + strideComp[compCtr] = inArgs->strideComp[compCtr]; + widthComp[compCtr] = inArgs->widthComp[compCtr]; + heightComp[compCtr] = inArgs->heightComp[compCtr]; + } + + wdPadded = ((inArgs->widthComp[0] - 1) | 0xF) + 1; + grainStripe = new Pel[wdPadded * BLK_16]; + + if (0 == inArgs->pFgrParameters->m_filmGrainRegionsCharacteristicsCancelFlag) + { + for (compCtr = 0; compCtr < numComp; compCtr++) + { + if (1 == inArgs->pFgrParameters->m_fgr_compModel[compCtr].presentFlag) + { + decSampleHbdOffsetY = decHbdComp[compCtr]; + uint32_t *offset_tmp = inArgs->fgsOffsets[compCtr]; + grainStripeWidth = ((widthComp[compCtr] - 1) | 0xF) + 1; // Make next muliptle of 16 + /* Loop of 16x16 blocks */ + for (y = 0; y < heightComp[compCtr]; y += BLK_16) + { + /* Initialization of grain stripe of 16xwidth size */ + memset(grainStripe, 0, (grainStripeWidth * BLK_16 * sizeof(Pel))); + for (x = 0; x < widthComp[compCtr]; x += BLK_16) + { + /* start position offset of decoded sample in x direction */ + grainStripeOffset = x; + + decSampleHbdBlk16 = decSampleHbdOffsetY + x; + + kOffset_const = (MSB16(*offset_tmp) % 52); + kOffset_const &= 0xFFFC; + + lOffset_const = (LSB16(*offset_tmp) % 56); + lOffset_const &= 0xFFF8; + scaleFactor_const = 1 - 2 * BIT0(*offset_tmp); + for (blkId = 0; blkId < NUM_8x8_BLKS_16x16; blkId++) + { + yOffset8x8 = (blkId >> 1) * BLK_8; + // printf("Y offset in block 8x8: %d ", yOffset8x8); + xOffset8x8 = (blkId & 0x1) * BLK_8; + // printf("X offset in block 8x8: %d \n", xOffset8x8); + offsetBlk8x8 = xOffset8x8 + (yOffset8x8 * strideComp[compCtr]); + + grainStripeOffsetBlk8 = grainStripeOffset + (xOffset8x8 + (yOffset8x8 * grainStripeWidth)); + + decSampleHbdBlk8 = decSampleHbdBlk16 + offsetBlk8x8; + blockAvg = blockAverage_8x8(decSampleHbdBlk8, strideComp[compCtr], &numSamples, BLK_8, BLK_8, bitDepth); + + /* Selection of the component model */ + + intensityInt = inArgs->pGrainSynt->intensityInterval[compCtr][blockAvg]; + + // ------------------------------- check if the intensity interval is within the intensity intervals for the region + if (compCtr==0) + { + int interval_offset_in_map = (y + yOffset8x8) * widthComp[compCtr]; + int intervalCompFactor = 1; + if (widthComp[compCtr] != widthComp[0]) + intervalCompFactor =intervalCompFactor*2 ; + if (intensityInt < inArgs->fgr_regionIntervals_min_map[compCtr][interval_offset_in_map + x + xOffset8x8]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + /*for (int jj = 0 ; jj < 8 ; jj++) + for (int ii = 0 ; ii < 8 ; ii++) + { + inArgs->fgr_grain_enabled_map[interval_offset_in_map +jj*widthComp[compCtr] + x + xOffset8x8 + ii] = false; + } // DEBUD MASK */ + + } + if (intensityInt > inArgs->fgr_regionIntervals_max_map[compCtr][interval_offset_in_map + x + xOffset8x8]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + /*for (int jj = 0 ; jj < 8 ; jj++) + for (int ii = 0 ; ii < 8 ; ii++) + { + inArgs->fgr_grain_enabled_map[interval_offset_in_map +jj*widthComp[compCtr] + x + xOffset8x8 + ii] = false; + } // DEBUG MASK */ + } + } + else + { + int interval_offset_in_map = (y+yOffset8x8)*widthComp[compCtr] ; + if (intensityInt < inArgs->fgr_regionIntervals_min_map[compCtr][interval_offset_in_map + x + xOffset8x8]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + /* for (int jj = 0 ; jj < 16 ; jj++) + for (int ii = 0 ; ii < 16 ; ii++) + { + inArgs->fgr_grain_enabled_map[interval_offset_in_map*4 +jj*widthComp[compCtr]*2 + x*2 + xOffset8x8*2 + ii] = false; + //printf("index to nulify: %d", interval_offset_in_map +jj*widthComp[compCtr]*4 + x*2 + xOffset8x8*2 + ii*2 ); + } // DEBUG MASK */ + + } + if (intensityInt > inArgs->fgr_regionIntervals_max_map[compCtr][interval_offset_in_map + x + xOffset8x8]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + /*for (int jj = 0 ; jj < 16 ; jj++) + for (int ii = 0 ; ii < 16 ; ii++) + { + inArgs->fgr_grain_enabled_map[interval_offset_in_map*4 +jj*widthComp[compCtr]*2 + x*2 + xOffset8x8*2 + ii] = false; + // printf("index to nulify: %d", interval_offset_in_map +jj*widthComp[compCtr]*4 + x*2 + xOffset8x8*2 + ii*2 ); + } // DEUBD MASK */ + } + } + // printf("---- For Block Average= %d Intensisty interval = %d \n", blockAvg, intensityInt); + // ------------------------------- check if the intensity interval is within the intensity intervals for the region + + if (INTENSITY_INTERVAL_MATCH_FAIL != intensityInt) + { + /* 8x8 grain block offset using co-ordinates of decoded 8x8 block in the frame */ + // kOffset = kOffset_const; + kOffset = kOffset_const + xOffset8x8; + + lOffset = lOffset_const + yOffset8x8; + + scaleFactor = + scaleFactor_const + * inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[0]; + h = inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[1] - 2; + v = inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[2] - 2; + /* 8x8 block grain simulation */ + simulateGrainBlk8x8(grainStripe, grainStripeOffsetBlk8, inArgs->pGrainSynt, grainStripeWidth, + log2ScaleFactor, scaleFactor, kOffset, lOffset, h, v, BLK_8); + } /* only if average falls in any interval */ + // }/* includes corner case handling */ + } /* 8x8 level block processing */ + + /* uppdate the PRNG once per 16x16 block of samples */ + offset_tmp++; + } /* End of 16xwidth grain simulation */ + + /* deblocking at the vertical edges of 8x8 at 16xwidth*/ + deblockGrainStripe(grainStripe, widthComp[compCtr], BLK_16, grainStripeWidth, BLK_8); + + /* Blending of size 16xwidth*/ + int offset_in_map = y*widthComp[compCtr] ; + int CompFactor = 1; + if (widthComp[compCtr] != widthComp[0]) + { + offset_in_map = y*widthComp[compCtr] * 4 ; // YUV 420 4:1 ratio to access the FGS enabled map from chroma coordinates + CompFactor = 2 ; + } + blendStripe(decSampleHbdOffsetY, grainStripe, widthComp[compCtr], strideComp[compCtr], grainStripeWidth,BLK_16, bitDepth, offset_in_map,inArgs->fgr_grain_enabled_map,CompFactor); + + decSampleHbdOffsetY += BLK_16 * strideComp[compCtr]; + + } /* end of component loop */ + decSampleHbdOffsetY = decHbdComp[compCtr]; + } + } + } + + delete [] grainStripe; + return FGS_SUCCESS; +} + +uint32_t SEIFilmGrainRegionsSynthesizer::fgrSimulationBlending_16x16(fgrProcessArgs *inArgs) +{ + uint8_t numComp, compCtr; /* number of color components */ + uint8_t log2ScaleFactor, h, v; + uint8_t bitDepth; /*grain bit depth and decoded bit depth are assumed to be same */ + uint32_t widthComp[MAX_NUM_COMPONENT], heightComp[MAX_NUM_COMPONENT]; + ptrdiff_t strideComp[MAX_NUM_COMPONENT]; + Pel * decSampleHbdBlk16, *decSampleHbdOffsetY; + Pel * decHbdComp[MAX_NUM_COMPONENT]; + uint16_t numSamples; + int16_t scaleFactor; + uint32_t kOffset, lOffset, grainStripeOffset; + Pel * grainStripe; /* worth a row of 16x16 : Max size : 16xw;*/ + uint32_t x, y; + uint32_t blockAvg, intensityInt; /* ec : seed to be used for the psudo random generator for a given color component */ + uint32_t grainStripeWidth; + uint32_t wdPadded; + + bitDepth = inArgs->bitDepth; + numComp = inArgs->numComp; + log2ScaleFactor = inArgs->pFgrParameters->m_fgr_log2ScaleFactor; + + for (compCtr = 0; compCtr < numComp; compCtr++) + { + decHbdComp[compCtr] = inArgs->decComp[compCtr]; + strideComp[compCtr] = inArgs->strideComp[compCtr]; + widthComp[compCtr] = inArgs->widthComp[compCtr]; + heightComp[compCtr] = inArgs->heightComp[compCtr]; + } + + wdPadded = ((inArgs->widthComp[0] - 1) | 0xF) + 1; + grainStripe = new Pel[wdPadded * BLK_16]; + + if (0 == inArgs->pFgrParameters->m_filmGrainRegionsCharacteristicsCancelFlag) + { + for (compCtr = 0; compCtr < numComp; compCtr++) + { + if (1 == inArgs->pFgrParameters->m_fgr_compModel[compCtr].presentFlag) + { + decSampleHbdOffsetY = decHbdComp[compCtr]; + uint32_t *offset_tmp = inArgs->fgsOffsets[compCtr]; + grainStripeWidth = ((widthComp[compCtr] - 1) | 0xF) + 1; // Make next muliptle of 16 + + /* Loop of 16x16 blocks */ + for (y = 0; y < heightComp[compCtr]; y += BLK_16) + { + /* Initialization of grain stripe of 16xwidth size */ + memset(grainStripe, 0, (grainStripeWidth * BLK_16 * sizeof(Pel))); + for (x = 0; x < widthComp[compCtr]; x += BLK_16) + { + /* start position offset of decoded sample in x direction */ + grainStripeOffset = x; + + decSampleHbdBlk16 = decSampleHbdOffsetY + x; + + blockAvg = + blockAverage_16x16(decSampleHbdBlk16, strideComp[compCtr], &numSamples, BLK_16, BLK_16, bitDepth); + blockAvg = blockAvg >> (BLK_16_shift + (bitDepth - BIT_DEPTH_8)); + /* Selection of the component model */ + intensityInt = inArgs->pGrainSynt->intensityInterval[compCtr][blockAvg]; + + // ------------------------------- check if the intensity interval is within the intensity intervals for the region + if (compCtr==0) + { + int interval_offset_in_map = (y)*widthComp[compCtr] ; + int intervalCompFactor = 1; + if (widthComp[compCtr] != widthComp[0]) + intervalCompFactor =intervalCompFactor*2 ; + if (intensityInt < inArgs->fgr_regionIntervals_min_map[compCtr][interval_offset_in_map + x]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + } + if (intensityInt > inArgs->fgr_regionIntervals_max_map[compCtr][interval_offset_in_map + x]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + } + } + else + { + int interval_offset_in_map = (y)*widthComp[compCtr] ; + if (intensityInt < inArgs->fgr_regionIntervals_min_map[compCtr][interval_offset_in_map + x]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + } + if (intensityInt > inArgs->fgr_regionIntervals_max_map[compCtr][interval_offset_in_map + x]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + } + } + // ------------------------------- check if the intensity interval is within the intensity intervals for the region + + + if (INTENSITY_INTERVAL_MATCH_FAIL != intensityInt) + { + kOffset = (MSB16(*offset_tmp) % 52); + kOffset &= 0xFFFC; + + lOffset = (LSB16(*offset_tmp) % 56); + lOffset &= 0xFFF8; + scaleFactor = 1 - 2 * BIT0(*offset_tmp); + + scaleFactor *= + inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[0]; + h = inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[1] - 2; + v = inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[2] - 2; + + /* 16x16 block grain simulation */ + simulateGrainBlk16x16(grainStripe, grainStripeOffset, inArgs->pGrainSynt, grainStripeWidth, + log2ScaleFactor, scaleFactor, kOffset, lOffset, h, v, BLK_16); + + } /* only if average falls in any interval */ + // }/* includes corner case handling */ + /* uppdate the PRNG once per 16x16 block of samples */ + offset_tmp++; + } /* End of 16xwidth grain simulation */ + /* deblocking at the vertical edges of 16x16 at 16xwidth*/ + deblockGrainStripe(grainStripe, widthComp[compCtr], BLK_16, grainStripeWidth, BLK_16); + + /* Blending of size 16xwidth*/ + int offset_in_map = y*widthComp[compCtr] ; + int CompFactor = 1; + if (widthComp[compCtr] != widthComp[0]) + CompFactor =CompFactor*2 ; + blendStripe(decSampleHbdOffsetY, grainStripe, widthComp[compCtr], strideComp[compCtr], grainStripeWidth, + BLK_16, bitDepth, offset_in_map, inArgs->fgr_grain_enabled_map,CompFactor); + decSampleHbdOffsetY += BLK_16 * strideComp[compCtr]; + + } /* end of component loop */ + } + } + } + + delete [] grainStripe; + return FGS_SUCCESS; +} + +uint32_t SEIFilmGrainRegionsSynthesizer::fgrSimulationBlending_32x32(fgrProcessArgs *inArgs) +{ + uint8_t numComp, compCtr; /* number of color components */ + uint8_t log2ScaleFactor, h, v; + uint8_t bitDepth; /*grain bit depth and decoded bit depth are assumed to be same */ + uint32_t widthComp[MAX_NUM_COMPONENT], heightComp[MAX_NUM_COMPONENT]; + ptrdiff_t strideComp[MAX_NUM_COMPONENT]; + Pel * decSampleBlk32, *decSampleOffsetY; + Pel * decComp[MAX_NUM_COMPONENT]; + int16_t scaleFactor; + uint32_t kOffset, lOffset, grainStripeOffset; + Pel * grainStripe; + uint32_t x, y; + uint32_t blockAvg, intensityInt; /* ec : seed to be used for the psudo random generator for a given color component */ + uint32_t grainStripeWidth; + uint32_t wdPadded; + + bitDepth = inArgs->bitDepth; + numComp = inArgs->numComp; + + log2ScaleFactor = inArgs->pFgrParameters->m_fgr_log2ScaleFactor; + + for (compCtr = 0; compCtr < numComp; compCtr++) + { + decComp[compCtr] = inArgs->decComp[compCtr]; + strideComp[compCtr] = inArgs->strideComp[compCtr]; + heightComp[compCtr] = inArgs->heightComp[compCtr]; + widthComp[compCtr] = inArgs->widthComp[compCtr]; + } + + wdPadded = ((inArgs->widthComp[0] - 1) | 0x1F) + 1; + grainStripe = new Pel[wdPadded * BLK_32]; + + if (0 == inArgs->pFgrParameters->m_filmGrainRegionsCharacteristicsCancelFlag) + { + for (compCtr = 0; compCtr < numComp; compCtr++) + { + if (1 == inArgs->pFgrParameters->m_fgr_compModel[compCtr].presentFlag) + { + uint32_t *offset_tmp = inArgs->fgsOffsets[compCtr]; + decSampleOffsetY = decComp[compCtr]; + grainStripeWidth = ((widthComp[compCtr] - 1) | 0x1F) + 1; // Make next muliptle of 32 + + /* Loop of 32x32 blocks */ + for (y = 0; y < heightComp[compCtr]; y += BLK_32) + { + /* Initialization of grain stripe of 32xwidth size */ + memset(grainStripe, 0, (grainStripeWidth * BLK_32 * sizeof(Pel))); + for (x = 0; x < widthComp[compCtr]; x += BLK_32) + { + /* start position offset of decoded sample in x direction */ + grainStripeOffset = x; + decSampleBlk32 = decSampleOffsetY + x; + blockAvg = blockAverage_32x32(decSampleBlk32, strideComp[compCtr], bitDepth); + + /* Selection of the component model */ + intensityInt = inArgs->pGrainSynt->intensityInterval[compCtr][blockAvg]; + + // ------------------------------- check if the intensity interval is within the intensity intervals for the region + if (compCtr==0) + { + int interval_offset_in_map = (y)*widthComp[compCtr] ; + int intervalCompFactor = 1; + if (widthComp[compCtr] != widthComp[0]) + intervalCompFactor =intervalCompFactor*2 ; + if (intensityInt < inArgs->fgr_regionIntervals_min_map[compCtr][interval_offset_in_map + x]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + } + if (intensityInt > inArgs->fgr_regionIntervals_max_map[compCtr][interval_offset_in_map + x]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + } + } + else + { + int interval_offset_in_map = (y)*widthComp[compCtr] ; + if (intensityInt < inArgs->fgr_regionIntervals_min_map[compCtr][interval_offset_in_map + x]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + } + if (intensityInt > inArgs->fgr_regionIntervals_max_map[compCtr][interval_offset_in_map + x]) + { + intensityInt = INTENSITY_INTERVAL_MATCH_FAIL ; + } + } + // ------------------------------- check if the intensity interval is within the intensity intervals for the region + + + if (INTENSITY_INTERVAL_MATCH_FAIL != intensityInt) + { + kOffset = (MSB16(*offset_tmp) % 36); + kOffset &= 0xFFFC; + + lOffset = (LSB16(*offset_tmp) % 40); + lOffset &= 0xFFF8; + scaleFactor = 1 - 2 * BIT0(*offset_tmp); + + scaleFactor *= inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[0]; + h = inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[1] - 2; + v = inArgs->pFgrParameters->m_fgr_compModel[compCtr].intensityValues[intensityInt].compModelValue[2] - 2; + + /* 32x32 block grain simulation */ + simulateGrainBlk32x32(grainStripe, grainStripeOffset, inArgs->pGrainSynt, grainStripeWidth, + log2ScaleFactor, scaleFactor, kOffset, lOffset, h, v); + + } /* only if average falls in any interval */ + + /* uppdate the PRNG once per 16x16 block of samples */ + offset_tmp++; + } /* End of 32xwidth grain simulation */ + + /* deblocking at the vertical edges of 8x8 at 16xwidth*/ + deblockGrainStripe(grainStripe, widthComp[compCtr], BLK_32, grainStripeWidth, BLK_32); + + int offset_in_map = y*widthComp[compCtr] ; + int CompFactor = 1; + if (widthComp[compCtr] != widthComp[0]) + CompFactor =CompFactor*2 ; + blendStripe_32x32(decSampleOffsetY, grainStripe, widthComp[compCtr], strideComp[compCtr], grainStripeWidth, BLK_32, bitDepth,offset_in_map,inArgs->fgr_grain_enabled_map,CompFactor); + decSampleOffsetY += BLK_32 * strideComp[compCtr]; + } /* end of component loop */ + } + } + } + + delete [] grainStripe; + return FGS_SUCCESS; +} +#endif diff --git a/source/Lib/CommonLib/SEIFilmGrainSynthesizer.h b/source/Lib/CommonLib/SEIFilmGrainSynthesizer.h index ff7a364bd..d251d9f00 100644 --- a/source/Lib/CommonLib/SEIFilmGrainSynthesizer.h +++ b/source/Lib/CommonLib/SEIFilmGrainSynthesizer.h @@ -225,6 +225,91 @@ private: };// END CLASS DEFINITION SEIFilmGrainSynthesizer +#if JVET_AG0328 +typedef struct fgrProcessArgs +{ + uint8_t numComp; + uint32_t * fgsOffsets[MAX_NUM_COMPONENT]; + Pel * decComp[MAX_NUM_COMPONENT]; + uint32_t widthComp[MAX_NUM_COMPONENT]; + uint32_t heightComp[MAX_NUM_COMPONENT]; + ptrdiff_t strideComp[MAX_NUM_COMPONENT]; + SEIFilmGrainRegionsCharacteristics *pFgrParameters; + GrainSynthesisStruct * pGrainSynt; + uint8_t bitDepth; + uint8_t blkSize; + std::vector fgr_grain_enabled_map; + std::vector fgr_regionIntervals_min_map[MAX_NUM_COMPONENT]; + std::vector fgr_regionIntervals_max_map[MAX_NUM_COMPONENT]; +} fgrProcessArgs; + +class SEIFilmGrainRegionsSynthesizer +{ + +private: + uint32_t m_width; + uint32_t m_height; + ChromaFormat m_chromaFormat; + uint8_t m_bitDepth; + uint32_t m_idrPicId; + + fgrProcessArgs m_fgrArgs; + GrainSynthesisStruct *m_grainSynt; + uint8_t m_fgsBlkSize; + +public: + uint32_t m_poc; + int32_t m_errorCode; + SEIFilmGrainRegionsCharacteristics *m_fgrParameters; + +public: + SEIFilmGrainRegionsSynthesizer(); + virtual ~SEIFilmGrainRegionsSynthesizer(); + + void create(uint32_t width, uint32_t height, ChromaFormat fmt, uint8_t bitDepth, uint32_t idrPicId); + void destroy (); + + void fgrInit (); + void grainSynthesizeAndBlend (PelStorage* pGrainBuf, bool isIdrPic); + uint8_t grainValidateParams (); + +private: + void deriveFGSBlkSize (); + void dataBaseGen (); + static uint32_t prng (uint32_t x_r); + static uint32_t fgrProcess (fgrProcessArgs &inArgs); + + static void deblockGrainStripe (Pel *grainStripe, uint32_t widthComp, uint32_t heightComp, uint32_t strideComp, + uint32_t blkSize); + static void blendStripe(Pel *decSampleOffsetY, Pel *grainStripe, uint32_t widthComp, ptrdiff_t strideSrc, + ptrdiff_t strideGrain, uint32_t blockHeight, uint8_t bitDepth, uint32_t offset_in_map,std::vector fgr_grain_enabled_map, uint32_t CompFactor ); + static void blendStripe_32x32(Pel *decSampleOffsetY, Pel *grainStripe, uint32_t widthComp, ptrdiff_t strideSrc, + ptrdiff_t strideGrain, uint32_t blockHeight, uint8_t bitDepth,uint32_t offset_in_map,std::vector fgr_grain_enabled_map, uint32_t CompFactor); + + static Pel blockAverage_8x8(Pel *decSampleBlk8, ptrdiff_t widthComp, uint16_t *pNumSamples, uint8_t ySize, + uint8_t xSize, uint8_t bitDepth); + static uint32_t blockAverage_16x16(Pel *decSampleBlk8, ptrdiff_t widthComp, uint16_t *pNumSamples, uint8_t ySize, + uint8_t xSize, uint8_t bitDepth); + static uint32_t blockAverage_32x32(Pel *decSampleBlk32, ptrdiff_t strideComp, uint8_t bitDepth); + + static void simulateGrainBlk8x8 (Pel *grainStripe, uint32_t grainStripeOffsetBlk8, GrainSynthesisStruct *pGrainSynt, + uint32_t width, uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset, + uint32_t lOffset, uint8_t h, uint8_t v, uint32_t xSize); + static void simulateGrainBlk16x16(Pel *grainStripe, uint32_t grainStripeOffsetBlk8, GrainSynthesisStruct *grain_synt, + uint32_t width, uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset, + uint32_t lOffset, uint8_t h, uint8_t v, uint32_t xSize); + static void simulateGrainBlk32x32(Pel *grainStripe, uint32_t grainStripeOffsetBlk32, GrainSynthesisStruct *grain_synt, + uint32_t width, uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset, + uint32_t lOffset, uint8_t h, uint8_t v); + static uint32_t fgrSimulationBlending_8x8 (fgrProcessArgs *inArgs); + static uint32_t fgrSimulationBlending_16x16 (fgrProcessArgs *inArgs); + static uint32_t fgrSimulationBlending_32x32 (fgrProcessArgs *inArgs); + +};// END CLASS DEFINITION SEIFilmGrainRegionsSynthesizer + +#endif + + //! \} #endif // __SEIFILMGRAINSYNTHESIZER__ diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 280da05f2..9de14e076 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -94,6 +94,10 @@ #define JVET_J0090_MEMORY_BANDWITH_MEASURE 0 #endif +#ifndef JVET_AG0328 +#define JVET_AG0328 1 +#endif + #ifndef EXTENSION_360_VIDEO #define EXTENSION_360_VIDEO 0 ///< extension for 360/spherical video coding support; this macro should be controlled by makefile, as it would be used to control whether the library is built and linked #endif diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index e796fb318..4f2f6f14c 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -491,6 +491,10 @@ DecLib::DecLib() , m_firstPictureInSequence(true) , m_grainCharacteristic() , m_grainBuf() +#if JVET_AG0328 + , m_grainRegionsCharacteristic() + , m_grainRegionsBuf() +#endif , m_colourTranfParams() , m_firstSliceInBitstream(true) , m_isFirstAuInCvs(true) @@ -2110,6 +2114,11 @@ void DecLib::xActivateParameterSets( const InputNALUnit nalu ) m_pcPic->createGrainSynthesizer(m_firstPictureInSequence, &m_grainCharacteristic, &m_grainBuf, pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getBitDepth(ChannelType::LUMA)); +#if JVET_AG0328 + m_pcPic->createGrainRegionsSynthesizer(m_firstPictureInSequence, &m_grainRegionsCharacteristic, &m_grainRegionsBuf, + pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), + sps->getChromaFormatIdc(), sps->getBitDepth(ChannelType::LUMA)); +#endif m_pcPic->createColourTransfProcessor(m_firstPictureInSequence, &m_colourTranfParams, &m_invColourTransfBuf, pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getBitDepth(ChannelType::LUMA)); diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 1476f7390..9cc3f9277 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -140,6 +140,10 @@ private: bool m_firstPictureInSequence; SEIFilmGrainSynthesizer m_grainCharacteristic; PelStorage m_grainBuf; +#if JVET_AG0328 + SEIFilmGrainRegionsSynthesizer m_grainRegionsCharacteristic; + PelStorage m_grainRegionsBuf; +#endif SEIColourTransformApply m_colourTranfParams; PelStorage m_invColourTransfBuf; bool m_firstSliceInSequence[MAX_VPS_LAYERS]; diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp index c033c4b1e..7650240e7 100644 --- a/source/Lib/DecoderLib/SEIread.cpp +++ b/source/Lib/DecoderLib/SEIread.cpp @@ -462,6 +462,12 @@ bool SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType sei = new SEIFilmGrainCharacteristics; xParseSEIFilmGrainCharacteristics((SEIFilmGrainCharacteristics &) *sei, payloadSize, pDecodedMessageOutputStream); break; +#if JVET_AG0328 + case SEI::PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS: + sei = new SEIFilmGrainRegionsCharacteristics; + xParseSEIFilmGrainRegionsCharacteristics((SEIFilmGrainRegionsCharacteristics &) *sei, payloadSize, pDecodedMessageOutputStream); + break; +#endif case SEI::PayloadType::CONTENT_LIGHT_LEVEL_INFO: sei = new SEIContentLightLevelInfo; xParseSEIContentLightLevelInfo((SEIContentLightLevelInfo &) *sei, payloadSize, pDecodedMessageOutputStream); @@ -1406,6 +1412,9 @@ void SEIReader::xCheckScalableNestingConstraints(const SEIScalableNesting& sei, const std::vector vclAssociatedSeiList{ SEI::PayloadType::FILLER_PAYLOAD, SEI::PayloadType::FILM_GRAIN_CHARACTERISTICS, +#if JVET_AG0328 + SEI::PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS, +#endif SEI::PayloadType::FRAME_PACKING, SEI::PayloadType::GREEN_METADATA, SEI::PayloadType::PARAMETER_SETS_INCLUSION_INDICATION, @@ -2181,9 +2190,97 @@ void SEIReader::xParseSEIFilmGrainCharacteristics(SEIFilmGrainCharacteristics& s } } } // for c - sei_read_flag(pDecodedMessageOutputStream, code, "fg_characteristics_persistence_flag"); sei.m_filmGrainCharacteristicsPersistenceFlag = code != 0; + sei_read_flag(pDecodedMessageOutputStream, code, "fg_characteristics_persistence_flag"); sei.m_filmGrainCharacteristicsPersistenceFlag = code != 0; + } // cancel flag +} + +#if JVET_AG0328 +void SEIReader::xParseSEIFilmGrainRegionsCharacteristics(SEIFilmGrainRegionsCharacteristics& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream) +{ + uint32_t code; + output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize); + + sei_read_flag(pDecodedMessageOutputStream, code, "fgr_characteristics_cancel_flag"); sei.m_filmGrainRegionsCharacteristicsCancelFlag = code != 0; + if (!sei.m_filmGrainRegionsCharacteristicsCancelFlag) + { + sei_read_code(pDecodedMessageOutputStream, 2, code, "fgr_model_id"); sei.m_filmGrainRegionsModelId = code; + sei_read_flag(pDecodedMessageOutputStream, code, "fgr_separate_colour_description_present_flag"); sei.m_fgr_separateColourDescriptionPresentFlag = code != 0; + if (sei.m_fgr_separateColourDescriptionPresentFlag) + { + sei_read_code(pDecodedMessageOutputStream, 3, code, "fgr_bit_depth_luma_minus8"); sei.m_filmGrainRegionsBitDepthLumaMinus8 = code; + sei_read_code(pDecodedMessageOutputStream, 3, code, "fgr_bit_depth_chroma_minus8"); sei.m_filmGrainRegionsBitDepthChromaMinus8 = code; + sei_read_flag(pDecodedMessageOutputStream, code, "fgr_full_range_flag"); sei.m_filmGrainRegionsFullRangeFlag = code != 0; + sei_read_code(pDecodedMessageOutputStream, 8, code, "fgr_colour_primaries"); sei.m_filmGrainRegionsColourPrimaries = code; + sei_read_code(pDecodedMessageOutputStream, 8, code, "fgr_transfer_characteristics"); sei.m_filmGrainRegionsTransferCharacteristics = code; + sei_read_code(pDecodedMessageOutputStream, 8, code, "fgr_matrix_coeffs"); sei.m_filmGrainRegionsMatrixCoeffs = code; + } + sei_read_code(pDecodedMessageOutputStream, 2, code, "fgr_blending_mode_id"); sei.m_fgr_blendingModeId = code; + sei_read_code(pDecodedMessageOutputStream, 4, code, "fgr_log2_scale_factor"); sei.m_fgr_log2ScaleFactor = code; + for (int c = 0; c<3; c++) + { + sei_read_flag(pDecodedMessageOutputStream, code, "fgr_comp_model_present_flag[c]"); sei.m_fgr_compModel[c].presentFlag = code != 0; + } + for (int c = 0; c<3; c++) + { + SEIFilmGrainRegionsCharacteristics::CompModel &cm = sei.m_fgr_compModel[c]; + if (cm.presentFlag) + { + sei_read_code(pDecodedMessageOutputStream, 8, code, "fgr_num_intensity_intervals_minus1[c]"); cm.numIntensityIntervals = code + 1; + sei_read_code(pDecodedMessageOutputStream, 3, code, "fgr_num_model_values_minus1[c]"); cm.numModelValues = code + 1; + cm.intensityValues.resize(cm.numIntensityIntervals); + for (uint32_t i = 0; i < cm.numIntensityIntervals; i++) + { + SEIFilmGrainRegionsCharacteristics::CompModelIntensityValues &cmiv = cm.intensityValues[i]; + sei_read_code(pDecodedMessageOutputStream, 8, code, "fgr_intensity_interval_lower_bound[c][i]"); cmiv.intensityIntervalLowerBound = code; + sei_read_code(pDecodedMessageOutputStream, 8, code, "fgr_intensity_interval_upper_bound[c][i]"); cmiv.intensityIntervalUpperBound = code; + cmiv.compModelValue.resize(cm.numModelValues); + for (uint32_t j = 0; j m_fgrSEITemporalFilterStrengths; + bool m_fgrSEIPerPictureSEI; + uint8_t m_fgrSEINumModelValuesMinus1 [MAX_NUM_COMPONENT]; + uint8_t m_fgrSEINumIntensityIntervalMinus1 [MAX_NUM_COMPONENT]; + uint8_t m_fgrSEIIntensityIntervalLowerBound [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES]; + uint8_t m_fgrSEIIntensityIntervalUpperBound [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES]; + uint32_t m_fgrSEICompModelValue [MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES][MAX_NUM_MODEL_VALUES]; + + bool m_fgrSEI_region_information_present_flag; + bool m_fgrSEI_region_based_adaptation_flag; + bool m_fgrSEI_alpha_channel_adaptation_flag; + uint32_t m_fgrSEINumActiveRegionsMinus1; + +public: + std::vector m_fgrSEIregionCharacteristics; +protected: +#endif + // cll SEI bool m_cllSEIEnabled; uint16_t m_cllSEIMaxContentLevel; @@ -2369,6 +2402,102 @@ public: uint8_t getFGCSEIIntensityIntervalUpperBound(int index, int ctr) { return m_fgcSEIIntensityIntervalUpperBound[index][ctr]; } void setFGCSEICompModelValue (uint32_t v, int index, int ctr, int modelCtr) { m_fgcSEICompModelValue[index][ctr][modelCtr] = v; } uint32_t getFGCSEICompModelValue (int index, int ctr, int modelCtr) { return m_fgcSEICompModelValue[index][ctr][modelCtr]; } +#if JVET_AG0328 + // film grain region SEI + void setFilmGrainRegionsCharactersticsSEIEnabled (bool b) { m_fgrSEIEnabled = b; } + bool getFilmGrainRegionsCharactersticsSEIEnabled() { return m_fgrSEIEnabled; } + void setFilmGrainRegionsCharactersticsSEICancelFlag(bool b) { m_fgrSEICancelFlag = b; } + bool getFilmGrainRegionsCharactersticsSEICancelFlag() { return m_fgrSEICancelFlag; } + void setFilmGrainRegionsCharactersticsSEIPersistenceFlag(bool b) { m_fgrSEIPersistenceFlag = b; } + bool getFilmGrainRegionsCharactersticsSEIPersistenceFlag() { return m_fgrSEIPersistenceFlag; } + void setFilmGrainRegionsCharactersticsSEIModelID(uint8_t v ) { m_fgrSEIModelID = v; } + uint8_t getFilmGrainRegionsCharactersticsSEIModelID() { return m_fgrSEIModelID; } + void setFilmGrainRegionsCharactersticsSEISepColourDescPresent(bool b) { m_fgrSEISepColourDescPresentFlag = b; } + bool getFilmGrainRegionsCharactersticsSEISepColourDescPresent() { return m_fgrSEISepColourDescPresentFlag; } + void setFilmGrainRegionsCharactersticsSEIBlendingModeID(uint8_t v ) { m_fgrSEIBlendingModeID = v; } + uint8_t getFilmGrainRegionsCharactersticsSEIBlendingModeID() { return m_fgrSEIBlendingModeID; } + void setFilmGrainRegionsCharactersticsSEILog2ScaleFactor(uint8_t v ) { m_fgrSEILog2ScaleFactor = v; } + uint8_t getFilmGrainRegionsCharactersticsSEILog2ScaleFactor() { return m_fgrSEILog2ScaleFactor; } + void setFGRSEICompModelPresent(bool b, int index) { m_fgrSEICompModelPresent[index] = b; } + bool getFGRSEICompModelPresent(int index) { return m_fgrSEICompModelPresent[index]; } + bool* getFGRSEICompModelPresent () { return m_fgrSEICompModelPresent; } + void setFilmGrainRegionsAnalysisEnabled (bool b) { m_fgrSEIAnalysisEnabled = b; } + bool getFilmGrainRegionsAnalysisEnabled () { return m_fgrSEIAnalysisEnabled; } + void setFilmGrainRegionsExternalMask(std::string s) { m_fgrSEIExternalMask = s; } + void setFilmGrainRegionsExternalDenoised(std::string s) { m_fgrSEIExternalDenoised = s; } + std::string getFilmGrainRegionsExternalMask() { return m_fgrSEIExternalMask; } + std::string getFilmGrainRegionsExternalDenoised() { return m_fgrSEIExternalDenoised; } + void setFilmGrainRegionsTemporalFilterPastRefs(int v) { m_fgrSEITemporalFilterPastRefs = v; } + void setFilmGrainRegionsTemporalFilterFutureRefs(int v) { m_fgrSEITemporalFilterFutureRefs = v; } + void setFilmGrainRegionsTemporalFilterStrengths(std::map v) { m_fgrSEITemporalFilterStrengths = v; } + int getFilmGrainRegionsTemporalFilterPastRefs() { return m_fgrSEITemporalFilterPastRefs; }; + int getFilmGrainRegionsTemporalFilterFutureRef() { return m_fgrSEITemporalFilterFutureRefs; }; + std::map getFilmGrainRegionsTemporalFilterStrengths() { return m_fgrSEITemporalFilterStrengths; }; + void setFilmGrainRegionsCharactersticsSEIPerPictureSEI(bool b) { m_fgrSEIPerPictureSEI = b; } + bool getFilmGrainRegionsCharactersticsSEIPerPictureSEI() { return m_fgrSEIPerPictureSEI; } + void setFGRSEINumIntensityIntervalMinus1 (uint8_t v, int index) { m_fgrSEINumIntensityIntervalMinus1[index] = v; } + uint8_t getFGRSEINumIntensityIntervalMinus1 (int index) { return m_fgrSEINumIntensityIntervalMinus1[index]; } + void setFGRSEINumModelValuesMinus1 (uint8_t v, int index) { m_fgrSEINumModelValuesMinus1[index] = v; } + uint8_t getFGRSEINumModelValuesMinus1 (int index) { return m_fgrSEINumModelValuesMinus1[index]; } + void setFGRSEIIntensityIntervalLowerBound(uint8_t v, int index, int ctr) { m_fgrSEIIntensityIntervalLowerBound[index][ctr] = v; } + uint8_t getFGRSEIIntensityIntervalLowerBound(int index, int ctr) { return m_fgrSEIIntensityIntervalLowerBound[index][ctr]; } + void setFGRSEIIntensityIntervalUpperBound(uint8_t v, int index, int ctr) { m_fgrSEIIntensityIntervalUpperBound[index][ctr] = v; } + uint8_t getFGRSEIIntensityIntervalUpperBound(int index, int ctr) { return m_fgrSEIIntensityIntervalUpperBound[index][ctr]; } + void setFGRSEICompModelValue (uint32_t v, int index, int ctr, int modelCtr) { m_fgrSEICompModelValue[index][ctr][modelCtr] = v; } + uint32_t getFGRSEICompModelValue (int index, int ctr, int modelCtr) { return m_fgrSEICompModelValue[index][ctr][modelCtr]; } + void setFilmGrainRegionInformationPresentFlag(bool b) { m_fgrSEI_region_information_present_flag = b; } + bool getFilmGrainRegionInformationPresentFlag() { return m_fgrSEI_region_information_present_flag; } + void setFilmGrainRegionBasedAdaptationFlag(bool b) { m_fgrSEI_region_based_adaptation_flag = b; } + bool getFilmGrainRegionBasedAdaptationFlag() { return m_fgrSEI_region_based_adaptation_flag; } + void setFilmGrainAlphaChannelAdaptationFlag(bool b) { m_fgrSEI_alpha_channel_adaptation_flag = b; } + bool getFilmGrainAlphaChannelAdaptationFlag() { return m_fgrSEI_alpha_channel_adaptation_flag; } + void setFilmGrainNumActiveRegionsMinus1(int b) { m_fgrSEINumActiveRegionsMinus1 = b; } + int getFilmGrainNumActiveRegionsMinus1() { return m_fgrSEINumActiveRegionsMinus1; } + void setFilmGrainRegionCharacteristics(std::vector RegionCharacteristics, int NumRegionsMinus1 ) + { + if(m_fgrSEI_region_based_adaptation_flag) + { + m_fgrSEIregionCharacteristics.resize(NumRegionsMinus1+1); + for (int i = 0 ; i <= NumRegionsMinus1; i++) + { + m_fgrSEIregionCharacteristics[i].m_fgr_region_top = RegionCharacteristics[i].m_fgr_region_top; + m_fgrSEIregionCharacteristics[i].m_fgr_region_left = RegionCharacteristics[i].m_fgr_region_left; + m_fgrSEIregionCharacteristics[i].m_fgr_region_width = RegionCharacteristics[i].m_fgr_region_width; + m_fgrSEIregionCharacteristics[i].m_fgr_region_height = RegionCharacteristics[i].m_fgr_region_height; + m_fgrSEIregionCharacteristics[i].m_film_grain_enabled_flag = RegionCharacteristics[i].m_film_grain_enabled_flag; + if (RegionCharacteristics[i].m_film_grain_enabled_flag) + { + m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[0].m_fgr_region_interval_min = RegionCharacteristics[i].m_fgr_regionIntervals[0].m_fgr_region_interval_min ; + m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[0].m_fgr_region_interval_max = RegionCharacteristics[i].m_fgr_regionIntervals[0].m_fgr_region_interval_max ; + m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[1].m_fgr_region_interval_min = RegionCharacteristics[i].m_fgr_regionIntervals[1].m_fgr_region_interval_min ; + m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[1].m_fgr_region_interval_max = RegionCharacteristics[i].m_fgr_regionIntervals[1].m_fgr_region_interval_max ; + m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[2].m_fgr_region_interval_min = RegionCharacteristics[i].m_fgr_regionIntervals[2].m_fgr_region_interval_min ; + m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[2].m_fgr_region_interval_max = RegionCharacteristics[i].m_fgr_regionIntervals[2].m_fgr_region_interval_max ; + } + } + } + } + void getFilmGrainRegionCharacteristics(std::vector& RegionCharacteristics, int NumRegionsMinus1 ) + { + for (int i = 0 ; i <= NumRegionsMinus1; i++) + { + RegionCharacteristics[i].m_fgr_region_top = m_fgrSEIregionCharacteristics[i].m_fgr_region_top; + RegionCharacteristics[i].m_fgr_region_left = m_fgrSEIregionCharacteristics[i].m_fgr_region_left ; + RegionCharacteristics[i].m_fgr_region_width = m_fgrSEIregionCharacteristics[i].m_fgr_region_width ; + RegionCharacteristics[i].m_fgr_region_height = m_fgrSEIregionCharacteristics[i].m_fgr_region_height ; + RegionCharacteristics[i].m_film_grain_enabled_flag = m_fgrSEIregionCharacteristics[i].m_film_grain_enabled_flag ; + if (RegionCharacteristics[i].m_film_grain_enabled_flag) + { + RegionCharacteristics[i].m_fgr_regionIntervals[0].m_fgr_region_interval_min = m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[0].m_fgr_region_interval_min ; + RegionCharacteristics[i].m_fgr_regionIntervals[0].m_fgr_region_interval_max = m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[0].m_fgr_region_interval_max ; + RegionCharacteristics[i].m_fgr_regionIntervals[1].m_fgr_region_interval_min = m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[1].m_fgr_region_interval_min ; + RegionCharacteristics[i].m_fgr_regionIntervals[1].m_fgr_region_interval_max = m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[1].m_fgr_region_interval_max ; + RegionCharacteristics[i].m_fgr_regionIntervals[2].m_fgr_region_interval_min = m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[2].m_fgr_region_interval_min ; + RegionCharacteristics[i].m_fgr_regionIntervals[2].m_fgr_region_interval_max = m_fgrSEIregionCharacteristics[i].m_fgr_regionIntervals[2].m_fgr_region_interval_max ; + } + } + } +#endif // cll SEI void setCLLSEIEnabled(bool b) { m_cllSEIEnabled = b; } bool getCLLSEIEnabled() { return m_cllSEIEnabled; } diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index c53985989..a98945f0d 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -801,7 +801,27 @@ void EncGOP::xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS } seiMessages.push_back(sei); } - +#if JVET_AG0328 + // film grain regions + if (m_pcCfg->getFilmGrainRegionsCharactersticsSEIEnabled() && !m_pcCfg->getFilmGrainRegionsCharactersticsSEIPerPictureSEI()) + { + SEIFilmGrainRegionsCharacteristics *sei = new SEIFilmGrainRegionsCharacteristics; + m_seiEncoder.initSEIFilmGrainRegionsCharacteristics(sei); + if (m_pcCfg->getFilmGrainRegionsAnalysisEnabled()) + { + printf("Film grain analysis not implemented yet for region based\n"); + /*sei->m_fgr_log2ScaleFactor = m_fgrAnalyzer.getLog2scaleFactor(); + for (int compIdx = 0; compIdx < getNumberValidComponents(m_pcCfg->getChromaFormatIdc()); compIdx++) + { + if (sei->m_compModel[compIdx].presentFlag) + { // higher importance of presentFlag is from cfg file + sei->m_compModel[compIdx] = m_fgAnalyzer.getCompModel(compIdx); + } + }*/ + } + seiMessages.push_back(sei); + } +#endif // mastering display colour volume if (m_pcCfg->getMasteringDisplaySEI().colourVolumeSEIEnabled) { @@ -1017,6 +1037,26 @@ void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessage } seiMessages.push_back(fgcSEI); } +#if JVET_AG0328 + if (m_pcCfg->getFilmGrainRegionsCharactersticsSEIEnabled() && m_pcCfg->getFilmGrainRegionsCharactersticsSEIPerPictureSEI()) + { + SEIFilmGrainRegionsCharacteristics *fgrSEI = new SEIFilmGrainRegionsCharacteristics; + m_seiEncoder.initSEIFilmGrainRegionsCharacteristics(fgrSEI); + if (m_pcCfg->getFilmGrainRegionsAnalysisEnabled()) + { + printf("Film grain analysis not implemented yet for region based\n"); + /*fgcSEI->m_log2ScaleFactor = m_fgAnalyzer.getLog2scaleFactor(); + for (int compIdx = 0; compIdx < getNumberValidComponents(m_pcCfg->getChromaFormatIdc()); compIdx++) + { + if (fgcSEI->m_compModel[compIdx].presentFlag) + { // higher importance of presentFlag is from cfg file + fgcSEI->m_compModel[compIdx] = m_fgAnalyzer.getCompModel(compIdx); + } + }*/ + } + seiMessages.push_back(fgrSEI); + } +#endif if (m_pcCfg->getNnPostFilterSEIActivationEnabled() && !m_pcCfg->getNnPostFilterSEIActivationUseSuffixSEI()) { diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp index 6a348d976..92e590d37 100644 --- a/source/Lib/EncoderLib/SEIEncoder.cpp +++ b/source/Lib/EncoderLib/SEIEncoder.cpp @@ -653,6 +653,20 @@ void SEIEncoder::initSEIProcessingOrderInfo(SEIProcessingOrderInfo *seiProcessin #endif break; } +#if JVET_AG0328 + case SEI::PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS: + { + SEIFilmGrainRegionsCharacteristics* seiFGR = new SEIFilmGrainRegionsCharacteristics; + initSEIFilmGrainRegionsCharacteristics(seiFGR); + #if JVET_AF0310_PO_NESTING + seiProcessingOrderNesting->m_ponWrapSeiMessages.push_back(seiFGR); + #else + seiProcessingOrderInfo->m_posWrapSeiMessages.push_back(seiFGR); + #endif + break; + } + +#endif case SEI::PayloadType::CONTENT_LIGHT_LEVEL_INFO: { SEIContentLightLevelInfo* seiCCL = new SEIContentLightLevelInfo; @@ -994,6 +1008,50 @@ void SEIEncoder::initSEIFilmGrainCharacteristics(SEIFilmGrainCharacteristics *se } } +#if JVET_AG0328 +void SEIEncoder::initSEIFilmGrainRegionsCharacteristics(SEIFilmGrainRegionsCharacteristics *seiFilmGrainRegion) +{ + CHECK(!(m_isInitialized), "Unspecified error"); + CHECK(!(seiFilmGrainRegion != nullptr), "Unspecified error"); + // Set SEI message parameters read from command line options + seiFilmGrainRegion->m_filmGrainRegionsCharacteristicsCancelFlag = m_pcCfg->getFilmGrainRegionsCharactersticsSEICancelFlag(); + seiFilmGrainRegion->m_filmGrainRegionsCharacteristicsPersistenceFlag = m_pcCfg->getFilmGrainRegionsCharactersticsSEIPersistenceFlag(); + seiFilmGrainRegion->m_filmGrainRegionsModelId = m_pcCfg->getFilmGrainRegionsCharactersticsSEIModelID(); + seiFilmGrainRegion->m_fgr_separateColourDescriptionPresentFlag = m_pcCfg->getFilmGrainRegionsCharactersticsSEISepColourDescPresent(); + seiFilmGrainRegion->m_fgr_blendingModeId = m_pcCfg->getFilmGrainRegionsCharactersticsSEIBlendingModeID(); + seiFilmGrainRegion->m_fgr_log2ScaleFactor = m_pcCfg->getFilmGrainRegionsCharactersticsSEILog2ScaleFactor(); + for (int i = 0; i < MAX_NUM_COMPONENT; i++) + { + seiFilmGrainRegion->m_fgr_compModel[i].presentFlag = m_pcCfg->getFGRSEICompModelPresent(i); + if (seiFilmGrainRegion->m_fgr_compModel[i].presentFlag) + { + seiFilmGrainRegion->m_fgr_compModel[i].numModelValues = 1 + m_pcCfg->getFGRSEINumModelValuesMinus1(i); + seiFilmGrainRegion->m_fgr_compModel[i].numIntensityIntervals = 1 + m_pcCfg->getFGRSEINumIntensityIntervalMinus1(i); + seiFilmGrainRegion->m_fgr_compModel[i].intensityValues.resize(seiFilmGrainRegion->m_fgr_compModel[i].numIntensityIntervals); + for (int j = 0; j < seiFilmGrainRegion->m_fgr_compModel[i].numIntensityIntervals; j++) + { + seiFilmGrainRegion->m_fgr_compModel[i].intensityValues[j].intensityIntervalLowerBound = m_pcCfg->getFGRSEIIntensityIntervalLowerBound(i, j); + seiFilmGrainRegion->m_fgr_compModel[i].intensityValues[j].intensityIntervalUpperBound = m_pcCfg->getFGRSEIIntensityIntervalUpperBound(i, j); + seiFilmGrainRegion->m_fgr_compModel[i].intensityValues[j].compModelValue.resize(seiFilmGrainRegion->m_fgr_compModel[i].numModelValues); + for (int k = 0; k < seiFilmGrainRegion->m_fgr_compModel[i].numModelValues; k++) + { + seiFilmGrainRegion->m_fgr_compModel[i].intensityValues[j].compModelValue[k] = m_pcCfg->getFGRSEICompModelValue(i, j, k); + } + } + } + } + seiFilmGrainRegion->m_fgr_region_information_present_flag = m_pcCfg->getFilmGrainRegionInformationPresentFlag(); + seiFilmGrainRegion->m_fgr_region_based_adaptation_flag = m_pcCfg->getFilmGrainRegionBasedAdaptationFlag(); + seiFilmGrainRegion->m_fgr_alpha_channel_adaptation_flag = m_pcCfg->getFilmGrainAlphaChannelAdaptationFlag(); + seiFilmGrainRegion->m_fgr_active_regions_number = m_pcCfg->getFilmGrainNumActiveRegionsMinus1() + 1 ; + if (seiFilmGrainRegion->m_fgr_region_based_adaptation_flag) + { + seiFilmGrainRegion->fgr_active_regions.resize(seiFilmGrainRegion->m_fgr_active_regions_number); + m_pcCfg->getFilmGrainRegionCharacteristics(seiFilmGrainRegion->fgr_active_regions,m_pcCfg->getFilmGrainNumActiveRegionsMinus1()); + } +} +#endif + void SEIEncoder::initSEIMasteringDisplayColourVolume(SEIMasteringDisplayColourVolume *seiMDCV) { CHECK(!(m_isInitialized), "Unspecified error"); diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h index df965ceda..1184026c1 100644 --- a/source/Lib/EncoderLib/SEIEncoder.h +++ b/source/Lib/EncoderLib/SEIEncoder.h @@ -77,6 +77,9 @@ public: void initSEISampleAspectRatioInfo(SEISampleAspectRatioInfo *sei); void initSEIPhaseIndication(SEIPhaseIndication* sei, int ppsId); void initSEIFilmGrainCharacteristics(SEIFilmGrainCharacteristics *sei); +#if JVET_AG0328 + void initSEIFilmGrainRegionsCharacteristics(SEIFilmGrainRegionsCharacteristics *sei); +#endif void initSEIMasteringDisplayColourVolume(SEIMasteringDisplayColourVolume *sei); void initSEIContentLightLevel(SEIContentLightLevelInfo *sei); void initSEIAmbientViewingEnvironment(SEIAmbientViewingEnvironment *sei); diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp index 678f3effd..2be643e11 100644 --- a/source/Lib/EncoderLib/SEIwrite.cpp +++ b/source/Lib/EncoderLib/SEIwrite.cpp @@ -137,7 +137,12 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI &sei, HRD &h case SEI::PayloadType::FILM_GRAIN_CHARACTERISTICS: xWriteSEIFilmGrainCharacteristics(*static_cast(&sei)); break; - case SEI::PayloadType::CONTENT_LIGHT_LEVEL_INFO: +#if JVET_AG0328 + case SEI::PayloadType::FILM_GRAIN_REGIONS_CHARACTERISTICS: + xWriteSEIFilmGrainRegionsCharacteristics(*static_cast(&sei)); + break; +#endif + case SEI::PayloadType::CONTENT_LIGHT_LEVEL_INFO: xWriteSEIContentLightLevelInfo(*static_cast(&sei)); break; case SEI::PayloadType::AMBIENT_VIEWING_ENVIRONMENT: @@ -1453,6 +1458,95 @@ void SEIWriter::xWriteSEIFilmGrainCharacteristics(const SEIFilmGrainCharacterist xWriteFlag(sei.m_filmGrainCharacteristicsPersistenceFlag, "fg_characteristics_persistence_flag"); } // cancel flag } +#if JVET_AG0328 +void SEIWriter::xWriteSEIFilmGrainRegionsCharacteristics(const SEIFilmGrainRegionsCharacteristics &sei) +{ + xWriteFlag(sei.m_filmGrainRegionsCharacteristicsCancelFlag, "fgr_cancel_flag"); + if (!sei.m_filmGrainRegionsCharacteristicsCancelFlag) + { + xWriteCode(sei.m_filmGrainRegionsModelId, 2, "fgr_model_id"); + xWriteFlag(sei.m_fgr_separateColourDescriptionPresentFlag, "fgr_separate_colour_description_present_flag"); + if (sei.m_fgr_separateColourDescriptionPresentFlag) + { + xWriteCode(sei.m_filmGrainRegionsBitDepthLumaMinus8, 3, "fgr_bit_depth_luma_minus8"); + xWriteCode(sei.m_filmGrainRegionsBitDepthChromaMinus8, 3, "fgr_bit_depth_chroma_minus8"); + xWriteFlag(sei.m_filmGrainRegionsFullRangeFlag, "fgr_full_range_flag"); + xWriteCode(sei.m_filmGrainRegionsColourPrimaries, 8, "fgr_colour_primaries"); + xWriteCode(sei.m_filmGrainRegionsTransferCharacteristics, 8, "fgr_transfer_characteristics"); + xWriteCode(sei.m_filmGrainRegionsMatrixCoeffs, 8, "fgr_matrix_coeffs"); + } + xWriteCode(sei.m_fgr_blendingModeId, 2, "fgr_blending_mode_id"); + xWriteCode(sei.m_fgr_log2ScaleFactor, 4, "fgr_log2_scale_factor"); + for (int c = 0; c<3; c++) + { + const SEIFilmGrainRegionsCharacteristics::CompModel &cm = sei.m_fgr_compModel[c]; + const uint32_t numIntensityIntervals = (uint32_t) cm.numIntensityIntervals; + const uint32_t numModelValues = cm.numModelValues; + xWriteFlag(sei.m_fgr_compModel[c].presentFlag && numIntensityIntervals>0 && numModelValues>0, "fgr_comp_model_present_flag[c]"); + } + for (uint32_t c = 0; c<3; c++) + { + const SEIFilmGrainRegionsCharacteristics::CompModel &cm = sei.m_fgr_compModel[c]; + const uint32_t numIntensityIntervals = (uint32_t) cm.numIntensityIntervals; + const uint32_t numModelValues = cm.numModelValues; + if (cm.presentFlag && numIntensityIntervals>0 && numModelValues>0) + { + assert(numIntensityIntervals <= 256); + assert(numModelValues <= 256); + xWriteCode(numIntensityIntervals - 1, 8, "fgr_num_intensity_intervals_minus1[c]"); + xWriteCode(numModelValues - 1, 3, "fgr_num_model_values_minus1[c]"); + for (uint32_t interval = 0; interval0 && numModelValues>0) + { + xWriteCode(sei.fgr_active_regions[idx].m_fgr_regionIntervals[c].m_fgr_region_interval_min, 8, "fgr_region_interval_min[i][c]"); + xWriteCode(sei.fgr_active_regions[idx].m_fgr_regionIntervals[c].m_fgr_region_interval_max, 8, "fgr_region_interval_max[i][c]"); + } + } + } + } + } + else + { + xWriteFlag(sei.m_fgr_alpha_channel_adaptation_flag, "fgr_alpha_channel_adaptation_flag"); + } + } + xWriteFlag(sei.m_filmGrainRegionsCharacteristicsPersistenceFlag, "fgr_characteristics_persistence_flag"); + } // cancel flag +} +#endif void SEIWriter::xWriteSEIContentLightLevelInfo(const SEIContentLightLevelInfo& sei) { diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h index fd890d63d..fd3b6aef6 100644 --- a/source/Lib/EncoderLib/SEIwrite.h +++ b/source/Lib/EncoderLib/SEIwrite.h @@ -89,6 +89,9 @@ protected: void xWriteSEIConstrainedRaslIndication (const SEIConstrainedRaslIndication &sei); void xWriteSEIUserDataRegistered(const SEIUserDataRegistered& sei); void xWriteSEIFilmGrainCharacteristics(const SEIFilmGrainCharacteristics& sei); +#if JVET_AG0328 + void xWriteSEIFilmGrainRegionsCharacteristics(const SEIFilmGrainRegionsCharacteristics& sei); +#endif void xWriteSEIContentLightLevelInfo(const SEIContentLightLevelInfo& sei); void xWriteSEIAmbientViewingEnvironment(const SEIAmbientViewingEnvironment& sei); void xWriteSEIContentColourVolume(const SEIContentColourVolume &sei);