MIP预测函数调用流程如下:
参考像素获取由initIntraMip()
调用prepareInputForPred()
完成,prepareInputForPred()
调用 deriveBoundaryData()
进行参考图像获取,并进行下采样,下面来看一下deriveBoundaryData()
这个函数,三个步骤:
void PredictorMIP::deriveBoundaryData(const CPelBuf& src, const Area& block, const int bitDepth, const AvailableInfo &availInfo)
{
// Step 1: Save block size and calculate dependent values
/* 参数初始化包括以下数据:m_blockSize和m_numModes
* 1. 预测块尺寸 及 尺寸对应MIP预测模式数量:
* 2. reduced bdry size (参考像素下采样目标尺寸):m_reducedBoundarySize
* 3. 仿射变换后的尺寸:m_reducedPredictionSize
* 4. 上采样使用的边界尺寸:m_boundarySizeForUpsampling
* 5. 两个方向的上采样因子m_upsmpFactorHor,m_upsmpFactorVer
*/
initPredBlockParams(block);
/************************* 获取重建参考 *******************************/
// 先将左上边界的参考值存下
// Step 2: Get the input data (left and top reference samples)
const int defaultPad = int(1 << (bitDepth - 1)); //默认填充值
// TOP (save top boundary since we might need it for upsampling)
m_boundaryForUpsamplingTop.resize( block.width );
const int availPosTop = availInfo.maxPosTop;
CHECKD(availPosTop > block.width, "Error: availPosTop out of range");
if (availPosTop > 0) //上边界参考有效
{
// top available
const Position posT0(block.x, block.y - 1); // offset(0,-1)
for (int x = 0; x < availPosTop; x++) // 对参考填充有效的availPosTop个值
{
m_boundaryForUpsamplingTop[ x ] = src.at( posT0.offset( x, 0 ) );
}
// top unavailable 余下填充默认值
const int padVal = m_boundaryForUpsamplingTop[ availPosTop - 1 ];
for( int x = availPosTop; x < m_boundaryForUpsamplingTop.size(); x++ )
{
m_boundaryForUpsamplingTop[ x ] = padVal;
}
}
else //参考填充默认值
{
std::fill( m_boundaryForUpsamplingTop.begin(), m_boundaryForUpsamplingTop.end(), defaultPad );
}
// LEFT (save left boundary since we might need it for upsampling)
m_boundaryForUpsamplingLeft.resize( block.height );
const int availPosLeft = availInfo.maxPosLeft;
CHECKD(availPosLeft > block.height, "Error: availPosLeft out of range");
// 左边界处理同上边界
if (availPosLeft > 0)
{
// left available
const Position posL0(block.x - 1, block.y);
for (int y = 0; y < availPosLeft; y++)
{
m_boundaryForUpsamplingLeft[ y ] = src.at( posL0.offset( 0, y ) );
}
// left unavailable
const int padVal = m_boundaryForUpsamplingLeft[ availPosLeft - 1 ];
for( int y = availPosLeft; y < m_boundaryForUpsamplingLeft.size(); y++ )
{
m_boundaryForUpsamplingLeft[ y ] = padVal;
}
}
else
{
std::fill( m_boundaryForUpsamplingLeft.begin(), m_boundaryForUpsamplingLeft.end(), defaultPad );
}
/************************* 对上述参考进行下采样 *******************************/
// Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction and intermediate boundary for upsampling)
m_reducedBoundary .resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height ); // concat [bdry_top bdry_left]
m_reducedBoundaryTransposed.resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height ); // concat [bdry_left bdry_top]
const bool needVerticalUpsampling = ( m_upsmpFactorVer > 1 ); // 垂直方向之后是否要进行上采样
int* const topReduced = m_reducedBoundary.data(); //下采样信号首地址
boundaryDownsampling1D( topReduced, m_boundaryForUpsamplingTop.data(), block.width, m_reducedBoundarySize.width, needVerticalUpsampling, m_boundarySizeForUpsampling.width ); // 进行下采样,不再详细说,详情见上一博文
m_boundaryForUpsamplingTop.resize( needVerticalUpsampling ? m_boundarySizeForUpsampling.width : 0 );
const bool needHorizontalUpsampling = ( m_upsmpFactorHor > 1 ); //水平方向之后是否要进行上采样
int* const leftReduced = m_reducedBoundary.data() + m_reducedBoundarySize.width; // 左侧参考首地址,相对原始参考偏移width
boundaryDownsampling1D( leftReduced, m_boundaryForUpsamplingLeft.data(), block.height, m_reducedBoundarySize.height, needHorizontalUpsampling, m_boundarySizeForUpsampling.height ); // 下采样
m_boundaryForUpsamplingLeft.resize( needHorizontalUpsampling ? m_boundarySizeForUpsampling.height : 0 );
int* const leftReducedTransposed = m_reducedBoundaryTransposed.data();
int* const topReducedTransposed = m_reducedBoundaryTransposed.data() + m_reducedBoundarySize.height;
for( int x = 0; x < m_reducedBoundarySize.width; x++ )
{
topReducedTransposed[ x ] = topReduced[ x ];
}
for( int y = 0; y < m_reducedBoundarySize.height; y++ )
{
leftReducedTransposed[ y ] = leftReduced[ y ];
}
}
在estIntraPredLumaQT()
中会调用predIntraMip()
获取MIP预测信号,predIntraMip()
通过调用MatrixIntraPrediction
类中函数 predBlock()
,predBlock()
最终调用PredictorMIP
类中函数 getPrediction()
得到预测值。看一下这个函数,主要以下步骤
void PredictorMIP::getPrediction(int* const result, const int modeIdx, const int bitDepth)
{
const bool transpose = isTransposed( modeIdx ); // 判断参考像素concat方式
const bool needUpsampling = ( m_upsmpFactorHor > 1 ) || ( m_upsmpFactorVer > 1 );
// pred = matrix * reduce_ref + bais
const short* matrix; // 系数矩阵
const short* bias; // 偏执
getMatrixBias( matrix, bias, modeIdx ); // 根据angular mode和MIP mode的映射表,查表获得
int shiftMatrix = 0;
int shiftBias = 0;
getShifts(shiftMatrix, shiftBias, modeIdx, bitDepth );
bool leaveHorOut = ( m_blockSize.width == 4 && m_blockSize.height >= 16 );
bool leaveVerOut = ( m_blockSize.height == 4 && m_blockSize.width >= 16 );
if (transpose)
{
std::swap(leaveHorOut, leaveVerOut);
}
static_vector<int, MIP_MAX_REDUCED_OUTPUT_SAMPLES> bufReducedPred( m_reducedPredictionSize.area() );
int* const reducedPred = needUpsampling ? bufReducedPred.data() : result;
const int* const reducedBoundary = transpose ? m_reducedBoundaryTransposed.data() : m_reducedBoundary.data();
xComputeMatrixTimesRedBndryPlusBias( reducedPred, reducedBoundary, matrix, bias,
leaveHorOut, leaveVerOut,
shiftMatrix, shiftBias,
transpose, needUpsampling );
// Reduced prediction is transposed if ( transpose && needUpsampling ).
if( needUpsampling )
{
predictionUpsampling( result, reducedPred, transpose );
}
}
class PredictorMIP
{
public:
PredictorMIP();
void deriveBoundaryData(const CPelBuf& src, const Area& block, const int bitDepth, const AvailableInfo &availInfo);
void getPrediction (int* const result, const int modeIdx, const int bitDepth);
private:
static_vector<int, MIP_MAX_INPUT_SIZE> m_reducedBoundary; // downsampled boundary of a block
static_vector<int, MIP_MAX_INPUT_SIZE> m_reducedBoundaryTransposed; // downsampled, transposed boundary of a block
static_vector<int, MIP_MAX_WIDTH> m_boundaryForUpsamplingTop; // top boundary samples for upsampling
static_vector<int, MIP_MAX_HEIGHT> m_boundaryForUpsamplingLeft; // left boundary samples for upsampling
Size m_blockSize;
int m_numModes;
Size m_reducedBoundarySize;
Size m_reducedPredictionSize;
Size m_boundarySizeForUpsampling;
unsigned int m_upsmpFactorHor;
unsigned int m_upsmpFactorVer;
void initPredBlockParams(const Size& block);
static void boundaryDownsampling1D( int* reducedDst, int* fullSrcAndIntermediateDst, const SizeType srcLen, const SizeType dstLen, const bool saveIntermediate, const SizeType intermediateLen );
static void doDownsampling( int* dst, const int* src, const SizeType srcLen, const SizeType dstLen );
void predictionUpsampling( int* const dst, const int* const src, const bool transpose ) const;
static void predictionUpsampling1D( int* const dst, const int* const src, const int* const bndry,
const SizeType srcSizeUpsmpDim, const SizeType srcSizeOrthDim,
const SizeType srcStep, const SizeType srcStride,
const SizeType dstStep, const SizeType dstStride,
const unsigned int upsmpFactor );
void getMatrixBias( const short*& matrix, const short*& bias, const int modeIdx ) const;
void getShifts( int &shiftMatrix, int &shiftBias, const int modeIdx, const int bitDepth ) const;
bool isTransposed( const int modeIdx ) const;
int getWeightIdx( const int modeIdx ) const;
void xComputeMatrixTimesRedBndryPlusBias( int*const result, const int* const input,
const short*matrix, const short*bias,
const bool leaveHorOut, const bool leaveVerOut,
const int shiftMatrix, const int shiftBias,
const bool transpose, const bool needUpsampling );
};