一 C语言实现
#define QUANT_ONE( coef, mf, f ) \
{ \
if( (coef) > 0 ) \
(coef) = (f + (coef)) * (mf) >> 16; \
else \
(coef) = - ((f - (coef)) * (mf) >> 16); \
nz |= (coef); \
}
static int quant_8x8( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] )
{
int nz = 0;
for( int i = 0; i < 64; i++ )
QUANT_ONE( dct[i], mf[i], bias[i] );
return !!nz;
}
二 汇编实现
//quant_8x8(int16_t dct[64], uint16_t mf[64], uint16_t bias[64])
function quant_8x8_neon, export=1
ld1 {v16.8h, v17.8h}, [x0] //从地址x0加载数据到neon寄存器v16和v17
abs v18.8h, v16.8h //对v16中的数据进行绝对值操作,并将结果存储在v18中
abs v19.8h, v17.8h //对v17中的数据进行绝对值操作,并将结果存储在v19中
ld1 {v0.8h, v1.8h}, [x2], #32 //从地址x2加载数据到neon寄存v0和v1,并跳过
ld1 {v2.8h, v3.8h}, [x1], #32 //从地址x1加载数据到neon寄存器v2和v3,并跳过
QUANT_TWO v0.8h, v1.8h, v2, v3, v4.16b//调用自定义的QUANT_TWO函数进行量化处理
.rept 3
//重复以下操作3次
ld1 {v16.8h, v17.8h}, [x0] //v16, v17 dct系数
abs v18.8h, v16.8h //求绝对值
abs v19.8h, v17.8h //求绝对值
ld1 {v0.8h, v1.8h}, [x2], #32
ld1 {v2.8h, v3.8h}, [x1], #32
QUANT_TWO v0.8h, v1.8h, v2, v3, v5.16b//再次强调QUANT_TWO函数进行量化处理
//v0.8h, v1.8h 是存储的偏移 数据,64bits
//v2.8h,v3.8h 是存储mf 量化因子,64bits
orr v4.16b, v4.16b, v5.16b //将每次量化处理的结果进行或操作,并存储在x4中
.endr
uqxtn v0.8b, v4.8h //对v4进行位转换操作
QUANT_END d0 //量化处理结束
endfunc
// QUANT_TWO v0.8h, v1.8h, v2, v3, v4.16b
//QUANT_TWO v0.8h, v1.8h, v2, v3, v5.16b
// v0 v1存储的偏移数组, v2,v3 量化因子,mask用来输出结果?
.macro QUANT_TWO bias0 bias1 mf0_1 mf2_3 mask
add v18.8h, v18.8h, bias0 //绝对值和v18.8h 相加bias0
add v19.8h, v19.8h, bias1 //绝对值和v19.8h 相加bias1
umull v20.4s, v18.4h, mf0_1().4h //这里的h表示 harfword, 4个half word。量化因子,4个存入 v20.4s s表示s word, 32bits ,这个也是一致的
umull2 v21.4s, v18.8h, mf0_1().8h //这里的h表示harfword, 4个half word, 量化因子,4个存入v21.4s ,v18.8h 64位4个系数 和这个乘以mf量化因子,4个halfword。
//意思是乘以之后,存入v21.4s中
umull v22.4s, v19.4h, mf2_3().4h
/*mf2_3().4h 的含义是4个half word, 乘以 v19.4h 存入 v22.4s */
umull2 v23.4s, v19.8h, mf2_3().8h
/*高4个halfword 和 系数相乘 存入 v23.4s 4个sword 32bits的数据中*/
sshr v16.8h, v16.8h, #15
/*v16以8个16bits 为单位,向右移位15位*/
sshr v17.8h, v17.8h, #15
/*v17也是这样操作,看起来是取符号位, 取的低64bits*/
shrn v18.4h, v20.4s, #16
/*对寄存器 v20 进行右移操作,移动 16 位,结果的低 16 位存储在寄存器 v18 中。*/
shrn2 v18.8h, v21.4s, #16
//上面两句话,一句话写了v18的低64bits,一句话写了高64bits,组合成一个完整的v18寄存器的值
/*对寄存器 v21 进行右移操作,移动 16 位,结果的低 16 位存储在寄存器 v18 中。*/
shrn v19.4h, v22.4s, #16
/*对寄存器 v22 进行右移操作,移动 16 位,结果的低 16 位存储在寄存器 v19 中。*/
shrn2 v19.8h, v23.4s, #16
/*对寄存器 v23 进行右移操作,移动 16 位,结果的低 16 位存储在寄存器 v19 中。*/
eor v18.16b, v18.16b, v16.16b
/*对寄存器 v18 和 v16 进行异或操作,结果存储在寄存器 v18字节 中*/
eor v19.16b, v19.16b, v17.16b
/*对寄存器 v19 和 v17 进行异或操作,结果存储在寄存器 v19 字节中*/
sub v18.8h, v19.8h, v16.8h
/*v16.8h 和 v19.8h 寄存器,相减 存入 18.8h */
sub 19.8h, v19.8h, v17.8h
/*v7.8h 和 v19.8h 寄存器,相减 存入 19.8h*/
orr mask, v18.16b, v19.16b
/*对寄存器 v18 和 v19 进行或操作,结果存储在寄存器 mask 中。*/
st1 {v18.8h, v19.8h}, [x0], #32
/*把最终的结果存入,x0的内存位置,dct 数组*/
.endm