diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 16637221df5529188b7361316c9639e391cd8b9d..648bf65eff57e3f9d2ff91f657282d365dfb0d04 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -2097,36 +2097,78 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } m_chromaQpMappingTableParams.m_deltaQpInValMinus1[0].resize(cfg_qpInValCb.values.size()); m_chromaQpMappingTableParams.m_deltaQpOutVal[0].resize(cfg_qpOutValCb.values.size()); +#if JVET_P0410_CHROMA_QP_MAPPING + m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[0] = (int)cfg_qpOutValCb.values.size() - 2; +#else m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[0] = (int)cfg_qpOutValCb.values.size()-1; +#endif int qpBdOffsetC = 6 * (m_internalBitDepth[CHANNEL_TYPE_CHROMA] - 8); +#if JVET_P0410_CHROMA_QP_MAPPING + m_chromaQpMappingTableParams.m_qpTableStartMinus26[0] = -26 + cfg_qpInValCb.values[0]; + CHECK(m_chromaQpMappingTableParams.m_qpTableStartMinus26[0] < -26 - qpBdOffsetC || m_chromaQpMappingTableParams.m_qpTableStartMinus26[0] > 36, "qpTableStartMinus26 is out of valid range of -26 -qpBdOffsetC to 36, inclusive.") + CHECK(cfg_qpInValCb.values[0] != cfg_qpOutValCb.values[0], "First qpIn value should be equal to first qpOut value"); + for (int i = 0; i < cfg_qpInValCb.values.size() - 1; i++) +#else for (int i = 0; i < cfg_qpInValCb.values.size(); i++) +#endif { CHECK(cfg_qpInValCb.values[i] < -qpBdOffsetC || cfg_qpInValCb.values[i] > MAX_QP, "Some entries cfg_qpInValCb are out of valid range of -qpBdOffsetC to 63, inclusive."); CHECK(cfg_qpOutValCb.values[i] < -qpBdOffsetC || cfg_qpOutValCb.values[i] > MAX_QP, "Some entries cfg_qpOutValCb are out of valid range of -qpBdOffsetC to 63, inclusive."); +#if JVET_P0410_CHROMA_QP_MAPPING + m_chromaQpMappingTableParams.m_deltaQpInValMinus1[0][i] = cfg_qpInValCb.values[i + 1] - cfg_qpInValCb.values[i] - 1; + m_chromaQpMappingTableParams.m_deltaQpOutVal[0][i] = cfg_qpOutValCb.values[i + 1] - cfg_qpOutValCb.values[i]; +#else m_chromaQpMappingTableParams.m_deltaQpInValMinus1[0][i] = (i == 0) ? cfg_qpInValCb.values[i] + qpBdOffsetC : cfg_qpInValCb.values[i] - cfg_qpInValCb.values[i - 1] - 1; m_chromaQpMappingTableParams.m_deltaQpOutVal[0][i] = (i == 0) ? cfg_qpOutValCb.values[i] + qpBdOffsetC : cfg_qpOutValCb.values[i] - cfg_qpOutValCb.values[i - 1]; +#endif } if (!m_chromaQpMappingTableParams.m_sameCQPTableForAllChromaFlag) { m_chromaQpMappingTableParams.m_deltaQpInValMinus1[1].resize(cfg_qpInValCr.values.size()); m_chromaQpMappingTableParams.m_deltaQpOutVal[1].resize(cfg_qpOutValCr.values.size()); +#if JVET_P0410_CHROMA_QP_MAPPING + m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[1] = (int)cfg_qpOutValCr.values.size() - 2; + m_chromaQpMappingTableParams.m_qpTableStartMinus26[1] = -26 + cfg_qpInValCr.values[0]; + CHECK(m_chromaQpMappingTableParams.m_qpTableStartMinus26[1] < -26 - qpBdOffsetC || m_chromaQpMappingTableParams.m_qpTableStartMinus26[1] > 36, "qpTableStartMinus26 is out of valid range of -26 -qpBdOffsetC to 36, inclusive.") + CHECK(cfg_qpInValCr.values[0] != cfg_qpOutValCr.values[0], "First qpIn value should be equal to first qpOut value"); + for (int i = 0; i < cfg_qpInValCr.values.size() - 1; i++) +#else m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[1] = (int)cfg_qpOutValCr.values.size()-1; for (int i = 0; i < cfg_qpInValCr.values.size(); i++) +#endif { CHECK(cfg_qpInValCr.values[i] < -qpBdOffsetC || cfg_qpInValCr.values[i] > MAX_QP, "Some entries cfg_qpInValCr are out of valid range of -qpBdOffsetC to 63, inclusive."); CHECK(cfg_qpOutValCr.values[i] < -qpBdOffsetC || cfg_qpOutValCr.values[i] > MAX_QP, "Some entries cfg_qpOutValCr are out of valid range of -qpBdOffsetC to 63, inclusive."); +#if JVET_P0410_CHROMA_QP_MAPPING + m_chromaQpMappingTableParams.m_deltaQpInValMinus1[1][i] = cfg_qpInValCr.values[i + 1] - cfg_qpInValCr.values[i] - 1; + m_chromaQpMappingTableParams.m_deltaQpOutVal[1][i] = cfg_qpOutValCr.values[i + 1] - cfg_qpOutValCr.values[i]; +#else m_chromaQpMappingTableParams.m_deltaQpInValMinus1[1][i] = (i == 0) ? cfg_qpInValCr.values[i] + qpBdOffsetC : cfg_qpInValCr.values[i] - cfg_qpInValCr.values[i - 1] - 1; m_chromaQpMappingTableParams.m_deltaQpOutVal[1][i] = (i == 0) ? cfg_qpOutValCr.values[i] + qpBdOffsetC : cfg_qpOutValCr.values[i] - cfg_qpOutValCr.values[i - 1]; +#endif } m_chromaQpMappingTableParams.m_deltaQpInValMinus1[2].resize(cfg_qpInValCbCr.values.size()); m_chromaQpMappingTableParams.m_deltaQpOutVal[2].resize(cfg_qpOutValCbCr.values.size()); +#if JVET_P0410_CHROMA_QP_MAPPING + m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[2] = (int)cfg_qpOutValCbCr.values.size() - 2; + m_chromaQpMappingTableParams.m_qpTableStartMinus26[2] = -26 + cfg_qpInValCbCr.values[0]; + CHECK(m_chromaQpMappingTableParams.m_qpTableStartMinus26[2] < -26 - qpBdOffsetC || m_chromaQpMappingTableParams.m_qpTableStartMinus26[2] > 36, "qpTableStartMinus26 is out of valid range of -26 -qpBdOffsetC to 36, inclusive.") + CHECK(cfg_qpInValCbCr.values[0] != cfg_qpInValCbCr.values[0], "First qpIn value should be equal to first qpOut value"); + for (int i = 0; i < cfg_qpInValCbCr.values.size() - 1; i++) +#else m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[2] = (int)cfg_qpOutValCbCr.values.size()-1; for (int i = 0; i < cfg_qpInValCbCr.values.size(); i++) +#endif { CHECK(cfg_qpInValCbCr.values[i] < -qpBdOffsetC || cfg_qpInValCbCr.values[i] > MAX_QP, "Some entries cfg_qpInValCbCr are out of valid range of -qpBdOffsetC to 63, inclusive."); CHECK(cfg_qpOutValCbCr.values[i] < -qpBdOffsetC || cfg_qpOutValCbCr.values[i] > MAX_QP, "Some entries cfg_qpOutValCbCr are out of valid range of -qpBdOffsetC to 63, inclusive."); +#if JVET_P0410_CHROMA_QP_MAPPING + m_chromaQpMappingTableParams.m_deltaQpInValMinus1[2][i] = cfg_qpInValCbCr.values[i + 1] - cfg_qpInValCbCr.values[i] - 1; + m_chromaQpMappingTableParams.m_deltaQpOutVal[2][i] = cfg_qpInValCbCr.values[i + 1] - cfg_qpInValCbCr.values[i]; +#else m_chromaQpMappingTableParams.m_deltaQpInValMinus1[2][i] = (i == 0) ? cfg_qpInValCbCr.values[i] + qpBdOffsetC : cfg_qpInValCbCr.values[i] - cfg_qpInValCbCr.values[i - 1] - 1; m_chromaQpMappingTableParams.m_deltaQpOutVal[2][i] = (i == 0) ? cfg_qpOutValCbCr.values[i] + qpBdOffsetC : cfg_qpOutValCbCr.values[i] - cfg_qpOutValCbCr.values[i - 1]; +#endif } } diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 8eb17bad47e56a19c1256624ea95011fcaf67ba8..671b53fdb4080c28be493fb587ab8bb450f9509e 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1836,6 +1836,9 @@ void ChromaQpMappingTable::setParams(const ChromaQpMappingTableParams ¶ms, c { m_numPtsInCQPTableMinus1[i] = params.m_numPtsInCQPTableMinus1[i]; m_deltaQpInValMinus1[i] = params.m_deltaQpInValMinus1[i]; +#if JVET_P0410_CHROMA_QP_MAPPING + m_qpTableStartMinus26[i] = params.m_qpTableStartMinus26[i]; +#endif m_deltaQpOutVal[i] = params.m_deltaQpOutVal[i]; } } @@ -1849,6 +1852,17 @@ void ChromaQpMappingTable::derivedChromaQPMappingTables() { const int qpBdOffsetC = m_qpBdOffset; const int numPtsInCQPTableMinus1 = getNumPtsInCQPTableMinus1(i); +#if JVET_P0410_CHROMA_QP_MAPPING + std::vector<int> qpInVal(numPtsInCQPTableMinus1 + 2), qpOutVal(numPtsInCQPTableMinus1 + 2); + + qpInVal[0] = getQpTableStartMinus26(i) + 26; + qpOutVal[0] = qpInVal[0]; + for (int j = 0; j <= getNumPtsInCQPTableMinus1(i); j++) + { + qpInVal[j + 1] = qpInVal[j] + getDeltaQpInValMinus1(i, j) + 1; + qpOutVal[j + 1] = qpOutVal[j] + getDeltaQpOutVal(i, j); + } +#else std::vector<int> qpInVal(numPtsInCQPTableMinus1 + 1), qpOutVal(numPtsInCQPTableMinus1 + 1); qpInVal[0] = -qpBdOffsetC + getDeltaQpInValMinus1(i, 0); @@ -1858,6 +1872,7 @@ void ChromaQpMappingTable::derivedChromaQPMappingTables() qpInVal[j] = qpInVal[j - 1] + getDeltaQpInValMinus1(i, j) + 1; qpOutVal[j] = qpOutVal[j - 1] + getDeltaQpOutVal(i, j); } +#endif for (int j = 0; j <= getNumPtsInCQPTableMinus1(i); j++) { @@ -1870,16 +1885,33 @@ void ChromaQpMappingTable::derivedChromaQPMappingTables() { m_chromaQpMappingTables[i][k] = Clip3(-qpBdOffsetC, MAX_QP, m_chromaQpMappingTables[i][k + 1] - 1); } +#if JVET_P0410_CHROMA_QP_MAPPING + for (int j = 0; j <= numPtsInCQPTableMinus1; j++) +#else for (int j = 0; j < numPtsInCQPTableMinus1; j++) +#endif { +#if JVET_P0410_CHROMA_QP_MAPPING + int sh = (getDeltaQpInValMinus1(i, j) + 1) >> 1; +#else int sh = (getDeltaQpInValMinus1(i, j + 1) + 1) >> 1; +#endif for (int k = qpInVal[j] + 1, m = 1; k <= qpInVal[j + 1]; k++, m++) { +#if JVET_P0410_CHROMA_QP_MAPPING + m_chromaQpMappingTables[i][k] = m_chromaQpMappingTables[i][qpInVal[j]] + + ((qpOutVal[j + 1] - qpOutVal[j]) * m + sh) / (getDeltaQpInValMinus1(i, j) + 1); +#else m_chromaQpMappingTables[i][k] = m_chromaQpMappingTables[i][qpInVal[j]] + (getDeltaQpOutVal(i, j + 1) * m + sh) / (getDeltaQpInValMinus1(i, j + 1) + 1); +#endif } } +#if JVET_P0410_CHROMA_QP_MAPPING + for (int k = qpInVal[numPtsInCQPTableMinus1 + 1] + 1; k <= MAX_QP; k++) +#else for (int k = qpInVal[numPtsInCQPTableMinus1]+1; k <= MAX_QP; k++) +#endif { m_chromaQpMappingTables[i][k] = Clip3(-qpBdOffsetC, MAX_QP, m_chromaQpMappingTables[i][k - 1] + 1); } diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index e7a0f6b14636258180aabdbcacddb84f6e7a0dd6..75b6675601d51771171685f2ad7039aed18c8856 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -538,6 +538,9 @@ struct ChromaQpMappingTableParams { bool m_sameCQPTableForAllChromaFlag; #if JVET_P0667_QP_OFFSET_TABLE_SIGNALING_JCCR int m_numQpTables; +#endif +#if JVET_P0410_CHROMA_QP_MAPPING + int m_qpTableStartMinus26[MAX_NUM_CQP_MAPPING_TABLES]; #endif int m_numPtsInCQPTableMinus1[MAX_NUM_CQP_MAPPING_TABLES]; std::vector<int> m_deltaQpInValMinus1[MAX_NUM_CQP_MAPPING_TABLES]; @@ -551,6 +554,9 @@ struct ChromaQpMappingTableParams { m_numQpTables = 1; #endif m_numPtsInCQPTableMinus1[0] = 0; +#if JVET_P0410_CHROMA_QP_MAPPING + m_qpTableStartMinus26[0] = 0; +#endif m_deltaQpInValMinus1[0] = { 0 }; m_deltaQpOutVal[0] = { 0 }; } @@ -560,6 +566,10 @@ struct ChromaQpMappingTableParams { #if JVET_P0667_QP_OFFSET_TABLE_SIGNALING_JCCR void setNumQpTables(int n) { m_numQpTables = n; } int getNumQpTables() const { return m_numQpTables; } +#endif +#if JVET_P0410_CHROMA_QP_MAPPING + void setQpTableStartMinus26(int tableIdx, int n) { m_qpTableStartMinus26[tableIdx] = n; } + int getQpTableStartMinus26(int tableIdx) const { return m_qpTableStartMinus26[tableIdx]; } #endif void setNumPtsInCQPTableMinus1(int tableIdx, int n) { m_numPtsInCQPTableMinus1[tableIdx] = n; } int getNumPtsInCQPTableMinus1(int tableIdx) const { return m_numPtsInCQPTableMinus1[tableIdx]; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index fa5423fa22172839bc0810bbd3b0a3e242be6d81..a031d7369c8ea4a5dec845f90c1d9df294e052b8 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -62,6 +62,8 @@ #define JVET_P01034_PRED_1D_SCALING_LIST 1 // JVET-P1034: 1D Scaling list index and add predictor mode +#define JVET_P0410_CHROMA_QP_MAPPING 1 // JVET-P0410: Chroma QP Mapping signalling + #define JVET_P0345_LD_GOP_8 1 // JVET-P0345: low-delay gop size 8 #define JVET_P0371_CHROMA_SCALING_OFFSET 1 // JVET-P0371: Signalling offset for chroma residual scaling diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 523f36e1adb3653dc2d691b517a3bacc025b0abb..d61b88a1fbe92b273e3bc6c96c1946c8ef19d7b7 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -1418,6 +1418,10 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) for (int i = 0; i < (chromaQpMappingTableParams.getSameCQPTableForAllChromaFlag() ? 1 : 3); i++) #endif { +#if JVET_P0410_CHROMA_QP_MAPPING + int32_t qpTableStart = 0; + READ_SVLC(qpTableStart, "qp_table_starts_minus26"); chromaQpMappingTableParams.setQpTableStartMinus26(i, qpTableStart); +#endif READ_UVLC(uiCode, "num_points_in_qp_table_minus1"); chromaQpMappingTableParams.setNumPtsInCQPTableMinus1(i,uiCode); std::vector<int> deltaQpInValMinus1(chromaQpMappingTableParams.getNumPtsInCQPTableMinus1(i) + 1); std::vector<int> deltaQpOutVal(chromaQpMappingTableParams.getNumPtsInCQPTableMinus1(i) + 1); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 505ca5ef016bc9a716f8bcc5e50a85d69bc58570..f2ac3e98fee29ae14e301675b06e0a78bc1b1e23 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -855,6 +855,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) for (int i = 0; i < (chromaQpMappingTable.getSameCQPTableForAllChromaFlag() ? 1 : 3); i++) #endif { +#if JVET_P0410_CHROMA_QP_MAPPING + WRITE_SVLC(chromaQpMappingTable.getQpTableStartMinus26(i), "qp_table_starts_minus26"); +#endif WRITE_UVLC(chromaQpMappingTable.getNumPtsInCQPTableMinus1(i), "num_points_in_qp_table_minus1"); for (int j = 0; j <= chromaQpMappingTable.getNumPtsInCQPTableMinus1(i); j++)