diff --git a/doc/software-manual.tex b/doc/software-manual.tex index e7d15072c8166c81486865daa1cf4a670591e87a..0b9e860dfaf0f79c7c7f2efe7905924f1e6543fe 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -3524,23 +3524,30 @@ Enables or disables the use of adaptive color transform (ACT). \Option{HorCollocatedChroma} & %\ShortOption{\None} & -\Default{true} & -Specifies location of a chroma sample relatively to the luma sample in horizontal direction in the reference picture resampling. +\Default{-1} & +Specifies location of top-left chroma sample relative to top-left luma sample in horizontal direction for reference picture resampling. +For chroma formats other than 4:2:0, the value defaults to 1. +When ChromaSampleLocType is equal to 6 (unspecified) and HorCollocatedChroma is equal to -1, the value defaults to 1. \par \begin{tabular}{cp{0.45\textwidth}} - 0 & horizontally shifted by 0.5 units of luma samples.\\ - 1 & collocated (default). \\ + -1 & value based on ChromaSampleLocType (default)\\ + 0 & horizontally shifted by 0.5 units of luma samples\\ + 1 & collocated \\ \end{tabular} \\ \Option{VerCollocatedChroma} & %\ShortOption{\None} & -\Default{false} & -Specifies location of a chroma sample relatively to the luma sample in vertical direction in the cross-component linear model intra prediction and the reference picture resampling. +\Default{-1} & +Specifies location of top-left chroma sample relative to top-left luma sample in vertical direction for cross-component linear model (CCLM) +intra prediction and for reference picture resampling. +For chroma formats other than 4:2:0, the value defaults to 1. +When ChromaSampleLocType is equal to 6 (unspecified) and VerCollocatedChroma is equal to -1, the value defaults to 0. \par \begin{tabular}{cp{0.45\textwidth}} - 0 & vertically shifted by 0.5 units of luma samples (default).\\ - 1 & collocated. \\ + -1 & value based on ChromaSampleLocType (default)\\ + 0 & vertically shifted by 0.5 units of luma samples\\ + 1 & collocated\\ \end{tabular} \\ @@ -3800,16 +3807,20 @@ Specifies the value of general_non_projected_constraint_flag \\ \Option{ChromaLocInfoPresent} & \Default{false} & -Signals whether chroma_sample_loc_type_top_field and chroma_sample_loc_type_bottom_field are present. +Signals whether chroma_sample_loc_type_top_field, chroma_sample_loc_type_bottom_field and chroma_sample_loc_type are present. \\ \Option{ChromaSampleLocTypeTopField} & -\Default{0} & +\Default{6 (Unspecified)} & Specifies the location of chroma samples for top field. \\ \Option{ChromaSampleLocTypeBottomField} & -\Default{0} & +\Default{6 (Unspecified)} & Specifies the location of chroma samples for bottom field. \\ +\Option{ChromaSampleLocType} & +\Default{6 (Unspecified)} & +Specifies the location of chroma samples for frame. +\\ \end{OptionTableNoShorthand} diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index c00f4c8a79dccff841c58d44a324c59cea7ffaa2..46d77124c210b4f1b12287097e66ef513d2d255f 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -487,7 +487,8 @@ uint32_t DecApp::decode() const int picWidth = pps->getPicWidthInLumaSamples() - (confWindow.getWindowLeftOffset() + confWindow.getWindowRightOffset()) * sx; const int picHeight = pps->getPicHeightInLumaSamples() - (confWindow.getWindowTopOffset() + confWindow.getWindowBottomOffset()) * sy; m_cVideoIOYuvReconFile[nalu.m_nuhLayerId].setOutputY4mInfo( - picWidth, picHeight, frameRate, layerOutputBitDepth[ChannelType::LUMA], sps->getChromaFormatIdc()); + picWidth, picHeight, frameRate, layerOutputBitDepth[ChannelType::LUMA], sps->getChromaFormatIdc(), + sps->getVuiParameters()->getChromaSampleLocType()); } m_cVideoIOYuvReconFile[nalu.m_nuhLayerId].open(reconFileName, true, layerOutputBitDepth, layerOutputBitDepth, bitDepths); // write mode diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index a75328360977618bf4023c6f98361181ce677062..a8289ee1f846d8606a28dac310c717437f62fe74 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -733,8 +733,8 @@ void EncApp::xInitLibCfg( int layerIdx ) m_cEncLib.setPROF ( m_PROF ); m_cEncLib.setBIO (m_BIO); m_cEncLib.setUseLMChroma ( m_LMChroma ); - m_cEncLib.setHorCollocatedChromaFlag ( m_horCollocatedChromaFlag ); - m_cEncLib.setVerCollocatedChromaFlag ( m_verCollocatedChromaFlag ); + m_cEncLib.setHorCollocatedChromaFlag(m_horCollocatedChromaFlag != 0); + m_cEncLib.setVerCollocatedChromaFlag(m_verCollocatedChromaFlag != 0); m_cEncLib.setExplicitMtsIntraEnabled((m_mtsMode & 1) != 0); m_cEncLib.setExplicitMtsInterEnabled((m_mtsMode & 2) != 0); m_cEncLib.setMTSIntraMaxCand ( m_MTSIntraMaxCand ); @@ -1493,9 +1493,9 @@ void EncApp::xCreateLib( std::list<PelUnitBuf*>& recBufList, const int layerId ) { const auto sx = SPS::getWinUnitX(m_chromaFormatIdc); const auto sy = SPS::getWinUnitY(m_chromaFormatIdc); - m_cVideoIOYuvReconFile.setOutputY4mInfo(m_sourceWidth - (m_confWinLeft + m_confWinRight) * sx, - m_sourceHeight - (m_confWinTop + m_confWinBottom) * sy, m_frameRate, - m_internalBitDepth[ChannelType::LUMA], m_chromaFormatIdc); + m_cVideoIOYuvReconFile.setOutputY4mInfo( + m_sourceWidth - (m_confWinLeft + m_confWinRight) * sx, m_sourceHeight - (m_confWinTop + m_confWinBottom) * sy, + m_frameRate, m_internalBitDepth[ChannelType::LUMA], m_chromaFormatIdc, m_chromaSampleLocType); } m_cVideoIOYuvReconFile.open( reconFileName, true, m_outputBitDepth, m_outputBitDepth, m_internalBitDepth ); // write mode } @@ -1734,7 +1734,9 @@ bool EncApp::encodePrep( bool& eos ) bool downsampling = (m_sourceWidthBeforeScale > m_sourceWidth) || (m_sourceHeightBeforeScale > m_sourceHeight); bool useLumaFilter = downsampling; - Picture::rescalePicture(scalingRatio, *m_orgPicBeforeScale, Window(), *m_orgPic, conformanceWindow1, m_inputChromaFormatIDC , m_internalBitDepth,useLumaFilter,downsampling,m_horCollocatedChromaFlag,m_verCollocatedChromaFlag ); + Picture::rescalePicture(scalingRatio, *m_orgPicBeforeScale, Window(), *m_orgPic, conformanceWindow1, + m_inputChromaFormatIDC, m_internalBitDepth, useLumaFilter, downsampling, + m_horCollocatedChromaFlag != 0, m_verCollocatedChromaFlag != 0); m_trueOrgPic->copyFrom(*m_orgPic); } else diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 259f0e711a9b65a1c3f5d6207065af01f577fd59..0147fd8937097dff73c49ccb0904637c523f2846 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -776,6 +776,10 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) bool sdr = false; + int chromaSampleLocType; + int chromaSampleLocTypeTopField; + int chromaSampleLocTypeBottomField; + // clang-format off po::Options opts; opts.addOptions() @@ -1014,10 +1018,12 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("LMChroma", m_LMChroma, 1, " LMChroma prediction " "\t0: Disable LMChroma\n" "\t1: Enable LMChroma\n") - ("HorCollocatedChroma", m_horCollocatedChromaFlag, true, "Specifies location of a chroma sample relatively to the luma sample in horizontal direction in the reference picture resampling\n" + ("HorCollocatedChroma", m_horCollocatedChromaFlag, -1, "Specifies location of a chroma sample relatively to the luma sample in horizontal direction in the reference picture resampling\n" + "\t-1: set according to chroma location type (default)\n" "\t0: horizontally shifted by 0.5 units of luma samples\n" - "\t1: collocated (default)\n") - ("VerCollocatedChroma", m_verCollocatedChromaFlag, false, "Specifies location of a chroma sample relatively to the luma sample in vertical direction in the cross-component linear model intra prediction and the reference picture resampling\n" + "\t1: collocated\n") + ("VerCollocatedChroma", m_verCollocatedChromaFlag, -1, "Specifies location of a chroma sample relatively to the luma sample in vertical direction in the cross-component linear model intra prediction and the reference picture resampling\n" + "\t-1: set according to chroma location type (default)\n" "\t0: horizontally co-sited, vertically shifted by 0.5 units of luma samples\n" "\t1: collocated\n") ("MTS", m_mtsMode, 0, "Multiple Transform Set (MTS)\n" @@ -1337,9 +1343,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("NonPackedSourceConstraintFlag", m_nonPackedConstraintFlag, false, "Indicate that source does not contain frame packing") ("NonProjectedConstraintFlag", m_nonProjectedConstraintFlag, false, "Indicate that the bitstream contains projection SEI messages") ("ChromaLocInfoPresent", m_chromaLocInfoPresentFlag, false, "Signals whether chroma_sample_loc_type_top_field and chroma_sample_loc_type_bottom_field are present") - ("ChromaSampleLocTypeTopField", m_chromaSampleLocTypeTopField, 0, "Specifies the location of chroma samples for top field") - ("ChromaSampleLocTypeBottomField", m_chromaSampleLocTypeBottomField, 0, "Specifies the location of chroma samples for bottom field") - ("ChromaSampleLocType", m_chromaSampleLocType, 0, "Specifies the location of chroma samples for progressive content") + ("ChromaSampleLocTypeTopField", chromaSampleLocTypeTopField, static_cast<int>(Chroma420LocType::UNSPECIFIED), "Specifies the location of chroma samples for top field") + ("ChromaSampleLocTypeBottomField", chromaSampleLocTypeBottomField, static_cast<int>(Chroma420LocType::UNSPECIFIED), "Specifies the location of chroma samples for bottom field") + ("ChromaSampleLocType", chromaSampleLocType, static_cast<int>(Chroma420LocType::UNSPECIFIED), "Specifies the location of chroma samples for progressive content") ("OverscanInfoPresent", m_overscanInfoPresentFlag, false, "Indicates whether conformant decoded pictures are suitable for display using overscan\n") ("OverscanAppropriate", m_overscanAppropriateFlag, false, "Indicates whether conformant decoded pictures are suitable for display using overscan\n") ("VideoFullRange", m_videoFullRangeFlag, false, "Indicates the black level and range of luma and chroma signals"); @@ -2477,6 +2483,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } } + // TODO: check whether values are within valid range + m_chromaSampleLocType = static_cast<Chroma420LocType>(chromaSampleLocType); + m_chromaSampleLocTypeTopField = static_cast<Chroma420LocType>(chromaSampleLocTypeTopField); + m_chromaSampleLocTypeBottomField = static_cast<Chroma420LocType>(chromaSampleLocTypeBottomField); + if (isY4mFileExt(m_inputFileName)) { int width = 0; @@ -2484,10 +2495,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) Fraction frameRate; int inputBitDepth = 0; ChromaFormat chromaFormat = ChromaFormat::_420; + Chroma420LocType locType = Chroma420LocType::UNSPECIFIED; + VideoIOYuv inputFile; - inputFile.parseY4mFileHeader(m_inputFileName, width, height, frameRate, inputBitDepth, chromaFormat); + inputFile.parseY4mFileHeader(m_inputFileName, width, height, frameRate, inputBitDepth, chromaFormat, locType); if (width != m_sourceWidth || height != m_sourceHeight || frameRate != m_frameRate - || inputBitDepth != m_inputBitDepth[ChannelType::LUMA] || chromaFormat != m_chromaFormatIdc) + || inputBitDepth != m_inputBitDepth[ChannelType::LUMA] || chromaFormat != m_chromaFormatIdc + || locType != m_chromaSampleLocType) { msg(WARNING, "\nWarning: Y4M file info is different from input setting. Using the info from Y4M file\n"); m_sourceWidth = width; @@ -2496,6 +2510,14 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) m_inputBitDepth.fill(inputBitDepth); m_chromaFormatIdc = chromaFormat; m_msbExtendedBitDepth = m_inputBitDepth; + m_chromaSampleLocType = locType; + } + + m_progressiveSourceFlag = true; // TODO: update when processing of interlaced y4m files is supported + if (m_chromaFormatIdc == ChromaFormat::_420 && m_chromaSampleLocType != Chroma420LocType::UNSPECIFIED) + { + m_chromaLocInfoPresentFlag = true; + m_vuiParametersPresentFlag = true; } } @@ -2884,17 +2906,58 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) if (m_chromaFormatIdc != ChromaFormat::_420) { - if (!m_horCollocatedChromaFlag) + if (m_horCollocatedChromaFlag != 1) { - msg(WARNING, "\nWARNING: HorCollocatedChroma is forced to 1 for chroma formats other than 4:2:0\n"); - m_horCollocatedChromaFlag = true; + if (m_horCollocatedChromaFlag == 0) + { + msg(WARNING, "WARNING: HorCollocatedChroma forced to 1 (chroma format is not 4:2:0)\n"); + } + m_horCollocatedChromaFlag = 1; } - if (!m_verCollocatedChromaFlag) + if (m_verCollocatedChromaFlag != 1) { - msg(WARNING, "\nWARNING: VerCollocatedChroma is forced to 1 for chroma formats other than 4:2:0\n"); - m_verCollocatedChromaFlag = true; + if (m_verCollocatedChromaFlag == 0) + { + msg(WARNING, "WARNING: VerCollocatedChroma is forced to 1 (chroma format is not 4:2:0)\n"); + } + m_verCollocatedChromaFlag = 1; } } + else + { + if (m_horCollocatedChromaFlag == -1) + { + if (m_chromaSampleLocType != Chroma420LocType::UNSPECIFIED) + { + m_horCollocatedChromaFlag = m_chromaSampleLocType == Chroma420LocType::LEFT + || m_chromaSampleLocType == Chroma420LocType::TOP_LEFT + || m_chromaSampleLocType == Chroma420LocType::BOTTOM_LEFT + ? 1 + : 0; + } + else + { + m_horCollocatedChromaFlag = 1; + } + } + + if (m_verCollocatedChromaFlag == -1) + { + if (m_chromaSampleLocType != Chroma420LocType::UNSPECIFIED) + { + m_verCollocatedChromaFlag = + m_chromaSampleLocType == Chroma420LocType::TOP_LEFT || m_chromaSampleLocType == Chroma420LocType::TOP ? 1 : 0; + } + else + { + m_verCollocatedChromaFlag = 0; + } + } + } + + CHECK(m_verCollocatedChromaFlag != 0 && m_verCollocatedChromaFlag != 1, "m_verCollocatedChromaFlag should be 0 or 1"); + CHECK(m_horCollocatedChromaFlag != 0 && m_horCollocatedChromaFlag != 1, "m_horCollocatedChromaFlag should be 0 or 1"); + #if JVET_O0756_CONFIG_HDRMETRICS && !JVET_O0756_CALCULATE_HDRMETRICS if ( m_calculateHdrMetrics == true) { diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 2cf5adbcadc222b3ec5db98b4ed1bf9784491107..93783a50533d02fbaab150b2e1a54cda6c9b0b65 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -354,8 +354,8 @@ protected: bool m_PROF; bool m_BIO; int m_LMChroma; - bool m_horCollocatedChromaFlag; - bool m_verCollocatedChromaFlag; + int m_horCollocatedChromaFlag; + int m_verCollocatedChromaFlag; int m_mtsMode; ///< XZ: Multiple Transform Set int m_MTSIntraMaxCand; ///< XZ: Number of additional candidates to test @@ -880,9 +880,9 @@ protected: bool m_progressiveSourceFlag; ///< Indicates if the content is progressive bool m_interlacedSourceFlag; ///< Indicates if the content is interlaced bool m_chromaLocInfoPresentFlag; ///< Signals whether chroma_sample_loc_type_top_field and chroma_sample_loc_type_bottom_field are present - int m_chromaSampleLocTypeTopField; ///< Specifies the location of chroma samples for top field - int m_chromaSampleLocTypeBottomField; ///< Specifies the location of chroma samples for bottom field - int m_chromaSampleLocType; ///< Specifies the location of chroma samples for progressive content + Chroma420LocType m_chromaSampleLocTypeTopField; // Specifies the location of chroma samples for top field + Chroma420LocType m_chromaSampleLocTypeBottomField; // Specifies the location of chroma samples for bottom field + Chroma420LocType m_chromaSampleLocType; // Specifies the location of chroma samples for progressive content bool m_overscanInfoPresentFlag; ///< Signals whether overscan_appropriate_flag is present bool m_overscanAppropriateFlag; ///< Indicates whether conformant decoded pictures are suitable for display using overscan bool m_videoFullRangeFlag; ///< Indicates the black level and range of luma and chroma signals diff --git a/source/Lib/CommonLib/SequenceParameterSet.h b/source/Lib/CommonLib/SequenceParameterSet.h index de81bd397e3825ab5c6b8ddc1341d582206f4853..983a2f3aee6aa4e5b01c74a524467793569dd4a8 100644 --- a/source/Lib/CommonLib/SequenceParameterSet.h +++ b/source/Lib/CommonLib/SequenceParameterSet.h @@ -57,10 +57,10 @@ private: int m_transferCharacteristics; int m_matrixCoefficients; bool m_videoFullRangeFlag; - bool m_chromaLocInfoPresentFlag; - int m_chromaSampleLocTypeTopField; - int m_chromaSampleLocTypeBottomField; - int m_chromaSampleLocType; + bool m_chromaLocInfoPresentFlag = false; + Chroma420LocType m_chromaSampleLocTypeTopField = Chroma420LocType::UNSPECIFIED; + Chroma420LocType m_chromaSampleLocTypeBottomField = Chroma420LocType::UNSPECIFIED; + Chroma420LocType m_chromaSampleLocType = Chroma420LocType::UNSPECIFIED; public: VUI() @@ -80,10 +80,6 @@ public: , m_transferCharacteristics(2) , m_matrixCoefficients(2) , m_videoFullRangeFlag(false) - , m_chromaLocInfoPresentFlag(false) - , m_chromaSampleLocTypeTopField(6) - , m_chromaSampleLocTypeBottomField(6) - , m_chromaSampleLocType(6) {} virtual ~VUI() {} @@ -131,14 +127,14 @@ public: bool getChromaLocInfoPresentFlag() const { return m_chromaLocInfoPresentFlag; } void setChromaLocInfoPresentFlag(bool i) { m_chromaLocInfoPresentFlag = i; } - int getChromaSampleLocTypeTopField() const { return m_chromaSampleLocTypeTopField; } - void setChromaSampleLocTypeTopField(int i) { m_chromaSampleLocTypeTopField = i; } + Chroma420LocType getChromaSampleLocTypeTopField() const { return m_chromaSampleLocTypeTopField; } + void setChromaSampleLocTypeTopField(Chroma420LocType val) { m_chromaSampleLocTypeTopField = val; } - int getChromaSampleLocTypeBottomField() const { return m_chromaSampleLocTypeBottomField; } - void setChromaSampleLocTypeBottomField(int i) { m_chromaSampleLocTypeBottomField = i; } + Chroma420LocType getChromaSampleLocTypeBottomField() const { return m_chromaSampleLocTypeBottomField; } + void setChromaSampleLocTypeBottomField(Chroma420LocType val) { m_chromaSampleLocTypeBottomField = val; } - int getChromaSampleLocType() const { return m_chromaSampleLocType; } - void setChromaSampleLocType(int i) { m_chromaSampleLocType = i; } + Chroma420LocType getChromaSampleLocType() const { return m_chromaSampleLocType; } + void setChromaSampleLocType(Chroma420LocType val) { m_chromaSampleLocType = val; } bool getOverscanInfoPresentFlag() const { return m_overscanInfoPresentFlag; } void setOverscanInfoPresentFlag(bool i) { m_overscanInfoPresentFlag = i; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index a1b83dd77a67e4cfc654881d62c575642076d2da..aedc31081cab304becf168c45ae5004f032157b6 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -427,6 +427,18 @@ enum class ChromaFormat : uint8_t UNDEFINED = NUM }; +enum class Chroma420LocType : uint8_t +{ + LEFT, + CENTER, + TOP_LEFT, + TOP, + BOTTOM_LEFT, + BOTTOM, + UNSPECIFIED, + NUM, +}; + enum class ChannelType : uint8_t { LUMA = 0, diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index db0f35edaac112de3c1d4d076718f5f985845208..64310f4764328dc3042016714546ab49a818c8ce 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -1156,12 +1156,19 @@ void HLSyntaxReader::parseVUI(VUI* pcVUI, SPS *pcSPS) { if(pcVUI->getProgressiveSourceFlag() && !pcVUI->getInterlacedSourceFlag()) { - xReadUvlc( symbol, "vui_chroma_sample_loc_type" ); pcVUI->setChromaSampleLocType(symbol); + xReadUvlc(symbol, "vui_chroma_sample_loc_type"); + CHECK(symbol >= to_underlying(Chroma420LocType::NUM), "vui_chroma_sample_loc_type out of range"); + pcVUI->setChromaSampleLocType(static_cast<Chroma420LocType>(symbol)); } else { - xReadUvlc( symbol, "vui_chroma_sample_loc_type_top_field" ); pcVUI->setChromaSampleLocTypeTopField(symbol); - xReadUvlc( symbol, "vui_chroma_sample_loc_type_bottom_field" ); pcVUI->setChromaSampleLocTypeBottomField(symbol); + xReadUvlc(symbol, "vui_chroma_sample_loc_type_top_field"); + CHECK(symbol >= to_underlying(Chroma420LocType::NUM), "vui_chroma_sample_loc_type_top_field out of range"); + pcVUI->setChromaSampleLocTypeTopField(static_cast<Chroma420LocType>(symbol)); + + xReadUvlc(symbol, "vui_chroma_sample_loc_type_bottom_field"); + CHECK(symbol >= to_underlying(Chroma420LocType::NUM), "vui_chroma_sample_loc_type_bottom_field out of range"); + pcVUI->setChromaSampleLocTypeBottomField(static_cast<Chroma420LocType>(symbol)); } } diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index de51148d91d731fcfd0d82e59026932f75b72ff3..50b32cbe8490863eda60cf4c9e42f6092bfff6de 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -950,9 +950,9 @@ protected: bool m_progressiveSourceFlag; ///< Indicates if the content is progressive bool m_interlacedSourceFlag; ///< Indicates if the content is interlaced bool m_chromaLocInfoPresentFlag; ///< Signals whether chroma_sample_loc_type_top_field and chroma_sample_loc_type_bottom_field are present - int m_chromaSampleLocTypeTopField; ///< Specifies the location of chroma samples for top field - int m_chromaSampleLocTypeBottomField; ///< Specifies the location of chroma samples for bottom field - int m_chromaSampleLocType; ///< Specifies the location of chroma samples for progressive content + Chroma420LocType m_chromaSampleLocTypeTopField; // Specifies the location of chroma samples for top field + Chroma420LocType m_chromaSampleLocTypeBottomField; // Specifies the location of chroma samples for bottom field + Chroma420LocType m_chromaSampleLocType; // Specifies the location of chroma samples for progressive content bool m_overscanInfoPresentFlag; ///< Signals whether overscan_appropriate_flag is present bool m_overscanAppropriateFlag; ///< Indicates whether conformant decoded pictures are suitable for display using overscan bool m_videoFullRangeFlag; ///< Indicates the black level and range of luma and chroma signals @@ -2642,12 +2642,12 @@ public: void setMatrixCoefficients(int i) { m_matrixCoefficients = i; } bool getChromaLocInfoPresentFlag() { return m_chromaLocInfoPresentFlag; } void setChromaLocInfoPresentFlag(bool i) { m_chromaLocInfoPresentFlag = i; } - int getChromaSampleLocTypeTopField() { return m_chromaSampleLocTypeTopField; } - void setChromaSampleLocTypeTopField(int i) { m_chromaSampleLocTypeTopField = i; } - int getChromaSampleLocTypeBottomField() { return m_chromaSampleLocTypeBottomField; } - void setChromaSampleLocTypeBottomField(int i) { m_chromaSampleLocTypeBottomField = i; } - int getChromaSampleLocType() { return m_chromaSampleLocType; } - void setChromaSampleLocType(int i) { m_chromaSampleLocType = i; } + Chroma420LocType getChromaSampleLocTypeTopField() { return m_chromaSampleLocTypeTopField; } + void setChromaSampleLocTypeTopField(Chroma420LocType val) { m_chromaSampleLocTypeTopField = val; } + Chroma420LocType getChromaSampleLocTypeBottomField() { return m_chromaSampleLocTypeBottomField; } + void setChromaSampleLocTypeBottomField(Chroma420LocType val) { m_chromaSampleLocTypeBottomField = val; } + Chroma420LocType getChromaSampleLocType() { return m_chromaSampleLocType; } + void setChromaSampleLocType(Chroma420LocType val) { m_chromaSampleLocType = val; } bool getOverscanInfoPresentFlag() { return m_overscanInfoPresentFlag; } void setOverscanInfoPresentFlag(bool i) { m_overscanInfoPresentFlag = i; } bool getOverscanAppropriateFlag() { return m_overscanAppropriateFlag; } diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 6369e8ba9b4073e86738029cd529262f7d063c28..aa14e4e15cba68ceb3209ce57dcf468491c0876c 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -728,12 +728,12 @@ void HLSWriter::codeVUI( const VUI *pcVUI, const SPS* pcSPS ) { if(pcVUI->getProgressiveSourceFlag() && !pcVUI->getInterlacedSourceFlag()) { - xWriteUvlc(pcVUI->getChromaSampleLocType(), "vui_chroma_sample_loc_type"); + xWriteUvlc(to_underlying(pcVUI->getChromaSampleLocType()), "vui_chroma_sample_loc_type"); } else { - xWriteUvlc(pcVUI->getChromaSampleLocTypeTopField(), "vui_chroma_sample_loc_type_top_field"); - xWriteUvlc(pcVUI->getChromaSampleLocTypeBottomField(), "vui_chroma_sample_loc_type_bottom_field"); + xWriteUvlc(to_underlying(pcVUI->getChromaSampleLocTypeTopField()), "vui_chroma_sample_loc_type_top_field"); + xWriteUvlc(to_underlying(pcVUI->getChromaSampleLocTypeBottomField()), "vui_chroma_sample_loc_type_bottom_field"); } } if(!isByteAligned()) diff --git a/source/Lib/Utilities/VideoIOYuv.cpp b/source/Lib/Utilities/VideoIOYuv.cpp index 98123631d2b52a47e5c0f9a694102d4b8895d5a6..d7618f378290ab65919824020e350454a98abffb 100644 --- a/source/Lib/Utilities/VideoIOYuv.cpp +++ b/source/Lib/Utilities/VideoIOYuv.cpp @@ -176,7 +176,9 @@ void VideoIOYuv::open(const std::string &fileName, bool bWriteMode, const BitDep Fraction dummyFrameRate; int dummyBitDepth = 0; ChromaFormat dummyChromaFormat = ChromaFormat::_420; - parseY4mFileHeader(fileName, dummyWidth, dummyHeight, dummyFrameRate, dummyBitDepth, dummyChromaFormat); + Chroma420LocType dummyLocType = Chroma420LocType::UNSPECIFIED; + parseY4mFileHeader(fileName, dummyWidth, dummyHeight, dummyFrameRate, dummyBitDepth, dummyChromaFormat, + dummyLocType); } } m_cHandle.open(fileName.c_str(), std::ios::binary | std::ios::in); @@ -195,8 +197,42 @@ void VideoIOYuv::open(const std::string &fileName, bool bWriteMode, const BitDep return; } +struct Y4mChromaFormat +{ + char name[16]; + int bitDepth; + ChromaFormat chromaFormat; + Chroma420LocType locType; +}; + +static const std::array y4mChromaFormats = { + Y4mChromaFormat{ "mono9", 9, ChromaFormat::_400, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "mono10", 10, ChromaFormat::_400, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "mono12", 12, ChromaFormat::_400, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "mono", 8, ChromaFormat::_400, Chroma420LocType::UNSPECIFIED }, + + Y4mChromaFormat{ "420jpeg", 8, ChromaFormat::_420, Chroma420LocType::CENTER }, + Y4mChromaFormat{ "420mpeg2", 8, ChromaFormat::_420, Chroma420LocType::LEFT }, + Y4mChromaFormat{ "420paldv", 8, ChromaFormat::_420, Chroma420LocType::TOP_LEFT }, + + Y4mChromaFormat{ "420p9", 9, ChromaFormat::_420, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "420p10", 10, ChromaFormat::_420, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "420p12", 12, ChromaFormat::_420, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "420", 8, ChromaFormat::_420, Chroma420LocType::UNSPECIFIED }, + + Y4mChromaFormat{ "422p9", 9, ChromaFormat::_422, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "422p10", 10, ChromaFormat::_422, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "422p12", 12, ChromaFormat::_422, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "422", 8, ChromaFormat::_422, Chroma420LocType::UNSPECIFIED }, + + Y4mChromaFormat{ "444p9", 9, ChromaFormat::_444, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "444p10", 10, ChromaFormat::_444, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "444p12", 12, ChromaFormat::_444, Chroma420LocType::UNSPECIFIED }, + Y4mChromaFormat{ "444", 8, ChromaFormat::_444, Chroma420LocType::UNSPECIFIED }, +}; + void VideoIOYuv::parseY4mFileHeader(const std::string& fileName, int& width, int& height, Fraction& frameRate, - int& bitDepth, ChromaFormat& chromaFormat) + int& bitDepth, ChromaFormat& chromaFormat, Chroma420LocType& locType) { m_cHandle.open(fileName.c_str(), std::ios::binary | std::ios::in); CHECK(m_cHandle.fail(), "File open failed.") @@ -218,45 +254,22 @@ void VideoIOYuv::parseY4mFileHeader(const std::string& fileName, int& width, int // parse Y4M header info for (int i = Y4M_SIGNATURE_LENGTH; i < m_inY4mFileHeaderLength; i++) { - int numerator = 0, denominator = 0, pos = 0; + int numerator = 0, denominator = 0; switch (header[i]) { case 'W': sscanf(header + i + 1, "%d", &width); break; case 'H': sscanf(header + i + 1, "%d", &height); break; case 'C': - if (strncmp(&header[i + 1], "mono", 4) == 0) + for (const auto& cf: y4mChromaFormats) { - chromaFormat = ChromaFormat::_400; - pos = i + 5; - } - else if (strncmp(&header[i + 1], "420", 3) == 0) - { - chromaFormat = ChromaFormat::_420; - pos = i + 4; - if (strncmp(&header[pos], "jpeg", 4) == 0) - { - pos += 4; - } - else if (strncmp(&header[pos], "paldv", 5) == 0) + if (strncmp(&header[i + 1], cf.name, strlen(cf.name)) == 0) { - pos += 5; + chromaFormat = cf.chromaFormat; + locType = cf.locType; + bitDepth = cf.bitDepth; + break; } } - else if (strncmp(&header[i + 1], "422", 3) == 0) - { - chromaFormat = ChromaFormat::_422; - pos = i + 4; - } - else if (strncmp(&header[i + 1], "444", 3) == 0) - { - chromaFormat = ChromaFormat::_444; - pos = i + 4; - } - bitDepth = 8; - if (header[pos] == 'p') - { - sscanf(&header[pos + 1], "%d", &bitDepth); - } break; case 'F': if (sscanf(header + i + 1, "%d:%d", &numerator, &denominator) == 2) @@ -281,13 +294,14 @@ void VideoIOYuv::parseY4mFileHeader(const std::string& fileName, int& width, int } void VideoIOYuv::setOutputY4mInfo(int width, int height, const Fraction& frameRate, int bitDepth, - ChromaFormat chromaFormat) + ChromaFormat chromaFormat, Chroma420LocType locType) { m_outPicWidth = width; m_outPicHeight = height; m_outBitDepth = bitDepth; m_outFrameRate = frameRate; m_outChromaFormat = chromaFormat; + m_outLocType = locType; } void VideoIOYuv::writeY4mFileHeader() @@ -299,26 +313,32 @@ void VideoIOYuv::writeY4mFileHeader() header += "H" + std::to_string(m_outPicHeight) + " "; header += "F" + std::to_string(m_outFrameRate.num) + ":" + std::to_string(m_outFrameRate.den) + " "; header += "Ip A0:0 "; - switch (m_outChromaFormat) + header += "C"; + bool found = false; + for (const auto& cf: y4mChromaFormats) { - case ChromaFormat::_400: - header += "Cmono"; - break; - case ChromaFormat::_420: - header += "C420"; - break; - case ChromaFormat::_422: - header += "C422"; - break; - case ChromaFormat::_444: - header += "C444"; - break; - default: CHECK(true, "Unknow chroma format"); + if (m_outBitDepth == cf.bitDepth && m_outChromaFormat == cf.chromaFormat && m_outLocType == cf.locType) + { + header += cf.name; + found = true; + break; + } } - if (m_outBitDepth > 8) + if (!found) { - header += "p" + std::to_string(m_outBitDepth); + for (const auto& cf: y4mChromaFormats) + { + if (m_outBitDepth == cf.bitDepth && m_outChromaFormat == cf.chromaFormat + && Chroma420LocType::UNSPECIFIED == cf.locType) + { + header += cf.name; + found = true; + msg(WARNING, "Value for chroma sample location unsupported by y4m. Signalling unspecified location."); + break; + } + } } + CHECK(!found, "Format unsupported by y4m"); header += "\n"; // not write extension/comment diff --git a/source/Lib/Utilities/VideoIOYuv.h b/source/Lib/Utilities/VideoIOYuv.h index fc006aeb3d078696604cbed0c6b0b29b3259d644..e353c48241878bbf08e377887dbb4aa9f2eab73d 100644 --- a/source/Lib/Utilities/VideoIOYuv.h +++ b/source/Lib/Utilities/VideoIOYuv.h @@ -67,6 +67,7 @@ private: int m_outBitDepth = 0; Fraction m_outFrameRate; ChromaFormat m_outChromaFormat = ChromaFormat::_420; + Chroma420LocType m_outLocType = Chroma420LocType::UNSPECIFIED; bool m_outY4m = false; public: @@ -74,8 +75,9 @@ public: virtual ~VideoIOYuv() {} void parseY4mFileHeader(const std::string& fileName, int& width, int& height, Fraction& frameRate, int& bitDepth, - ChromaFormat& chromaFormat); - void setOutputY4mInfo(int width, int height, const Fraction& frameRate, int bitDepth, ChromaFormat chromaFormat); + ChromaFormat& chromaFormat, Chroma420LocType& locType); + void setOutputY4mInfo(int width, int height, const Fraction& frameRate, int bitDepth, ChromaFormat chromaFormat, + Chroma420LocType locType); void writeY4mFileHeader(); void open(const std::string &fileName, bool bWriteMode, const BitDepths &fileBitDepth, const BitDepths &MSBExtendedBitDepth,