源码阅读 x264 - 代价计算
x264
中 x264_pixel_init
函数中初始化了与代价计算有关的函数,本文分析部分代价计算函数的实现,包括 SAD
、SATD
、SSD
、等
- SAD (Sum of Absolute Difference) = SAE(Sum of Absolute Error) 绝对误差和
- SATD(Sum of Absolute Transformed Difference)即 hadamard 变换后再绝对值求和
- SSD(Sum of Squared Difference)= SSE(Sum of Squared Error) 差值的平方和
- MAD(Mean Absolute Difference)= MAE(Mean Absolute Error) 平均绝对差值
- MSD(Mean Squared Difference)= MSE(Mean Squared Error)平均平方误差
下面分别介绍 SAD
、SSD
、SATD
的实现过程。
SAD 实现过程
将 x264_pixel_init
函数中的 INIT8(sad,) 展开,可以得到如下代码:
pixf->sad[PIXEL_16x16] = x264_pixel_sad_16x16;
pixf->sad[PIXEL_16x8] = x264_pixel_sad_16x8;
pixf->sad[PIXEL_8x16] = x264_pixel_sad_8x16;
pixf->sad[PIXEL_8x8] = x264_pixel_sad_8x8;
pixf->sad[PIXEL_8x4] = x264_pixel_sad_8x4;
pixf->sad[PIXEL_4x8] = x264_pixel_sad_4x8;
pixf->sad[PIXEL_4x4] = x264_pixel_sad_4x4;
pixf->sad[PIXEL_4x16] = x264_pixel_sad_4x16;
我们选取其中最简单的 x264_pixel_sad_4x4
继续展开,它是通过一个宏来定义的:
#define PIXEL_SAD_C(name, lx, ly) \
static int name( pixel *pix1, intptr_t i_stride_pix1, \
pixel *pix2, intptr_t i_stride_pix2 ) \
{ \
int i_sum = 0; \
for(int y = 0; y < ly; y++) \
{ \
for(int x = 0; x < lx; x++) \
{ \
i_sum += abs(pix1[x] - pix2[x] ); \
} \
pix1 += i_stride_pix1; \
pix2 += i_stride_pix2; \
} \
return i_sum; \
}
PIXEL_SAD_C(x264_pixel_sad_4x4, 4, 4)
/* 展开宏定义如下 */
static int x264_pixel_sad_4x4(uint8_t *pix1, intptr_t i_stride_pix1, uint8_t *pix2, intptr_t i_stride_pix2) {
int i_sum = 0;
for(int y = 0; y < 4; y++) {
for(int x = 0; x < 4; x++) {
i_sum += abs(pix1[x] - pix2[x]);
}
pix1 += i_stride_pix1;
pix2 += i_stride_pix2;
}
return i_sum;
}
SSD 实现过程
将 x264_pixel_init
函数中的 INIT8(ssd,)
展开,可以得到如下代码:
pixf->ssd[PIXEL_16x16] = x264_pixel_ssd_16x16;
pixf->ssd[PIXEL_16x8] = x264_pixel_ssd_16x8;
pixf->ssd[PIXEL_8x16] = x264_pixel_ssd_8x16;
pixf->ssd[PIXEL_8x8] = x264_pixel_ssd_8x8;
pixf->ssd[PIXEL_8x4] = x264_pixel_ssd_8x4;
pixf->ssd[PIXEL_4x8] = x264_pixel_ssd_4x8;
pixf->ssd[PIXEL_4x4] = x264_pixel_ssd_4x4;
pixf->ssd[PIXEL_4x16] = x264_pixel_ssd_4x16;
我们选取其中最简单的 x264_pixel_ssd_4x4
继续展开,它也是通过一个宏来定义的:
#define PIXEL_SSD_C(name, lx, ly) \
static int x264_pixel_ssd_4x4( pixel *pix1, intptr_t i_stride_pix1, \
pixel *pix2, intptr_t i_stride_pix2 ) \
{ \
int i_sum = 0; \
for(int y = 0; y < ly; y++) \
{ \
for(int x = 0; x < lx; x++) \
{ \
int d = pix1[x] - pix2[x]; \
i_sum += d*d; \
} \
pix1 += i_stride_pix1; \
pix2 += i_stride_pix2; \
} \
return i_sum; \
}
PIXEL_SSD_C(x264_pixel_ssd_4x4, 4, 4)
/* 展开宏定义如下 */
tatic int name(uint8_t *pix1, intptr_t i_stride_pix1, uint8_t *pix2, intptr_t i_stride_pix2) {
int i_sum = 0;
for(int y = 0; y < 4; y++) {
for(int x = 0; x < 4; x++) {
int d = pix1[x] - pix2[x];
i_sum += d*d;
}
pix1 += i_stride_pix1;
pix2 += i_stride_pix2;
}
return i_sum;
}
SATD 实现过程
将 x264_pixel_init
函数中的 INIT8(satd,)
展开,可以得到如下代码:
pixf->satd[PIXEL_16x16] = x264_pixel_satd_16x16;
pixf->satd[PIXEL_16x8] = x264_pixel_satd_16x8;
pixf->satd[PIXEL_8x16] = x264_pixel_satd_8x16;
pixf->satd[PIXEL_8x8] = x264_pixel_satd_8x8;
pixf->satd[PIXEL_8x4] = x264_pixel_satd_8x4;
pixf->satd[PIXEL_4x8] = x264_pixel_satd_4x8;
pixf->satd[PIXEL_4x4] = x264_pixel_satd_4x4;
pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16;
同样,选取最简单的 x264_pixel_satd_4x4
继续展开,它的定义如下:
typedef uint8_t pixel;
typedef uint16_t sum_t;
typedef uint32_t sum2_t;
#define BITS_PER_SUM (8 * sizeof(sum_t))
#define HADAMARD4(d0, d1, d2, d3, s0, s1, s2, s3) {\
sum2_t t0 = s0 + s1;\
sum2_t t1 = s0 - s1;\
sum2_t t2 = s2 + s3;\
sum2_t t3 = s2 - s3;\
d0 = t0 + t2;\
d2 = t0 - t2;\
d1 = t1 + t3;\
d3 = t1 - t3;\
}
static NOINLINE int x264_pixel_satd_4x4(pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2 ) {
sum2_t tmp[4][2];
sum2_t a0, a1, a2, a3, b0, b1;
sum2_t sum = 0;
for ( int i = 0; i < 4; i++, pix1 += i_pix1, pix2 += i_pix2 ) {
a0 = pix1[0] - pix2[0];
a1 = pix1[1] - pix2[1];
b0 = (a0+a1) + ((a0-a1)<<BITS_PER_SUM);
a2 = pix1[2] - pix2[2];
a3 = pix1[3] - pix2[3];
b1 = (a2+a3) + ((a2-a3)<<BITS_PER_SUM);
tmp[i][0] = b0 + b1;
tmp[i][1] = b0 - b1;
}
for( int i = 0; i < 2; i++ ) {
HADAMARD4( a0, a1, a2, a3, tmp[0][i], tmp[1][i], tmp[2][i], tmp[3][i] );
a0 = abs2(a0) + abs2(a1) + abs2(a2) + abs2(a3);
sum += ((sum_t)a0) + (a0>>BITS_PER_SUM);
}
return sum >> 1;
}