forked from mirror/libbpg
3333 lines
122 KiB
C++
3333 lines
122 KiB
C++
/* 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-2014, 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 TComTrQuant.cpp
|
|
\brief transform and quantization class
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <limits>
|
|
#include <memory.h>
|
|
#include "TComTrQuant.h"
|
|
#include "TComPic.h"
|
|
#include "ContextTables.h"
|
|
#include "TComTU.h"
|
|
#include "Debug.h"
|
|
|
|
typedef struct
|
|
{
|
|
Int iNNZbeforePos0;
|
|
Double d64CodedLevelandDist; // distortion and level cost only
|
|
Double d64UncodedDist; // all zero coded block distortion
|
|
Double d64SigCost;
|
|
Double d64SigCost_0;
|
|
} coeffGroupRDStats;
|
|
|
|
//! \ingroup TLibCommon
|
|
//! \{
|
|
|
|
// ====================================================================================================================
|
|
// Constants
|
|
// ====================================================================================================================
|
|
|
|
#define RDOQ_CHROMA 1 ///< use of RDOQ in chroma
|
|
|
|
|
|
// ====================================================================================================================
|
|
// QpParam constructor
|
|
// ====================================================================================================================
|
|
|
|
QpParam::QpParam(const Int qpy,
|
|
const ChannelType chType,
|
|
const Int qpBdOffset,
|
|
const Int chromaQPOffset,
|
|
const ChromaFormat chFmt )
|
|
{
|
|
Int baseQp;
|
|
|
|
if(isLuma(chType))
|
|
{
|
|
baseQp = qpy + qpBdOffset;
|
|
}
|
|
else
|
|
{
|
|
baseQp = Clip3( -qpBdOffset, (chromaQPMappingTableSize - 1), qpy + chromaQPOffset );
|
|
|
|
if(baseQp < 0)
|
|
{
|
|
baseQp = baseQp + qpBdOffset;
|
|
}
|
|
else
|
|
{
|
|
baseQp = getScaledChromaQP(baseQp, chFmt) + qpBdOffset;
|
|
}
|
|
}
|
|
|
|
Qp =baseQp;
|
|
per=baseQp/6;
|
|
rem=baseQp%6;
|
|
}
|
|
|
|
QpParam::QpParam(const TComDataCU &cu, const ComponentID compID)
|
|
{
|
|
Int chromaQpOffset = 0;
|
|
|
|
if (isChroma(compID))
|
|
{
|
|
chromaQpOffset += cu.getSlice()->getPPS()->getQpOffset(compID);
|
|
chromaQpOffset += cu.getSlice()->getSliceChromaQpDelta(compID);
|
|
|
|
chromaQpOffset += cu.getSlice()->getPPS()->getChromaQpAdjTableAt(cu.getChromaQpAdj(0)).u.offset[Int(compID)-1];
|
|
}
|
|
|
|
*this = QpParam(cu.getQP( 0 ),
|
|
toChannelType(compID),
|
|
cu.getSlice()->getSPS()->getQpBDOffset(toChannelType(compID)),
|
|
chromaQpOffset,
|
|
cu.getPic()->getChromaFormat());
|
|
}
|
|
|
|
|
|
// ====================================================================================================================
|
|
// TComTrQuant class member functions
|
|
// ====================================================================================================================
|
|
|
|
TComTrQuant::TComTrQuant()
|
|
{
|
|
// allocate temporary buffers
|
|
m_plTempCoeff = new TCoeff[ MAX_CU_SIZE*MAX_CU_SIZE ];
|
|
|
|
// allocate bit estimation class (for RDOQ)
|
|
m_pcEstBitsSbac = new estBitsSbacStruct;
|
|
initScalingList();
|
|
}
|
|
|
|
TComTrQuant::~TComTrQuant()
|
|
{
|
|
// delete temporary buffers
|
|
if ( m_plTempCoeff )
|
|
{
|
|
delete [] m_plTempCoeff;
|
|
m_plTempCoeff = NULL;
|
|
}
|
|
|
|
// delete bit estimation class
|
|
if ( m_pcEstBitsSbac )
|
|
{
|
|
delete m_pcEstBitsSbac;
|
|
}
|
|
destroyScalingList();
|
|
}
|
|
|
|
#if ADAPTIVE_QP_SELECTION
|
|
Void TComTrQuant::storeSliceQpNext(TComSlice* pcSlice)
|
|
{
|
|
// NOTE: does this work with negative QPs or when some blocks are transquant-bypass enabled?
|
|
|
|
Int qpBase = pcSlice->getSliceQpBase();
|
|
Int sliceQpused = pcSlice->getSliceQp();
|
|
Int sliceQpnext;
|
|
Double alpha = qpBase < 17 ? 0.5 : 1;
|
|
|
|
Int cnt=0;
|
|
for(Int u=1; u<=LEVEL_RANGE; u++)
|
|
{
|
|
cnt += m_sliceNsamples[u] ;
|
|
}
|
|
|
|
if( !m_useRDOQ )
|
|
{
|
|
sliceQpused = qpBase;
|
|
alpha = 0.5;
|
|
}
|
|
|
|
if( cnt > 120 )
|
|
{
|
|
Double sum = 0;
|
|
Int k = 0;
|
|
for(Int u=1; u<LEVEL_RANGE; u++)
|
|
{
|
|
sum += u*m_sliceSumC[u];
|
|
k += u*u*m_sliceNsamples[u];
|
|
}
|
|
|
|
Int v;
|
|
Double q[MAX_QP+1] ;
|
|
for(v=0; v<=MAX_QP; v++)
|
|
{
|
|
q[v] = (Double)(g_invQuantScales[v%6] * (1<<(v/6)))/64 ;
|
|
}
|
|
|
|
Double qnext = sum/k * q[sliceQpused] / (1<<ARL_C_PRECISION);
|
|
|
|
for(v=0; v<MAX_QP; v++)
|
|
{
|
|
if(qnext < alpha * q[v] + (1 - alpha) * q[v+1] )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
sliceQpnext = Clip3(sliceQpused - 3, sliceQpused + 3, v);
|
|
}
|
|
else
|
|
{
|
|
sliceQpnext = sliceQpused;
|
|
}
|
|
|
|
m_qpDelta[qpBase] = sliceQpnext - qpBase;
|
|
}
|
|
|
|
Void TComTrQuant::initSliceQpDelta()
|
|
{
|
|
for(Int qp=0; qp<=MAX_QP; qp++)
|
|
{
|
|
m_qpDelta[qp] = qp < 17 ? 0 : 1;
|
|
}
|
|
}
|
|
|
|
Void TComTrQuant::clearSliceARLCnt()
|
|
{
|
|
memset(m_sliceSumC, 0, sizeof(Double)*(LEVEL_RANGE+1));
|
|
memset(m_sliceNsamples, 0, sizeof(Int)*(LEVEL_RANGE+1));
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#if MATRIX_MULT
|
|
/** NxN forward transform (2D) using brute force matrix multiplication (3 nested loops)
|
|
* \param block pointer to input data (residual)
|
|
* \param coeff pointer to output data (transform coefficients)
|
|
* \param uiStride stride of input data
|
|
* \param uiTrSize transform size (uiTrSize x uiTrSize)
|
|
* \param uiMode is Intra Prediction mode used in Mode-Dependent DCT/DST only
|
|
*/
|
|
Void xTr(Int bitDepth, Pel *block, TCoeff *coeff, UInt uiStride, UInt uiTrSize, Bool useDST, const Int maxTrDynamicRange)
|
|
{
|
|
UInt i,j,k;
|
|
TCoeff iSum;
|
|
TCoeff tmp[MAX_TU_SIZE * MAX_TU_SIZE];
|
|
const TMatrixCoeff *iT;
|
|
UInt uiLog2TrSize = g_aucConvertToBit[ uiTrSize ] + 2;
|
|
|
|
if (uiTrSize==4)
|
|
{
|
|
iT = (useDST ? g_as_DST_MAT_4[TRANSFORM_FORWARD][0] : g_aiT4[TRANSFORM_FORWARD][0]);
|
|
}
|
|
else if (uiTrSize==8)
|
|
{
|
|
iT = g_aiT8[TRANSFORM_FORWARD][0];
|
|
}
|
|
else if (uiTrSize==16)
|
|
{
|
|
iT = g_aiT16[TRANSFORM_FORWARD][0];
|
|
}
|
|
else if (uiTrSize==32)
|
|
{
|
|
iT = g_aiT32[TRANSFORM_FORWARD][0];
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
static const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_FORWARD];
|
|
|
|
const Int shift_1st = (uiLog2TrSize + bitDepth + TRANSFORM_MATRIX_SHIFT) - maxTrDynamicRange;
|
|
const Int shift_2nd = uiLog2TrSize + TRANSFORM_MATRIX_SHIFT;
|
|
const Int add_1st = (shift_1st>0) ? (1<<(shift_1st-1)) : 0;
|
|
const Int add_2nd = 1<<(shift_2nd-1);
|
|
|
|
/* Horizontal transform */
|
|
|
|
for (i=0; i<uiTrSize; i++)
|
|
{
|
|
for (j=0; j<uiTrSize; j++)
|
|
{
|
|
iSum = 0;
|
|
for (k=0; k<uiTrSize; k++)
|
|
{
|
|
iSum += iT[i*uiTrSize+k]*block[j*uiStride+k];
|
|
}
|
|
tmp[i*uiTrSize+j] = (iSum + add_1st)>>shift_1st;
|
|
}
|
|
}
|
|
|
|
/* Vertical transform */
|
|
for (i=0; i<uiTrSize; i++)
|
|
{
|
|
for (j=0; j<uiTrSize; j++)
|
|
{
|
|
iSum = 0;
|
|
for (k=0; k<uiTrSize; k++)
|
|
{
|
|
iSum += iT[i*uiTrSize+k]*tmp[j*uiTrSize+k];
|
|
}
|
|
coeff[i*uiTrSize+j] = (iSum + add_2nd)>>shift_2nd;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** NxN inverse transform (2D) using brute force matrix multiplication (3 nested loops)
|
|
* \param coeff pointer to input data (transform coefficients)
|
|
* \param block pointer to output data (residual)
|
|
* \param uiStride stride of output data
|
|
* \param uiTrSize transform size (uiTrSize x uiTrSize)
|
|
* \param uiMode is Intra Prediction mode used in Mode-Dependent DCT/DST only
|
|
*/
|
|
Void xITr(Int bitDepth, TCoeff *coeff, Pel *block, UInt uiStride, UInt uiTrSize, Bool useDST, const Int maxTrDynamicRange)
|
|
{
|
|
UInt i,j,k;
|
|
TCoeff iSum;
|
|
TCoeff tmp[MAX_TU_SIZE * MAX_TU_SIZE];
|
|
const TMatrixCoeff *iT;
|
|
|
|
if (uiTrSize==4)
|
|
{
|
|
iT = (useDST ? g_as_DST_MAT_4[TRANSFORM_INVERSE][0] : g_aiT4[TRANSFORM_INVERSE][0]);
|
|
}
|
|
else if (uiTrSize==8)
|
|
{
|
|
iT = g_aiT8[TRANSFORM_INVERSE][0];
|
|
}
|
|
else if (uiTrSize==16)
|
|
{
|
|
iT = g_aiT16[TRANSFORM_INVERSE][0];
|
|
}
|
|
else if (uiTrSize==32)
|
|
{
|
|
iT = g_aiT32[TRANSFORM_INVERSE][0];
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
static const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_INVERSE];
|
|
|
|
const Int shift_1st = TRANSFORM_MATRIX_SHIFT + 1; //1 has been added to shift_1st at the expense of shift_2nd
|
|
const Int shift_2nd = (TRANSFORM_MATRIX_SHIFT + maxTrDynamicRange - 1) - bitDepth;
|
|
const TCoeff clipMinimum = -(1 << maxTrDynamicRange);
|
|
const TCoeff clipMaximum = (1 << maxTrDynamicRange) - 1;
|
|
assert(shift_2nd>=0);
|
|
const Int add_1st = 1<<(shift_1st-1);
|
|
const Int add_2nd = (shift_2nd>0) ? (1<<(shift_2nd-1)) : 0;
|
|
|
|
/* Horizontal transform */
|
|
for (i=0; i<uiTrSize; i++)
|
|
{
|
|
for (j=0; j<uiTrSize; j++)
|
|
{
|
|
iSum = 0;
|
|
for (k=0; k<uiTrSize; k++)
|
|
{
|
|
iSum += iT[k*uiTrSize+i]*coeff[k*uiTrSize+j];
|
|
}
|
|
|
|
// Clipping here is not in the standard, but is used to protect the "Pel" data type into which the inverse-transformed samples will be copied
|
|
tmp[i*uiTrSize+j] = Clip3<TCoeff>(clipMinimum, clipMaximum, (iSum + add_1st)>>shift_1st);
|
|
}
|
|
}
|
|
|
|
/* Vertical transform */
|
|
for (i=0; i<uiTrSize; i++)
|
|
{
|
|
for (j=0; j<uiTrSize; j++)
|
|
{
|
|
iSum = 0;
|
|
for (k=0; k<uiTrSize; k++)
|
|
{
|
|
iSum += iT[k*uiTrSize+j]*tmp[i*uiTrSize+k];
|
|
}
|
|
|
|
block[i*uiStride+j] = Clip3<TCoeff>(std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max(), (iSum + add_2nd)>>shift_2nd);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif //MATRIX_MULT
|
|
|
|
|
|
/** 4x4 forward transform implemented using partial butterfly structure (1D)
|
|
* \param src input data (residual)
|
|
* \param dst output data (transform coefficients)
|
|
* \param shift specifies right shift after 1D transform
|
|
*/
|
|
Void partialButterfly4(TCoeff *src, TCoeff *dst, Int shift, Int line)
|
|
{
|
|
Int j;
|
|
TCoeff E[2],O[2];
|
|
TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
|
|
for (j=0; j<line; j++)
|
|
{
|
|
/* E and O */
|
|
E[0] = src[0] + src[3];
|
|
O[0] = src[0] - src[3];
|
|
E[1] = src[1] + src[2];
|
|
O[1] = src[1] - src[2];
|
|
|
|
dst[0] = (g_aiT4[TRANSFORM_FORWARD][0][0]*E[0] + g_aiT4[TRANSFORM_FORWARD][0][1]*E[1] + add)>>shift;
|
|
dst[2*line] = (g_aiT4[TRANSFORM_FORWARD][2][0]*E[0] + g_aiT4[TRANSFORM_FORWARD][2][1]*E[1] + add)>>shift;
|
|
dst[line] = (g_aiT4[TRANSFORM_FORWARD][1][0]*O[0] + g_aiT4[TRANSFORM_FORWARD][1][1]*O[1] + add)>>shift;
|
|
dst[3*line] = (g_aiT4[TRANSFORM_FORWARD][3][0]*O[0] + g_aiT4[TRANSFORM_FORWARD][3][1]*O[1] + add)>>shift;
|
|
|
|
src += 4;
|
|
dst ++;
|
|
}
|
|
}
|
|
|
|
// Fast DST Algorithm. Full matrix multiplication for DST and Fast DST algorithm
|
|
// give identical results
|
|
Void fastForwardDst(TCoeff *block, TCoeff *coeff, Int shift) // input block, output coeff
|
|
{
|
|
Int i;
|
|
TCoeff c[4];
|
|
TCoeff rnd_factor = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
for (i=0; i<4; i++)
|
|
{
|
|
// Intermediate Variables
|
|
c[0] = block[4*i+0];
|
|
c[1] = block[4*i+1];
|
|
c[2] = block[4*i+2];
|
|
c[3] = block[4*i+3];
|
|
|
|
for (Int row = 0; row < 4; row++)
|
|
{
|
|
TCoeff result = 0;
|
|
for (Int column = 0; column < 4; column++)
|
|
result += c[column] * g_as_DST_MAT_4[TRANSFORM_FORWARD][row][column]; // use the defined matrix, rather than hard-wired numbers
|
|
|
|
coeff[(row * 4) + i] = rightShift((result + rnd_factor), shift);
|
|
}
|
|
}
|
|
}
|
|
|
|
Void fastInverseDst(TCoeff *tmp, TCoeff *block, Int shift, const TCoeff outputMinimum, const TCoeff outputMaximum) // input tmp, output block
|
|
{
|
|
Int i;
|
|
TCoeff c[4];
|
|
TCoeff rnd_factor = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
for (i=0; i<4; i++)
|
|
{
|
|
// Intermediate Variables
|
|
c[0] = tmp[ i];
|
|
c[1] = tmp[4 +i];
|
|
c[2] = tmp[8 +i];
|
|
c[3] = tmp[12+i];
|
|
|
|
for (Int column = 0; column < 4; column++)
|
|
{
|
|
TCoeff &result = block[(i * 4) + column];
|
|
|
|
result = 0;
|
|
for (Int row = 0; row < 4; row++)
|
|
result += c[row] * g_as_DST_MAT_4[TRANSFORM_INVERSE][row][column]; // use the defined matrix, rather than hard-wired numbers
|
|
|
|
result = Clip3( outputMinimum, outputMaximum, rightShift((result + rnd_factor), shift));
|
|
}
|
|
}
|
|
}
|
|
|
|
/** 4x4 inverse transform implemented using partial butterfly structure (1D)
|
|
* \param src input data (transform coefficients)
|
|
* \param dst output data (residual)
|
|
* \param shift specifies right shift after 1D transform
|
|
*/
|
|
Void partialButterflyInverse4(TCoeff *src, TCoeff *dst, Int shift, Int line, const TCoeff outputMinimum, const TCoeff outputMaximum)
|
|
{
|
|
Int j;
|
|
TCoeff E[2],O[2];
|
|
TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
|
|
for (j=0; j<line; j++)
|
|
{
|
|
/* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
|
|
O[0] = g_aiT4[TRANSFORM_INVERSE][1][0]*src[line] + g_aiT4[TRANSFORM_INVERSE][3][0]*src[3*line];
|
|
O[1] = g_aiT4[TRANSFORM_INVERSE][1][1]*src[line] + g_aiT4[TRANSFORM_INVERSE][3][1]*src[3*line];
|
|
E[0] = g_aiT4[TRANSFORM_INVERSE][0][0]*src[0] + g_aiT4[TRANSFORM_INVERSE][2][0]*src[2*line];
|
|
E[1] = g_aiT4[TRANSFORM_INVERSE][0][1]*src[0] + g_aiT4[TRANSFORM_INVERSE][2][1]*src[2*line];
|
|
|
|
/* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
|
|
dst[0] = Clip3( outputMinimum, outputMaximum, (E[0] + O[0] + add)>>shift );
|
|
dst[1] = Clip3( outputMinimum, outputMaximum, (E[1] + O[1] + add)>>shift );
|
|
dst[2] = Clip3( outputMinimum, outputMaximum, (E[1] - O[1] + add)>>shift );
|
|
dst[3] = Clip3( outputMinimum, outputMaximum, (E[0] - O[0] + add)>>shift );
|
|
|
|
src ++;
|
|
dst += 4;
|
|
}
|
|
}
|
|
|
|
/** 8x8 forward transform implemented using partial butterfly structure (1D)
|
|
* \param src input data (residual)
|
|
* \param dst output data (transform coefficients)
|
|
* \param shift specifies right shift after 1D transform
|
|
*/
|
|
Void partialButterfly8(TCoeff *src, TCoeff *dst, Int shift, Int line)
|
|
{
|
|
Int j,k;
|
|
TCoeff E[4],O[4];
|
|
TCoeff EE[2],EO[2];
|
|
TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
|
|
for (j=0; j<line; j++)
|
|
{
|
|
/* E and O*/
|
|
for (k=0;k<4;k++)
|
|
{
|
|
E[k] = src[k] + src[7-k];
|
|
O[k] = src[k] - src[7-k];
|
|
}
|
|
/* EE and EO */
|
|
EE[0] = E[0] + E[3];
|
|
EO[0] = E[0] - E[3];
|
|
EE[1] = E[1] + E[2];
|
|
EO[1] = E[1] - E[2];
|
|
|
|
dst[0] = (g_aiT8[TRANSFORM_FORWARD][0][0]*EE[0] + g_aiT8[TRANSFORM_FORWARD][0][1]*EE[1] + add)>>shift;
|
|
dst[4*line] = (g_aiT8[TRANSFORM_FORWARD][4][0]*EE[0] + g_aiT8[TRANSFORM_FORWARD][4][1]*EE[1] + add)>>shift;
|
|
dst[2*line] = (g_aiT8[TRANSFORM_FORWARD][2][0]*EO[0] + g_aiT8[TRANSFORM_FORWARD][2][1]*EO[1] + add)>>shift;
|
|
dst[6*line] = (g_aiT8[TRANSFORM_FORWARD][6][0]*EO[0] + g_aiT8[TRANSFORM_FORWARD][6][1]*EO[1] + add)>>shift;
|
|
|
|
dst[line] = (g_aiT8[TRANSFORM_FORWARD][1][0]*O[0] + g_aiT8[TRANSFORM_FORWARD][1][1]*O[1] + g_aiT8[TRANSFORM_FORWARD][1][2]*O[2] + g_aiT8[TRANSFORM_FORWARD][1][3]*O[3] + add)>>shift;
|
|
dst[3*line] = (g_aiT8[TRANSFORM_FORWARD][3][0]*O[0] + g_aiT8[TRANSFORM_FORWARD][3][1]*O[1] + g_aiT8[TRANSFORM_FORWARD][3][2]*O[2] + g_aiT8[TRANSFORM_FORWARD][3][3]*O[3] + add)>>shift;
|
|
dst[5*line] = (g_aiT8[TRANSFORM_FORWARD][5][0]*O[0] + g_aiT8[TRANSFORM_FORWARD][5][1]*O[1] + g_aiT8[TRANSFORM_FORWARD][5][2]*O[2] + g_aiT8[TRANSFORM_FORWARD][5][3]*O[3] + add)>>shift;
|
|
dst[7*line] = (g_aiT8[TRANSFORM_FORWARD][7][0]*O[0] + g_aiT8[TRANSFORM_FORWARD][7][1]*O[1] + g_aiT8[TRANSFORM_FORWARD][7][2]*O[2] + g_aiT8[TRANSFORM_FORWARD][7][3]*O[3] + add)>>shift;
|
|
|
|
src += 8;
|
|
dst ++;
|
|
}
|
|
}
|
|
|
|
/** 8x8 inverse transform implemented using partial butterfly structure (1D)
|
|
* \param src input data (transform coefficients)
|
|
* \param dst output data (residual)
|
|
* \param shift specifies right shift after 1D transform
|
|
*/
|
|
Void partialButterflyInverse8(TCoeff *src, TCoeff *dst, Int shift, Int line, const TCoeff outputMinimum, const TCoeff outputMaximum)
|
|
{
|
|
Int j,k;
|
|
TCoeff E[4],O[4];
|
|
TCoeff EE[2],EO[2];
|
|
TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
|
|
for (j=0; j<line; j++)
|
|
{
|
|
/* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
|
|
for (k=0;k<4;k++)
|
|
{
|
|
O[k] = g_aiT8[TRANSFORM_INVERSE][ 1][k]*src[line] + g_aiT8[TRANSFORM_INVERSE][ 3][k]*src[3*line] +
|
|
g_aiT8[TRANSFORM_INVERSE][ 5][k]*src[5*line] + g_aiT8[TRANSFORM_INVERSE][ 7][k]*src[7*line];
|
|
}
|
|
|
|
EO[0] = g_aiT8[TRANSFORM_INVERSE][2][0]*src[ 2*line ] + g_aiT8[TRANSFORM_INVERSE][6][0]*src[ 6*line ];
|
|
EO[1] = g_aiT8[TRANSFORM_INVERSE][2][1]*src[ 2*line ] + g_aiT8[TRANSFORM_INVERSE][6][1]*src[ 6*line ];
|
|
EE[0] = g_aiT8[TRANSFORM_INVERSE][0][0]*src[ 0 ] + g_aiT8[TRANSFORM_INVERSE][4][0]*src[ 4*line ];
|
|
EE[1] = g_aiT8[TRANSFORM_INVERSE][0][1]*src[ 0 ] + g_aiT8[TRANSFORM_INVERSE][4][1]*src[ 4*line ];
|
|
|
|
/* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
|
|
E[0] = EE[0] + EO[0];
|
|
E[3] = EE[0] - EO[0];
|
|
E[1] = EE[1] + EO[1];
|
|
E[2] = EE[1] - EO[1];
|
|
for (k=0;k<4;k++)
|
|
{
|
|
dst[ k ] = Clip3( outputMinimum, outputMaximum, (E[k] + O[k] + add)>>shift );
|
|
dst[ k+4 ] = Clip3( outputMinimum, outputMaximum, (E[3-k] - O[3-k] + add)>>shift );
|
|
}
|
|
src ++;
|
|
dst += 8;
|
|
}
|
|
}
|
|
|
|
/** 16x16 forward transform implemented using partial butterfly structure (1D)
|
|
* \param src input data (residual)
|
|
* \param dst output data (transform coefficients)
|
|
* \param shift specifies right shift after 1D transform
|
|
*/
|
|
Void partialButterfly16(TCoeff *src, TCoeff *dst, Int shift, Int line)
|
|
{
|
|
Int j,k;
|
|
TCoeff E[8],O[8];
|
|
TCoeff EE[4],EO[4];
|
|
TCoeff EEE[2],EEO[2];
|
|
TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
|
|
for (j=0; j<line; j++)
|
|
{
|
|
/* E and O*/
|
|
for (k=0;k<8;k++)
|
|
{
|
|
E[k] = src[k] + src[15-k];
|
|
O[k] = src[k] - src[15-k];
|
|
}
|
|
/* EE and EO */
|
|
for (k=0;k<4;k++)
|
|
{
|
|
EE[k] = E[k] + E[7-k];
|
|
EO[k] = E[k] - E[7-k];
|
|
}
|
|
/* EEE and EEO */
|
|
EEE[0] = EE[0] + EE[3];
|
|
EEO[0] = EE[0] - EE[3];
|
|
EEE[1] = EE[1] + EE[2];
|
|
EEO[1] = EE[1] - EE[2];
|
|
|
|
dst[ 0 ] = (g_aiT16[TRANSFORM_FORWARD][ 0][0]*EEE[0] + g_aiT16[TRANSFORM_FORWARD][ 0][1]*EEE[1] + add)>>shift;
|
|
dst[ 8*line ] = (g_aiT16[TRANSFORM_FORWARD][ 8][0]*EEE[0] + g_aiT16[TRANSFORM_FORWARD][ 8][1]*EEE[1] + add)>>shift;
|
|
dst[ 4*line ] = (g_aiT16[TRANSFORM_FORWARD][ 4][0]*EEO[0] + g_aiT16[TRANSFORM_FORWARD][ 4][1]*EEO[1] + add)>>shift;
|
|
dst[ 12*line] = (g_aiT16[TRANSFORM_FORWARD][12][0]*EEO[0] + g_aiT16[TRANSFORM_FORWARD][12][1]*EEO[1] + add)>>shift;
|
|
|
|
for (k=2;k<16;k+=4)
|
|
{
|
|
dst[ k*line ] = (g_aiT16[TRANSFORM_FORWARD][k][0]*EO[0] + g_aiT16[TRANSFORM_FORWARD][k][1]*EO[1] +
|
|
g_aiT16[TRANSFORM_FORWARD][k][2]*EO[2] + g_aiT16[TRANSFORM_FORWARD][k][3]*EO[3] + add)>>shift;
|
|
}
|
|
|
|
for (k=1;k<16;k+=2)
|
|
{
|
|
dst[ k*line ] = (g_aiT16[TRANSFORM_FORWARD][k][0]*O[0] + g_aiT16[TRANSFORM_FORWARD][k][1]*O[1] +
|
|
g_aiT16[TRANSFORM_FORWARD][k][2]*O[2] + g_aiT16[TRANSFORM_FORWARD][k][3]*O[3] +
|
|
g_aiT16[TRANSFORM_FORWARD][k][4]*O[4] + g_aiT16[TRANSFORM_FORWARD][k][5]*O[5] +
|
|
g_aiT16[TRANSFORM_FORWARD][k][6]*O[6] + g_aiT16[TRANSFORM_FORWARD][k][7]*O[7] + add)>>shift;
|
|
}
|
|
|
|
src += 16;
|
|
dst ++;
|
|
|
|
}
|
|
}
|
|
|
|
/** 16x16 inverse transform implemented using partial butterfly structure (1D)
|
|
* \param src input data (transform coefficients)
|
|
* \param dst output data (residual)
|
|
* \param shift specifies right shift after 1D transform
|
|
*/
|
|
Void partialButterflyInverse16(TCoeff *src, TCoeff *dst, Int shift, Int line, const TCoeff outputMinimum, const TCoeff outputMaximum)
|
|
{
|
|
Int j,k;
|
|
TCoeff E[8],O[8];
|
|
TCoeff EE[4],EO[4];
|
|
TCoeff EEE[2],EEO[2];
|
|
TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
|
|
for (j=0; j<line; j++)
|
|
{
|
|
/* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
|
|
for (k=0;k<8;k++)
|
|
{
|
|
O[k] = g_aiT16[TRANSFORM_INVERSE][ 1][k]*src[ line] + g_aiT16[TRANSFORM_INVERSE][ 3][k]*src[ 3*line] +
|
|
g_aiT16[TRANSFORM_INVERSE][ 5][k]*src[ 5*line] + g_aiT16[TRANSFORM_INVERSE][ 7][k]*src[ 7*line] +
|
|
g_aiT16[TRANSFORM_INVERSE][ 9][k]*src[ 9*line] + g_aiT16[TRANSFORM_INVERSE][11][k]*src[11*line] +
|
|
g_aiT16[TRANSFORM_INVERSE][13][k]*src[13*line] + g_aiT16[TRANSFORM_INVERSE][15][k]*src[15*line];
|
|
}
|
|
for (k=0;k<4;k++)
|
|
{
|
|
EO[k] = g_aiT16[TRANSFORM_INVERSE][ 2][k]*src[ 2*line] + g_aiT16[TRANSFORM_INVERSE][ 6][k]*src[ 6*line] +
|
|
g_aiT16[TRANSFORM_INVERSE][10][k]*src[10*line] + g_aiT16[TRANSFORM_INVERSE][14][k]*src[14*line];
|
|
}
|
|
EEO[0] = g_aiT16[TRANSFORM_INVERSE][4][0]*src[ 4*line ] + g_aiT16[TRANSFORM_INVERSE][12][0]*src[ 12*line ];
|
|
EEE[0] = g_aiT16[TRANSFORM_INVERSE][0][0]*src[ 0 ] + g_aiT16[TRANSFORM_INVERSE][ 8][0]*src[ 8*line ];
|
|
EEO[1] = g_aiT16[TRANSFORM_INVERSE][4][1]*src[ 4*line ] + g_aiT16[TRANSFORM_INVERSE][12][1]*src[ 12*line ];
|
|
EEE[1] = g_aiT16[TRANSFORM_INVERSE][0][1]*src[ 0 ] + g_aiT16[TRANSFORM_INVERSE][ 8][1]*src[ 8*line ];
|
|
|
|
/* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
|
|
for (k=0;k<2;k++)
|
|
{
|
|
EE[k] = EEE[k] + EEO[k];
|
|
EE[k+2] = EEE[1-k] - EEO[1-k];
|
|
}
|
|
for (k=0;k<4;k++)
|
|
{
|
|
E[k] = EE[k] + EO[k];
|
|
E[k+4] = EE[3-k] - EO[3-k];
|
|
}
|
|
for (k=0;k<8;k++)
|
|
{
|
|
dst[k] = Clip3( outputMinimum, outputMaximum, (E[k] + O[k] + add)>>shift );
|
|
dst[k+8] = Clip3( outputMinimum, outputMaximum, (E[7-k] - O[7-k] + add)>>shift );
|
|
}
|
|
src ++;
|
|
dst += 16;
|
|
}
|
|
}
|
|
|
|
/** 32x32 forward transform implemented using partial butterfly structure (1D)
|
|
* \param src input data (residual)
|
|
* \param dst output data (transform coefficients)
|
|
* \param shift specifies right shift after 1D transform
|
|
*/
|
|
Void partialButterfly32(TCoeff *src, TCoeff *dst, Int shift, Int line)
|
|
{
|
|
Int j,k;
|
|
TCoeff E[16],O[16];
|
|
TCoeff EE[8],EO[8];
|
|
TCoeff EEE[4],EEO[4];
|
|
TCoeff EEEE[2],EEEO[2];
|
|
TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
|
|
for (j=0; j<line; j++)
|
|
{
|
|
/* E and O*/
|
|
for (k=0;k<16;k++)
|
|
{
|
|
E[k] = src[k] + src[31-k];
|
|
O[k] = src[k] - src[31-k];
|
|
}
|
|
/* EE and EO */
|
|
for (k=0;k<8;k++)
|
|
{
|
|
EE[k] = E[k] + E[15-k];
|
|
EO[k] = E[k] - E[15-k];
|
|
}
|
|
/* EEE and EEO */
|
|
for (k=0;k<4;k++)
|
|
{
|
|
EEE[k] = EE[k] + EE[7-k];
|
|
EEO[k] = EE[k] - EE[7-k];
|
|
}
|
|
/* EEEE and EEEO */
|
|
EEEE[0] = EEE[0] + EEE[3];
|
|
EEEO[0] = EEE[0] - EEE[3];
|
|
EEEE[1] = EEE[1] + EEE[2];
|
|
EEEO[1] = EEE[1] - EEE[2];
|
|
|
|
dst[ 0 ] = (g_aiT32[TRANSFORM_FORWARD][ 0][0]*EEEE[0] + g_aiT32[TRANSFORM_FORWARD][ 0][1]*EEEE[1] + add)>>shift;
|
|
dst[ 16*line ] = (g_aiT32[TRANSFORM_FORWARD][16][0]*EEEE[0] + g_aiT32[TRANSFORM_FORWARD][16][1]*EEEE[1] + add)>>shift;
|
|
dst[ 8*line ] = (g_aiT32[TRANSFORM_FORWARD][ 8][0]*EEEO[0] + g_aiT32[TRANSFORM_FORWARD][ 8][1]*EEEO[1] + add)>>shift;
|
|
dst[ 24*line ] = (g_aiT32[TRANSFORM_FORWARD][24][0]*EEEO[0] + g_aiT32[TRANSFORM_FORWARD][24][1]*EEEO[1] + add)>>shift;
|
|
for (k=4;k<32;k+=8)
|
|
{
|
|
dst[ k*line ] = (g_aiT32[TRANSFORM_FORWARD][k][0]*EEO[0] + g_aiT32[TRANSFORM_FORWARD][k][1]*EEO[1] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][2]*EEO[2] + g_aiT32[TRANSFORM_FORWARD][k][3]*EEO[3] + add)>>shift;
|
|
}
|
|
for (k=2;k<32;k+=4)
|
|
{
|
|
dst[ k*line ] = (g_aiT32[TRANSFORM_FORWARD][k][0]*EO[0] + g_aiT32[TRANSFORM_FORWARD][k][1]*EO[1] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][2]*EO[2] + g_aiT32[TRANSFORM_FORWARD][k][3]*EO[3] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][4]*EO[4] + g_aiT32[TRANSFORM_FORWARD][k][5]*EO[5] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][6]*EO[6] + g_aiT32[TRANSFORM_FORWARD][k][7]*EO[7] + add)>>shift;
|
|
}
|
|
for (k=1;k<32;k+=2)
|
|
{
|
|
dst[ k*line ] = (g_aiT32[TRANSFORM_FORWARD][k][ 0]*O[ 0] + g_aiT32[TRANSFORM_FORWARD][k][ 1]*O[ 1] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][ 2]*O[ 2] + g_aiT32[TRANSFORM_FORWARD][k][ 3]*O[ 3] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][ 4]*O[ 4] + g_aiT32[TRANSFORM_FORWARD][k][ 5]*O[ 5] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][ 6]*O[ 6] + g_aiT32[TRANSFORM_FORWARD][k][ 7]*O[ 7] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][ 8]*O[ 8] + g_aiT32[TRANSFORM_FORWARD][k][ 9]*O[ 9] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][10]*O[10] + g_aiT32[TRANSFORM_FORWARD][k][11]*O[11] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][12]*O[12] + g_aiT32[TRANSFORM_FORWARD][k][13]*O[13] +
|
|
g_aiT32[TRANSFORM_FORWARD][k][14]*O[14] + g_aiT32[TRANSFORM_FORWARD][k][15]*O[15] + add)>>shift;
|
|
}
|
|
|
|
src += 32;
|
|
dst ++;
|
|
}
|
|
}
|
|
|
|
/** 32x32 inverse transform implemented using partial butterfly structure (1D)
|
|
* \param src input data (transform coefficients)
|
|
* \param dst output data (residual)
|
|
* \param shift specifies right shift after 1D transform
|
|
*/
|
|
Void partialButterflyInverse32(TCoeff *src, TCoeff *dst, Int shift, Int line, const TCoeff outputMinimum, const TCoeff outputMaximum)
|
|
{
|
|
Int j,k;
|
|
TCoeff E[16],O[16];
|
|
TCoeff EE[8],EO[8];
|
|
TCoeff EEE[4],EEO[4];
|
|
TCoeff EEEE[2],EEEO[2];
|
|
TCoeff add = (shift > 0) ? (1<<(shift-1)) : 0;
|
|
|
|
for (j=0; j<line; j++)
|
|
{
|
|
/* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
|
|
for (k=0;k<16;k++)
|
|
{
|
|
O[k] = g_aiT32[TRANSFORM_INVERSE][ 1][k]*src[ line ] + g_aiT32[TRANSFORM_INVERSE][ 3][k]*src[ 3*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][ 5][k]*src[ 5*line ] + g_aiT32[TRANSFORM_INVERSE][ 7][k]*src[ 7*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][ 9][k]*src[ 9*line ] + g_aiT32[TRANSFORM_INVERSE][11][k]*src[ 11*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][13][k]*src[ 13*line ] + g_aiT32[TRANSFORM_INVERSE][15][k]*src[ 15*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][17][k]*src[ 17*line ] + g_aiT32[TRANSFORM_INVERSE][19][k]*src[ 19*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][21][k]*src[ 21*line ] + g_aiT32[TRANSFORM_INVERSE][23][k]*src[ 23*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][25][k]*src[ 25*line ] + g_aiT32[TRANSFORM_INVERSE][27][k]*src[ 27*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][29][k]*src[ 29*line ] + g_aiT32[TRANSFORM_INVERSE][31][k]*src[ 31*line ];
|
|
}
|
|
for (k=0;k<8;k++)
|
|
{
|
|
EO[k] = g_aiT32[TRANSFORM_INVERSE][ 2][k]*src[ 2*line ] + g_aiT32[TRANSFORM_INVERSE][ 6][k]*src[ 6*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][10][k]*src[ 10*line ] + g_aiT32[TRANSFORM_INVERSE][14][k]*src[ 14*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][18][k]*src[ 18*line ] + g_aiT32[TRANSFORM_INVERSE][22][k]*src[ 22*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][26][k]*src[ 26*line ] + g_aiT32[TRANSFORM_INVERSE][30][k]*src[ 30*line ];
|
|
}
|
|
for (k=0;k<4;k++)
|
|
{
|
|
EEO[k] = g_aiT32[TRANSFORM_INVERSE][ 4][k]*src[ 4*line ] + g_aiT32[TRANSFORM_INVERSE][12][k]*src[ 12*line ] +
|
|
g_aiT32[TRANSFORM_INVERSE][20][k]*src[ 20*line ] + g_aiT32[TRANSFORM_INVERSE][28][k]*src[ 28*line ];
|
|
}
|
|
EEEO[0] = g_aiT32[TRANSFORM_INVERSE][8][0]*src[ 8*line ] + g_aiT32[TRANSFORM_INVERSE][24][0]*src[ 24*line ];
|
|
EEEO[1] = g_aiT32[TRANSFORM_INVERSE][8][1]*src[ 8*line ] + g_aiT32[TRANSFORM_INVERSE][24][1]*src[ 24*line ];
|
|
EEEE[0] = g_aiT32[TRANSFORM_INVERSE][0][0]*src[ 0 ] + g_aiT32[TRANSFORM_INVERSE][16][0]*src[ 16*line ];
|
|
EEEE[1] = g_aiT32[TRANSFORM_INVERSE][0][1]*src[ 0 ] + g_aiT32[TRANSFORM_INVERSE][16][1]*src[ 16*line ];
|
|
|
|
/* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
|
|
EEE[0] = EEEE[0] + EEEO[0];
|
|
EEE[3] = EEEE[0] - EEEO[0];
|
|
EEE[1] = EEEE[1] + EEEO[1];
|
|
EEE[2] = EEEE[1] - EEEO[1];
|
|
for (k=0;k<4;k++)
|
|
{
|
|
EE[k] = EEE[k] + EEO[k];
|
|
EE[k+4] = EEE[3-k] - EEO[3-k];
|
|
}
|
|
for (k=0;k<8;k++)
|
|
{
|
|
E[k] = EE[k] + EO[k];
|
|
E[k+8] = EE[7-k] - EO[7-k];
|
|
}
|
|
for (k=0;k<16;k++)
|
|
{
|
|
dst[k] = Clip3( outputMinimum, outputMaximum, (E[k] + O[k] + add)>>shift );
|
|
dst[k+16] = Clip3( outputMinimum, outputMaximum, (E[15-k] - O[15-k] + add)>>shift );
|
|
}
|
|
src ++;
|
|
dst += 32;
|
|
}
|
|
}
|
|
|
|
/** MxN forward transform (2D)
|
|
* \param block input data (residual)
|
|
* \param coeff output data (transform coefficients)
|
|
* \param iWidth input data (width of transform)
|
|
* \param iHeight input data (height of transform)
|
|
*/
|
|
Void xTrMxN(Int bitDepth, TCoeff *block, TCoeff *coeff, Int iWidth, Int iHeight, Bool useDST, const Int maxTrDynamicRange)
|
|
{
|
|
static const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_FORWARD];
|
|
|
|
const Int shift_1st = ((g_aucConvertToBit[iWidth] + 2) + bitDepth + TRANSFORM_MATRIX_SHIFT) - maxTrDynamicRange;
|
|
const Int shift_2nd = (g_aucConvertToBit[iHeight] + 2) + TRANSFORM_MATRIX_SHIFT;
|
|
|
|
assert(shift_1st >= 0);
|
|
assert(shift_2nd >= 0);
|
|
|
|
TCoeff tmp[ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
|
|
switch (iWidth)
|
|
{
|
|
case 4:
|
|
{
|
|
if ((iHeight == 4) && useDST) // Check for DCT or DST
|
|
{
|
|
fastForwardDst( block, tmp, shift_1st );
|
|
}
|
|
else partialButterfly4 ( block, tmp, shift_1st, iHeight );
|
|
}
|
|
break;
|
|
|
|
case 8: partialButterfly8 ( block, tmp, shift_1st, iHeight ); break;
|
|
case 16: partialButterfly16( block, tmp, shift_1st, iHeight ); break;
|
|
case 32: partialButterfly32( block, tmp, shift_1st, iHeight ); break;
|
|
default:
|
|
assert(0); exit (1); break;
|
|
}
|
|
|
|
switch (iHeight)
|
|
{
|
|
case 4:
|
|
{
|
|
if ((iWidth == 4) && useDST) // Check for DCT or DST
|
|
{
|
|
fastForwardDst( tmp, coeff, shift_2nd );
|
|
}
|
|
else partialButterfly4 ( tmp, coeff, shift_2nd, iWidth );
|
|
}
|
|
break;
|
|
|
|
case 8: partialButterfly8 ( tmp, coeff, shift_2nd, iWidth ); break;
|
|
case 16: partialButterfly16( tmp, coeff, shift_2nd, iWidth ); break;
|
|
case 32: partialButterfly32( tmp, coeff, shift_2nd, iWidth ); break;
|
|
default:
|
|
assert(0); exit (1); break;
|
|
}
|
|
}
|
|
|
|
|
|
/** MxN inverse transform (2D)
|
|
* \param coeff input data (transform coefficients)
|
|
* \param block output data (residual)
|
|
* \param iWidth input data (width of transform)
|
|
* \param iHeight input data (height of transform)
|
|
*/
|
|
Void xITrMxN(Int bitDepth, TCoeff *coeff, TCoeff *block, Int iWidth, Int iHeight, Bool useDST, const Int maxTrDynamicRange)
|
|
{
|
|
static const Int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_INVERSE];
|
|
|
|
Int shift_1st = TRANSFORM_MATRIX_SHIFT + 1; //1 has been added to shift_1st at the expense of shift_2nd
|
|
Int shift_2nd = (TRANSFORM_MATRIX_SHIFT + maxTrDynamicRange - 1) - bitDepth;
|
|
const TCoeff clipMinimum = -(1 << maxTrDynamicRange);
|
|
const TCoeff clipMaximum = (1 << maxTrDynamicRange) - 1;
|
|
|
|
assert(shift_1st >= 0);
|
|
assert(shift_2nd >= 0);
|
|
|
|
TCoeff tmp[MAX_TU_SIZE * MAX_TU_SIZE];
|
|
|
|
switch (iHeight)
|
|
{
|
|
case 4:
|
|
{
|
|
if ((iWidth == 4) && useDST) // Check for DCT or DST
|
|
{
|
|
fastInverseDst( coeff, tmp, shift_1st, clipMinimum, clipMaximum);
|
|
}
|
|
else partialButterflyInverse4 ( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum);
|
|
}
|
|
break;
|
|
|
|
case 8: partialButterflyInverse8 ( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break;
|
|
case 16: partialButterflyInverse16( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break;
|
|
case 32: partialButterflyInverse32( coeff, tmp, shift_1st, iWidth, clipMinimum, clipMaximum); break;
|
|
|
|
default:
|
|
assert(0); exit (1); break;
|
|
}
|
|
|
|
switch (iWidth)
|
|
{
|
|
// Clipping here is not in the standard, but is used to protect the "Pel" data type into which the inverse-transformed samples will be copied
|
|
case 4:
|
|
{
|
|
if ((iHeight == 4) && useDST) // Check for DCT or DST
|
|
{
|
|
fastInverseDst( tmp, block, shift_2nd, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max() );
|
|
}
|
|
else partialButterflyInverse4 ( tmp, block, shift_2nd, iHeight, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max());
|
|
}
|
|
break;
|
|
|
|
case 8: partialButterflyInverse8 ( tmp, block, shift_2nd, iHeight, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max()); break;
|
|
case 16: partialButterflyInverse16( tmp, block, shift_2nd, iHeight, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max()); break;
|
|
case 32: partialButterflyInverse32( tmp, block, shift_2nd, iHeight, std::numeric_limits<Pel>::min(), std::numeric_limits<Pel>::max()); break;
|
|
|
|
default:
|
|
assert(0); exit (1); break;
|
|
}
|
|
}
|
|
|
|
|
|
// To minimize the distortion only. No rate is considered.
|
|
Void TComTrQuant::signBitHidingHDQ( const ComponentID compID, TCoeff* pQCoef, TCoeff* pCoef, TCoeff* deltaU, const TUEntropyCodingParameters &codingParameters )
|
|
{
|
|
const UInt width = codingParameters.widthInGroups << MLS_CG_LOG2_WIDTH;
|
|
const UInt height = codingParameters.heightInGroups << MLS_CG_LOG2_HEIGHT;
|
|
const UInt groupSize = 1 << MLS_CG_SIZE;
|
|
|
|
const TCoeff entropyCodingMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]);
|
|
const TCoeff entropyCodingMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1;
|
|
|
|
Int lastCG = -1;
|
|
Int absSum = 0 ;
|
|
Int n ;
|
|
|
|
for( Int subSet = (width*height-1) >> MLS_CG_SIZE; subSet >= 0; subSet-- )
|
|
{
|
|
Int subPos = subSet << MLS_CG_SIZE;
|
|
Int firstNZPosInCG=groupSize , lastNZPosInCG=-1 ;
|
|
absSum = 0 ;
|
|
|
|
for(n = groupSize-1; n >= 0; --n )
|
|
{
|
|
if( pQCoef[ codingParameters.scan[ n + subPos ]] )
|
|
{
|
|
lastNZPosInCG = n;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(n = 0; n <groupSize; n++ )
|
|
{
|
|
if( pQCoef[ codingParameters.scan[ n + subPos ]] )
|
|
{
|
|
firstNZPosInCG = n;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(n = firstNZPosInCG; n <=lastNZPosInCG; n++ )
|
|
{
|
|
absSum += Int(pQCoef[ codingParameters.scan[ n + subPos ]]);
|
|
}
|
|
|
|
if(lastNZPosInCG>=0 && lastCG==-1)
|
|
{
|
|
lastCG = 1 ;
|
|
}
|
|
|
|
if( lastNZPosInCG-firstNZPosInCG>=SBH_THRESHOLD )
|
|
{
|
|
UInt signbit = (pQCoef[codingParameters.scan[subPos+firstNZPosInCG]]>0?0:1) ;
|
|
if( signbit!=(absSum&0x1) ) //compare signbit with sum_parity
|
|
{
|
|
TCoeff curCost = std::numeric_limits<TCoeff>::max();
|
|
TCoeff minCostInc = std::numeric_limits<TCoeff>::max();
|
|
Int minPos =-1, finalChange=0, curChange=0;
|
|
|
|
for( n = (lastCG==1?lastNZPosInCG:groupSize-1) ; n >= 0; --n )
|
|
{
|
|
UInt blkPos = codingParameters.scan[ n+subPos ];
|
|
if(pQCoef[ blkPos ] != 0 )
|
|
{
|
|
if(deltaU[blkPos]>0)
|
|
{
|
|
curCost = - deltaU[blkPos];
|
|
curChange=1 ;
|
|
}
|
|
else
|
|
{
|
|
//curChange =-1;
|
|
if(n==firstNZPosInCG && abs(pQCoef[blkPos])==1)
|
|
{
|
|
curCost = std::numeric_limits<TCoeff>::max();
|
|
}
|
|
else
|
|
{
|
|
curCost = deltaU[blkPos];
|
|
curChange =-1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(n<firstNZPosInCG)
|
|
{
|
|
UInt thisSignBit = (pCoef[blkPos]>=0?0:1);
|
|
if(thisSignBit != signbit )
|
|
{
|
|
curCost = std::numeric_limits<TCoeff>::max();
|
|
}
|
|
else
|
|
{
|
|
curCost = - (deltaU[blkPos]) ;
|
|
curChange = 1 ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curCost = - (deltaU[blkPos]) ;
|
|
curChange = 1 ;
|
|
}
|
|
}
|
|
|
|
if( curCost<minCostInc)
|
|
{
|
|
minCostInc = curCost ;
|
|
finalChange = curChange ;
|
|
minPos = blkPos ;
|
|
}
|
|
} //CG loop
|
|
|
|
if(pQCoef[minPos] == entropyCodingMaximum || pQCoef[minPos] == entropyCodingMinimum)
|
|
{
|
|
finalChange = -1;
|
|
}
|
|
|
|
if(pCoef[minPos]>=0)
|
|
{
|
|
pQCoef[minPos] += finalChange ;
|
|
}
|
|
else
|
|
{
|
|
pQCoef[minPos] -= finalChange ;
|
|
}
|
|
} // Hide
|
|
}
|
|
if(lastCG==1)
|
|
{
|
|
lastCG=0 ;
|
|
}
|
|
} // TU loop
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
Void TComTrQuant::xQuant( TComTU &rTu,
|
|
TCoeff * pSrc,
|
|
TCoeff * pDes,
|
|
#if ADAPTIVE_QP_SELECTION
|
|
TCoeff *pArlDes,
|
|
#endif
|
|
TCoeff &uiAbsSum,
|
|
const ComponentID compID,
|
|
const QpParam &cQP )
|
|
{
|
|
const TComRectangle &rect = rTu.getRect(compID);
|
|
const UInt uiWidth = rect.width;
|
|
const UInt uiHeight = rect.height;
|
|
TComDataCU* pcCU = rTu.getCU();
|
|
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
|
|
|
|
TCoeff* piCoef = pSrc;
|
|
TCoeff* piQCoef = pDes;
|
|
#if ADAPTIVE_QP_SELECTION
|
|
TCoeff* piArlCCoef = pArlDes;
|
|
#endif
|
|
|
|
const Bool useTransformSkip = pcCU->getTransformSkip(uiAbsPartIdx, compID);
|
|
|
|
Bool useRDOQ = useTransformSkip ? m_useRDOQTS : m_useRDOQ;
|
|
if ( useRDOQ && (isLuma(compID) || RDOQ_CHROMA) )
|
|
{
|
|
#if ADAPTIVE_QP_SELECTION
|
|
xRateDistOptQuant( rTu, piCoef, pDes, pArlDes, uiAbsSum, compID, cQP );
|
|
#else
|
|
xRateDistOptQuant( rTu, piCoef, pDes, uiAbsSum, compID, cQP );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
TUEntropyCodingParameters codingParameters;
|
|
getTUEntropyCodingParameters(codingParameters, rTu, compID);
|
|
|
|
const TCoeff entropyCodingMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]);
|
|
const TCoeff entropyCodingMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1;
|
|
|
|
TCoeff deltaU[MAX_TU_SIZE * MAX_TU_SIZE];
|
|
|
|
const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID);
|
|
|
|
Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID);
|
|
assert(scalingListType < SCALING_LIST_NUM);
|
|
Int *piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrSize-2);
|
|
|
|
const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0));
|
|
const Int defaultQuantisationCoefficient = g_quantScales[cQP.rem];
|
|
|
|
/* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be
|
|
* implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the
|
|
* uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller)
|
|
* Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result
|
|
*/
|
|
|
|
// Represents scaling through forward transform
|
|
Int iTransformShift = getTransformShift(toChannelType(compID), uiLog2TrSize);
|
|
if (useTransformSkip && pcCU->getSlice()->getSPS()->getUseExtendedPrecision())
|
|
{
|
|
iTransformShift = std::max<Int>(0, iTransformShift);
|
|
}
|
|
|
|
const Int iQBits = QUANT_SHIFT + cQP.per + iTransformShift;
|
|
// QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset
|
|
|
|
#if ADAPTIVE_QP_SELECTION
|
|
Int iQBitsC = MAX_INT;
|
|
Int iAddC = MAX_INT;
|
|
|
|
if (m_bUseAdaptQpSelect)
|
|
{
|
|
iQBitsC = iQBits - ARL_C_PRECISION;
|
|
iAddC = 1 << (iQBitsC-1);
|
|
}
|
|
#endif
|
|
|
|
const Int iAdd = (pcCU->getSlice()->getSliceType()==I_SLICE ? 171 : 85) << (iQBits-9);
|
|
const Int qBits8 = iQBits - 8;
|
|
|
|
for( Int uiBlockPos = 0; uiBlockPos < uiWidth*uiHeight; uiBlockPos++ )
|
|
{
|
|
const TCoeff iLevel = piCoef[uiBlockPos];
|
|
const TCoeff iSign = (iLevel < 0 ? -1: 1);
|
|
|
|
const Int64 tmpLevel = (Int64)abs(iLevel) * (enableScalingLists ? piQuantCoeff[uiBlockPos] : defaultQuantisationCoefficient);
|
|
|
|
#if ADAPTIVE_QP_SELECTION
|
|
if( m_bUseAdaptQpSelect )
|
|
{
|
|
piArlCCoef[uiBlockPos] = (TCoeff)((tmpLevel + iAddC ) >> iQBitsC);
|
|
}
|
|
#endif
|
|
|
|
const TCoeff quantisedMagnitude = TCoeff((tmpLevel + iAdd ) >> iQBits);
|
|
deltaU[uiBlockPos] = (TCoeff)((tmpLevel - (quantisedMagnitude<<iQBits) )>> qBits8);
|
|
|
|
uiAbsSum += quantisedMagnitude;
|
|
const TCoeff quantisedCoefficient = quantisedMagnitude * iSign;
|
|
|
|
piQCoef[uiBlockPos] = Clip3<TCoeff>( entropyCodingMinimum, entropyCodingMaximum, quantisedCoefficient );
|
|
} // for n
|
|
|
|
if( pcCU->getSlice()->getPPS()->getSignHideFlag() )
|
|
{
|
|
if(uiAbsSum >= 2) //this prevents TUs with only one coefficient of value 1 from being tested
|
|
{
|
|
signBitHidingHDQ( compID, piQCoef, piCoef, deltaU, codingParameters ) ;
|
|
}
|
|
}
|
|
} //if RDOQ
|
|
//return;
|
|
}
|
|
|
|
Void TComTrQuant::xDeQuant( TComTU &rTu,
|
|
const TCoeff * pSrc,
|
|
TCoeff * pDes,
|
|
const ComponentID compID,
|
|
const QpParam &cQP )
|
|
{
|
|
assert(compID<MAX_NUM_COMPONENT);
|
|
|
|
TComDataCU *pcCU = rTu.getCU();
|
|
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
|
|
const TComRectangle &rect = rTu.getRect(compID);
|
|
const UInt uiWidth = rect.width;
|
|
const UInt uiHeight = rect.height;
|
|
const TCoeff *const piQCoef = pSrc;
|
|
TCoeff *const piCoef = pDes;
|
|
const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID);
|
|
const UInt numSamplesInBlock = uiWidth*uiHeight;
|
|
const TCoeff transformMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]);
|
|
const TCoeff transformMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1;
|
|
const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0));
|
|
const Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID);
|
|
|
|
assert (scalingListType < SCALING_LIST_NUM);
|
|
assert ( uiWidth <= m_uiMaxTrSize );
|
|
|
|
// Represents scaling through forward transform
|
|
const Bool bClipTransformShiftTo0 = (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0) && pcCU->getSlice()->getSPS()->getUseExtendedPrecision();
|
|
const Int originalTransformShift = getTransformShift(toChannelType(compID), uiLog2TrSize);
|
|
const Int iTransformShift = bClipTransformShiftTo0 ? std::max<Int>(0, originalTransformShift) : originalTransformShift;
|
|
|
|
const Int QP_per = cQP.per;
|
|
const Int QP_rem = cQP.rem;
|
|
|
|
const Int rightShift = (IQUANT_SHIFT - (iTransformShift + QP_per)) + (enableScalingLists ? LOG2_SCALING_LIST_NEUTRAL_VALUE : 0);
|
|
|
|
if(enableScalingLists)
|
|
{
|
|
//from the dequantisation equation:
|
|
//iCoeffQ = ((Intermediate_Int(clipQCoef) * piDequantCoef[deQuantIdx]) + iAdd ) >> rightShift
|
|
//(sizeof(Intermediate_Int) * 8) = inputBitDepth + dequantCoefBits - rightShift
|
|
const UInt dequantCoefBits = 1 + IQUANT_SHIFT + SCALING_LIST_BITS;
|
|
const UInt targetInputBitDepth = std::min<UInt>((g_maxTrDynamicRange[toChannelType(compID)] + 1), (((sizeof(Intermediate_Int) * 8) + rightShift) - dequantCoefBits));
|
|
|
|
const Intermediate_Int inputMinimum = -(1 << (targetInputBitDepth - 1));
|
|
const Intermediate_Int inputMaximum = (1 << (targetInputBitDepth - 1)) - 1;
|
|
|
|
Int *piDequantCoef = getDequantCoeff(scalingListType,QP_rem,uiLog2TrSize-2);
|
|
|
|
if(rightShift > 0)
|
|
{
|
|
const Intermediate_Int iAdd = 1 << (rightShift - 1);
|
|
|
|
for( Int n = 0; n < numSamplesInBlock; n++ )
|
|
{
|
|
const TCoeff clipQCoef = TCoeff(Clip3<Intermediate_Int>(inputMinimum, inputMaximum, piQCoef[n]));
|
|
const Intermediate_Int iCoeffQ = ((Intermediate_Int(clipQCoef) * piDequantCoef[n]) + iAdd ) >> rightShift;
|
|
|
|
piCoef[n] = TCoeff(Clip3<Intermediate_Int>(transformMinimum,transformMaximum,iCoeffQ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const Int leftShift = -rightShift;
|
|
|
|
for( Int n = 0; n < numSamplesInBlock; n++ )
|
|
{
|
|
const TCoeff clipQCoef = TCoeff(Clip3<Intermediate_Int>(inputMinimum, inputMaximum, piQCoef[n]));
|
|
const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * piDequantCoef[n]) << leftShift;
|
|
|
|
piCoef[n] = TCoeff(Clip3<Intermediate_Int>(transformMinimum,transformMaximum,iCoeffQ));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const Int scale = g_invQuantScales[QP_rem];
|
|
const Int scaleBits = (IQUANT_SHIFT + 1) ;
|
|
|
|
//from the dequantisation equation:
|
|
//iCoeffQ = Intermediate_Int((Int64(clipQCoef) * scale + iAdd) >> rightShift);
|
|
//(sizeof(Intermediate_Int) * 8) = inputBitDepth + scaleBits - rightShift
|
|
const UInt targetInputBitDepth = std::min<UInt>((g_maxTrDynamicRange[toChannelType(compID)] + 1), (((sizeof(Intermediate_Int) * 8) + rightShift) - scaleBits));
|
|
const Intermediate_Int inputMinimum = -(1 << (targetInputBitDepth - 1));
|
|
const Intermediate_Int inputMaximum = (1 << (targetInputBitDepth - 1)) - 1;
|
|
|
|
if (rightShift > 0)
|
|
{
|
|
const Intermediate_Int iAdd = 1 << (rightShift - 1);
|
|
|
|
for( Int n = 0; n < numSamplesInBlock; n++ )
|
|
{
|
|
const TCoeff clipQCoef = TCoeff(Clip3<Intermediate_Int>(inputMinimum, inputMaximum, piQCoef[n]));
|
|
const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * scale + iAdd) >> rightShift;
|
|
|
|
piCoef[n] = TCoeff(Clip3<Intermediate_Int>(transformMinimum,transformMaximum,iCoeffQ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const Int leftShift = -rightShift;
|
|
|
|
for( Int n = 0; n < numSamplesInBlock; n++ )
|
|
{
|
|
const TCoeff clipQCoef = TCoeff(Clip3<Intermediate_Int>(inputMinimum, inputMaximum, piQCoef[n]));
|
|
const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * scale) << leftShift;
|
|
|
|
piCoef[n] = TCoeff(Clip3<Intermediate_Int>(transformMinimum,transformMaximum,iCoeffQ));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Void TComTrQuant::init( UInt uiMaxTrSize,
|
|
Bool bUseRDOQ,
|
|
Bool bUseRDOQTS,
|
|
Bool bEnc,
|
|
Bool useTransformSkipFast
|
|
#if ADAPTIVE_QP_SELECTION
|
|
, Bool bUseAdaptQpSelect
|
|
#endif
|
|
)
|
|
{
|
|
m_uiMaxTrSize = uiMaxTrSize;
|
|
m_bEnc = bEnc;
|
|
m_useRDOQ = bUseRDOQ;
|
|
m_useRDOQTS = bUseRDOQTS;
|
|
#if ADAPTIVE_QP_SELECTION
|
|
m_bUseAdaptQpSelect = bUseAdaptQpSelect;
|
|
#endif
|
|
m_useTransformSkipFast = useTransformSkipFast;
|
|
}
|
|
|
|
|
|
Void TComTrQuant::transformNxN( TComTU & rTu,
|
|
const ComponentID compID,
|
|
Pel * pcResidual,
|
|
const UInt uiStride,
|
|
TCoeff * rpcCoeff,
|
|
#if ADAPTIVE_QP_SELECTION
|
|
TCoeff * pcArlCoeff,
|
|
#endif
|
|
TCoeff & uiAbsSum,
|
|
const QpParam & cQP
|
|
)
|
|
{
|
|
const TComRectangle &rect = rTu.getRect(compID);
|
|
const UInt uiWidth = rect.width;
|
|
const UInt uiHeight = rect.height;
|
|
TComDataCU* pcCU = rTu.getCU();
|
|
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
|
|
const UInt uiOrgTrDepth = rTu.GetTransformDepthRel();
|
|
|
|
uiAbsSum=0;
|
|
|
|
RDPCMMode rdpcmMode = RDPCM_OFF;
|
|
rdpcmNxN( rTu, compID, pcResidual, uiStride, cQP, rpcCoeff, uiAbsSum, rdpcmMode );
|
|
|
|
if (rdpcmMode == RDPCM_OFF)
|
|
{
|
|
uiAbsSum = 0;
|
|
//transform and quantise
|
|
if(pcCU->getCUTransquantBypass(uiAbsPartIdx))
|
|
{
|
|
const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID);
|
|
const UInt uiSizeMinus1 = (uiWidth * uiHeight) - 1;
|
|
|
|
for (UInt y = 0, coefficientIndex = 0; y<uiHeight; y++)
|
|
{
|
|
for (UInt x = 0; x<uiWidth; x++, coefficientIndex++)
|
|
{
|
|
const Pel currentSample = pcResidual[(y * uiStride) + x];
|
|
|
|
rpcCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] = currentSample;
|
|
uiAbsSum += TCoeff(abs(currentSample));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_TRANSFORM_AND_QUANTISE
|
|
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at input to transform\n";
|
|
printBlock(pcResidual, uiWidth, uiHeight, uiStride);
|
|
#endif
|
|
|
|
assert( (pcCU->getSlice()->getSPS()->getMaxTrSize() >= uiWidth) );
|
|
|
|
if(pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0)
|
|
{
|
|
xTransformSkip( pcResidual, uiStride, m_plTempCoeff, rTu, compID );
|
|
}
|
|
else
|
|
{
|
|
xT( compID, rTu.useDST(compID), pcResidual, uiStride, m_plTempCoeff, uiWidth, uiHeight );
|
|
}
|
|
|
|
#ifdef DEBUG_TRANSFORM_AND_QUANTISE
|
|
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU between transform and quantiser\n";
|
|
printBlock(m_plTempCoeff, uiWidth, uiHeight, uiWidth);
|
|
#endif
|
|
|
|
xQuant( rTu, m_plTempCoeff, rpcCoeff,
|
|
|
|
#if ADAPTIVE_QP_SELECTION
|
|
pcArlCoeff,
|
|
#endif
|
|
uiAbsSum, compID, cQP );
|
|
|
|
#ifdef DEBUG_TRANSFORM_AND_QUANTISE
|
|
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at output of quantiser\n";
|
|
printBlock(rpcCoeff, uiWidth, uiHeight, uiWidth);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//set the CBF
|
|
pcCU->setCbfPartRange((((uiAbsSum > 0) ? 1 : 0) << uiOrgTrDepth), compID, uiAbsPartIdx, rTu.GetAbsPartIdxNumParts(compID));
|
|
}
|
|
|
|
|
|
Void TComTrQuant::invTransformNxN( TComTU &rTu,
|
|
const ComponentID compID,
|
|
Pel *pcResidual,
|
|
const UInt uiStride,
|
|
TCoeff * pcCoeff,
|
|
const QpParam &cQP
|
|
DEBUG_STRING_FN_DECLAREP(psDebug))
|
|
{
|
|
TComDataCU* pcCU=rTu.getCU();
|
|
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
|
|
const TComRectangle &rect = rTu.getRect(compID);
|
|
const UInt uiWidth = rect.width;
|
|
const UInt uiHeight = rect.height;
|
|
|
|
if (uiWidth != uiHeight) //for intra, the TU will have been split above this level, so this condition won't be true, hence this only affects inter
|
|
{
|
|
//------------------------------------------------
|
|
|
|
//recurse deeper
|
|
|
|
TComTURecurse subTURecurse(rTu, false, TComTU::VERTICAL_SPLIT, true, compID);
|
|
|
|
do
|
|
{
|
|
//------------------
|
|
|
|
const UInt lineOffset = subTURecurse.GetSectionNumber() * subTURecurse.getRect(compID).height;
|
|
|
|
Pel *subTUResidual = pcResidual + (lineOffset * uiStride);
|
|
TCoeff *subTUCoefficients = pcCoeff + (lineOffset * subTURecurse.getRect(compID).width);
|
|
|
|
invTransformNxN(subTURecurse, compID, subTUResidual, uiStride, subTUCoefficients, cQP DEBUG_STRING_PASS_INTO(psDebug));
|
|
|
|
//------------------
|
|
|
|
}
|
|
while (subTURecurse.nextSection(rTu));
|
|
|
|
//------------------------------------------------
|
|
|
|
return;
|
|
}
|
|
|
|
#if defined DEBUG_STRING
|
|
if (psDebug)
|
|
{
|
|
std::stringstream ss(stringstream::out);
|
|
printBlockToStream(ss, (compID==0)?"###InvTran ip Ch0: " : ((compID==1)?"###InvTran ip Ch1: ":"###InvTran ip Ch2: "), pcCoeff, uiWidth, uiHeight, uiWidth);
|
|
DEBUG_STRING_APPEND((*psDebug), ss.str())
|
|
}
|
|
#endif
|
|
|
|
if(pcCU->getCUTransquantBypass(uiAbsPartIdx))
|
|
{
|
|
const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID);
|
|
const UInt uiSizeMinus1 = (uiWidth * uiHeight) - 1;
|
|
|
|
for (UInt y = 0, coefficientIndex = 0; y<uiHeight; y++)
|
|
{
|
|
for (UInt x = 0; x<uiWidth; x++, coefficientIndex++)
|
|
{
|
|
pcResidual[(y * uiStride) + x] = Pel(pcCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_TRANSFORM_AND_QUANTISE
|
|
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at input to dequantiser\n";
|
|
printBlock(pcCoeff, uiWidth, uiHeight, uiWidth);
|
|
#endif
|
|
|
|
xDeQuant(rTu, pcCoeff, m_plTempCoeff, compID, cQP);
|
|
|
|
#ifdef DEBUG_TRANSFORM_AND_QUANTISE
|
|
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU between dequantiser and inverse-transform\n";
|
|
printBlock(m_plTempCoeff, uiWidth, uiHeight, uiWidth);
|
|
#endif
|
|
|
|
#if defined DEBUG_STRING
|
|
if (psDebug)
|
|
{
|
|
std::stringstream ss(stringstream::out);
|
|
printBlockToStream(ss, "###InvTran deq: ", m_plTempCoeff, uiWidth, uiHeight, uiWidth);
|
|
(*psDebug)+=ss.str();
|
|
}
|
|
#endif
|
|
|
|
if(pcCU->getTransformSkip(uiAbsPartIdx, compID))
|
|
{
|
|
xITransformSkip( m_plTempCoeff, pcResidual, uiStride, rTu, compID );
|
|
|
|
#if defined DEBUG_STRING
|
|
if (psDebug)
|
|
{
|
|
std::stringstream ss(stringstream::out);
|
|
printBlockToStream(ss, "###InvTran resi: ", pcResidual, uiWidth, uiHeight, uiStride);
|
|
(*psDebug)+=ss.str();
|
|
(*psDebug)+="(<- was a Transform-skipped block)\n";
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
xIT( compID, rTu.useDST(compID), m_plTempCoeff, pcResidual, uiStride, uiWidth, uiHeight );
|
|
|
|
#if defined DEBUG_STRING
|
|
if (psDebug)
|
|
{
|
|
std::stringstream ss(stringstream::out);
|
|
printBlockToStream(ss, "###InvTran resi: ", pcResidual, uiWidth, uiHeight, uiStride);
|
|
(*psDebug)+=ss.str();
|
|
(*psDebug)+="(<- was a Transformed block)\n";
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef DEBUG_TRANSFORM_AND_QUANTISE
|
|
std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at output of inverse-transform\n";
|
|
printBlock(pcResidual, uiWidth, uiHeight, uiStride);
|
|
g_debugCounter++;
|
|
#endif
|
|
}
|
|
|
|
invRdpcmNxN( rTu, compID, pcResidual, uiStride );
|
|
}
|
|
|
|
Void TComTrQuant::invRecurTransformNxN( const ComponentID compID,
|
|
TComYuv *pResidual,
|
|
TComTU &rTu)
|
|
{
|
|
if (!rTu.ProcessComponentSection(compID)) return;
|
|
|
|
TComDataCU* pcCU = rTu.getCU();
|
|
UInt absPartIdxTU = rTu.GetAbsPartIdxTU();
|
|
UInt uiTrMode=rTu.GetTransformDepthRel();
|
|
if( (pcCU->getCbf(absPartIdxTU, compID, uiTrMode) == 0) && (isLuma(compID) || !pcCU->getSlice()->getPPS()->getUseCrossComponentPrediction()) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( uiTrMode == pcCU->getTransformIdx( absPartIdxTU ) )
|
|
{
|
|
const TComRectangle &tuRect = rTu.getRect(compID);
|
|
const Int uiStride = pResidual->getStride( compID );
|
|
Pel *rpcResidual = pResidual->getAddr( compID );
|
|
UInt uiAddr = (tuRect.x0 + uiStride*tuRect.y0);
|
|
Pel *pResi = rpcResidual + uiAddr;
|
|
TCoeff *pcCoeff = pcCU->getCoeff(compID) + rTu.getCoefficientOffset(compID);
|
|
|
|
const QpParam cQP(*pcCU, compID);
|
|
|
|
if(pcCU->getCbf(absPartIdxTU, compID, uiTrMode) != 0)
|
|
{
|
|
DEBUG_STRING_NEW(sTemp)
|
|
#ifdef DEBUG_STRING
|
|
std::string *psDebug=((DebugOptionList::DebugString_InvTran.getInt()&(pcCU->isIntra(absPartIdxTU)?1:(pcCU->isInter(absPartIdxTU)?2:4)))!=0) ? &sTemp : 0;
|
|
#endif
|
|
|
|
invTransformNxN( rTu, compID, pResi, uiStride, pcCoeff, cQP DEBUG_STRING_PASS_INTO(psDebug) );
|
|
|
|
#ifdef DEBUG_STRING
|
|
if (psDebug != 0)
|
|
std::cout << (*psDebug);
|
|
#endif
|
|
}
|
|
|
|
if (isChroma(compID) && (pcCU->getCrossComponentPredictionAlpha(absPartIdxTU, compID) != 0))
|
|
{
|
|
const Pel *piResiLuma = pResidual->getAddr( COMPONENT_Y );
|
|
const Int strideLuma = pResidual->getStride( COMPONENT_Y );
|
|
const Int tuWidth = rTu.getRect( compID ).width;
|
|
const Int tuHeight = rTu.getRect( compID ).height;
|
|
|
|
if(pcCU->getCbf(absPartIdxTU, COMPONENT_Y, uiTrMode) != 0)
|
|
{
|
|
pResi = rpcResidual + uiAddr;
|
|
const Pel *pResiLuma = piResiLuma + uiAddr;
|
|
|
|
crossComponentPrediction( rTu, compID, pResiLuma, pResi, pResi, tuWidth, tuHeight, strideLuma, uiStride, uiStride, true );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TComTURecurse tuRecurseChild(rTu, false);
|
|
do
|
|
{
|
|
invRecurTransformNxN( compID, pResidual, tuRecurseChild );
|
|
}
|
|
while (tuRecurseChild.nextSection(rTu));
|
|
}
|
|
}
|
|
|
|
Void TComTrQuant::applyForwardRDPCM( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride, const QpParam& cQP, TCoeff* pcCoeff, TCoeff &uiAbsSum, const RDPCMMode mode )
|
|
{
|
|
TComDataCU *pcCU=rTu.getCU();
|
|
const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU();
|
|
|
|
const Bool bLossless = pcCU->getCUTransquantBypass( uiAbsPartIdx );
|
|
const UInt uiWidth = rTu.getRect(compID).width;
|
|
const UInt uiHeight = rTu.getRect(compID).height;
|
|
const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID);
|
|
const UInt uiSizeMinus1 = (uiWidth * uiHeight) - 1;
|
|
|
|
Pel reconstructedResi[MAX_TU_SIZE * MAX_TU_SIZE];
|
|
|
|
UInt uiX = 0;
|
|
UInt uiY = 0;
|
|
|
|
UInt &majorAxis = (mode == RDPCM_HOR) ? uiX : uiY;
|
|
UInt &minorAxis = (mode == RDPCM_HOR) ? uiY : uiX;
|
|
const UInt majorAxisLimit = (mode == RDPCM_HOR) ? uiWidth : uiHeight;
|
|
const UInt minorAxisLimit = (mode == RDPCM_HOR) ? uiHeight : uiWidth;
|
|
const UInt referenceSampleOffset = (mode == RDPCM_HOR) ? 1 : uiWidth;
|
|
|
|
const Bool bUseHalfRoundingPoint = (mode != RDPCM_OFF);
|
|
|
|
uiAbsSum = 0;
|
|
|
|
for ( majorAxis = 0; majorAxis < majorAxisLimit; majorAxis++ )
|
|
{
|
|
for ( minorAxis = 0; minorAxis < minorAxisLimit; minorAxis++ )
|
|
{
|
|
const UInt sampleIndex = (uiY * uiWidth) + uiX;
|
|
const UInt coefficientIndex = (rotateResidual ? (uiSizeMinus1-sampleIndex) : sampleIndex);
|
|
const Pel currentSample = pcResidual[(uiY * uiStride) + uiX];
|
|
const Pel referenceSample = ((mode != RDPCM_OFF) && (majorAxis > 0)) ? reconstructedResi[sampleIndex - referenceSampleOffset] : 0;
|
|
|
|
const Pel encoderSideDelta = currentSample - referenceSample;
|
|
|
|
Pel reconstructedDelta;
|
|
if ( bLossless )
|
|
{
|
|
pcCoeff[coefficientIndex] = encoderSideDelta;
|
|
reconstructedDelta = encoderSideDelta;
|
|
}
|
|
else
|
|
{
|
|
transformSkipQuantOneSample(rTu, compID, encoderSideDelta, pcCoeff, coefficientIndex, cQP, bUseHalfRoundingPoint);
|
|
invTrSkipDeQuantOneSample (rTu, compID, pcCoeff[coefficientIndex], reconstructedDelta, cQP, coefficientIndex);
|
|
}
|
|
|
|
uiAbsSum += abs(pcCoeff[coefficientIndex]);
|
|
|
|
reconstructedResi[sampleIndex] = reconstructedDelta + referenceSample;
|
|
}
|
|
}
|
|
}
|
|
|
|
Void TComTrQuant::rdpcmNxN ( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride, const QpParam& cQP, TCoeff* pcCoeff, TCoeff &uiAbsSum, RDPCMMode& rdpcmMode )
|
|
{
|
|
TComDataCU *pcCU=rTu.getCU();
|
|
const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU();
|
|
|
|
if (!pcCU->isRDPCMEnabled(uiAbsPartIdx) || ((pcCU->getTransformSkip(uiAbsPartIdx, compID) == 0) && !pcCU->getCUTransquantBypass(uiAbsPartIdx)))
|
|
{
|
|
rdpcmMode = RDPCM_OFF;
|
|
}
|
|
else if ( pcCU->isIntra( uiAbsPartIdx ) )
|
|
{
|
|
const ChromaFormat chFmt = pcCU->getPic()->getPicYuvOrg()->getChromaFormat();
|
|
const ChannelType chType = toChannelType(compID);
|
|
const UInt uiChPredMode = pcCU->getIntraDir( chType, uiAbsPartIdx );
|
|
const UInt uiChCodedMode = (uiChPredMode==DM_CHROMA_IDX && isChroma(compID)) ? pcCU->getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, chFmt)) : uiChPredMode;
|
|
const UInt uiChFinalMode = ((chFmt == CHROMA_422) && isChroma(compID)) ? g_chroma422IntraAngleMappingTable[uiChCodedMode] : uiChCodedMode;
|
|
|
|
if (uiChFinalMode == VER_IDX || uiChFinalMode == HOR_IDX)
|
|
{
|
|
rdpcmMode = (uiChFinalMode == VER_IDX) ? RDPCM_VER : RDPCM_HOR;
|
|
applyForwardRDPCM( rTu, compID, pcResidual, uiStride, cQP, pcCoeff, uiAbsSum, rdpcmMode );
|
|
}
|
|
else rdpcmMode = RDPCM_OFF;
|
|
}
|
|
else // not intra, need to select the best mode
|
|
{
|
|
const UInt uiWidth = rTu.getRect(compID).width;
|
|
const UInt uiHeight = rTu.getRect(compID).height;
|
|
|
|
RDPCMMode bestMode = NUMBER_OF_RDPCM_MODES;
|
|
TCoeff bestAbsSum = std::numeric_limits<TCoeff>::max();
|
|
TCoeff bestCoefficients[MAX_TU_SIZE * MAX_TU_SIZE];
|
|
|
|
for (UInt modeIndex = 0; modeIndex < NUMBER_OF_RDPCM_MODES; modeIndex++)
|
|
{
|
|
const RDPCMMode mode = RDPCMMode(modeIndex);
|
|
|
|
TCoeff currAbsSum = 0;
|
|
|
|
applyForwardRDPCM( rTu, compID, pcResidual, uiStride, cQP, pcCoeff, currAbsSum, mode );
|
|
|
|
if (currAbsSum < bestAbsSum)
|
|
{
|
|
bestMode = mode;
|
|
bestAbsSum = currAbsSum;
|
|
if (mode != RDPCM_OFF)
|
|
{
|
|
memcpy(bestCoefficients, pcCoeff, (uiWidth * uiHeight * sizeof(TCoeff)));
|
|
}
|
|
}
|
|
}
|
|
|
|
rdpcmMode = bestMode;
|
|
uiAbsSum = bestAbsSum;
|
|
|
|
if (rdpcmMode != RDPCM_OFF) //the TU is re-transformed and quantised if DPCM_OFF is returned, so there is no need to preserve it here
|
|
{
|
|
memcpy(pcCoeff, bestCoefficients, (uiWidth * uiHeight * sizeof(TCoeff)));
|
|
}
|
|
}
|
|
|
|
pcCU->setExplicitRdpcmModePartRange(rdpcmMode, compID, uiAbsPartIdx, rTu.GetAbsPartIdxNumParts(compID));
|
|
}
|
|
|
|
Void TComTrQuant::invRdpcmNxN( TComTU& rTu, const ComponentID compID, Pel* pcResidual, const UInt uiStride )
|
|
{
|
|
TComDataCU *pcCU=rTu.getCU();
|
|
const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU();
|
|
|
|
if (pcCU->isRDPCMEnabled( uiAbsPartIdx ) && ((pcCU->getTransformSkip(uiAbsPartIdx, compID ) != 0) || pcCU->getCUTransquantBypass(uiAbsPartIdx)))
|
|
{
|
|
const UInt uiWidth = rTu.getRect(compID).width;
|
|
const UInt uiHeight = rTu.getRect(compID).height;
|
|
|
|
RDPCMMode rdpcmMode = RDPCM_OFF;
|
|
|
|
if ( pcCU->isIntra( uiAbsPartIdx ) )
|
|
{
|
|
const ChromaFormat chFmt = pcCU->getPic()->getPicYuvRec()->getChromaFormat();
|
|
const ChannelType chType = toChannelType(compID);
|
|
const UInt uiChPredMode = pcCU->getIntraDir( chType, uiAbsPartIdx );
|
|
const UInt uiChCodedMode = (uiChPredMode==DM_CHROMA_IDX && isChroma(compID)) ? pcCU->getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, chFmt)) : uiChPredMode;
|
|
const UInt uiChFinalMode = ((chFmt == CHROMA_422) && isChroma(compID)) ? g_chroma422IntraAngleMappingTable[uiChCodedMode] : uiChCodedMode;
|
|
|
|
if (uiChFinalMode == VER_IDX || uiChFinalMode == HOR_IDX)
|
|
{
|
|
rdpcmMode = (uiChFinalMode == VER_IDX) ? RDPCM_VER : RDPCM_HOR;
|
|
}
|
|
}
|
|
else // not intra case
|
|
{
|
|
rdpcmMode = RDPCMMode(pcCU->getExplicitRdpcmMode( compID, uiAbsPartIdx ));
|
|
}
|
|
|
|
if (rdpcmMode == RDPCM_VER)
|
|
{
|
|
pcResidual += uiStride; //start from row 1
|
|
|
|
for( UInt uiY = 1; uiY < uiHeight; uiY++ )
|
|
{
|
|
for( UInt uiX = 0; uiX < uiWidth; uiX++ )
|
|
{
|
|
pcResidual[ uiX ] = pcResidual[ uiX ] + pcResidual [ (Int)uiX - (Int)uiStride ];
|
|
}
|
|
pcResidual += uiStride;
|
|
}
|
|
}
|
|
else if (rdpcmMode == RDPCM_HOR)
|
|
{
|
|
for( UInt uiY = 0; uiY < uiHeight; uiY++ )
|
|
{
|
|
for( UInt uiX = 1; uiX < uiWidth; uiX++ )
|
|
{
|
|
pcResidual[ uiX ] = pcResidual[ uiX ] + pcResidual [ (Int)uiX-1 ];
|
|
}
|
|
pcResidual += uiStride;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Logical transform
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
/** Wrapper function between HM interface and core NxN forward transform (2D)
|
|
* \param piBlkResi input data (residual)
|
|
* \param psCoeff output data (transform coefficients)
|
|
* \param uiStride stride of input residual data
|
|
* \param iSize transform size (iSize x iSize)
|
|
* \param uiMode is Intra Prediction mode used in Mode-Dependent DCT/DST only
|
|
*/
|
|
Void TComTrQuant::xT( const ComponentID compID, Bool useDST, Pel* piBlkResi, UInt uiStride, TCoeff* psCoeff, Int iWidth, Int iHeight )
|
|
{
|
|
#if MATRIX_MULT
|
|
if( iWidth == iHeight)
|
|
{
|
|
xTr(g_bitDepth[toChannelType(compID)], piBlkResi, psCoeff, uiStride, (UInt)iWidth, useDST, g_maxTrDynamicRange[toChannelType(compID)]);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
TCoeff block[ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
TCoeff coeff[ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
|
|
for (Int y = 0; y < iHeight; y++)
|
|
for (Int x = 0; x < iWidth; x++)
|
|
{
|
|
block[(y * iWidth) + x] = piBlkResi[(y * uiStride) + x];
|
|
}
|
|
|
|
xTrMxN( g_bitDepth[toChannelType(compID)], block, coeff, iWidth, iHeight, useDST, g_maxTrDynamicRange[toChannelType(compID)] );
|
|
|
|
memcpy(psCoeff, coeff, (iWidth * iHeight * sizeof(TCoeff)));
|
|
}
|
|
|
|
/** Wrapper function between HM interface and core NxN inverse transform (2D)
|
|
* \param plCoef input data (transform coefficients)
|
|
* \param pResidual output data (residual)
|
|
* \param uiStride stride of input residual data
|
|
* \param iSize transform size (iSize x iSize)
|
|
* \param uiMode is Intra Prediction mode used in Mode-Dependent DCT/DST only
|
|
*/
|
|
Void TComTrQuant::xIT( const ComponentID compID, Bool useDST, TCoeff* plCoef, Pel* pResidual, UInt uiStride, Int iWidth, Int iHeight )
|
|
{
|
|
#if MATRIX_MULT
|
|
if( iWidth == iHeight )
|
|
{
|
|
#if O0043_BEST_EFFORT_DECODING
|
|
xITr(g_bitDepthInStream[toChannelType(compID)], plCoef, pResidual, uiStride, (UInt)iWidth, useDST, g_maxTrDynamicRange[toChannelType(compID)]);
|
|
#else
|
|
xITr(g_bitDepth[toChannelType(compID)], plCoef, pResidual, uiStride, (UInt)iWidth, useDST, g_maxTrDynamicRange[toChannelType(compID)]);
|
|
#endif
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
TCoeff block[ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
TCoeff coeff[ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
|
|
memcpy(coeff, plCoef, (iWidth * iHeight * sizeof(TCoeff)));
|
|
|
|
#if O0043_BEST_EFFORT_DECODING
|
|
xITrMxN( g_bitDepthInStream[toChannelType(compID)], coeff, block, iWidth, iHeight, useDST, g_maxTrDynamicRange[toChannelType(compID)] );
|
|
#else
|
|
xITrMxN( g_bitDepth[toChannelType(compID)], coeff, block, iWidth, iHeight, useDST, g_maxTrDynamicRange[toChannelType(compID)] );
|
|
#endif
|
|
|
|
for (Int y = 0; y < iHeight; y++)
|
|
for (Int x = 0; x < iWidth; x++)
|
|
{
|
|
pResidual[(y * uiStride) + x] = Pel(block[(y * iWidth) + x]);
|
|
}
|
|
}
|
|
|
|
/** Wrapper function between HM interface and core 4x4 transform skipping
|
|
* \param piBlkResi input data (residual)
|
|
* \param psCoeff output data (transform coefficients)
|
|
* \param uiStride stride of input residual data
|
|
* \param iSize transform size (iSize x iSize)
|
|
*/
|
|
Void TComTrQuant::xTransformSkip( Pel* piBlkResi, UInt uiStride, TCoeff* psCoeff, TComTU &rTu, const ComponentID component )
|
|
{
|
|
const TComRectangle &rect = rTu.getRect(component);
|
|
const Int width = rect.width;
|
|
const Int height = rect.height;
|
|
|
|
Int iTransformShift = getTransformShift(toChannelType(component), rTu.GetEquivalentLog2TrSize(component));
|
|
if (rTu.getCU()->getSlice()->getSPS()->getUseExtendedPrecision())
|
|
{
|
|
iTransformShift = std::max<Int>(0, iTransformShift);
|
|
}
|
|
|
|
const Bool rotateResidual = rTu.isNonTransformedResidualRotated(component);
|
|
const UInt uiSizeMinus1 = (width * height) - 1;
|
|
|
|
if (iTransformShift >= 0)
|
|
{
|
|
for (UInt y = 0, coefficientIndex = 0; y < height; y++)
|
|
{
|
|
for (UInt x = 0; x < width; x++, coefficientIndex++)
|
|
{
|
|
psCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] = TCoeff(piBlkResi[(y * uiStride) + x]) << iTransformShift;
|
|
}
|
|
}
|
|
}
|
|
else //for very high bit depths
|
|
{
|
|
iTransformShift = -iTransformShift;
|
|
const TCoeff offset = 1 << (iTransformShift - 1);
|
|
|
|
for (UInt y = 0, coefficientIndex = 0; y < height; y++)
|
|
{
|
|
for (UInt x = 0; x < width; x++, coefficientIndex++)
|
|
{
|
|
psCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] = (TCoeff(piBlkResi[(y * uiStride) + x]) + offset) >> iTransformShift;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Wrapper function between HM interface and core NxN transform skipping
|
|
* \param plCoef input data (coefficients)
|
|
* \param pResidual output data (residual)
|
|
* \param uiStride stride of input residual data
|
|
* \param iSize transform size (iSize x iSize)
|
|
*/
|
|
Void TComTrQuant::xITransformSkip( TCoeff* plCoef, Pel* pResidual, UInt uiStride, TComTU &rTu, const ComponentID component )
|
|
{
|
|
const TComRectangle &rect = rTu.getRect(component);
|
|
const Int width = rect.width;
|
|
const Int height = rect.height;
|
|
|
|
Int iTransformShift = getTransformShift(toChannelType(component), rTu.GetEquivalentLog2TrSize(component));
|
|
if (rTu.getCU()->getSlice()->getSPS()->getUseExtendedPrecision())
|
|
{
|
|
iTransformShift = std::max<Int>(0, iTransformShift);
|
|
}
|
|
|
|
const Bool rotateResidual = rTu.isNonTransformedResidualRotated(component);
|
|
const UInt uiSizeMinus1 = (width * height) - 1;
|
|
|
|
if (iTransformShift >= 0)
|
|
{
|
|
const TCoeff offset = iTransformShift==0 ? 0 : (1 << (iTransformShift - 1));
|
|
|
|
for (UInt y = 0, coefficientIndex = 0; y < height; y++)
|
|
{
|
|
for (UInt x = 0; x < width; x++, coefficientIndex++)
|
|
{
|
|
pResidual[(y * uiStride) + x] = Pel((plCoef[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] + offset) >> iTransformShift);
|
|
}
|
|
}
|
|
}
|
|
else //for very high bit depths
|
|
{
|
|
iTransformShift = -iTransformShift;
|
|
|
|
for (UInt y = 0, coefficientIndex = 0; y < height; y++)
|
|
{
|
|
for (UInt x = 0; x < width; x++, coefficientIndex++)
|
|
{
|
|
pResidual[(y * uiStride) + x] = Pel(plCoef[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] << iTransformShift);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** RDOQ with CABAC
|
|
* \param pcCU pointer to coding unit structure
|
|
* \param plSrcCoeff pointer to input buffer
|
|
* \param piDstCoeff reference to pointer to output buffer
|
|
* \param uiWidth block width
|
|
* \param uiHeight block height
|
|
* \param uiAbsSum reference to absolute sum of quantized transform coefficient
|
|
* \param eTType plane type / luminance or chrominance
|
|
* \param uiAbsPartIdx absolute partition index
|
|
* \returns Void
|
|
* Rate distortion optimized quantization for entropy
|
|
* coding engines using probability models like CABAC
|
|
*/
|
|
Void TComTrQuant::xRateDistOptQuant ( TComTU &rTu,
|
|
TCoeff * plSrcCoeff,
|
|
TCoeff * piDstCoeff,
|
|
#if ADAPTIVE_QP_SELECTION
|
|
TCoeff * piArlDstCoeff,
|
|
#endif
|
|
TCoeff &uiAbsSum,
|
|
const ComponentID compID,
|
|
const QpParam &cQP )
|
|
{
|
|
const TComRectangle & rect = rTu.getRect(compID);
|
|
const UInt uiWidth = rect.width;
|
|
const UInt uiHeight = rect.height;
|
|
TComDataCU * pcCU = rTu.getCU();
|
|
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
|
|
const ChannelType channelType = toChannelType(compID);
|
|
const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID);
|
|
|
|
const Bool extendedPrecision = pcCU->getSlice()->getSPS()->getUseExtendedPrecision();
|
|
|
|
/* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be
|
|
* implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the
|
|
* uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller)
|
|
* Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result
|
|
*/
|
|
|
|
// Represents scaling through forward transform
|
|
Int iTransformShift = getTransformShift(channelType, uiLog2TrSize);
|
|
if ((pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0) && pcCU->getSlice()->getSPS()->getUseExtendedPrecision())
|
|
{
|
|
iTransformShift = std::max<Int>(0, iTransformShift);
|
|
}
|
|
|
|
const Bool bUseGolombRiceParameterAdaptation = pcCU->getSlice()->getSPS()->getUseGolombRiceParameterAdaptation();
|
|
const UInt initialGolombRiceParameter = m_pcEstBitsSbac->golombRiceAdaptationStatistics[rTu.getGolombRiceStatisticsIndex(compID)] / RExt__GOLOMB_RICE_INCREMENT_DIVISOR;
|
|
UInt uiGoRiceParam = initialGolombRiceParameter;
|
|
Double d64BlockUncodedCost = 0;
|
|
const UInt uiLog2BlockWidth = g_aucConvertToBit[ uiWidth ] + 2;
|
|
const UInt uiLog2BlockHeight = g_aucConvertToBit[ uiHeight ] + 2;
|
|
const UInt uiMaxNumCoeff = uiWidth * uiHeight;
|
|
assert(compID<MAX_NUM_COMPONENT);
|
|
|
|
Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID);
|
|
assert(scalingListType < SCALING_LIST_NUM);
|
|
|
|
#if ADAPTIVE_QP_SELECTION
|
|
memset(piArlDstCoeff, 0, sizeof(TCoeff) * uiMaxNumCoeff);
|
|
#endif
|
|
|
|
Double pdCostCoeff [ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
Double pdCostSig [ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
Double pdCostCoeff0[ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
memset( pdCostCoeff, 0, sizeof(Double) * uiMaxNumCoeff );
|
|
memset( pdCostSig, 0, sizeof(Double) * uiMaxNumCoeff );
|
|
Int rateIncUp [ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
Int rateIncDown [ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
Int sigRateDelta[ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
TCoeff deltaU [ MAX_TU_SIZE * MAX_TU_SIZE ];
|
|
memset( rateIncUp, 0, sizeof(Int ) * uiMaxNumCoeff );
|
|
memset( rateIncDown, 0, sizeof(Int ) * uiMaxNumCoeff );
|
|
memset( sigRateDelta, 0, sizeof(Int ) * uiMaxNumCoeff );
|
|
memset( deltaU, 0, sizeof(TCoeff) * uiMaxNumCoeff );
|
|
|
|
const Int iQBits = QUANT_SHIFT + cQP.per + iTransformShift; // Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits
|
|
const Double *const pdErrScale = getErrScaleCoeff(scalingListType, (uiLog2TrSize-2), cQP.rem);
|
|
const Int *const piQCoef = getQuantCoeff(scalingListType, cQP.rem, (uiLog2TrSize-2));
|
|
|
|
const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0));
|
|
const Int defaultQuantisationCoefficient = g_quantScales[cQP.rem];
|
|
const Double defaultErrorScale = getErrScaleCoeffNoScalingList(scalingListType, (uiLog2TrSize-2), cQP.rem);
|
|
|
|
const TCoeff entropyCodingMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]);
|
|
const TCoeff entropyCodingMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1;
|
|
|
|
#if ADAPTIVE_QP_SELECTION
|
|
Int iQBitsC = iQBits - ARL_C_PRECISION;
|
|
Int iAddC = 1 << (iQBitsC-1);
|
|
#endif
|
|
|
|
TUEntropyCodingParameters codingParameters;
|
|
getTUEntropyCodingParameters(codingParameters, rTu, compID);
|
|
const UInt uiCGSize = (1 << MLS_CG_SIZE);
|
|
|
|
Double pdCostCoeffGroupSig[ MLS_GRP_NUM ];
|
|
UInt uiSigCoeffGroupFlag[ MLS_GRP_NUM ];
|
|
Int iCGLastScanPos = -1;
|
|
|
|
UInt uiCtxSet = 0;
|
|
Int c1 = 1;
|
|
Int c2 = 0;
|
|
Double d64BaseCost = 0;
|
|
Int iLastScanPos = -1;
|
|
|
|
UInt c1Idx = 0;
|
|
UInt c2Idx = 0;
|
|
Int baseLevel;
|
|
|
|
memset( pdCostCoeffGroupSig, 0, sizeof(Double) * MLS_GRP_NUM );
|
|
memset( uiSigCoeffGroupFlag, 0, sizeof(UInt) * MLS_GRP_NUM );
|
|
|
|
UInt uiCGNum = uiWidth * uiHeight >> MLS_CG_SIZE;
|
|
Int iScanPos;
|
|
coeffGroupRDStats rdStats;
|
|
|
|
const UInt significanceMapContextOffset = getSignificanceMapContextOffset(compID);
|
|
|
|
for (Int iCGScanPos = uiCGNum-1; iCGScanPos >= 0; iCGScanPos--)
|
|
{
|
|
UInt uiCGBlkPos = codingParameters.scanCG[ iCGScanPos ];
|
|
UInt uiCGPosY = uiCGBlkPos / codingParameters.widthInGroups;
|
|
UInt uiCGPosX = uiCGBlkPos - (uiCGPosY * codingParameters.widthInGroups);
|
|
|
|
memset( &rdStats, 0, sizeof (coeffGroupRDStats));
|
|
|
|
const Int patternSigCtx = TComTrQuant::calcPatternSigCtx(uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups);
|
|
|
|
for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--)
|
|
{
|
|
iScanPos = iCGScanPos*uiCGSize + iScanPosinCG;
|
|
//===== quantization =====
|
|
UInt uiBlkPos = codingParameters.scan[iScanPos];
|
|
// set coeff
|
|
|
|
const Int quantisationCoefficient = (enableScalingLists) ? piQCoef [uiBlkPos] : defaultQuantisationCoefficient;
|
|
const Double errorScale = (enableScalingLists) ? pdErrScale[uiBlkPos] : defaultErrorScale;
|
|
|
|
const Int64 tmpLevel = Int64(abs(plSrcCoeff[ uiBlkPos ])) * quantisationCoefficient;
|
|
|
|
const Intermediate_Int lLevelDouble = (Intermediate_Int)min<Int64>(tmpLevel, MAX_INTERMEDIATE_INT - (Intermediate_Int(1) << (iQBits - 1)));
|
|
|
|
#if ADAPTIVE_QP_SELECTION
|
|
if( m_bUseAdaptQpSelect )
|
|
{
|
|
piArlDstCoeff[uiBlkPos] = (TCoeff)(( lLevelDouble + iAddC) >> iQBitsC );
|
|
}
|
|
#endif
|
|
const UInt uiMaxAbsLevel = std::min<UInt>(UInt(entropyCodingMaximum), UInt((lLevelDouble + (Intermediate_Int(1) << (iQBits - 1))) >> iQBits));
|
|
|
|
const Double dErr = Double( lLevelDouble );
|
|
pdCostCoeff0[ iScanPos ] = dErr * dErr * errorScale;
|
|
d64BlockUncodedCost += pdCostCoeff0[ iScanPos ];
|
|
piDstCoeff[ uiBlkPos ] = uiMaxAbsLevel;
|
|
|
|
if ( uiMaxAbsLevel > 0 && iLastScanPos < 0 )
|
|
{
|
|
iLastScanPos = iScanPos;
|
|
uiCtxSet = getContextSetIndex(compID, (iScanPos >> MLS_CG_SIZE), 0);
|
|
iCGLastScanPos = iCGScanPos;
|
|
}
|
|
|
|
if ( iLastScanPos >= 0 )
|
|
{
|
|
//===== coefficient level estimation =====
|
|
UInt uiLevel;
|
|
UInt uiOneCtx = (NUM_ONE_FLAG_CTX_PER_SET * uiCtxSet) + c1;
|
|
UInt uiAbsCtx = (NUM_ABS_FLAG_CTX_PER_SET * uiCtxSet) + c2;
|
|
|
|
if( iScanPos == iLastScanPos )
|
|
{
|
|
uiLevel = xGetCodedLevel( pdCostCoeff[ iScanPos ], pdCostCoeff0[ iScanPos ], pdCostSig[ iScanPos ],
|
|
lLevelDouble, uiMaxAbsLevel, significanceMapContextOffset, uiOneCtx, uiAbsCtx, uiGoRiceParam,
|
|
c1Idx, c2Idx, iQBits, errorScale, 1, extendedPrecision, channelType
|
|
);
|
|
}
|
|
else
|
|
{
|
|
UShort uiCtxSig = significanceMapContextOffset + getSigCtxInc( patternSigCtx, codingParameters, iScanPos, uiLog2BlockWidth, uiLog2BlockHeight, channelType );
|
|
|
|
uiLevel = xGetCodedLevel( pdCostCoeff[ iScanPos ], pdCostCoeff0[ iScanPos ], pdCostSig[ iScanPos ],
|
|
lLevelDouble, uiMaxAbsLevel, uiCtxSig, uiOneCtx, uiAbsCtx, uiGoRiceParam,
|
|
c1Idx, c2Idx, iQBits, errorScale, 0, extendedPrecision, channelType
|
|
);
|
|
|
|
sigRateDelta[ uiBlkPos ] = m_pcEstBitsSbac->significantBits[ uiCtxSig ][ 1 ] - m_pcEstBitsSbac->significantBits[ uiCtxSig ][ 0 ];
|
|
}
|
|
|
|
deltaU[ uiBlkPos ] = TCoeff((lLevelDouble - (Intermediate_Int(uiLevel) << iQBits)) >> (iQBits-8));
|
|
|
|
if( uiLevel > 0 )
|
|
{
|
|
Int rateNow = xGetICRate( uiLevel, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx, extendedPrecision, channelType );
|
|
rateIncUp [ uiBlkPos ] = xGetICRate( uiLevel+1, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx, extendedPrecision, channelType ) - rateNow;
|
|
rateIncDown [ uiBlkPos ] = xGetICRate( uiLevel-1, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx, extendedPrecision, channelType ) - rateNow;
|
|
}
|
|
else // uiLevel == 0
|
|
{
|
|
rateIncUp [ uiBlkPos ] = m_pcEstBitsSbac->m_greaterOneBits[ uiOneCtx ][ 0 ];
|
|
}
|
|
piDstCoeff[ uiBlkPos ] = uiLevel;
|
|
d64BaseCost += pdCostCoeff [ iScanPos ];
|
|
|
|
baseLevel = (c1Idx < C1FLAG_NUMBER) ? (2 + (c2Idx < C2FLAG_NUMBER)) : 1;
|
|
if( uiLevel >= baseLevel )
|
|
{
|
|
if (uiLevel > 3*(1<<uiGoRiceParam))
|
|
{
|
|
uiGoRiceParam = bUseGolombRiceParameterAdaptation ? (uiGoRiceParam + 1) : (std::min<UInt>((uiGoRiceParam + 1), 4));
|
|
}
|
|
}
|
|
if ( uiLevel >= 1)
|
|
{
|
|
c1Idx ++;
|
|
}
|
|
|
|
//===== update bin model =====
|
|
if( uiLevel > 1 )
|
|
{
|
|
c1 = 0;
|
|
c2 += (c2 < 2);
|
|
c2Idx ++;
|
|
}
|
|
else if( (c1 < 3) && (c1 > 0) && uiLevel)
|
|
{
|
|
c1++;
|
|
}
|
|
|
|
//===== context set update =====
|
|
if( ( iScanPos % uiCGSize == 0 ) && ( iScanPos > 0 ) )
|
|
{
|
|
uiCtxSet = getContextSetIndex(compID, ((iScanPos - 1) >> MLS_CG_SIZE), (c1 == 0)); //(iScanPos - 1) because we do this **before** entering the final group
|
|
c1 = 1;
|
|
c2 = 0;
|
|
c1Idx = 0;
|
|
c2Idx = 0;
|
|
uiGoRiceParam = initialGolombRiceParameter;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
d64BaseCost += pdCostCoeff0[ iScanPos ];
|
|
}
|
|
rdStats.d64SigCost += pdCostSig[ iScanPos ];
|
|
if (iScanPosinCG == 0 )
|
|
{
|
|
rdStats.d64SigCost_0 = pdCostSig[ iScanPos ];
|
|
}
|
|
if (piDstCoeff[ uiBlkPos ] )
|
|
{
|
|
uiSigCoeffGroupFlag[ uiCGBlkPos ] = 1;
|
|
rdStats.d64CodedLevelandDist += pdCostCoeff[ iScanPos ] - pdCostSig[ iScanPos ];
|
|
rdStats.d64UncodedDist += pdCostCoeff0[ iScanPos ];
|
|
if ( iScanPosinCG != 0 )
|
|
{
|
|
rdStats.iNNZbeforePos0++;
|
|
}
|
|
}
|
|
} //end for (iScanPosinCG)
|
|
|
|
if (iCGLastScanPos >= 0)
|
|
{
|
|
if( iCGScanPos )
|
|
{
|
|
if (uiSigCoeffGroupFlag[ uiCGBlkPos ] == 0)
|
|
{
|
|
UInt uiCtxSig = getSigCoeffGroupCtxInc( uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups );
|
|
d64BaseCost += xGetRateSigCoeffGroup(0, uiCtxSig) - rdStats.d64SigCost;;
|
|
pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(0, uiCtxSig);
|
|
}
|
|
else
|
|
{
|
|
if (iCGScanPos < iCGLastScanPos) //skip the last coefficient group, which will be handled together with last position below.
|
|
{
|
|
if ( rdStats.iNNZbeforePos0 == 0 )
|
|
{
|
|
d64BaseCost -= rdStats.d64SigCost_0;
|
|
rdStats.d64SigCost -= rdStats.d64SigCost_0;
|
|
}
|
|
// rd-cost if SigCoeffGroupFlag = 0, initialization
|
|
Double d64CostZeroCG = d64BaseCost;
|
|
|
|
// add SigCoeffGroupFlag cost to total cost
|
|
UInt uiCtxSig = getSigCoeffGroupCtxInc( uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, codingParameters.widthInGroups, codingParameters.heightInGroups );
|
|
|
|
if (iCGScanPos < iCGLastScanPos)
|
|
{
|
|
d64BaseCost += xGetRateSigCoeffGroup(1, uiCtxSig);
|
|
d64CostZeroCG += xGetRateSigCoeffGroup(0, uiCtxSig);
|
|
pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(1, uiCtxSig);
|
|
}
|
|
|
|
// try to convert the current coeff group from non-zero to all-zero
|
|
d64CostZeroCG += rdStats.d64UncodedDist; // distortion for resetting non-zero levels to zero levels
|
|
d64CostZeroCG -= rdStats.d64CodedLevelandDist; // distortion and level cost for keeping all non-zero levels
|
|
d64CostZeroCG -= rdStats.d64SigCost; // sig cost for all coeffs, including zero levels and non-zerl levels
|
|
|
|
// if we can save cost, change this block to all-zero block
|
|
if ( d64CostZeroCG < d64BaseCost )
|
|
{
|
|
uiSigCoeffGroupFlag[ uiCGBlkPos ] = 0;
|
|
d64BaseCost = d64CostZeroCG;
|
|
if (iCGScanPos < iCGLastScanPos)
|
|
{
|
|
pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(0, uiCtxSig);
|
|
}
|
|
// reset coeffs to 0 in this block
|
|
for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--)
|
|
{
|
|
iScanPos = iCGScanPos*uiCGSize + iScanPosinCG;
|
|
UInt uiBlkPos = codingParameters.scan[ iScanPos ];
|
|
|
|
if (piDstCoeff[ uiBlkPos ])
|
|
{
|
|
piDstCoeff [ uiBlkPos ] = 0;
|
|
pdCostCoeff[ iScanPos ] = pdCostCoeff0[ iScanPos ];
|
|
pdCostSig [ iScanPos ] = 0;
|
|
}
|
|
}
|
|
} // end if ( d64CostAllZeros < d64BaseCost )
|
|
}
|
|
} // end if if (uiSigCoeffGroupFlag[ uiCGBlkPos ] == 0)
|
|
}
|
|
else
|
|
{
|
|
uiSigCoeffGroupFlag[ uiCGBlkPos ] = 1;
|
|
}
|
|
}
|
|
} //end for (iCGScanPos)
|
|
|
|
//===== estimate last position =====
|
|
if ( iLastScanPos < 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
Double d64BestCost = 0;
|
|
Int ui16CtxCbf = 0;
|
|
Int iBestLastIdxP1 = 0;
|
|
if( !pcCU->isIntra( uiAbsPartIdx ) && isLuma(compID) && pcCU->getTransformIdx( uiAbsPartIdx ) == 0 )
|
|
{
|
|
ui16CtxCbf = 0;
|
|
d64BestCost = d64BlockUncodedCost + xGetICost( m_pcEstBitsSbac->blockRootCbpBits[ ui16CtxCbf ][ 0 ] );
|
|
d64BaseCost += xGetICost( m_pcEstBitsSbac->blockRootCbpBits[ ui16CtxCbf ][ 1 ] );
|
|
}
|
|
else
|
|
{
|
|
ui16CtxCbf = pcCU->getCtxQtCbf( rTu, channelType );
|
|
ui16CtxCbf += getCBFContextOffset(compID);
|
|
d64BestCost = d64BlockUncodedCost + xGetICost( m_pcEstBitsSbac->blockCbpBits[ ui16CtxCbf ][ 0 ] );
|
|
d64BaseCost += xGetICost( m_pcEstBitsSbac->blockCbpBits[ ui16CtxCbf ][ 1 ] );
|
|
}
|
|
|
|
|
|
Bool bFoundLast = false;
|
|
for (Int iCGScanPos = iCGLastScanPos; iCGScanPos >= 0; iCGScanPos--)
|
|
{
|
|
UInt uiCGBlkPos = codingParameters.scanCG[ iCGScanPos ];
|
|
|
|
d64BaseCost -= pdCostCoeffGroupSig [ iCGScanPos ];
|
|
if (uiSigCoeffGroupFlag[ uiCGBlkPos ])
|
|
{
|
|
for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--)
|
|
{
|
|
iScanPos = iCGScanPos*uiCGSize + iScanPosinCG;
|
|
|
|
if (iScanPos > iLastScanPos) continue;
|
|
UInt uiBlkPos = codingParameters.scan[iScanPos];
|
|
|
|
if( piDstCoeff[ uiBlkPos ] )
|
|
{
|
|
UInt uiPosY = uiBlkPos >> uiLog2BlockWidth;
|
|
UInt uiPosX = uiBlkPos - ( uiPosY << uiLog2BlockWidth );
|
|
|
|
Double d64CostLast= codingParameters.scanType == SCAN_VER ? xGetRateLast( uiPosY, uiPosX, compID ) : xGetRateLast( uiPosX, uiPosY, compID );
|
|
Double totalCost = d64BaseCost + d64CostLast - pdCostSig[ iScanPos ];
|
|
|
|
if( totalCost < d64BestCost )
|
|
{
|
|
iBestLastIdxP1 = iScanPos + 1;
|
|
d64BestCost = totalCost;
|
|
}
|
|
if( piDstCoeff[ uiBlkPos ] > 1 )
|
|
{
|
|
bFoundLast = true;
|
|
break;
|
|
}
|
|
d64BaseCost -= pdCostCoeff[ iScanPos ];
|
|
d64BaseCost += pdCostCoeff0[ iScanPos ];
|
|
}
|
|
else
|
|
{
|
|
d64BaseCost -= pdCostSig[ iScanPos ];
|
|
}
|
|
} //end for
|
|
if (bFoundLast)
|
|
{
|
|
break;
|
|
}
|
|
} // end if (uiSigCoeffGroupFlag[ uiCGBlkPos ])
|
|
} // end for
|
|
|
|
|
|
for ( Int scanPos = 0; scanPos < iBestLastIdxP1; scanPos++ )
|
|
{
|
|
Int blkPos = codingParameters.scan[ scanPos ];
|
|
TCoeff level = piDstCoeff[ blkPos ];
|
|
uiAbsSum += level;
|
|
piDstCoeff[ blkPos ] = ( plSrcCoeff[ blkPos ] < 0 ) ? -level : level;
|
|
}
|
|
|
|
//===== clean uncoded coefficients =====
|
|
for ( Int scanPos = iBestLastIdxP1; scanPos <= iLastScanPos; scanPos++ )
|
|
{
|
|
piDstCoeff[ codingParameters.scan[ scanPos ] ] = 0;
|
|
}
|
|
|
|
|
|
if( pcCU->getSlice()->getPPS()->getSignHideFlag() && uiAbsSum>=2)
|
|
{
|
|
const Double inverseQuantScale = Double(g_invQuantScales[cQP.rem]);
|
|
Int64 rdFactor = (Int64)(inverseQuantScale * inverseQuantScale * (1 << (2 * cQP.per))
|
|
/ m_dLambda / 16 / (1 << (2 * DISTORTION_PRECISION_ADJUSTMENT(g_bitDepth[channelType] - 8)))
|
|
+ 0.5);
|
|
|
|
Int lastCG = -1;
|
|
Int absSum = 0 ;
|
|
Int n ;
|
|
|
|
for( Int subSet = (uiWidth*uiHeight-1) >> MLS_CG_SIZE; subSet >= 0; subSet-- )
|
|
{
|
|
Int subPos = subSet << MLS_CG_SIZE;
|
|
Int firstNZPosInCG=uiCGSize , lastNZPosInCG=-1 ;
|
|
absSum = 0 ;
|
|
|
|
for(n = uiCGSize-1; n >= 0; --n )
|
|
{
|
|
if( piDstCoeff[ codingParameters.scan[ n + subPos ]] )
|
|
{
|
|
lastNZPosInCG = n;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(n = 0; n <uiCGSize; n++ )
|
|
{
|
|
if( piDstCoeff[ codingParameters.scan[ n + subPos ]] )
|
|
{
|
|
firstNZPosInCG = n;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(n = firstNZPosInCG; n <=lastNZPosInCG; n++ )
|
|
{
|
|
absSum += Int(piDstCoeff[ codingParameters.scan[ n + subPos ]]);
|
|
}
|
|
|
|
if(lastNZPosInCG>=0 && lastCG==-1)
|
|
{
|
|
lastCG = 1;
|
|
}
|
|
|
|
if( lastNZPosInCG-firstNZPosInCG>=SBH_THRESHOLD )
|
|
{
|
|
UInt signbit = (piDstCoeff[codingParameters.scan[subPos+firstNZPosInCG]]>0?0:1);
|
|
if( signbit!=(absSum&0x1) ) // hide but need tune
|
|
{
|
|
// calculate the cost
|
|
Int64 minCostInc = MAX_INT64, curCost = MAX_INT64;
|
|
Int minPos = -1, finalChange = 0, curChange = 0;
|
|
|
|
for( n = (lastCG==1?lastNZPosInCG:uiCGSize-1) ; n >= 0; --n )
|
|
{
|
|
UInt uiBlkPos = codingParameters.scan[ n + subPos ];
|
|
if(piDstCoeff[ uiBlkPos ] != 0 )
|
|
{
|
|
Int64 costUp = rdFactor * ( - deltaU[uiBlkPos] ) + rateIncUp[uiBlkPos];
|
|
Int64 costDown = rdFactor * ( deltaU[uiBlkPos] ) + rateIncDown[uiBlkPos]
|
|
- ((abs(piDstCoeff[uiBlkPos]) == 1) ? sigRateDelta[uiBlkPos] : 0);
|
|
|
|
if(lastCG==1 && lastNZPosInCG==n && abs(piDstCoeff[uiBlkPos])==1)
|
|
{
|
|
costDown -= (4<<15);
|
|
}
|
|
|
|
if(costUp<costDown)
|
|
{
|
|
curCost = costUp;
|
|
curChange = 1;
|
|
}
|
|
else
|
|
{
|
|
curChange = -1;
|
|
if(n==firstNZPosInCG && abs(piDstCoeff[uiBlkPos])==1)
|
|
{
|
|
curCost = MAX_INT64;
|
|
}
|
|
else
|
|
{
|
|
curCost = costDown;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curCost = rdFactor * ( - (abs(deltaU[uiBlkPos])) ) + (1<<15) + rateIncUp[uiBlkPos] + sigRateDelta[uiBlkPos] ;
|
|
curChange = 1 ;
|
|
|
|
if(n<firstNZPosInCG)
|
|
{
|
|
UInt thissignbit = (plSrcCoeff[uiBlkPos]>=0?0:1);
|
|
if(thissignbit != signbit )
|
|
{
|
|
curCost = MAX_INT64;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( curCost<minCostInc)
|
|
{
|
|
minCostInc = curCost;
|
|
finalChange = curChange;
|
|
minPos = uiBlkPos;
|
|
}
|
|
}
|
|
|
|
if(piDstCoeff[minPos] == entropyCodingMaximum || piDstCoeff[minPos] == entropyCodingMinimum)
|
|
{
|
|
finalChange = -1;
|
|
}
|
|
|
|
if(plSrcCoeff[minPos]>=0)
|
|
{
|
|
piDstCoeff[minPos] += finalChange ;
|
|
}
|
|
else
|
|
{
|
|
piDstCoeff[minPos] -= finalChange ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(lastCG==1)
|
|
{
|
|
lastCG=0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/** Pattern decision for context derivation process of significant_coeff_flag
|
|
* \param sigCoeffGroupFlag pointer to prior coded significant coeff group
|
|
* \param uiCGPosX column of current coefficient group
|
|
* \param uiCGPosY row of current coefficient group
|
|
* \param width width of the block
|
|
* \param height height of the block
|
|
* \returns pattern for current coefficient group
|
|
*/
|
|
Int TComTrQuant::calcPatternSigCtx( const UInt* sigCoeffGroupFlag, UInt uiCGPosX, UInt uiCGPosY, UInt widthInGroups, UInt heightInGroups )
|
|
{
|
|
if ((widthInGroups <= 1) && (heightInGroups <= 1)) return 0;
|
|
|
|
const Bool rightAvailable = uiCGPosX < (widthInGroups - 1);
|
|
const Bool belowAvailable = uiCGPosY < (heightInGroups - 1);
|
|
|
|
UInt sigRight = 0;
|
|
UInt sigLower = 0;
|
|
|
|
if (rightAvailable) sigRight = ((sigCoeffGroupFlag[ (uiCGPosY * widthInGroups) + uiCGPosX + 1 ] != 0) ? 1 : 0);
|
|
if (belowAvailable) sigLower = ((sigCoeffGroupFlag[ (uiCGPosY + 1) * widthInGroups + uiCGPosX ] != 0) ? 1 : 0);
|
|
|
|
return sigRight + (sigLower << 1);
|
|
}
|
|
|
|
|
|
/** Context derivation process of coeff_abs_significant_flag
|
|
* \param patternSigCtx pattern for current coefficient group
|
|
* \param codingParameters coding parmeters for the TU (includes the scan)
|
|
* \param scanPosition current position in scan order
|
|
* \param log2BlockWidth log2 width of the block
|
|
* \param log2BlockHeight log2 height of the block
|
|
* \param ChannelType channel type (CHANNEL_TYPE_LUMA/CHROMA)
|
|
* \returns ctxInc for current scan position
|
|
*/
|
|
Int TComTrQuant::getSigCtxInc ( Int patternSigCtx,
|
|
const TUEntropyCodingParameters &codingParameters,
|
|
const Int scanPosition,
|
|
const Int log2BlockWidth,
|
|
const Int log2BlockHeight,
|
|
const ChannelType chanType)
|
|
{
|
|
if (codingParameters.firstSignificanceMapContext == significanceMapContextSetStart[chanType][CONTEXT_TYPE_SINGLE])
|
|
{
|
|
//single context mode
|
|
return significanceMapContextSetStart[chanType][CONTEXT_TYPE_SINGLE];
|
|
}
|
|
|
|
const UInt rasterPosition = codingParameters.scan[scanPosition];
|
|
const UInt posY = rasterPosition >> log2BlockWidth;
|
|
const UInt posX = rasterPosition - (posY << log2BlockWidth);
|
|
|
|
if ((posX + posY) == 0) return 0; //special case for the DC context variable
|
|
|
|
Int offset = MAX_INT;
|
|
|
|
if ((log2BlockWidth == 2) && (log2BlockHeight == 2)) //4x4
|
|
{
|
|
offset = ctxIndMap4x4[ (4 * posY) + posX ];
|
|
}
|
|
else
|
|
{
|
|
Int cnt = 0;
|
|
|
|
switch (patternSigCtx)
|
|
{
|
|
//------------------
|
|
|
|
case 0: //neither neighbouring group is significant
|
|
{
|
|
const Int posXinSubset = posX & ((1 << MLS_CG_LOG2_WIDTH) - 1);
|
|
const Int posYinSubset = posY & ((1 << MLS_CG_LOG2_HEIGHT) - 1);
|
|
const Int posTotalInSubset = posXinSubset + posYinSubset;
|
|
|
|
//first N coefficients in scan order use 2; the next few use 1; the rest use 0.
|
|
const UInt context1Threshold = NEIGHBOURHOOD_00_CONTEXT_1_THRESHOLD_4x4;
|
|
const UInt context2Threshold = NEIGHBOURHOOD_00_CONTEXT_2_THRESHOLD_4x4;
|
|
|
|
cnt = (posTotalInSubset >= context1Threshold) ? 0 : ((posTotalInSubset >= context2Threshold) ? 1 : 2);
|
|
}
|
|
break;
|
|
|
|
//------------------
|
|
|
|
case 1: //right group is significant, below is not
|
|
{
|
|
const Int posYinSubset = posY & ((1 << MLS_CG_LOG2_HEIGHT) - 1);
|
|
const Int groupHeight = 1 << MLS_CG_LOG2_HEIGHT;
|
|
|
|
cnt = (posYinSubset >= (groupHeight >> 1)) ? 0 : ((posYinSubset >= (groupHeight >> 2)) ? 1 : 2); //top quarter uses 2; second-from-top quarter uses 1; bottom half uses 0
|
|
}
|
|
break;
|
|
|
|
//------------------
|
|
|
|
case 2: //below group is significant, right is not
|
|
{
|
|
const Int posXinSubset = posX & ((1 << MLS_CG_LOG2_WIDTH) - 1);
|
|
const Int groupWidth = 1 << MLS_CG_LOG2_WIDTH;
|
|
|
|
cnt = (posXinSubset >= (groupWidth >> 1)) ? 0 : ((posXinSubset >= (groupWidth >> 2)) ? 1 : 2); //left quarter uses 2; second-from-left quarter uses 1; right half uses 0
|
|
}
|
|
break;
|
|
|
|
//------------------
|
|
|
|
case 3: //both neighbouring groups are significant
|
|
{
|
|
cnt = 2;
|
|
}
|
|
break;
|
|
|
|
//------------------
|
|
|
|
default:
|
|
std::cerr << "ERROR: Invalid patternSigCtx \"" << Int(patternSigCtx) << "\" in getSigCtxInc" << std::endl;
|
|
exit(1);
|
|
break;
|
|
}
|
|
|
|
//------------------------------------------------
|
|
|
|
const Bool notFirstGroup = ((posX >> MLS_CG_LOG2_WIDTH) + (posY >> MLS_CG_LOG2_HEIGHT)) > 0;
|
|
|
|
offset = (notFirstGroup ? notFirstGroupNeighbourhoodContextOffset[chanType] : 0) + cnt;
|
|
}
|
|
|
|
return codingParameters.firstSignificanceMapContext + offset;
|
|
}
|
|
|
|
|
|
/** Get the best level in RD sense
|
|
* \param rd64CodedCost reference to coded cost
|
|
* \param rd64CodedCost0 reference to cost when coefficient is 0
|
|
* \param rd64CodedCostSig reference to cost of significant coefficient
|
|
* \param lLevelDouble reference to unscaled quantized level
|
|
* \param uiMaxAbsLevel scaled quantized level
|
|
* \param ui16CtxNumSig current ctxInc for coeff_abs_significant_flag
|
|
* \param ui16CtxNumOne current ctxInc for coeff_abs_level_greater1 (1st bin of coeff_abs_level_minus1 in AVC)
|
|
* \param ui16CtxNumAbs current ctxInc for coeff_abs_level_greater2 (remaining bins of coeff_abs_level_minus1 in AVC)
|
|
* \param ui16AbsGoRice current Rice parameter for coeff_abs_level_minus3
|
|
* \param iQBits quantization step size
|
|
* \param dTemp correction factor
|
|
* \param bLast indicates if the coefficient is the last significant
|
|
* \returns best quantized transform level for given scan position
|
|
* This method calculates the best quantized transform level for a given scan position.
|
|
*/
|
|
__inline UInt TComTrQuant::xGetCodedLevel ( Double& rd64CodedCost,
|
|
Double& rd64CodedCost0,
|
|
Double& rd64CodedCostSig,
|
|
Intermediate_Int lLevelDouble,
|
|
UInt uiMaxAbsLevel,
|
|
UShort ui16CtxNumSig,
|
|
UShort ui16CtxNumOne,
|
|
UShort ui16CtxNumAbs,
|
|
UShort ui16AbsGoRice,
|
|
UInt c1Idx,
|
|
UInt c2Idx,
|
|
Int iQBits,
|
|
Double errorScale,
|
|
Bool bLast,
|
|
Bool useLimitedPrefixLength,
|
|
ChannelType channelType
|
|
) const
|
|
{
|
|
Double dCurrCostSig = 0;
|
|
UInt uiBestAbsLevel = 0;
|
|
|
|
if( !bLast && uiMaxAbsLevel < 3 )
|
|
{
|
|
rd64CodedCostSig = xGetRateSigCoef( 0, ui16CtxNumSig );
|
|
rd64CodedCost = rd64CodedCost0 + rd64CodedCostSig;
|
|
if( uiMaxAbsLevel == 0 )
|
|
{
|
|
return uiBestAbsLevel;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rd64CodedCost = MAX_DOUBLE;
|
|
}
|
|
|
|
if( !bLast )
|
|
{
|
|
dCurrCostSig = xGetRateSigCoef( 1, ui16CtxNumSig );
|
|
}
|
|
|
|
UInt uiMinAbsLevel = ( uiMaxAbsLevel > 1 ? uiMaxAbsLevel - 1 : 1 );
|
|
for( Int uiAbsLevel = uiMaxAbsLevel; uiAbsLevel >= uiMinAbsLevel ; uiAbsLevel-- )
|
|
{
|
|
Double dErr = Double( lLevelDouble - ( Intermediate_Int(uiAbsLevel) << iQBits ) );
|
|
Double dCurrCost = dErr * dErr * errorScale + xGetICost( xGetICRate( uiAbsLevel, ui16CtxNumOne, ui16CtxNumAbs, ui16AbsGoRice, c1Idx, c2Idx, useLimitedPrefixLength, channelType ) );
|
|
dCurrCost += dCurrCostSig;
|
|
|
|
if( dCurrCost < rd64CodedCost )
|
|
{
|
|
uiBestAbsLevel = uiAbsLevel;
|
|
rd64CodedCost = dCurrCost;
|
|
rd64CodedCostSig = dCurrCostSig;
|
|
}
|
|
}
|
|
|
|
return uiBestAbsLevel;
|
|
}
|
|
|
|
/** Calculates the cost for specific absolute transform level
|
|
* \param uiAbsLevel scaled quantized level
|
|
* \param ui16CtxNumOne current ctxInc for coeff_abs_level_greater1 (1st bin of coeff_abs_level_minus1 in AVC)
|
|
* \param ui16CtxNumAbs current ctxInc for coeff_abs_level_greater2 (remaining bins of coeff_abs_level_minus1 in AVC)
|
|
* \param ui16AbsGoRice Rice parameter for coeff_abs_level_minus3
|
|
* \returns cost of given absolute transform level
|
|
*/
|
|
__inline Int TComTrQuant::xGetICRate ( UInt uiAbsLevel,
|
|
UShort ui16CtxNumOne,
|
|
UShort ui16CtxNumAbs,
|
|
UShort ui16AbsGoRice,
|
|
UInt c1Idx,
|
|
UInt c2Idx,
|
|
Bool useLimitedPrefixLength,
|
|
ChannelType channelType
|
|
) const
|
|
{
|
|
Int iRate = Int(xGetIEPRate()); // cost of sign bit
|
|
UInt baseLevel = (c1Idx < C1FLAG_NUMBER) ? (2 + (c2Idx < C2FLAG_NUMBER)) : 1;
|
|
|
|
if ( uiAbsLevel >= baseLevel )
|
|
{
|
|
UInt symbol = uiAbsLevel - baseLevel;
|
|
UInt length;
|
|
if (symbol < (COEF_REMAIN_BIN_REDUCTION << ui16AbsGoRice))
|
|
{
|
|
length = symbol>>ui16AbsGoRice;
|
|
iRate += (length+1+ui16AbsGoRice)<< 15;
|
|
}
|
|
else if (useLimitedPrefixLength)
|
|
{
|
|
const UInt maximumPrefixLength = (32 - (COEF_REMAIN_BIN_REDUCTION + g_maxTrDynamicRange[channelType]));
|
|
|
|
UInt prefixLength = 0;
|
|
UInt suffix = (symbol >> ui16AbsGoRice) - COEF_REMAIN_BIN_REDUCTION;
|
|
|
|
while ((prefixLength < maximumPrefixLength) && (suffix > ((2 << prefixLength) - 2)))
|
|
{
|
|
prefixLength++;
|
|
}
|
|
|
|
const UInt suffixLength = (prefixLength == maximumPrefixLength) ? (g_maxTrDynamicRange[channelType] - ui16AbsGoRice) : (prefixLength + 1/*separator*/);
|
|
|
|
iRate += (COEF_REMAIN_BIN_REDUCTION + prefixLength + suffixLength + ui16AbsGoRice) << 15;
|
|
}
|
|
else
|
|
{
|
|
length = ui16AbsGoRice;
|
|
symbol = symbol - ( COEF_REMAIN_BIN_REDUCTION << ui16AbsGoRice);
|
|
while (symbol >= (1<<length))
|
|
{
|
|
symbol -= (1<<(length++));
|
|
}
|
|
iRate += (COEF_REMAIN_BIN_REDUCTION+length+1-ui16AbsGoRice+length)<< 15;
|
|
}
|
|
|
|
if (c1Idx < C1FLAG_NUMBER)
|
|
{
|
|
iRate += m_pcEstBitsSbac->m_greaterOneBits[ ui16CtxNumOne ][ 1 ];
|
|
|
|
if (c2Idx < C2FLAG_NUMBER)
|
|
{
|
|
iRate += m_pcEstBitsSbac->m_levelAbsBits[ ui16CtxNumAbs ][ 1 ];
|
|
}
|
|
}
|
|
}
|
|
else if( uiAbsLevel == 1 )
|
|
{
|
|
iRate += m_pcEstBitsSbac->m_greaterOneBits[ ui16CtxNumOne ][ 0 ];
|
|
}
|
|
else if( uiAbsLevel == 2 )
|
|
{
|
|
iRate += m_pcEstBitsSbac->m_greaterOneBits[ ui16CtxNumOne ][ 1 ];
|
|
iRate += m_pcEstBitsSbac->m_levelAbsBits[ ui16CtxNumAbs ][ 0 ];
|
|
}
|
|
else
|
|
{
|
|
iRate = 0;
|
|
}
|
|
|
|
return iRate;
|
|
}
|
|
|
|
__inline Double TComTrQuant::xGetRateSigCoeffGroup ( UShort uiSignificanceCoeffGroup,
|
|
UShort ui16CtxNumSig ) const
|
|
{
|
|
return xGetICost( m_pcEstBitsSbac->significantCoeffGroupBits[ ui16CtxNumSig ][ uiSignificanceCoeffGroup ] );
|
|
}
|
|
|
|
/** Calculates the cost of signaling the last significant coefficient in the block
|
|
* \param uiPosX X coordinate of the last significant coefficient
|
|
* \param uiPosY Y coordinate of the last significant coefficient
|
|
* \returns cost of last significant coefficient
|
|
*/
|
|
/*
|
|
* \param uiWidth width of the transform unit (TU)
|
|
*/
|
|
__inline Double TComTrQuant::xGetRateLast ( const UInt uiPosX,
|
|
const UInt uiPosY,
|
|
const ComponentID component ) const
|
|
{
|
|
UInt uiCtxX = g_uiGroupIdx[uiPosX];
|
|
UInt uiCtxY = g_uiGroupIdx[uiPosY];
|
|
|
|
Double uiCost = m_pcEstBitsSbac->lastXBits[toChannelType(component)][ uiCtxX ] + m_pcEstBitsSbac->lastYBits[toChannelType(component)][ uiCtxY ];
|
|
|
|
if( uiCtxX > 3 )
|
|
{
|
|
uiCost += xGetIEPRate() * ((uiCtxX-2)>>1);
|
|
}
|
|
if( uiCtxY > 3 )
|
|
{
|
|
uiCost += xGetIEPRate() * ((uiCtxY-2)>>1);
|
|
}
|
|
return xGetICost( uiCost );
|
|
}
|
|
|
|
/** Calculates the cost for specific absolute transform level
|
|
* \param uiAbsLevel scaled quantized level
|
|
* \param ui16CtxNumOne current ctxInc for coeff_abs_level_greater1 (1st bin of coeff_abs_level_minus1 in AVC)
|
|
* \param ui16CtxNumAbs current ctxInc for coeff_abs_level_greater2 (remaining bins of coeff_abs_level_minus1 in AVC)
|
|
* \param ui16CtxBase current global offset for coeff_abs_level_greater1 and coeff_abs_level_greater2
|
|
* \returns cost of given absolute transform level
|
|
*/
|
|
__inline Double TComTrQuant::xGetRateSigCoef ( UShort uiSignificance,
|
|
UShort ui16CtxNumSig ) const
|
|
{
|
|
return xGetICost( m_pcEstBitsSbac->significantBits[ ui16CtxNumSig ][ uiSignificance ] );
|
|
}
|
|
|
|
/** Get the cost for a specific rate
|
|
* \param dRate rate of a bit
|
|
* \returns cost at the specific rate
|
|
*/
|
|
__inline Double TComTrQuant::xGetICost ( Double dRate ) const
|
|
{
|
|
return m_dLambda * dRate;
|
|
}
|
|
|
|
/** Get the cost of an equal probable bit
|
|
* \returns cost of equal probable bit
|
|
*/
|
|
__inline Double TComTrQuant::xGetIEPRate ( ) const
|
|
{
|
|
return 32768;
|
|
}
|
|
|
|
/** Context derivation process of coeff_abs_significant_flag
|
|
* \param uiSigCoeffGroupFlag significance map of L1
|
|
* \param uiBlkX column of current scan position
|
|
* \param uiBlkY row of current scan position
|
|
* \param uiLog2BlkSize log2 value of block size
|
|
* \returns ctxInc for current scan position
|
|
*/
|
|
UInt TComTrQuant::getSigCoeffGroupCtxInc (const UInt* uiSigCoeffGroupFlag,
|
|
const UInt uiCGPosX,
|
|
const UInt uiCGPosY,
|
|
const UInt widthInGroups,
|
|
const UInt heightInGroups)
|
|
{
|
|
UInt sigRight = 0;
|
|
UInt sigLower = 0;
|
|
|
|
if (uiCGPosX < (widthInGroups - 1)) sigRight = ((uiSigCoeffGroupFlag[ (uiCGPosY * widthInGroups) + uiCGPosX + 1 ] != 0) ? 1 : 0);
|
|
if (uiCGPosY < (heightInGroups - 1)) sigLower = ((uiSigCoeffGroupFlag[ (uiCGPosY + 1) * widthInGroups + uiCGPosX ] != 0) ? 1 : 0);
|
|
|
|
return ((sigRight + sigLower) != 0) ? 1 : 0;
|
|
}
|
|
|
|
|
|
/** set quantized matrix coefficient for encode
|
|
* \param scalingList quantaized matrix address
|
|
*/
|
|
Void TComTrQuant::setScalingList(TComScalingList *scalingList, const ChromaFormat format)
|
|
{
|
|
const Int minimumQp = 0;
|
|
const Int maximumQp = SCALING_LIST_REM_NUM;
|
|
|
|
for(UInt size = 0; size < SCALING_LIST_SIZE_NUM; size++)
|
|
{
|
|
for(UInt list = 0; list < SCALING_LIST_NUM; list++)
|
|
{
|
|
for(Int qp = minimumQp; qp < maximumQp; qp++)
|
|
{
|
|
xSetScalingListEnc(scalingList,list,size,qp,format);
|
|
xSetScalingListDec(scalingList,list,size,qp,format);
|
|
setErrScaleCoeff(list,size,qp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/** set quantized matrix coefficient for decode
|
|
* \param scalingList quantaized matrix address
|
|
*/
|
|
Void TComTrQuant::setScalingListDec(TComScalingList *scalingList, const ChromaFormat format)
|
|
{
|
|
const Int minimumQp = 0;
|
|
const Int maximumQp = SCALING_LIST_REM_NUM;
|
|
|
|
for(UInt size = 0; size < SCALING_LIST_SIZE_NUM; size++)
|
|
{
|
|
for(UInt list = 0; list < SCALING_LIST_NUM; list++)
|
|
{
|
|
for(Int qp = minimumQp; qp < maximumQp; qp++)
|
|
{
|
|
xSetScalingListDec(scalingList,list,size,qp,format);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/** set error scale coefficients
|
|
* \param list List ID
|
|
* \param uiSize Size
|
|
* \param uiQP Quantization parameter
|
|
*/
|
|
Void TComTrQuant::setErrScaleCoeff(UInt list, UInt size, Int qp)
|
|
{
|
|
const UInt uiLog2TrSize = g_aucConvertToBit[ g_scalingListSizeX[size] ] + 2;
|
|
const ChannelType channelType = ((list == 0) || (list == MAX_NUM_COMPONENT)) ? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA;
|
|
|
|
const Int iTransformShift = getTransformShift(channelType, uiLog2TrSize); // Represents scaling through forward transform
|
|
|
|
UInt i,uiMaxNumCoeff = g_scalingListSize[size];
|
|
Int *piQuantcoeff;
|
|
Double *pdErrScale;
|
|
piQuantcoeff = getQuantCoeff(list, qp,size);
|
|
pdErrScale = getErrScaleCoeff(list, size, qp);
|
|
|
|
Double dErrScale = (Double)(1<<SCALE_BITS); // Compensate for scaling of bitcount in Lagrange cost function
|
|
dErrScale = dErrScale*pow(2.0,(-2.0*iTransformShift)); // Compensate for scaling through forward transform
|
|
|
|
for(i=0;i<uiMaxNumCoeff;i++)
|
|
{
|
|
pdErrScale[i] = dErrScale / piQuantcoeff[i] / piQuantcoeff[i] / (1 << DISTORTION_PRECISION_ADJUSTMENT(2 * (g_bitDepth[channelType] - 8)));
|
|
}
|
|
|
|
getErrScaleCoeffNoScalingList(list, size, qp) = dErrScale / g_quantScales[qp] / g_quantScales[qp] / (1 << DISTORTION_PRECISION_ADJUSTMENT(2 * (g_bitDepth[channelType] - 8)));
|
|
}
|
|
|
|
/** set quantized matrix coefficient for encode
|
|
* \param scalingList quantaized matrix address
|
|
* \param listId List index
|
|
* \param sizeId size index
|
|
* \param uiQP Quantization parameter
|
|
*/
|
|
Void TComTrQuant::xSetScalingListEnc(TComScalingList *scalingList, UInt listId, UInt sizeId, Int qp, const ChromaFormat format)
|
|
{
|
|
UInt width = g_scalingListSizeX[sizeId];
|
|
UInt height = g_scalingListSizeX[sizeId];
|
|
UInt ratio = g_scalingListSizeX[sizeId]/min(MAX_MATRIX_SIZE_NUM,(Int)g_scalingListSizeX[sizeId]);
|
|
Int *quantcoeff;
|
|
Int *coeff = scalingList->getScalingListAddress(sizeId,listId);
|
|
quantcoeff = getQuantCoeff(listId, qp, sizeId);
|
|
|
|
Int quantScales = g_quantScales[qp];
|
|
|
|
processScalingListEnc(coeff,
|
|
quantcoeff,
|
|
(quantScales << LOG2_SCALING_LIST_NEUTRAL_VALUE),
|
|
height, width, ratio,
|
|
min(MAX_MATRIX_SIZE_NUM, (Int)g_scalingListSizeX[sizeId]),
|
|
scalingList->getScalingListDC(sizeId,listId));
|
|
}
|
|
|
|
/** set quantized matrix coefficient for decode
|
|
* \param scalingList quantaized matrix address
|
|
* \param list List index
|
|
* \param size size index
|
|
* \param uiQP Quantization parameter
|
|
*/
|
|
Void TComTrQuant::xSetScalingListDec(TComScalingList *scalingList, UInt listId, UInt sizeId, Int qp, const ChromaFormat format)
|
|
{
|
|
UInt width = g_scalingListSizeX[sizeId];
|
|
UInt height = g_scalingListSizeX[sizeId];
|
|
UInt ratio = g_scalingListSizeX[sizeId]/min(MAX_MATRIX_SIZE_NUM,(Int)g_scalingListSizeX[sizeId]);
|
|
Int *dequantcoeff;
|
|
Int *coeff = scalingList->getScalingListAddress(sizeId,listId);
|
|
|
|
dequantcoeff = getDequantCoeff(listId, qp, sizeId);
|
|
|
|
Int invQuantScale = g_invQuantScales[qp];
|
|
|
|
processScalingListDec(coeff,
|
|
dequantcoeff,
|
|
invQuantScale,
|
|
height, width, ratio,
|
|
min(MAX_MATRIX_SIZE_NUM, (Int)g_scalingListSizeX[sizeId]),
|
|
scalingList->getScalingListDC(sizeId,listId));
|
|
}
|
|
|
|
/** set flat matrix value to quantized coefficient
|
|
*/
|
|
Void TComTrQuant::setFlatScalingList(const ChromaFormat format)
|
|
{
|
|
const Int minimumQp = 0;
|
|
const Int maximumQp = SCALING_LIST_REM_NUM;
|
|
|
|
for(UInt size = 0; size < SCALING_LIST_SIZE_NUM; size++)
|
|
{
|
|
for(UInt list = 0; list < SCALING_LIST_NUM; list++)
|
|
{
|
|
for(Int qp = minimumQp; qp < maximumQp; qp++)
|
|
{
|
|
xsetFlatScalingList(list,size,qp,format);
|
|
setErrScaleCoeff(list,size,qp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** set flat matrix value to quantized coefficient
|
|
* \param list List ID
|
|
* \param uiQP Quantization parameter
|
|
* \param uiSize Size
|
|
*/
|
|
Void TComTrQuant::xsetFlatScalingList(UInt list, UInt size, Int qp, const ChromaFormat format)
|
|
{
|
|
UInt i,num = g_scalingListSize[size];
|
|
Int *quantcoeff;
|
|
Int *dequantcoeff;
|
|
|
|
Int quantScales = g_quantScales [qp];
|
|
Int invQuantScales = g_invQuantScales[qp] << 4;
|
|
|
|
quantcoeff = getQuantCoeff(list, qp, size);
|
|
dequantcoeff = getDequantCoeff(list, qp, size);
|
|
|
|
for(i=0;i<num;i++)
|
|
{
|
|
*quantcoeff++ = quantScales;
|
|
*dequantcoeff++ = invQuantScales;
|
|
}
|
|
}
|
|
|
|
/** set quantized matrix coefficient for encode
|
|
* \param coeff quantaized matrix address
|
|
* \param quantcoeff quantaized matrix address
|
|
* \param quantScales Q(QP%6)
|
|
* \param height height
|
|
* \param width width
|
|
* \param ratio ratio for upscale
|
|
* \param sizuNum matrix size
|
|
* \param dc dc parameter
|
|
*/
|
|
Void TComTrQuant::processScalingListEnc( Int *coeff, Int *quantcoeff, Int quantScales, UInt height, UInt width, UInt ratio, Int sizuNum, UInt dc)
|
|
{
|
|
for(UInt j=0;j<height;j++)
|
|
{
|
|
for(UInt i=0;i<width;i++)
|
|
{
|
|
quantcoeff[j*width + i] = quantScales / coeff[sizuNum * (j / ratio) + i / ratio];
|
|
}
|
|
}
|
|
|
|
if(ratio > 1)
|
|
{
|
|
quantcoeff[0] = quantScales / dc;
|
|
}
|
|
}
|
|
|
|
/** set quantized matrix coefficient for decode
|
|
* \param coeff quantaized matrix address
|
|
* \param dequantcoeff quantaized matrix address
|
|
* \param invQuantScales IQ(QP%6))
|
|
* \param height height
|
|
* \param width width
|
|
* \param ratio ratio for upscale
|
|
* \param sizuNum matrix size
|
|
* \param dc dc parameter
|
|
*/
|
|
Void TComTrQuant::processScalingListDec( Int *coeff, Int *dequantcoeff, Int invQuantScales, UInt height, UInt width, UInt ratio, Int sizuNum, UInt dc)
|
|
{
|
|
for(UInt j=0;j<height;j++)
|
|
{
|
|
for(UInt i=0;i<width;i++)
|
|
{
|
|
dequantcoeff[j*width + i] = invQuantScales * coeff[sizuNum * (j / ratio) + i / ratio];
|
|
}
|
|
}
|
|
|
|
if(ratio > 1)
|
|
{
|
|
dequantcoeff[0] = invQuantScales * dc;
|
|
}
|
|
}
|
|
|
|
/** initialization process of scaling list array
|
|
*/
|
|
Void TComTrQuant::initScalingList()
|
|
{
|
|
for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++)
|
|
{
|
|
for(UInt qp = 0; qp < SCALING_LIST_REM_NUM; qp++)
|
|
{
|
|
for(UInt listId = 0; listId < SCALING_LIST_NUM; listId++)
|
|
{
|
|
m_quantCoef [sizeId][listId][qp] = new Int [g_scalingListSize[sizeId]];
|
|
m_dequantCoef [sizeId][listId][qp] = new Int [g_scalingListSize[sizeId]];
|
|
m_errScale [sizeId][listId][qp] = new Double [g_scalingListSize[sizeId]];
|
|
} // listID loop
|
|
}
|
|
}
|
|
}
|
|
|
|
/** destroy quantization matrix array
|
|
*/
|
|
Void TComTrQuant::destroyScalingList()
|
|
{
|
|
for(UInt sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++)
|
|
{
|
|
for(UInt listId = 0; listId < SCALING_LIST_NUM; listId++)
|
|
{
|
|
for(UInt qp = 0; qp < SCALING_LIST_REM_NUM; qp++)
|
|
{
|
|
if(m_quantCoef [sizeId][listId][qp]) delete [] m_quantCoef [sizeId][listId][qp];
|
|
if(m_dequantCoef [sizeId][listId][qp]) delete [] m_dequantCoef [sizeId][listId][qp];
|
|
if(m_errScale [sizeId][listId][qp]) delete [] m_errScale [sizeId][listId][qp];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Void TComTrQuant::transformSkipQuantOneSample(TComTU &rTu, const ComponentID compID, const Pel resiDiff, TCoeff* pcCoeff, const UInt uiPos, const QpParam &cQP, const Bool bUseHalfRoundingPoint)
|
|
{
|
|
TComDataCU *pcCU = rTu.getCU();
|
|
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
|
|
const TComRectangle &rect = rTu.getRect(compID);
|
|
const UInt uiWidth = rect.width;
|
|
const UInt uiHeight = rect.height;
|
|
const Int iTransformShift = getTransformShift(toChannelType(compID), rTu.GetEquivalentLog2TrSize(compID));
|
|
const Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID);
|
|
const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, true);
|
|
const Int defaultQuantisationCoefficient = g_quantScales[cQP.rem];
|
|
|
|
assert( scalingListType < SCALING_LIST_NUM );
|
|
const Int *const piQuantCoeff = getQuantCoeff( scalingListType, cQP.rem, (rTu.GetEquivalentLog2TrSize(compID)-2) );
|
|
|
|
|
|
/* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be
|
|
* implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the
|
|
* uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller)
|
|
* Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result
|
|
*/
|
|
|
|
const Int iQBits = QUANT_SHIFT + cQP.per + iTransformShift;
|
|
// QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset
|
|
|
|
const Int iAdd = ( bUseHalfRoundingPoint ? 256 : (pcCU->getSlice()->getSliceType() == I_SLICE ? 171 : 85) ) << (iQBits - 9);
|
|
|
|
TCoeff transformedCoefficient;
|
|
|
|
// transform-skip
|
|
if (iTransformShift >= 0)
|
|
{
|
|
transformedCoefficient = resiDiff << iTransformShift;
|
|
}
|
|
else // for very high bit depths
|
|
{
|
|
const Int iTrShiftNeg = -iTransformShift;
|
|
const Int offset = 1 << (iTrShiftNeg - 1);
|
|
transformedCoefficient = ( resiDiff + offset ) >> iTrShiftNeg;
|
|
}
|
|
|
|
// quantization
|
|
const TCoeff iSign = (transformedCoefficient < 0 ? -1: 1);
|
|
|
|
const Int quantisationCoefficient = enableScalingLists ? piQuantCoeff[uiPos] : defaultQuantisationCoefficient;
|
|
|
|
const Int64 tmpLevel = (Int64)abs(transformedCoefficient) * quantisationCoefficient;
|
|
|
|
const TCoeff quantisedCoefficient = (TCoeff((tmpLevel + iAdd ) >> iQBits)) * iSign;
|
|
|
|
const TCoeff entropyCodingMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]);
|
|
const TCoeff entropyCodingMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1;
|
|
pcCoeff[ uiPos ] = Clip3<TCoeff>( entropyCodingMinimum, entropyCodingMaximum, quantisedCoefficient );
|
|
}
|
|
|
|
|
|
Void TComTrQuant::invTrSkipDeQuantOneSample( TComTU &rTu, ComponentID compID, TCoeff inSample, Pel &reconSample, const QpParam &cQP, UInt uiPos )
|
|
{
|
|
TComDataCU *pcCU = rTu.getCU();
|
|
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
|
|
const TComRectangle &rect = rTu.getRect(compID);
|
|
const UInt uiWidth = rect.width;
|
|
const UInt uiHeight = rect.height;
|
|
const Int QP_per = cQP.per;
|
|
const Int QP_rem = cQP.rem;
|
|
const Int iTransformShift = getTransformShift(toChannelType(compID), rTu.GetEquivalentLog2TrSize(compID));
|
|
const Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID);
|
|
const Bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, true);
|
|
const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID);
|
|
|
|
assert( scalingListType < SCALING_LIST_NUM );
|
|
|
|
const Int rightShift = (IQUANT_SHIFT - (iTransformShift + QP_per)) + (enableScalingLists ? LOG2_SCALING_LIST_NEUTRAL_VALUE : 0);
|
|
|
|
const TCoeff transformMinimum = -(1 << g_maxTrDynamicRange[toChannelType(compID)]);
|
|
const TCoeff transformMaximum = (1 << g_maxTrDynamicRange[toChannelType(compID)]) - 1;
|
|
|
|
// Dequantisation
|
|
|
|
TCoeff dequantisedSample;
|
|
|
|
if(enableScalingLists)
|
|
{
|
|
const UInt dequantCoefBits = 1 + IQUANT_SHIFT + SCALING_LIST_BITS;
|
|
const UInt targetInputBitDepth = std::min<UInt>((g_maxTrDynamicRange[toChannelType(compID)] + 1), (((sizeof(Intermediate_Int) * 8) + rightShift) - dequantCoefBits));
|
|
|
|
const Intermediate_Int inputMinimum = -(1 << (targetInputBitDepth - 1));
|
|
const Intermediate_Int inputMaximum = (1 << (targetInputBitDepth - 1)) - 1;
|
|
|
|
Int *piDequantCoef = getDequantCoeff(scalingListType,QP_rem,uiLog2TrSize-2);
|
|
|
|
if(rightShift > 0)
|
|
{
|
|
const Intermediate_Int iAdd = 1 << (rightShift - 1);
|
|
const TCoeff clipQCoef = TCoeff(Clip3<Intermediate_Int>(inputMinimum, inputMaximum, inSample));
|
|
const Intermediate_Int iCoeffQ = ((Intermediate_Int(clipQCoef) * piDequantCoef[uiPos]) + iAdd ) >> rightShift;
|
|
|
|
dequantisedSample = TCoeff(Clip3<Intermediate_Int>(transformMinimum,transformMaximum,iCoeffQ));
|
|
}
|
|
else
|
|
{
|
|
const Int leftShift = -rightShift;
|
|
const TCoeff clipQCoef = TCoeff(Clip3<Intermediate_Int>(inputMinimum, inputMaximum, inSample));
|
|
const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * piDequantCoef[uiPos]) << leftShift;
|
|
|
|
dequantisedSample = TCoeff(Clip3<Intermediate_Int>(transformMinimum,transformMaximum,iCoeffQ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const Int scale = g_invQuantScales[QP_rem];
|
|
const Int scaleBits = (IQUANT_SHIFT + 1) ;
|
|
|
|
const UInt targetInputBitDepth = std::min<UInt>((g_maxTrDynamicRange[toChannelType(compID)] + 1), (((sizeof(Intermediate_Int) * 8) + rightShift) - scaleBits));
|
|
const Intermediate_Int inputMinimum = -(1 << (targetInputBitDepth - 1));
|
|
const Intermediate_Int inputMaximum = (1 << (targetInputBitDepth - 1)) - 1;
|
|
|
|
if (rightShift > 0)
|
|
{
|
|
const Intermediate_Int iAdd = 1 << (rightShift - 1);
|
|
const TCoeff clipQCoef = TCoeff(Clip3<Intermediate_Int>(inputMinimum, inputMaximum, inSample));
|
|
const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * scale + iAdd) >> rightShift;
|
|
|
|
dequantisedSample = TCoeff(Clip3<Intermediate_Int>(transformMinimum,transformMaximum,iCoeffQ));
|
|
}
|
|
else
|
|
{
|
|
const Int leftShift = -rightShift;
|
|
const TCoeff clipQCoef = TCoeff(Clip3<Intermediate_Int>(inputMinimum, inputMaximum, inSample));
|
|
const Intermediate_Int iCoeffQ = (Intermediate_Int(clipQCoef) * scale) << leftShift;
|
|
|
|
dequantisedSample = TCoeff(Clip3<Intermediate_Int>(transformMinimum,transformMaximum,iCoeffQ));
|
|
}
|
|
}
|
|
|
|
// Inverse transform-skip
|
|
|
|
if (iTransformShift >= 0)
|
|
{
|
|
const TCoeff offset = iTransformShift==0 ? 0 : (1 << (iTransformShift - 1));
|
|
reconSample = Pel(( dequantisedSample + offset ) >> iTransformShift);
|
|
}
|
|
else //for very high bit depths
|
|
{
|
|
const Int iTrShiftNeg = -iTransformShift;
|
|
reconSample = Pel(dequantisedSample << iTrShiftNeg);
|
|
}
|
|
}
|
|
|
|
|
|
Void TComTrQuant::crossComponentPrediction( TComTU & rTu,
|
|
const ComponentID compID,
|
|
const Pel * piResiL,
|
|
const Pel * piResiC,
|
|
Pel * piResiT,
|
|
const Int width,
|
|
const Int height,
|
|
const Int strideL,
|
|
const Int strideC,
|
|
const Int strideT,
|
|
const Bool reverse )
|
|
{
|
|
const Pel *pResiL = piResiL;
|
|
const Pel *pResiC = piResiC;
|
|
Pel *pResiT = piResiT;
|
|
|
|
TComDataCU *pCU = rTu.getCU();
|
|
const Char alpha = pCU->getCrossComponentPredictionAlpha( rTu.GetAbsPartIdxTU( compID ), compID );
|
|
const Int diffBitDepth = pCU->getSlice()->getSPS()->getDifferentialLumaChromaBitDepth();
|
|
|
|
for( Int y = 0; y < height; y++ )
|
|
{
|
|
if (reverse)
|
|
{
|
|
for( Int x = 0; x < width; x++ )
|
|
{
|
|
pResiT[x] = pResiC[x] + (( alpha * rightShift( pResiL[x], diffBitDepth) ) >> 3);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( Int x = 0; x < width; x++ )
|
|
{
|
|
pResiT[x] = pResiC[x] - (( alpha * rightShift(pResiL[x], diffBitDepth) ) >> 3);
|
|
}
|
|
}
|
|
|
|
pResiL += strideL;
|
|
pResiC += strideC;
|
|
pResiT += strideT;
|
|
}
|
|
}
|
|
|
|
//! \}
|