由于后面要在运动估计方面做些优化,所以这几天看了下JMVC的motionEstimation.cpp即运动估计。
大家都知道运动估计只是在inter prediction即帧间预测才用到的
所以在宏块预测MbEncoder中有如下函数
xEstimateMb16x16
xEstimateMb16x8
xEstimateMb8x16
xEstimateSubMb8x8
xEstimateSubMb8x4
xEstimateSubMb4x8
xEstimateSubMb4x4
通过调用运动估计的入口函数m_pcMotionEstimation->estimateBlockWithStart()来实现运动估计。
而xEstimateMb8x8和eEstimateMb8x8Frext也间接通过调用xEstimateSubMb8x8,8x4,4x8,4x4来进行运动估计。
下面进入正题运动估计的入口函数estimateBlockWithStart()
首先是很多的预处理和初始化工作(这个还没有看太明白,希望有大牛懂的话讲解下吧)
然后就是调用一些搜索策略进行运动估计,主要有
xPelBlockSearch()全搜索
xPelSpiralSearch()螺旋搜索
xPelLogSearch()对数搜索
xTZSearch()这个就不知到叫什么名字了(to be continued)
至于搜索算法的具体实现,目前只看了全搜索的,下面就讲一下对xPelBlockSearch()的理解与疑问吧,希望大家能指出我理解不透的地方或解答我没有解决的问题,谢谢
全搜索顾名思义,就是在搜索范围内把所有的宏块都扫描一遍,然后取最优的结果(搜索范围内最优,基本上是全局最优)。
JMVC运动估计motionEstimation全搜索xPelBlockSearch()代码详解
Void MotionEstimation::xPelBlockSearch( IntYuvPicBuffer *pcPelData, Mv& rcMv, UInt& ruiSAD, UInt uiSearchRange )
{
if( ! uiSearchRange ) //对为0的SearchRange进行赋值,值为配置文件中给定的值
{
uiSearchRange = m_cParams.getSearchRange();
}
Int iYStride = pcPelData->getLStride(); //获取Y的行跨度
XPel* pucYRef = pcPelData->getLumBlk (); //获取当前块的Y地址
XPel* pucYSearch;
Int iCStride = pcPelData->getCStride(); //获取C的行跨度
XPel* pucURef = pcPelData->getCbBlk (); //获取当前块的U地址
XPel* pucVRef = pcPelData->getCrBlk (); //获取当前块的V地址
UInt uiSad;
Int y = 0;
Int x = 0;
m_cXDSS.iYStride = iYStride;
m_cXDSS.iCStride = iCStride;
ruiSAD = MSYS_UINT_MAX; //初始化绝对误差和,置为最大
rcMv.limitComponents( m_cMin, m_cMax );
rcMv >>= 2;
SearchRect cSearchRect;
cSearchRect.init( uiSearchRange, rcMv, m_cMin, m_cMax );
pucYSearch = pucYRef - iYStride * (cSearchRect.iNegVerLimit); //计算Y的初始搜索地址
for( y = -cSearchRect.iNegVerLimit; y <= cSearchRect.iPosVerLimit; y++ )
{
for( x = -cSearchRect.iNegHorLimit; x <= cSearchRect.iPosHorLimit; x++ )
{
//JVT-W080 BUG_FIX
if( OmitPDISearch( x, y+rcMv.getVer(),false ) )
continue;
//~JVT-W080 BUG_FIX
m_cXDSS.pYSearch = pucYSearch + x; //分别计算搜索块的YUV地址
m_cXDSS.pUSearch = pucURef + (y>>1)*iCStride + (x>>1);
m_cXDSS.pVSearch = pucVRef + (y>>1)*iCStride + (x>>1);
uiSad = m_cXDSS.Func( &m_cXDSS ); //计算当前块和搜索块的绝对误差和
uiSad += xGetCost( x, y); //这个是干什么的?先加上,后面又减了?
if( ruiSAD > uiSad ) //更新绝对误差最小的块和块的地址
{
ruiSAD = uiSad;
rcMv.setVer( y );
rcMv.setHor( x );
}
}
pucYSearch += iYStride; //加Y的宽度,即切换到下一行
}
y = rcMv.getVer();
x = rcMv.getHor();
ruiSAD -= xGetCost( x, y); //减了?到底是什么情况?
DO_DBG( m_cXDSS.pYSearch = pucYRef + y * iYStride + x );
DO_DBG( m_cXDSS.pUSearch = pucURef + (y>>1) * iCStride + (x>>1) );
DO_DBG( m_cXDSS.pVSearch = pucVRef + (y>>1) * iCStride + (x>>1) );
uiSad = m_cXDSS.Func( &m_cXDSS );
AOF_DBG( ruiSAD == ( uiSad = m_cXDSS.Func( &m_cXDSS ) ) );
}
上段代码有三个地方我还是不是很清楚:
1: rcMv.limitComponents( m_cMin, m_cMax );
rcMv >>= 2;
2: SearchRect cSearchRect;
cSearchRect.init( uiSearchRange, rcMv, m_cMin, m_cMax );
3: y = rcMv.getVer();
x = rcMv.getHor();
希望看到并了解其中含义的大牛们解释下