diff --git a/doc/software-manual.tex b/doc/software-manual.tex index 1b2fcd8f2895a370e8a08508480009e046a21d42..aa92e1c289b8e093daad9ae0fe473419a387ea41 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -3800,16 +3800,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 1019f1e77af7fb6e5346be6118adda756c0cca34..a8ab6c746c0df2756fcfa08c4be36f913cbadac1 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -1490,9 +1490,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 } diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index fa33f47be055df6f01523ea06c041fd97655efed..12d84e3af49e54025bb2df0d0eb4c340664ec378 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -772,6 +772,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() @@ -1333,9 +1337,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"); @@ -2470,6 +2474,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; @@ -2477,10 +2486,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; @@ -2489,6 +2501,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; } } diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 4985ac7d41ae67d7b3190d5edf89b6e8557b379b..712830e729b9865ebed0d419270d1ee81ca80d82 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -877,9 +877,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 fba9189bb7029e6396b87cfae919d116bfa07d18..335791293a2bd2d55bd67ddef5a302fc8ca8b637 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -426,6 +426,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 017751786616a1243d9fd37b3d2b776e7821243a..188f9ce01ed140e4eb9c28f1b3a66373cd4d2403 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -947,9 +947,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 @@ -2635,12 +2635,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,