From 4a25ab06ea964012e3179cd5c6a66d0404696654 Mon Sep 17 00:00:00 2001 From: Mohammed Golam Sarwer <m.sarwer@alibaba-inc.com> Date: Sat, 9 May 2020 05:56:44 +0200 Subject: [PATCH] JVET-R0110: Mixed lossy/lossless coding --- cfg/lossless/lossless.cfg | 1 + cfg/lossless/lossless_mixed.cfg | 46 ++++++ doc/software-manual.tex | 6 + source/App/EncoderApp/EncApp.cpp | 3 + source/App/EncoderApp/EncAppCfg.cpp | 40 ++++- source/App/EncoderApp/EncAppCfg.h | 3 + source/Lib/CommonLib/Picture.h | 9 +- source/Lib/CommonLib/QuantRDOQ.cpp | 5 + source/Lib/CommonLib/RdCost.cpp | 6 +- source/Lib/CommonLib/RdCost.h | 7 + source/Lib/CommonLib/Slice.cpp | 3 + source/Lib/CommonLib/Slice.h | 7 + source/Lib/CommonLib/TypeDef.h | 2 + .../Lib/EncoderLib/EncAdaptiveLoopFilter.cpp | 19 +++ source/Lib/EncoderLib/EncAdaptiveLoopFilter.h | 3 + source/Lib/EncoderLib/EncCfg.h | 8 +- source/Lib/EncoderLib/EncCu.cpp | 4 + source/Lib/EncoderLib/EncGOP.cpp | 75 ++++++++- source/Lib/EncoderLib/EncSlice.cpp | 36 +++++ source/Lib/EncoderLib/EncSlice.h | 3 + source/Lib/EncoderLib/InterSearch.cpp | 39 ++++- source/Lib/EncoderLib/IntraSearch.cpp | 143 ++++++++++++++++-- 22 files changed, 435 insertions(+), 33 deletions(-) create mode 100644 cfg/lossless/lossless_mixed.cfg diff --git a/cfg/lossless/lossless.cfg b/cfg/lossless/lossless.cfg index 793b2bedb..2ab513b33 100644 --- a/cfg/lossless/lossless.cfg +++ b/cfg/lossless/lossless.cfg @@ -21,4 +21,5 @@ PROF : 0 Log2MaxTbSize : 5 InternalBitDepth : 0 TSRCdisableLL : 1 +SliceLosslessArray : 1 diff --git a/cfg/lossless/lossless_mixed.cfg b/cfg/lossless/lossless_mixed.cfg new file mode 100644 index 000000000..c53046585 --- /dev/null +++ b/cfg/lossless/lossless_mixed.cfg @@ -0,0 +1,46 @@ +CostMode : lossless +BDPCM : 1 +ChromaTS : 1 +BDPCM : 1 +DepQuant : 0 +RDOQ : 1 +RDOQTS : 1 +SBT : 0 +LMCSEnable : 0 +ISP : 0 +MTS : 0 +LFNST : 0 +JointCbCr : 0 +LoopFilterDisable : 0 +SAO : 1 +ALF : 1 +CCALF : 0 +DMVR : 0 +BIO : 0 +PROF : 0 +Log2MaxTbSize : 5 +InternalBitDepth : 0 +TSRCdisableLL : 1 + +# Configuration to achieve mixed-lossy lossless coding +QP : 55 # Quantization parameter for lossy slices +CbQpOffset : 0 +CrQpOffset : 0 +SliceLevelDblk : 1 +SliceLevelAlf : 1 +SliceLevelSao : 1 +SignHideFlag : 0 +SliceLosslessArray : 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 + +#============ Tiles / Slices ================ +EnablePicPartitioning : 1 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) + +TileColumnWidthArray : 3 3 3 3 3 3 # Tile column widths in units of CTUs. Last column width will be repeated uniformly to cover any remaining picture width +TileRowHeightArray : 3 3 3 3 # Tile row heights in units of CTUs. Last row height will be repeated uniformly to cover any remaining picture height +RasterScanSlices : 0 # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan) +RectSliceFixedWidth : 1 # Fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead) +RectSliceFixedHeight : 1 # Fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead) +DisableLoopFilterAcrossTiles : 1 # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries) +DisableLoopFilterAcrossSlices : 1 # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries) + + diff --git a/doc/software-manual.tex b/doc/software-manual.tex index aa01684f0..9b5c193ca 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -2024,6 +2024,12 @@ Allow signalling of entry points for WPP in slice header. Note that when a slice contains more than one tile, entry point offsets for tile are always present in the slice header. \\ +\Option{SliceLosslessArray} & +%\ShortOption{\None} & +\Default{0} & +Define pattern of lossless coding in unit of slices, 0 means lossy slice; 1 means lossless slice. Example: 1 1 0 0 means first 2 slices are lossless coded and rest of the slices are lossy coded. Default is all slices are lossy coded. +\\ + \end{OptionTableNoShorthand} %% diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 2b50392d1..db141a6fa 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -559,6 +559,9 @@ void EncApp::xInitLibCfg() //====== Parallel Merge Estimation ======== m_cEncLib.setLog2ParallelMergeLevelMinus2(m_log2ParallelMergeLevel - 2); +#if JVET_R0110_MIXED_LOSSLESS + m_cEncLib.setSliceLosslessArray(m_sliceLosslessArray); +#endif //====== Tiles and Slices ======== m_cEncLib.setNoPicPartitionFlag( !m_picPartitionFlag ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 0faec54b6..c07e8e978 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -606,7 +606,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) SMultiValueInput<double> cfg_adIntraLambdaModifier (0, std::numeric_limits<double>::max(), 0, MAX_TLAYER); ///< Lambda modifier for Intra pictures, one for each temporal layer. If size>temporalLayer, then use [temporalLayer], else if size>0, use [size()-1], else use m_adLambdaModifier. - +#if JVET_R0110_MIXED_LOSSLESS + SMultiValueInput<uint32_t> cfgSliceLosslessArray(0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); +#endif #if SHARP_LUMA_DELTA_QP const int defaultLumaLevelTodQp_QpChangePoints[] = {-3, -2, -1, 0, 1, 2, 3, 4, 5, 6}; const int defaultLumaLevelTodQp_LumaChangePoints[] = { 0, 301, 367, 434, 501, 567, 634, 701, 767, 834}; @@ -1081,6 +1083,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("SAOLcuBoundary", m_saoCtuBoundary, false, "0: right/bottom CTU boundary areas skipped from SAO parameter estimation, 1: non-deblocked pixels are used for those areas") ("SAOGreedyEnc", m_saoGreedyMergeEnc, false, "SAO greedy merge encoding algorithm") ("EnablePicPartitioning", m_picPartitionFlag, false, "Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used)") +#if JVET_R0110_MIXED_LOSSLESS + ("SliceLosslessArray", cfgSliceLosslessArray, cfgSliceLosslessArray, " Lossless slice array Last lossless flag in the list will be repeated uniformly to cover any remaining slice") +#endif ("TileColumnWidthArray", cfgTileColumnWidth, cfgTileColumnWidth, "Tile column widths in units of CTUs. Last column width in list will be repeated uniformly to cover any remaining picture width") ("TileRowHeightArray", cfgTileRowHeight, cfgTileRowHeight, "Tile row heights in units of CTUs. Last row height in list will be repeated uniformly to cover any remaining picture height") ("RasterScanSlices", m_rasterSliceFlag, false, "Indicates if using raster-scan or rectangular slices (0: rectangular, 1: raster-scan)") @@ -1610,6 +1615,34 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } } +#if JVET_R0110_MIXED_LOSSLESS + // store slice lossless array + const int maxSlicesPerPicture = 600; // the maximum number of slices per picture is 600 + m_sliceLosslessArray.resize(maxSlicesPerPicture); + if (cfgSliceLosslessArray.values.size() == 0) + { + // Default all slices are lossy + for (uint32_t i = 0; i < maxSlicesPerPicture; i++) + { + m_sliceLosslessArray[i] = 0; + } + } + else + { + for (uint32_t i = 0; i < cfgSliceLosslessArray.values.size(); i++) + { + m_sliceLosslessArray[i] = cfgSliceLosslessArray.values[i]; + } + for (uint32_t i = (uint32_t)cfgSliceLosslessArray.values.size(); i < maxSlicesPerPicture; i++) + { + if (cfgSliceLosslessArray.values.size() > 0) + m_sliceLosslessArray[i] = cfgSliceLosslessArray.values[cfgSliceLosslessArray.values.size() - 1]; + else + m_sliceLosslessArray[i] = 0; + } + } +#endif + if( m_picPartitionFlag ) { // store tile column widths @@ -2220,11 +2253,16 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #endif #endif // ENABLE_QPA +#if JVET_R0110_MIXED_LOSSLESS + if (m_costMode == COST_LOSSLESS_CODING && m_sliceLosslessArray[0]) // if first slice is lossless +#else if( m_costMode == COST_LOSSLESS_CODING ) +#endif { m_iQP = LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP - ( ( m_internalBitDepth[CHANNEL_TYPE_LUMA] - 8 ) * 6 ); } + m_uiMaxCUWidth = m_uiMaxCUHeight = m_uiCTUSize; // check validity of input parameters diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 0263cb3ba..14cf20b36 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -440,6 +440,9 @@ protected: bool m_bUseCbfFastMode; ///< flag for using Cbf Fast PU Mode Decision bool m_useEarlySkipDetection; ///< flag for using Early SKIP Detection bool m_picPartitionFlag; ///< enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) +#if JVET_R0110_MIXED_LOSSLESS + std::vector<uint32_t> m_sliceLosslessArray; ///< Slice lossless array +#endif std::vector<uint32_t> m_tileColumnWidth; ///< tile column widths in units of CTUs (last column width will be repeated uniformly to cover any remaining picture width) std::vector<uint32_t> m_tileRowHeight; ///< tile row heights in units of CTUs (last row height will be repeated uniformly to cover any remaining picture height) bool m_rasterSliceFlag; ///< indicates if using raster-scan or rectangular slices (0: rectangular, 1: raster-scan) diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 4a0b4ab8b..6f4b5b6da 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -155,6 +155,11 @@ struct Picture : public UnitArea void setBorderExtension( bool bFlag) { m_bIsBorderExtended = bFlag;} Pel* getOrigin( const PictureType &type, const ComponentID compID ) const; +#if JVET_R0110_MIXED_LOSSLESS + void setLossyQPValue(int i) { m_lossyQP = i; } + int getLossyQPValue() const { return m_lossyQP; } +#endif + int getSpliceIdx(uint32_t idx) const { return m_spliceIdx[idx]; } void setSpliceIdx(uint32_t idx, int poc) { m_spliceIdx[idx] = poc; } void createSpliceIdx(int nums); @@ -211,7 +216,9 @@ public: int* m_spliceIdx; int m_ctuNums; - +#if JVET_R0110_MIXED_LOSSLESS + int m_lossyQP; +#endif bool interLayerRefPicFlag; #if ENABLE_SPLIT_PARALLELISM diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp index 881f0178c..26a17c99d 100644 --- a/source/Lib/CommonLib/QuantRDOQ.cpp +++ b/source/Lib/CommonLib/QuantRDOQ.cpp @@ -527,6 +527,11 @@ void QuantRDOQ::quant(TransformUnit &tu, const ComponentID &compID, const CCoeff useRDOQ &= uiHeight > 2; } +#if JVET_R0110_MIXED_LOSSLESS + if (tu.cs->slice->isLossless()) + useRDOQ = false; +#endif + if (useRDOQ && (isLuma(compID) || RDOQ_CHROMA)) { #if T0196_SELECTIVE_RDOQ diff --git a/source/Lib/CommonLib/RdCost.cpp b/source/Lib/CommonLib/RdCost.cpp index 81eec7926..4f4cdb585 100644 --- a/source/Lib/CommonLib/RdCost.cpp +++ b/source/Lib/CommonLib/RdCost.cpp @@ -65,7 +65,11 @@ double RdCost::calcRdCost( uint64_t fracBits, Distortion distortion, bool useUna double RdCost::calcRdCost( uint64_t fracBits, Distortion distortion ) #endif { - if( m_costMode == COST_LOSSLESS_CODING && 0 != distortion ) +#if JVET_R0110_MIXED_LOSSLESS + if (m_costMode == COST_LOSSLESS_CODING && 0 != distortion && m_isLosslessRDCost) +#else + if( m_costMode == COST_LOSSLESS_CODING && 0 != distortion) +#endif { return MAX_DOUBLE; } diff --git a/source/Lib/CommonLib/RdCost.h b/source/Lib/CommonLib/RdCost.h index 15a2c5c74..3cf776c1a 100644 --- a/source/Lib/CommonLib/RdCost.h +++ b/source/Lib/CommonLib/RdCost.h @@ -114,6 +114,10 @@ private: CostMode m_costMode; double m_distortionWeight[MAX_NUM_COMPONENT]; // only chroma values are used. double m_dLambda; +#if JVET_R0110_MIXED_LOSSLESS + bool m_isLosslessRDCost; +#endif + #if WCG_EXT double m_dLambda_unadjusted; // TODO: check is necessary double m_DistScaleUnadjusted; @@ -164,6 +168,9 @@ public: #endif void setCostMode(CostMode m) { m_costMode = m; } +#if JVET_R0110_MIXED_LOSSLESS + void setLosslessRDCost(bool m) { m_isLosslessRDCost = m; } +#endif // Distortion Functions void init(); diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 948a5a3b0..d28342e43 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1019,6 +1019,9 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll) m_tileGroupLumaApsId = pSrc->m_tileGroupLumaApsId; m_tileGroupChromaApsId = pSrc->m_tileGroupChromaApsId; m_disableSATDForRd = pSrc->m_disableSATDForRd; +#if JVET_R0110_MIXED_LOSSLESS + m_isLossless = pSrc->m_isLossless; +#endif if( cpyAlmostAll ) m_encCABACTableIdx = pSrc->m_encCABACTableIdx; for( int i = 0; i < NUM_REF_PIC_LIST_01; i ++ ) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index a9e092631..3b9109cc6 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -2588,6 +2588,9 @@ private: int m_tileGroupCcAlfCbApsId; int m_tileGroupCcAlfCrApsId; bool m_disableSATDForRd; +#if JVET_R0110_MIXED_LOSSLESS + bool m_isLossless; +#endif public: Slice(); virtual ~Slice(); @@ -2877,6 +2880,10 @@ public: int getTileGroupCcAlfCrApsId() { return m_tileGroupCcAlfCrApsId; } void setDisableSATDForRD(bool b) { m_disableSATDForRd = b; } bool getDisableSATDForRD() { return m_disableSATDForRd; } +#if JVET_R0110_MIXED_LOSSLESS + void setLossless(bool b) { m_isLossless = b; } + bool isLossless() const { return m_isLossless; } +#endif void scaleRefPicList( Picture *scaledRefPic[ ], PicHeader *picHeader, APS** apss, APS* lmcsAps, APS* scalingListAps, const bool isDecoder ); void freeScaledRefPicList( Picture *scaledRefPic[] ); bool checkRPR(); diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 3ba52903d..99e8bcb6b 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -85,6 +85,8 @@ #define JVET_R0437_BS_DERIVATION 1 // JVET-R0437: fix the bS derivation for palette mode +#define JVET_R0110_MIXED_LOSSLESS 1 // JVET-R0110: Slice level mixed lossy/lossless coding: encoder only method + #define JVET_R0330_CRS_CLIP_REM 1 // JVET-R0330: Remove redundant clipping in chroma residual scaling factor derivation #define JVET_R0059_RPL_CLEANUP 1 // JVET-R0059 aspect 2: Condition the signalling of ltrp_in_header_flag[ listIdx ][ rplsIdx ]. diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp index 111872fb0..76ce5f0da 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp @@ -886,6 +886,9 @@ void EncAdaptiveLoopFilter::xSetupCcAlfAPS( CodingStructure &cs ) void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambdas #if ENABLE_QPA , const double lambdaChromaWeight +#endif +#if JVET_R0110_MIXED_LOSSLESS + , Picture* pcPic, uint32_t numSliceSegments #endif ) { @@ -1049,6 +1052,22 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda #endif ); +#if JVET_R0110_MIXED_LOSSLESS + for (int s = 0; s < numSliceSegments; s++) + { + if (pcPic->slices[s]->isLossless()) + { + for (uint32_t ctuIdx = 0; ctuIdx < pcPic->slices[s]->getNumCtuInSlice(); ctuIdx++) + { + uint32_t ctuRsAddr = pcPic->slices[s]->getCtuAddrInSlice(ctuIdx); + m_ctuEnableFlag[COMPONENT_Y][ctuRsAddr] = 0; + m_ctuEnableFlag[COMPONENT_Cb][ctuRsAddr] = 0; + m_ctuEnableFlag[COMPONENT_Cr][ctuRsAddr] = 0; + } + } + } +#endif + alfReconstructor(cs, recYuv); // Do not transmit CC ALF if it is unchanged diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h index db4c7d313..cecff4c84 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h @@ -293,6 +293,9 @@ public: void ALFProcess(CodingStructure& cs, const double *lambdas #if ENABLE_QPA , const double lambdaChromaWeight +#endif +#if JVET_R0110_MIXED_LOSSLESS + , Picture* pcPic, uint32_t numSliceSegments #endif ); int getNewCcAlfApsId(CodingStructure &cs, int cIdx); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 40e2516d8..6c64775ab 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -472,6 +472,9 @@ protected: bool m_bUseBLambdaForNonKeyLowDelayPictures; bool m_gopBasedTemporalFilterEnabled; bool m_noPicPartitionFlag; ///< no picture partitioning flag (single tile, single slice) +#if JVET_R0110_MIXED_LOSSLESS + std::vector<uint32_t> m_sliceLosslessArray; ///< Slice lossless array +#endif std::vector<uint32_t> m_tileColumnWidth; ///< tile column widths in units of CTUs (last column width will be repeated uniformly to cover any remaining picture width) std::vector<uint32_t> m_tileRowHeight; ///< tile row heights in units of CTUs (last row height will be repeated uniformly to cover any remaining picture height) bool m_rectSliceFlag; ///< indicates if using rectangular or raster-scan slices @@ -1355,7 +1358,10 @@ public: const int* getdQPs () const { return m_aidQP; } uint32_t getDeltaQpRD () const { return m_uiDeltaQpRD; } bool getFastDeltaQp () const { return m_bFastDeltaQP; } - +#if JVET_R0110_MIXED_LOSSLESS + void setSliceLosslessArray(std::vector<uint32_t> sliceLosslessArray) { m_sliceLosslessArray = sliceLosslessArray; } + const std::vector<uint32_t>* getSliceLosslessArray() const { return &m_sliceLosslessArray; } +#endif //====== Tiles and Slices ======== void setNoPicPartitionFlag( bool b ) { m_noPicPartitionFlag = b; } bool getNoPicPartitionFlag() { return m_noPicPartitionFlag; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index ff9addd27..8e63c8799 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -775,7 +775,11 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par { bool skipSecColorSpace = false; skipSecColorSpace = xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? true : false)); +#if JVET_R0110_MIXED_LOSSLESS + if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) && !m_pcEncCfg->getRGBFormatFlag()) +#else if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) && !m_pcEncCfg->getRGBFormatFlag()) +#endif { skipSecColorSpace = true; } diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 78a98415c..1d508ce9b 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -2663,6 +2663,9 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, // now compress (trial encode) the various slice segments (slices, and dependent slices) { DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) ); +#if JVET_R0110_MIXED_LOSSLESS + const std::vector<uint32_t> sliceLosslessArray = *(m_pcCfg->getSliceLosslessArray()); +#endif for(uint32_t sliceIdx = 0; sliceIdx < pcPic->cs->pps->getNumSlicesInPic(); sliceIdx++ ) { @@ -2705,6 +2708,16 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, } } } + +#if JVET_R0110_MIXED_LOSSLESS + bool isLossless = false; + if (m_pcCfg->getCostMode() == COST_LOSSLESS_CODING) + { + isLossless = (sliceLosslessArray[sliceIdx] != 0); + } + m_pcSliceEncoder->setLosslessSlice(pcPic, isLossless); +#endif + m_pcSliceEncoder->precompressSlice( pcPic ); m_pcSliceEncoder->compressSlice ( pcPic, false, false ); @@ -2799,7 +2812,18 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, } #endif } - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcCfg->getCostMode() == COST_LOSSLESS_CODING) + { + for (int s = 0; s < uiNumSliceSegments; s++) + { + if (pcPic->slices[s]->isLossless()) + { + pcPic->slices[s]->setDeblockingFilterDisable(true); + } + } + } +#endif m_pcLoopFilter->loopFilterPic( cs ); CS::setRefinedMotionField(cs); @@ -2815,11 +2839,26 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, #endif m_pcCfg->getTestSAODisableAtPictureLevel(), m_pcCfg->getSaoEncodingRate(), m_pcCfg->getSaoEncodingRateChroma(), m_pcCfg->getSaoCtuBoundary(), m_pcCfg->getSaoGreedyMergeEnc() ); //assign SAO slice header - for(int s=0; s< uiNumSliceSegments; s++) + for (int s = 0; s < uiNumSliceSegments; s++) { - pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_LUMA, sliceEnabled[COMPONENT_Y]); - CHECK(!(sliceEnabled[COMPONENT_Cb] == sliceEnabled[COMPONENT_Cr]), "Unspecified error"); - pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, sliceEnabled[COMPONENT_Cb]); + +#if JVET_R0110_MIXED_LOSSLESS + if (pcPic->slices[s]->isLossless() && m_pcCfg->getCostMode() == COST_LOSSLESS_CODING) + { + pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_LUMA, false); + pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, false); + } + else + { +#endif + pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_LUMA, sliceEnabled[COMPONENT_Y]); + CHECK(!(sliceEnabled[COMPONENT_Cb] == sliceEnabled[COMPONENT_Cr]), "Unspecified error"); + pcPic->slices[s]->setSaoEnabledFlag(CHANNEL_TYPE_CHROMA, sliceEnabled[COMPONENT_Cb]); + +#if JVET_R0110_MIXED_LOSSLESS + } +#endif + } } @@ -2836,15 +2875,35 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, m_pcALF->ALFProcess(cs, pcSlice->getLambdas() #if ENABLE_QPA , (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && pcSlice->getPPS()->getUseDQP() ? m_pcEncLib->getRdCost(PARL_PARAM0(0))->getChromaWeight() : 0.0) +#endif +#if JVET_R0110_MIXED_LOSSLESS + , pcPic, uiNumSliceSegments #endif ); //assign ALF slice header for (int s = 0; s < uiNumSliceSegments; s++) { - pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Y, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y)); - pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb)); - pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr)); +#if JVET_R0110_MIXED_LOSSLESS + //For the first slice, even if it is lossless, slice level ALF is not disabled and ALF-APS is signaled so that the later lossy slices can use APS of the first slice. + //However, if the first slice is lossless, the ALF process is disabled for all of the CTUs ( m_ctuEnableFlag == 0) of that slice which is implemented in the function void EncAdaptiveLoopFilter::ALFProcess. + + if (pcPic->slices[s]->isLossless() && s && m_pcCfg->getCostMode() == COST_LOSSLESS_CODING) + { + pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Y, false); + pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, false); + pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, false); + } + else + { +#endif + pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Y, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y)); + pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb)); + pcPic->slices[s]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr)); + +#if JVET_R0110_MIXED_LOSSLESS + } +#endif if (pcPic->slices[s]->getTileGroupAlfEnabledFlag(COMPONENT_Y)) { pcPic->slices[s]->setTileGroupNumAps(cs.slice->getTileGroupNumAps()); diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 599701109..46aa69ba7 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -628,6 +628,9 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr rpcSlice->setSliceQp ( iQP ); rpcSlice->setSliceQpDelta ( 0 ); +#if JVET_R0110_MIXED_LOSSLESS + pcPic->setLossyQPValue(iQP); +#endif #if !W0038_CQP_ADJ rpcSlice->setSliceChromaQpDelta( COMPONENT_Cb, 0 ); rpcSlice->setSliceChromaQpDelta( COMPONENT_Cr, 0 ); @@ -1135,6 +1138,36 @@ void EncSlice::setSearchRange( Slice* pcSlice ) } } +#if JVET_R0110_MIXED_LOSSLESS +void EncSlice::setLosslessSlice(Picture* pcPic, bool islossless) +{ + Slice* slice = pcPic->slices[getSliceSegmentIdx()]; + slice->setLossless(islossless); + + if (m_pcCfg->getCostMode() == COST_LOSSLESS_CODING) + { + if (islossless) + { + int losslessQp = LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP - ((slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 8) * 6); + slice->setSliceQp(losslessQp); // update the slice/base QPs + +#if JVET_R0143_TSRCdisableLL + slice->setTSResidualCodingDisabledFlag(m_pcCfg->getTSRCdisableLL() ? true : false); +#else + slice->setTSResidualCodingDisabledFlag(true); +#endif + + } + else + { + slice->setSliceQp(pcPic->getLossyQPValue()); + slice->setTSResidualCodingDisabledFlag(false); + } + } +} +#endif + + /** Multi-loop slice encoding for different slice QP @@ -1441,6 +1474,9 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons RdCost* pRdCost = pEncLib->getRdCost( PARL_PARAM0( dataId ) ); EncCfg* pCfg = pEncLib; RateCtrl* pRateCtrl = pEncLib->getRateCtrl(); +#if JVET_R0110_MIXED_LOSSLESS + pRdCost->setLosslessRDCost(pcSlice->isLossless()); +#endif #if RDOQ_CHROMA_LAMBDA pTrQuant ->setLambdas( pcSlice->getLambdas() ); #else diff --git a/source/Lib/EncoderLib/EncSlice.h b/source/Lib/EncoderLib/EncSlice.h index 53fadab31..aeff8eb1c 100644 --- a/source/Lib/EncoderLib/EncSlice.h +++ b/source/Lib/EncoderLib/EncSlice.h @@ -128,6 +128,9 @@ public: void precompressSlice ( Picture* pcPic ); ///< precompress slice for multi-loop slice-level QP opt. void compressSlice ( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP ); ///< analysis stage of slice void calCostSliceI ( Picture* pcPic ); +#if JVET_R0110_MIXED_LOSSLESS + void setLosslessSlice(Picture* pcPic, bool b); ///< Set if the slice is lossless or not +#endif void encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, uint32_t &numBinsCoded ); void encodeCtus ( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP, EncLib* pcEncLib ); diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index bea5d61e5..ad660bb8f 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -6533,7 +6533,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par uint8_t nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests std::vector<TrMode> trModes; +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) +#endif { nNumTransformCands = 0; } @@ -6570,8 +6574,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par #endif } } - +#if JVET_R0110_MIXED_LOSSLESS + if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())) +#else if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)) +#endif { m_pcTrQuant->lambdaAdjustColorTrans(true); m_pcRdCost->lambdaAdjustColorTrans(true, compID); @@ -6588,7 +6595,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par m_CABACEstimator->resetBits(); { - if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING ) ) +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless())) +#else + if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) ) +#endif { if (bestTU.mtsIdx[compID] == MTS_SKIP && m_pcEncCfg->getUseTransformSkipFast()) { @@ -6636,7 +6647,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par m_pcTrQuant->transformNxN( tu, compID, cQP, &trModes, m_pcEncCfg->getMTSInterMaxCand() ); tu.mtsIdx[compID] = trModes[0].first; } +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0)) +#else if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0 ) ) +#endif { m_pcTrQuant->transformNxN( tu, compID, cQP, currAbsSum, m_CABACEstimator->getCtx(), true ); } @@ -6684,8 +6699,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { *puiZeroDist += nonCoeffDist; // initialized with zero residual distortion } - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) +#else if( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0 ) +#endif { currAbsSum = 0; } @@ -6784,8 +6802,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par // copy component tu.copyComponentFrom( bestTU, compID ); csFull->getResiBuf( compArea ).copyFrom( saveCS.getResiBuf( compArea ) ); - +#if JVET_R0110_MIXED_LOSSLESS + if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())) +#else if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)) +#endif { m_pcTrQuant->lambdaAdjustColorTrans(false); m_pcRdCost->lambdaAdjustColorTrans(false, compID); @@ -6887,8 +6908,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par tu.mtsIdx[codeCompId] = trModes[modeId].first; tu.mtsIdx[otherCompId] = MTS_DCT2_DCT2; int codedCbfMask = 0; - +#if JVET_R0110_MIXED_LOSSLESS + if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())) +#else if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)) +#endif { m_pcTrQuant->lambdaAdjustColorTrans(true); m_pcTrQuant->selectLambda(codeCompId); @@ -7026,8 +7050,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } } - +#if JVET_R0110_MIXED_LOSSLESS + if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())) +#else if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)) +#endif { m_pcTrQuant->lambdaAdjustColorTrans(false); } diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index b8b296650..29be70ab3 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -1766,7 +1766,11 @@ void IntraSearch::preCalcPLTIndexRD(CodingStructure& cs, Partitioner& partitione CodingUnit &cu = *cs.getCU(partitioner.chType); uint32_t height = cu.block(compBegin).height; uint32_t width = cu.block(compBegin).width; +#if JVET_R0110_MIXED_LOSSLESS + bool lossless = (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && cs.slice->isLossless()); +#else bool lossless = (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING); +#endif CPelBuf orgBuf[3]; for (int comp = compBegin; comp < (compBegin + numComp); comp++) @@ -2270,7 +2274,11 @@ void IntraSearch::calcPixelPred(CodingStructure& cs, Partitioner& partitioner, u { CodingUnit &cu = *cs.getCU(partitioner.chType); TransformUnit &tu = *cs.getTU(partitioner.chType); +#if JVET_R0110_MIXED_LOSSLESS + bool lossless = (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && cs.slice->isLossless()); +#else bool lossless = (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING); +#endif CPelBuf orgBuf[3]; for (int comp = compBegin; comp < (compBegin + numComp); comp++) @@ -2357,7 +2365,11 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner, CodingUnit &cu = *cs.getCU(partitioner.chType); const int channelBitDepth_L = cs.sps->getBitDepth(CHANNEL_TYPE_LUMA); const int channelBitDepth_C = cs.sps->getBitDepth(CHANNEL_TYPE_CHROMA); +#if JVET_R0110_MIXED_LOSSLESS + bool lossless = (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && cs.slice->isLossless()); +#else bool lossless = (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING); +#endif int pcmShiftRight_L = (channelBitDepth_L - PLT_ENCBITDEPTH); int pcmShiftRight_C = (channelBitDepth_C - PLT_ENCBITDEPTH); if (lossless) @@ -3162,7 +3174,11 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, m_pcEncCfg->getMTSIntraMaxCand()); tu.mtsIdx[compID] = trModes->at(0).first; } +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmMode != 0) +#else if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0 ) || tu.cu->bdpcmMode != 0 ) +#endif { m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); } @@ -3176,8 +3192,11 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp ruiDist = MAX_INT; return; } - +#if JVET_R0110_MIXED_LOSSLESS + if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) && 0 == tu.cu->bdpcmMode) +#else if( ( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0 ) && 0 == tu.cu->bdpcmMode ) +#endif { uiAbsSum = 0; tu.getCoeffs( compID ).fill( 0 ); @@ -3219,12 +3238,19 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } } // encoder bugfix: Set loadTr to aovid redundant transform process +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmModeChroma != 0) +#else if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmModeChroma != 0) +#endif { m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); } - +#if JVET_R0110_MIXED_LOSSLESS + if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) && 0 == tu.cu->bdpcmModeChroma) +#else if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0) && 0 == tu.cu->bdpcmModeChroma) +#endif { uiAbsSum = 0; tu.getCoeffs(compID).fill(0); @@ -3343,8 +3369,11 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c bool jointCbCr = tu.jointCbCr && compID == COMPONENT_Cb; m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc()); - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcTrQuant->lambdaAdjustColorTrans(true); if (jointCbCr) @@ -3386,9 +3415,17 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, m_pcEncCfg->getMTSIntraMaxCand()); tu.mtsIdx[compID] = trModes->at(0).first; } +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmMode != 0) +#else if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmMode != 0) +#endif m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); +#if JVET_R0110_MIXED_LOSSLESS + if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) && tu.cu->bdpcmMode == 0) +#else if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0) && tu.cu->bdpcmMode == 0) +#endif { uiAbsSum = 0; tu.getCoeffs(compID).fill(0); @@ -3428,7 +3465,11 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c tu.mtsIdx[(codeCompId == COMPONENT_Cr) ? COMPONENT_Cb : COMPONENT_Cr] = MTS_DCT2_DCT2; } } +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[codeCompId] == 0) || tu.cu->bdpcmModeChroma != 0) +#else if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[codeCompId] == 0) || tu.cu->bdpcmModeChroma != 0) +#endif { m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); } @@ -3452,7 +3493,11 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c if (tu.jointCbCr != codedCbfMask) { ruiDist = std::numeric_limits<Distortion>::max(); +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcTrQuant->lambdaAdjustColorTrans(false); return; } @@ -3469,8 +3514,11 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c crResi.scaleSignal(tu.getChromaAdj(), 0, slice.clpRng(COMPONENT_Cr)); } } - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcTrQuant->lambdaAdjustColorTrans(false); ruiDist += m_pcRdCost->getDistPart(piOrgResi, piResi, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE); @@ -3604,6 +3652,9 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par bool bCheckSplit = false; bCheckFull = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); bCheckSplit = partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); +#if JVET_R0110_MIXED_LOSSLESS + const Slice &slice = *cs.slice; +#endif if( cu.ispMode ) { @@ -3667,8 +3718,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par else { nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) +#endif { nNumTransformCands = 1; CHECK(!tsAllowed && !cu.bdpcmMode, "transform skip should be enabled for LS"); @@ -3746,7 +3800,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par } else { - if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING ) ) +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless())) +#else + if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) ) +#endif { if( !cbfDCT2 || ( m_pcEncCfg->getUseTransformSkipFast() && bestModeId[ COMPONENT_Y ] == MTS_SKIP)) { @@ -3873,7 +3931,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par if( ( sps.getUseLFNST() ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) ) { //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif singleCostTmp = MAX_DOUBLE; else { @@ -4222,7 +4284,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti } else { +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) +#endif { nNumTransformCands = 1; CHECK(!tsAllowed && !cu.bdpcmMode, "transform skip should be enabled for LS"); @@ -4275,11 +4341,17 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti bool cbfBestMode = false; bool cbfBestModeValid = false; bool cbfDCT2 = true; - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcRdCost->lambdaAdjustColorTrans(true, COMPONENT_Y); - +#if JVET_R0110_MIXED_LOSSLESS + for (int modeId = firstCheckId; modeId <= ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) ? (nNumTransformCands - 1) : lastCheckId); modeId++) +#else for (int modeId = firstCheckId; modeId <= ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) ? (nNumTransformCands - 1) : lastCheckId); modeId++) +#endif { uint8_t transformIndex = modeId; csFull->getResiBuf(tu.Y()).copyFrom(csFull->getOrgResiBuf(tu.Y())); @@ -4300,7 +4372,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti } else { +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless())) +#else if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)) +#endif { if (!cbfDCT2 || (m_pcEncCfg->getUseTransformSkipFast() && bestLumaModeId == 1)) { @@ -4394,7 +4470,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti if ((sps.getUseLFNST() ? (modeId == lastCheckId && modeId != 0 && checkTransformSkip) : (trModes[modeId].first != 0)) && !TU::getCbfAtDepth(tu, COMPONENT_Y, currDepth)) { //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif singleCostTmp = MAX_DOUBLE; else { @@ -4449,8 +4529,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti } } } - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcRdCost->lambdaAdjustColorTrans(false, COMPONENT_Y); if (sps.getUseLFNST()) @@ -4524,8 +4607,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti bool cbfDCT2 = true; trModes.clear(); - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) +#endif { numTransformCands = 1; CHECK(!tsAllowed && !cu.bdpcmModeChroma, "transform skip should be enabled for LS"); @@ -4546,8 +4632,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti trModes.push_back(TrMode(1, true)); // TS } } - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcRdCost->lambdaAdjustColorTrans(true, compID); TempCtx ctxBegin(m_CtxCache); @@ -4555,7 +4644,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti for (int modeId = 0; modeId < numTransformCands; modeId++) { +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif { if (modeId && !cbfDCT2) { @@ -4605,8 +4698,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti tu.copyComponentFrom(*tmpTU, compID); m_CABACEstimator->getCtx() = ctxBest; } - +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcRdCost->lambdaAdjustColorTrans(false, compID); } @@ -4885,7 +4981,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio UnitArea currArea = partitioner.currArea(); const bool keepResi = cs.sps->getUseLMChroma() || KEEP_PRED_AND_RESI_SIGNALS; if( !currArea.Cb().valid() ) return ChromaCbfs( false ); - +#if JVET_R0110_MIXED_LOSSLESS + const Slice &slice = *cs.slice; +#endif TransformUnit &currTU = *cs.getTU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); const PredictionUnit &pu = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); @@ -5018,7 +5116,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio const bool tsAllowed = TU::isTSAllowed(currTU, compID) && m_pcEncCfg->getUseChromaTS() && !currTU.cu->lfnstIdx; uint8_t nNumTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests std::vector<TrMode> trModes; +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) +#endif { nNumTransformCands = 1; CHECK(!tsAllowed && !currTU.cu->bdpcmModeChroma, "transform skip should be enabled for LS"); @@ -5067,8 +5169,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio const bool isFirstMode = (currModeId == 1); const bool isLastMode = false; // Always store output to saveCS and tmpTU - - if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING ) ) +#if JVET_R0110_MIXED_LOSSLESS + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless())) +#else + if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) ) +#endif { //if DCT2's cbf==0, skip ts search if (!cbfDCT2 && trModes[modeId].first == MTS_SKIP) @@ -5099,7 +5204,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio if (((currTU.mtsIdx[compID] == MTS_SKIP && !currTU.cu->bdpcmModeChroma) && !TU::getCbf(currTU, compID))) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. { +#if JVET_R0110_MIXED_LOSSLESS + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless()) +#else if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif singleCostTmp = MAX_DOUBLE; else { @@ -5174,7 +5283,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio } // Done with one component of separate coding of Cr and Cb, just switch to the best Cb contexts if Cr coding is still to be done +#if JVET_R0110_MIXED_LOSSLESS + if ((c == COMPONENT_Cb && bestModeId < totalModesToTest) || (c == COMPONENT_Cb && m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless())) +#else if ((c == COMPONENT_Cb && bestModeId < totalModesToTest) || (c == COMPONENT_Cb && m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)) +#endif { m_CABACEstimator->getCtx() = ctxBest; -- GitLab