diff --git a/cfg/lossless/lossless.cfg b/cfg/lossless/lossless.cfg index 793b2bedbd16f9300826026cd8bb27cf2024e94a..2ab513b33ad737766719b20fe14442b1d902a339 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 0000000000000000000000000000000000000000..c53046585f386a8ab9534772ba473b5e917d63fc --- /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 aa01684f08146d77982494e93e0deaadbdcfde73..9b5c193ca5fdf54e3b1302f5666f99f64e3ae6a1 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 2b50392d19c98b02151434483751da5f4022f3f8..db141a6faf6633906e9bfb4b27befc77a3d3b62a 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 0faec54b600fe41cd102ec4691c79ebfd64b866d..c07e8e97880a8d49cae6cc1a23f9041ed42a4192 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 0263cb3bad5986fb489fabddc729a0a6da432a44..14cf20b36e0148ef090d525c7c2cd0a8303bf918 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 4a0b4ab8b4d01c255ec75af1b8c5a9ff47985475..6f4b5b6dabb0e29eed0b53728b3f4b0ee7257a10 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 881f0178c4f42f4d62e5d4534b1230cc9582ee9f..26a17c99d44f4864f59c485da43e2b8878819d5d 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 81eec7926fcd289cea9d6dc4eab76113fa15beeb..4f4cdb5850559216f6475ebbfb0b61f0813a535c 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 15a2c5c740dfd3e57fb4116a06e23ba378974409..3cf776c1af231d0e9d420c53ef414b7acdf49116 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 948a5a3b052e05e635ace4f571719970dc4462cb..d28342e43968e573abc137d9db6aec86fb8a0d35 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 a9e092631d78a297b89bde3112eef59d2b5c43a3..3b9109cc6a400e8bb50d194a8c7a74f2e4d8f441 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 3ba52903d6dcbe59a45e5684eae9f04286f5a95b..99e8bcb6b24a8f8cf40821d06d7dc578150a0878 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 111872fb01d07910cea2fea261d8577a5b3ad311..76ce5f0da3a70b0ca590d517ab53bccf7bce89cd 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 db4c7d313e4fa410cb1e0db36258d041a265d209..cecff4c840677371c42632aa14e26dea53c10947 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 40e2516d8d12f3220ac93decb21b15c6cc53b9b4..6c64775ab196bb8a8c77c9e1603069ba53779784 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 ff9addd27141f2bbf2ffcabc2e7ff73f61ef088a..8e63c8799cf65a3acff745f0f0a059e49264c261 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 78a98415c6401df956f3d9f17a1e6b06cbc17306..1d508ce9b06fff3460b4e9fe34adb8aae1969849 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 59970110933d34e4064e8a3df3a4833bee0df710..46aa69ba7d5922ebee933821c8b612dc591fdfc0 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 53fadab31876c5ef4cb5a2bc7c38b11907fc423f..aeff8eb1c0c5d88ce9a3b3578a7376e697986c43 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 bea5d61e505474fc35867858d543ca88aafef359..ad660bb8f98565b81297db018b67525996c19d08 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 b8b29665013a6c030b4cabaa9b41c20d3d57f5d1..29be70ab385de60de57353f4a969524c9c2ce9fe 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;