Commit 442a0444 authored by Taoran Lu's avatar Taoran Lu

merge JVET-M0427 into master

parent 69292704
......@@ -120,6 +120,7 @@ PBIntraFast : 1
FastMrg : 1
AMaxBT : 1
### DO NOT ADD ANYTHING BELOW THIS LINE ###
### DO NOT DELETE THE EMPTY LINE BELOW ###
......
......@@ -550,6 +550,12 @@ void EncApp::xInitLibCfg()
#endif
m_cEncLib.setUseALF ( m_alf );
#if JVET_M0427_INLOOP_RESHAPER
m_cEncLib.setReshaper ( m_bLumaReshapeEnable );
m_cEncLib.setReshapeSignalType ( m_uiSignalType );
m_cEncLib.setReshapeIntraCMD ( m_uiIntraCMD );
m_cEncLib.setReshapeCW ( m_reshapeCW );
#endif
}
void EncApp::xCreateLib( std::list<PelUnitBuf*>& recBufList
......
......@@ -707,6 +707,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
#endif
int warnUnknowParameter = 0;
#if JVET_M0427_INLOOP_RESHAPER
const uint32_t defaultBinCW[CW_NUMS - 1] = { 38, 28 };
const uint32_t defaultBinThr[CW_NUMS - 1] = { 2500, 4000 };
SMultiValueInput<uint32_t> cfg_BinCW (0, 64, CW_NUMS - 1, CW_NUMS - 1, defaultBinCW, sizeof(defaultBinCW) / sizeof(uint32_t));
SMultiValueInput<uint32_t> cfg_BinThr (0, std::numeric_limits<uint32_t>::max(), CW_NUMS - 1, CW_NUMS - 1, defaultBinThr, sizeof(defaultBinThr) / sizeof(uint32_t));
#endif
#if ENABLE_TRACING
string sTracingRule;
string sTracingFile;
......@@ -882,7 +889,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
("WrapAroundOffset", m_wrapAroundOffset, 0u, "Offset in luma samples used for computing the horizontal wrap-around position")
// ADD_NEW_TOOL : (encoder app) add parsing parameters here
#if JVET_M0427_INLOOP_RESHAPER
("LumaReshapeEnable", m_bLumaReshapeEnable, false, "Enable Reshaping for Luma Channel")
("ReshapeSignalType", m_uiSignalType, 0u, "Input signal type: 0: SDR, 1:PQ, 2:HLG")
("IntraCMD", m_uiIntraCMD, 0u, "IntraChroma MD: 0: none, 1:fixed to default wPSNR weight")
#endif
("LCTUFast", m_useFastLCTU, false, "Fast methods for large CTU")
("FastMrg", m_useFastMrg, false, "Fast methods for inter merge")
("PBIntraFast", m_usePbIntraFast, false, "Fast assertion if the intra mode is probable")
......@@ -1836,6 +1847,15 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
}
}
#if JVET_M0427_INLOOP_RESHAPER
m_reshapeCW.BinCW.resize(CW_NUMS);
m_reshapeCW.RspFps = m_iFrameRate;
m_reshapeCW.RspIntraPeriod = m_iIntraPeriod;
m_reshapeCW.RspPicSize = m_iSourceWidth*m_iSourceHeight;
const int FpsToIpTable[MAX_FRAME_RATE + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128 };
m_reshapeCW.RspFpsToIp = FpsToIpTable[m_iFrameRate];
m_reshapeCW.RspBaseQP = m_iQP;
#endif
#if ENABLE_TRACING
g_trace_ctx = tracing_init(sTracingFile, sTracingRule);
if( bTracingChannelsList && g_trace_ctx )
......@@ -2219,6 +2239,30 @@ bool EncAppCfg::xCheckParameter()
#if SHARP_LUMA_DELTA_QP
xConfirmPara( m_lumaLevelToDeltaQPMapping.mode && m_uiDeltaQpRD > 0, "Luma-level-based Delta QP cannot be used together with slice level multiple-QP optimization\n" );
#endif
#if JVET_M0427_INLOOP_RESHAPER
if (m_bLumaReshapeEnable && (m_internalBitDepth[CHANNEL_TYPE_LUMA] != 10))
{
m_bLumaReshapeEnable = false;
msg(WARNING, "Reshaping is implemented for 10bit luma internal bitdepth.\n");
}
if (!m_bLumaReshapeEnable)
{
m_uiSignalType = RESHAPE_SIGNAL_NULL;
m_uiIntraCMD = 0;
}
if (m_bLumaReshapeEnable && m_uiSignalType == RESHAPE_SIGNAL_PQ)
{
m_uiIntraCMD = 1;
}
else if (m_bLumaReshapeEnable && m_uiSignalType == RESHAPE_SIGNAL_SDR)
{
m_uiIntraCMD = 0;
}
else
{
m_bLumaReshapeEnable = false;
}
#endif
xConfirmPara( m_cbQpOffset < -12, "Min. Chroma Cb QP Offset is -12" );
xConfirmPara( m_cbQpOffset > 12, "Max. Chroma Cb QP Offset is 12" );
......@@ -3164,7 +3208,14 @@ void EncAppCfg::xPrintParameter()
msg( VERBOSE, "WrapAroundOffset:%d ", m_wrapAroundOffset );
}
// ADD_NEW_TOOL (add some output indicating the usage of tools)
#if JVET_M0427_INLOOP_RESHAPER
msg(VERBOSE, "Reshape:%d ", m_bLumaReshapeEnable);
if (m_bLumaReshapeEnable)
{
msg(VERBOSE, "(Sigal:%s ", m_uiSignalType==0? "SDR" : "HDR-PQ");
msg(VERBOSE, ") ");
}
#endif
msg( VERBOSE, "\nFAST TOOL CFG: " );
if( m_LargeCTU )
{
......
......@@ -256,7 +256,12 @@ protected:
unsigned m_wrapAroundOffset;
// ADD_NEW_TOOL : (encoder app) add tool enabling flags and associated parameters here
#if JVET_M0427_INLOOP_RESHAPER
bool m_bLumaReshapeEnable;
uint32_t m_uiSignalType;
uint32_t m_uiIntraCMD;
ReshapeCW m_reshapeCW;
#endif
unsigned m_uiMaxCUWidth; ///< max. CU width in pixel
unsigned m_uiMaxCUHeight; ///< max. CU height in pixel
unsigned m_uiMaxCUDepth; ///< max. CU depth (as specified by command line)
......
......@@ -343,6 +343,99 @@ void AreaBuf<Pel>::addWeightedAvg(const AreaBuf<const Pel> &other1, const AreaBu
#undef ADD_AVG_INC
}
#if JVET_M0427_INLOOP_RESHAPER
template<>
void AreaBuf<Pel>::rspSignal(std::vector<Pel>& pLUT)
{
Pel* dst = buf;
Pel* src = buf;
if (width == 1)
{
THROW("Blocks of width = 1 not supported");
}
else
{
for (unsigned y = 0; y < height; y++)
{
for (unsigned x = 0; x < width; x++)
{
dst[x] = pLUT[src[x]];
}
dst += stride;
src += stride;
}
}
}
template<>
void AreaBuf<Pel>::scaleSignal(const int scale, const bool dir)
{
Pel* dst = buf;
Pel* src = buf;
int sign, absval;
if (dir) // forward
{
if (width == 1)
{
THROW("Blocks of width = 1 not supported");
}
else
{
for (unsigned y = 0; y < height; y++)
{
for (unsigned x = 0; x < width; x++)
{
sign = src[x] >= 0 ? 1 : -1;
absval = sign * src[x];
dst[x] = sign * (((absval << CSCALE_FP_PREC) + (scale >> 1)) / scale);
dst[x] = dst[x] > 1023 ? 1023 : dst[x] < -1023 ? -1023 : dst[x];
}
dst += stride;
src += stride;
}
}
}
else // inverse
{
for (unsigned y = 0; y < height; y++)
{
for (unsigned x = 0; x < width; x++)
{
sign = src[x] >= 0 ? 1 : -1;
absval = sign * src[x];
dst[x] = sign * ((absval * scale + (1 << (CSCALE_FP_PREC - 1))) >> CSCALE_FP_PREC);
}
dst += stride;
src += stride;
}
}
}
template<>
Pel AreaBuf <Pel> ::computeAvg() const
{
const Pel* src = buf;
if (width == 1)
{
THROW("Blocks of width = 1 not supported");
}
else
{
int32_t acc = 0;
#define AVG_INC \
src += stride;
#define AVG_OP(ADDR) acc += src[ADDR]
SIZE_AWARE_PER_EL_OP(AVG_OP, AVG_INC);
#undef AVG_INC
#undef AVG_OP
return Pel((acc + (area() >> 1)) / area());
}
}
#endif
template<>
void AreaBuf<Pel>::addAvg( const AreaBuf<const Pel> &other1, const AreaBuf<const Pel> &other2, const ClpRng& clpRng)
{
......
......@@ -132,6 +132,11 @@ struct AreaBuf : public Size
void toLast ( const ClpRng& clpRng );
#if JVET_M0427_INLOOP_RESHAPER
void rspSignal ( std::vector<Pel>& pLUT );
void scaleSignal ( const int scale, const bool dir );
T computeAvg ( ) const;
#endif
T& at( const int &x, const int &y ) { return buf[y * stride + x]; }
const T& at( const int &x, const int &y ) const { return buf[y * stride + x]; }
......
......@@ -969,6 +969,14 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel
// copy data to picture
picture->getRecoBuf( area ).copyFrom( recoBuf );
#if JVET_M0427_INLOOP_RESHAPER
CPelUnitBuf predBuf = other.getPredBuf(area);
if (parent)
{
getPredBuf(area).copyFrom(predBuf);
}
picture->getPredBuf(area).copyFrom(predBuf);
#endif
}
}
......
......@@ -53,6 +53,9 @@ enum PictureType
{
PIC_RECONSTRUCTION = 0,
PIC_ORIGINAL,
#if JVET_M0427_INLOOP_RESHAPER
PIC_TRUE_ORIGINAL,
#endif
PIC_PREDICTION,
PIC_RESIDUAL,
PIC_ORG_RESI,
......
......@@ -404,7 +404,19 @@ static const int CHROMA_REFINEMENT_CANDIDATES = 8; /// 8 candidates BV to choose
static const int IBC_FAST_METHOD_NOINTRA_IBCCBF0 = 0x01;
static const int IBC_FAST_METHOD_BUFFERBV = 0X02;
static const int IBC_FAST_METHOD_ADAPTIVE_SEARCHRANGE = 0X04;
#if JVET_M0427_INLOOP_RESHAPER
static const int MAX_LUMA_RESHAPING_LUT_SIZE = 1024;
static const int CSCALE_FP_PREC = 11;
static const int PIC_ANALYZE_CW_BINS = 32;
static const int FP_PREC = 14;
static const int log2_MAX_LUMA_RESHAPING_LUT_SIZE = 10;
static const int log2_PIC_ANALYZE_CW_BINS = 5;
static const int PIC_ANALYZE_WIN_SIZE = 5;
static const int CW_NUMS = 3;
static const int MAX_FRAME_RATE = 128;
static const int PIC_CODE_CW_BINS = 16;
static const int log2_PIC_CODE_CW_BINS = 4;
#endif
#if JVET_M0512_MOTION_BUFFER_COMPRESSION
static constexpr int MV_EXPONENT_BITCOUNT = 4;
static constexpr int MV_MANTISSA_BITCOUNT = 6;
......
......@@ -742,6 +742,9 @@ void Picture::create(const ChromaFormat &_chromaFormat, const Size &size, const
if( !_decoder )
{
M_BUFS( 0, PIC_ORIGINAL ). create( _chromaFormat, a );
#if JVET_M0427_INLOOP_RESHAPER
M_BUFS( 0, PIC_TRUE_ORIGINAL ). create( _chromaFormat, a );
#endif
}
#if !KEEP_PRED_AND_RESI_SIGNALS
......@@ -846,6 +849,14 @@ const CPelUnitBuf Picture::getOrigBuf(const UnitArea &unit) const { return getBu
PelUnitBuf Picture::getOrigBuf() { return M_BUFS(0, PIC_ORIGINAL); }
const CPelUnitBuf Picture::getOrigBuf() const { return M_BUFS(0, PIC_ORIGINAL); }
#if JVET_M0427_INLOOP_RESHAPER
PelBuf Picture::getOrigBuf(const ComponentID compID) { return getBuf(compID, PIC_ORIGINAL); }
const CPelBuf Picture::getOrigBuf(const ComponentID compID) const { return getBuf(compID, PIC_ORIGINAL); }
PelUnitBuf Picture::getTrueOrigBuf() { return M_BUFS(0, PIC_TRUE_ORIGINAL); }
const CPelUnitBuf Picture::getTrueOrigBuf() const { return M_BUFS(0, PIC_TRUE_ORIGINAL); }
PelBuf Picture::getTrueOrigBuf(const CompArea &blk) { return getBuf(blk, PIC_TRUE_ORIGINAL); }
const CPelBuf Picture::getTrueOrigBuf(const CompArea &blk) const { return getBuf(blk, PIC_TRUE_ORIGINAL); }
#endif
PelBuf Picture::getPredBuf(const CompArea &blk) { return getBuf(blk, PIC_PREDICTION); }
const CPelBuf Picture::getPredBuf(const CompArea &blk) const { return getBuf(blk, PIC_PREDICTION); }
PelUnitBuf Picture::getPredBuf(const UnitArea &unit) { return getBuf(unit, PIC_PREDICTION); }
......
......@@ -192,6 +192,14 @@ struct Picture : public UnitArea
const CPelUnitBuf getOrigBuf(const UnitArea &unit) const;
PelUnitBuf getOrigBuf();
const CPelUnitBuf getOrigBuf() const;
#if JVET_M0427_INLOOP_RESHAPER
PelBuf getOrigBuf(const ComponentID compID);
const CPelBuf getOrigBuf(const ComponentID compID) const;
PelUnitBuf getTrueOrigBuf();
const CPelUnitBuf getTrueOrigBuf() const;
PelBuf getTrueOrigBuf(const CompArea &blk);
const CPelBuf getTrueOrigBuf(const CompArea &blk) const;
#endif
PelBuf getPredBuf(const CompArea &blk);
const CPelBuf getPredBuf(const CompArea &blk) const;
......
......@@ -176,6 +176,10 @@ void RdCost::init()
m_motionLambda = 0;
m_iCostScale = 0;
#if JVET_M0427_INLOOP_RESHAPER
m_iSignalType = RESHAPE_SIGNAL_NULL;
m_chroma_weight = 1.0;
#endif
}
......@@ -2859,6 +2863,11 @@ Distortion RdCost::xGetHADs( const DistParam &rcDtParam )
#if WCG_EXT
double RdCost::m_lumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE];
#if JVET_M0427_INLOOP_RESHAPER
double RdCost::m_reshapeLumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE];
uint32_t RdCost::m_iSignalType;
double RdCost::m_chroma_weight;
#endif
void RdCost::saveUnadjustedLambda()
{
......@@ -2868,6 +2877,18 @@ void RdCost::saveUnadjustedLambda()
void RdCost::initLumaLevelToWeightTable()
{
#if JVET_M0427_INLOOP_RESHAPER
if (m_iSignalType == RESHAPE_SIGNAL_SDR)
{
double weight = 1.0;
for (int i = 0; i < LUMA_LEVEL_TO_DQP_LUT_MAXSIZE; i++)
{
m_lumaLevelToWeightPLUT[i] = weight;
}
return;
}
#endif
for (int i = 0; i < LUMA_LEVEL_TO_DQP_LUT_MAXSIZE; i++) {
double x = i;
double y;
......@@ -2889,7 +2910,69 @@ void RdCost::initLumaLevelToWeightTable()
m_lumaLevelToWeightPLUT[i] = pow(2.0, y / 3.0); // or power(10, dQp/10) they are almost equal
}
#if JVET_M0427_INLOOP_RESHAPER
memcpy(m_reshapeLumaLevelToWeightPLUT, m_lumaLevelToWeightPLUT, LUMA_LEVEL_TO_DQP_LUT_MAXSIZE * sizeof(double));
#endif
}
#if JVET_M0427_INLOOP_RESHAPER
void RdCost::updateReshapeLumaLevelToWeightTableChromaMD(std::vector<Pel>& ILUT)
{
for (int i = 0; i < LUMA_LEVEL_TO_DQP_LUT_MAXSIZE; i++) // idx in reshaped domain;
{
m_reshapeLumaLevelToWeightPLUT[i] = m_lumaLevelToWeightPLUT[ILUT[i]];
}
}
void RdCost::restoreReshapeLumaLevelToWeightTable()
{
memcpy(m_reshapeLumaLevelToWeightPLUT, m_lumaLevelToWeightPLUT, LUMA_LEVEL_TO_DQP_LUT_MAXSIZE * sizeof(double));
}
void RdCost::updateReshapeLumaLevelToWeightTable(sliceReshapeInfo &sliceReshape, Pel *wt_table, double cwt)
{
if (m_iSignalType == RESHAPE_SIGNAL_SDR)
{
if (sliceReshape.getSliceReshapeModelPresentFlag())
{
double w_bin = 1.0;
double weight = 1.0;
int hist_lens = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS;
for (int i = 0; i < PIC_CODE_CW_BINS; i++)
{
if ((i < sliceReshape.reshape_model_min_bin_idx) || (i > sliceReshape.reshape_model_max_bin_idx))
weight = 1.0;
else
{
if (sliceReshape.reshape_model_bin_CW_delta[i] == 1 || sliceReshape.reshape_model_bin_CW_delta[i] == -1 * MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS)
weight = w_bin;
else
{
weight = (double)wt_table[i] / (double)hist_lens;
weight = weight*weight;
}
}
for (int j = 0; j < hist_lens; j++)
{
int ii = i*hist_lens + j;
m_reshapeLumaLevelToWeightPLUT[ii] = weight;
}
}
m_chroma_weight = cwt;
}
else
{
THROW("updateReshapeLumaLevelToWeightTable ERROR!!");
}
}
else
{
THROW("updateReshapeLumaLevelToWeightTable not support other signal types!!");
}
}
#endif
Distortion RdCost::getWeightedMSE(int compIdx, const Pel org, const Pel cur, const uint32_t uiShift, const Pel orgLuma)
{
......@@ -2902,8 +2985,28 @@ Distortion RdCost::getWeightedMSE(int compIdx, const Pel org, const Pel cur, con
CHECK(org!=orgLuma, "");
}
// use luma to get weight
#if JVET_M0427_INLOOP_RESHAPER
double weight = 1.0;
if (m_iSignalType == RESHAPE_SIGNAL_SDR)
{
if (compIdx == COMPONENT_Y)
weight = m_reshapeLumaLevelToWeightPLUT[orgLuma];
else
{
weight = m_chroma_weight;
}
}
else
weight = m_reshapeLumaLevelToWeightPLUT[orgLuma];
#else
double weight = m_lumaLevelToWeightPLUT[orgLuma];
#endif
#if JVET_M0427_INLOOP_RESHAPER // FIXED_PT_WD_CALCULATION
int64_t fixedPTweight = (int64_t)(weight * (double)(1 << 16));
Intermediate_Int mse = Intermediate_Int((fixedPTweight*(iTemp*iTemp) + (1 << 15)) >> 16);
#else
Intermediate_Int mse = Intermediate_Int(weight*(double)iTemp*(double)iTemp+0.5);
#endif
distortionVal = Distortion( mse >> uiShift);
return distortionVal;
}
......
......@@ -108,6 +108,11 @@ private:
double m_dLambda_unadjusted; // TODO: check is necessary
double m_DistScaleUnadjusted;
static double m_lumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE];
#if JVET_M0427_INLOOP_RESHAPER
static double m_reshapeLumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE];
static uint32_t m_iSignalType;
static double m_chroma_weight;
#endif
#endif
double m_DistScale;
double m_dLambdaMotionSAD[2 /* 0=standard, 1=for transquant bypass when mixed-lossless cost evaluation enabled*/];
......@@ -290,6 +295,15 @@ public:
void saveUnadjustedLambda ();
void initLumaLevelToWeightTable ();
inline double getWPSNRLumaLevelWeight (int val) { return m_lumaLevelToWeightPLUT[val]; }
#if JVET_M0427_INLOOP_RESHAPER
void updateReshapeLumaLevelToWeightTableChromaMD (std::vector<Pel>& ILUT);
void restoreReshapeLumaLevelToWeightTable ();
inline double getWPSNRReshapeLumaLevelWeight (int val) { return m_reshapeLumaLevelToWeightPLUT[val]; }
uint32_t getReshapeSignalType () const { return m_iSignalType; }
void setReshapeSignalType (uint32_t type) { m_iSignalType = type; }
void updateReshapeLumaLevelToWeightTable (sliceReshapeInfo &sliceReshape, Pel *wt_table, double cwt);
inline double* getLumaLevelWeightTable() { return m_lumaLevelToWeightPLUT; }
#endif
#endif
private:
......
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2010-2019, ITU/ISO/IEC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file Reshape.cpp
\brief common reshaper class
*/
#include "Reshape.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#if JVET_M0427_INLOOP_RESHAPER
//! \ingroup CommonLib
//! \{
// ====================================================================================================================
// Constructor / destructor / create / destroy
// ====================================================================================================================
Reshape::Reshape()
{
m_bCTUFlag = false;
m_bRecReshaped = false;
m_bReshape = true;
m_uiCWOrg = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS;
}
Reshape::~Reshape()
{
}
void Reshape::create_dec()
{
if (forwardReshapingLUT.empty())
forwardReshapingLUT.resize(MAX_LUMA_RESHAPING_LUT_SIZE, 0);
if (inverseReshapingLUT.empty())
inverseReshapingLUT.resize(MAX_LUMA_RESHAPING_LUT_SIZE, 0);
if (m_uiBinCWAll.empty())
m_uiBinCWAll.resize(PIC_CODE_CW_BINS, 0);
if (m_ReshapePivot.empty())
m_ReshapePivot.resize(PIC_CODE_CW_BINS + 1, 0);
if (ChromaAdjHelpLUT.empty())
ChromaAdjHelpLUT.resize(PIC_CODE_CW_BINS, 2048);
}
void Reshape::destroy()
{
}
/**
-Perform inverse of a one dimension LUT
\param InputLUT describing the input LUT
\retval OutputLUT describing the inversed LUT of InputLUT
\param lut_size size of LUT in number of samples
*/
void Reshape::ReverseLUT(std::vector<Pel>& InputLUT, std::vector<Pel>& OutputLUT, uint16_t lut_size)
{
int i, j;
OutputLUT[m_ReshapePivot[m_sliceReshapeInfo.reshape_model_min_bin_idx]] = m_sliceReshapeInfo.reshape_model_min_bin_idx*m_uiCWOrg;
for (i = m_sliceReshapeInfo.reshape_model_min_bin_idx; i <= m_sliceReshapeInfo.reshape_model_max_bin_idx; i++)
{
int16_t X1 = m_ReshapePivot[i];
int16_t X2 = m_ReshapePivot[i + 1];
OutputLUT[X2] = (i + 1)*m_uiCWOrg;
int16_t Y1 = OutputLUT[X1];
int16_t Y2 = OutputLUT[X2];
if (X2 !=X1)
{
int32_t scale = (int32_t)(Y2 - Y1) * (1 << FP_PREC) / (int32_t)(X2 - X1);
for (j = X1 + 1; j < X2; j++)
{
OutputLUT[j] = (Pel)((scale*(int32_t)(j - X1) + (1 << (FP_PREC - 1))) >> FP_PREC) + Y1;
}
}
}
for (i = 0; i < m_ReshapePivot[m_sliceReshapeInfo.reshape_model_min_bin_idx]; i++)
OutputLUT[i] = OutputLUT[m_ReshapePivot[m_sliceReshapeInfo.reshape_model_min_bin_idx]];
for (i = m_ReshapePivot[m_sliceReshapeInfo.reshape_model_max_bin_idx + 1]; i < MAX_LUMA_RESHAPING_LUT_SIZE; i++)
OutputLUT[i] = OutputLUT[m_ReshapePivot[m_sliceReshapeInfo.reshape_model_max_bin_idx + 1]];
bool clipRange = ((m_sliceReshapeInfo.reshape_model_min_bin_idx > 0) && (m_sliceReshapeInfo.reshape_model_max_bin_idx < (PIC_CODE_CW_BINS - 1)));
for (i = 0; i < lut_size; i++)
{
if (clipRange) OutputLUT[i] = Clip3((Pel)64, (Pel)940, OutputLUT[i]);
else OutputLUT[i] = Clip3((Pel)0, (Pel)1023, OutputLUT[i]);
}
}
/** compute chroma residuce scale for TU
* \param average luma pred of TU
* \return chroma residue scale
*/
int Reshape::calculateChromaAdj(Pel avgLuma)
{
int lumaIdx = Clip3<int>(0, int(LUMA_LEVEL_TO_DQP_LUT_MAXSIZE) - 1, avgLuma);
int iAdj = ChromaAdjHelpLUT[getPWLIdxInv(lumaIdx)];
return(iAdj);
}
/** find inx of PWL for inverse mapping
* \param average luma pred of TU
* \return idx of PWL for inverse mapping
*/
int Reshape::getPWLIdxInv(int lumaVal)
{
int idxS = 0;
if (lumaVal < m_ReshapePivot[m_sliceReshapeInfo.reshape_model_min_bin_idx + 1])
return m_sliceReshapeInfo.reshape_model_min_bin_idx;
else if (lumaVal >= m_ReshapePivot[m_sliceReshapeInfo.reshape_model_max_bin_idx])
return m_sliceReshapeInfo.reshape_model_max_bin_idx;
else
{
for (idxS = m_sliceReshapeInfo.reshape_model_min_bin_idx; (idxS < m_sliceReshapeInfo.reshape_model_max_bin_idx); idxS++)
{
if (lumaVal < m_ReshapePivot[idxS + 1]) break;
}
return idxS;
}
}
/**
-copy Slice reshaper info structure
\param tInfo describing the target Slice reshaper info structure
\param sInfo describing the source Slice reshaper info structure
*/
void Reshape::copySliceReshaperInfo(sliceReshapeInfo& tInfo, sliceReshapeInfo& sInfo)
{
tInfo.slice_reshaper_model_present_flag = sInfo.slice_reshaper_model_present_flag;
if (sInfo.slice_reshaper_model_present_flag)
{
tInfo.reshape_model_max_bin_idx = sInfo.reshape_model_max_bin_idx;
tInfo.reshape_model_min_bin_idx = sInfo.reshape_model_min_bin_idx;
memcpy(tInfo.reshape_model_bin_CW_delta, sInfo.reshape_model_bin_CW_delta, sizeof(int)*(PIC_CODE_CW_BINS));
tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW;
}
tInfo.slice_reshaper_enable_flag = sInfo.slice_reshaper_enable_flag;
if (sInfo.slice_reshaper_enable_flag)
tInfo.uiReshapeChromaAdj = sInfo.uiReshapeChromaAdj;
else
tInfo.uiReshapeChromaAdj = 0;
}
/** Construct reshaper from syntax
* \param void
* \return void
*/
void Reshape::constructReshaper()
{
int pwlFwdLUTsize = PIC_CODE_CW_BINS;
int pwlFwdBinLen = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS;
for (int i = 0; i < m_sliceReshapeInfo.reshape_model_min_bin_idx; i++)
m_uiBinCWAll[i] = 0;
for (int i = m_sliceReshapeInfo.reshape_model_max_bin_idx + 1; i < PIC_CODE_CW_BINS; i++)
m_uiBinCWAll[i] = 0;
for (int i = m_sliceReshapeInfo.reshape_model_min_bin_idx; i <= m_sliceReshapeInfo.reshape_model_max_bin_idx; i++)
m_uiBinCWAll[i] = (uint16_t)(m_sliceReshapeInfo.reshape_model_bin_CW_delta[i] + (int)m_uiCWOrg);
for (int i = 0; i < pwlFwdLUTsize; i++)
{
m_ReshapePivot[i + 1] = m_ReshapePivot[i] + m_uiBinCWAll[i];
int16_t Y1 = m_ReshapePivot[i];
int16_t Y2 = m_ReshapePivot[i + 1];
forwardReshapingLUT[i*pwlFwdBinLen] = Clip3((Pel)0, (Pel)1023, (Pel)Y1);
int log2_pwlFwdBinLen = log2_MAX_LUMA_RESHAPING_LUT_SIZE - log2_PIC_CODE_CW_BINS;