/* 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 EncReshape.cpp \brief encoder reshaper class */ #include "EncReshape.h" #include <stdio.h> #include <string.h> #include <math.h> #if JVET_M0427_INLOOP_RESHAPER //! \ingroup EncLib //! \{ // ==================================================================================================================== // Constructor / destructor / create / destroy // ==================================================================================================================== EncReshape::EncReshape() { m_bCTUFlag = false; m_bSrcReshaped = false; m_bRecReshaped = false; m_bReshape = true; m_bExceedSTD = false; m_tcase = 0; m_rateAdpMode = 0; m_chromaAdj = 0; } EncReshape::~EncReshape() { } void EncReshape::createEnc(int picWidth, int picHeight, uint32_t maxCUWidth, uint32_t maxCUHeight, int bitDepth) { m_lumaBD = bitDepth; m_reshapeLUTSize = 1 << m_lumaBD; m_initCWAnalyze = m_reshapeLUTSize / PIC_ANALYZE_CW_BINS; m_initCW = m_reshapeLUTSize / PIC_CODE_CW_BINS; if (forwardReshapingLUT.empty()) forwardReshapingLUT.resize(m_reshapeLUTSize, 0); if (inverseReshapingLUT.empty()) inverseReshapingLUT.resize(m_reshapeLUTSize,0); if (m_binCW.empty()) m_binCW.resize(PIC_ANALYZE_CW_BINS); if (m_uiBinImportance.empty()) m_uiBinImportance.resize(PIC_ANALYZE_CW_BINS); if (m_reshapePivot.empty()) m_reshapePivot.resize(PIC_CODE_CW_BINS + 1, 0); if (m_chromaAdjHelpLUT.empty()) m_chromaAdjHelpLUT.resize(PIC_CODE_CW_BINS, 1<<CSCALE_FP_PREC); m_sliceReshapeInfo.setUseSliceReshaper(true); m_sliceReshapeInfo.setSliceReshapeChromaAdj(true); m_sliceReshapeInfo.setSliceReshapeModelPresentFlag(true); m_sliceReshapeInfo.reshape_model_min_bin_idx = 0; m_sliceReshapeInfo.reshape_model_max_bin_idx = PIC_CODE_CW_BINS - 1; memset(m_sliceReshapeInfo.reshape_model_bin_CW_delta, 0, (PIC_CODE_CW_BINS) * sizeof(int)); m_picWidth = picWidth; m_picHeight = picHeight; m_maxCUWidth = maxCUWidth; m_maxCUHeight = maxCUHeight; m_widthInCtus = (m_picWidth + m_maxCUWidth - 1) / m_maxCUWidth; m_heightInCtus = (m_picHeight + m_maxCUHeight - 1) / m_maxCUHeight; m_numCtuInFrame = m_widthInCtus * m_heightInCtus; } void EncReshape::destroy() { } /** -Perform HDR set up \param pcPic describe pointer of current coding picture \param sliceType describe the slice type */ void EncReshape::preAnalyzerHDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isCPR) { if (m_lumaBD == 10) { m_sliceReshapeInfo.slice_reshaper_enable_flag = true; if (reshapeCW.RspIntraPeriod == 1) { if (pcPic->getPOC() == 0) { m_sliceReshapeInfo.slice_reshaper_model_present_flag = true; } else { m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; } } else { if (sliceType == I_SLICE || (sliceType==P_SLICE && isCPR) ) { m_sliceReshapeInfo.slice_reshaper_model_present_flag = true; } else { m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; } } if ((sliceType == I_SLICE || (sliceType == P_SLICE && isCPR)) && isDualT) { m_sliceReshapeInfo.uiReshapeChromaAdj = 0; } else { m_sliceReshapeInfo.uiReshapeChromaAdj = 1; } } else { m_sliceReshapeInfo.slice_reshaper_enable_flag = false; m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; } } /** -Perform picture analysis for SDR \param pcPic describe pointer of current coding picture \param sliceType describe the slice type \param reshapeCW describe some input info */ void EncReshape::preAnalyzerSDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isCPR) { m_sliceReshapeInfo.slice_reshaper_model_present_flag = true; m_sliceReshapeInfo.slice_reshaper_enable_flag = true; int modIP = pcPic->getPOC() - pcPic->getPOC() / reshapeCW.RspFpsToIp * reshapeCW.RspFpsToIp; if (sliceType == I_SLICE || (reshapeCW.RspIntraPeriod == -1 && modIP == 0) || (sliceType== P_SLICE && isCPR)) { if (m_sliceReshapeInfo.slice_reshaper_model_present_flag == true) { uint32_t uiStdMin = 16 <<(m_lumaBD-8); uint32_t uiStdMax = 235 << (m_lumaBD - 8); int binLen = m_reshapeLUTSize / PIC_ANALYZE_CW_BINS; m_reshapeCW = reshapeCW; for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) { m_uiBinImportance[b] = 0; m_binCW[b] = binLen; } int startBinIdx = int(floor((double(uiStdMin) / double(binLen)))); int endBinIdx = int(floor((double(uiStdMax) / double(binLen)))); m_sliceReshapeInfo.reshape_model_min_bin_idx = startBinIdx; m_sliceReshapeInfo.reshape_model_max_bin_idx = endBinIdx; PelBuf picY = pcPic->getOrigBuf(COMPONENT_Y); const int iWidth = picY.width; const int iHeight = picY.height; const int iStride = picY.stride; double dBlockBinVarSum[PIC_ANALYZE_CW_BINS] = { 0.0 }; uint32_t dBlockBinCnt[PIC_ANALYZE_CW_BINS] = { 0 }; const int PIC_ANALYZE_WIN_SIZE = 5; const uint32_t uiWinSize = PIC_ANALYZE_WIN_SIZE; const uint32_t uiWinLens = (uiWinSize - 1) >> 1; int64_t tempSq = 0; int64_t leftSum = 0, leftSumSq = 0; int64_t *leftColSum = new int64_t[iWidth]; int64_t *leftColSumSq = new int64_t[iWidth]; memset(leftColSum, 0, iWidth * sizeof(int64_t)); memset(leftColSumSq, 0, iWidth * sizeof(int64_t)); int64_t topSum = 0, topSumSq = 0; int64_t *topRowSum = new int64_t[iHeight]; int64_t *topRowSumSq = new int64_t[iHeight]; memset(topRowSum, 0, iHeight * sizeof(int64_t)); memset(topRowSumSq, 0, iHeight * sizeof(int64_t)); int64_t *topColSum = new int64_t[iWidth]; int64_t *topColSumSq = new int64_t[iWidth]; memset(topColSum, 0, iWidth * sizeof(int64_t)); memset(topColSumSq, 0, iWidth * sizeof(int64_t)); for (uint32_t y = 0; y < iHeight; y++) { for (uint32_t x = 0; x < iWidth; x++) { const Pel pPxlY = picY.buf[x]; int64_t uiSum = 0; int64_t uiSumSq = 0; uint32_t uiNumPixInPart = 0; uint32_t y1 = std::max((int)(y - uiWinLens), 0); uint32_t y2 = std::min((int)(y + uiWinLens), (iHeight - 1)); uint32_t x1 = std::max((int)(x - uiWinLens), 0); uint32_t x2 = std::min((int)(x + uiWinLens), (iWidth - 1)); uint32_t bx = 0, by = 0; const Pel *pWinY = &picY.buf[0]; uiNumPixInPart = (x2 - x1 + 1) * (y2 - y1 + 1); if (x == 0 && y == 0) // for the 1st Pixel, calc all points { for (by = y1; by <= y2; by++) { for (bx = x1; bx <= x2; bx++) { tempSq = pWinY[bx] * pWinY[bx]; leftSum += pWinY[bx]; leftSumSq += tempSq; leftColSum[bx] += pWinY[bx]; leftColSumSq[bx] += tempSq; topColSum[bx] += pWinY[bx]; topColSumSq[bx] += tempSq; topRowSum[by] += pWinY[bx]; topRowSumSq[by] += tempSq; } pWinY += iStride; } topSum = leftSum; topSumSq = leftSumSq; uiSum = leftSum; uiSumSq = leftSumSq; } else if (x == 0 && y > 0) // for the 1st column, calc the bottom stripe { if (y < iHeight - uiWinLens) { pWinY += uiWinLens*iStride; topRowSum[y + uiWinLens] = 0; topRowSumSq[y + uiWinLens] = 0; for (bx = x1; bx <= x2; bx++) { topRowSum[y + uiWinLens] += pWinY[bx]; topRowSumSq[y + uiWinLens] += pWinY[bx] * pWinY[bx]; } topSum += topRowSum[y + uiWinLens]; topSumSq += topRowSumSq[y + uiWinLens]; } if (y > uiWinLens) { topSum -= topRowSum[y - 1 - uiWinLens]; topSumSq -= topRowSumSq[y - 1 - uiWinLens]; } memset(leftColSum, 0, iWidth * sizeof(int64_t)); memset(leftColSumSq, 0, iWidth * sizeof(int64_t)); pWinY = &picY.buf[0]; pWinY -= (y <= uiWinLens ? y : uiWinLens)*iStride; for (by = y1; by <= y2; by++) { for (bx = x1; bx <= x2; bx++) { leftColSum[bx] += pWinY[bx]; leftColSumSq[bx] += pWinY[bx] * pWinY[bx]; } pWinY += iStride; } leftSum = topSum; leftSumSq = topSumSq; uiSum = topSum; uiSumSq = topSumSq; } else if (x > 0) { if (x < iWidth - uiWinLens) { pWinY -= (y <= uiWinLens ? y : uiWinLens)*iStride; if (y == 0) // for the 1st row, calc the right stripe { leftColSum[x + uiWinLens] = 0; leftColSumSq[x + uiWinLens] = 0; for (by = y1; by <= y2; by++) { leftColSum[x + uiWinLens] += pWinY[x + uiWinLens]; leftColSumSq[x + uiWinLens] += pWinY[x + uiWinLens] * pWinY[x + uiWinLens]; pWinY += iStride; } } else // for the main area, calc the B-R point { leftColSum[x + uiWinLens] = topColSum[x + uiWinLens]; leftColSumSq[x + uiWinLens] = topColSumSq[x + uiWinLens]; if (y < iHeight - uiWinLens) { pWinY = &picY.buf[0]; pWinY += uiWinLens * iStride; leftColSum[x + uiWinLens] += pWinY[x + uiWinLens]; leftColSumSq[x + uiWinLens] += pWinY[x + uiWinLens] * pWinY[x + uiWinLens]; } if (y > uiWinLens) { pWinY = &picY.buf[0]; pWinY -= (uiWinLens + 1) * iStride; leftColSum[x + uiWinLens] -= pWinY[x + uiWinLens]; leftColSumSq[x + uiWinLens] -= pWinY[x + uiWinLens] * pWinY[x + uiWinLens]; } } topColSum[x + uiWinLens] = leftColSum[x + uiWinLens]; topColSumSq[x + uiWinLens] = leftColSumSq[x + uiWinLens]; leftSum += leftColSum[x + uiWinLens]; leftSumSq += leftColSumSq[x + uiWinLens]; } if (x > uiWinLens) { leftSum -= leftColSum[x - 1 - uiWinLens]; leftSumSq -= leftColSumSq[x - 1 - uiWinLens]; } uiSum = leftSum; uiSumSq = leftSumSq; } double dAverage = double(uiSum) / uiNumPixInPart; double dVariance = double(uiSumSq) / uiNumPixInPart - dAverage * dAverage; if (m_lumaBD > 10) { dAverage = dAverage / (double)(1<<(m_lumaBD - 10)); dVariance = dVariance / (double)(1 << (2*m_lumaBD - 20)); } else if (m_lumaBD < 10) { dAverage = dAverage * (double)(1 << (10 - m_lumaBD)); dVariance = dVariance * (double)(1 << (20-2*m_lumaBD)); } double dVarLog10 = log10(dVariance + 1.0); uint32_t uiBinNum = (uint32_t)floor((double)pPxlY / (double)PIC_ANALYZE_CW_BINS); dBlockBinVarSum[uiBinNum] += dVarLog10; dBlockBinCnt[uiBinNum]++; } picY.buf += iStride; } delete[] topColSum; delete[] topColSumSq; delete[] topRowSum; delete[] topRowSumSq; delete[] leftColSum; delete[] leftColSumSq; for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) { if (dBlockBinCnt[b] > 0) dBlockBinVarSum[b] = dBlockBinVarSum[b] / dBlockBinCnt[b]; } m_bReshape = true; m_bExceedSTD = false; m_bUseAdpCW = false; m_chromaWeight = 1.0; m_sliceReshapeInfo.uiReshapeChromaAdj = 1; bool bIntraAdp = false; bool bInterAdp = true; double dReshapeTH1 = 0.0; double dReshapeTH2 = 5.0; deriveReshapeParametersSDRfromStats(dBlockBinCnt, dBlockBinVarSum, &dReshapeTH1, &dReshapeTH2, &bIntraAdp, &bInterAdp); if (m_rateAdpMode == 2 && reshapeCW.RspBaseQP <= 22) { bIntraAdp = false; bInterAdp = false; } m_sliceReshapeInfo.slice_reshaper_enable_flag = bIntraAdp; if (!bIntraAdp && !bInterAdp) { m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; m_bReshape = false; return; } if (m_bExceedSTD) { startBinIdx = 2; endBinIdx = 29; for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) { if (dBlockBinCnt[b] > 0 && b < startBinIdx) startBinIdx = b; if (dBlockBinCnt[b] > 0 && b > endBinIdx) endBinIdx = b; } m_sliceReshapeInfo.reshape_model_min_bin_idx = startBinIdx; m_sliceReshapeInfo.reshape_model_max_bin_idx = endBinIdx; } if (reshapeCW.RspBaseQP <= 22 && m_rateAdpMode == 1) { for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) { if (i >= startBinIdx && i <= endBinIdx) m_binCW[i] = m_initCWAnalyze + 1; else m_binCW[i] = 0; } } else if (m_bUseAdpCW) { double Alpha = 1.0, Beta = 0.0; deriveReshapeParameters(dBlockBinVarSum, startBinIdx, endBinIdx, m_reshapeCW, Alpha, Beta); for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) { if (i >= startBinIdx && i <= endBinIdx) m_binCW[i] = (uint32_t)round(Alpha*dBlockBinVarSum[i] + Beta); else m_binCW[i] = 0; } } else { for (int b = startBinIdx; b <= endBinIdx; b++) { if (dBlockBinVarSum[b] < dReshapeTH1) m_uiBinImportance[b] = 2; else if (dBlockBinVarSum[b] > dReshapeTH2) m_uiBinImportance[b] = 3; else m_uiBinImportance[b] = 1; } for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) { if (m_uiBinImportance[i] == 0) m_binCW[i] = 0; else if (m_uiBinImportance[i] == 1) m_binCW[i] = m_initCWAnalyze + 1; else if (m_uiBinImportance[i] == 2) m_binCW[i] = m_reshapeCW.BinCW[0]; else if (m_uiBinImportance[i] == 3) m_binCW[i] = m_reshapeCW.BinCW[1]; else THROW("SDR Reshape Bin Importance not supported"); } } if (m_reshapeCW.RspPicSize <= 1497600 && reshapeCW.RspIntraPeriod == -1 && modIP == 0 && sliceType != I_SLICE) { m_sliceReshapeInfo.slice_reshaper_enable_flag = false; } } m_chromaAdj = m_sliceReshapeInfo.uiReshapeChromaAdj; if ((sliceType == I_SLICE || (sliceType == P_SLICE && isCPR)) && isDualT) { m_sliceReshapeInfo.uiReshapeChromaAdj = 0; } } else // Inter slices { m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; m_sliceReshapeInfo.uiReshapeChromaAdj = m_chromaAdj; if (!m_bReshape) { m_sliceReshapeInfo.slice_reshaper_enable_flag = false; } else { const int cTid = m_reshapeCW.Tid; bool enableRsp = m_tcase == 5 ? false : (m_tcase < 5 ? (cTid < m_tcase + 1 ? false : true) : (cTid <= 10 - m_tcase ? true : false)); m_sliceReshapeInfo.slice_reshaper_enable_flag = enableRsp; } } } // Bubble Sort to descending order with index void EncReshape::bubbleSortDsd(double* array, int * idx, int n) { int i, j; bool swapped; for (i = 0; i < n - 1; i++) { swapped = false; for (j = 0; j < n - i - 1; j++) { if (array[j] < array[j + 1]) { swap(&array[j], &array[j + 1]); swap(&idx[j], &idx[j + 1]); swapped = true; } } if (swapped == false) break; } } void EncReshape::deriveReshapeParametersSDRfromStats(uint32_t * dBlockBinCnt, double *dBlockBinVarSum, double* dReshapeTH1, double* dReshapeTH2, bool *bIntraAdp, bool *bInterAdp) { int BinIdxSortDsd[PIC_ANALYZE_CW_BINS] = { 0 }; double BinVarSortDsd[PIC_ANALYZE_CW_BINS] = { 0.0 }; double BinHist[PIC_ANALYZE_CW_BINS] = { 0.0 }; double BinVarSortDsdCDF[PIC_ANALYZE_CW_BINS] = { 0.0 }; double maxBinVar = 0.0, meanBinVar = 0.0, minBinVar = 5.0; int nonZeroBinCt = 0; for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) { BinHist[b] = (double)dBlockBinCnt[b] / (double)(m_reshapeCW.RspPicSize); if (BinHist[b] > 0.001) { nonZeroBinCt++; meanBinVar += dBlockBinVarSum[b]; if (dBlockBinVarSum[b] > maxBinVar) { maxBinVar = dBlockBinVarSum[b]; } if (dBlockBinVarSum[b] < minBinVar) { minBinVar = dBlockBinVarSum[b]; } } BinVarSortDsd[b] = dBlockBinVarSum[b]; BinIdxSortDsd[b] = b; } if ((BinHist[0] + BinHist[1] + BinHist[PIC_ANALYZE_CW_BINS - 2] + BinHist[PIC_ANALYZE_CW_BINS - 1]) > 0.01) { m_bExceedSTD = true; } if ((BinHist[PIC_ANALYZE_CW_BINS - 2] + BinHist[PIC_ANALYZE_CW_BINS - 1]) > 0.01) { *bInterAdp = false; return; } else { *bInterAdp = true; } meanBinVar = meanBinVar / (double)nonZeroBinCt; bubbleSortDsd(BinVarSortDsd, BinIdxSortDsd, PIC_ANALYZE_CW_BINS); BinVarSortDsdCDF[0] = BinHist[BinIdxSortDsd[0]]; for (int b = 1; b < PIC_ANALYZE_CW_BINS; b++) { BinVarSortDsdCDF[b] = BinVarSortDsdCDF[b - 1] + BinHist[BinIdxSortDsd[b]]; } int firstBinVarLessThanVal1 = 0; // Val1 = 3.5 int firstBinVarLessThanVal2 = 0; // Val2 = 3.0 int firstBinVarLessThanVal3 = 0; // Val3 = 2.5 int firstBinVarLessThanVal4 = 0; // Val4 = 2.0 for (int b = 0; b < PIC_ANALYZE_CW_BINS - 1; b++) { if (BinVarSortDsd[b] > 3.5) { firstBinVarLessThanVal1 = b + 1; } if (BinVarSortDsd[b] > 3.0) { firstBinVarLessThanVal2 = b + 1; } if (BinVarSortDsd[b] > 2.5) { firstBinVarLessThanVal3 = b + 1; } if (BinVarSortDsd[b] > 2.0) { firstBinVarLessThanVal4 = b + 1; } } m_reshapeCW.BinCW[0] = 38; m_reshapeCW.BinCW[1] = 28; if (m_reshapeCW.RspIntraPeriod == -1) { *bIntraAdp = true; if (m_reshapeCW.RspPicSize > 1497600) { m_reshapeCW.BinCW[0] = 36; *dReshapeTH1 = 2.4; *dReshapeTH2 = 4.5; m_rateAdpMode = 2; if (meanBinVar >= 2.52) { if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) { *dReshapeTH1 = 2.5; *dReshapeTH2 = 3.0; } else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) { *dReshapeTH1 = 2.2; } else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) { m_reshapeCW.BinCW[1] = 30; *dReshapeTH1 = 2.0; m_rateAdpMode = 0; } else { m_reshapeCW.BinCW[1] = 30; m_rateAdpMode = 1; } } } else if (m_reshapeCW.RspPicSize > 660480) { m_reshapeCW.BinCW[0] = 34; *dReshapeTH1 = 3.4; *dReshapeTH2 = 4.0; m_rateAdpMode = 2; if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) { if (maxBinVar < 3.5) { m_bUseAdpCW = true; m_reshapeCW.BinCW[0] = 38; } else { m_reshapeCW.BinCW[0] = 40; *dReshapeTH1 = 2.2; *dReshapeTH2 = 4.5; m_rateAdpMode = 0; } } else { if (maxBinVar > 3.3) { m_reshapeCW.BinCW[1] = 30; } else { m_reshapeCW.BinCW[1] = 28; } } } else if (m_reshapeCW.RspPicSize > 249600) { m_reshapeCW.BinCW[0] = 36; *dReshapeTH1 = 2.5; *dReshapeTH2 = 4.5; if (m_bExceedSTD) { m_reshapeCW.BinCW[0] = 36; m_reshapeCW.BinCW[1] = 30; } if (minBinVar > 2.6) { *dReshapeTH1 = 3.0; } else { double diff1 = BinVarSortDsdCDF[firstBinVarLessThanVal4] - BinVarSortDsdCDF[firstBinVarLessThanVal3]; double diff2 = BinVarSortDsdCDF[firstBinVarLessThanVal2] - BinVarSortDsdCDF[firstBinVarLessThanVal1]; if (diff1 > 0.4 || BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.1) { m_bUseAdpCW = true; m_rateAdpMode = 1; } else if (diff2 <= 0.1 && BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.99 && BinVarSortDsdCDF[firstBinVarLessThanVal3] > 0.642 && BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.03) { m_bUseAdpCW = true; m_rateAdpMode = 1; } else { m_rateAdpMode = 2; } } } else { m_reshapeCW.BinCW[0] = 36; *dReshapeTH1 = 2.6; *dReshapeTH2 = 4.5; if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5 && maxBinVar < 4.7) { *dReshapeTH1 = 3.2; m_rateAdpMode = 1; } } } else if (m_reshapeCW.RspIntraPeriod == 1) { *bIntraAdp = true; if (m_reshapeCW.RspPicSize > 5184000) { *dReshapeTH1 = 2.0; *dReshapeTH2 = 3.0; m_rateAdpMode = 2; if (maxBinVar > 2.4) { if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.88) { if (maxBinVar < 2.695) { *dReshapeTH2 = 2.2; } else { if (BinVarSortDsdCDF[firstBinVarLessThanVal3] < 0.45) { *dReshapeTH1 = 2.5; *dReshapeTH2 = 4.0; m_reshapeCW.BinCW[0] = 36; m_sliceReshapeInfo.uiReshapeChromaAdj = 0; m_rateAdpMode = 0; } else { m_bUseAdpCW = true; m_reshapeCW.BinCW[0] = 36; m_reshapeCW.BinCW[1] = 30; } } } else { if (maxBinVar > 2.8) { *dReshapeTH1 = 2.2; *dReshapeTH2 = 4.0; m_reshapeCW.BinCW[0] = 36; m_sliceReshapeInfo.uiReshapeChromaAdj = 0; } else { m_bUseAdpCW = true; m_reshapeCW.BinCW[0] = 38; m_reshapeCW.BinCW[1] = 28; } } } else { if (maxBinVar > 2.24) { m_bUseAdpCW = true; m_reshapeCW.BinCW[0] = 34; m_reshapeCW.BinCW[1] = 30; } } } else if (m_reshapeCW.RspPicSize > 1497600) { *dReshapeTH1 = 2.0; *dReshapeTH2 = 4.5; m_rateAdpMode = 2; if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) { int firstVarCDFLargerThanVal = 1; for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) { if (BinVarSortDsdCDF[b] > 0.7) { firstVarCDFLargerThanVal = b; break; } } if (meanBinVar < 2.52 || BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) { *dReshapeTH1 = 2.2; *dReshapeTH2 = (BinVarSortDsd[firstVarCDFLargerThanVal] + BinVarSortDsd[firstVarCDFLargerThanVal - 1]) / 2.0; } else { m_reshapeCW.BinCW[1] = 30; *dReshapeTH2 = 2.8; } } else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) { m_reshapeCW.BinCW[0] = 36; *dReshapeTH1 = 3.5; m_rateAdpMode = 1; } } else if (m_reshapeCW.RspPicSize > 660480) { *dReshapeTH1 = 2.5; *dReshapeTH2 = 4.5; m_rateAdpMode = 1; if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) { if (maxBinVar < 3.5) { *dReshapeTH1 = 2.0; } } else { if (maxBinVar > 3.3) { m_reshapeCW.BinCW[0] = 35; } else { *dReshapeTH1 = 2.8; m_reshapeCW.BinCW[0] = 35; } } } else if (m_reshapeCW.RspPicSize > 249600) { m_rateAdpMode = 1; m_reshapeCW.BinCW[0] = 36; *dReshapeTH1 = 2.5; *dReshapeTH2 = 4.5; } else { if (BinVarSortDsdCDF[firstBinVarLessThanVal2] < 0.33 && m_reshapeCW.RspFps>40) { *bIntraAdp = false; *bInterAdp = false; } else { m_rateAdpMode = 1; m_reshapeCW.BinCW[0] = 36; *dReshapeTH1 = 3.0; *dReshapeTH2 = 4.0; } } } else { if (m_reshapeCW.RspPicSize > 5184000) { m_reshapeCW.BinCW[0] = 40; *dReshapeTH2 = 4.0; m_rateAdpMode = 2; if (maxBinVar < 2.4) { *dReshapeTH1 = 3.0; if (m_reshapeCW.RspBaseQP <= 22) m_tcase = 3; } else if (maxBinVar > 3.0) { if (minBinVar > 1) { m_reshapeCW.BinCW[0] = 36; *dReshapeTH1 = 2.8; *dReshapeTH2 = 3.5; m_sliceReshapeInfo.uiReshapeChromaAdj = 0; m_chromaWeight = 1.05; m_rateAdpMode = 0; } else { m_reshapeCW.BinCW[0] = 36; *dReshapeTH1 = 2.2; *dReshapeTH2 = 3.5; m_sliceReshapeInfo.uiReshapeChromaAdj = 0; m_chromaWeight = 0.95; if (m_reshapeCW.RspBaseQP <= 27 && m_reshapeCW.RspBaseQP >=25) m_tcase = 3; } } else { *dReshapeTH1 = 1.5; } } else if (m_reshapeCW.RspPicSize > 1497600) { *dReshapeTH1 = 2.5; *dReshapeTH2 = 4.5; m_rateAdpMode = 1; if (meanBinVar < 2.52) { *bIntraAdp = true; m_rateAdpMode = 0; m_tcase = 9; } else { if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) { *dReshapeTH2 = 3.0; *bIntraAdp = true; } else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) { *dReshapeTH1 = 3.0; *bIntraAdp = true; m_rateAdpMode = 0; m_tcase = 9; } else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) { *dReshapeTH1 = 2.4; m_reshapeCW.BinCW[0] = 36; } else { *dReshapeTH1 = 2.4; m_reshapeCW.BinCW[0] = 36; } } } else if (m_reshapeCW.RspPicSize > 660480) { *bIntraAdp = true; m_rateAdpMode = 1; if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) { if (maxBinVar < 3.5) { *dReshapeTH1 = 2.1; *dReshapeTH2 = 3.5; } else { *dReshapeTH1 = 2.4; *dReshapeTH2 = 4.5; m_reshapeCW.BinCW[0] = 40; m_rateAdpMode = 0; } } else { if (maxBinVar > 3.3) { *dReshapeTH1 = 3.5; *dReshapeTH2 = 3.8; } else { *dReshapeTH1 = 3.0; *dReshapeTH2 = 4.0; m_reshapeCW.BinCW[1] = 30; } } } else if (m_reshapeCW.RspPicSize > 249600) { m_reshapeCW.BinCW[1] = 30; *dReshapeTH1 = 2.5; *dReshapeTH2 = 4.5; *bIntraAdp = true; m_rateAdpMode = 1; if (minBinVar > 2.6) { *dReshapeTH1 = 3.2; m_rateAdpMode = 0; m_tcase = 9; } else { double diff1 = BinVarSortDsdCDF[firstBinVarLessThanVal4] - BinVarSortDsdCDF[firstBinVarLessThanVal3]; double diff2 = BinVarSortDsdCDF[firstBinVarLessThanVal2] - BinVarSortDsdCDF[firstBinVarLessThanVal1]; if (diff1 > 0.4 || BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.1) { *dReshapeTH1 = 2.9; *bIntraAdp = false; } else { if (diff2 > 0.1) { *dReshapeTH1 = 2.5; } else { *dReshapeTH1 = 2.9; if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.99 && BinVarSortDsdCDF[firstBinVarLessThanVal3] > 0.642 && BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.03) { m_rateAdpMode = 0; m_tcase = 9; } } } } } else { m_reshapeCW.BinCW[0] = 36; m_reshapeCW.BinCW[1] = 30; *dReshapeTH1 = 2.6; *dReshapeTH2 = 4.5; *bIntraAdp = true; m_rateAdpMode = 1; if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5 && maxBinVar < 4.7) { *dReshapeTH1 = 3.4; } } } } void EncReshape::deriveReshapeParameters(double *array, int start, int end, ReshapeCW respCW, double &alpha, double &beta) { double minVar = 10.0, maxVar = 0.0; for (int b = start; b <= end; b++) { if (array[b] < minVar) minVar = array[b]; if (array[b] > maxVar) maxVar = array[b]; } double maxCW = (double)respCW.BinCW[0]; double minCW = (double)respCW.BinCW[1]; alpha = (minCW - maxCW) / (maxVar - minVar); beta = (maxCW*maxVar - minCW*minVar) / (maxVar - minVar); } /** -Init reshaping LUT from dQP model */ void EncReshape::initLUTfromdQPModel() { initModelParam(); int pwlFwdLUTsize = PIC_CODE_CW_BINS; int pwlFwdBinLen = m_reshapeLUTSize / PIC_CODE_CW_BINS; int p1 = m_dQPModel.ScaleFracPrec; //=16, precision of 0.015 int p2 = m_dQPModel.OffsetFracPrec; //=1, precision of 7.5 int total_shift = p1 + p2; int scaleFP = (1 - 2 * m_dQPModel.ScaleSign) * m_dQPModel.ScaleAbs; int offsetFP = (1 - 2 * m_dQPModel.OffsetSign) * m_dQPModel.OffsetAbs; int maxQP = (1 - 2 * m_dQPModel.MaxQPSign) * m_dQPModel.MaxQPAbs; int minQP = (1 - 2 * m_dQPModel.MinQPSign) * m_dQPModel.MinQPAbs; int maxFP = maxQP * (1 << total_shift); int minFP = minQP * (1 << total_shift); int temp, signval, absval; int dQPDIV6_FP; int32_t * SlopeLUT = new int32_t[m_reshapeLUTSize](); int32_t * fLUT_HP = new int32_t[m_reshapeLUTSize](); for (int i = 0; i < m_reshapeLUTSize; i++) { int inputY = m_lumaBD < 10 ? i << (10 - m_lumaBD) : m_lumaBD > 10 ? i >> (m_lumaBD - 10) : i; temp = int64_t((scaleFP*inputY) * (1 << p2)) + int64_t(offsetFP * (1 << p1)); temp = temp > maxFP ? maxFP : temp < minFP ? minFP : temp; signval = temp >= 0 ? 1 : -1; absval = signval * temp; dQPDIV6_FP = signval * (((absval + 3) / 6 + (1 << (total_shift - 17))) >> (total_shift - 16)); SlopeLUT[i] = calcEXP2(dQPDIV6_FP); } if (m_dQPModel.FullRangeInputFlag == 0) { for (int i = 0; i < (16 << (m_lumaBD - 8)); i++) { SlopeLUT[i] = 0; } for (int i = (235 << (m_lumaBD - 8)); i < m_reshapeLUTSize; i++) { SlopeLUT[i] = 0; } } for (int i = 0; i < m_reshapeLUTSize - 1; i++) fLUT_HP[i + 1] = fLUT_HP[i] + SlopeLUT[i]; if (SlopeLUT != nullptr) { delete[] SlopeLUT; SlopeLUT = nullptr; } int max_Y = (fLUT_HP[m_reshapeLUTSize - 1] + (1 << 7)) >> 8; int Roffset = max_Y >> 1; for (int i = 0; i < m_reshapeLUTSize; i++) { forwardReshapingLUT[i] = (short)(((fLUT_HP[i] >> 8) * (m_reshapeLUTSize - 1) + Roffset) / max_Y); } if (fLUT_HP != nullptr) { delete[] fLUT_HP; fLUT_HP = nullptr; } m_sliceReshapeInfo.reshape_model_min_bin_idx = 1; m_sliceReshapeInfo.reshape_model_max_bin_idx = 14; for (int i = 0; i < pwlFwdLUTsize; i++) { int16_t X1 = i * pwlFwdBinLen; m_reshapePivot[i] = forwardReshapingLUT[X1]; } m_reshapePivot[pwlFwdLUTsize] = ((1 << m_lumaBD) - 1); for (int i = 0; i < pwlFwdLUTsize; i++) { m_binCW[i] = m_reshapePivot[i + 1] - m_reshapePivot[i]; } int maxAbsDeltaCW = 0, AbsDeltaCW = 0, DeltaCW = 0; for (int i = m_sliceReshapeInfo.reshape_model_min_bin_idx; i <= m_sliceReshapeInfo.reshape_model_max_bin_idx; i++) { DeltaCW = (int)m_binCW[i] - (int)m_initCW; m_sliceReshapeInfo.reshape_model_bin_CW_delta[i] = DeltaCW; AbsDeltaCW = (DeltaCW < 0) ? (-DeltaCW) : DeltaCW; if (AbsDeltaCW > maxAbsDeltaCW) { maxAbsDeltaCW = AbsDeltaCW; } } m_sliceReshapeInfo.maxNbitsNeededDeltaCW = g_aucLog2[maxAbsDeltaCW << 1]; for (int i = 0; i < pwlFwdLUTsize; i++) { int16_t Y1 = m_reshapePivot[i]; int16_t Y2 = m_reshapePivot[i + 1]; forwardReshapingLUT[i*pwlFwdBinLen] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)Y1); int log2_pwlFwdBinLen = g_aucLog2[pwlFwdBinLen]; int32_t scale = ((int32_t)(Y2 - Y1) * (1 << FP_PREC) + (1 << (log2_pwlFwdBinLen - 1))) >> (log2_pwlFwdBinLen); for (int j = 1; j < pwlFwdBinLen; j++) { int tempVal = Y1 + (((int32_t)scale * (int32_t)j + (1 << (FP_PREC - 1))) >> FP_PREC); forwardReshapingLUT[i*pwlFwdBinLen + j] = Clip3((Pel)0, (Pel)((1<<m_lumaBD) -1), (Pel)tempVal); } } reverseLUT(forwardReshapingLUT, inverseReshapingLUT, m_reshapeLUTSize); updateChromaDQPLUT(); } /** -Perform fixe point exp2 calculation \param val input value \retval output value = exp2(val) */ int EncReshape::calcEXP2(int val) { int32_t i, f, r, s; r = 0x00000e20; i = ((int32_t)(val)+0x8000) & ~0xffff; f = (int32_t)(val)-i; s = ((15 << 16) - i) >> 16; r = (r * f + 0x3e1cc333) >> 17; r = (r * f + 0x58bd46a6) >> 16; r = r * f + 0x7ffde4a3; return (uint32_t)r >> s; } void EncReshape::constructReshaperSDR() { int used_codewords; int tot_cw = m_reshapeLUTSize; int hist_bins = PIC_ANALYZE_CW_BINS; int hist_lens = m_initCWAnalyze; int log2_hist_lens = g_aucLog2[hist_lens]; int16_t *Y_LUT_all = new int16_t[m_reshapeLUTSize + 1](); int i, j; int cw_scale_bins1, cw_scale_bins2; int max_allow_cw = tot_cw; cw_scale_bins1 = m_reshapeCW.BinCW[0]; cw_scale_bins2 = m_reshapeCW.BinCW[1]; used_codewords = 0; for (i = 0; i < hist_bins; i++) used_codewords += m_binCW[i]; if (used_codewords > max_allow_cw) { int cnt0 = 0, cnt1 = 0, cnt2 = 0; for (i = 0; i < hist_bins; i++) { if (m_binCW[i] == hist_lens + 1) cnt0++; else if (m_binCW[i] == cw_scale_bins1) cnt1++; else if (m_binCW[i] == cw_scale_bins2) cnt2++; } int delta_cw = used_codewords - max_allow_cw; int cw_reduce1 = (cw_scale_bins1 - hist_lens - 1) * cnt1; int cw_reduce2 = (hist_lens + 1 - cw_scale_bins2) * cnt0; if (delta_cw <= cw_reduce1) { int idx = 0; while (delta_cw > 0) { if (m_binCW[idx] > (hist_lens + 1)) { m_binCW[idx]--; delta_cw--; } idx++; if (idx == hist_bins) idx = 0; } } else if (delta_cw > cw_reduce1 && delta_cw <= (cw_reduce1 + cw_reduce2)) { delta_cw -= cw_reduce1; int idx = 0; while (delta_cw > 0) { if (m_binCW[idx] > cw_scale_bins2 && m_binCW[idx] < cw_scale_bins1) { m_binCW[idx]--; delta_cw--; } idx++; if (idx == hist_bins) idx = 0; } for (i = 0; i < hist_bins; i++) { if (m_binCW[i] == cw_scale_bins1) m_binCW[i] = hist_lens + 1; } } else if (delta_cw > (cw_reduce1 + cw_reduce2)) { delta_cw -= (cw_reduce1 + cw_reduce2); int idx = 0; while (delta_cw > 0) { if (m_binCW[idx] > 0 && m_binCW[idx] < (hist_lens + 1)) { m_binCW[idx]--; delta_cw--; } idx++; if (idx == hist_bins) idx = 0; } for (i = 0; i < hist_bins; i++) { if (m_binCW[i] == m_initCWAnalyze + 1) m_binCW[i] = cw_scale_bins2; if (m_binCW[i] == cw_scale_bins1) m_binCW[i] = m_initCWAnalyze + 1; } } } for (int i = 0; i < PIC_CODE_CW_BINS; i++) { m_binCW[i] = m_binCW[2 * i] + m_binCW[2 * i + 1]; } m_sliceReshapeInfo.reshape_model_min_bin_idx = 0; m_sliceReshapeInfo.reshape_model_max_bin_idx = PIC_CODE_CW_BINS - 1; for (int i = 0; i < PIC_CODE_CW_BINS; i++) { if (m_binCW[i] > 0) { m_sliceReshapeInfo.reshape_model_min_bin_idx = i; break; } } for (int i = PIC_CODE_CW_BINS - 1; i >= 0; i--) { if (m_binCW[i] > 0) { m_sliceReshapeInfo.reshape_model_max_bin_idx = i; break; } } int maxAbsDeltaCW = 0, AbsDeltaCW = 0, DeltaCW = 0; for (int i = m_sliceReshapeInfo.reshape_model_min_bin_idx; i <= m_sliceReshapeInfo.reshape_model_max_bin_idx; i++) { DeltaCW = (int)m_binCW[i] - (int)m_initCW; m_sliceReshapeInfo.reshape_model_bin_CW_delta[i] = DeltaCW; AbsDeltaCW = (DeltaCW < 0) ? (-DeltaCW) : DeltaCW; if (AbsDeltaCW > maxAbsDeltaCW) { maxAbsDeltaCW = AbsDeltaCW; } } m_sliceReshapeInfo.maxNbitsNeededDeltaCW = g_aucLog2[maxAbsDeltaCW << 1]; hist_bins = PIC_CODE_CW_BINS; hist_lens = m_initCW; log2_hist_lens = g_aucLog2[hist_lens]; int sum_bins = 0; for (i = 0; i < hist_bins; i++) { sum_bins += m_binCW[i]; } CHECK(sum_bins > max_allow_cw, "SDR CW assignment is wrong!!"); memset(Y_LUT_all, 0, (m_reshapeLUTSize + 1) * sizeof(int16_t)); Y_LUT_all[0] = 0; for (i = 0; i < hist_bins; i++) { Y_LUT_all[(i + 1)*hist_lens] = Y_LUT_all[i*hist_lens] + m_binCW[i]; int16_t Y1 = Y_LUT_all[i*hist_lens]; int16_t Y2 = Y_LUT_all[(i + 1)*hist_lens]; m_reshapePivot[i + 1] = Y2; int32_t scale = ((int32_t)(Y2 - Y1) * (1 << FP_PREC) + (1 << (log2_hist_lens - 1))) >> (log2_hist_lens); forwardReshapingLUT[i*hist_lens] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)Y1); for (j = 1; j < hist_lens; j++) { Y_LUT_all[i*hist_lens + j] = Y1 + (((int32_t)scale * (int32_t)j + (1 << (FP_PREC - 1))) >> FP_PREC); forwardReshapingLUT[i*hist_lens + j] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)Y_LUT_all[i*hist_lens + j]); } } for (i = 0; i < PIC_CODE_CW_BINS; i++) { int i_start = i*hist_lens; int i_end = (i + 1)*hist_lens - 1; m_cwLumaWeight[i] = forwardReshapingLUT[i_end] - forwardReshapingLUT[i_start]; } if (Y_LUT_all != nullptr) { delete[] Y_LUT_all; Y_LUT_all = nullptr; } reverseLUT(forwardReshapingLUT, inverseReshapingLUT, m_reshapeLUTSize); updateChromaDQPLUT(); } #endif // //! \}