为了简单期间,这里以8x8宏块为例说明一下源码中的实现。
void x264_predict_8x8c_dc_c( pixel *src )
{
int s0 = 0, s1 = 0, s2 = 0, s3 = 0;
/*
s0 s1
s2
s3
*/
for( int i = 0; i < 4; i++ )
{
s0 += src[i - FDEC_STRIDE]; //s0 = src[-32] + src[-31] + src[-30] + src[-29]
s1 += src[i + 4 - FDEC_STRIDE]; //s1 = src[-28] + src[-27] + src[-26] + src[-25]
s2 += src[-1 + i * FDEC_STRIDE]; //s2 = src[31] + src[63] + src[95] + src[127]
s3 += src[-1 + (i+4)*FDEC_STRIDE]; //s3 = ...
}
/*
dc0 dc1
dc2 dc3
*/
pixel4 dc0 = PIXEL_SPLAT_X4( ( s0 + s2 + 4 ) >> 3 ); //(s0 + s2 + 4) / 8 * 0x01010101U
pixel4 dc1 = PIXEL_SPLAT_X4( ( s1 + 2 ) >> 2 ); //(s1 + 2) / 4 * 0x01010101U
pixel4 dc2 = PIXEL_SPLAT_X4( ( s3 + 2 ) >> 2 ); //(s3 + 2) / 4 * 0x01010101U
pixel4 dc3 = PIXEL_SPLAT_X4( ( s1 + s3 + 4 ) >> 3 ); //(s1 + s3 + 4) / 8 * 0x01010101U
for( int y = 0; y < 4; y++ )
{
MPIXEL_X4( src+0 ) = dc0;
MPIXEL_X4( src+4 ) = dc1;
src += FDEC_STRIDE;
}
for( int y = 0; y < 4; y++ )
{
MPIXEL_X4( src+0 ) = dc2;
MPIXEL_X4( src+4 ) = dc3;
src += FDEC_STRIDE;
}
}
从源码看出dc预测很简单,实际上就是求左方和上方像素的平均值。简单画了个图:
dc预测00.png
水平,垂直预测更简单,就不做分析了,贴下代码:
void x264_predict_8x8c_h_c( pixel *src )
{
for( int i = 0; i < 8; i++ )
{
pixel4 v = PIXEL_SPLAT_X4( src[-1] );
MPIXEL_X4( src+0 ) = v;
MPIXEL_X4( src+4 ) = v;
src += FDEC_STRIDE;
}
}
void x264_predict_8x8c_v_c( pixel *src )
{
pixel4 v0 = MPIXEL_X4( src+0-FDEC_STRIDE );
pixel4 v1 = MPIXEL_X4( src+4-FDEC_STRIDE );
for( int i = 0; i < 8; i++ )
{
MPIXEL_X4( src+0 ) = v0;
MPIXEL_X4( src+4 ) = v1;
src += FDEC_STRIDE;
}
}
plane模式稍微复杂些,源码如下:
void x264_predict_8x8c_p_c( pixel *src )
{
int H = 0, V = 0;
for( int i = 0; i < 4; i++ )
{
//H = (H[4] - H[2]) + 2 * (H[5] - H[1]) + 3 * (H[6] - H[0]) + 4 * (H[7] - H[1])
//V = (V[4] - V[2]) + 2 * (V[5] - V[1]) + 3 * (V[6] - V[0]) + 4 * (V[7] - V[1])
H += ( i + 1 ) * ( src[4+i - FDEC_STRIDE] - src[2 - i -FDEC_STRIDE] );
V += ( i + 1 ) * ( src[-1 +(i+4)*FDEC_STRIDE] - src[-1+(2-i)*FDEC_STRIDE] );
}
//a = 16 * (V[7] + H[7])
int a = 16 * ( src[-1+7*FDEC_STRIDE] + src[7 - FDEC_STRIDE] );
int b = ( 17 * H + 16 ) >> 5;
int c = ( 17 * V + 16 ) >> 5;
int i00 = a -3*b -3*c + 16;
//src[x][y] = 16 * (V[7] + H[7]) + m * ((H[4]-H[2]) + 2*(H[5]-H[1]) + 3*(H[6]-H[0]) + 4*(H[7]-H[1])) + n * ((V[4] - V[2]) + 2 * (V[5] - V[1]) + 3 * (V[6] - V[0]) + 4 * (V[7] - V[1])) + 16
for( int y = 0; y < 8; y++ )
{
int pix = i00;
for( int x = 0; x < 8; x++ )
{
src[x] = x264_clip_pixel( pix>>5 );
pix += b;
}
src += FDEC_STRIDE;
i00 += c;
}
}
源码中,H的值大小代表宏块上方靠右边的像素与左边像素的差值,V的值大小宏块左方靠下方的像素与靠上方像素的差值,src[x][y]是预测宏块的值,m和n是一个系数,它的大小跟x和y有关,当x越大时,m的值越大,表示水平方向的差值占的权重越大,当y越大时,n的值越大,表示垂直方向的差值占的权重越大。
网友评论