WelsMdPSkipEnc函数介绍
函数功能 :它尝试对当前宏块(MB)进行P-skip模式的编码,并返回一个布尔值表示是否成功。函数参数 :
函数接受编码上下文 pEncCtx MD结构体 pWelsMd 当前宏块 pCurMb 宏块缓存 pMbCache
函数调用关系图 :
WelsMdPSkipEnc 函数原理
原理过程 :
获取当前编码层和函数列表; 从缓存中获取参考帧的亮度、色度数据; iLineSizeY 和 iLineSizeUV 分别是亮度和色度分量的行间距,用于计算像素数据的偏移; pDstLuma, pDstCb, pDstCr 分别指向用于存储P-skip宏块数据的目标缓冲区,色度分量偏移量是亮度分量的两倍,因为色度分辨率通常是亮度分辨率的一半; sMvp 用于存储预测的运动向量,初始化为 0; 获取编码器的stride信息,iEncStride 是编码帧的stride,即每行像素的字节数,pEncMb 指向当前宏块的编码数据; pStrideEncBlockOffset 包含了编码块的stride偏移信息,pEncBlockOffset 将用于计算编码块在帧中的具体位置; iSadCostLuma、iSadCostChroma 和 iSadCostMb 分别初始化为0,这些变量将用于存储亮度、色度和整个宏块的SAD成本; 调用 PredSkipMv
函数来预测P-skip宏块的运动向量sMvp; 将运动向量的 iMvX 和 iMvY 成员右移两位,相当于除以4,从而将宏块级别的运动向量转换为四分之一像素级别的运动向量。这通常用于更精细的运动补偿; 计算水平方向上的像素索引,将当前宏块的X坐标 iMbX 左移4位(乘以16),得到当前宏块左上角的像素索引。然后加上运动向量的X分量 sQpelMvp.iMvX,得到实际要引用的像素的X坐标 n ; 检查水平方向是否越界,如果计算出的X坐标 n 小于 -29 或者大于宏块宽度加上12(转换为像素坐标后的范围),则认为运动向量越界,返回 false 表示不能使用这个运动向量; 计算垂直方向上的像素索引,计算当前宏块的Y坐标 iMbY左移4位(乘以16), 加上运动向量的Y分量 sQpelMvp.iMvY,得到实际要引用的像素的Y坐标 n。 检查垂直方向是否越界,如果计算出的Y坐标小于 -29 或者大于宏块高度加上12的范围,则认为运动向量越界,同样返回 false; pRefLuma 指针根据四分之一像素精度的运动向量 sQpelMvp 进行偏移,以便对齐到正确的参考像素; pMcLumaFunc
函数用于执行亮度分量的运动补偿,将参考帧中预测的宏块复制到目标位置 pDstLuma;pfSampleSad[BLOCK_16x16]
函数计算编码宏块和运动补偿后的宏块之间的SAD成本,存储在 iSadCostLuma 变量中;类似的,pMcChromaFunc
函数执行两个色度分量的运动补偿,pfSampleSad[BLOCK_8x8]
函数计算两个色度分量的 SAD 代价,累加存储在iSadCostChroma变量中; 宏块的总SAD成本 iSadCostMb 是亮度和色度SAD成本的总和; 如果宏块的总SAD成本为0,或者小于预测的SAD成本 pWelsMd->iSadPredSkip,或者在P-slice中且参考宏块是P-skip类型且SAD成本小于参考宏块的SAD成本,则认为P-skip模式是可行的;
pfUpdateMbMv
函数更新当前宏块的运动信息;根据是否使用SAD作为编码成本的度量,更新 pWelsMd 结构体中的相关亮度成本信息iCostLuma; 宏块的总SAD成本 iSadCostMb 更新到pWelsMd 结构体的iCostSkipMb; sMvp更新到pWelsMd 结构体的sP16x16Mv,同时更新到当前层解码图像的MV列表中对应位置‘ 返回 true,表示当前宏块是pskip 模式是可行的; WelsDctMb
函数对亮度分量进行DCT变换;WelsTryPYskip
函数尝试对Y分量进行P-skip检查。如果Y分量的DCT系数在阈值内,即宏块在视觉上没有显著变化,可以尝试P-skip;
更新 色度 U 分量编码参数; pfDctFourT4
函数用于对4x4块的色度分量执行DCT变换;WelsTryPUVskip
函数尝试对U分量进行P-skip检查,如果U分量的DCT系数在阈值内,即宏块在视觉上没有显著变化,可以尝试P-skip;
更新 色度 V 分量编码参数; pfDctFourT4
函数用于对4x4块的色度分量执行DCT变换;WelsTryPUVskip
函数尝试对V分量进行P-skip检查,如果V分量的DCT系数在阈值内,即宏块在视觉上没有显著变化,可以尝试P-skip;
pfUpdateMbMv
函数更新当前宏块的运动信息;根据是否使用SAD作为编码成本的度量,更新 pWelsMd 结构体中的相关亮度成本信息iCostLuma; 宏块的总SAD成本 iSadCostMb 更新到pWelsMd 结构体的iCostSkipMb; sMvp更新到pWelsMd 结构体的sP16x16Mv,同时更新到当前层解码图像的MV列表中对应位置‘ 返回 true,表示当前宏块是pskip 模式是可行的; 返回 false,表明P-skip 模式不可行。
原理图 :
WelsMdPSkipEnc 函数源码
bool WelsMdPSkipEnc ( sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SMB* pCurMb, SMbCache* pMbCache) {
SDqLayer* pCurLayer = pEncCtx-> pCurDqLayer;
SWelsFuncPtrList* pFunc = pEncCtx-> pFuncList;
uint8_t * pRefLuma = pMbCache-> SPicData. pRefMb[ 0 ] ;
uint8_t * pRefCb = pMbCache-> SPicData. pRefMb[ 1 ] ;
uint8_t * pRefCr = pMbCache-> SPicData. pRefMb[ 2 ] ;
int32_t iLineSizeY = pCurLayer-> pRefPic-> iLineSize[ 0 ] ;
int32_t iLineSizeUV = pCurLayer-> pRefPic-> iLineSize[ 1 ] ;
uint8_t * pDstLuma = pMbCache-> pSkipMb;
uint8_t * pDstCb = pMbCache-> pSkipMb + 256 ;
uint8_t * pDstCr = pMbCache-> pSkipMb + 256 + 64 ;
SMVUnitXY sMvp = { 0 } ;
int32_t n;
int32_t iEncStride = pCurLayer-> iEncStride[ 0 ] ;
uint8_t * pEncMb = pMbCache-> SPicData. pEncMb[ 0 ] ;
int32_t * pStrideEncBlockOffset = pEncCtx-> pStrideTab-> pStrideEncBlockOffset[ pEncCtx-> uiDependencyId] ;
int32_t * pEncBlockOffset;
int32_t iSadCostLuma = 0 ;
int32_t iSadCostChroma = 0 ;
int32_t iSadCostMb = 0 ;
PredSkipMv ( pMbCache, & sMvp) ;
SMVUnitXY sQpelMvp = { static_cast < int16_t > ( sMvp. iMvX >> 2 ) , static_cast < int16_t > ( sMvp. iMvY >> 2 ) } ;
n = ( pCurMb-> iMbX << 4 ) + sQpelMvp. iMvX;
if ( n < - 29 )
return false ;
else if ( n > ( int32_t ) ( ( pCurLayer-> iMbWidth << 4 ) + 12 ) )
return false ;
n = ( pCurMb-> iMbY << 4 ) + sQpelMvp. iMvY;
if ( n < - 29 )
return false ;
else if ( n > ( int32_t ) ( ( pCurLayer-> iMbHeight << 4 ) + 12 ) )
return false ;
pRefLuma += sQpelMvp. iMvY * iLineSizeY + sQpelMvp. iMvX;
pFunc-> sMcFuncs. pMcLumaFunc ( pRefLuma, iLineSizeY, pDstLuma, 16 , sMvp. iMvX, sMvp. iMvY, 16 , 16 ) ;
iSadCostLuma = pFunc-> sSampleDealingFuncs. pfSampleSad[ BLOCK_16x16] ( pMbCache-> SPicData. pEncMb[ 0 ] ,
pCurLayer-> iEncStride[ 0 ] , pDstLuma, 16 ) ;
const int32_t iStrideUV = ( sQpelMvp. iMvY >> 1 ) * iLineSizeUV + ( sQpelMvp. iMvX >> 1 ) ;
pRefCb += iStrideUV;
pFunc-> sMcFuncs. pMcChromaFunc ( pRefCb, iLineSizeUV, pDstCb, 8 , sMvp. iMvX, sMvp. iMvY, 8 , 8 ) ;
iSadCostChroma = pFunc-> sSampleDealingFuncs. pfSampleSad[ BLOCK_8x8] ( pMbCache-> SPicData. pEncMb[ 1 ] ,
pCurLayer-> iEncStride[ 1 ] , pDstCb, 8 ) ;
pRefCr += iStrideUV;
pFunc-> sMcFuncs. pMcChromaFunc ( pRefCr, iLineSizeUV, pDstCr, 8 , sMvp. iMvX, sMvp. iMvY, 8 , 8 ) ;
iSadCostChroma += pFunc-> sSampleDealingFuncs. pfSampleSad[ BLOCK_8x8] ( pMbCache-> SPicData. pEncMb[ 2 ] ,
pCurLayer-> iEncStride[ 2 ] , pDstCr, 8 ) ;
iSadCostMb = iSadCostLuma + iSadCostChroma;
if ( iSadCostMb == 0 ||
iSadCostMb < pWelsMd-> iSadPredSkip ||
( pCurLayer-> pRefPic-> iPictureType == P_SLICE &&
pMbCache-> uiRefMbType == MB_TYPE_SKIP &&
iSadCostMb < pCurLayer-> pRefPic-> pMbSkipSad[ pCurMb-> iMbXY] ) ) {
ST32 ( pCurMb-> pRefIndex, 0 ) ;
pFunc-> pfUpdateMbMv ( pCurMb-> sMv, sMvp) ;
if ( pWelsMd-> bMdUsingSad) {
pCurMb-> pSadCost[ 0 ] = iSadCostLuma;
pWelsMd-> iCostLuma = pCurMb-> pSadCost[ 0 ] ;
} else
pWelsMd-> iCostLuma = pFunc-> sSampleDealingFuncs. pfSampleSatd[ BLOCK_16x16] ( pMbCache-> SPicData. pEncMb[ 0 ] ,
pCurLayer-> iEncStride[ 0 ] , pDstLuma, 16 ) ;
pWelsMd-> iCostSkipMb = iSadCostMb;
pCurMb-> sP16x16Mv = sMvp;
pCurLayer-> pDecPic-> sMvList[ pCurMb-> iMbXY] = sMvp;
return true ;
}
WelsDctMb ( pMbCache-> pCoeffLevel, pEncMb, iEncStride, pDstLuma, pEncCtx-> pFuncList-> pfDctFourT4) ;
if ( WelsTryPYskip ( pEncCtx, pCurMb, pMbCache) ) {
iEncStride = pEncCtx-> pCurDqLayer-> iEncStride[ 1 ] ;
pEncMb = pMbCache-> SPicData. pEncMb[ 1 ] ;
pEncBlockOffset = pStrideEncBlockOffset + 16 ;
pFunc-> pfDctFourT4 ( pMbCache-> pCoeffLevel + 256 , & ( pEncMb[ * pEncBlockOffset] ) , iEncStride, pMbCache-> pSkipMb + 256 , 8 ) ;
if ( WelsTryPUVskip ( pEncCtx, pCurMb, pMbCache, 1 ) ) {
pEncMb = pMbCache-> SPicData. pEncMb[ 2 ] ;
pEncBlockOffset = pStrideEncBlockOffset + 20 ;
pFunc-> pfDctFourT4 ( pMbCache-> pCoeffLevel + 320 , & ( pEncMb[ * pEncBlockOffset] ) , iEncStride, pMbCache-> pSkipMb + 320 , 8 ) ;
if ( WelsTryPUVskip ( pEncCtx, pCurMb, pMbCache, 2 ) ) {
ST32 ( pCurMb-> pRefIndex, 0 ) ;
pFunc-> pfUpdateMbMv ( pCurMb-> sMv, sMvp) ;
if ( pWelsMd-> bMdUsingSad) {
pCurMb-> pSadCost[ 0 ] = iSadCostLuma;
pWelsMd-> iCostLuma = pCurMb-> pSadCost[ 0 ] ;
} else
pWelsMd-> iCostLuma = pFunc-> sSampleDealingFuncs. pfSampleSatd[ BLOCK_16x16] ( pMbCache-> SPicData. pEncMb[ 0 ] ,
pCurLayer-> iEncStride[ 0 ] , pDstLuma, 16 ) ;
pWelsMd-> iCostSkipMb = iSadCostMb;
pCurMb-> sP16x16Mv = sMvp;
pCurLayer-> pDecPic-> sMvList[ pCurMb-> iMbXY] = sMvp;
return true ;
}
}
}
return false ;
}