通过前面一篇亚像素入口和过程的博客,分析了亚像素的入口和过程,这篇文章分析1/2插值的过程:
xExtDIFUpSamplingH 这个函数是进行1/2精度插值,首先对参考图像进行水平插值,整像素位置直接复制给了m_filteredBlockTmp[0],调用了filterHor这个函数进行水平插值
调用了m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[0].getAddr(COMPONENT_Y), intStride, width + 1, height + filterSize, 0, false, chFmt, pattern->getBitDepthY());进行水平整像素复制给m_filteredBlockTmp[0]
filterHor这个函数分了三种情况:frac = 0、亮度和色度。frac = 0,即整数,不需要插值。,在进行整像素复制的时候有调用了filterCopy这个函数,
调用了filterCopy(bitDepth, src, srcStride, dst, dstStride, width, height, true, isLast );先看isFirst == true为第一次插值:Pel val = leftShift_round(src[col], shift);dst[col] = val - (Pel)IF_INTERNAL_OFFS;
再调用m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[2].getAddr(COMPONENT_Y), intStride, width + 1, height + filterSize, 2, false, chFmt, pattern->getBitDepthY());进行1/2像素水平插值赋值给m_filteredBlockTmp[2]
水平整像素插值后的Y做垂直方向整像素插值,结果存储在m_filteredBlock[0][0]中, dstPtr = m_filteredBlock[0][0].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width + 0, height + 0, 0, false, true, chFmt, pattern->getBitDepthY());
水平1/2像素插值后的Y做垂直方向1/2像素插值,结果存储在m_filteredBlock[2][0]中
intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + (halfFilterSize - 1) * intStride + 1;
dstPtr = m_filteredBlock[2][0].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width + 0, height + 1, 2, false, true, chFmt, pattern->getBitDepthY());
/**
* \brief Generate half-sample interpolated block
*
* \param pattern Reference picture ROI
* \param biPred Flag indicating whether block is for biprediction
*/
//产生1/2精度的插值像素块
Void TEncSearch::xExtDIFUpSamplingH(TComPattern* pattern)
{
Int width = pattern->getROIYWidth();
Int height = pattern->getROIYHeight();
Int srcStride = pattern->getPatternLStride();
//m_filteredBlockTmp[]是个临时的中间量。实际用于存储水平插值得到的各像素位置的YUV信息。[]中的数字指示水平插值的像素位置。
//m_filteredBlock[][]在做完水平插值之后,会进行垂直插值,得到最终的数据,存储与m_filteredBlock[][]中。第一个[]中的数字指示垂直插值位置,第二个指示水平插值位置。
Int intStride = m_filteredBlockTmp[0].getStride(COMPONENT_Y);
Int dstStride = m_filteredBlock[0][0].getStride(COMPONENT_Y);
Pel *intPtr;
Pel *dstPtr; //插值后的MV地址
Int filterSize = NTAPS_LUMA;//8抽头
Int halfFilterSize = (filterSize >> 1);//4
Pel *srcPtr = pattern->getROIY() - halfFilterSize * srcStride - 1; //源MV地址
const ChromaFormat chFmt = m_filteredBlock[0][0].getChromaFormat();
//对参考图像进行水平插值,整像素位置直接复制给了m_filteredBlockTmp[0],1/2像素位置插值后给了m_filteredBlockTmp[2]。
m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[0].getAddr(COMPONENT_Y), intStride, width + 1, height + filterSize, 0, false, chFmt, pattern->getBitDepthY());
m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[2].getAddr(COMPONENT_Y), intStride, width + 1, height + filterSize, 2, false, chFmt, pattern->getBitDepthY());
水平整像素插值后的Y做垂直方向整像素插值,结果存储在m_filteredBlock[0][0]中
intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + halfFilterSize * intStride + 1;
dstPtr = m_filteredBlock[0][0].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intP