From 5961578d61da2407703175e7d0e3ba35633c9efa Mon Sep 17 00:00:00 2001 From: urbanf <fabrice.urban@interdigital.com> Date: Mon, 21 Jun 2021 20:48:24 +0200 Subject: [PATCH] added code for JVET_V0108: Colour Transform Information SEI --- source/App/DecoderApp/DecApp.cpp | 91 ++++++++++ source/App/DecoderApp/DecApp.h | 3 + source/App/DecoderApp/DecAppCfg.cpp | 6 + source/App/DecoderApp/DecAppCfg.h | 3 + source/App/EncoderApp/EncApp.cpp | 17 ++ source/App/EncoderApp/EncAppCfg.cpp | 71 ++++++++ source/App/EncoderApp/EncAppCfg.h | 15 ++ source/App/Parcat/parcat.cpp | 20 ++ source/Lib/CommonLib/Buffer.cpp | 64 +++++++ source/Lib/CommonLib/Buffer.h | 4 + source/Lib/CommonLib/Picture.cpp | 49 +++++ source/Lib/CommonLib/Picture.h | 9 + source/Lib/CommonLib/SEI.cpp | 3 + source/Lib/CommonLib/SEI.h | 27 +++ source/Lib/CommonLib/SEIColourTransform.cpp | 192 ++++++++++++++++++++ source/Lib/CommonLib/SEIColourTransform.h | 73 ++++++++ source/Lib/CommonLib/TypeDef.h | 12 +- source/Lib/DecoderLib/DecLib.cpp | 8 + source/Lib/DecoderLib/DecLib.h | 5 + source/Lib/DecoderLib/SEIread.cpp | 86 +++++++++ source/Lib/DecoderLib/SEIread.h | 3 + source/Lib/EncoderLib/EncCfg.h | 43 +++++ source/Lib/EncoderLib/EncGOP.cpp | 9 + source/Lib/EncoderLib/SEIEncoder.cpp | 26 +++ source/Lib/EncoderLib/SEIEncoder.h | 3 + source/Lib/EncoderLib/SEIwrite.cpp | 61 +++++++ source/Lib/EncoderLib/SEIwrite.h | 3 + 27 files changed, 905 insertions(+), 1 deletion(-) create mode 100644 source/Lib/CommonLib/SEIColourTransform.cpp create mode 100644 source/Lib/CommonLib/SEIColourTransform.h diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index 023ab1594..5886ea266 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -417,6 +417,42 @@ uint32_t DecApp::decode() m_cVideoIOYuvReconFile[nalu.m_nuhLayerId].setBitdepthShift(channelType, reconBitdepth - fileBitdepth); } } +#if JVET_V0108 + if (!m_SEICTIFileName.empty() && !m_cVideoIOYuvSEICTIFile[nalu.m_nuhLayerId].isOpen()) + { + const BitDepths& bitDepths = pcListPic->front()->cs->sps->getBitDepths(); // use bit depths of first reconstructed picture. + for (uint32_t channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) + { + if (m_outputBitDepth[channelType] == 0) + { + m_outputBitDepth[channelType] = bitDepths.recon[channelType]; + } + } + + if (m_packedYUVMode && (m_outputBitDepth[CH_L] != 10 && m_outputBitDepth[CH_L] != 12)) + { + EXIT("Invalid output bit-depth for packed YUV output, aborting\n"); + } + + std::string SEICTIFileName = m_SEICTIFileName; + if (m_SEICTIFileName.compare("/dev/null") && m_cDecLib.getVPS() != nullptr && m_cDecLib.getVPS()->getMaxLayers() > 1 && xIsNaluWithinTargetOutputLayerIdSet(&nalu)) + { + size_t pos = SEICTIFileName.find_last_of('.'); + if (pos != string::npos) + { + SEICTIFileName.insert(pos, std::to_string(nalu.m_nuhLayerId)); + } + else + { + SEICTIFileName.append(std::to_string(nalu.m_nuhLayerId)); + } + } + if ((m_cDecLib.getVPS() != nullptr && (m_cDecLib.getVPS()->getMaxLayers() == 1 || xIsNaluWithinTargetOutputLayerIdSet(&nalu))) || m_cDecLib.getVPS() == nullptr) + { + m_cVideoIOYuvSEICTIFile[nalu.m_nuhLayerId].open(SEICTIFileName, true, m_outputBitDepth, m_outputBitDepth, bitDepths.recon); // write mode + } + } +#endif if (!m_annotatedRegionsSEIFileName.empty()) { xOutputAnnotatedRegions(pcListPic); @@ -618,6 +654,15 @@ void DecApp::xDestroyDecLib() recFile.second.close(); } } +#if JVET_V0108 + if (!m_SEICTIFileName.empty()) + { + for (auto& recFile : m_cVideoIOYuvSEICTIFile) + { + recFile.second.close(); + } + } +#endif // destroy decoder class m_cDecLib.destroy(); @@ -776,6 +821,29 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId ) NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range ); } } +#if JVET_V0108 + // Perform CTI on decoded frame and write to output CTI file + if (!m_SEICTIFileName.empty()) + { + const Window& conf = pcPic->getConformanceWindow(); + const SPS* sps = pcPic->cs->sps; + ChromaFormat chromaFormatIDC = sps->getChromaFormatIdc(); + if (m_upscaledOutput) + { + m_cVideoIOYuvSEICTIFile[pcPic->layerId].writeUpscaledPicture(*sps, *pcPic->cs->pps, pcPic->getDisplayBuf(), m_outputColourSpaceConvert, m_packedYUVMode, m_upscaledOutput, NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); + } + else + { + m_cVideoIOYuvSEICTIFile[pcPic->layerId].write(pcPic->getRecoBuf().get(COMPONENT_Y).width, pcPic->getRecoBuf().get(COMPONENT_Y).height, pcPic->getDisplayBuf(), + m_outputColourSpaceConvert, m_packedYUVMode, + conf.getWindowLeftOffset() * SPS::getWinUnitX(chromaFormatIDC), + conf.getWindowRightOffset() * SPS::getWinUnitX(chromaFormatIDC), + conf.getWindowTopOffset() * SPS::getWinUnitY(chromaFormatIDC), + conf.getWindowBottomOffset() * SPS::getWinUnitY(chromaFormatIDC), + NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); + } + } +#endif writeLineToOutputLog(pcPic); // update POC of display order @@ -923,6 +991,29 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId ) NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range ); } } +#if JVET_V0108 + // Perform CTI on decoded frame and write to output CTI file + if (!m_SEICTIFileName.empty()) + { + const Window& conf = pcPic->getConformanceWindow(); + const SPS* sps = pcPic->cs->sps; + ChromaFormat chromaFormatIDC = sps->getChromaFormatIdc(); + if (m_upscaledOutput) + { + m_cVideoIOYuvSEICTIFile[pcPic->layerId].writeUpscaledPicture(*sps, *pcPic->cs->pps, pcPic->getDisplayBuf(), m_outputColourSpaceConvert, m_packedYUVMode, m_upscaledOutput, NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); + } + else + { + m_cVideoIOYuvSEICTIFile[pcPic->layerId].write(pcPic->getRecoBuf().get(COMPONENT_Y).width, pcPic->getRecoBuf().get(COMPONENT_Y).height, pcPic->getDisplayBuf(), + m_outputColourSpaceConvert, m_packedYUVMode, + conf.getWindowLeftOffset() * SPS::getWinUnitX(chromaFormatIDC), + conf.getWindowRightOffset() * SPS::getWinUnitX(chromaFormatIDC), + conf.getWindowTopOffset() * SPS::getWinUnitY(chromaFormatIDC), + conf.getWindowBottomOffset() * SPS::getWinUnitY(chromaFormatIDC), + NUM_CHROMA_FORMAT, m_bClipOutputVideoToRec709Range); + } + } +#endif writeLineToOutputLog(pcPic); #if JVET_S0078_NOOUTPUTPRIORPICFLAG } diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h index d3573294b..2b3580ab4 100644 --- a/source/App/DecoderApp/DecApp.h +++ b/source/App/DecoderApp/DecApp.h @@ -61,6 +61,9 @@ private: // class interface DecLib m_cDecLib; ///< decoder class std::unordered_map<int, VideoIOYuv> m_cVideoIOYuvReconFile; ///< reconstruction YUV class +#if JVET_V0108 + std::unordered_map<int, VideoIOYuv> m_cVideoIOYuvSEICTIFile; ///< reconstruction YUV with CTI class +#endif // for output control int m_iPOCLastDisplay; ///< last POC in display order diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index 0a126cb13..439517aba 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -96,6 +96,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) ("SEINoDisplay", m_decodedNoDisplaySEIEnabled, true, "Control handling of decoded no display SEI messages") ("TarDecLayerIdSetFile,l", cfg_TargetDecLayerIdSetFile, string(""), "targetDecLayerIdSet file name. The file should include white space separated LayerId values to be decoded. Omitting the option or a value of -1 in the file decodes all layers.") ("SEIColourRemappingInfoFilename", m_colourRemapSEIFileName, string(""), "Colour Remapping YUV output file name. If empty, no remapping is applied (ignore SEI message)\n") +#if JVET_V0108 + ("SEICTIFilename", m_SEICTIFileName, string(""), "CTI YUV output file name. If empty, no Colour Transform is applied (ignore SEI message)\n") +#endif ("SEIAnnotatedRegionsInfoFilename", m_annotatedRegionsSEIFileName, string(""), "Annotated regions output file name. If empty, no object information will be saved (ignore SEI message)\n") ("OutputDecodedSEIMessagesFilename", m_outputDecodedSEIMessagesFilename, 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 @@ -258,6 +261,9 @@ DecAppCfg::DecAppCfg() , m_decodedPictureHashSEIEnabled(0) , m_decodedNoDisplaySEIEnabled(false) , m_colourRemapSEIFileName() +#if JVET_V0108 +, m_SEICTIFileName() +#endif , m_annotatedRegionsSEIFileName() , m_targetDecLayerIdSet() , m_outputDecodedSEIMessagesFilename() diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index bdf0db7a9..157c18cfc 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -72,6 +72,9 @@ protected: int m_decodedPictureHashSEIEnabled; ///< Checksum(3)/CRC(2)/MD5(1)/disable(0) acting on decoded picture hash SEI message bool m_decodedNoDisplaySEIEnabled; ///< Enable(true)/disable(false) writing only pictures that get displayed based on the no display SEI message std::string m_colourRemapSEIFileName; ///< output Colour Remapping file name +#if JVET_V0108 + std::string m_SEICTIFileName; ///< output Recon with CTI file name +#endif std::string m_annotatedRegionsSEIFileName; ///< annotated regions file name std::vector<int> 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 ba5e799ef..6b6e0c8fd 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -972,6 +972,23 @@ void EncApp::xInitLibCfg() m_cEncLib.setAmbientViewingEnvironmentSEIIlluminance (m_aveSEIAmbientIlluminance); m_cEncLib.setAmbientViewingEnvironmentSEIAmbientLightX ((uint16_t)m_aveSEIAmbientLightX); m_cEncLib.setAmbientViewingEnvironmentSEIAmbientLightY ((uint16_t)m_aveSEIAmbientLightY); +#if JVET_V0108 + // colour tranform information sei + m_cEncLib.setCtiSEIEnabled(m_ctiSEIEnabled); + m_cEncLib.setCtiSEIId(m_ctiSEIId); + m_cEncLib.setCtiSEISignalInfoFlag(m_ctiSEISignalInfoFlag); + m_cEncLib.setCtiSEIFullRangeFlag(m_ctiSEIFullRangeFlag); + m_cEncLib.setCtiSEIPrimaries(m_ctiSEIPrimaries); + m_cEncLib.setCtiSEITransferFunction(m_ctiSEITransferFunction); + m_cEncLib.setCtiSEIMatrixCoefs(m_ctiSEIMatrixCoefs); + m_cEncLib.setCtiSEICrossComponentFlag(m_ctiSEICrossComponentFlag); + m_cEncLib.setCtiSEICrossComponentInferred(m_ctiSEICrossComponentInferred); + m_cEncLib.setCtiSEINbChromaLut(m_ctiSEINumberChromaLut); + m_cEncLib.setCtiSEIChromaOffset(m_ctiSEIChromaOffset); + for (int i = 0; i < MAX_NUM_COMPONENT; i++) { + m_cEncLib.setCtiSEILut(m_ctiSEILut[i], i); + } +#endif // content colour volume SEI m_cEncLib.setCcvSEIEnabled (m_ccvSEIEnabled); m_cEncLib.setCcvSEICancelFlag (m_ccvSEICancelFlag); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index ed0823ede..96d9ad09a 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -622,6 +622,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) SMultiValueInput<int> cfg_DisplayPrimariesCode (0, 50000, 6, 6, defaultPrimaryCodes, sizeof(defaultPrimaryCodes )/sizeof(int)); SMultiValueInput<int> cfg_DisplayWhitePointCode (0, 50000, 2, 2, defaultWhitePointCode, sizeof(defaultWhitePointCode)/sizeof(int)); +#if JVET_V0108 + SMultiValueInput<int16_t> cfg_SEICTILut0(0, 128, 0, MAX_CTI_LUT_SIZE + 1); + SMultiValueInput<int16_t> cfg_SEICTILut1(0, 128, 0, MAX_CTI_LUT_SIZE + 1); + SMultiValueInput<int16_t> cfg_SEICTILut2(0, 128, 0, MAX_CTI_LUT_SIZE + 1); +#endif SMultiValueInput<bool> cfg_timeCodeSeiTimeStampFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); SMultiValueInput<bool> cfg_timeCodeSeiNumUnitFieldBasedFlag(0, 1, 0, MAX_TIMECODE_SEI_SETS); SMultiValueInput<int> cfg_timeCodeSeiCountingType (0, 6, 0, MAX_TIMECODE_SEI_SETS); @@ -1381,6 +1386,23 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("SEIAVEAmbientIlluminance", m_aveSEIAmbientIlluminance, 100000u, "Specifies the environmental illluminance of the ambient viewing environment in units of 1/10000 lux for the ambient viewing environment SEI message") ("SEIAVEAmbientLightX", m_aveSEIAmbientLightX, 15635u, "Specifies the normalized x chromaticity coordinate of the environmental ambient light in the nominal viewing enviornment according to the CIE 1931 definition in units of 1/50000 lux for the ambient viewing enviornment SEI message") ("SEIAVEAmbientLightY", m_aveSEIAmbientLightY, 16450u, "Specifies the normalized y chromaticity coordinate of the environmental ambient light in the nominal viewing enviornment according to the CIE 1931 definition in units of 1/50000 lux for the ambient viewing enviornment SEI message") +#if JVET_V0108 +// colour tranform information SEI + ("SEICTIEnabled", m_ctiSEIEnabled, false, "Control generation of the Colour transform information SEI message") + ("SEICTIId", m_ctiSEIId, 0u, "Id of the Colour transform information SEI message") + ("SEICTISignalInfoFlag", m_ctiSEISignalInfoFlag, false, "indicates if signal information are present in the Colour transform information SEI message") + ("SEICTIFullRangeFlag", m_ctiSEIFullRangeFlag, false, "specifies signal range after applying the Colour transform information SEI message") + ("SEICTIPrimaries", m_ctiSEIPrimaries, 0u, "indicates the signal primaries after applying the Colour transform information SEI message") + ("SEICTITransferFunction", m_ctiSEITransferFunction, 0u, "indicates the signal transfer function after applying the Colour transform information SEI message") + ("SEICTIMatrixCoefs", m_ctiSEIMatrixCoefs, 0u, "indicates the signal matrix coefficients after applying the Colour transform information SEI message") + ("SEICTICrossCompFlag", m_ctiSEICrossComponentFlag, true, "Specifies if cross-component transform mode is enabled in SEI CTI") + ("SEICTICrossCompInferred", m_ctiSEICrossComponentInferred, true, "Specifies if cross-component transform LUT is inferred in SEI CTI") + ("SEICTINbChromaLut", m_ctiSEINumberChromaLut, 0u, "Specifies the number of chroma LUTs in SEI CTI") + ("SEICTIChromaOffset", m_ctiSEIChromaOffset, 0, "Specifies the chroma offset of SEI CTI") + ("SEICTILut0", cfg_SEICTILut0, cfg_SEICTILut0, "slope values for component 0 of SEI CTI") + ("SEICTILut1", cfg_SEICTILut1, cfg_SEICTILut1, "slope values for component 1 of SEI CTI") + ("SEICTILut2", cfg_SEICTILut2, cfg_SEICTILut2, "slope values for component 2 of SEI CTI") +#endif // content colour volume SEI ("SEICCVEnabled", m_ccvSEIEnabled, false, "Control generation of the Content Colour Volume SEI message") ("SEICCVCancelFlag", m_ccvSEICancelFlag, true, "Specifies the persistence of any previous content colour volume SEI message in output order.") @@ -2385,6 +2407,46 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) m_masteringDisplay.whitePoint[idx] = uint16_t((cfg_DisplayWhitePointCode.values.size() > idx) ? cfg_DisplayWhitePointCode.values[idx] : 0); } } +#if JVET_V0108 + if (m_ctiSEIEnabled) { + CHECK(!m_ctiSEICrossComponentFlag && m_ctiSEICrossComponentInferred, "CTI CrossComponentFlag is 0, but CTI CrossComponentInferred is 1 (must be 0 for CrossComponentFlag 0)"); + CHECK(!m_ctiSEICrossComponentFlag && !m_ctiSEICrossComponentInferred && !m_ctiSEINumberChromaLut, "For CTI CrossComponentFlag = 0, CTI NumberChromaLut needs to be specified (1 or 2) "); + CHECK(m_ctiSEICrossComponentFlag && !m_ctiSEICrossComponentInferred && !m_ctiSEINumberChromaLut, "For CTI CrossComponentFlag = 1 and CrossComponentInferred = 0, CTI NumberChromaLut needs to be specified (1 or 2) "); + + CHECK(cfg_SEICTILut0.values.empty(), "SEI CTI (SEICTIEnabled) but no LUT0 specified"); + m_ctiSEILut[0].presentFlag = true; + m_ctiSEILut[0].numLutValues = (int)cfg_SEICTILut0.values.size(); + m_ctiSEILut[0].lutValues = cfg_SEICTILut0.values; + + if (!m_ctiSEICrossComponentFlag || (m_ctiSEICrossComponentFlag && !m_ctiSEICrossComponentInferred)) { + CHECK(cfg_SEICTILut1.values.empty(), "SEI CTI LUT1 not specified"); + m_ctiSEILut[1].presentFlag = true; + m_ctiSEILut[1].numLutValues = (int)cfg_SEICTILut1.values.size(); + m_ctiSEILut[1].lutValues = cfg_SEICTILut1.values; + + if (m_ctiSEINumberChromaLut == 1) { // Cb lut the same as Cr lut + m_ctiSEILut[2].presentFlag = true; + m_ctiSEILut[2].numLutValues = m_ctiSEILut[1].numLutValues; + m_ctiSEILut[2].lutValues = m_ctiSEILut[1].lutValues; + } + else if (m_ctiSEINumberChromaLut == 2) { // read from cfg + CHECK(cfg_SEICTILut2.values.empty(), "SEI CTI LUT2 not specified"); + m_ctiSEILut[2].presentFlag = true; + m_ctiSEILut[2].numLutValues = (int)cfg_SEICTILut2.values.size(); + m_ctiSEILut[2].lutValues = cfg_SEICTILut2.values; + } + else { + CHECK(m_ctiSEINumberChromaLut < 1 && m_ctiSEINumberChromaLut > 2, "Number of chroma LUTs is missing or out of range!"); + } + } + // check if lut size is power of 2 + for (int idx = 0; idx < MAX_NUM_COMPONENT; idx++) { + int n = m_ctiSEILut[idx].numLutValues - 1; + CHECK(n > 0 && (n & (n - 1)) != 0, "Size of LUT minus 1 should be power of 2!"); + CHECK(n > MAX_CTI_LUT_SIZE, "LUT size minus 1 is larger than MAX_CTI_LUT_SIZE (64)!"); + } + } +#endif if ( m_omniViewportSEIEnabled && !m_omniViewportSEICancelFlag ) { CHECK (!( m_omniViewportSEICntMinus1 >= 0 && m_omniViewportSEICntMinus1 < 16 ), "SEIOmniViewportCntMinus1 must be in the range of 0 to 16"); @@ -2858,6 +2920,12 @@ bool EncAppCfg::xCheckParameter() if (m_updateCtrl > 0 && m_adpOption > 2) { m_adpOption -= 2; } } +#if JVET_V0108 + if (m_ctiSEIEnabled) + { + xConfirmPara(m_ctiSEINumberChromaLut < 0 || m_ctiSEINumberChromaLut > 2, "CTI number of chroma LUTs is out of range"); + } +#endif xConfirmPara( m_cbQpOffset < -12, "Min. Chroma Cb QP Offset is -12" ); xConfirmPara( m_cbQpOffset > 12, "Max. Chroma Cb QP Offset is 12" ); xConfirmPara( m_crQpOffset < -12, "Min. Chroma Cr QP Offset is -12" ); @@ -4210,6 +4278,9 @@ void EncAppCfg::xPrintParameter() msg(VERBOSE, "MRL:%d ", m_MRL); msg(VERBOSE, "MIP:%d ", m_MIP); msg(VERBOSE, "EncDbOpt:%d ", m_encDbOpt); +#if JVET_V0108 + msg(VERBOSE, "\nSEI CTI:%d ", m_ctiSEIEnabled); +#endif msg( VERBOSE, "\nFAST TOOL CFG: " ); msg( VERBOSE, "LCTUFast:%d ", m_useFastLCTU ); msg( VERBOSE, "FastMrg:%d ", m_useFastMrg ); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 76eaa2db0..305ce15a2 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -536,6 +536,21 @@ protected: uint32_t m_aveSEIAmbientIlluminance; uint32_t m_aveSEIAmbientLightX; uint32_t m_aveSEIAmbientLightY; +#if JVET_V0108 + // colour tranform information sei + bool m_ctiSEIEnabled; + uint32_t m_ctiSEIId; + bool m_ctiSEISignalInfoFlag; + bool m_ctiSEIFullRangeFlag; + uint32_t m_ctiSEIPrimaries; + uint32_t m_ctiSEITransferFunction; + uint32_t m_ctiSEIMatrixCoefs; + bool m_ctiSEICrossComponentFlag; + bool m_ctiSEICrossComponentInferred; + uint32_t m_ctiSEINumberChromaLut; + int m_ctiSEIChromaOffset; + LutModel m_ctiSEILut[MAX_NUM_COMPONENT]; +#endif // content colour volume sei bool m_ccvSEIEnabled; bool m_ccvSEICancelFlag; diff --git a/source/App/Parcat/parcat.cpp b/source/App/Parcat/parcat.cpp index d23035edf..17bbac025 100644 --- a/source/App/Parcat/parcat.cpp +++ b/source/App/Parcat/parcat.cpp @@ -214,6 +214,9 @@ std::vector<uint8_t> filter_segment(const std::vector<uint8_t> & v, int idx, int int off = 0; int cnt = 0; bool idr_found = false; +#if JVET_V0108 + bool is_pre_sei_before_idr = true; +#endif std::vector<uint8_t> out; out.reserve(v.size()); @@ -269,6 +272,12 @@ std::vector<uint8_t> filter_segment(const std::vector<uint8_t> & v, int idx, int parameterSetManager.storePPS( pps, inp_nalu.getBitstream().getFifo() ); } +#if JVET_V0108 + if (nalu_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nalu_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) + { + is_pre_sei_before_idr = false; + } +#endif if(nalu_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nalu_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) { poc = 0; @@ -329,13 +338,24 @@ std::vector<uint8_t> filter_segment(const std::vector<uint8_t> & v, int idx, int skip_next_sei = true; idr_found = true; } +#if JVET_V0108 + if ((idx > 1 && (nalu_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nalu_type == NAL_UNIT_CODED_SLICE_IDR_N_LP)) + || ((idx > 1 && !idr_found) && (nalu_type == NAL_UNIT_OPI || nalu_type == NAL_UNIT_DCI || nalu_type == NAL_UNIT_VPS || nalu_type == NAL_UNIT_SPS || nalu_type == NAL_UNIT_PPS || nalu_type == NAL_UNIT_PREFIX_APS || nalu_type == NAL_UNIT_SUFFIX_APS || nalu_type == NAL_UNIT_PH || nalu_type == NAL_UNIT_ACCESS_UNIT_DELIMITER)) + || (nalu_type == NAL_UNIT_SUFFIX_SEI && skip_next_sei) + || (idx > 1 && nalu_type == NAL_UNIT_PREFIX_SEI && is_pre_sei_before_idr)) +#else if ((idx > 1 && (nalu_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nalu_type == NAL_UNIT_CODED_SLICE_IDR_N_LP)) || ((idx > 1 && !idr_found) && (nalu_type == NAL_UNIT_OPI || nalu_type == NAL_UNIT_DCI || nalu_type == NAL_UNIT_VPS || nalu_type == NAL_UNIT_SPS || nalu_type == NAL_UNIT_PPS || nalu_type == NAL_UNIT_PREFIX_APS || nalu_type == NAL_UNIT_SUFFIX_APS || nalu_type == NAL_UNIT_PH || nalu_type == NAL_UNIT_ACCESS_UNIT_DELIMITER || nalu_type == NAL_UNIT_PREFIX_SEI)) || (nalu_type == NAL_UNIT_SUFFIX_SEI && skip_next_sei)) +#endif { } else { +#if JVET_V0108 + if (nalu_type == NAL_UNIT_PREFIX_SEI) + printf("insert NAL_UNIT_PREFIX_SEI\n"); +#endif out.insert(out.end(), p - nal_start, p); out.insert(out.end(), nalu.begin(), nalu.end()); } diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp index a53adaf77..863a5e971 100644 --- a/source/Lib/CommonLib/Buffer.cpp +++ b/source/Lib/CommonLib/Buffer.cpp @@ -484,6 +484,70 @@ void AreaBuf<Pel>::scaleSignal(const int scale, const bool dir, const ClpRng& cl } } +#if JVET_V0108 +template<> +void AreaBuf<Pel>::applyLumaCTI(std::vector<Pel>& pLUTY) +{ + Pel* dst = buf; + Pel* src = buf; + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + dst[x] = pLUTY[src[x]]; + } + dst += stride; + src += stride; + } +} + +template<> +void AreaBuf<Pel>::applyChromaCTI(Pel* bufY, int strideY, std::vector<Pel>& pLUTC, int bitDepth, ChromaFormat chrFormat, bool fwdMap) +{ + int range = 1 << bitDepth; + int offset = range / 2; + int sx = 1; + int sy = 1; + if (CHROMA_420 == chrFormat) { + sx = 2; sy = 2; + } + else if (CHROMA_422 == chrFormat) + { + sx = 2; + } + + Pel* dst = buf; + Pel* src = buf; + if (fwdMap) + { + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + int pelY = bufY[sy * y * strideY + sx * x]; + double scale = (double)pLUTC[pelY] / (double)(1 << CSCALE_FP_PREC); + dst[x] = Clip3((Pel)0, (Pel)(range - 1), (Pel)(offset + (double)(src[x] - offset) / scale + .5)); + } + dst += stride; + src += stride; + } + } + else + { + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + int pelY = bufY[sy * y * strideY + sx * x]; + int scal = pLUTC[pelY]; + dst[x] = Clip3(0, range - 1, ((offset << CSCALE_FP_PREC) + (src[x] - offset) * scal + (1 << (CSCALE_FP_PREC - 1))) >> CSCALE_FP_PREC); + } + dst += stride; + src += stride; + } + } +} +#endif template<> void AreaBuf<Pel>::addAvg( const AreaBuf<const Pel> &other1, const AreaBuf<const Pel> &other2, const ClpRng& clpRng) { diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h index 331c30950..ae3d874fd 100644 --- a/source/Lib/CommonLib/Buffer.h +++ b/source/Lib/CommonLib/Buffer.h @@ -137,6 +137,10 @@ struct AreaBuf : public Size void rspSignal ( std::vector<Pel>& pLUT ); void scaleSignal ( const int scale, const bool dir , const ClpRng& clpRng); +#if JVET_V0108 + void applyLumaCTI(std::vector<Pel>& pLUTY); + void applyChromaCTI(Pel* bufY, int strideY, std::vector<Pel>& pLUTUV, int bitDepth, ChromaFormat chrFormat, bool fwdMap); +#endif T computeAvg ( ) const; T& at( const int &x, const int &y ) { return buf[y * stride + x]; } diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index 892477ec5..1c6e648cd 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -63,6 +63,9 @@ Picture::Picture() topField = false; precedingDRAP = false; nonReferencePictureFlag = false; +#if JVET_V0108 + m_colourTranfParams = NULL; +#endif for( int i = 0; i < MAX_NUM_CHANNEL_TYPE; i++ ) { @@ -130,6 +133,9 @@ void Picture::destroy() delete[] m_spliceIdx; m_spliceIdx = NULL; } +#if JVET_V0108 + m_invColourTransfBuf = NULL; +#endif } void Picture::createTempBuffers( const unsigned _maxCUSize ) @@ -1208,3 +1214,46 @@ void Picture::addPictureToHashMapForInter() } } } +#if JVET_V0108 +void Picture::createColourTransfProcessor(bool bFirstPictureInSequence, SEIColourTransformApply* pCtiCharacteristics, PelStorage* pCtiBuf, int width, int height, ChromaFormat fmt, int bitDepth) +{ + m_colourTranfParams = pCtiCharacteristics; + m_invColourTransfBuf = pCtiBuf; + if (bFirstPictureInSequence) + { + // Create and initialize the Colour Transform Processor + m_colourTranfParams->create(width, height, fmt, bitDepth); + + //Frame level PelStorage buffer created to apply the Colour Transform + m_invColourTransfBuf->create(UnitArea(chromaFormat, Area(0, 0, width, height))); + } +} + +PelUnitBuf Picture::getDisplayBuf() +{ + int payloadType = 0; + std::list<SEI*>::iterator message; + + for (message = SEIs.begin(); message != SEIs.end(); ++message) + { + payloadType = (*message)->payloadType(); + if (payloadType == SEI::COLOUR_TRANSFORM_INFO) + { + // re-init parameters + *m_colourTranfParams->m_pColourTransfParams = *static_cast<SEIColourTransformInfo*>(*message); + //m_colourTranfParams->m_pColourTransfParams = static_cast<SEIColourTransformInfo*>(*message); + break; + } + } + + m_invColourTransfBuf->copyFrom(getRecoBuf()); + + if (m_colourTranfParams->m_pColourTransfParams != NULL) + { + m_colourTranfParams->generateColourTransfLUTs(); + m_colourTranfParams->inverseColourTransform(m_invColourTransfBuf); + } + + return *m_invColourTransfBuf; +} +#endif \ No newline at end of file diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 2f985828e..2ac2bea8b 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -48,6 +48,9 @@ #include "CodingStructure.h" #include "Hash.h" #include "MCTS.h" +#if JVET_V0108 +#include "SEIColourTransform.h" +#endif #include <deque> @@ -68,6 +71,12 @@ struct Picture : public UnitArea void createTempBuffers( const unsigned _maxCUSize ); void destroyTempBuffers(); +#if JVET_V0108 + SEIColourTransformApply* m_colourTranfParams; + PelStorage* m_invColourTransfBuf; + void createColourTransfProcessor(bool bFirstPictureInSequence, SEIColourTransformApply* pCtiCharacteristics, PelStorage* pCtiBuf, int width, int height, ChromaFormat fmt, int bitDepth); + PelUnitBuf getDisplayBuf(); +#endif PelBuf getOrigBuf(const CompArea &blk); const CPelBuf getOrigBuf(const CompArea &blk) const; diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp index ef10af904..30b0febc0 100644 --- a/source/Lib/CommonLib/SEI.cpp +++ b/source/Lib/CommonLib/SEI.cpp @@ -173,6 +173,9 @@ const char *SEI::getSEIMessageString(SEI::PayloadType payloadType) case SEI::CONTENT_LIGHT_LEVEL_INFO: return "Content light level information"; case SEI::AMBIENT_VIEWING_ENVIRONMENT: return "Ambient viewing environment"; case SEI::CONTENT_COLOUR_VOLUME: return "Content colour volume"; +#if JVET_V0108 + case SEI::COLOUR_TRANSFORM_INFO: return "Colour transform information"; +#endif case SEI::EQUIRECTANGULAR_PROJECTION: return "Equirectangular projection"; case SEI::SPHERE_ROTATION: return "Sphere rotation"; case SEI::REGION_WISE_PACKING: return "Region wise packing information"; diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h index 0c4e03602..60f7bbbf9 100644 --- a/source/Lib/CommonLib/SEI.h +++ b/source/Lib/CommonLib/SEI.h @@ -66,6 +66,9 @@ public: DECODED_PICTURE_HASH = 132, SCALABLE_NESTING = 133, MASTERING_DISPLAY_COLOUR_VOLUME = 137, +#if JVET_V0108 + COLOUR_TRANSFORM_INFO = 142, +#endif DEPENDENT_RAP_INDICATION = 145, EQUIRECTANGULAR_PROJECTION = 150, SPHERE_ROTATION = 154, @@ -618,6 +621,30 @@ public: uint16_t m_ambientLightY; }; +#if JVET_V0108 +class SEIColourTransformInfo : public SEI +{ +public: + PayloadType payloadType() const { return COLOUR_TRANSFORM_INFO; } + SEIColourTransformInfo() { } + + virtual ~SEIColourTransformInfo() { } + + uint16_t m_id; + bool m_signalInfoFlag; + bool m_fullRangeFlag; + uint16_t m_primaries; + uint16_t m_transferFunction; + uint16_t m_matrixCoefs; + bool m_crossComponentFlag; + bool m_crossComponentInferred; + uint16_t m_numberChromaLutMinus1; + int m_chromaOffset; + uint16_t m_bitdepth; + uint16_t m_log2NumberOfPointsPerLut; + LutModel m_lut[MAX_NUM_COMPONENT]; +}; +#endif class SEIContentColourVolume : public SEI { public: diff --git a/source/Lib/CommonLib/SEIColourTransform.cpp b/source/Lib/CommonLib/SEIColourTransform.cpp new file mode 100644 index 000000000..c1e2f9001 --- /dev/null +++ b/source/Lib/CommonLib/SEIColourTransform.cpp @@ -0,0 +1,192 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2021, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + /** \file SEIColourTransform.cpp + \brief Colour transform SEI + */ + +#include "SEIColourTransform.h" + +#if JVET_V0108 +#include "SEI.h" +#include "unit.h" +#include "Buffer.h" + +SEIColourTransformApply::SEIColourTransformApply() + : m_width (0) + , m_height (0) + , m_chromaFormat (NUM_CHROMA_FORMAT) + , m_bitDepth (0) + , m_pColourTransfParams (NULL) +{ +} + +void SEIColourTransformApply::create(uint32_t width, uint32_t height, ChromaFormat fmt, uint8_t bitDepth) +{ + m_width = width; + m_height = height; + m_chromaFormat = fmt; + m_bitDepth = bitDepth; + m_pColourTransfParams = new SEIColourTransformInfo; + m_lutSize = 1 << m_bitDepth; + for (int i = 0; i < MAX_NUM_COMPONENT; i++) { + m_mapLut[i].resize(m_lutSize, 0); + } +} + +SEIColourTransformApply::~SEIColourTransformApply() +{ +} + +void SEIColourTransformApply::inverseColourTransform(PelStorage* pTransformBuf) +{ + uint8_t numComp = m_chromaFormat ? MAX_NUM_COMPONENT : 1; + PelBuf* buffY = &pTransformBuf->Y(); + PelBuf* buffCb = &pTransformBuf->Cb(); + PelBuf* buffCr = &pTransformBuf->Cr(); + + if (numComp == 3) + { + if (m_pColourTransfParams->m_crossComponentFlag) { + buffCb->applyChromaCTI(buffY->buf, buffY->stride, m_mapLut[COMPONENT_Cb], m_bitDepth, m_chromaFormat, false); + buffCr->applyChromaCTI(buffY->buf, buffY->stride, m_mapLut[COMPONENT_Cr], m_bitDepth, m_chromaFormat, false); + } + else { + buffCb->applyLumaCTI(m_mapLut[COMPONENT_Cb]); // apply direct mapping like in luma (no cross component mapping); same function, but different lut. + buffCr->applyLumaCTI(m_mapLut[COMPONENT_Cr]); + } + } + buffY->applyLumaCTI(m_mapLut[COMPONENT_Y]); +} + +void SEIColourTransformApply::generateColourTransfLUTs() +{ + uint8_t numComp = m_chromaFormat ? MAX_NUM_COMPONENT : 1; + int numPreLutPoints = 1 << m_pColourTransfParams->m_log2NumberOfPointsPerLut; + int dynamicRange = 1 << m_bitDepth; + const uint32_t orgCW = dynamicRange / numPreLutPoints; + int scalingPreLut = 1 << ( 11 - (int)floorLog2(orgCW) ); // scale-up values from cfg file (chroma preLut is scaled down in cfg) + + std::vector<Pel> pivotInPoints; + std::vector<Pel> pivotMappedPointsY(numPreLutPoints+1); + std::vector<Pel> pivotMappedPointsX(numPreLutPoints+1); + + // Create Inverse Luma LUT - same for all possible combinations of ctiCrossComp and ctiChromaLutInferred + + std::vector<int> invScale(numPreLutPoints); + + pivotInPoints = m_pColourTransfParams->m_lut[0].lutValues; + pivotMappedPointsX[0] = pivotInPoints[0]; + pivotMappedPointsY[0] = 0; + for (int j = 1; j < numPreLutPoints; j++) { + pivotMappedPointsX[j] = pivotMappedPointsX[j - 1] + pivotInPoints[j]; + pivotMappedPointsY[j] = j * orgCW; + } + + for (int i = 0; i < numPreLutPoints; i++) + { + invScale[i] = ((int32_t)m_pColourTransfParams->m_lut[0].lutValues[i + 1] * (1 << FP_PREC) + (1 << (floorLog2(orgCW) - 1))) >> floorLog2(orgCW); + } + + for (int i = 0; i < dynamicRange; i++) + { + int idx = i / orgCW; + int tempVal = pivotMappedPointsX[idx] + ((invScale[idx] * (i - pivotMappedPointsY[idx]) + (1 << (FP_PREC - 1))) >> FP_PREC); + m_mapLut[0][i] = Clip3((Pel)0, (Pel)(dynamicRange - 1), (Pel)(tempVal)); + } + + // calculate chroma LUTs + if (m_pColourTransfParams->m_crossComponentInferred == 0) + { + for (int i = 1; i < numComp; i++) { // loop for U and V + if (m_pColourTransfParams->m_crossComponentFlag == 1) + { + // cross-component U and V LUT + for (int j = 0; j < dynamicRange; j++) { + int idx = j / orgCW; + int slope = scalingPreLut * (m_pColourTransfParams->m_lut[i].lutValues[idx + 1] - m_pColourTransfParams->m_lut[i].lutValues[idx]); + //m_mapLut[i][j] = (scalingPreLut * orgCW * m_pColourTransfParams->m_lut[i].lutValues[idx] + slope * (j - pivotMappedPointsY[idx]) + (orgCW / 2)) / orgCW; + m_mapLut[i][j] = scalingPreLut * m_pColourTransfParams->m_lut[i].lutValues[idx] + slope * (j - pivotMappedPointsY[idx]) / orgCW; + } + } + else + { + // intra-component Chroma (U and V) LUT + // initialize pivot points + pivotInPoints = m_pColourTransfParams->m_lut[i].lutValues; + pivotMappedPointsX[0] = pivotInPoints[0]; + for (int j = 1; j <= numPreLutPoints; j++) { + pivotMappedPointsX[j] = pivotMappedPointsX[j-1] + pivotInPoints[j]; + } + + for (int i = 0; i < numPreLutPoints; i++) + { + invScale[i] = ((int32_t)m_pColourTransfParams->m_lut[0].lutValues[i + 1] * (1 << FP_PREC) + (1 << (floorLog2(orgCW) - 1))) >> floorLog2(orgCW); + } + + for (int j = 0; j < dynamicRange; j++) { + int idx = j / orgCW; + int tempVal = pivotMappedPointsX[idx] + ((invScale[idx] * (j - pivotMappedPointsY[idx]) + (1 << (FP_PREC - 1))) >> FP_PREC); + m_mapLut[i][j] = Clip3((Pel)0, (Pel)(dynamicRange - 1), (Pel)(tempVal)); + } + } + } + } + else + { + int chrOffset = m_pColourTransfParams->m_chromaOffset; + + std::vector<int> chromaAdjHelpLUT (numPreLutPoints); + for (int i = 0; i < numPreLutPoints; i++) + { + chromaAdjHelpLUT[i] = (m_pColourTransfParams->m_lut[0].lutValues[i + 1] == 0) ? (1 << CSCALE_FP_PREC) : ((int32_t)((m_pColourTransfParams->m_lut[0].lutValues[i + 1] + chrOffset) * (1 << FP_PREC) / orgCW)); + } + + // generate smoothed chroma LUT as done by JVET-U0078 + std::vector<int> interpLut(numPreLutPoints + 1); + for (int i = 1; i < numPreLutPoints; i++) { + interpLut[i] = (chromaAdjHelpLUT[i] + chromaAdjHelpLUT[i - 1] + 1) / 2; + } + interpLut[0] = chromaAdjHelpLUT[0]; + interpLut[numPreLutPoints] = chromaAdjHelpLUT[numPreLutPoints - 1]; + + for (int i = 0; i < dynamicRange; i++) + { + int idx = i / orgCW; + int slope = interpLut[idx + 1] - interpLut[idx]; + m_mapLut[1][i] = interpLut[idx] + slope * (i - pivotMappedPointsY[idx]) / orgCW; + m_mapLut[2][i] = m_mapLut[1][i]; + } + } +} +#endif diff --git a/source/Lib/CommonLib/SEIColourTransform.h b/source/Lib/CommonLib/SEIColourTransform.h new file mode 100644 index 000000000..86f03b0d8 --- /dev/null +++ b/source/Lib/CommonLib/SEIColourTransform.h @@ -0,0 +1,73 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2021, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + /** \file SEIColourTransform.h + \brief Colour transform SEI + */ + +#ifndef __SEIFILMCOLOURTRANFORMAPPLY__ +#define __SEIFILMCOLOURTRANFORMAPPLY__ + +#include "CommonDef.h" +//! \ingroup CommonLib +//! \{ + +#if JVET_V0108 +struct PelStorage; +class SEIColourTransformInfo; + +class SEIColourTransformApply +{ +private: + uint32_t m_width; + uint32_t m_height; + ChromaFormat m_chromaFormat; + uint8_t m_bitDepth; + uint32_t m_lutSize; + std::vector<Pel> m_mapLut[MAX_NUM_COMPONENT]; + +public: + SEIColourTransformInfo* m_pColourTransfParams; + +public: + SEIColourTransformApply(); + virtual ~SEIColourTransformApply(); + + void create (uint32_t width, uint32_t height, ChromaFormat fmt, uint8_t bitDepth); + void inverseColourTransform (PelStorage* pTransformBuf); + void generateColourTransfLUTs (); + +};// END CLASS DEFINITION SEIColourTransformApply +#endif + +#endif \ No newline at end of file diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 7154f52f0..3da9279f3 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -68,6 +68,8 @@ #define JVET_S0078_NOOUTPUTPRIORPICFLAG 0 // JVET-S0078: Handling of NoOutputOfPriorPicsFlag in output process +#define JVET_V0108 1 // JVET_V0108: Colour Transform Information SEI + //########### place macros to be be kept below this line ############### #define GDR_ENABLED 1 @@ -911,8 +913,16 @@ struct LFCUParam bool leftEdge; ///< indicates left edge bool topEdge; ///< indicates top edge }; +#if JVET_V0108 +#define MAX_CTI_LUT_SIZE 64 ///< max size of lut for color transform - +struct LutModel +{ + bool presentFlag = false; + int numLutValues = 0; + std::vector<Pel> lutValues; +}; +#endif struct PictureHash { diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index b3b4205eb..0de8b2951 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -426,6 +426,10 @@ DecLib::DecLib() , m_prevPicPOC(MAX_INT) , m_prevTid0POC(0) , m_bFirstSliceInPicture(true) +#if JVET_V0108 + , m_bFirstPictureInSequence(true) + , m_colourTranfParams() +#endif , m_firstSliceInBitstream(true) , m_isFirstAuInCvs( true ) , m_prevSliceSkipped(false) @@ -1650,6 +1654,10 @@ void DecLib::xActivateParameterSets( const InputNALUnit nalu ) m_pcPic->finalInit(vps, *sps, *pps, picHeader, apss, lmcsAPS, scalinglistAPS); #else m_pcPic->finalInit( vps, *sps, *pps, &m_picHeader, apss, lmcsAPS, scalinglistAPS ); +#endif +#if JVET_V0108 + m_pcPic->createColourTransfProcessor(m_bFirstPictureInSequence, &m_colourTranfParams, &m_invColourTransfBuf, pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getBitDepth(CHANNEL_TYPE_LUMA)); + m_bFirstPictureInSequence = false; #endif m_pcPic->createTempBuffers( m_pcPic->cs->pps->pcv->maxCUWidth ); m_pcPic->cs->createCoeffs((bool)m_pcPic->cs->sps->getPLTMode()); diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index d95f4a760..9345930d9 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -128,6 +128,11 @@ private: int m_prevPicPOC; int m_prevTid0POC; bool m_bFirstSliceInPicture; +#if JVET_V0108 + bool m_bFirstPictureInSequence; + SEIColourTransformApply m_colourTranfParams; + PelStorage m_invColourTransfBuf; +#endif bool m_firstSliceInSequence[MAX_VPS_LAYERS]; bool m_firstSliceInBitstream; bool m_isFirstAuInCvs; diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp index 25fc7cbbf..2ef85d7f8 100644 --- a/source/Lib/DecoderLib/SEIread.cpp +++ b/source/Lib/DecoderLib/SEIread.cpp @@ -300,6 +300,12 @@ void SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType sei = new SEIContentColourVolume; xParseSEIContentColourVolume((SEIContentColourVolume&)*sei, payloadSize, pDecodedMessageOutputStream); break; +#if JVET_V0108 + case SEI::COLOUR_TRANSFORM_INFO: + sei = new SEIColourTransformInfo; + xParseSEIColourTransformInfo((SEIColourTransformInfo&)*sei, payloadSize, pDecodedMessageOutputStream); + break; +#endif default: for (uint32_t i = 0; i < payloadSize; i++) { @@ -1322,6 +1328,86 @@ void SEIReader::xParseSEIAmbientViewingEnvironment(SEIAmbientViewingEnvironment& sei_read_code(pDecodedMessageOutputStream, 16, code, "ambient_light_y"); sei.m_ambientLightY = (uint16_t)code; } +#if JVET_V0108 +void SEIReader::xParseSEIColourTransformInfo(SEIColourTransformInfo& sei, uint32_t payloadSize, std::ostream* pDecodedMessageOutputStream) +{ + uint32_t code; + + output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize); + + sei_read_uvlc(pDecodedMessageOutputStream, code, "colour_transform_id"); sei.m_id = code; + sei_read_flag(pDecodedMessageOutputStream, code, "colour_transform_cancel_flag"); bool colourTransformCancelFlag = code; + + if (colourTransformCancelFlag == 0) + { + sei_read_flag(pDecodedMessageOutputStream, code, "colour_transform_persistence_flag"); + sei_read_flag(pDecodedMessageOutputStream, code, "colour_transform_video_signal_info_present_flag"); sei.m_signalInfoFlag = code; + + if (sei.m_signalInfoFlag) + { + sei_read_flag(pDecodedMessageOutputStream, code, "colour_transform_full_range_flag"); sei.m_fullRangeFlag = code; + sei_read_code(pDecodedMessageOutputStream, 8, code, "colour_transform_primaries"); sei.m_primaries = code; + sei_read_code(pDecodedMessageOutputStream, 8, code, "colour_transform_transfer_function"); sei.m_transferFunction = code; + sei_read_code(pDecodedMessageOutputStream, 8, code, "colour_transform_matrix_coefficients"); sei.m_matrixCoefs = code; + } + else + { + sei.m_fullRangeFlag = 0; + sei.m_primaries = 0; + sei.m_transferFunction = 0; + sei.m_matrixCoefs = 0; + } + sei_read_code(pDecodedMessageOutputStream, 4, code, "colour_transform_bit_depth_minus8"); sei.m_bitdepth = 8+code; + sei_read_code(pDecodedMessageOutputStream, 3, code, "colour_transform_log2_number_of_points_per_lut_minus1"); sei.m_log2NumberOfPointsPerLut = code + 1; + int numLutValues = (1 << sei.m_log2NumberOfPointsPerLut) + 1; + sei_read_flag(pDecodedMessageOutputStream, code, "colour_transform_cross_comp_flag"); sei.m_crossComponentFlag = code; + sei.m_crossComponentInferred = 0; + if (sei.m_crossComponentFlag == true) + { + sei_read_flag(pDecodedMessageOutputStream, code, "colour_transform_cross_comp_inferred"); sei.m_crossComponentInferred = code; + } + for (int i = 0; i < MAX_NUM_COMPONENT; i++) { + sei.m_lut[i].lutValues.resize(numLutValues); + } + + uint16_t lutCodingLength = 2 + sei.m_bitdepth - sei.m_log2NumberOfPointsPerLut; + for (uint32_t j = 0; j < numLutValues; j++) + { + sei_read_code(pDecodedMessageOutputStream, lutCodingLength, code, "colour_transform_lut[0][i]"); + sei.m_lut[0].lutValues[j] = code; + } + sei.m_lut[0].numLutValues = numLutValues; + sei.m_lut[0].presentFlag = true; + if (sei.m_crossComponentFlag == 0 || sei.m_crossComponentInferred == 0) + { + sei_read_flag(pDecodedMessageOutputStream, code, "colour_transform_number_chroma_lut_minus1"); sei.m_numberChromaLutMinus1 = code; + for (uint32_t j = 0; j < numLutValues; j++) + { + sei_read_code(pDecodedMessageOutputStream, lutCodingLength, code, "colour_transform_lut[1][i]"); + sei.m_lut[1].lutValues[j] = code; + sei.m_lut[2].lutValues[j] = code; + } + if (sei.m_numberChromaLutMinus1 == 1) + { + for (uint32_t j = 0; j < numLutValues; j++) + { + sei_read_code(pDecodedMessageOutputStream, lutCodingLength, code, "colour_transform_lut[2][i]"); + sei.m_lut[2].lutValues[j] = code; + } + } + sei.m_lut[1].numLutValues = numLutValues; + sei.m_lut[2].numLutValues = numLutValues; + sei.m_lut[1].presentFlag = true; + sei.m_lut[2].presentFlag = true; + } + else + { + sei_read_code(pDecodedMessageOutputStream, lutCodingLength, code, "colour_transform_chroma_offset"); + sei.m_chromaOffset = code; + } + } +} +#endif void SEIReader::xParseSEIContentColourVolume(SEIContentColourVolume& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream) { int i; diff --git a/source/Lib/DecoderLib/SEIread.h b/source/Lib/DecoderLib/SEIread.h index 94cbd7f66..fde1ad7ad 100644 --- a/source/Lib/DecoderLib/SEIread.h +++ b/source/Lib/DecoderLib/SEIread.h @@ -87,6 +87,9 @@ protected: void xParseSEIContentLightLevelInfo (SEIContentLightLevelInfo& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); void xParseSEIAmbientViewingEnvironment (SEIAmbientViewingEnvironment& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); void xParseSEIContentColourVolume (SEIContentColourVolume& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); +#if JVET_V0108 + void xParseSEIColourTransformInfo (SEIColourTransformInfo& sei, uint32_t payloadSize, std::ostream* pDecodedMessageOutputStream); +#endif void sei_read_scode(std::ostream *pOS, uint32_t length, int& code, const char *pSymbolName); void sei_read_code(std::ostream *pOS, uint32_t uiLength, uint32_t& ruiCode, const char *pSymbolName); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 657288a66..ccde89ae5 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -648,6 +648,21 @@ protected: uint32_t m_aveSEIAmbientIlluminance; uint16_t m_aveSEIAmbientLightX; uint16_t m_aveSEIAmbientLightY; +#if JVET_V0108 + // colour tranform information sei + bool m_ctiSEIEnabled; + uint32_t m_ctiSEIId; + bool m_ctiSEISignalInfoFlag; + bool m_ctiSEIFullRangeFlag; + uint32_t m_ctiSEIPrimaries; + uint32_t m_ctiSEITransferFunction; + uint32_t m_ctiSEIMatrixCoefs; + bool m_ctiSEICrossComponentFlag; + bool m_ctiSEICrossComponentInferred; + uint32_t m_ctiSEINumberChromaLut; + int m_ctiSEIChromaOffset; + LutModel m_ctiSEILut[MAX_NUM_COMPONENT]; +#endif // ccv sei bool m_ccvSEIEnabled; bool m_ccvSEICancelFlag; @@ -1760,6 +1775,34 @@ public: uint16_t getAmbientViewingEnvironmentSEIAmbientLightX() { return m_aveSEIAmbientLightX; } void setAmbientViewingEnvironmentSEIAmbientLightY( uint16_t v ) { m_aveSEIAmbientLightY = v; } uint16_t getAmbientViewingEnvironmentSEIAmbientLightY() { return m_aveSEIAmbientLightY; } +#if JVET_V0108 + // colour tranform information sei + void setCtiSEIEnabled(bool b) { m_ctiSEIEnabled = b; } + bool getCtiSEIEnabled() { return m_ctiSEIEnabled; } + void setCtiSEIId(uint32_t b) { m_ctiSEIId = b; } + uint32_t getCtiSEIId() { return m_ctiSEIId; } + void setCtiSEISignalInfoFlag(bool b) { m_ctiSEISignalInfoFlag = b; } + bool getCtiSEISignalInfoFlag() { return m_ctiSEISignalInfoFlag; } + void setCtiSEIFullRangeFlag(bool b) { m_ctiSEIFullRangeFlag = b; } + bool getCtiSEIFullRangeFlag() { return m_ctiSEIFullRangeFlag; } + uint32_t getCtiSEIPrimaries() { return m_ctiSEIPrimaries; } + void setCtiSEIPrimaries(uint32_t v) { m_ctiSEIPrimaries = v; } + uint32_t getCtiSEITransferFunction() { return m_ctiSEITransferFunction; } + void setCtiSEITransferFunction(uint32_t v) { m_ctiSEITransferFunction = v; } + uint32_t getCtiSEIMatrixCoefs() { return m_ctiSEIMatrixCoefs; } + void setCtiSEIMatrixCoefs(uint32_t v) { m_ctiSEIMatrixCoefs = v; } + void setCtiSEICrossComponentFlag(bool b) { m_ctiSEICrossComponentFlag = b; } + bool getCtiSEICrossComponentFlag() { return m_ctiSEICrossComponentFlag; } + void setCtiSEICrossComponentInferred(bool b) { m_ctiSEICrossComponentInferred = b; } + bool getCtiSEICrossComponentInferred() { return m_ctiSEICrossComponentInferred; } + uint32_t getCtiSEINbChromaLut() { return m_ctiSEINumberChromaLut; } + void setCtiSEINbChromaLut(uint32_t v) { m_ctiSEINumberChromaLut = v; } + int getCtiSEIChromaOffset() { return m_ctiSEIChromaOffset; } + void setCtiSEIChromaOffset(int v) { m_ctiSEIChromaOffset = v; } + LutModel getCtiSEILut(int idx) { return m_ctiSEILut[idx]; } + void setCtiSEILut(LutModel& cmp, int idx) { m_ctiSEILut[idx] = cmp; } + LutModel* getCtiSEILuts() { return m_ctiSEILut; } +#endif // ccv SEI void setCcvSEIEnabled(bool b) { m_ccvSEIEnabled = b; } bool getCcvSEIEnabled() { return m_ccvSEIEnabled; } diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 2323c8d77..f764b80a1 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -772,6 +772,15 @@ void EncGOP::xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS m_seiEncoder.initSEIContentColourVolume(seiContentColourVolume); seiMessages.push_back(seiContentColourVolume); } +#if JVET_V0108 + // colour transform information + if (m_pcCfg->getCtiSEIEnabled()) + { + SEIColourTransformInfo* seiCTI = new SEIColourTransformInfo; + m_seiEncoder.initSEIColourTransformInfo(seiCTI); + seiMessages.push_back(seiCTI); + } +#endif } void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, Slice *slice) diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp index f53b7551d..4c718f519 100644 --- a/source/Lib/EncoderLib/SEIEncoder.cpp +++ b/source/Lib/EncoderLib/SEIEncoder.cpp @@ -796,6 +796,32 @@ void SEIEncoder::initSEIContentColourVolume(SEIContentColourVolume *seiContentCo seiContentColourVolume->m_ccvAvgLuminanceValue = (uint32_t)(10000000 * m_pcCfg->getCcvSEIAvgLuminanceValue()); } } +#if JVET_V0108 +void SEIEncoder::initSEIColourTransformInfo(SEIColourTransformInfo* seiCTI) +{ + CHECK(!(m_isInitialized), "Unspecified error"); + CHECK(!(seiCTI != NULL), "Unspecified error"); + + // Set SEI message parameters read from command line options + seiCTI->m_id = m_pcCfg->getCtiSEIId(); + seiCTI->m_signalInfoFlag = m_pcCfg->getCtiSEISignalInfoFlag(); + seiCTI->m_fullRangeFlag = m_pcCfg->getCtiSEIFullRangeFlag(); + seiCTI->m_primaries = m_pcCfg->getCtiSEIPrimaries(); + seiCTI->m_transferFunction = m_pcCfg->getCtiSEITransferFunction(); + seiCTI->m_matrixCoefs = m_pcCfg->getCtiSEIMatrixCoefs(); + seiCTI->m_crossComponentFlag = m_pcCfg->getCtiSEICrossComponentFlag(); + seiCTI->m_crossComponentInferred = m_pcCfg->getCtiSEICrossComponentInferred(); + seiCTI->m_numberChromaLutMinus1 = m_pcCfg->getCtiSEINbChromaLut() - 1; + seiCTI->m_chromaOffset = m_pcCfg->getCtiSEIChromaOffset(); + + seiCTI->m_bitdepth = m_pcCfg->getBitDepth(CHANNEL_TYPE_LUMA); + + for (int i = 0; i < MAX_NUM_COMPONENT; i++) { + seiCTI->m_lut[i] = m_pcCfg->getCtiSEILut(i); + } + seiCTI->m_log2NumberOfPointsPerLut = floorLog2(seiCTI->m_lut[0].numLutValues - 1); +} +#endif void SEIEncoder::initSEISubpictureLevelInfo(SEISubpicureLevelInfo *sei, const SPS *sps) { const EncCfgParam::CfgSEISubpictureLevel &cfgSubPicLevel = m_pcCfg->getSubpicureLevelInfoSEICfg(); diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h index aa6fdfedb..6ed2a4f09 100644 --- a/source/Lib/EncoderLib/SEIEncoder.h +++ b/source/Lib/EncoderLib/SEIEncoder.h @@ -87,6 +87,9 @@ public: void initSEIAmbientViewingEnvironment(SEIAmbientViewingEnvironment *sei); void initSEIContentColourVolume(SEIContentColourVolume *sei); bool initSEIAnnotatedRegions(SEIAnnotatedRegions *sei, int currPOC); +#if JVET_V0108 + void initSEIColourTransformInfo(SEIColourTransformInfo* sei); +#endif void readAnnotatedRegionSEI(std::istream &fic, SEIAnnotatedRegions *seiAnnoRegion, bool &failed); private: EncCfg* m_pcCfg; diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp index a00ca9284..2643c77e2 100644 --- a/source/Lib/EncoderLib/SEIwrite.cpp +++ b/source/Lib/EncoderLib/SEIwrite.cpp @@ -121,6 +121,11 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI& sei, HRD &h case SEI::CONTENT_COLOUR_VOLUME: xWriteSEIContentColourVolume(*static_cast<const SEIContentColourVolume*>(&sei)); break; +#if JVET_V0108 + case SEI::COLOUR_TRANSFORM_INFO: + xWriteSEIColourTransformInfo(*static_cast<const SEIColourTransformInfo*>(&sei)); + break; +#endif case SEI::SUBPICTURE_LEVEL_INFO: xWriteSEISubpictureLevelInfo(*static_cast<const SEISubpicureLevelInfo*>(&sei)); break; @@ -1005,4 +1010,60 @@ void SEIWriter::xWriteSEIContentColourVolume(const SEIContentColourVolume &sei) } } +#if JVET_V0108 +void SEIWriter::xWriteSEIColourTransformInfo(const SEIColourTransformInfo& sei) +{ + bool colourTransformCancelFlag = 0; + bool colourTransformPersistenceFlag = 0; + + WRITE_UVLC(sei.m_id, "colour_transform_id"); + WRITE_FLAG(colourTransformCancelFlag, "colour_transform_cancel_flag"); + + if (colourTransformCancelFlag == 0) + { + WRITE_FLAG(colourTransformPersistenceFlag, "colour_transform_persistence_flag"); + WRITE_FLAG(sei.m_signalInfoFlag, "colour_transform_video_signal_info_present_flag"); + + if (sei.m_signalInfoFlag) + { + WRITE_FLAG(sei.m_fullRangeFlag, "colour_transform_full_range_flag"); + WRITE_CODE(sei.m_primaries, 8, "colour_transform_primaries"); + WRITE_CODE(sei.m_transferFunction, 8, "colour_transform_transfer_function"); + WRITE_CODE(sei.m_matrixCoefs, 8, "colour_transform_matrix_coefficients"); + } + WRITE_CODE(sei.m_bitdepth - 8, 4, "colour_transform_bit_depth_minus8"); + WRITE_CODE(sei.m_log2NumberOfPointsPerLut - 1, 3, "colour_transform_log2_number_of_points_per_lut_minus1"); + WRITE_FLAG(sei.m_crossComponentFlag, "colour_transform_cross_comp_flag"); + if (sei.m_crossComponentFlag) + { + WRITE_FLAG(sei.m_crossComponentInferred, "colour_transform_cross_comp_inferred"); + } + + uint16_t lutCodingLength = 2 + sei.m_bitdepth - sei.m_log2NumberOfPointsPerLut; + for (uint32_t j = 0; j < sei.m_lut[0].numLutValues; j++) + { + WRITE_CODE(sei.m_lut[0].lutValues[j], lutCodingLength, "colour_transform_lut[0][i]"); + } + if (sei.m_crossComponentFlag == 0 || sei.m_crossComponentInferred == 0) + { + WRITE_FLAG(sei.m_numberChromaLutMinus1, "colour_transform_number_chroma_lut_minus1"); + for (uint32_t j = 0; j < sei.m_lut[1].numLutValues; j++) + { + WRITE_CODE(sei.m_lut[1].lutValues[j], lutCodingLength, "colour_transform_lut[1][i]"); + } + if (sei.m_numberChromaLutMinus1 == 1) + { + for (uint32_t j = 0; j < sei.m_lut[2].numLutValues; j++) + { + WRITE_CODE(sei.m_lut[2].lutValues[j], lutCodingLength, "colour_transform_lut[2][i]"); + } + } + } + else + { + WRITE_CODE(sei.m_chromaOffset, lutCodingLength, "colour_transform_chroma_offset"); + } + } +} +#endif //! \} diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h index ef3f9b4ad..50224621d 100644 --- a/source/Lib/EncoderLib/SEIwrite.h +++ b/source/Lib/EncoderLib/SEIwrite.h @@ -79,6 +79,9 @@ protected: void xWriteSEIContentLightLevelInfo(const SEIContentLightLevelInfo& sei); void xWriteSEIAmbientViewingEnvironment(const SEIAmbientViewingEnvironment& sei); void xWriteSEIContentColourVolume(const SEIContentColourVolume &sei); +#if JVET_V0108 + void xWriteSEIColourTransformInfo(const SEIColourTransformInfo& sei); +#endif void xWriteSEIAnnotatedRegions (const SEIAnnotatedRegions& sei); void xWriteSEIpayloadData(OutputBitstream &bs, const SEI& sei, HRD &hrd, const uint32_t temporalId); void xWriteByteAlign(); -- GitLab